Nick Retallack
Nick Retallack

Reputation: 19561

Importing a file with the same name as the file you're in

Lets say you're in a file called logging.py. If you try to import the standard logging module, you'll end up importing the file you're in. How can you import the standard logging module from here?

Upvotes: 4

Views: 741

Answers (4)

abarnert
abarnert

Reputation: 365697

The answer from samy.vilar gives lots of useful options. But if you're looking for the simplest and most direct answer:

import imp
import sys

f, pathname, desc = imp.find_module('logging', sys.path[1:])
logging = imp.load_module('logging', f, pathname, desc)

A few things to note here:

The load_module call is more like reload(logging) than import logging in that it won't bind the name logging in the local scope, but will replace any existing module under the name logging. So, if you've done an import logging before this, that name now refers to the new module, not the old one; if you hadn't, the name logging isn't bound in your scope. (That's why the logging = is there above, to put it into scope.)

I don't know if it's actually guaranteed that the '' that puts the current directory into the module path is actually the first entry in sys.path. For that matter, it's always possible to insert '', or for that matter '.', into sys.path yourself. So, if you want to be paranoid you could do something like this:

f, pathname, desc = imp.find_module('logging', [path for path in sys.path if path and path[0] != '.'])

Or you could get even more paranoid, e.g., compare abspath(path) to sys.argv[0] and os.getcwd() in various ways to make sure nobody is sneakily forcing you to re-import yourself. It depends on what your goals are.

Upvotes: 1

Samy Vilar
Samy Vilar

Reputation: 11120

Well you can use imp to load the module with an absolute path.

import imp
help(imp.load_module)
load_module(...)
    load_module(name, file, filename, (suffix, mode, type)) -> module
    Load a module, given information returned by find_module().
    The module name must include the full package name, if any.

on my mac I did this:

import imp
py_logging = imp.load_module('logging', None, '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging', ('', '', 5))
dir(py_logging)
['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', 'FATAL', 'FileHandler', 'Filter', 'Filterer', 'Formatter', 'Handler', 'INFO', 'LogRecord', 'Logger', 'LoggerAdapter', 'Manager', 'NOTSET', 'PlaceHolder', 'RootLogger', 'StreamHandler', 'WARN', 'WARNING', '__all__', '__author__', '__builtins__', '__date__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__status__', '__version__', '_acquireLock', '_defaultFormatter', '_handlerList', '_handlers', '_levelNames', '_lock', '_loggerClass', '_releaseLock', '_srcfile', '_startTime', 'addLevelName', 'atexit', 'basicConfig', 'cStringIO', 'codecs', 'critical', 'currentframe', 'debug', 'disable', 'error', 'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass', 'info', 'log', 'logProcesses', 'logThreads', 'makeLogRecord', 'os', 'raiseExceptions', 'root', 'setLoggerClass', 'shutdown', 'string', 'sys', 'thread', 'threading', 'time', 'traceback', 'types', 'warn', 'warning']

dir(logging)
['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', 'FATAL', 'FileHandler', 'Filter', 'Filterer', 'Formatter', 'Handler', 'INFO', 'LogRecord', 'Logger', 'LoggerAdapter', 'Manager', 'NOTSET', 'PlaceHolder', 'RootLogger', 'StreamHandler', 'WARN', 'WARNING', '__all__', '__author__', '__builtins__', '__date__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__status__', '__version__', '_acquireLock', '_defaultFormatter', '_handlerList', '_handlers', '_levelNames', '_lock', '_loggerClass', '_releaseLock', '_srcfile', '_startTime', 'addLevelName', 'atexit', 'basicConfig', 'cStringIO', 'codecs', 'critical', 'currentframe', 'debug', 'disable', 'error', 'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass', 'info', 'log', 'logProcesses', 'logThreads', 'makeLogRecord', 'os', 'raiseExceptions', 'root', 'setLoggerClass', 'shutdown', 'string', 'sys', 'thread', 'threading', 'time', 'traceback', 'types', 'warn', 'warning']

as we can see we have the same the set of components.

keep in mind that this isn't very dry, meaning you would need to update the location of the logging module based on the underlying system you are in, you can check for it by

>>> import logging
>>> logging.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.pyc'

or use imp.find_module fp, pathname, description = imp.find_module('logging') in a directory where your custom logging.py can't be found ...

As a last note Im sure you have your reasons for naming your module logging.py I would still recommend something else that wouldn't conflict.

Upvotes: 1

Thomas Orozco
Thomas Orozco

Reputation: 55207

You could always remove the current directory from sys.path, but that's very hackish, and not reliable. After testing, I realized that this can works if the file is being run (as __main__, but not if it's being imported, which is very unreliable).

I think the best thing you could do is not name your file with a name that is used by a std lib package.

Upvotes: 2

Mark Ransom
Mark Ransom

Reputation: 308130

Imported files are cached in sys.modules, and any attempt to import another module with the same name will simply return the cached module. There's no way to resolve the conflict.

As a hack you could delete the dictionary entry in sys.modules, but I don't know how well that would work. Caveat Emptor.

del sys.modules['logging']

Of course after that you'll have to find a way to modify the path so that the proper file gets imported.

My overall advice is to prevent the situation altogether and rename your file so that there's no conflict.

Upvotes: -1

Related Questions