Dependency conflict: two packages install the same top-level module name (ulid)

Hello everyone,

I’m facing an import conflict caused by two Python packages that both expose the same top-level module name, and I’m looking for best practices to handle this.

Problem description

In my project, I need to use:

  • ulid-py

  • python-ulid (required by another internal/third-party library)

Both packages install a top-level package named ulid.

When both dependencies are installed using Poetry, one ulid package overwrites the other in site-packages, causing unexpected behavior depending on install order.

Example:

poetry run python -c "import ulid; print(ulid.__file__)"

Only one implementation is available at runtime.

Environment

  • Python version: 3.12

  • Dependency manager: Poetry

  • OS: Ubuntu

Questions

  1. Is there any recommended way in Python to handle two dependencies that expose the same top-level module name?

Any guidance or confirmation would be appreciated.

Thank you!

1 Like

Hello,

welcome to Python. I believe that you can alleviate this by way of a virtual environment. In the following link, scroll down to where it states: Creating Virtual Environments

Hi @onePythonUser

I’m using Poetry with a virtual environment created inside the project folder. In my case, I need to use both packages within the same project and the same virtual environment.

1 Like

Install one globally and one in your virtual environment so that one does not overwrite the other.

View the video that I included. It gives you pointers.

@onePythonUser As mentioned earlier, I’m using Poetry for dependency management, and this setup is part of a project that builds and ships dependencies inside a Docker image, not just for local development. Because of this, installing one dependency globally and another in a virtual environment is not a viable option.

I see the problem. What needs ulid-py? Its last commit was September 2021. If you control how it’s imported, can you vendor it (copy/paste/static link) and import it using relative imports where needed? Presumably you don’t want to ditch the third party dep or ulid-py?

Are other users going to install your project as a library (possibly amongst even more deps), or can it be typically installed as an application (e.g. installed and used via uvx or pipx)?

1 Like

HI @JamesParrott

No, this is a closed-source application/web server used only internally, so that isn’t a concern.

I did consider the option of vendoring it, but I’m hoping to find a cleaner alternative solution, if one exists. We are using ulid-py and the another third party dependency is using python-ulid.

I forgot - vendoring it and using relative imports, relies on the vendored package using relative imports internally. Otherwise you have to fork it and do a minor rewrite (and then there are 15 competing standards).

You can’t control what third party deps do with their transitive deps. If you can’t drop them, it’s best not to break them.

I’d focus on what you can control without creating too much future work, which it sounds like is the code that uses ulid-py, or even the entire way the user installs the project, or the entire venv shipped to the user (even if they’re only yourself, your colleagues, or employer).

1 Like

Ask the 2 internal projects to fix the conflict by one renaming there top-level maybe?

What? You mean make a reasonable request, communicate effectively, and actually talk to people?

2 Likes

What was I thinking :open_mouth:

2 Likes

Thanks for the reply.

As a workaround, I switched to using a single ULID library in my own codebase (replacing ulid-py with python-ulid) to avoid the overwrite issue. However, this doesn’t fully solve the problem, because the conflict still occurs if a third-party dependency internally relies on ulid-py and both packages end up installed in the same environment.

More generally, this feels like a class of problem that the Python packaging ecosystem doesn’t handle well today—there’s no built-in protection or clear guidance when multiple distributions install the same top-level module name. Other ecosystems handle similar cases differently; for example, in Java, dependencies are namespaced by their package names, and in Rust, crates are isolated by default and explicitly renamed when conflicts arise.

Is there any ongoing discussion or proposal in Python packaging (e.g. pip, PyPA, or import system changes) to detect or mitigate this kind of conflict—such as warnings at install time, metadata-based conflict detection, or stronger recommendations around namespacing top-level modules?

2 Likes

There’s a convention that import names match PyPI install names which, since PyPI names have to be unique, is usually enough to keep import names unique. Honestly, this is the first time I’ve ever seen someone have this issue. Although I am surprised that pip doesn’t check for file trampling before it goes ahead and tramples files.

It’s unlikely that two packages with the same name will ever be allowed to coexist for the same reasons that multiple versions of the same package are practically unsupportable.

1 Like