-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Closed
Description
Note: I'm not sure whether this is a mkdos issue. So feel free to close it if it isn't.
If I use @dataclass in the hook, then mkdocs can't execute it because the module is not in sys.modules.
Minimal Example
# my_hook.py
from __future__ import annotations # I've no idea why this matters, but it does… (@_@)
from dataclasses import dataclass
@dataclass
class Foo:
bar: str# mkdocs.yml
# …
hooks:
- my_hook.pyNow mkdocs build.
# (skip many lines)
File "~\AppData\Local\Programs\Python\Python311\Lib\site-packages\mkdocs\config\base.py", line 55, in validate
return self.run_validation(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "~\AppData\Local\Programs\Python\Python311\Lib\site-packages\mkdocs\config\config_options.py", line 1048, in run_validation
hooks[name] = self._load_hook(name, path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "~\AppData\Local\Programs\Python\Python311\Lib\site-packages\mkdocs\config\config_options.py", line 1061, in _load_hook
spec.loader.exec_module(module)
# (skip many lines)
File "~\AppData\Local\Programs\Python\Python311\Lib\dataclasses.py", line 712, in _is_type
ns = sys.modules.get(cls.__module__).__dict__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute '__dict__'. Did you mean: '__dir__'?Workaround (for mkdocs users)
Try TypedDict or normal class + __init__().
Possible Cause
The module is executed (exec_module), but not added to sys.module. Therefore when dataclass calls sys.modules.get(cls.__module__), it gets nothing.
mkdocs/mkdocs/config/config_options.py
Lines 1051 to 1062 in 56b235a
| @functools.lru_cache(maxsize=None) | |
| def _load_hook(self, name, path): | |
| import importlib.util | |
| spec = importlib.util.spec_from_file_location(name, path) | |
| if spec is None: | |
| raise ValidationError(f"Cannot import path '{path}' as a Python module") | |
| module = importlib.util.module_from_spec(spec) | |
| if spec.loader is None: | |
| raise ValidationError(f"Cannot import path '{path}' as a Python module") | |
| spec.loader.exec_module(module) | |
| return module |
I am not an expert on importlib or CPython, but all examples in Python Doc add the module to sys.module.
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module # 👈 Here
spec.loader.exec_module(module)I can reproduce the errors in Python REPL:
>>> import sys
>>> from importlib import util
>>> spec = util.spec_from_file_location('my_hook', './my_hook.py')
>>> spec.loader.exec_module(module)
# (skip many lines)
File "~\AppData\Local\Programs\Python\Python311\Lib\dataclasses.py", line 712, in _is_type
ns = sys.modules.get(cls.__module__).__dict__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute '__dict__'. Did you mean: '__dir__'?
>>> module = util.module_from_spec(spec)
>>> spec.loader.exec_module(module)
>>>Additional Information
- Windows 10
- Python 3.11.2 (Update: and 3.11.3)
- mkdocs 1.4.2
pawamoy and oprypin
Metadata
Metadata
Assignees
Labels
No labels