pycountry
pycountry copied to clipboard
idea: A simple autoload plugin system analogous to `pytest`
Introduction
First off, thanks for pycountry
! I have a proposal that might sound a bit outlandish/overengineered just based on the title - but I think I have a good case to make here.
Motivation
I'll start by outlining the problem this would help with.
Support for adding/removing country records is great, but comes with one flaw - it's necessary to ensure that additions/removals happen before code runs that depends on them.
This often isn't an issue when these modifications run on startup, and the code using them runs later.
However, there is also the case where pycountry
is imported on startup to initialize constants that are used later on - for example, to generate a set of choices for a model definition, or define an enum.
And then, things can get hairy. Let's take the example of a Django project:
Here, it's pretty natural to use pycountry
to generate choices
for a model field. Developers need to guarantee that pycountry
is imported and modified before Django reads model definitions on startup, which happens fairly early.
And this needs to be guaranteed (if applicable)
- when the project is run as a wsgi app
- when the project is run as a asgi app
- when a management command is run in the project
- when tests are run
- when celery tasks are run
- ...
It's also possible to make the modification in settings IF you are using monolithic settings, or at least base settings that are always used. But neither monolithic settings nor running unrelated code in settings are a very good practice in the first place.
In general, covering all entry points in a large project isn't easy. What's more, getting it wrong is impossible to detect via testing, as that's just one of the entry points. It's possible to get things to fail loudly by verifying after startup is completed that pycountry was modified, and raising an exception if not, but also, I think there would be a better way:
Inspiration
pytest
supports plugins that can be installed as packages. What's more, it's possible for these plugin packages to be autoloaded - ie, just installing a package will cause pytest
to detect and load them.
Here's an explanation of how it works: https://github.com/pytest-dev/pytest/discussions/11615
Proposition
pycountry
could do something similar, and provide a hook for packages that want to modify the data before pycountry
is used for the first time.
Including Kosovo, the example from the README of this project as well as what set me on the path to write this issue, could be as simple as installing a potential new package pycountry-kosovo
(I have not verified whether or not this package already exists!).
Contraindication
Of course, this can lead to a situation where there is an external dependency that never needs to be imported, but causes subtle errors when it happens not to be installed.
This is ugly, but less so than what I outlined above. It's also comparatively easy to guard against plugins not being loaded accidentally - since the plugin will be present as soon as pycountry
is imported (if installed), simply importing pycountry
and then asserting the presence of the plugin, anywhere in the startup code (including where it would have been too late to make modifications), is sufficient.
This approach also changes pycountry
across an entire environment, which might not be desirable.
However, the current mechanism for changing it on a per-process basis would still exist, and be a suitable match if more fine-grained control is required.
Inquisition
Would this be considered a suitable addition to this project?