139

Situation: - There is a module in my project_folder called calendar - I would like to use the built-in Calendar class from the Python libraries - When I use from calendar import Calendar it complains because it's trying to load from my module.

I've done a few searches and I can't seem to find a solution to my problem.

Any ideas without having to rename my module?

Community
  • 1
  • 1
twig
  • 3,804
  • 5
  • 35
  • 46
  • 26
    It is a best practice not to name modules to hide builtin modules. – the_drow May 17 '11 at 13:37
  • 3
    The solution is "pick a different name". Your approach of not renaming is a bad idea. Why can't you rename your module? What's wrong with renaming? – S.Lott May 17 '11 at 13:54
  • Indeed. It is because there is *no* good answer to this question that shadowing stdlib modules is so strongly discouraged. – ncoghlan May 17 '11 at 14:42
  • I avoided using the same module name as the solutions seemed more trouble than it's worth. Thanks! – twig Aug 30 '11 at 11:14
  • 13
    @the_drow This advice doesn’t scale, pure and simple. PEP328 readily acknowledges this. – Konrad Rudolph Aug 21 '12 at 12:17
  • See my answer here: http://stackoverflow.com/questions/12011327/using-absolute-import-and-handling-relative-module-name-confilcts-in-python/19270302#19270302 – crusaderky Oct 09 '13 at 11:22
  • I had a similar issue and landed on this question. I solved it with `from __future__ import absolute_import` That way when I `import module_name` I got the library but when I did `import mypackage.module_name` I got the local module. – Matt Jan 15 '19 at 21:51

6 Answers6

145

Changing the name of your module is not necessary. Rather, you can use absolute_import to change the importing behavior. For example with stem/socket.py I import the socket module as follows:

from __future__ import absolute_import
import socket

This only works with Python 2.5 and above; it's enabling behavior that is the default in Python 3.0 and higher. Pylint will complain about the code but it's perfectly valid.

Philip Taron
  • 133
  • 8
Damian
  • 2,906
  • 2
  • 17
  • 15
  • 4
    This seems the correct answer to me. See the [2.5 changelog](http://docs.python.org/release/2.5/whatsnew/pep-328.html) or [PEP328](http://www.python.org/dev/peps/pep-0328/#rationale-for-absolute-imports) for more. – Pieter Ennes May 21 '12 at 22:40
  • 6
    This is the correct solution. Unfortunately, it doesn’t work when code from within the package is launched because then the package isn’t recognised as such, and the local path is prepended to `PYTHONPATH`. [Another question](http://stackoverflow.com/q/12011327/1968) shows how to solve that. – Konrad Rudolph Aug 21 '12 at 13:22
  • 5
    This is the solution. I checked for Python 2.7.6 and this is required, it's still not the default. – Havok Jul 14 '14 at 20:33
  • 3
    Indeed: The first python version where this behaviour is the default was 3.0, according to https://docs.python.org/2/library/__future__.html – misnomer Oct 13 '14 at 17:53
  • 1
    If I have a file named `gzip.py`, and I call `import gzip` there, it always ends up as being a reference to `__main__` module (i.e. - it has a `gzip.gzip` field, but no `gzip.open`). – Tomasz Gandor Oct 17 '14 at 14:28
  • 1
    Then do not name your *main* module as one that clashes with a builtin module. – Antti Haapala -- Слава Україні Jul 19 '15 at 16:18
  • 1
    @TomaszGandor, you could use the python convention for nameclashes: add a trailing underline. gzip -> gzip_ – Mayou36 Jan 17 '18 at 11:08
38

Actually, solving this is rather easy, but the implementation will always be a bit fragile, because it depends python import mechanism's internals and they are subject to change in future versions.

(the following code shows how to load both local and non-local modules and how they may coexist)

def import_non_local(name, custom_name=None):
    import imp, sys

    custom_name = custom_name or name

    f, pathname, desc = imp.find_module(name, sys.path[1:])
    module = imp.load_module(custom_name, f, pathname, desc)
    f.close()

    return module

# Import non-local module, use a custom name to differentiate it from local
# This name is only used internally for identifying the module. We decide
# the name in the local scope by assigning it to the variable calendar.
calendar = import_non_local('calendar','std_calendar')

# import local module normally, as calendar_local
import calendar as calendar_local

print calendar.Calendar
print calendar_local

The best solution, if possible, is to avoid naming your modules with the same name as standard-library or built-in module names.

BartoszKP
  • 33,416
  • 13
  • 100
  • 127
Boaz Yaniv
  • 6,136
  • 20
  • 29
  • How will this interact with `sys.modules` and subsequent attempts to load the local module? – Omnifarious May 17 '11 at 14:11
  • @Omnifarious: It will add the module to sys.modules with its name, which will prevent loading the local module. You can always use a custom name to avoid that. – Boaz Yaniv May 17 '11 at 14:21
  • @Boaz Yaniv: You should be using a custom name for the local calendar, not the standard one. Other Python modules might try to import the standard one. And if you do that, what you achieve with this is to basically rename the local module without having to rename the file. – Omnifarious May 17 '11 at 14:33
  • @Omnifarious: You could do it either way. Some other code may try to load the local module and get the very same error. You'll have to make a compromise, and it's up to you to decide which module to support. – Boaz Yaniv May 17 '11 at 14:40
  • And just in case someone wants to do the reverse, as Omnifarious suggested, and use a custom name for the local module - all you need to do is to change `sys.path[1:]` to `sys.path[:1]` and import_non_local() becomes import_local(). – Boaz Yaniv May 17 '11 at 14:51
  • 2
    Thanks for that Boaz! Although your snippet is shorter (and document), I think it is just easier to rename the module than have some hacky code that may confuse people (or myself) in the future. – twig May 17 '11 at 23:29
  • My `f` was `None`, so I added an if clause to help. Thanks! – Aleck Landgraf Nov 13 '15 at 01:47
  • Enabling absolute imports as suggested in other solution is better. `from __future__ import absolute_import` – Daniel Milde Aug 28 '17 at 14:17
  • Does anybody have a version of this code snippet that works without `import imp` which is deprecated? – Alper Jul 08 '19 at 09:33
  • What if the local file is named `sys.py`? – theonlygusti Oct 19 '20 at 12:51
  • `imp` is deprecated how can this be done with `importlib`? – theonlygusti Oct 19 '20 at 13:00
15

The only way to solve this problem is to hijack the internal import machinery yourself. This is not easy, and fraught with peril. You should avoid the grail shaped beacon at all costs because the peril is too perilous.

Rename your module instead.

If you want to learn how to hijack the internal import machinery, here is where you would go about finding out how to do this:

There are sometimes good reasons to get into this peril. The reason you give is not among them. Rename your module.

If you take the perilous path, one problem you will encounter is that when you load a module it ends up with an 'official name' so that Python can avoid ever having to parse the contents of that module ever again. A mapping of the 'official name' of a module to the module object itself can be found in sys.modules.

This means that if you import calendar in one place, whatever module is imported will be thought of as the module with the official name calendar and all other attempts to import calendar anywhere else, including in other code that's part of the main Python library, will get that calendar.

It might be possible to design a customer importer using the imputil module in Python 2.x that caused modules loaded from certain paths to look up the modules they were importing in something other than sys.modules first or something like that. But that's an extremely hairy thing to be doing, and it won't work in Python 3.x anyway.

There is an extremely ugly and horrible thing you can do that does not involve hooking the import mechanism. This is something you should probably not do, but it will likely work. It turns your calendar module into a hybrid of the system calendar module and your calendar module. Thanks to Boaz Yaniv for the skeleton of the function I use. Put this at the beginning of your calendar.py file:

import sys

def copy_in_standard_module_symbols(name, local_module):
    import imp

    for i in range(0, 100):
        random_name = 'random_name_%d' % (i,)
        if random_name not in sys.modules:
            break
        else:
            random_name = None
    if random_name is None:
        raise RuntimeError("Couldn't manufacture an unused module name.")
    f, pathname, desc = imp.find_module(name, sys.path[1:])
    module = imp.load_module(random_name, f, pathname, desc)
    f.close()
    del sys.modules[random_name]
    for key in module.__dict__:
        if not hasattr(local_module, key):
            setattr(local_module, key, getattr(module, key))

copy_in_standard_module_symbols('calendar', sys.modules[copy_in_standard_module_symbols.__module__])
Community
  • 1
  • 1
Omnifarious
  • 52,547
  • 18
  • 126
  • 186
  • imputil is considered deprecated. You should use the [imp](http://docs.python.org/library/imp.html) module. – Boaz Yaniv May 17 '11 at 14:34
  • Which is perfectly compatible with Python 3, by the way. And not that hairy to use at all. But you should always be aware that code that relies on python treating paths in one way or looking up modules in that order may break sooner or later. – Boaz Yaniv May 17 '11 at 14:38
  • @Boaz Yaniv: I know, but it doesn't seem like there's a replacement for the functionality until Python 3. As far as I can tell, the `imp` module merely provides an implementation of the standard import mechanism, not a way to globally hook the import mechanism to make it do what you want. – Omnifarious May 17 '11 at 14:41
  • 1
    Right, but in such an isolated case (module name collision) hooking the import mechanism is an overkill. And since it's hairy and incompatible, it's better left alone. – Boaz Yaniv May 17 '11 at 14:50
  • @Boaz Yaniv: But in order to really get `import calendar` to do exactly what you're expecting in every instance, hooking the import mechanism is the only way to go. Though, I can think of an extremely ugly way to handle this in this specific case. I will outline it. It's evil though. It does use your idea. – Omnifarious May 17 '11 at 14:59
  • @Boaz Yaniv: There, my answer now includes the evil, horrible, ugly mechanism that you should not use. – Omnifarious May 17 '11 at 15:17
  • Ah, I see. Yes, it is quite a hack. :) But even more than the random names and messing with sys.modules, I'd worry about effectively merging the namespace of both local and standard modules. – Boaz Yaniv May 17 '11 at 15:28
  • @Boaz Yaniv: That is worrisome. And if the functions in the system calendar module put any more names into the module global namespace, there could be trouble if code outside the module expects to be able to see them. – Omnifarious May 17 '11 at 21:39
  • Thank you for such a detailed response! Now that I know what is involved I'll definitely stay clear of that peril. I was hoping there would be an easy way of getting around that as "calendar" is quite a common name. – twig May 17 '11 at 23:26
  • +1: Merging namespaces is both incredibly clever /and/ incredibly dangerous. In a nutshell, I *loved* it :) – MestreLion Nov 16 '12 at 13:43
  • And, ugly hack or not, it worked beautifully. I'll soon use this very trick, believe or not, in production code! I have a project whose source *package* is called `code`, and I'm not willing to rename everything to `src` right now just because PyDev imports stdlib'd `code.InteractiveConsole` – MestreLion Nov 16 '12 at 16:05
  • @MestreLion: Well, I'm not certain if I should be pleased or horrified. ;-) – Omnifarious Nov 17 '12 at 06:33
  • Take a look and decide for yourself: https://github.com/MestreLion/singularity/blob/master/code/__init__.py – MestreLion Nov 24 '12 at 08:07
  • @Omnifarious: actually, I had to remove the `del` statement to make it truly work. Despite the `setattr` to `local_module`, Classes were still bound to `random_name` module. Functions and other vars worked fine tho. Any ideas why? – MestreLion Dec 04 '12 at 01:18
  • How could you tell that classes were still bound to `random_name` module? – Omnifarious Dec 04 '12 at 02:06
  • @Omnifarious Now that I have enough rep points, I can comment and ask this :) Why is this an "ugly and terrible" solution? I want to use it to combine socket functions, in order to interpose on logging. This merging could be done one time upon installation. I have posed a question on this, and one of the suggestions was to use monkey-hijaking. Is this ugly and terrible as well? Does it help that it will just be for logging messages? – jspacek May 23 '14 at 15:41
  • @MestreLion Have you had any issues with this solution in production? – jspacek May 23 '14 at 15:41
  • 1
    @jspacek nope, so far so good, but collision would only occur when using PyDev's debbuger, not in regular use. And make sure you check the latest code (the URL in github), since it changed a bit from the above answer – MestreLion May 28 '14 at 00:32
  • @MestreLion was the issue of collision the main consideration? I've received some advice that says merging could affect backwards compatibility as well, though it doesn't sound like it's been an issue in your case. – jspacek May 29 '14 at 15:30
  • 1
    @jspacek: It's a game, not a library, so in my case backward compatibility is not a concern at all. And the namespace collision occurs only when using running via PyDev IDE (which uses Python's `code` std module), meaning only a fraction of *developers* could ever have any issues with this "merging hack". Users would not be affected at all. – MestreLion May 30 '14 at 08:49
  • @MestreLion thanks for taking the time to clarify the context, really appreciated. I'm going to explore patching which was suggested to help with the compatibility issue as users & devs could be affected in our case. – jspacek May 30 '14 at 17:15
  • @jspacek - It's an ugly hack because it basically monkey patches your module with a whole tons of names from some system module. Monkey patching in a very targeted way is a highly questionable practice, and doing it en-masse this way seems quite disturbing. – Omnifarious May 08 '17 at 03:14
6

The accepted solution contains a now-deprecated approach.

The importlib documentation here gives a good example of the more appropriate way to load a module directly from a file path for python >= 3.5:

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)

So, you can load any .py file from a path and set the module name to be whatever you want. So just adjust the module_name to be whatever custom name you'd like the module to have upon importing.

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

  • Works like a charm... Used this to test while developing a library, so that my tests were always using the developing version and not the published (and installed) one. In windows 10 i had to write the path to my module like this: `file_path=r"C:\Users\My User\My Path\Module File.py"`. Then i called `module_name` just like the released module so that i had full working script that, stripped off this snippet, coud be used on other pcs – Luke Savefrogs Jul 21 '20 at 23:22
  • 2
    Where are the default python modules located? How do you know it will be the same on every system? Is this solutions portable? – theonlygusti Oct 19 '20 at 12:48
  • 2
    The first sentence should be removed... or it would let people think that this solution contains a now-deprecated approach. – alan23273850 Nov 12 '20 at 03:11
  • I also want to ask whether the argument "module_name" is important or not, since it seems to be ok even if I pass an empty string into it. – alan23273850 Nov 12 '20 at 03:13
  • 1
    But how does one import a module from the standard library? – Tom Jan 20 '21 at 22:00
  • 1
    How's this even an accepted answer? The question is to import from the standard lib, not user code. – j4hangir Jan 26 '21 at 22:34
  • Good points. My reply here was pointing out that the methods of importing a custom path in the previously accepted answer were now deprecated, but my reply is not showing the complete answer to the question. Presumably it will need to be a combination of the logic Boaz Yaniv gave (first find the std lib package's __init__.py) and then the code here to actually import that file. – Brandon Squizzato Jan 28 '21 at 01:03
1

I'd like to offer my version, which is a combination of Boaz Yaniv's and Omnifarious's solution. It will import the system version of a module, with two main differences from the previous answers:

  • Supports the 'dot' notation, eg. package.module
  • Is a drop-in replacement for the import statement on system modules, meaning you just have to replace that one line and if there are already calls being made to the module they will work as-is

Put this somewhere accessible so you can call it (I have mine in my __init__.py file):

class SysModule(object):
    pass

def import_non_local(name, local_module=None, path=None, full_name=None, accessor=SysModule()):
    import imp, sys, os

    path = path or sys.path[1:]
    if isinstance(path, basestring):
        path = [path]

    if '.' in name:
        package_name = name.split('.')[0]
        f, pathname, desc = imp.find_module(package_name, path)
        if pathname not in __path__:
            __path__.insert(0, pathname)
        imp.load_module(package_name, f, pathname, desc)
        v = import_non_local('.'.join(name.split('.')[1:]), None, pathname, name, SysModule())
        setattr(accessor, package_name, v)
        if local_module:
            for key in accessor.__dict__.keys():
                setattr(local_module, key, getattr(accessor, key))
        return accessor
    try:
        f, pathname, desc = imp.find_module(name, path)
        if pathname not in __path__:
            __path__.insert(0, pathname)
        module = imp.load_module(name, f, pathname, desc)
        setattr(accessor, name, module)
        if local_module:
            for key in accessor.__dict__.keys():
                setattr(local_module, key, getattr(accessor, key))
            return module
        return accessor
    finally:
        try:
            if f:
                f.close()
        except:
            pass

Example

I wanted to import mysql.connection, but I had a local package already called mysql (the official mysql utilities). So to get the connector from the system mysql package, I replaced this:

import mysql.connector

With this:

import sys
from mysql.utilities import import_non_local         # where I put the above function (mysql/utilities/__init__.py)
import_non_local('mysql.connector', sys.modules[__name__])

Result

# This unmodified line further down in the file now works just fine because mysql.connector has actually become part of the namespace
self.db_conn = mysql.connector.connect(**parameters)
casey
  • 1,079
  • 1
  • 12
  • 25
-2

Change the import path:

import sys
save_path = sys.path[:]
sys.path.remove('')
import calendar
sys.path = save_path
linuts
  • 6,352
  • 4
  • 34
  • 36
  • This will not work because after doing this there will be no way to import the local module without going and fiddling with the import machinery yourself. – Omnifarious May 17 '11 at 14:06
  • @Omnifarious: that is a different problem, which you can get around with a third module that does a from calendar import *. – linuts May 17 '11 at 14:12
  • No, this probably wouldn't work because python caches the module name in `sys.modules`, and it will not import a module with the same name again. – Boaz Yaniv May 17 '11 at 14:33