Python import is overridden by the standard library (Python 2.4)

I have a python package that I am writing and I have a problem when the standard library is imported instead of my files due to name conflicts.

For example, the file structure as shown below:

package/__init__.py

 # No data in this file 

package /module.py

 #!/usr/bin/env python print 'Loading module.py' import signal 

package /signal.py

 #!/usr/bin/env python print 'Loading signal.py' 

I get the following results when I run this:

 $ ./module.py Loading module.py 

I would like to get:

 $ ./module.py Loading module.py Loading signal.py 

Actual question:

So, when I run module.py , it import signal goes to the stdlib version. How can I get module.py to import signal.py instead?

As noted in the tags, this should be possible to run on python-2.4.3. Although this is an old version, this is what is included in RHEL 5.


Additional Information

Just for more information, I explicitly set the following setting:

 [10:30pm][~/test] tree . . |-- package | |-- __init__.py | |-- module.py | `-- signal.py `-- script [10:30pm][~/test] cat script #!/usr/bin/env python from package import signal [10:30pm][~/test] cat package/__init__.py [10:30pm][~/test] cat package/module.py #!/usr/bin/env python print "Loading module.py" import signal [10:30pm][~/test] cat package/signal.py #!/usr/bin/env python print "Loading signal.py" [10:30pm][~/test] python ./script Loading signal.py [10:32pm][~/test] python ./package/module.py Loading module.py [10:32pm][~/test] python -m package.module python: module package.module not found 

Note that when I ran ./package/module.py , the print statement in ./package/signal.py was not launched. This means that the loaded signal is one of stdlib.

+4
source share
3 answers

The problem in this case is that the built-in signal module is imported as part of the interpreter startup process. Thus, by the time you run your code in module.py , there is already an entry in sys.modules under the name signal with a built-in module as the value. Since sys.modules is the first place the import statement looks, it will return this built-in module and stop there. He didn't even bother to look for his own signal.py .

I can present three solutions:

  • Rename your module. This is the simplest solution. You do not need to worry about the names of your modules colliding with the installed packages (eggs), because usually the import statement will look for directories in the order specified by sys.path , and the current working directory when starting the interpreter is first in this list. signal is a special case because it is automatically imported before your code runs, but there are a limited number of modules for which this is true, and these are the only ones with which you need to avoid name conflicts.
  • You can del sys.modules['signal'] and replace the record with your own signal module. Actually do not do this unless your module is really intended to replace the built-in signal . If you do this, then any code that starts import signal from this point will get your version, not the built-in one, and this can harm any internal code that needs the signal module.
  • You can use the imp module to access the internal functions of import or at least the equivalent code that allows you to bypass the sys.modules check.

    If you really need to do this, here is a sample code that you could use:

     import imp, sys f, path, desc = imp.find_module('signal', sys.path) if f: f.close() signal = imp.new_module('signal') execfile(path, signal.__dict__) else: raise ImportError('signal.py not found') # signal is your module 

    This piece of code is roughly equivalent to import signal , except that it does not insert the found module into sys.modules , and it does not look for the built-in modules before finding the path.

+5
source

In the project directory (parent directory of package ):

 python -mpackage.state # Python 2.6+ python2.4 -c'from package.state import test; test()' 
  • always use absolute imports in your modules, i.e. import package.signal instead of import signal if you don't know what you are doing
  • make sure the parent directory of package is in sys.path . unittest2 , nose , pytest test runners can do it for you
  • Avoid module names that conflict with stdlib modules. Many test runners, code analyzers are broken and add directories with the module processed on sys.path
  • python package/stat.py adds package to sys.path (see http://bugs.python.org/issue13475 ). You do not want in this case
0
source

File hierarchy

 . |-- package | |-- __init__.py | |-- module.py | `-- signal.py `-- script `-- __init__.py 

script.py

 #!/usr/bin/env python from package import module 

package /module.py

 #!/usr/bin/env python print 'Loading module.py' from package import signal 

package /signal.py

 #!/usr/bin/env python print 'Loading signal.py' 

Output:

 $ ./script Loading module.py Loading signal.py 

Edit

Just test this with mod.py modification, on python 2.4.3

-1
source

Source: https://habr.com/ru/post/1386979/


All Articles