How to Access a Standard-Library Module in Python When There Is a Local Module with the Same Name

How to access a standard-library module in Python when there is a local module with the same name?

You are looking for Absolute/Relative imports from PEP 328, available with 2.5 and upward.

In Python 2.5, you can switch import‘s behaviour to absolute imports using a from __future__ import absolute_import directive. This absolute- import behaviour will become the default in a future version (probably Python 2.7). Once absolute imports are the default, import math will always find the standard library’s version. It’s suggested that users should begin using absolute imports as much as possible, so it’s preferable to begin writing from pkg import string in your code.

Relative imports are still possible by adding a leading period to the module name when using the from ... import form:

from __future__ import absolute_import
# Import uncertainties.math
from . import math as local_math
import math as sys_math

Can I import a local module with the same name as a standard-library one?

Rename your internal file to something like my_queue.py and import it into your file like this. That avoids bad practices like from queue import * and name conflicts with the standard library which is most likely the problem you are running into now.

import my_queue

def driver():
q = my_queue.Queue()
for line in df:
if 'received' in line:
q.enqueue(line)
print("Adding job " + new_item.job_ID + " to the queue with the timestamp: " + new_item.time_stamp + ".")
print("The prority of the job is: " + new_item.job_priority)
print("The job type is: " + new_item.job_type)

How can I import from the standard library, when my project has a module with the same name? (How can I control where Python looks for modules?)

In Python 3.5 and up, use the standard library importlib module to import directly from a specified path, bypassing import's lookup mechanism:

import importlib.util
import sys

# For illustrative purposes.
import tokenize
file_path = tokenize.__file__ # returns "/path/to/tokenize.py"
module_name = tokenize.__name__ # returns "tokenize"

spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)

In actual code, file_path can be set to any path to a .py file to import; module_name should be the name of the module that will be imported (the name that the import system uses to look up the module when further import statements are attempted). Subsequent code will use module as the name of the module; change the variable name module to use a different name.

To load a package instead of a single file, file_path should be the path to the package's root __init__.py.

How to import standard library module instead of local directory?

The problem is that the current working directory (as either '' or '.', depending on version/platform) is always at the top of sys.path when you start up Python.

Using absolute imports makes no difference—that just means to look in sys.path first, instead of looking for relative imports before falling back to sys.path.

The right solution is obviously to either (a) rename calendar, or (b) move it into subpackage of some other package instead of having it at the top level. Whatever your Good Reasons are, the Good Reasons for doing the right thing are likely even better.


But if you must get around this, there are a few things you can do. The simplest is to temporarily munge sys.path:

syspath = sys.path
sys.path = [path for path in sys.path if path.strip('.')]
import calendar
sys.path = syspath

However, no matter what you do, this is going to cause huge problems. When you later try to import your local package calendar—even if you're doing so from a completely different source file—nothing will happen, because there's already something named calendar in sys.modules, so that other source file will just get the stdlib calendar module instead of your package.

So you'll also need to rename one or the other on the fly and remove it from sys.modules. Maybe this:

syspath = sys.path
sys.path = [path for path in sys.path if path.strip('.')]
calmod = sys.modules.get('calendar')
del sys.modules['calendar']
calendar = __import__('calendar')
sys.modules['calendar'] = calmod
sys.path = syspath

And, depending on the order at which your modules get run (which may not be easily predictable, or even deterministic), there's a good chance you'll need similar hackery in the other location.

(What if you never actually need to import your local package calendar? Well, in that case you don't have this problem… but then I can't imagine what your Good Reasons could possibly be…)

Python 3: Import of core module when local module exists with same name?

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.

Python modules with identical names (i.e., reusing standard module names in packages)

Reusing names of standard functions/classes/modules/packages is never a good idea. Try to avoid it as much as possible. However there are clean workarounds to your situation.

The behaviour you see, importing your SWS.time instead of the stdlib time, is due to the semantics of import in ancient python versions (2.x). To fix it add:

from __future__ import absolute_import

at the very top of the file. This will change the semantics of import to that of python3.x, which are much more sensible. In that case the statement:

import time

Will only refer to a top-level module. So the interpreter will not consider your SWS.time module when executing that import inside the package, but it will only use the standard library one.

If a module inside your package needs to import SWS.time you have the choice of:

  • Using an explicit relative import:

    from . import time
  • Using an absolute import:

    import SWS.time as time

So, your foo.py would be something like:

from __future__ import absolute_import

import time

from . import time as SWS_time

python module names with same name as existing modules

In Python 2, imports in packages without a package qualifier indeed first look for package local modules.

Thus, import pyglet will find msa.pyglet before the top-level pyglet is considered.

Switch to absolute imports to make the Python 3 behaviour the default, where unqualified names are always top level names:

from __future__ import absolute_import

Now import pyglet can only ever find the top-level name, never msa.pyglet. To reference other modules within your msa namespace, use from . import pyglet or from msa import pyglet.

See PEP 328 -- Imports: Multi-Line and Absolute/Relative for more details.

Importing a python standard library with the same name as the current module

First, it is bad practice to create a module that shadows another module. However, that doesn't prevent you from proceeding.

Import __future__ import absolute_import as your first import in your main file.

This forces imports to use absolute paths instead of relative. Now, import email imports that standard library. You can import your local version by from . import email

Python 3: importing different python modules with same name

I think you should be using the PYTHONPATH variable in order to avoid using sys.

Content of a/a.py and b/b.py:

import utils
utils.hello()

Content of X/utils.py with X one of a, b or c:

def hello():
print('hello from X')

Content of c/main.py:

import a.a
import b.b

import utils
utils.hello()

Output (when running: export PYTHONPATH='$PYTHONPATH:<project_root>'; python main.py):

hello from a
hello from b
hello from c


Related Topics



Leave a reply



Submit