Overview
The module pyTooling.Packaging provides helper functions to achieve a single-source-of-truth Python package
description, where (almost) no information is duplicated. The main idea is to read configuration files, READMEs, and
Python source files from setup.py, so it doesn’t duplicate information. This allows an easier the maintenance of
Python packages.
Helper Functions
The following helper functions are used by DescribePythonPackage(), but these can also be
called individually to reuse internal features offered by that package description function.
loadReadmeFile
The function loadReadmeFile() reads a README file and guesses the contents MIME type on
the file’s extension. It returns an instance of Readme.
This read text can then be used for the package’s long description.
Usage in a setup.py
from pathlib import Path
from pyTooling.Packaging import loadReadmeFile
readmeFile = Path("README.md")
readme = loadReadmeFile(readmeFile)
# print(readme.Content)
# print(readme.MimeType)
README.md
# pyTooling
**pyTooling** is a powerful collection of arbitrary useful abstract data models, missing classes,
decorators, a new performance boosting meta-class and enhanced exceptions. It also provides lots of helper
functions e.g. to ease the handling of package descriptions or to unify multiple existing APIs into a single
API.
loadRequirementsFile
The function loadRequirementsFile() recursively reads a requirements.txt file and
extracts all specified dependencies. As a result, a list of requirement strings is returned.
Warning
The returned list might contain duplicates, which should be removed before further processing.
This can be achieve by converting the result to a set and back to a list.
requirements = list(set(loadRequirementsFile(requirementsFile)))
Usage in a setup.py
from pathlib import Path
from pyTooling.Packaging import loadRequirementsFile
requirementsFile = Path("doc/requirements.txt")
requirements = loadRequirementsFile(requirementsFile)
# for req in requirements:
# print(req)
requirements.txt
-r ../requirements.txt
Sphinx ~= 8.2
docutils <= 0.21
sphinx_rtd_theme ~= 3.0
extractVersionInformation
The function extractVersionInformation() extracts version information from a Python source
file (module). Usually these module variables are defined in a __init__.py file.
Supported fields
Author name (
__author__)Author email address (
__email__)Copyright information (
__copyright_)License name (
__license__)Version number (
__version__)Keywords (
__keywords__)
The function returns an instance of VersionInformation, which offers the gathered
information as properties.
Usage in setup.py
from setuptools import setup
from pyTooling.Packaging import extractVersionInformation
file = Path("./pyTooling/Common/__init__.py")
versionInfo = extractVersionInformation(file)
setup(
# ...
version=versionInformation.Version,
author=versionInformation.Author,
author_email=versionInformation.Email,
keywords=versionInformation.Keywords,
# ...
)
__init__.py
__author__ = "Patrick Lehmann"
__email__ = "Paebbels@gmail.com"
__copyright__ = "2017-2025, Patrick Lehmann"
__license__ = "Apache License, Version 2.0"
__version__ = "1.10.1"
__keywords__ = ["decorators", "meta classes", "exceptions", "platform", "versioning"]
PackageDescriptions
DescribePythonPackage
DescribePythonPackage() is a helper function to describe a Python package. The result is a
dictionary that can be handed over to setuptools.setup(). Some information will be gathered implicitly from
well-known files (e.g. README.md, requirements.txt, __init__.py).
Handling of namespace packages
If parameter packageName contains a dot, a namespace package is assumed. Then
setuptools.find_namespace_packages() is used to discover package files.
Otherwise, the package is considered a normal package and setuptools.find_packages() is used.
In both cases, the following packages (directories) are excluded from search:
build,build.*dist,dist.*doc,doc.*tests,tests.*
Handling of minimal Python version
The minimal required Python version is selected from parameter pythonVersions.
Handling of dunder variables
A Python source file specified by parameter sourceFileWithVersion will be analyzed with Pythons parser and the
resulting AST will be searched for the following dunder variables:
__author__:str__copyright__:str__email__:str__keywords__:typing.Iterable`[:class:`str]__license__:str__version__:str
The gathered information be used to add further mappings in the result dictionary.
Handling of package classifiers
To reduce redundantly provided parameters to this function (e.g. supported pythonVersions), only additional
classifiers should be provided via parameter classifiers. The supported Python versions will be implicitly
converted to package classifiers, so no need to specify them in parameter classifiers.
The following classifiers are implicitly handled:
- license
The license specified by parameter
licenseis translated into a classifier.
See alsopyTooling.Licensing.License.PythonClassifier()- Python versions
Always add
Programming Language :: Python :: 3 :: Only.
For each value inpythonVersions, oneProgramming Language :: Python :: Major.Minoris added.- Development status
The development status specified by parameter
developmentStatusis translated to a classifier and added.
See also
Handling of extra requirements
If additional requirement files are provided, e.g. requirements to build the documentation, then extra
requirements are defined. These can be installed via pip install packageName[extraName]. If so, an extra called
all is added, so developers can install all dependencies needed for package development.
docIf parameter
documentationRequirementsFileis present, an extra requirements calleddocwill be defined.testIf parameter
unittestRequirementsFileis present, an extra requirements calledtestwill be defined.buildIf parameter
packagingRequirementsFileis present, an extra requirements calledbuildwill be defined.- User-defined
If parameter
additionalRequirementsis present, an extra requirements for every mapping entry in the dictionary will be added.allIf any of the above was added, an additional extra requirement called
allwill be added, summarizing all extra requirements.
Handling of keywords
If parameter keywords is not specified, the dunder variable __keywords__ from sourceFileWithVersion
will be used. Otherwise, the content of the parameter, if not None or empty.
DescribePythonPackageHostedOnGitHub
DescribePythonPackageHostedOnGitHub() is a helper function to describe a Python package when
the source code is hosted on GitHub.
This is a wrapper for DescribePythonPackage(), because some parameters can be simplified by
knowing the GitHub namespace and repository name: issue tracker URL, source code URL, …
Todo
- normal packages
PackageName- namespace package root package
NamespacePackage.*- namespace package sub package
NamespacePackage.PackageName
deriving URLs
Usage in setup.py
from setuptools import setup
from pathlib import Path
from pyTooling.Packaging import DescribePythonPackageHostedOnGitHub
packageName = "pyTooling.Packaging"
setup(
**DescribePythonPackageHostedOnGitHub(
packageName=packageName,
description="A set of helper functions to describe a Python package for setuptools.",
gitHubNamespace="pyTooling",
keywords="Python3 setuptools package wheel installation",
sourceFileWithVersion=Path(f"{packageName.replace('.', '/')}/__init__.py"),
developmentStatus="beta",
pythonVersions=("3.8", "3.9", "3.10")
)
)