Python local module name shadowing standard lib in third package module - python

I'm using libusb1 and noticed an import error when there is a platform module in my main module:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/duranda/.local/lib/python3.6/site-packages/usb1/__init__.py", line 61, in <module>
from . import libusb1
File "/home/duranda/.local/lib/python3.6/site-packages/usb1/libusb1.py", line 199, in <module>
libusb = _loadLibrary()
File "/home/duranda/.local/lib/python3.6/site-packages/usb1/libusb1.py", line 161, in _loadLibrary
system = platform.system()
AttributeError: module 'platform' has no attribute 'system'
This can be easily reproduced by launching a Python interpreter from a directory containing a platform.py or platform/__init__.py and then importing usb1 using import usb1.
How is it possible that a local module shadows another module (in this case the platform module from the standard lib) from a third party module? To the best of my knowledge, libusb1 imports platform directly and doesn't do anything crazy with globals.

add as first lines in your module:
import sys
print("\n".join(sys.path))
import platform
print("platform file is", platform.__file__)
This will probably show, that the python path tries to first import your local modules and only then the system modules.
In other words. don't use local modules with names, that conflict with system or thrd party module names.
More explanations:
if multiple modules import a module with the same name, then python imports the module only once.
Only the first import imports the module
The second import will just point to the already imported module, which it will find in sys.modules
Thus a module name can be considered a unique pointer to python code.
(Try printing out sys.modules this is a dict and will show you which modules are imported so far.)
So it doesn't matter whether an import statement is located in your file or in a third party file.
import platform will only point to one module. The one that is being selected / found is the one, that occurs first in the python path.
So self written modules should not have conflicting names with existing modules.

Since the module platform in your working directory, and Python interpreter would insert current working directory into sys.path at the beginning. You could print sys.path out to check.
Thus, Python interpreter use the first one found when looking for module based on sys.path, which is your own module instead of the one in standard library.
A workaround (trick) is to move the current working directory to the end position; Note to put it at the top of file, and then import the module
import sys
# move the current working directory to the end position
sys.path = sys.path[1:] + sys.path[:1]
More Comments:
To reply #gelonida: suppose that we really want to use both modules,
we could import one first and give it an alias, and then modify
sys.path to import another one
import sys
# <------- newly added
_platform = patch_module('platform', '_platform') # our own module
# move the current working directory to the end position
sys.path = sys.path[1:] + sys.path[:1]
And the above code use a patch_module() method
def patch_module(source_module_name, target_module_name):
""" All imported modules are cached in *sys.modules*
"""
__import__(source_module_name)
m = sys.modules.pop(source_module_name)
sys.modules[target_module_name] = m
target_module = __import__(target_module_name)
return target_module

Related

Why can't Idle import from .py files created after it was launched?

I can't explain this phenomena, other than to assume that Idle somehow works off of a snapshot of the filesystem, taken at launch-time.
Repro steps:
create a myLib.py file with (e.g.):
#!/usr/bin/env python3
pre_launch_str = "Pre-launch!"
# post_launch_str = "Post-launch!"
launch Idle (from the containing folder)
from myLib import pre_launch_str works as expected: the string is imported/usable
Keep Idle running/open
[from another application/terminal] modify myLib.py to include a new object (e.g.) post_launch_str
from myLib import post_launch_str will throw an error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'post_launch_str' from 'myLib' (/home/myUser/myLib.py)```
Anyone know what the cause of this is?
Linux (zsh) + Python 3.10 inthe example above, but I've noticed this long ago (~Python3.5 and on MacOS too)
This has nothing to do with IDLE. When you've already put a module into scope (regardless of which names you imported from it), Python will never reload that module. It assumes the module's code has not changed and will use the in-memory version.
If you're planning to modify the module live during development, you'll need to use importlib to reload it. You need a reference to the module itself. If you imported the module name as import myLib, then myLib will do. Otherwise, take a class or function that you imported and get its __module__ (so pre_launch_str.__module__ in your example). Then take that and call reload on it.
from importlib import reload
reload(pre_launch_str.__module__)

How to get path of the pyd file aka equivalent of __file__

I have a file package.py that i am trying to package into package.pyd. I have the following statement in package.py
CURR = os.path.dirname(os.path.realpath(__file__))
which works fine when I run package.py but when I import package.pyd into another file wrapper.py I get the following error message
Traceback (most recent call last):
File "C:\Projects\Wrapper.py", line 1, in <module>
import package
File "package.py", line 40, in init package (package.c:4411)
NameError: name '__file__' is not defined
How can I get the location of the .pyd file. Also is there a way to check if it is being run as a .pyd or .py.
Thank you!
It seems that __file__ variable not available in module init.
But you can get __file__ after module was loaded:
def get_file():
return __file__
You can check the __file__ variable to know what file was loaded.
Also keep in mind python's search order: pyd (so), py, pyw(for windows), pyc.
More information about it is in this this question
Found two working methods.
Involving inspect module:
import inspect
import sys
import os
if hasattr(sys.modules[__name__], '__file__'):
_file_name = __file__
else:
_file_name = inspect.getfile(inspect.currentframe())
CURR = os.path.dirname(os.path.realpath(_file_name))
import some file from the same level and using its __file__ attribute:
import os
from . import __file__ as _initpy_file
CURR = os.path.dirname(os.path.realpath(_initpy_file))
Actually, it doesn't have to be __init__.py module, you can add and import any [empty] file to make it work.
__file__ now works in recent more versions of Cython (0.27 ish) when on run on a version of Python that supports multi-phase module initialization (Python >=3.5). See https://github.com/cython/cython/issues/1715 for the point at which it was added.

import error in python on ubuntu

I have created my first python module on ubuntu. When I'm trying to import the module in python using :
import brian
it is giving error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named brian
I have brian in /home/noamaan and python is in /usr/bin.
If you launch python from the directory that contains brian module, everything will work as it is now.
To import custom module from anywhere you want you should read attentively something on the import mechanism in python to learn where the imported modules are searched for, etc.
But to make your code work right now, I can recommend you the following:
Either extend your PYTHONPATH variable before running python, to include the directory of your module
Or append it right in the code by using sys module in this way.
import sys
sys.path.append("path/to/module/dir")
import brian
Also, see info on site module
by default Python import modules from Python path var.
You can view these paths so:
import sys
print sys.path

Python: Submodules Not Found

My Python couldn't figure out the submodules when I was trying to import reportlab.graphics.shapes like this:
>>> from reportlab.graphics.shapes import Drawing
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
from reportlab.graphics.shapes import Drawing
ImportError: No module named shapes
I have copied the reportlab package to /site-packages and I can import module reportlab.graphics successfully.
My Python version is 2.7.3.
Could anyone help me to fix this problem?
As #dan-boa pointed out, you can add paths to the module search path, but since you can find the parent module, I doubt that this is your root problem.
Do you have some left-over installation of the module at another path? You can check the path where it is finding the parent package (reportlab) by executing:
import reportlab
print reportlab.__file__
If this is indeed the path you were expecting, then try this recursively with the the sub-modules, until you can see where the problem is. Perhaps, your package is corrupted? Try manually checking in the path returned if you can find the files/modules in question.
If this is not the path you were expecting, clean-up the installation from this 2nd path and try again.
Finally, in case you do find that it is a path problem, instead of adding the path each time using sys.path.append, you can add it to PYTHONPATH
Please check your sys path and if the directory of the module is not present then add it.
import sys
sys.path.append('PATH_OF_THE_MODULE')
As site-packages is already their in the sys.path, may be therefore the package was imported successfully.

Python script import fails if script is moved to subdirectory

This may be my own misunderstanding of how Python imports and search paths work, or it may be a problem in the packaging of the caldav package.
I have set up a virtualenv environment named myproject
In the top level of myproject, I have a script test.py which contains two imports:
import lxml
import caldav
In this directory, I type:
python test.py
and it works fine without any problem
Now I move the script to the subdirectory test and run the command:
python test/test.py
The import lxml seems to still work. The import caldav fails with the following exception:
Traceback (most recent call last):
File "test/test.py", line 34, in <module>
main()
File "test/test.py", line 29, in main
exec ( "import " + modulename )
File "<string>", line 1, in <module>
File "/home/ec2-user/caldav2sql/myproject/test/caldav/__init__.py", line 3, in <module>
from davclient import DAVClient
File "/home/ec2-user/caldav2sql/myproject/test/caldav/davclient.py", line 8, in <module>
from caldav.lib import error
ImportError: No module named lib
Am I doing something wrong here? Should I be setting up some kind of path?
Most likely, caldav was in the same directory as test.py, so when you import it it worked fine. Now that you moved test.py to a subdirectory, your imports can't find it. You can either move caldav or set your PYTHONPATH.
You could also modify your sys.path
Information from Python's module tutorial: http://docs.python.org/tutorial/modules.html
The variable sys.path is a list of strings that determines the interpreter’s search path for modules. It is initialized to a default path taken from the environment variable PYTHONPATH, or from a built-in default if PYTHONPATH is not set. You can modify it using standard list operations:
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')

Categories

Resources