How do I code-sign an executable created by a python wheel? - python

I'm creating a python package with an executable as a wheel using setuptools. My simplified setup.py file looks like this:
setup(
name="mypackage",
version="1.0.0",
entry_points={"console_scripts": {"mypackage = mypackage.cli:cli"}}
)
Command to create the python package:
python setup.py bdist_wheel
When installing the resulting wheel, a mypackage.exe file is created in the scripts directory as expected.
How can I make sure, that the created executable is code-signed with a given certificate? I know how to code sign an existing executable using signtool.exe or Powershell, but since the executable seems to be created on the client machine when the wheel is installed, I don't know how to do it.

Related

Installing shared library with python package not separately

I have successfully built a Python package that uses CMake combined with pybind11 to create a shared object (.so - assuming only Linux usage at the moment) file. The implementation works but I am unable to remove this shared object file using pip uninstall .
My setup command in setup.py file looks like this taken from the pybind/cmake_example repository:
setup(
name='package',
version='0.0.1',
author='-',
author_email='-',
description='A test project using pybind11 and CMake',
long_description='',
ext_modules=[CMakeExtension('packagebindings')],
cmdclass=dict(build_ext=CMakeBuild),
zip_safe=False,
packages=setuptools.find_packages()
)
My CMakeLists.txt file has an install instruction that looks like this:
install(TARGETS packagebindings COMPONENT python LIBRARY DESTINATION ${Python_SITELIB})
To summarise, here are the files that are created when running pip install .:
path/to/site-packages/package/* - removed by pip uninstall package
path/to/site-packages/package-0.0.1.dist-info/* - removed by pip uninstall package
path/to/site-packages/packagebindings.cpython-37m-x86_64-linux-gnu.so - still present after pip uninstall package
I would like to know how make it so that running pip uninstall . removes the .so file.
If a further MRE is required, I can link to a repository.
Your CMake install target seems to place the .so directly into the python installation directory (DESTINATION ${Python_SITE_LIB}). I'm guessing this stops the .so from being registered by Python proper, so it is not removed when uninstalling. I would suggest to make CMake place the .so in a distribution directory, and then add the following option to setup():
data_files = [("installation_bin", ["distribution_bin/library.so"])]
This will let the .so be tracked by the Python package manager. The first string is a directory relative to the installation prefix. The second string is the .so file in your distribution, relative to the setup.py script.

When installing a package in pip, how to configure to generate an exe file?

When installing a package in pip, how to configure to generate an exe file, like this
Extracting twine-3.2.0rc1-py3.7.egg to c:\python37\lib\site-packages
twine 3.2.0rc1 is already the active version in easy-install.pth
Installing twine-script.py script to C:\Python37\Scripts
Installing twine.exe script to C:\Python37\Scripts
The keywords you are looking for are: console script entry points
These are a couple of references to help you package your Python project so that it creates executables (*.exe on Windows):
https://packaging.python.org/guides/distributing-packages-using-setuptools/#console-scripts
https://setuptools.readthedocs.io/en/latest/setuptools.html#automatic-script-creation

How do you build a wheel outside of a repo containing the package?

Question
Is there a way to build a wheel for a package while in a different repository such that the wheel has been built exactly as it would be if you built the wheel inside of the repository containing the package?
Example
Consider the following repo:
/repo-containing-your-package
|___ your_module/
|___ setup.py
Build method A
When I run python setup.py bdist_wheel from within repo-containing-your-package it builds the wheel as expected, including your_module. This means after I install pip install ./dist/your_module-#.#.#-py3-none-any.whl (which is successful), I can run python -m your_module.foo from the command line.
When the package is building, I get output that verifies that my module has been picked up by the wheel:
creating 'dist/your_module-#.#.#-py3-none-any.whl' and adding 'build/bar' to it
adding 'your_module/__init__.py'
etc...
Build method B
However, if I run python ../repo-containing-your-package/setup.py bdist_wheel from a repository that is a sibling to repo-containing-your-package, it does not build the wheel as expected, as it fails to include your_module. This means after I install pip install ./dist/your_module-#.#.#-py3-none-any.whl (which is successful), attempting python -m your_module.foo fails:
Error while finding module specification for 'your_module.foo' (ModuleNotFoundError: No module named 'your_module')
The fact that the module has not been properly installed with the package is confirmed by reviewing the build output, which does not include the adding 'your_module' output that method A includes.
Two solutions I know of:
change working directory in setup.py
If you can modify the setup script, you can change the working directory programmatically. Add an os.chdir call early enough in the setup script:
import os
from setuptools import setup
os.chdir(os.path.dirname(__file__))
setup(...)
You can also change the working directory with other means without having to modify the setup script, e.g. in bash:
$ pushd path/to/repo; python setup.py bdist_wheel; popd
Use pip wheel
pip has a subcommand wheel that builds a wheel from the given arg; this arg is usually the name of the package, but can be a directory containing the setup script. Pass -e in that case so the wheel has the correct name:
$ pip wheel -e path/to/repo

How to write setup.py to produce generic .whl package

I am writing setup.py for my small python package, which is python wrapper on c++ tool, and it's depends on shared libraries like icu-uc, boost_program_options, and some custom ones. Python wrapper build with swig. I use Extension(libraries=[...]) to specify libraries to link.
My setup.py looks like this:
package_name = Extension(
name='_package_name',
sources=['some_souces.cpp',
'some_swig_interfaces.i'
],
swig_opts=['-c++'],
libraries=['icuuc', ...],
)
setup(
name='package_name',
version='0.1.0',
....
ext_modules=[package_name],
py_modules=['package_name']
)
and I build this with python3 setup.py bdist_wheel
And when I build and install generated file locally it works fine, but when I truing to use pip3 install package_name.whl on computer with other version of icu-uc or other libraries it's crashes at runtime throwing ImportError: libicuuc.so.60: cannot open shared object file: No such file or directory. So basically my question is how to build more generic .whl package that don't stick to library version but looks for any match?

Releasing a python package with tkinter for pip

I have build a small quiz using Tkinter in Python and I wish to release the game for all to play, so that people can just pip install and play the game.
I have gone through the docs to release a PyPi package, I released one, it gets successfully installed. However, I'm unable to launch the application from commandline nor can I look for the binary. I don't know where am I going wrong. Please help me out here.
My setup.py file looks like this
from setuptools import setup
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
with open(path.join(here, 'README.rst')) as f:
long_description = f.read()
setup(
name='py-quiz',
version='0.1.1',
description='Python based Quiz game.',
long_description=long_description,
author='Abhijit Nathwani',
author_email='abhijit.nathwani#gmail.com',
LICENSE='MIT',
url='https://github.com/abhijitnathwani/PyQuiz',
keywords='pyquiz tkinter'
)
To package it, I use
python setup.py sdist upload
The package is successfully added to PyPi package and I could install it using:
pip install py-quiz
The output of the installation:
Collecting py-quiz
Downloading py-quiz-0.1.1.tar.gz
Installing collected packages: py-quiz
Running setup.py install for py-quiz ... done
Successfully installed py-quiz-0.1.1
But then when i do,
user#somecomputer:~/PyQuiz$ py-quiz
py-quiz: command not found
How do I launch the game from command line? Please help me out here.
The application code is maintained here.
I finally solved the problem above by making the following changes.
There must be a package created in the directory and the folder structure should be as follows:
<Directory>
|-setup.py
|-dist
|-LICENCSE
|-readme
|-<package-name>
|-__init__.py
|-__main__.py
|-other files
and in the setup.py the following change should be
entry_points={
'console_scripts':['<command_name> = <package_name>.__main__:<function to be called>']
In my case, it is as follows:
entry_points={
'console_scripts':['py-quiz = py_quiz.__main__:main']
The main point is to create a package inside your project directory. This should solve major problems.

Categories