Our main application has some extra features, that users can enable. Those features are in their own directory. Those features might need extra dependencies. I am considering to put those in a requires.txt
file there. At runtime, we would like to let people know, if the feature will break. I am currently considering something like this:
def checkfeature(feature):
everything_okay = True
f = pkg_resources.resource_stream(feature, "requires.txt")
with f:
for r in pkg_resources.parse_requirements(f):
if pkg_resources.working_set.find(r) is None:
print "%r not found, please install, otherwise this feature does not work" % (r,)
everything_okay = False
return everything_okay
Is this the right, pythonic way of doing things? Does this make sense?
Small update:
Why so complex and not just try: import ... except ImportError: ...
like suggested in one answer:
pkg_resources
anyway. So that's why my idea above uses pkg_resources.can_we_unit_test_this_plugin(plugin)
function makes things easier.Second update: What about extra_require
in setup.py
?
setup.py
loads the extra_require
straight from the above mentioned requires.txt
in the individual subdirs for the individual features. But that's really the next step.Generally, you just try to import the dependency, and handle the ImportError
exception gracefully:
try:
import dependency
except ImportError:
# dependency missing, issue a warning
import warnings
warnings.warn('dependency not found, please install to enable xyz feature')
You can list such dependencies in the extras_require
entry of your setuptools-based setup.py
script. pip
, easy_install
and zc.buildout
all can handle installing such extras. See Declaring “Extras” (optional features with their own dependencies).
You can use the extras_require
entry to list minimal version requirements if you have those. Yes, there is a possibility that the user already has an older version of the dependency installed; I'd just document the requirements clearly. Really, test for features, not versions. If you need a newer version because a certain API method has been added? Test for that method rather than for the version.
However, it sounds as if you may want to package the plugins as separate packages instead, then list those in extras_require
. I'd use entry points to register and enumerate such plugins. That way you do not need to test for imports or for packages, you just enumerate over registered entry points instead. Each plugin lists their own dependencies and has it's own unit tests.