When you register a new python-package on Pypi, it is registered by name as defined in the package-metadata, and then this name is guaranteed to be unique across the entire repository.
The name for the django-package is “Django”:
pip install Django
but the names on Pypi are case-insensitive, so this also works:
pip install django|DJANGO
Besides the case-insensitivity, Pypi also introduces an equivalence between hyphens and underscores
because names with hypens are not valid python-modules.
so this is equivalent:
pip install django-foo
pip install Django_FOO
But the whole idea of this unique namespace on Pypi, is meant that the toplevel python-module provided by this package is unique, because that is what we use in code.
A proper name for a python-package is lowercased using dashes, eg “django-foo”
with a corresponding module-name “django_foo” belonging to this same unique namespace. In short:
module_name = package_name.lower().replace(‘-’, ‘_’)
This convention has probably been too implicit in the python-community.
But a lot of code is using this convention when they have a soft-dependency on another package,
they will try to import the module, and then assume the corresponding package has been installed.
For example Flask tries to “import dotenv” and then assumes its soft-dependency “python-dotenv” is installed, but Flask will break when you have install “django-dotenv” installed.
Unfortunately the django-community has been promoting for a long time
a different naming-pattern:
module_name = package_name.lower().replace(‘-’, ‘').replace('django’, ‘’)
Now we have thousands of published python-packages, installing a python-module
belonging to the unique namespace of ANOTHER PACKAGE.
You can install both packages without noticeable problems:
pip install django-foo
pip install foo # completely independent project
Pip will happily install both packages, and report both as being installed successfully.
but the second one has DELETED & REPLACED the source-code of the first package.
AND NO TOOL WILL WARN YOU ABOUT THIS.
As a consequence, you can never use such packages in the same project.
Or packages that depend on one of those.
This is not “shadowing”, it’s worse.
This is not “dependency-hell”, it’s worse.
Because you are silently deleting another package (but keeping its metadata intact).
Your quickfix-solution is to privately fork it, change the name of the module, and re-publish privately.
Publishing a python-package were the name of the module belongs to the namespace of different project is probably the most diabolical evil anti-pattern in the entire python-community.
Thanks to Adam for tackling this.