Mark package as "conflicts with" another package?

I’m currently refactoring a package I maintain into several sub-packages, inspired by the way argon2 was structured:

  • pypqc
  • pypqc-cffi-bindings-libre
  • pypqc-cffi-bindings-falcon
  • pypqc-cffi-bindings-hqc
  • pypqc-cffi-bindings-kyber

At some point in the next few years, I hope to secure an OSI-approved license for Kyber. If I succeed, I plan on merging the -kyber package into the -libre package and deprecating the separate package.

But I’m trying to decide which of these is the correct approach:

Option 1: deprecate the old package, and conflict with it

  • Publish a new, Kyber-included version of the -libre package, and declare it explicitly as conflicting with the -kyber package, since it provides the same physical files;
  • Deprecate the -kyber package;
  • Publish a metadata-only post-release of pypqc that makes the [kyber] extra depend on at least the new, Kyber-included version of the -libre package.

This seems like the cleanest, best, and obviously correct option — except that I can’t figure out how to do this, and I’m worried it’s just not supported by Pip.

Option 2: lockstep hand-off

  • Publish a new, Kyber-included version of the -libre package, which depends on the next major version of the -kyber package;
  • Simultaneously publish a new major version of the -kyber package which provides no files, and depends on the new, Kyber-included version of the -libre package;
  • Publish a metadata-only post-release of pypqc that makes the [kyber] extra depend on at least the new, Kyber-included version of the -libre package.

This seems like it would work, but feels over-engineered and seems to lock me into keeping a “package carcass” positively pulled in as a dependency forever. Not great.

Option 3: laissez-faire hand-off

(Basically just the same as option 2 except without pulling in a dud package forever)

  • Publish a version of the -kyber package that provides no files, emits a deprecation warning on installation, and depends on the next major version of the -libre package;
  • Publish a new, Kyber-included major version of the -libre package;
    • if anyone ends up with a file conflict, declare it a skill issue on their part for doing piecemeal updates and not using latest stable release of all applicable packages
  • Publish a metadata-only post-release of pypqc that makes the [kyber] extra depend on at least the new, Kyber-included version of the -libre package.

Option 4: go back in time and establish different premises

Right now, I have not committed to this new packaging split.

If the way I’m setting this up now is going to fundamentally cause my future self strife if/when it comes time to fold these splinters into the OSI-approved-licensed baseline, I’d like to know what other options there are.

Look at the “rarely used” core metadata fields. In principle what you want exists. Except no tool that I know of implements behavior for those fields. So you can use them, for documentation, but they will have no effect.

My advice would be: don’t overthink it. You will probably not manage to get a perfect setup for what you are trying to achieve, the Python packaging ecosystem is not ready for this.

At some point in the next few years

Who knows what the Python packaging ecosystem will be in a few years?

It also seems to me like you are trying to cover for failure cases that might never arise. I guess I understand what you are trying to achieve, but unless I misread it your post does not express what those potential failure cases are. And the failure cases that I have in mind seem quite unlikely to me or at least in the realm of “oh well I guess I need to check the documentation of pypqc to understand what has changed and how to fix this dependency conflict”.

1 Like