Move compatibility logic into its own module #1130
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
From #1024 (comment):
First, I found the use of
importlib_metadata
a little grating, since it's using the legacy name over the preferred, future name. I aim to make the diff between the future syntax and the current syntax as small as possible. I've been using this technique across a number of projects (example) and found it particularly useful when maintaining compatibility for a backport (like importlib_metadata itself), as it allows the code to be ported into another place that doesn't require the library with a small diff to the main code, but also nice to clearly illustrate what code is essential and what code is there temporarily to serve for compatibility. Essentially, write the code as you would if you had the latest Python, then write a compatibility shim that makes that functionality possible with as little diff to the essential code as possible.I also wanted to re-use the logic rather than repeating it everywhere it's used. My rule of thumb is it's okay to repeat the logic once, but if there's a third instance, consider refactoring to consolidate the logic.
With this approach, when python 3.9 is dropped, this module can be dropped and its functionality in the modules replaced with the built-in support with very little change to the implementation.
I also wanted to reduce the diff in this PR by not creating a mutable
deps
where an immutable one was suitable before (although presumably a+=
could have done the trick).I do find it a little regrettable that tools like ruff won't be able to remove the blocks because they're no longer following a basic if/else pattern. I've just found that in general, the if/else pattern is messy at best and inadequate at worst to creating a robust abstraction around compatibility. It feels like the difference between a macro in C and a proper library. I thought maybe ruff would be able to at least remove the unreachable blocks in
compat.py39
but it seems not.