How to handle multiple major versions of dependency
Asked Answered
B

2

1

I'm wondering how to handle multiple major versions of a dependency library.

I have an open source library, Foo, at an early release stage. The library is a wrapper around another open source library, Bar. Bar has just launched a new major version. Foo currently only supports the previous version. As I'm guessing that a lot of people will be very slow to convert from the previous major version of Bar to the new major version, I'm reluctant to switch to the new version myself.

How is this best handled? As I see it I have these options

  1. Switch to the new major version, potentially denying people on the old version.
  2. Keep going with the old version, potentially denying people on the new version.
  3. Have two different branches, updating both branches for all new features. Not sure how this works with PyPi. Wouldn't I have to release at different version numbers each time?
  4. Separate the repository into two parts. Don't really want to do this.

The ideal solution for me would be to have the same code base, where I could have some sort of C/C++ macro-like thing where if the version is new, use new_bar_function, else use old_bar_function. When installing the library from PyPi, the already installed version of the major version dictates which version is used. If no version is installed, install the newest.

Would much appreciate some pointers.

Breath answered 4/4, 2019 at 15:23 Comment(0)
P
1

Normally the Package version information is available after import with package.__version__. You could parse that information from Bar and decide based on this what to do (chose the appropriate function calls or halt the program or raise an error or ...).

You might also gain some insight from https://www.python.org/dev/peps/pep-0518/ for ways to control dependency installation.

It seems that if someone already has Bar installed, installing Foo only updates Bar if Foo explicitly requires the new version. See https://github.com/pypa/pip/pull/4500 and this answer

Paper answered 4/4, 2019 at 15:31 Comment(3)
That could work. But is that not bad practice? I don't think I've ever seen that used in source code before. Only typically in an init or setup file.Breath
You can definitely define the function in the init file to achieve " ... if the version is new, use new_bar_function, else use old_bar_function." by assigning whichever is appropriate to bar_function and then use bar_function. Having said that, I agree with @di that it is hard to judge which approach should be taken without discussing design choices and the concrete situation. i.e. do the functions behave differently regarding input/output? Is there only one function or do you have to change substantial parts of Foo to go from one to the other version (in both directions)?Paper
I marked this as correct, as it technically was the solution that I was looking for. I ended up realizing that I could bypass the difference in pure code, without versioning, by being a bit clever. I, therefore, can support both versions, as my wrapper library only touches the core, not the new features. But thanks to both of you for good answers.Breath
F
1

Have two different branches, updating both branches for all new features. Not sure how this works with PyPI. Wouldn't I have to release at different version numbers each time?

Yes, you could have a 1.x release (that supports the old version) and a 2.x release (that supports the new version) and release both simultaneously. This is a common pattern for packages that want to introduce a breaking change, but still want to continue maintaining the previous release as well.

Floridafloridia answered 4/4, 2019 at 15:41 Comment(3)
Even though the changes between the major versions of the library doesn't necessarily affect my library?Breath
I think if it affects the users using your library, it would be appropriate, but hard to tell without more information.Floridafloridia
I encounter same situation as the OP. Although I would first try @Paper 's answer as a quick hack, the "splitting Foo into 1.x and 2.x branches" topic here leads to a generic realization: When my LIBRARY Foo 1.x has an INTERNAL dependency on library Bar 1.x, even though Foo does NOT directly expose old_bar_function() in its API surface, it still has an IMPLICIT exposure (or we would even call it a requirement) of pinning bar.old_bar_function() in the current environment/namespace. So, simply upgrading dependency to Bar 2.x would justify a major version bump on Foo. Yes? No?Rothenberg

© 2022 - 2024 — McMap. All rights reserved.