Question

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:

  1. Our plugins might have a bunch of dependencies. Creating actual code like the one below is quite verbose.
  2. Some plugins might need a specific version of a package. Testing that requires either a pakcage specific test or using pkg_resources anyway. So that's why my idea above uses pkg_resources.
  3. We want to run unit tests for plugins that can be run. Handling the ImportError in the unit tests is not nice. Having a can_we_unit_test_this_plugin(plugin) function makes things easier.

Second update: What about extra_require in setup.py?

  1. people miss to install those often. Okay, bad excuse.
  2. My vision is, that 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.
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top