Choosing a Package/Module Name#
This discussion is a complement to Packaging Python Projects.
Make sure to choose a valid Python identifier for the names of all your import packages and modules. The name of the project and the name of the distribution package are one and the same. It is the name you will see on PyPI, for example. The name of the project and the name of the top-level import package (or module) can be different.
Moreover, one PyPI project/dist may ship more than one module or importable package — it is only possible that one matches the name, others can’t.
It is recommended to have only one importable package, with a name as similar as possible as the dist-info file in the installation folder.
Project names (usually found in pyproject.toml) and import package names follow different rules and conventions.
The normalized form (and thus the preferred form) for project names
is the so-called “kebab case” (see Package name normalization), for example abcd-1234.
But import packages and modules should have a valid Python identifier as a name.
With an import package name abcd-1234, the following would not work:
>>> import abcd-1234
>>> from abcd-1234 import something
Since abcd-1234 is not a valid Python identifier.
(Importing such a module would be cumbersome, completely unnatural and against the long-established conventions in the Python community;
see, for example, PEP 8#package-and-module-names.
There is a way to import it anyway, see importlib and this question.)
Python identifiers follow the so-called “snake case”.
The preferred form for an import package name is abcd_1234 which is a valid Python identifier.
Note the underscore _ as separation character instead of of the dash - seen in the project name.
Having a directory structure with src/abcd_1234/ instead of src/abcd-1234/ has 2 consequences:
The following works:
>>> import abcd_1234 >>> from abcd_1234 import something
All four build backends covered in the tutorial Packaging Python Projects will work:
Flit will not crash with an error;
Hatch will recognize that the module corresponding to the package is
abcd_1234instead of defaulting tosrcand building a not working wheel.
More information about Python imports and its grammar.
Another aspect of choosing a package/module name is the naming consistency of the files generated by the build backend. With the four build backends covered in the tutorial (Flit, Hatchling, PDM, and Setuptools), when the correct import package is found, its name is always leaved as is.
But, starting from the project name, the build backend also generates:
an archive file like
abcd_1234-1.0.0.tar.gzwith Flit, Hatchling, and PDM, orabcd-1234-1.0.0.tar.gzwith setup-tools; here we can see that some backends but not all apply a normalization on the project name: lowercase, underscore (“snake case”) instead of hyphen; note that we do not talk about the same normalization referenced at the beginning of this document (Package name normalization);a wheel like
abcd_1234-1.0.0-py3-none-any.whlwith all build backends;a dist-info like
abcd_1234-1.0.0.dist-infowith all build backends;in the case of setuptools, an egg-info like
abcd_1234-1.0.0.egg-info.
Thus, except for the archive with setuptools, all prefixes of filenames
use a normalization of project name.
This normalization will match an import package name chosen consistently
by normalization of the project name.
You may see an interest in installing a wheel named abcd_1234-1.0.0-py3-none-any.whl,
and having as a result abcd_1234-1.0.0.dist-info and abcd_1234/ (or abcd_1234.py) in your installation directory :)
(instead of a project aBcD-1234, a wheel abcd_1234-1.0.0-py3-none-any.whl, installing abcd_1234-1.0.0.dist-info and 4-3-2-1cDbA/ ;) ).