Python module import works for one file, fails for another - python

I'm facing a very strange problem. I've got three files, the first contains the base class, from which the classes in the other two files inherit from.
The strange thing is, everything worked fine yesterday, but one of the files doesn't work anymore today. I haven't touched the imports in the meantime.
.
└── orangecontrib
├──__init__.py
└── prototypes
├──__init__.py
└── widgets
├──__init__.py
├── owpythagorastree.py
├── owclassificationpythagorastree.py
└── owregressionpythagorastree.py
So the classification and regression classes need to inherit from the base class, and the imports are done in the exact same way:
owclassificationpythagorastree.py
...
from orangecontrib.prototypes.widgets.owpythagorastree import OWPythagorasTree
...
owregressionpythagorastree.py
...
from orangecontrib.prototypes.widgets.owpythagorastree import OWPythagorasTree
...
Yet when I try to run the two scripts from the command line (with python owregressionpythagorastree.py) the regression widget works fine, but the classification widget produces the following error:
Traceback (most recent call last): File
"owclassificationpythagorastree.py", line 6, in
from orangecontrib.prototypes.widgets.owpythagorastree import OWPythagorasTree ImportError: No module named
'orangecontrib.prototypes'
This has happened several times in other projects as well, but it eventually sorts itself out. But it bothers me that I don't know what is causing this.
I did try running this both from my regular machine and a python virtualenv, where I have the module installed (I did this with pip install -e . in the base directory).
I see no apparent reason for this behaviour and it is bothering me a lot, so any help or insight as to why this is happening and how to fix it would be appreciated.
EDIT
As requested, I ran import sys; print(sys.path) at the top of both scripts, and after running it through diff, they are both completely identical. Nevertheless, I am posting the results here.
['/home/pavlin/dev/orange3-prototypes/orangecontrib/prototypes/widgets',
'/home/pavlin/dev/orange3',
'/home/pavlin/dev/orange3env/lib/python3.5/site-packages/setuptools_git-1.1-py3.5.egg',
'/home/pavlin/dev/orange-bio',
'/home/pavlin/dev/orange3env/lib/python3.5/site-packages/pyqtgraph-0.9.10-py3.5.egg',
'/home/pavlin/dev/orange3env/lib/python3.5/site-packages/requests-2.9.1-py3.5.egg',
'/home/pavlin/dev/orange3env/lib/python3.5/site-packages/slumber-0.7.1-py3.5.egg',
'/home/pavlin/dev/orange3env/lib/python3.5/site-packages/Genesis_PyAPI-1.2.0-py3.5.egg',
'/usr/lib/python3.5/site-packages/qt_graph_helpers-0.1.3-py3.5-linux-x86_64.egg',
'/home/pavlin/dev/orange3-prototypes',
'/usr/lib/python3.5/site-packages',
'/home/pavlin/dev/orange3env/lib/python35.zip',
'/home/pavlin/dev/orange3env/lib/python3.5',
'/home/pavlin/dev/orange3env/lib/python3.5/plat-linux',
'/home/pavlin/dev/orange3env/lib/python3.5/lib-dynload',
'/usr/lib64/python3.5', '/usr/lib/python3.5',
'/usr/lib/python3.5/plat-linux',
'/home/pavlin/dev/orange3env/lib/python3.5/site-packages',
'/usr/lib/python3.5/site-packages/setuptools-18.7.1-py3.5.egg',
'/home/pavlin/.local/lib/python3.5/site-packages']

It looks like your problem is a not-complete understanding of how python finds modules.
For an absolute import (i.e. one where you specify the name of the first module such as import mymodule, and don't use a period to do a relative import from the package to which the code belongs, such as from . import mymodule), the order of lookups is:
The current directory.
Any directories in PYTHONPATH in your environment.
Any installed system paths, which may be set in various ways.
To see your complete set of paths to import from, use:
import sys
print(sys.path)
Also, remember that a directory is only importable if it has an __init__.py file – you didn't say whether that was the case or not with your code.
Therefore, provided you have the following layout:
.
└── orangecontrib
├── __init__.py
└── prototypes
├── __init__.py
└── widgets
├── __init__.py
├── owpythagorastree.py
├── owclassificationpythagorastree.py
└── owregressionpythagorastree.py
I would expect that if you run python orangecontrib/prototypes/widgets/owclassificationpythagorastree.py from the base directory ., both should work just fine, without needing to modify your PYTHONPATH, since python always looks in the current directory for absolutely imported modules first.
If you are running from the widgets directory, I would expect it not to work, unless you had first added the base directory to your PYTHONPATH.
As a general hint though, except for very small things, you should avoid mixing module code with script code, for exactly these reasons! Make separate python scripts that are designed to be run from a command line, and separate python module code that is designed to be imported. Avoid making modules that can also be run from the command line as scripts.

Just a thought. Have you checked the permissions? Maybe somehow the permissions got messed up and they are giving you the problems.

Related

Python imports in vscode

I'm trying to run a simple project in python but I have always the same problem and it drives me crazy every single time.
My project structure looks like the following:
└── myproject
├── mypackage
├── __init__.py
├── a.py
├── b.py
With vscode I open up the myproject folder. When I click on run in the a.py file which looks like
# a.py
from mypackage import b
.
.
.
I always get ModuleNotFoundError: No module named 'mypackage'. What is confusing to me is that vscode itself sees it correctly and shows the text colored (means it detects the module correctly).
Edit:
I want to use myproject as a package so just import b won't help.
The solution I found is actually relatively easy. Just type python3 -m mypackage.a into the command line in the top myproject directory. Worked for me.
I know this has nothing to do with vscode but I was just confused why vscode seems to accept the import but the python interpreter didn't.
Since you've probably didn't install myproject (or mypackage, if it is top level Python package), Python cannot find it on the path. You have two options:
Install the package.
Use relative import import b. However, see here for implications.
I recommend to avoid approaches like adding mypackage path to system path (see here). Maybe this documentation/tutorial can help you to understand better, what happened and why the import you used is not working.
However, I do not know, how VS Code searches for files in project, so I cannot tell you, why it marks it like this...
according to what you mentioned, both file 'a.py' and 'b.py' are in the same directory and if both files are in the same director, you don't have to actually mention the name of the directory in which they are present.
To import the file 'b.py' in 'a.py', you can just simply type the code shown below to import 'b.py':
import b
This should work.

Unable to import class even though I already have __init__.py files

I'm trying to import a class in a different directory to another file, but can't seem to get it to work. I know this question has been asked a lot and I have looked through multiple stackoverflow solutions and at https://docs.python.org/3/tutorial/modules.html#packages
1: Importing files from different folder
2: import python file in another directory failed
I want to try to just use the method containing just __init__.py file instead of doing an import sys
My directory structure is as follows:
django_vue/
__init__.py
devices/
__init__.py
models.py
lib/
__init__.py
my_file.py
I'm trying to import the class Device from /django_vue/devices/models.py to /django_vue/lib/my_file.py by:
from devices.models import Device
However when I do that I still get the error:
from devices.models import Device
ModuleNotFoundError: No module named 'devices'
I'm not sure what I'm dong wrong since I already have the __init__ file in both directories. Any help is appreciated. Also I'm running python 3.6.
This is the folder structure I'm working with.
.
└── django_vue
├── devices
│   └── models.py
└── lib
└── file.py
When you run
$ python file.py
python has no way of knowing what's outside the directory.
python can't go back and then into devices/ just like that.
The easiest way to solve this would be to add the folder devices/ to sys.path. When python imports a module, it searches for the module from sys.path. Adding the path to devices/ would make it available for imports.
Here are my files.
# models.py
Device = 'device'
# file.py
import sys
sys.path.append('..') # adds the parent dir (which is django-vue/) to path
# django-vue dir has devices/ so now this is available for imports
# importing this works now
from devices.models import Device
print(Device)
Output
django_vue/lib$ python3 file.py
device
Think about it your are inside my_file.py and import something called devices.
How can python know where the name devices has come from.
It won't search your entire Drive for that module/package
Relative Import
use a relative import instead. write from ..devices.models import Device. This is telling python to go up one directory to the parent directory and that's where it will find the devices package. Your lib module should now work as a module
If you however run the my_file.py package directly (as in python C:/django_vue/lib/my_file.py)
You will still get an error. Not the same error; the new error will be something like
ImportError: attempted relative import with no known parent package
This is happening because you are actually running my_file.py
If you think about it why would you want to run my_file.py by itself when it is clearly a part of a package. Maybe you are just testing to see if the import works when you use your package. The problem with this is that it makes it seem like your packages relative imports don't work even though this actually works.
Create a main.py in django_vue and write from lib import my_file. This will run your my_file.py and you will notice there is no error.
What's happening here
Have you heard of __package__?
if you put print(str(__package__)) in your my_file.py and run my_file.py directly you will see that it prints None.
However if you run main.py (that you just created) you will see that when It reaches my_file.py, __package__ will actually be defined to something.
Ahhh... you see now it all makes sense; The error you originally got said something about no known parent package. If __package__ is undefined that means there is no relative parent package because the file was obviously run directly instead of as part of a package.
Consider Absolute imports
you also might want to consider using absolute imports because if you are working on the package you might change it directory structure while developing. so you need to keep changing the import references on the affected files.
Although you can find IDE's with python extensions that automatically to this as you change your directory. I believe VS Code does this automatically.
Replace the __init__ files with __main__.

ImportError: No module named <something>

The following is my directory structure.
ankur
├── ankur1
│ ├── __init__.py
│ └── util.py
├── ankur2
│ └── main.py
└── __init__.py
In main.py, I am importing the following.
import ankur.ankur1.util
When I execute the code in Windows, it works perfectly fine. But in Linux, I get the following error.
ImportError: No module named ankur.ankur1.util
I also read the official python doc on Modules and Packages.
Your package structure is OK. Your import statement is OK. The only thing missing is for the package to be visible in sys.path, a list of locations where import statements can be resolved.
Usually we do this by "installing" the package locally with pip, which copies your code into site-packages†. This directory is one of the entries in sys.path, so when your code is installed in site-packages, the import statements can now be resolved as usual.
However, to install your code you'll need an installer (setup.py script) or a build system (pyproject.toml file) defined for the package. Your project doesn't appear to have any installer or build system, so you'll need to create one (see the Python Packaging User Guide for details about that) and then install the package with pip. If you don't want to learn Python packaging just yet, you'll need to find another way around.
It is possible to modify sys.path directly in main.py, which is subsequently enabling the statement import ankur.ankur1.util to be resolved. This is hacky and I recommend against that. It would add the restriction that executing main.py is the only entry point to the rest of the package, and so any other code wanting to import ankur will first need to know the path to main.py on the filesystem. That's a messy approach and should be avoided.
Another way around is to use the environment - there is an environment variable PYTHONPATH which can be used to augment the default search path for module files. In your shell:
export PYTHONPATH=/path/to/parent # linux/macOS
SET PYTHONPATH=C:/path/to/parent # Windows
Where parent is the directory containing ankur subdirectory.
† The exact location of site-packages depends on your OS/platform, but you can check with import sysconfig; sysconfig.get_paths()["purelib"]

Relative import in Python 3 is not working [duplicate]

This question already has answers here:
Python3 correct way to import relative or absolute?
(2 answers)
Closed 2 years ago.
I have the following directory:
mydirectory
├── __init__.py
├── file1.py
└── file2.py
I have a function f defined in file1.py.
If, in file2.py, I do
from .file1 import f
I get the following error:
SystemError: Parent module '' not loaded, cannot perform relative
import
Why? And how to make it work?
Launching modules inside a package as executables is a bad practice.
When you develop something you either build a library, which is intended to be imported by other programs and thus it doesn't make much sense to allow executing its submodules directly, or you build an executable in which case there's no reason to make it part of a package.
This is why in setup.py you distinguish between packages and scripts. The packages will go under site-packages while the scripts will be installed under /usr/bin (or similar location depending on the OS).
My recommendation is thus to use the following layout:
/
├── mydirectory
| ├── __init__.py
| ├── file1.py
└── file2.py
Where file2.py imports file1.py as any other code that wants to use the library mydirectory, with an absolute import:
from mydirectory.file1 import f
When you write a setup.py script for the project you simply list mydirectory as a package and file2.py as a script and everything will work. No need to fiddle with sys.path.
If you ever, for some reason, really want to actually run a submodule of a package, the proper way to do it is to use the -m switch:
python -m mydirectory.file1
This loads the whole package and then executes the module as a script, allowing the relative import to succeed.
I'd personally avoid doing this. Also because a lot of people don't even know you can do this and will end up getting the same error as you and think that the package is broken.
Regarding the currently accepted answer, which says that you should just use an implicit relative import from file1 import f because it will work since they are in the same directory:
This is wrong!
It will not work in python3 where implicit relative imports are disallowed and will surely break if you happen to have installed a file1 module (since it will be imported instead of your module!).
Even if it works the file1 will not be seen as part of the mydirectory package. This can matter.
For example if file1 uses pickle, the name of the package is important for proper loading/unloading of data.
When launching a python source file, it is forbidden to import another file, that is in the current package, using relative import.
In documentation it is said:
Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.
So, as #mrKelley said, you need to use absolute import in such situation.
since file1 and file2 are in the same directory, you don't even need to have an __init__.py file. If you're going to be scaling up, then leave it there.
To import something in a file in the same directory, just do like this
from file1 import f
i.e., you don't need to do the relative path .file1 because they are in the same directory.
If your main function, script, or whatever, that will be running the whole application is in another directory, then you will have to make everything relative to wherever that is being executed.
myproject/
mypackage
├── __init__.py
├── file1.py
├── file2.py
└── file3.py
mymainscript.py
Example to import from one file to another
#file1.py
from myproject import file2
from myproject.file3 import MyClass
Import the package example to the mainscript
#mymainscript.py
import mypackage
https://docs.python.org/3/tutorial/modules.html#packages
https://docs.python.org/3/reference/import.html#regular-packages
https://docs.python.org/3/reference/simple_stmts.html#the-import-statement
https://docs.python.org/3/glossary.html#term-import-path
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')
sys.path.insert(0, '/ufs/guido/myhaxxlib/python')
Inserting it at the beginning has the benefit of guaranteeing that the path is searched before others (even built-in ones) in the case of naming conflicts.

Cannot import twisted's internet module

Am getting the below error when executing python protocols/smpp/test/test_post_upgrade.py:
Traceback (most recent call last):
File "protocols/smpp/test/test_post_upgrade.py", line 1, in <module>
from protocols.smpp.proto import *
File "/tmp/Wass/protocols/smpp/proto.py", line 1, in <module>
from twisted.internet import defer, reactor
ImportError: No module named internet
Here's my tree:
/tmp/Wass$ tree
.
├── __init__.py
└── protocols
├── __init__.py
├── __init__.pyc
└── smpp
├── __init__.py
├── __init__.pyc
├── proto.py
├── proto.pyc
└── test
├── __init__.py
└── test_post_upgrade.py
3 directories, 10 files
Here's the content of the principal files:
/tmp/Wass$ cat protocols/smpp/proto.py
from twisted.internet import defer, reactor
/tmp/Wass$ cat protocols/smpp/test/test_post_upgrade.py
from protocols.smpp.proto import *
/tmp/Wass$ cat protocols/smpp/__init__.py
__import__('pkg_resources').declare_namespace(__name__)
For information, i can resolve this issue by one of these actions:
Emptying protocols/smpp/__init__.py, but this is usefull for the whole project so i can just empty this file, my project will no more run ..
Renaming protocols/smpp to anything else, for example protocols/toto will work (with changing protocols/smpp/test/test_post_upgrade.py to from protocols.toto.proto import *
The second solution is so confusing as i dont have any smpp/proto.py in my system that can cause a conflict ...
Here's a simpler representation of the issue:
Wass/
Wass/__init__.py
Wass/protocols/
Wass/protocols/smpp/
Wass/protocols/smpp/__init__.py
Wass/protocols/smpp/test/
Wass/protocols/smpp/test/__init__.py
Wass/protocols/__init__.py
Wass/protocols/smpp/test/test_post_upgrade.py:
> from Wass.protocols.smpp.proto import SMPPClientProtocol
Wass/protocols/smpp/proto.py
> from twisted.internet import defer, reactor
>
> class SMPPClientProtocol:
> pass
Execution outcome:
$ echo $PYTHONPATH
:/opt/smpp.twisted/:/opt/smpp.pdu/:/tmp/Wass/
python /tmp/Wass/protocols/smpp/test/test_post_upgrade.py
> Returns the same problem above
There are a number of potential issues here.
Is Wass really supposed to be a package, or is it an entry on sys.path? If it's really a package, you should be adding /tmp to your PYTHONPATH; if it's a path entry, you should be adding /tmp/Wass to PYTHONPATH, and deleting /tmp/Wass/__init__.py*.
Don't run python on modules within a hierarchy directly. It confuses the issue.
If Wass is going to continue to be a package (i.e. contain an __init__.py), you should adjust your imports to be from Wass.protocols.smpp.proto import ....
Don't use import *. It's just confusing; someone reading your code has no idea what names are supposed to come from what module.
Try to simplify this as much as possible, and upload a complete, runnable example of a set of files that causes the problem. Since I don't know what's inside those .py files, I have to guess at the cause.
Ultimately I think that the problem you're seeing is caused by the combination of a top-level module named protocols, which conflicts with several modules within Twisted, and the use of import * which is probably pulling in another name like basic or smtp or pop3 into that namespace and clashing with something, then the magic of namespace packages combines with it all to create an explosion. I can't be more specific than that without seeing the actual code that triggers the problem :).
Whenever faced with an issue like this though, it's good to take a step back and make sure that the working directory, the script directory, and PYTHONPATH are all separated out so you know exactly how your code is being imported. Specifically, I'd recommend doing something like this:
$ cd /tmp
$ mkdir runstuff
$ cd runstuff
$ PYTHONPATH=/tmp/Wass trial protocols
Hopefully that will work out better for you.

Categories

Resources