1

I'm working on a Python 3 project that unfortunately has a local module called typing, which clashes with the built in typing module.

The net result of this is there is no way for me to import the built in typing module as the local typing module is referenced first and ends up with the name typing in sys.modules.

I know I can rename the local module to something else and fix all the references and if there's no alternative I'll do that. The issue with that is I don't own the code so keeping my copy and the definitive copy in sync will get tricky if changes are made to that file by either me or the owners of the definitive copy.

I was wondering if there is a way using something like the importlib module to import the core typing module under a different name?

I tried a couple of things but they always fail because the local typing module is referenced first and ends up with the name typing in sys.modules. A few of the solutions in Importing from builtin library when module with same name exists looked promising but fail with recursion errors.

user783836
  • 3,099
  • 2
  • 29
  • 34
  • Ultimately that _is_ something that should be fixed upstream by renaming that module, since you're not the only one having this problem, surely… – deceze Jun 18 '21 at 10:20

1 Answers1

0

You are correct : the better solution would be to rename that module. Hacking around the import system may lead to sad headaches down the road, and more hackeries. Break the pattern : rename the module, make everyone happy.

A poor man's solution would be to change the sys.path order. If you manage to put the path ......./lib/site-packages before the path to the directory containing your package containing the typing module, and if you do that before any other module of the WHOLE Python program imports any typing, it can work.

Here is my setup :

stack_overflow/
├─ annoying/
│  ├─ __init__.py
│  ├─ innocent.py
│  ├─ typing.py
│  ├─ main.py
# file: innocent.py
import typing
print("'typing' imported")

abc: typing.List[str] = ["a", "b", "c"]
# file: main.py

import sys

print(sys.path)

import innocent

and both __init__.py and typing.py are empty.

When I execute my main I get :

['C:\\PycharmProjects\\stack_overflow\\annoying', ... Python regular stuff ...]
'typing' imported
Traceback (most recent call last):
[...]
AttributeError: module 'typing' has no attribute 'List'

because the wrong file was imported, due to the sys.path order such that Python searched for typing in the annoying directory before to search in its site-packages.

I am now putting the path to the library at the end :

# file: main.py

import sys

print(sys.path)
annoying_library_index_in_syspath, annoying_library_path = next((i, path) for i, path in enumerate(sys.path))
sys.path.pop(annoying_library_index_in_syspath)
sys.path.append(annoying_library_path)
print(sys.path)

import innocent

which prints :

['C:\\PycharmProjects\\stack_overflow\\annoying', ... Python regular stuff ...]
[... Python regular stuff ..., 'C:\\PycharmProjects\\stack_overflow\\annoying']
'typing' imported

now that the order is reversed, Python imports typing from its site-packages in priority, and everything works as expected. But if I have an import (even transitive) to to module which imports a typing before I change the sys.path, it will fail again :

# file: main.py

import sys

import innocent  # raise AttributeError: module 'typing' has no attribute 'List'

print(sys.path)
annoying_library_index_in_syspath, annoying_library_path = next((i, path) for i, path in enumerate(sys.path))
sys.path.pop(annoying_library_index_in_syspath)
sys.path.append(annoying_library_path)
print(sys.path)

import innocent

But messing with sys.path is prone to errors, conflicts, pain and sadness. That's why is discouraged to reuse standard library names for user modules. So please fix the file, it really is the best solution.

Lenormju
  • 4,078
  • 2
  • 8
  • 22