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
Related
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'
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].
I'm trying to define a method (let's call it hello) in main.py's Things class, from define.py.
The code I currently have is raising AttributeError: module 'runme' has no attribute 'promptMe' (full traceback below).
Here's main.py's code:
import define
class Things:
def doWhatever():
print("whatever")
Here's define.py's code:
import main
def hello():
print("Hello!")
main.Things.hello = hello()
I've tried other solutions such as def main.Things.hello: hello() and def main.Things.hello: print("Hello!") but none work.
Here's the traceback when running define.py:
Traceback (most recent call last):
File "define.py", line 5, in <module>
import main
File "/path/to/main.py", line 9, in <module>
import define
File "/path/to/define.py", line 10, in <module>
main.Things.hello = hello
AttributeError: module 'main' has no attribute 'Things'
All help would be greatly appreciated. Thanks!
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.
How do you print doc strings in python 3.1.x?
I tried with the re and sys modules as a test and I keep getting errors. Thanks
import re
print(re._doc_)
Traceback (most recent call last):
File "<pyshell#91>", line 1, in <module>
print(re._doc_)
AttributeError: 'module' object has no attribute '_doc_'
It's called __doc__, not _doc_.
import re
print(re.__doc__)
Works just fine.