ImportError: cannot import name (not a circular dependency) - python

I have the problem on importing the class in the same package, and it seems not a circular dependency problem. So I'm really confused now.
my-project/
lexer.py
exceptions.py
I declared an exception in exceptions.py and wants to use it in lexer.py:
exceptions.py:
class LexError(Exception):
def __init__(self, message, line):
self.message = message
self.line = line
and in lexer.py:
import re
import sys
from exceptions import LexError
...
It shouldn't be circular dependency since lexer.py is the only file has import in it.
Thanks!!

exceptions conflicts with builtin module exception.
>>> import exceptions
>>> exceptions.LexError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'LexError'
>>> from exceptions import LexError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name LexError
Use different module name.

Related

Wierd attribute error with importing into directories

I have a directory tree as follows:
main.py
dir1
sub1.py
sub2.py
In main.py:
import dir1.sub1
In dir1/sub1.py:
def f1() -> None:
print("f1")
import dir1.sub2
dir1.sub2.f2()
In dir1/sub2.py:
import dir1.sub1
def f2() -> None:
dir1.sub1.f1()
print("f2")
When I run main.py, I get the following error message:
Traceback (most recent call last):
File "...\main.py", line 1, in <module>
import dir1.sub1
File "...\dir1\sub1.py", line 7, in <module>
dir1.sub2.f2()
File "...\dir1\sub2.py", line 5, in f2
dir1.sub1.f1()
AttributeError: module 'dir1' has no attribute 'sub1'. Did you mean: 'sub2'?
(Where the ... at the beginning of the file path is my working directory.)
If I change main.py to
import dir1.sub2
I get a slightly different error message:
Traceback (most recent call last):
File "...\main.py", line 1, in <module>
import dir1.sub2
File "...\dir1\sub2.py", line 1, in <module>
import dir1.sub1
File "...\dir1\sub1.py", line 7, in <module>
dir1.sub2.f2()
AttributeError: module 'dir1' has no attribute 'sub2'
If I move sub1.py and sub2.py to the same directory as main.py and re‐direct imports as necessary, I get the expected output of
f1
f2
Why does this happen, and how can I make it not happen?
You need to use absolute import because Python 3 only supports that. In Python 2 your method will work. So for example if you have import dir1.sub2 change it to from dir1 import sub2. See here.
Note: I've tested it with your setup and it works.

After setting __import__ to None why I can still import?

If I do this:
__import__ = None
Then import a module:
import random
I still can. Why?
It doesn't call the reference in your module. It uses the one in builtins. Try:
import builtins
builtins.__import__ = None
import random
And you'll see it fail with:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

Raise custom ImportError when user imports a deprecated variable [duplicate]

This question already has answers here:
How to mark a global as deprecated in Python?
(4 answers)
Closed 4 years ago.
I have written a package where a sub-module contains a module-level variable deprecated_var that I want to remove, because it was a horrible mistake.
mypkg
- mymodule
- __init__.py
But instead of just leaving my end users with a generic ImportError, I want to print a message that says their import is deprecated, and what they should do. So instead of:
>>> from mypkg.mymodule import deprecated_var
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'deprecated_var'
I want users to see something like this:
>>> from mypkg.mymodule import deprecated_var
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: mypkg.mymodule.deprecated_var was removed. Replace
with "from foo.bar import Baz; deprecated_var = Baz()"
How can I achieve that?
I don't think this is possible before python 3.7.
However, in python 3.7 or later, this can be achieved by using the module level __getattr__ added in PEP562.
You'd use like so:
#_deprecated_vars is a dict of keys -> alternatives (or None)
_deprecated_vars: Dict[str, Optional[str]] = {
'deprecated_var': 'from foo.bar import Baz; deprecated_var = Baz()',
'other_deprecated_var': None
}
def __getattr__(name):
if name in _deprecated_vars:
alt_text = '{name} was removed from module {__name__}'
replace_text = _deprecated_vars[name]
if replace_text is not None:
alt_text += f'. Replace with {replace_text!r}.'
raise AttributeError(alt_text)
raise AttributeError(f"module {__name__} has no attribute {name}")
However, I'm not sure this works for your use case of from a.b import deprecated_var. This is more for import a.b; a.b.deprecated_var. See the other answer for the former.
For your specific example, you could use the following:
mymodule/__init__.py:
#deprecated_var = 5
replacement_var = 6
mymodule/deprecated_var.py:
raise ImportError("deprecated_var is deprecated. Use mypkg.mymodule.replacement_var instead")
While this raises the custom ImportError when importing the variable directly:
>>> from mymodule import deprecated_var
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../mymodule/deprecated_var.py", line 1, in <module>
raise ImportError("deprecated_var is deprecated. Use mypkg.mymodule.replacement_var instead")
ImportError: deprecated_var is deprecated. Use mypkg.mymodule.replacement_var instead
it does nothing when accessing it as a module attribute. Or rather, it throws an AttributeError instead of a deprecation warning:
>>> import mymodule
>>> mymodule.deprecated_var
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'mymodule' has no attribute 'deprecated_var'

python reload module for beginner. importlib.reload doesn't seem to work

I have a file called skdb and class called skmysqldb. I am trying to force reload.
I tried reloading "skdb", "skdb.skmysqldb" "skmysqldb" and none of them seem to work.
>>> from skdb import skmysqldb
>>> importlib.reload(skdb.skmysqldb)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'skdb' is not defined
>>> importlib.reload(skmysqldb)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\importlib\__init__.py", line 139, in reload
raise TypeError("reload() argument must be a module")
TypeError: reload() argument must be a module
>>> importlib.reload(skdb)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'skdb' is not defined
When you import some object using the from <module> import <obj> syntax as in
from skdb import skmysqldb
the module itself is not added to the current namespace, hence why you get a NameError when you try to do reload(skdb).
Instead try:
import skdb
importlib.reload(skdb)
Be cautious when using reload. If the module your reload imports other modules, those modules are not reloaded recursively, so depending on the exact code you can wind up in a rather broken state where it's better to just restart the whole interpreter.
I don't think this is supported, but try doing del sys.modules['mymodule'] for everything that vaguely matches. To find relevant ones, try something like [x for x in sys.modules if 'mymodule' in x].

How can I display exceptions normally in iPython?

I like iPythons way of mixing terminal commands and Python, but I dislike its way of showing exceptions. It looks like this:
>>> import foo
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
<ipython-input-5-34d390fb3acc> in <module>()
----> 1 import foo
ImportError: No module named foo
I would rather see the normal Python exception printing:
>>> import foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named foo
I've searched for such a setting in the config but couldn't find it. How can I do it?
Set xmode to plain:
In [8]: %xmode plain
Exception reporting mode: Plain
In [9]: import foo
Traceback (most recent call last):
File "<ipython-input-9-34d390fb3acc>", line 1, in <module>
import foo
ImportError: No module named 'foo'
Or use the corresponding config file entry:
c.TerminalInteractiveShell.xmode = 'Plain'

Categories

Resources