API documentation¶
The following documentation is based on the source code of version 5.0 of the py2deb package. The following modules are available:
py2deb.cli
¶
Usage: py2deb [OPTIONS] …
Convert Python packages to Debian packages according to the given command line options (see below). The command line arguments are the same as accepted by the “pip install” command because py2deb invokes pip during the conversion process. This means you can name the package(s) to convert on the command line but you can also use “requirement files” if you prefer.
If you want to pass command line options to pip (e.g. because you want to use a custom index URL or a requirements file) then you will need to tell py2deb where the options for py2deb stop and the options for pip begin. In such cases you can use the following syntax:
$ py2deb -r /tmp -- -r requirements.txt
So the “–” marker separates the py2deb options from the pip options.
Supported options:
Option | Description |
---|---|
-c , --config=FILENAME |
Load a configuration file. Because the command line arguments are processed in the given order, you have the choice and responsibility to decide if command line options override configuration file options or vice versa. Refer to the documentation for details on the configuration file format. The default configuration files /etc/py2deb.ini and ~/.py2deb.ini are automatically loaded if they exist. This happens before environment variables and command line options are processed. Can also be set using the environment variable |
-r , --repository=DIRECTORY |
Change the directory where *.deb archives are stored. Defaults to the system wide temporary directory (which is usually /tmp). If this directory doesn’t exist py2deb refuses to run. Can also be set using the environment variable |
--use-system-package=PYTHON_PACKAGE_NAME,DEBIAN_PACKAGE_NAME |
Exclude a Python package (the name before the comma) from conversion and replace references to the Python package with a specific Debian package name. This allows you to use system packages for specific Python requirements. |
--name-prefix=PREFIX |
Set the name prefix used during the name conversion from Python to Debian packages. Defaults to “python”. The name prefix and package names are always delimited by a dash. Can also be set using the environment variable |
--no-name-prefix=PYTHON_PACKAGE_NAME |
Exclude a Python package from having the name prefix applied during the package name conversion. This is useful to avoid awkward repetitions. |
--rename=PYTHON_PACKAGE_NAME,DEBIAN_PACKAGE_NAME |
Override the package name conversion algorithm for the given pair of package names. Useful if you don’t agree with the algorithm :-) |
--install-prefix=DIRECTORY |
Override the default system wide installation prefix. By setting this to anything other than “/usr” or “/usr/local” you change the way py2deb works. It will build packages with a file system layout similar to a Python virtual environment, except there will not be a Python executable: The packages are meant to be loaded by modifying Python’s module search path. Refer to the documentation for details. Can also be set using the environment variable |
--install-alternative=LINK,PATH |
Use Debian’s “update-alternatives” system to add an executable that’s installed in a custom installation prefix (see above) to the system wide executable search path. Refer to the documentation for details. |
--python-callback=EXPRESSION |
Set a Python callback to be called during the conversion process. Refer to
the documentation for details about the use of this feature and the syntax
of Can also be set using the environment variable |
--report-dependencies=FILENAME |
Add the Debian relationships needed to depend on the converted package(s) to the given control file. If the control file already contains relationships the additional relationships will be added to the control file; they won’t overwrite existing relationships. |
-y , --yes |
Instruct pip-accel to automatically install build time dependencies where possible. Refer to the pip-accel documentation for details. Can also be set using the environment variable |
-v , --verbose |
Make more noise :-). |
-h , --help |
Show this message and exit. |
py2deb.converter
¶
The py2deb.converter
module contains the high level conversion logic.
This module defines the PackageConverter
class which provides the
intended way for external Python code to interface with py2deb. The separation
between the PackageConverter
and PackageToConvert
classes is somewhat crude (because neither class can work without the other)
but the idea is to separate the high level conversion logic from the low level
conversion logic.
-
py2deb.converter.
MACHINE_ARCHITECTURE_MAPPING
= {'armv6l': 'armhf', 'i686': 'i386', 'x86_64': 'amd64'}¶ Mapping of supported machine architectures (a dictionary).
The keys are the names reported by
os.uname()
and the values are machine architecture labels used in the Debian packaging system.
-
class
py2deb.converter.
PackageConverter
(load_configuration_files=True, load_environment_variables=True, **options)[source]¶ The external interface of py2deb, the Python to Debian package converter.
Here’s an overview of the
PackageConverter
class:You can set the values of the
install_prefix
,lintian_enabled
,name_prefix
,prerelease_workaround
,python_callback
andrepository
properties by passing keyword arguments to the class initializer.-
__init__
(load_configuration_files=True, load_environment_variables=True, **options)[source]¶ Initialize a Python to Debian package converter.
Parameters: - load_configuration_files – When
True
(the default)load_default_configuration_files()
is called automatically. - load_environment_variables – When
True
(the default)load_environment_variables()
is called automatically. - options – Any keyword arguments are passed on to the initializer of the
PropertyManager
class.
- load_configuration_files – When
-
alternatives
[source]¶ The update-alternatives configuration (a set of tuples).
The value of this property is a set of
set
of tuples with two strings each (the strings passed toinstall_alternative()
). It’s used bycreate_alternatives()
andcleanup_alternatives()
during installation and removal of the generated package.Note
The
alternatives
property is alazy_property
. This property’s value is computed once (the first time it is accessed) and the result is cached.
-
debian_architecture
[source]¶ The Debian architecture of the current environment (a string).
This logic was originally implemented in py2deb but has since been moved to
deb_pkg_tools.utils.find_debian_architecture()
. This property remains as a convenient shortcut.Note
The
debian_architecture
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
install_prefix
[source]¶ The installation prefix for converted packages (a string, defaults to
/usr
).To generate system wide packages one of the installation prefixes
/usr
or/usr/local
should be used. Setting this property to any other value will create packages using a “custom installation prefix” that’s not included insys.path
by default.The installation prefix directory doesn’t have to exist on the system where the package is converted and will be automatically created on the system where the package is installed.
New in version 2.0: Before his property became part of the documented and public API in release 2.0 the setter
set_install_prefix()
was the only documented interface. The use of this setter is no longer required but still allowed.Note
The
install_prefix
property is amutable_property
. You can change the value of this property using normal attribute assignment syntax. To reset it to its default (computed) value you can usedel
ordelattr()
.
-
lintian_enabled
[source]¶ True
to enable Lintian,False
to disable it (defaults toTrue
).If this is
True
then Lintian will automatically be run after each package is converted to sanity check the result. Any problems found by Lintian are information intended for the operator, that is to say they don’t cause py2deb to fail.Note
The
lintian_enabled
property is amutable_property
. You can change the value of this property using normal attribute assignment syntax. To reset it to its default (computed) value you can usedel
ordelattr()
.
-
lintian_ignore
[source]¶ A list of strings with Lintian tags to ignore.
Note
The
lintian_ignore
property is alazy_property
. This property’s value is computed once (the first time it is accessed) and the result is cached.
-
name_mapping
[source]¶ Mapping of Python package names to Debian package names (a dictionary).
The
name_mapping
property enables renaming of packages during the conversion process. The keys as well as the values of the dictionary are expected to be lowercased strings.New in version 2.0: Before his property became part of the documented and public API in release 2.0 the
rename_package()
method was the only documented interface. The use of this setter is no longer required but still allowed.Note
The
name_mapping
property is alazy_property
. This property’s value is computed once (the first time it is accessed) and the result is cached.
-
name_prefix
[source]¶ The name prefix for converted packages (a string).
The default value of
name_prefix
depends on the Python interpreter that’s used to run py2deb:- On Python 2 the default name prefix is
python
. - On Python 3 the default name prefix is
python3
. - On PyPy 2 the default name prefix is
pypy
. - On PyPy 3 the default name prefix is
pypy3
.
When one of these default name prefixes is used, converted packages may conflict with system wide packages provided by Debian / Ubuntu. If this starts to bite then consider changing the name and installation prefix.
New in version 2.0: Before his property became part of the documented and public API in release 2.0 the setter
set_name_prefix()
was the only documented interface. The use of this setter is no longer required but still allowed.Release 2.0 introduced the alternative default name prefixes
pypy
andpython3
. Before that release the default name prefixpython
was (erroneously) used for all interpreters.Note
The
name_prefix
property is amutable_property
. You can change the value of this property using normal attribute assignment syntax. To reset it to its default (computed) value you can usedel
ordelattr()
.- On Python 2 the default name prefix is
-
prerelease_workaround
[source]¶ Whether to enable the pre-release workaround in
normalize_package_version()
(a boolean).By setting this to
False
converted version numbers will match those generated by py2deb 0.25 and earlier. Release 1.0 introduced the pre-release workaround and release 2.1 added the option to control backwards compatibility in this respect.Note
The
prerelease_workaround
property is amutable_property
. You can change the value of this property using normal attribute assignment syntax. To reset it to its default (computed) value you can usedel
ordelattr()
.
-
python_callback
[source]¶ An optional Python callback to be called during the conversion process (defaults to
None
).You can set the value of
python_callback
to one of the following:- A callable object (to be provided by Python API callers).
- A string containing the pathname of a Python script and the name of
a callable, separated by a colon. The Python script will be loaded
using
exec
. - A string containing the “dotted path” of a Python module and the
name of a callable, separated by a colon. The Python module will be
loaded using
importlib.import_module()
. - Any value that evaluates to
False
will clear an existing callback (if any).
The callback will be called at the very last step before the binary package’s metadata and contents are packaged as a
*.deb
archive. This allows arbitrary manipulation of resulting binary packages, e.g. changing package metadata or files to be packaged. An example use case:- Consider a dependency set (group of related packages) that has previously been converted and deployed.
- A new version of the dependency set switches from Python package A to Python package B, where the two Python packages contain conflicting files (installed in the same location). This could happen when switching to a project’s fork.
- A deployment of the new dependency set will conflict with existing installations due to “unrelated” packages (in the eyes of apt and dpkg) installing the same files.
- By injecting a custom Python callback the user can mark package B as
“replacing” and “breaking” package A. Refer to section 7.6 of the
Debian policy manual for details about the required binary control
fields (hint:
Replaces:
andBreaks:
).
Warning
The callback is responsible for not making changes that would break the installation of the converted dependency set!
Raises: The following exceptions can be raised when you set this property:
ValueError
when you set this to something that’s not callable and cannot be converted to a callable.ImportError
when the expression contains a dotted path that cannot be imported.
New in version 2.0: Before his property became part of the documented and public API in release 2.0 the setter
set_python_callback()
was the only documented way to configure the callback. The use of this setter is no longer required but still allowed.Note
The
python_callback
property is amutable_property
. You can change the value of this property using normal attribute assignment syntax. To reset it to its default (computed) value you can usedel
ordelattr()
.
-
repository
[source]¶ The directory where py2deb stores generated
*.deb
archives (aPackageRepository
object).By default the system wide temporary files directory is used as the repository directory (usually this is
/tmp
) but it’s expected that most callers will want to change this.New in version 2.0: Before his property became part of the documented and public API in release 2.0 the
set_repository()
method was the only documented interface. The use of this method is no longer required but still allowed.Note
The
repository
property is acustom_property
. You can change the value of this property using normal attribute assignment syntax. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
scripts
[source]¶ Mapping of Python package names to shell commands (a dictionary).
The keys of this dictionary are expected to be lowercased strings.
New in version 2.0: Before his property became part of the documented and public API in release 2.0 the
set_conversion_command()
method was the only documented interface. The use of this method is no longer required but still allowed.Note
The
scripts
property is alazy_property
. This property’s value is computed once (the first time it is accessed) and the result is cached.
-
system_packages
[source]¶ Mapping of Python package names to Debian package names (a dictionary).
The
system_packages
property enables Python packages in a requirement set to be excluded from the package conversion process. Any references to excluded packages are replaced with a reference to the corresponding system package. The keys as well as the values of the dictionary are expected to be lowercased strings.New in version 2.0: Before his property became part of the documented and public API in release 2.0 the
use_system_package()
method was the only documented interface. The use of this method is no longer required but still allowed.Note
The
system_packages
property is alazy_property
. This property’s value is computed once (the first time it is accessed) and the result is cached.
-
install_alternative
(link, path)[source]¶ Install system wide link for program installed in custom installation prefix.
Use Debian’s update-alternatives system to add an executable that’s installed in a custom installation prefix to the system wide executable search path using a symbolic link.
Parameters: - link – The generic name for the master link (a string). This is
the first argument passed to
update-alternatives --install
. - path – The alternative being introduced for the master link (a
string). This is the third argument passed to
update-alternatives --install
.
Raises: ValueError
when one of the paths is not provided (e.g. an empty string).If this is a bit vague, consider the following example:
$ py2deb --name-prefix=py2deb \ --no-name-prefix=py2deb \ --install-prefix=/usr/lib/py2deb \ --install-alternative=/usr/bin/py2deb,/usr/lib/py2deb/bin/py2deb \ py2deb==0.1
This example will convert py2deb and its dependencies using a custom name prefix and a custom installation prefix which means the
py2deb
program is not available on the default executable search path. This is why update-alternatives is used to create a symbolic link/usr/bin/py2deb
which points to the program inside the custom installation prefix.- link – The generic name for the master link (a string). This is
the first argument passed to
-
rename_package
(python_package_name, debian_package_name)[source]¶ Override the package name conversion algorithm for the given pair of names.
Parameters: - python_package_name – The name of a Python package as found on PyPI (a string).
- debian_package_name – The name of the converted Debian package (a string).
Raises: ValueError
when a package name is not provided (e.g. an empty string).
-
set_auto_install
(enabled)[source]¶ Enable or disable automatic installation of build time dependencies.
Parameters: enabled – Any value, evaluated using coerce_boolean()
.
-
set_conversion_command
(python_package_name, command)[source]¶ Set shell command to be executed during conversion process.
Parameters: - python_package_name – The name of a Python package as found on PyPI (a string).
- command – The shell command to execute (a string).
Raises: ValueError
when the package name or command is not provided (e.g. an empty string).The shell command is executed in the directory containing the Python module(s) that are to be installed by the converted package.
Warning
This functionality allows arbitrary manipulation of the Python modules to be installed by the converted package. It should clearly be considered a last resort, only for for fixing things like packaging issues with Python packages that you can’t otherwise change.
For example old versions of Fabric bundle a copy of Paramiko. Most people will never notice this because Python package managers don’t complain about this, they just blindly overwrite the files… Debian’s packaging system is much more strict and will consider the converted Fabric and Paramiko packages as conflicting and thus broken. In this case you have two options:
- Switch to a newer version of Fabric that no longer bundles Paramiko;
- Use the conversion command
rm -rf paramiko
to convert Fabric (yes this is somewhat brute force :-).
-
set_install_prefix
(directory)[source]¶ Set installation prefix to use during package conversion.
The installation directory doesn’t have to exist on the system where the package is converted.
Parameters: directory – The pathname of the directory where the converted packages should be installed (a string). Raises: ValueError
when no installation prefix is provided (e.g. an empty string).
-
set_lintian_enabled
(enabled)[source]¶ Enable or disable automatic Lintian checks after package building.
Parameters: enabled – Any value, evaluated using coerce_boolean()
.
-
set_name_prefix
(prefix)[source]¶ Set package name prefix to use during package conversion.
Parameters: prefix – The name prefix to use (a string). Raises: ValueError
when no name prefix is provided (e.g. an empty string).
-
set_python_callback
(expression)[source]¶ Set the value of
python_callback
.
-
set_repository
(directory)[source]¶ Set pathname of directory where py2deb stores converted packages.
Parameters: directory – The pathname of a directory (a string). Raises: ValueError
when the directory doesn’t exist.
-
use_system_package
(python_package_name, debian_package_name)[source]¶ Exclude a Python package from conversion.
Parameters: - python_package_name – The name of a Python package as found on PyPI (a string).
- debian_package_name – The name of the Debian package that should be used to fulfill the dependency (a string).
Raises: ValueError
when a package name is not provided (e.g. an empty string).References to the Python package are replaced with a specific Debian package name. This allows you to use system packages for specific Python requirements.
-
load_environment_variables
()[source]¶ Load configuration defaults from environment variables.
The following environment variables are currently supported:
$PY2DEB_CONFIG
$PY2DEB_REPOSITORY
$PY2DEB_NAME_PREFIX
$PY2DEB_INSTALL_PREFIX
$PY2DEB_AUTO_INSTALL
$PY2DEB_LINTIAN
-
load_configuration_file
(configuration_file)[source]¶ Load configuration defaults from a configuration file.
Parameters: configuration_file – The pathname of a configuration file (a string). Raises: Exception
when the configuration file cannot be loaded.Below is an example of the available options, I assume that the mapping between the configuration options and the setters of
PackageConverter
is fairly obvious (it should be :-).# The `py2deb' section contains global options. [py2deb] repository = /tmp name-prefix = py2deb install-prefix = /usr/lib/py2deb auto-install = on lintian = on # The `alternatives' section contains instructions # for Debian's `update-alternatives' system. [alternatives] /usr/bin/py2deb = /usr/lib/py2deb/bin/py2deb # Sections starting with `package:' contain conversion options # specific to a package. [package:py2deb] no-name-prefix = true
Note that the configuration options shown here are just examples, they are not the configuration defaults (they are what I use to convert py2deb itself). Package specific sections support the following options:
- no-name-prefix:
- A boolean indicating whether the configured name prefix should be
applied or not. Understands
true
andfalse
(false
is the default and you only need this option to change the default). - rename:
- Gives an override for the package name conversion algorithm (refer to
rename_package()
for details). - script:
- Set a shell command to be executed during the conversion process
(refer to
set_conversion_command()
for details).
-
load_default_configuration_files
()[source]¶ Load configuration options from default configuration files.
The following default configuration file locations are checked:
/etc/py2deb.ini
~/.py2deb.ini
Raises: Exception
when a configuration file exists but cannot be loaded.
-
convert
(pip_install_arguments)[source]¶ Convert one or more Python packages to Debian packages.
Parameters: pip_install_arguments – The command line arguments to the pip install
command.Returns: A tuple with two lists: - A list of strings containing the pathname(s) of the generated Debian package package archive(s).
- A list of strings containing the Debian package relationship(s) required to depend on the converted package(s).
Raises: DuplicateFilesFound
if two converted package archives contain the same files (certainly not what you want within a set of dependencies).Here’s an example of what’s returned:
>>> from py2deb.converter import PackageConverter >>> converter = PackageConverter() >>> archives, relationships = converter.convert(['py2deb']) >>> print(archives) ['/tmp/python-py2deb_0.18_all.deb'] >>> print(relationships) ['python-py2deb (=0.18)']
-
get_source_distributions
(pip_install_arguments)[source]¶ Use pip-accel to download and unpack Python source distributions.
Retries several times if a download fails (so it doesn’t fail immediately when a package index server returns a transient error).
Parameters: pip_install_arguments – The command line arguments to the pip install
command (an iterable of strings).Returns: A generator of PackageToConvert
objects.Raises: When downloading fails even after several retries this function raises pip.exceptions.DistributionNotFound
. This function can also raise other exceptions raised by pip because it uses pip-accel to call pip (as a Python API).
-
transform_name
(python_package_name, *extras)[source]¶ Transform Python package name to Debian package name.
Parameters: - python_package_name – The name of a Python package as found on PyPI (a string).
- extras – Any extras requested to be included (a tuple of strings).
Returns: The transformed name (a string).
Examples:
>>> from py2deb.converter import PackageConverter >>> converter = PackageConverter() >>> converter.transform_name('example') 'python-example' >>> converter.set_name_prefix('my-custom-prefix') >>> converter.transform_name('example') 'my-custom-prefix-example' >>> converter.set_name_prefix('some-web-app') >>> converter.transform_name('raven', 'flask') 'some-web-app-raven-flask'
-
transform_version
(package_to_convert, python_requirement_name, python_requirement_version)[source]¶ Transform a Python requirement version to a Debian version number.
Parameters: - package_to_convert – The
PackageToConvert
whose requirement is being transformed. - python_requirement_name – The name of a Python package as found on PyPI (a string).
- python_requirement_version – The required version of the Python package (a string).
Returns: The transformed version (a string).
This method is a wrapper for
normalize_package_version()
that takes care of one additional quirk to ensure compatibility with pip. Explaining this quirk requires a bit of context:- When package A requires package B (via
install_requires
) and package A absolutely pins the required version of package B using one or more trailing zeros (e.g.B==1.0.0
) but the actual version number of package B (embedded in the metadata of package B) contains less trailing zeros (e.g.1.0
) then pip will not complain but silently fetch version1.0
of package B to satisfy the requirement. - However this doesn’t change the absolutely pinned version in the
install_requires
metadata of package A. - When py2deb converts the resulting requirement set, the dependency of
package A is converted as
B (= 1.0.0)
. The resulting packages will not be installable because apt considers1.0
to be different from1.0.0
.
This method analyzes the requirement set to identify occurrences of this quirk and strip trailing zeros in
install_requires
metadata that would otherwise result in converted packages that cannot be installed.- package_to_convert – The
-
py2deb.hooks
¶
The py2deb.hooks
module contains post-installation and pre-removal hooks.
This module is a bit special in the sense that it is a part of the py2deb code base but it is embedded in the Debian binary packages generated by py2deb as a post-installation and pre-removal hook.
Because this module is embedded in generated packages it can’t use the external dependencies of the py2deb project, it needs to restrict itself to Python’s standard library.
My reasons for including this Python script as a “proper module” inside the py2deb project:
- It encourages proper documentation of the functionality in this module, which enables users to read through the documentation without having to dive into py2deb’s source code.
- It makes it easier to unit test the individual functions in this script without jumping through too many hoops (I greatly value test suite coverage).
The generate_maintainer_script()
method is responsible for converting this module into a post-installation or
pre-removal script. It does so by reading this module’s source code and
appending a call to post_installation_hook()
or
pre_removal_hook()
at the bottom.
-
py2deb.hooks.
post_installation_hook
(package_name, alternatives, modules_directory, namespaces, namespace_style)[source]¶ Generic post-installation hook for packages generated by py2deb.
Parameters: - package_name – The name of the system package (a string).
- alternatives – The relevant subset of values in
alternatives
. - modules_directory – The absolute pathname of the directory where Python modules are installed (a string).
- namespaces – The namespaces used by the package (a list of tuples in the format
generated by
namespaces
). - namespace_style – The style of namespaces being used (one of the strings returned by
namespace_style
).
Uses the following functions to implement everything py2deb needs from the post-installation maintainer script:
-
py2deb.hooks.
pre_removal_hook
(package_name, alternatives, modules_directory, namespaces)[source]¶ Generic pre-removal hook for packages generated by py2deb.
Parameters: - package_name – The name of the system package (a string).
- alternatives – The relevant subset of values in
alternatives
. - modules_directory – The absolute pathname of the directory where Python modules are installed (a string).
- namespaces – The namespaces used by the package (a list of tuples in the format
generated by
py2deb.package.PackageToConvert.namespaces
).
Uses the following functions to implement everything py2deb needs from the pre-removal maintainer script:
-
py2deb.hooks.
find_installed_files
(package_name)[source]¶ Find the files installed by a Debian system package.
Parameters: package_name – The name of the system package (a string). Returns: A list of absolute filenames (strings). Uses the
dpkg -L
command.
-
py2deb.hooks.
generate_bytecode_files
(package_name, installed_files)[source]¶ Generate Python byte code files for the
*.py
files installed by a package.Parameters: - package_name – The name of the system package (a string).
- installed_files – A list of strings with the absolute pathnames of installed files.
Uses
py_compile.compile()
to generate bytecode files.
-
py2deb.hooks.
cleanup_bytecode_files
(package_name, installed_files)[source]¶ Cleanup Python byte code files generated when a package was installed.
Parameters: - package_name – The name of the system package (a string).
- installed_files – A list of strings with the absolute pathnames of installed files.
-
py2deb.hooks.
cleanup_bytecode_helper
(filenames)[source]¶ Cleanup Python byte code files.
Parameters: filenames – A list of strings with the absolute pathnames of installed files. Returns: The number of files that were removed (an integer).
-
py2deb.hooks.
remove_empty_directory
(directory)[source]¶ Remove a directory if it is empty.
Parameters: directory – The pathname of the directory (a string).
-
py2deb.hooks.
find_bytecode_files
(python_file)[source]¶ Find the byte code file(s) generated from a Python file.
Parameters: python_file – The pathname of a *.py
file (a string).Returns: A generator of pathnames (strings). Starting from Python 3.2 byte code files are written according to PEP 3147 which also defines
imp.cache_from_source()
to locate (optimized) byte code files. When this function is available it is used, when it’s not available the corresponding*.pyc
and/or*.pyo
files are located manually byfind_bytecode_files()
.
-
py2deb.hooks.
create_alternatives
(package_name, alternatives)[source]¶ Use update-alternatives to install a global symbolic link to a program.
Parameters: - package_name – The name of the system package (a string).
- alternatives – The relevant subset of values in
alternatives
.
Install a program available inside the custom installation prefix in the system wide executable search path using the Debian alternatives system.
-
py2deb.hooks.
cleanup_alternatives
(package_name, alternatives)[source]¶ Cleanup the alternatives that were previously installed by
create_alternatives()
.Parameters: - package_name – The name of the system package (a string).
- alternatives – The relevant subset of values in
alternatives
.
-
py2deb.hooks.
initialize_namespaces
(package_name, modules_directory, namespaces, namespace_style)[source]¶ Initialize Python namespace packages so they can be imported in the normal way.
Both pkgutil-style and pkg_resources-style namespace packages are supported (although support for the former was added in 2020 whereas support for the latter has existed since 2015).
Parameters: - package_name – The name of the system package (a string).
- modules_directory – The absolute pathname of the directory where Python modules are installed (a string).
- namespaces – The namespaces used by the package (a list of tuples in the format
generated by
namespaces
). - namespace_style – The style of namespaces being used (one of the strings returned by
namespace_style
).
-
py2deb.hooks.
cleanup_namespaces
(package_name, modules_directory, namespaces)[source]¶ Clean up Python namespace packages previously initialized using
initialize_namespaces()
.Parameters: - package_name – The name of the system package (a string).
- modules_directory – The absolute pathname of the directory where Python modules are installed (a string).
- namespaces – The namespaces used by the package (a list of tuples in the format
generated by
namespaces
).
-
class
py2deb.hooks.
NameSpaceReferenceCount
(modules_directory)[source]¶ Persistent reference counting for initialization of namespace packages.
-
__init__
(modules_directory)[source]¶ Initialize a
NameSpaceReferenceCount
object.Parameters: modules_directory – The absolute pathname of the directory where Python modules are installed (a string).
-
py2deb.namespaces
¶
Python package namespace auto detection.
This module is used by py2deb to detect pkgutil-style namespace
packages to enable special handling of the __init__.py
files involved,
because these would otherwise cause dpkg file conflicts.
Note
The __init__.py
files that define pkgutil-style namespace
packages can contain arbitrary Python code (including comments and
with room for minor differences in coding style) which makes reliable
identification harder than it should be. We use ast.parse()
to look for hints and only when we find enough hints do we consider a
module to be part of a pkgutil-style namespace package.
-
py2deb.namespaces.
find_pkgutil_namespaces
(directory)[source]¶ Find the pkgutil-style namespace packages in an unpacked Python distribution archive.
Parameters: directory – The pathname of a directory containing an unpacked Python distribution archive (a string). Returns: A generator of dictionaries similar to those returned by find_python_modules()
.This function combines
find_python_modules()
andfind_pkgutil_ns_hints()
to make it easy for callers to identify the namespace packages defined by an unpacked Python distribution archive.
-
py2deb.namespaces.
find_pkgutil_ns_hints
(tree)[source]¶ Analyze an AST for hints that we’re dealing with a Python module that defines a pkgutil-style namespace package.
Parameters: tree – The result of ast.parse()
when run on a Python module (which is assumed to be an__init__.py
file).Returns: A set
of strings where each string represents a hint (an indication) that we’re dealing with a pkgutil-style namespace module. No single hint can definitely tell us, but a couple of unique hints taken together should provide a reasonable amount of confidence (at least this is the idea, how well this works in practice remains to be seen).
-
py2deb.namespaces.
find_python_modules
(directory)[source]¶ Find the Python modules in an unpacked Python distribution archive.
Parameters: directory – The pathname of a directory containing an unpacked Python distribution archive (a string). Returns: A list of dictionaries with the following key/value pairs: abspath
gives the absolute pathname of a Python module (a string).relpath
gives the pathname of a Python module (a string) relative to the intended installation directory.name
gives the dotted name of a Python module (a string).
This function works as follows:
- Use
os.walk()
to recursively search for__init__.py
files in the directory given by the caller and collect the relative pathnames of the directories containing the__init__.py
files. - Use
os.path.commonprefix()
to determine the common prefix of the resulting directory pathnames. - Use
os.path.split()
to partition the common prefix into an insignificant part (all but the final pathname component) and the significant part (the final pathname component). - Strip the insignificant part of the common prefix from the directory pathnames we collected in step 1.
- Replace
os.sep
occurrences with dots to convert (what remains of) the directory pathnames to “dotted paths”.
py2deb.package
¶
The py2deb.package
module contains the low level conversion logic.
This module defines the PackageToConvert
class which implements the
low level logic of converting a single Python package to a Debian package. The
separation between the PackageConverter
and PackageToConvert
classes is somewhat crude (because neither class can work without the other)
but the idea is to separate the high level conversion logic from the low level
conversion logic.
-
class
py2deb.package.
PackageToConvert
(converter, requirement)[source]¶ Abstraction for Python packages to be converted to Debian packages.
Contains a
pip_accel.req.Requirement
object, has a back reference to thePackageConverter
and provides all of the Debian package metadata implied by the Python package metadata.Here’s an overview of the
PackageToConvert
class:-
__init__
(converter, requirement)[source]¶ Initialize a package to convert.
Parameters: - converter – The
PackageConverter
that holds the user options and knows how to transform package names. - requirement – A
pip_accel.req.Requirement
object (created byget_source_distributions()
).
- converter – The
-
debian_dependencies
[source]¶ Find Debian dependencies of Python package.
Converts Python version specifiers to Debian package relationships.
Returns: A list with Debian package relationships (strings) in the format of the Depends:
line of a Debian packagecontrol
file. Based onpython_requirements
.Note
The
debian_dependencies
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
debian_description
[source]¶ Get a minimal description for the converted Debian package.
Includes the name of the Python package and the date at which the package was converted.
Note
The
debian_description
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
debian_maintainer
[source]¶ Get the package maintainer name and e-mail address.
The name and e-mail address are combined into a single string that can be embedded in a Debian package (in the format
name <email>
). The metadata is retrieved as follows:- If the environment variable
$DEBFULLNAME
is defined then its value is taken to be the name of the maintainer (this logic was added in #25). If$DEBEMAIL
is set as well that will be incorporated into the result. - The Python package maintainer name and email address are looked up in the package metadata and if found these are used.
- The Python package author name and email address are looked up in the package metadata and if found these are used.
- Finally if all else fails the text “Unknown” is returned.
Note
The
debian_maintainer
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.- If the environment variable
-
debian_name
[source]¶ The name of the converted Debian package (a string).
Note
The
debian_name
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
debian_provides
[source]¶ A symbolic name for the role the package provides (a string).
When a Python package provides “extras” those extras are encoded into the name of the generated Debian package, to represent the additional dependencies versus the package without extras.
However the package including extras definitely also satisfies a dependency on the package without extras, so a
Provides: ...
control field is added to the Debian package that contains the converted package name without extras.Note
The
debian_provides
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
debian_version
[source]¶ The version of the Debian package (a string).
Reformats
python_version
usingnormalize_package_version()
.Note
The
debian_version
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
existing_archive
[source]¶ Find
*.deb
archive for current package name and version.Returns: The pathname of the found archive (a string) or None
if no existing archive is found.Note
The
existing_archive
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
has_custom_install_prefix
[source]¶ Check whether package is being installed under custom installation prefix.
Returns: True
if the package is being installed under a custom installation prefix,False
otherwise.A custom installation prefix is an installation prefix whose
bin
directory is (likely) not available on the default executable search path (the environment variable$PATH
).Note
The
has_custom_install_prefix
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
metadata
[source]¶ Get the Python package metadata.
The metadata is loaded from the
PKG-INFO
file generated by pip when it unpacked the source distribution archive. Results in a pkginfo.UnpackedSDist object.Note
The
metadata
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
namespace_packages
[source]¶ Get the Python namespace packages defined by the Python package.
Returns: A list of dotted names (strings). When
setuptools_namespaces
is available that will be used, otherwise we fall back topkgutil_namespaces
. This order of preference may be switched in the future, but not untilpkgutil_namespaces
has seen more thorough testing:- Support for
setuptools_namespaces
was added to py2deb in release 0.22 (2015) so this is fairly mature code that has seen thousands of executions between 2015-2020. - Support for
pkgutil_namespaces
was added in August 2020 so this is new (and complicated) code that hasn’t seen a lot of use yet. Out of conservativeness on my part this is nested in the ‘else’ branch (to reduce the scope of potential regressions).
Additionally computing
setuptools_namespaces
is very cheap (all it has to do is search for and read one text file) compared topkgutil_namespaces
(which needs to recursively search a directory tree for__init__.py
files and parse each file it finds to determine whether it’s relevant).Note
The
namespace_packages
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.- Support for
-
namespace_style
[source]¶ Get the style of Python namespace packages in use by this package.
Returns: One of the strings pkgutil
,setuptools
ornone
.Note
The
namespace_style
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
namespaces
[source]¶ Get the Python namespace packages defined by the Python package.
Returns: A list of unique tuples of strings. The tuples are sorted by increasing length (the number of strings in each tuple) so that e.g. zope
is guaranteed to sort beforezope.app
.This property processes the result of
namespace_packages
into a more easily usable format. Here’s an example of the difference betweennamespace_packages
andnamespaces
:>>> from py2deb.converter import PackageConverter >>> converter = PackageConverter() >>> package = next(converter.get_source_distributions(['zope.app.cache'])) >>> package.namespace_packages ['zope', 'zope.app'] >>> package.namespaces [('zope',), ('zope', 'app')]
The value of this property is used by
initialize_namespaces()
andcleanup_namespaces()
during installation and removal of the generated package.Note
The
namespaces
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
pkgutil_namespaces
[source]¶ Namespace packages declared through
pkgutil
.Returns: A list of dictionaries similar to those returned by find_pkgutil_namespaces()
.For details about this type of namespace packages please refer to <https://packaging.python.org/guides/packaging-namespace-packages/#pkgutil-style-namespace-packages>.
The implementation of this property lives in a separate module (refer to
find_pkgutil_namespaces()
) in order to compartmentalize the complexity of reliably identifying namespace packages defined usingpkgutil
.Note
The
pkgutil_namespaces
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
python_name
¶ The name of the Python package (a string).
-
python_requirements
[source]¶ Find the installation requirements of the Python package.
Returns: A list of pkg_resources.Requirement objects. This property used to be implemented by manually parsing the
requires.txt
file generated by pip when it unpacks a distribution archive.While this implementation was eventually enhanced to supported named extras, it never supported environment markers.
Since then this property has been reimplemented to use pkg_resources.Distribution.requires() so that environment markers are supported.
If the new implementation fails the property falls back to the old implementation (as a precautionary measure to avoid unexpected side effects of the new implementation).
Note
The
python_requirements
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
python_requirements_fallback
[source]¶ Fall-back implementation of
python_requirements
.Note
The
python_requirements_fallback
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
python_version
¶ The version of the Python package (a string).
-
setuptools_namespaces
[source]¶ Namespace packages declared through setuptools.
Returns: A list of dotted names (strings). For details about this type of namespace packages please refer to <https://packaging.python.org/guides/packaging-namespace-packages/#pkg-resources-style-namespace-packages>.
Note
The
setuptools_namespaces
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
vcs_revision
[source]¶ The VCS revision of the Python package.
This works by parsing the
.hg_archival.txt
file generated by thehg archive
command so for now this only supports Python source distributions exported from Mercurial repositories.Note
The
vcs_revision
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
convert
()[source]¶ Convert current package from Python package to Debian package.
Returns: The pathname of the generated *.deb
archive.
-
determine_package_architecture
(has_shared_object_files)[source]¶ Determine binary architecture that Debian package should be tagged with.
Parameters: has_shared_objects – True
if the package contains*.so
files,False
otherwise.Returns: The architecture string, ‘all’ or one of the values of debian_architecture
.If a package contains
*.so
files we’re dealing with a compiled Python module. To determine the applicable architecture, we take the Debian architecture reported bydebian_architecture
.
-
find_egg_info_file
(pattern='')[source]¶ Find pip metadata files in unpacked source distributions.
Parameters: pattern – The glob
pattern to search for (a string).Returns: A list of matched filenames (strings). When pip unpacks a source distribution archive it creates a directory
pip-egg-info
which contains the package metadata in a declarative and easy to parse format. This method finds such metadata files.
-
generate_maintainer_script
(filename, python_executable, function, **arguments)[source]¶ Generate a post-installation or pre-removal maintainer script.
Parameters: - filename – The pathname of the maintainer script (a string).
- python_executable – The absolute pathname of the Python interpreter on the target system (a string).
- function – The name of the function in the
py2deb.hooks
module to be called when the maintainer script is run (a string). - arguments – Any keyword arguments to the function in the
py2deb.hooks
are serialized to text usingrepr()
and embedded inside the generated maintainer script.
-
load_control_field_overrides
(control_fields)[source]¶ Apply user defined control field overrides.
Parameters: control_fields – The control field defaults constructed by py2deb (a deb_pkg_tools.deb822.Deb822
object).Returns: The merged defaults and overrides (a deb_pkg_tools.deb822.Deb822
object).Looks for an
stdeb.cfg
file inside the Python package’s source distribution and if found it merges the overrides into the control fields that will be embedded in the generated Debian binary package.This method first applies any overrides defined in the
DEFAULT
section and then it applies any overrides defined in the section whose normalized name (seepackage_names_match()
) matches that of the Python package.
-
transform_binary_dist
(interpreter)[source]¶ Build Python package and transform directory layout.
Parameters: interpreter – The absolute pathname of the Python interpreter that should be referenced by executable scripts in the binary distribution (a string). Returns: An iterable of tuples with two values each: - A
tarfile.TarInfo
object; - A file-like object.
Builds the Python package (using pip-accel) and changes the names of the files included in the package to match the layout corresponding to the given conversion options.
- A
-
update_shebang
(handle, interpreter)[source]¶ Update the shebang of executable scripts.
Parameters: - handle – A file-like object containing an executable.
- interpreter – The absolute pathname of the Python interpreter that should be referenced by the script (a string).
Returns: A file-like object.
Normally pip-accel is responsible for updating interpreter references in executable scripts, however there’s a bug in pip-accel where it assumes that the string ‘python’ will appear literally in the shebang (which isn’t true when running on PyPy).
Note
Of course this bug should be fixed in pip-accel however that project is in limbo while I decide whether to reinvigorate or kill it (the second of which implies needing to make a whole lot of changes to py2deb).
-
py2deb.tests
¶
The py2deb.tests
module contains the automated tests for py2deb.
The makefile in the py2deb git repository uses pytest to run the test suite
because of pytest’s great error reporting. Nevertheless the test suite is
written to be compatible with the unittest
module (part of Python’s
standard library) so that the test suite can be run without additional external
dependencies.
-
py2deb.tests.
execute
()¶ Execute an external command and make sure it succeeded.
Parameters: - command – All positional arguments are passed on to the constructor
of
ExternalCommand
. - options – All keyword arguments are passed on to the constructor of
ExternalCommand
.
Returns: Refer to
execute_prepared()
.Raises: ExternalCommandFailed
when the command exits with a nonzero exit code (andcheck
isTrue
).If
asynchronous
isTrue
thenexecute()
will automatically start the external command for you usingstart()
(but it won’t wait for it to end). If you want to create anExternalCommand
object instance without immediately starting the external command then you can useExternalCommand
directly.Some examples
By default the status code of the external command is returned as a boolean:
>>> from executor import execute >>> execute('true') True
However when an external command exits with a nonzero status code an exception is raised, this is intended to “make it easy to do the right thing” (never forget to check the status code of an external command without having to write a lot of repetitive code):
>>> execute('false') Traceback (most recent call last): File "executor/__init__.py", line 124, in execute cmd.start() File "executor/__init__.py", line 516, in start self.wait() File "executor/__init__.py", line 541, in wait self.check_errors() File "executor/__init__.py", line 568, in check_errors raise ExternalCommandFailed(self) executor.ExternalCommandFailed: External command failed with exit code 1! (command: false)
What’s also useful to know is that exceptions raised by
execute()
exposecommand
andreturncode
attributes. If you know a command is likely to exit with a nonzero status code and you wantexecute()
to simply return a boolean you can do this instead:>>> execute('false', check=False) False
- command – All positional arguments are passed on to the constructor
of
-
py2deb.tests.
setUpModule
()[source]¶ Prepare the test suite.
This function does two things:
- Sets up verbose logging to the terminal. When a test fails the logging output can help to perform a post-mortem analysis of the failure in question (even when its hard to reproduce locally). This is especially useful when debugging remote test failures, whether they happened on Travis CI or a user’s local system.
- Creates temporary directories where the pip download cache and the
pip-accel binary cache are located. Isolating the pip-accel binary cache
from the user’s system is meant to ensure that the tests are as
independent from the user’s system as possible. The function
tearDownModule()
is responsible for cleaning up the temporary directory after the test suite finishes.
-
py2deb.tests.
tearDownModule
()[source]¶ Clean up temporary directories created by
setUpModule()
.
-
py2deb.tests.
create_temporary_directory
()[source]¶ Create a temporary directory for the test suite to use.
The created temporary directory will be cleaned up by
tearDownModule()
when the test suite is being torn down.Returns: The pathname of the created temporary directory (a string).
-
class
py2deb.tests.
PackageConverterTestCase
(*args, **kw)[source]¶ unittest
compatible container for the test suite of py2deb.-
test_argument_validation
()[source]¶ Test argument validation done by setters of
py2deb.converter.PackageConverter
.
-
test_conversion_of_simple_package
()[source]¶ Convert a simple Python package without any dependencies.
Converts coloredlogs and sanity checks the result. Performs several static checks on the metadata and contents of the resulting package archive.
-
test_custom_conversion_command
()[source]¶ Convert a simple Python package that requires a custom conversion command.
Converts Fabric and sanity checks the result. For details please refer to
py2deb.converter.PackageConverter.set_conversion_command()
.
-
test_duplicate_files_check
()[source]¶ Ensure that py2deb checks for duplicate file conflicts within dependency sets.
Converts a version of Fabric that bundles Paramiko but also includes Paramiko itself in the dependency set, thereby causing a duplicate file conflict, to verify that py2deb recognizes duplicate file conflicts.
-
test_conversion_of_package_with_dependencies
()[source]¶ Convert a non trivial Python package with several dependencies.
Converts deb-pkg-tools to a Debian package archive and sanity checks the result. Performs static checks on the metadata (dependencies) of the resulting package archive.
-
test_conversion_of_extras
()[source]¶ Convert a package with extras.
Converts
raven[flask]==3.6.0
and sanity checks the result.
-
test_conversion_of_environment_markers
()[source]¶ Convert a package with installation requirements using environment markers.
Converts
weasyprint==0.42
and sanity checks that thecairosvg
dependency is present.
-
test_python_requirements_fallback
()[source]¶ Test the fall-back implementation of the
python_requirements
property.
-
test_conversion_of_binary_package
()[source]¶ Convert a package that includes a
*.so
file (a shared object file).Converts
setproctitle==1.1.8
and sanity checks the result. The goal of this test is to verify that pydeb properly handles packages with binary components (including dpkg-shlibdeps magic). This explains why I chose the setproctitle package:- This package is known to require a compiled shared object file for proper functioning.
- Despite requiring a compiled shared object file the package is fairly lightweight and has little dependencies so including this test on every run of the test suite won’t slow things down so much that it becomes annoying.
- The package is documented to support Python 3.x as well which means we can run this test on all supported Python versions.
-
test_converted_package_installation
()[source]¶ Install a converted package on the test system and verify that it works.
This test only runs on Travis CI, it’s a functional test that uses py2deb to convert a Python package to a Debian package, installs that package on the local system and verifies that the system wide Python installation can successfully import the installed package.
-
test_conversion_of_binary_package_with_executable
()[source]¶ Convert a package that includes a binary executable file.
Converts
uwsgi==2.0.17.1
and sanity checks the result. The goal of this test is to verify that pydeb preserves binary executables instead of truncating them as it did until issue 9 was reported.
-
test_install_requires_version_munging
()[source]¶ Convert a package with a requirement whose version is “munged” by pip.
Refer to
py2deb.converter.PackageConverter.transform_version()
for details about the purpose of this test.
-
test_conversion_with_system_package
()[source]¶ Convert a package and map one of its requirements to a system package.
-
test_conversion_of_isolated_packages
()[source]¶ Convert a group of packages with a custom name and installation prefix.
Converts pip-accel and its dependencies to a group of “isolated Debian packages” that are installed with a custom name prefix and installation prefix and sanity check the result. Also tests the
--rename=FROM,TO
command line option. Performs static checks on the metadata and contents of the resulting package archive.
-
test_conversion_with_configuration_file
()[source]¶ Convert a group of packages based on the settings in a configuration file.
Repeats the same test as
test_conversion_of_isolated_packages()
but instead of using command line options the conversion process is configured using a configuration file.
-
check_converted_pip_accel_packages
(directory)[source]¶ Check a group of packages converted with a custom name and installation prefix.
Check the results of
test_conversion_of_isolated_packages()
andtest_conversion_with_configuration_file()
.
-
test_python_callback_from_api
()[source]¶ Test Python callback logic (registered through the Python API).
-
test_python_callback_from_dotted_path
()[source]¶ Test Python callback logic (through a dotted path expression).
-
test_python_callback_from_filename
()[source]¶ Test Python callback logic (through a filename expression).
-
check_python_callback
(expression)[source]¶ Test for Python callback logic manipulating the build of a package.
-
test_find_installed_files
()[source]¶ Test the
py2deb.hooks.find_installed_files()
function.
-
test_bytecode_generation
()[source]¶ Test byte code generation and cleanup.
This tests the
generate_bytecode_files()
andcleanup_bytecode_files()
functions.
-
test_namespace_initialization
()[source]¶ Test namespace package initialization and cleanup.
This tests the
initialize_namespaces()
andcleanup_namespaces()
functions.
-
test_pkgutil_namespaces
()[source]¶ Test compatibility with
pkgutil
style namespace packages.This test fails on py2deb <= 4.0 because the two packages involved both define the same pkgutil-style namespace package and this causes a file conflict that’s detected by py2deb, in the form of a
DuplicateFilesFound
exception:deb_pkg_tools.checks.DuplicateFilesFound: Found 1 duplicate file in 2 package archives! ------------------------------------------------------------------------------- Found 1 conflict between 2 packages: 1. /tmp/tmpgqz6ettd/python3-backports-functools-lru-cache_1.6.1_all.deb 2. /tmp/tmpgqz6ettd/python3-configparser_3.7.4_all.deb These packages contain 1 conflict: 1. /usr/lib/python3.6/dist-packages/backports/__init__.py -------------------------------------------------------------------------------
-
test_post_install_hook
()[source]¶ Test the
post_installation_hook()
function.
-
test_pre_removal_hook
()[source]¶ Test the
pre_removal_hook()
function.
-
run_post_install_hook
(directory, namespace_style)[source]¶ Helper for
test_post_install_hook()
andtest_pre_removal_hook()
.
-
-
py2deb.tests.
find_package_archive
(available_archives, package_name)[source]¶ Find the
*.deb
archive of a specific package.Parameters: - available_packages – The pathnames of the available package archives (a list of strings).
- package_name – The name of the package whose archive file we’re interested in (a string).
Returns: The pathname of the package archive (a string).
Raises: exceptions.AssertionError
if zero or more than one package archive is found.
-
py2deb.tests.
find_file
(contents, pattern)[source]¶ Find the file matching the given filename pattern.
Searches the dictionary of Debian package archive entries reported by
deb_pkg_tools.package.inspect_package()
.Parameters: - contents – The dictionary of package archive entries.
- pattern – The filename pattern to match (
fnmatch
syntax).
Returns: The metadata of the matched file.
Raises: exceptions.AssertionError
if zero or more than one archive entry is found.
py2deb.utils
¶
The py2deb.utils
module contains miscellaneous code.
-
py2deb.utils.
integer_pattern
= <_sre.SRE_Pattern object>¶ Compiled regular expression to match a consecutive run of digits.
-
py2deb.utils.
PYTHON_EXECUTABLE_PATTERN
= <_sre.SRE_Pattern object>¶ A compiled regular expression to match Python interpreter executable names.
The following are examples of program names that match this pattern:
- pypy
- pypy2.7
- pypy3
- python
- python2
- python2.7
- python3m
-
class
py2deb.utils.
PackageRepository
(directory)[source]¶ Very simply abstraction for a directory containing
*.deb
archives.Used by
py2deb.converter.PackageConverter
to recognize which Python packages have previously been converted (and so can be skipped).Here’s an overview of the
PackageRepository
class:Superclass: PropertyManager
Special methods: __init__()
Public methods: get_package()
Properties: archives
anddirectory
When you initialize a
PackageRepository
object you are required to provide a value for thedirectory
property. You can set the value of thedirectory
property by passing a keyword argument to the class initializer.-
__init__
(directory)[source]¶ Initialize a
PackageRepository
object.Parameters: directory – The pathname of a directory containing *.deb
archives (a string).
-
archives
[source]¶ A sorted list of package archives in
directory
.The value of
archives
is computed usingdeb_pkg_tools.package.find_package_archives()
.An example:
>>> from py2deb import PackageRepository >>> repo = PackageRepository('/tmp') >>> repo.archives [PackageFile(name='py2deb', version='0.1', architecture='all', filename='/tmp/py2deb_0.1_all.deb'), PackageFile(name='py2deb-cached-property', version='0.1.5', architecture='all', filename='/tmp/py2deb-cached-property_0.1.5_all.deb'), PackageFile(name='py2deb-chardet', version='2.2.1', architecture='all', filename='/tmp/py2deb-chardet_2.2.1_all.deb'), PackageFile(name='py2deb-coloredlogs', version='0.5', architecture='all', filename='/tmp/py2deb-coloredlogs_0.5_all.deb'), PackageFile(name='py2deb-deb-pkg-tools', version='1.20.4', architecture='all', filename='/tmp/py2deb-deb-pkg-tools_1.20.4_all.deb'), PackageFile(name='py2deb-docutils', version='0.11', architecture='all', filename='/tmp/py2deb-docutils_0.11_all.deb'), PackageFile(name='py2deb-executor', version='1.2', architecture='all', filename='/tmp/py2deb-executor_1.2_all.deb'), PackageFile(name='py2deb-html2text', version='2014.4.5', architecture='all', filename='/tmp/py2deb-html2text_2014.4.5_all.deb'), PackageFile(name='py2deb-humanfriendly', version='1.8.2', architecture='all', filename='/tmp/py2deb-humanfriendly_1.8.2_all.deb'), PackageFile(name='py2deb-pkginfo', version='1.1', architecture='all', filename='/tmp/py2deb-pkginfo_1.1_all.deb'), PackageFile(name='py2deb-python-debian', version='0.1.21-nmu2', architecture='all', filename='/tmp/py2deb-python-debian_0.1.21-nmu2_all.deb'), PackageFile(name='py2deb-six', version='1.6.1', architecture='all', filename='/tmp/py2deb-six_1.6.1_all.deb')]
Note
The
archives
property is acached_property
. This property’s value is computed once (the first time it is accessed) and the result is cached. To clear the cached value you can usedel
ordelattr()
.
-
directory
[source]¶ The pathname of a directory containing
*.deb
archives (a string).Note
The
directory
property is arequired_property
. You are required to provide a value for this property by calling the constructor of the class that defines the property with a keyword argument named directory (unless a custom constructor is defined, in this case please refer to the documentation of that constructor). You can change the value of this property using normal attribute assignment syntax.
-
get_package
(package, version, architecture)[source]¶ Find a package in the repository.
Parameters: - package – The name of the package (a string).
- version – The version of the package (a string).
- architecture – The architecture of the package (a string).
Returns: A
deb_pkg_tools.package.PackageFile
object orNone
.Here’s an example:
>>> from py2deb import PackageRepository >>> repo = PackageRepository('/tmp') >>> repo.get_package('py2deb', '0.1', 'all') PackageFile(name='py2deb', version='0.1', architecture='all', filename='/tmp/py2deb_0.1_all.deb')
-
-
class
py2deb.utils.
TemporaryDirectory
(**options)[source]¶ Easy temporary directory creation & cleanup using the
with
statement.Here’s an example of how to use this:
with TemporaryDirectory() as directory: # Do something useful here. assert os.path.isdir(directory)
-
__init__
(**options)[source]¶ Initialize context manager that manages creation & cleanup of temporary directory.
Parameters: options – Any keyword arguments are passed on to tempfile.mkdtemp()
.
-
-
py2deb.utils.
compact_repeating_words
(words)[source]¶ Remove adjacent repeating words.
Parameters: words – An iterable of words (strings), assumed to already be normalized (lowercased). Returns: An iterable of words with adjacent repeating words replaced by a single word. This is used to avoid awkward word repetitions in the package name conversion algorithm. Here’s an example of what I mean:
>>> from py2deb import compact_repeating_words >>> name_prefix = 'python' >>> package_name = 'python-mcrypt' >>> combined_words = [name_prefix] + package_name.split('-') >>> print(list(combined_words)) ['python', 'python', 'mcrypt'] >>> compacted_words = compact_repeating_words(combined_words) >>> print(list(compacted_words)) ['python', 'mcrypt']
-
py2deb.utils.
convert_package_name
(python_package_name, name_prefix=None, extras=())[source]¶ Convert a Python package name to a Debian package name.
Parameters: - python_package_name – The name of a Python package as found on PyPI (a string).
- name_prefix – The name prefix to apply (a string or
None
, in which case the result ofdefault_name_prefix()
is used instead).
Returns: A Debian package name (a string).
-
py2deb.utils.
default_name_prefix
()[source]¶ Get the default package name prefix for the Python version we’re running.
Returns: One of the strings python
,python3
orpypy
.
-
py2deb.utils.
detect_python_script
(handle)[source]¶ Detect whether a file-like object contains an executable Python script.
Parameters: handle – A file-like object (assumed to contain an executable). Returns: True
if the program name in the shebang of the script references a known Python interpreter,False
otherwise.
-
py2deb.utils.
embed_install_prefix
(handle, install_prefix)[source]¶ Embed Python snippet that adds custom installation prefix to module search path.
Parameters: - handle – A file-like object containing an executable Python script.
- install_prefix – The pathname of the custom installation prefix (a string).
Returns: A file-like object containing the modified Python script.
-
py2deb.utils.
extract_shebang_command
(handle)[source]¶ Extract the shebang command line from an executable script.
Parameters: handle – A file-like object (assumed to contain an executable). Returns: The command in the shebang line (a string). The seek position is expected to be at the start of the file and will be reset afterwards, before this function returns. It is not an error if the executable contains binary data.
-
py2deb.utils.
extract_shebang_program
(command)[source]¶ Extract the program name from a shebang command line.
Parameters: command – The result of extract_shebang_command()
.Returns: The program name in the shebang command line (a string).
-
py2deb.utils.
normalize_package_name
(python_package_name)[source]¶ Normalize Python package name to be used as Debian package name.
Parameters: python_package_name – The name of a Python package as found on PyPI (a string). Returns: The normalized name (a string). >>> from py2deb import normalize_package_name >>> normalize_package_name('MySQL-python') 'mysql-python' >>> normalize_package_name('simple_json') 'simple-json'
-
py2deb.utils.
normalize_package_version
(python_package_version, prerelease_workaround=True)[source]¶ Normalize Python package version to be used as Debian package version.
Parameters: Reformats Python package versions to comply with the Debian policy manual. All characters except alphanumerics, dot (
.
) and plus (+
) are replaced with dashes (-
).The PEP 440 pre-release identifiers ‘a’, ‘b’, ‘c’ and ‘rc’ are prefixed by a tilde (
~
) to replicate the intended ordering in Debian versions, also the identifier ‘c’ is translated into ‘rc’. Refer to issue #8 for details.
-
py2deb.utils.
package_names_match
(a, b)[source]¶ Check whether two Python package names are equal.
Parameters: - a – The name of the first Python package (a string).
- b – The name of the second Python package (a string).
Returns: Uses
normalize_package_name()
to normalize both names before comparing them for equality. This makes sure differences in case and dashes versus underscores are ignored.
-
py2deb.utils.
python_version
()[source]¶ Find the version of Python we’re running.
Returns: A string like python2.7
,python3.8
,pypy
orpypy3
.This specifically returns a name that matches both of the following:
- The name of the Debian package providing the current Python version.
- The name of the interpreter executable for the current Python version.