Jacopo
Jacopo

Reputation: 1021

Python entry point fails for dependency conflict

I work on a project where two of the dependencies require conflicting dependencies. In particular the project requires eli5==0.8 which requires tabulate>=0.7.7 and invocations==1.4.0 which requires tabulate==0.7.5.

I can still install the project, import the module and run the code, however when I try to create an entry point via setup.py and run it I encounter the following failure:

Traceback (most recent call last):
  File "/Users/user/.pyenv/versions/3.6.6/envs/repro/lib/python3.6/site-packages/pkg_resources/__init__.py", line 574, in _build_master
    ws.require(__requires__)
  File "/Users/user/.pyenv/versions/3.6.6/envs/repro/lib/python3.6/site-packages/pkg_resources/__init__.py", line 892, in require
    needed = self.resolve(parse_requirements(requirements))
  File "/Users/user/.pyenv/versions/3.6.6/envs/repro/lib/python3.6/site-packages/pkg_resources/__init__.py", line 783, in resolve
    raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.ContextualVersionConflict: (tabulate 0.8.2 (/Users/user/.pyenv/versions/3.6.6/envs/repro/lib/python3.6/site-packages), Requirement.parse('tabulate==0.7.5'), {'invocations'})

Even if I try to pin the version of tabulate directly in my setup.py I get the same failure.

How are situations like this resolved?

As extra information. I'm using Python 3.6.6 and the following minimal python module and setup.py can be used to reproduce the problem.

a_script.py:

def cli():
    print('Hello world')

if __name__ == '__main__':
    cli()

setup.py:

from setuptools import setup

setup(
    name='repro',
    version='0.1',
    py_modules=['a_script'],
    install_requires=[
        'eli5==0.8',
        'invocations==1.4.0',
        # 'tabulate==0.8.2'
    ],
    entry_points='''
        [console_scripts]
        repro=a_script:cli
    ''',
)

Upvotes: 1

Views: 629

Answers (2)

I'll Eat My Hat
I'll Eat My Hat

Reputation: 1344

I recently resolved a situation like this by patching the package's METADATA file using a unified diff, made using git diff, and GNU patch.

This is an effective solution if you are trying to deploy an application, but if you are writing a library, then only effective solution is to go bother the maintainers and tell them to relax their constraints, or eliminate your reliance on their work.

Upvotes: 1

Serge Ballesta
Serge Ballesta

Reputation: 149075

Welcome to the world of dependencies hell!

I know no clean way to solve this. Some hints for a simple workaround:

  • can you find a later (may be called dev or unstable) version of the older dependency meeting the requirement of the newer? If yes you could try if it passes the integration tests of your own project (do all your nominal use cases pass with it).
  • can you find an older version of the newer dependency meeting your own requirements? If yes you should test that is works in all your nominal use cases

If none of the above worked, you will have to build a custom version of one of the conflicting projects (assuming at least one is open source). Ideally you should clone the oldest (here invocation), set its version to a local version identifier (here for example 1.4.0+tab0-7) and change its own requirement to accept a tabulate>=0.7.7. then use that special version and again throughly test that all your use cases pass with that.

If all the tests of the modified project still pass, you could try to propose its maintainer to change their version requirement for a future release, for example by proposing a patch / pull request based on the current development tree.

Upvotes: 1

Related Questions