Skip to content

Conversation

@p-zander
Copy link
Contributor

@p-zander p-zander commented Aug 29, 2025

I was running into import issues with dataclass (when running pytest) in Python 3.12 that were observed in other projects as well:

The error message looks like this:

tests/linter/utils/__init__.py:121: in check_rule
    check_files(
src/robocop/run.py:314: in check_files
    return runner.run()
           ^^^^^^^^^^^^
src/robocop/linter/runner.py:55: in run
    diagnostics = self.run_check(model, source, config)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/robocop/linter/runner.py:85: in run_check
    for checker in config.linter.checkers:
                   ^^^^^^^^^^^^^^^^^^^^^^
src/robocop/config.py:207: in checkers
    self.load_configuration()
src/robocop/config.py:227: in load_configuration
    self.load_checkers()
src/robocop/config.py:241: in load_checkers
    rules.init(self)
src/robocop/linter/rules/__init__.py:808: in init
    for checker in robocop_importer.get_initialized_checkers():
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/robocop/linter/rules/__init__.py:643: in get_initialized_checkers
    yield from self._get_checkers_from_modules(self.get_internal_modules())
src/robocop/linter/rules/__init__.py:657: in _get_checkers_from_modules
    for module in modules:
                  ^^^^^^^
src/robocop/linter/rules/__init__.py:692: in modules_from_paths
    yield self._import_module_from_file(path_object)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/robocop/linter/rules/__init__.py:712: in _import_module_from_file
    spec.loader.exec_module(mod)
<frozen importlib._bootstrap_external>:999: in exec_module
    ???
<frozen importlib._bootstrap>:488: in _call_with_frames_removed
    ???
src/robocop/linter/rules/lengths.py:674: in <module>
    @dataclass
     ^^^^^^^^^
../../.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/dataclasses.py:1275: in dataclass
    return wrap(cls)
           ^^^^^^^^^
../../.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/dataclasses.py:1265: in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash,
../../.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/dataclasses.py:983: in _process_class
    and _is_type(type, cls, dataclasses, dataclasses.KW_ONLY,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

annotation = 'str', cls = <class 'lengths.CachedVariable'>
a_module = <module 'dataclasses' from '/home/name/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/dataclasses.py'>
a_type = <dataclasses._KW_ONLY_TYPE object at 0x72387b805e20>
is_type_predicate = <function _is_kw_only at 0x72387b89ef20>

    def _is_type(annotation, cls, a_module, a_type, is_type_predicate):
        ...
    
        match = _MODULE_IDENTIFIER_RE.match(annotation)
        if match:
            ns = None
            module_name = match.group(1)
            if not module_name:
                # No module name, assume the class's module did
                # "from dataclasses import InitVar".
>               ns = sys.modules.get(cls.__module__).__dict__
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E               AttributeError: 'NoneType' object has no attribute '__dict__'. Did you mean: '__dir__'?

../../.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/dataclasses.py:749: AttributeError

I don't claim that I understand what's going on there, but the examples from the importlib documentation, the solutions to the above mentioned bugs and other references like https://github.com/wntrblm/nox/blob/main/nox/tasks.py#L78 all lead me to believe that this is the way. At least for me it did solve the errors.

I would love to verify with Python 3.9 as well Also failing as you can see here. Not sure what is triggering this problem only now.

Maybe someone with a deeper understanding of importlib can make sense of this.

Fix AttributeError when importing dataclass
@bhirsz
Copy link
Member

bhirsz commented Aug 30, 2025

That's interesting..but I admit that I have also used tinkered with sys.modules in the past because of the pytest. There are some leftovers in code such as:

def clear_imported_module(module):
sys.modules.pop(module, None)

I also don't know exactly what's happening but my suspicion is that pytest is doing a bit of caching on its own to speed up test execution. This doesn't play nice with how Robocop is constructed (we have some dynamic code loading to enable pluginable rules and formatters). This is actually reflected in #1419 since it's also connected to dynamic loading.

Since our regression seems fine with the change, LGTM.

@bhirsz bhirsz merged commit e55f3df into MarketSquare:main Aug 30, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants