I just took over maintainership of docopt-ng, which is a jazzband-maintained fork of the popular but abandoned docopt.
When fork was originally forked, they distributed it as docopt-ng (ie pip install docopt-ng), so as not to clash with the existing docopt. BUT, they made what I think was a tragic decision to keep the package name the same, so you still import it as import docopt. This makes it impossible to install both libraries in the same environment, since you don’t know which docopt you get when you import docopt.
What are the solutions here? I assume it’s to do a breaking change in a 1.0 release and change both the distribution name and package name to something like docopt2. Do you know of any projects that have done this, so I could see how that went and maybe learn a lesson or two? Any other advice?
You could distribute a shim docopt module that just wraps your renamed docopt_ng or etc, and raises a deprecation warning – that would allow a longer transition period. Not sure what you are referring to by changing the distribtution name, I assume you’d still pip install docopt-ng?
The shim module is a good idea, if I change the name then this will probably be the route I follow.
I figured that while I was changing the package name, I might as well also change the distribution name so that both names match (seems sane, and recommended by the [non-accepted] PEP 423). I could shim the distribution name as well as Peter Suter suggests following the skimage → scikit-image shim. If a user has to make the change in their code for the package rename, I figure it would be minimal additional work to also update the distribution name.
A prominent example of a similar situation is Pillow, an imaging library. It originated as a fork of PIL, but even now, more than a decade later, it is imported with “import PIL”.
Great point. So that’s evidence that just keeping things exactly how they are is feasible.
Ask for a claim to the name on PyPI if abandoned.
The original docopt is too popular still to pull the rug out from underneath all the folks still using that.
Still waiting a bit longer to see if anyone else chimes in before I make a decision…
This doesn’t do that at all; rather, it benefits them by allowing them to take advantage of your maintenance and improvements (if they choose) without having to switch to a totally new distribution package. If its been over a year since the last release and the maintainer can’t reasonably be reached (or can and okays it), then it can be all yours.
docopt-ng has several breaking changes as compared to docopt, plus the versioning is going to be inconsistent between them, so if someone’s requirements.txt, still saying docopt, suddenly begins pointing to my fork, then their code is going to inexplicably break. Unless I’m missing something that you’re saying?
If docopt development had continued, it would inevitably released a new major version with breaking changes, unless its goal was 100% backward compat with every previous version of docopt forever. Therefore, what you would be doing is no different form the original project, if it was still being developed (or development resumed at some point). That’s what major versions are for in semver, and many projects release breaking changes without even doing that.
Yes, of course, but you just make your first new release to the existing PyPA project name a new major version relative to the current docopt version.
If they haven’t upper capped it to at least the current major version, yes, but the same would be true if and when the original docopt authors released a new major version with breaking changes, and that’s on them, not yet. And its not that; inexplicable, if they aren’t upper capping their dep versions properly, then their library/application would almost certainly broken before due to breaking changes in a dependency.
Releasing a pre-release (alpha, beta, rc) could help devs ensure their versions are either upper capped or compatible, assuming they are paying attention as they should.
I also support the idea of name transfer or PEP 541 (if necessary). It’s in the best interest of users and the supply-chain who may have an unsupported dependency without awareness. Having a fresh maintainer come along is healthier, even if it does temporarily break certain unpinned builds because it highlights to the user that they have 2 options: update their code to a new supported version or pin to an unsupported version.
Reflecting on the OP, I’ve done this for a couple of internal packages, essentially package to company-package. One thing that worked was to release a package v1.0 with no (Python) files, then release the new company-package v1.0 which depends on package v1.0. This is because both package <1.0 and company-package provide the same Python modules.
I know this is all internal and I’m free to do what I want, but in the wild is the recommended to add a barrier to using the unmaintained package? Or is renaming Python modules preferred to keep compatibility? I guess there’s more factors, such as security and necessity for change
For the first revived release, I bumped the major version.
I tried to avoid backwards incompatible changes, beyond:
dropping support for EOL Python versions
removing a VERSION constant (and recommended importlib.metadata.version in the release notes)
Also re-organised source structure, switched from setuptools to hatchling, and some other modernisation, which shouldn’t be backwards incompatible . And didn’t add too much, it’s the first release in 11 years(!) so we don’t want cause problems.
If there were to be major changes (none planned), they would come in future major bumps with deprecations where appropriate, but after this one had safely bedded in.