Issue
I'm working on updating an Python library to use modern versions of Python (the Equation library) and am having trouble with Pylance when importing from the module. The base form of the library also had this issue, but for reference, here's my fork: Antyos/Equation.
As the library describes, you are supposed to be able to import the Expression class like so:
from Equation import Expression
e = Expression("sin(x+y^2)")
This code works, however, Pylance will give the following error:
"Expression" is unknown import symbol Pylance(reportGeneralTypeIssues)
If I import the code as follows, I don't receive the error and I can get type hints.
from Equation.core import Expression
My Understanding
I roughly understand the issue--as shown in the file structure below, it makes sense that from Equation.core import Expression would work. I also understand that __init__.py is exposing the Expression class to the top level of the module. (I still don't totally get how this part works and I can't seem to find the right page/section detailing it.)
Equation
├─ __init__.py
├─ _info.py
├─ core.py # Contains Expression()
├─ equation_base.py
├─ equation_scipy.py
├─ similar.py
└─ util.py
While I'm pretty sure I could get around this issue by writing a stub (*.pyi) file, it seems redundant (to me) to create a stub file for a class that I already have direct access to; why would I need to redefine something that's already there? However, it is also likely that I don't completely understand how stub files / module imports work and this is the right way.
I'm sure this issue has been addressed before, but I think I've been using the wrong terminology. What am I missing?
In __init__.py I believe you are performing relative import:
try:
from Equation.core import Expression
except ImportError:
from core import Expression
The correct way to perform relative import here is to put . in front of core like this .core.
For example:
try:
from Equation.core import Expression
except ImportError:
from .core import Expression
This fixes Pylance when I tried it.
Spec reference: https://docs.python.org/3/reference/import.html#package-relative-imports
I ran into a problem in which I was having the following error within vscode:
"some_module" is unknown import symbol
It turned out to be that the folder structure where the module was contained changed but the way to import it remained. The problem was that some old pycache existed in my local working copy within the old folder structure. After removing all of them, pylance started to work normally.
Related
I currently have a package A from someone else that uses an import syntax like import A in its code, e.g. A/B/C/xx.py.
What I want to do is to reference package A in my project X, forming a package structure X/A like this. However, I need to meet the following two requirements:
not modify a single line of code in A
import A is not valid anywhere else unless it is in package X.
I spent a few days looking for a workaround, but none of it worked. All methods that do not throw an error result in import A being available everywhere else.
You could create a my_requirements.py file that does all imports leaving out module_name or again deleing module_name under the conditions that you demand. You would then just have to:
import my_requirements
I am working in the following directory tree:
src/
__init__.py
train.py
modules/
__init__.py
encoders/
__init__.py
rnn_encoder.py
My pwd is the top-level directory and my __init__.py files are all empty. I am executing train.py, which contains the following code snippet.
import modules
# RNNEncoder is a class in rnn_encoder.py
encoder = modules.encoders.rnn_encoder.RNNEncoder(**params)
When I execute train.py, I get an error saying that
AttributeError: module 'modules' has no attribute 'encoders'
I am wondering if there is any clean way to make this work. Note that I am not looking for alternative methods of importing, I am well-aware that this can be done in other ways. What I'd like to know is whether it is possible to keep the code in train.py as is while maintaining the given directory structure.
Putting an __init__.py file in a folder allows that folder to act as an import target, even when it's empty. The way you currently have things set up, the following should work:
from modules.encoders import rnn_encoder
encoder = rnn_encoder.RNNEncoder(**params)
Here, python treats modules.encoders as a filepath, essentially, and then tries to actually import the code inside rnn_encoder.
However, this won't work:
import modules
encoder = modules.encoders.rnn_encoder.RNNEncoder(**params)
The reason is that, when you do import modules, what python is doing behind the scenes is importing __init__.py from the modules folder, and nothing else. It doesn't run into an error, since __init__.py exists, but since it's empty it doesn't actually do much of anything.
You can put code in __init__.py to fill out your module's namespace and allow people to access that namespace from outside your module. To solve your problem, make the following changes:
modules/encoders/__init__.py
from . import rnn_encoder
modules/__init__.py
from . import encoders
This imports rnn_encoder and assigns it to the namespace of encoders, allowing you to import encoders and then access encoders.rnn_encoder. Same with modules.encoders, except a step upwards.
I have the following project structure:
MainScript.py
ExampleFolder
├ MainImport.py
└ SecondaryImport.py
MainScript.py: import ExampleFolder.MainImport
MainImport.py: Import SecondaryImport
When I try to run MainImport.py it gets no errors, but when I try to run MainScript.py, I get an import error that says No module named 'SecondaryImport'.
My question is simple - is there any way that I can import only MainImport.py from MainScript.py without getting this error, and importing SecondaryImport.py? Thanks in advance!
I have also tried adding a blank file named __init__.py to the ExampleFolder, but the error still appears. I also read Python's official documentation, but I could not find the problem. Am I missing something? (:
I think using the statement import ExampleFolder.SecondaryImport would work.
If it does, the error might be happening because as mentioned in docs, import statements will usually start searching your main project directory where the python interpreter was called if your module is not in python itself.
Another way would be to use relative import statement like this:
import .secondaryimport in order to tell the python interpreter to look in the current directory. Hope this helps!
Taking a look at these links will help, I think (It helped me when I was stuck in a similar problem):
https://docs.python.org/3/library/sys.html#sys.path
https://realpython.com/absolute-vs-relative-python-imports/
I have also tried adding a blank file named __init__.py to the ExampleFolder
That's the way - you're creating a Python package from a directory that way. And with packages you have got namespace directory.file where file is a Python file also known as module in Python world.
Then you can do from mainscript.py:
from examplefolder import mainimport
For importing inside package you may use the following syntax inside mainscript.py:
import secondaryimport
and use it in that mainscript.py as:
sevondaryimport.SomeClass()
or you may just do:
from secondaryimport import SomeClass
and use it like:
SomeClass()
Btw, use lowercase in all the cases except classes names - only they should have CamelCase names.
My structure is thus:
companynamespace/
__init__.py
projectpackage/
__init__.py
somemodule.py
companynamespace/__init__.py is empty
projectpackage/__init__.py has this line:
import companynamespace.projectpackage.somemodule as module_shortname
When I open up a python console and type import companynamespace.projectpackage (PYTHONPATH is set correctly for this), I get AttributeError: 'module' object has no attribute 'projectpackage' on the import companynamespace.projectpackage.somemodule as module_shortname line. If I remove the as module_shortname part (and make all the requisite substitutions in the rest of the file), everything imports correctly.
Can anyone tell me why this is? My Google-Fu fails me.
There is no need for absolute import in projectpackage/__init__.py, do relative one
import somemodule as module_shortname
The way you're doing it (with absolute import), would lead to circular import, which don't work very well in Python. When you're importing module, you're also calling __init__.py of parent modules. In your case, with absolute import you're also calling projectpackage/__init__.py in projectpackage/__init__.py.
Well, according to the PEP 221 your code seems to be legitimate. It could be a bug. The following workaround, which is equivalent of that expression, works for me (Python 2.6.6):
from companynamespace.projectpackage import somemodule as module_shortname
Hope it helps.
I've done what I shouldn't have done and written 4 modules (6 hours or so) without running any tests along the way.
I have a method inside of /mydir/__init__.py called get_hash(), and a class inside of /mydir/utils.py called SpamClass.
/mydir/utils.py imports get_hash() from /mydir/__init__.
/mydir/__init__.py imports SpamClass from /mydir/utils.py.
Both the class and the method work fine on their own but for some reason if I try to import /mydir/, I get an import error saying "Cannot import name get_hash" from /mydir/__init__.py.
The only stack trace is the line saying that __init__.py imported SpamClass. The next line is where the error occurs in in SpamClass when trying to import get_hash. Why is this?
This is a pretty easy problem to encounter. What's happening is this that the interpreter evaluates your __init__.py file line-by line. When you have the following code:
import mydir.utils
def get_hash(): return 1
The interpreter will suspend processing __init__.py at the point of import mydir.utils until it has fully executed 'mydir/utils.py' So when utils.py attempts to import get_hash(), it isn't defined because the interpreter hasn't gotten to it's definition yet.
To add to what the others have said, another good approach to avoiding circular import problems is to avoid from module import stuff.
If you just do standard import module at the top of each script, and write module.stuff in your functions, then by the time those functions run, the import will have finished and the module members will all be available.
You then also don't have to worry about situations where some modules can update/change one of their members (or have it monkey-patched by a naughty third party). If you'd imported from the module, you'd still have your old, out-of-date copy of the member.
Personally, I only use from-import for simple, dependency-free members that I'm likely to refer to a lot: in particular, symbolic constants.
In absence of more information, I would say you have a circular import that you aren't working around. The simplest, most obvious fix is to not put anything in mydir/__init__.py that you want to use from any module inside mydir. So, move your get_hash function to another module inside the mydir package, and import that module where you need it.