Making an Executable out of an entire Python Project - python-3.x

Is there any way I can make an executable out of my Python project? There are many Python scripts that are in my Project and there are SQLite db files as well as other files and folders that are required for the software to run correctly. What is the best way of making this entire project executable?, Should I only make the Python scripts executable?
I have tried Pyinstaller but I am not sure how to bundle all the files into 1 single executable. Shown above is a copy of all the files and folders in my directory.

I think you need to modify the spec file, which PyInstaller creates on a first run. There is a special parameter for data files:
binaries: non-python modules needed by the scripts, including names given by the --add-binary option;
Try adding your database and other data files to this field and they should be included to you package.
For further question I recommend to refer to official documentation and check examples on Github

Related

Copy non python files via package_data to Scripts directory

I have some scripts in my package, that rely on some template xml files.
Those scripts are callable by entry points and I wanted to reference the template files by a relative path.
When calling the script via python -m ... the scripts themselves are called from within lib\site-packages and there the xml files are available as I put them in my setup.py like this:
setup(
...
packages=['my_pck'],
package_dir={'my_pck': 'python/src/my_pck'},
package_data={'my_pck': ['reports/templates/*.xml']},
...
)
I know, I could copy those templates also by using data_files in my setup.py but using package_data seems better to me.
Unfortunately package_data seems not to copy those files to the Scripts folder where the entry points are located.
So my question is, is this even achievable via package_data and if, how?
Or is there a more pythonic, easier way to achieve this? Maybe not referencing those files via paths relative to the scripts?
Looks like importlib-resources might help here. This library is able to find the actual path to a resource file packaged as package_data by setuptools.
Access the package_data files from your code with something like this:
with importlib_resources.path('my_pck.reports.templates', 'a.xml') as xml_path:
do_something(xml_path)

How do I recursively generate documentation of an entire project with pydoc?

I have a python project inside a specific folder named "Project 1". I want to extract all the docstrings of all the python files inside this project.
In this project all the modules are imported dynamically through __init__.py and, for that reason, when I run pydoc it fails on the imports.
python -m pydoc -w module_folder/ will work for some scenarios, but not all. For example, if you want to document modules and submodules of an installed package, it won't work, you'd need to pivot to a different tool.
Using your favorite language you will need to:
Iterate through files in your target folder
Call pydoc once per (sub)module
Here is one of many examples on Github.
Pdoc, pydoctor both handle walking folders automatically, my fork of pydoc walks the module dependency tree by default.

Packaging Multiple Python Files

I currently am using this guide to package up my project wasp. However currently everything lives inside of the wasp file.
That's not ideal. I would rather have all the classes in separate files so it can be more effectively managed. I have the series of files needed in the debian directory. But I'm not sure how to configure the packaging to package multiple files.
Is there a way to change my packaging to package more than just the one script file?
I'm not a debian package or Python expert, but one way would be to copy the various source files to another location (outside of /usr/bin), and then have /usr/bin/wasp call out to them.
Say you put all of your python code in src/ in the root of your repo. In the debian/install file, you'd have:
wasp usr/bin
src/* usr/lib/wasp/
You'd then just need /usr/bin/wasp to call some entry point in src. For example,
#!/usr/bin/python3
import sys
sys.path.append('/usr/lib/wasp/')
import wasp # or whatever you expose in src
# ...
Again, I don't know the best practices here (either in directory or python usage) but I think this would at least work!

SCons: When adding a Node to the LIBS variable, how do I make it use just the file without the directory?

I have SCons code in which I am using SConscripts to build different directories separately. In my Src directory, my SConscript builds a shared library, and then returns the resulting Node as the Python variable libMyLibrary. I typically use the install option to copy this library to a directory that is on my system's LD_LIBRARY_PATH (I'm using OpenSUSE).
So far, so good. Now, in another directory, Src/Test, another SConscript imports libMyLibrary and builds some Programs using code like this:
env.Program('myProgram', 'myProgram.cpp', LIBS=[env['LIBS'], libMyLibrary])
The program then gets installed to my local bin folder. This code does track the library dependency and build the program, but the problem is that since the library is in a sub-directory (Src), that sub-directory gets included in the linker command. Here is an abbreviated example of the linker command that SCons generates:
g++ -o Src/Test/myProgram Src/Test/myProgram.o Src/libMyLibrary.so
I believe this happens because the Node,libMyLibrary, is essentially a path. The problem is that when I try to run the program, it is not looking for libMyLibrary.so in my library folder, but rather Src/libMyLibrary.so, and of course it doesn't find it.
I do NOT want the libraries I build to be installed in sub-directories of my install folder.
I already add the Src folder to LIBPATH, so SCons adds the -LSrc option to the linker command, but that doesn't solve the problem. My preference would be that when I add a Node, the path should automatically get parsed out to add the appropriate -L and -l options.
I know that I can get around this problem by adding the string 'MyLibrary' to the LIBS variable instead of the libMyLibrary Node, but then I have to explicitly tell SCons that each Program Depends() on libMyLibrary. It seems very inefficient to short-circuit SCons's built-in dependency tracking this way. Does anyone know the correct, SCons-y way to do this?
I'm referring to your latest comment: It looks to me as if this is not really a SCons problem, but more a general linker question (XY problem). Are you perhaps simply searching for RPATH? Please also check this old SO question: scons executable + shared library in project directory

How to manage development and installed versions of a shared library?

In short: This question is basically about telling Linux to load the development version of the .so file for executables in the dev directory and the installed .so file for others.
In long: Imagine a shared library, let's call it libasdf.so. And imagine the following directories:
/home/user/asdf/lib: libasdf.so
/home/user/asdf/test: ... perform_test
/opt/asdf/lib: libasdf.so
/home/user/jkl: ... use_asdf
In other words, you have a development directory for your library (/home/user/asdf) and you have an installed copy of its previous stable version (/opt/asdf) and some other programs using it (/home/user/jkl).
My question is, how can I tell Linux, to load /home/user/asdf/lib/libasdf.so when executing /home/user/asdf/test/perform_test and to load /opt/asdf/lib/libasdf.so when executing /home/user/jkl/use_asdf? Note that, even though I specify the directory by -L during link, Linux uses other methods (for example /ect/ld.so.conf and $LD_LIBRARY_PATH) to find the .so file.
The reason I need such a thing is that, of course the executables in the development directory need to link with the latest version of the library, while the other programs, would want to use the stable version.
Putting ../lib in the library path doesn't seem like a secure idea, not to mention not completely correct since you can't run the test from a different directory.
One solution I thought about is to have perform_test link with libasdf-dev.so and upon install, copy libasdf-dev.so as libasdf.so and have others link with that. This solution has one problem though. Imagine the following additional directory:
/home/user/asdf/tool: ... use_asdf_too
Which gets installed to:
/opt/asdf/bin: use_asdf_too
In my solution, it is unknown what use_asdf_too should be linked against. If linked against libasdf.so, it wouldn't work properly if invoked from the dev directory and if linked against libasdf-dev.so, it wouldn't work properly if invoked from the installed location.
What can I do? How is this managed by other people?
Installed shared objects usually don't just end with ".so". Usually they also include their soname, such as libadsf.so.42.1. The .so file for development is typically a symlink to a fully-versioned filename. The linker will look for the .so file and resolve it to the full filename, and the loader will then load the fully-versioned library instead.

Resources