Python:builtins
lastmod 2025-02-15created 2021-09-1314 edits
Types, functions, etc. built into (builtins) Python
exec
The isolated way to call exec with the fewest malfunctions is as follows:
from importlib import import_module
def get_annotations_compiler_flag() -> int:
future = import_module("__future__")
assert future is not None
annotations = getattr(future, "annotations")
assert annotations is not None
compiler_flag = getattr(annotations, "compiler_flag")
assert isinstance(compiler_flag, int)
return compiler_flag
COMPILE_MODE_EXEC = "exec"
COMPILE_FLAGS = get_annotations_compiler_flag()
path = '/python/file/path.py'
global_variables = {}
with open(path, "r") as f:
source = f.read()
ast = compile(source, path, COMPILE_MODE_EXEC, COMPILE_FLAGS)
exec(ast, global_variables, global_variables)
property
Returns a property attribute.
-
fget: a function for getting the attribute value. -
fset: a function for setting the attribute value. -
fdel: a function for deleting the attribute value. -
doc: creates the docstring of the attribute.
class C:
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
Troubleshooting
NameError from the typing package in exec
When running the exec() function, a Type Annotation-related error like the following may occur.
The first approach is to add code that enables Annotations Future to the code passed to exec().
Alternatively, add the above flag to the flags variable when calling compile(). The following shows how to obtain that flag. (See the related documentation for details):
from importlib import import_module
def get_annotations_compiler_flag() -> int:
future = import_module("__future__")
assert future is not None
annotations = getattr(future, "annotations")
assert annotations is not None
compiler_flag = getattr(annotations, "compiler_flag")
assert isinstance(compiler_flag, int)
return compiler_flag
coverage.py malfunctions after exec
An AttributeError like the following may occur.
The full Traceback is as follows:
Traceback (most recent call last):
File "/home/yourid/Project/answer-dev/core/recc/http/http_app.py", line 178, in _runner
await _run_app(
File "/home/yourid/.pyenv/versions/opy-yourid-3.8.9/lib/python3.8/site-packages/aiohttp/web.py", line 319, in _run_app
await runner.setup()
File "/home/yourid/.pyenv/versions/opy-yourid-3.8.9/lib/python3.8/site-packages/aiohttp/web_runner.py", line 275, in setup
self._server = await self._make_server()
File "/home/yourid/.pyenv/versions/opy-yourid-3.8.9/lib/python3.8/site-packages/aiohttp/web_runner.py", line 375, in _make_server
await self._app.startup()
File "/home/yourid/.pyenv/versions/opy-yourid-3.8.9/lib/python3.8/site-packages/aiohttp/web_app.py", line 416, in startup
await self.on_startup.send(self)
File "/home/yourid/.pyenv/versions/opy-yourid-3.8.9/lib/python3.8/site-packages/aiohttp/signals.py", line 34, in send
await receiver(*args, **kwargs) # type: ignore
File "/home/yourid/Project/answer-dev/core/recc/http/http_app.py", line 141, in on_startup
await self._context.open()
File "/home/yourid/Project/answer-dev/core/recc/core/context.py", line 85, in open
self._plugins.create(self, *plugin_scripts)
File "/home/yourid/Project/answer-dev/core/recc/plugin/plugin_manager.py", line 13, in create
plugin = Plugin(file)
File "/home/yourid/Project/answer-dev/core/recc/plugin/plugin.py", line 49, in __init__
self._global_variables = exec_python_plugin(path)
File "/home/yourid/Project/answer-dev/core/recc/plugin/plugin.py", line 40, in exec_python_plugin
exec(ast, global_variables, local_variables)
File "/home/yourid/.pyenv/versions/opy-yourid-3.8.9/lib/python3.8/site-packages/coverage/control.py", line 323, in _should_trace
disp = self._inorout.should_trace(filename, frame)
File "/home/yourid/.pyenv/versions/opy-yourid-3.8.9/lib/python3.8/site-packages/coverage/inorout.py", line 237, in should_trace
filename = source_for_file(dunder_file)
File "/home/yourid/.pyenv/versions/opy-yourid-3.8.9/lib/python3.8/site-packages/coverage/python.py", line 106, in source_for_file
if filename.endswith(".py"):
AttributeError: 'PosixPath' object has no attribute 'endswith'
This happens because a pathlib.Path was passed as the filename (filename) during #compile. The filename (filename) argument of #compile must be passed as a str.
NameError when using Annotated assignment statements in exec
- Glossary — Python 3.9.7 documentation # variable annotation
- 7. Simple statements — Python 3.9.7 documentation # 7.2.2. Annotated assignment statements
Use the same object for the exec() globals and locals arguments.
AttributeError when using dataclass in exec
When using dataclass, an error like the following may occur:
The full Traceback is as follows:
Traceback (most recent call last):
...
File "/home/yourid/Project/answer-dev/core/recc/plugin/plugin.py", line 39, in __init__
exec_python_plugin(path, global_variables, global_variables)
File "/home/yourid/Project/answer-dev/core/recc/plugin/plugin.py", line 30, in exec_python_plugin
exec(ast, global_variables, local_variables)
File "/home/yourid/Project/answer-dev/core/storage/plugin/a4y.py", line 517, in <module>
class A4yA:
File "/home/yourid/.pyenv/versions/3.8.9/lib/python3.8/dataclasses.py", line 1019, in dataclass
return wrap(cls)
File "/home/yourid/.pyenv/versions/3.8.9/lib/python3.8/dataclasses.py", line 1011, in wrap
return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
File "/home/yourid/.pyenv/versions/3.8.9/lib/python3.8/dataclasses.py", line 861, in _process_class
cls_fields = [_get_field(cls, name, type)
File "/home/yourid/.pyenv/versions/3.8.9/lib/python3.8/dataclasses.py", line 861, in <listcomp>
cls_fields = [_get_field(cls, name, type)
File "/home/yourid/.pyenv/versions/3.8.9/lib/python3.8/dataclasses.py", line 712, in _get_field
and _is_type(f.type, cls, typing, typing.ClassVar,
File "/home/yourid/.pyenv/versions/3.8.9/lib/python3.8/dataclasses.py", line 658, in _is_type
ns = sys.modules.get(cls.__module__).__dict__
AttributeError: 'NoneType' object has no attribute '__dict__'
The Python code is as follows:
global_variables = {
"__name__": "__recc_plugin__",
"__file__": path,
}
with open(path, "r") as f:
source = f.read()
ast = compile(source, path, COMPILE_MODE_EXEC, COMPILE_FLAGS)
exec(ast, global_variables, global_variables)
The problem is a chain reaction in the following order:
- If
__name__is set in the global variables, the module with that name is used. - The
clsargument passed to@dataclassis delivered as {module}.{class}. - So in the case above,
clsis__recc_plugin__.A4yA. -
cls.__module__is'__recc_plugin__'. -
sys.modules.get(cls.__module__)looks up the module named__recc_plugin__. - As a result, there is no such module, so it is None.
The fix is to remove all values passed in global_variables; then appropriate values are applied. (The module seems to be set to builtins)
The fixed code is as follows:
global_variables = {}
with open(path, "r") as f:
source = f.read()
ast = compile(source, path, COMPILE_MODE_EXEC, COMPILE_FLAGS)
exec(ast, global_variables, global_variables)
For reference, see the Python:importlib page for how to load modules.
The annotations instance of a function symbol obtained from exec is Dict[str, str] instead of Dict[str, type]
In this case, reset annotations using the #eval function.
def update_routes(self) -> None:
routes = list()
for method, path, guest_route in self._call_get_routes():
host_route = deepcopy(guest_route)
if hasattr(host_route, "__annotations__"):
assert isinstance(host_route.__annotations__, dict)
update_annotations: Dict[str, Any] = dict()
for key, annotation in host_route.__annotations__.items():
if isinstance(annotation, type):
update_annotations[key] = annotation
else:
type_origin = eval(
annotation,
self._global_variables,
self._global_variables,
)
if type_origin is not None:
update_annotations[key] = type_origin
else:
update_annotations[key] = annotation
host_route.__annotations__ = update_annotations
routes.append(Route(method, path, host_route))
self._routes = routes
See also
Favorite site
- [Recommended] Jump to Python - Built-in Functions 1
References
-
Jump_to_Python_-_Builtin_Functions.pdf ↩