astroid icon indicating copy to clipboard operation
astroid copied to clipboard

Visit the transforms before handling delayed assattr nodes

Open marmarek opened this issue 1 year ago • 9 comments

Type of Changes

Type
:bug: Bug fix

Description

When importing Gtk, it looks like this:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

It is vital that gi.require_version() is made before related 'from gi.repository import ...'. The brain_gi tries to do that using transforms. And it works unless Gtk is imported as part of delayed assattr handling.

Fix this by handling transforms earlier.

Closes https://github.com/pylint-dev/astroid/issues/2190 Closes https://github.com/pylint-dev/pylint/issues/6352

marmarek avatar Jun 24 '24 00:06 marmarek

My change made one test fail now:

____________________ TypingBrain.test_typing_generic_slots _____________________

self = <tests.brain.test_brain.TypingBrain testMethod=test_typing_generic_slots>

    def test_typing_generic_slots(self):
        """Test slots for Generic subclass."""
        node = builder.extract_node(
            """
        from typing import Generic, TypeVar
        T = TypeVar('T')
        class A(Generic[T]):
            __slots__ = ['value']
            def __init__(self, value):
                self.value = value
        """
        )
        inferred = next(node.infer())
        slots = inferred.slots()
>       assert len(slots) == 1
E       TypeError: object of type 'NoneType' has no len()

I don't fully understand why, yet, but I think one option to make my change less invasive is to add "early transforms" and leave the original transforms in the old place. And then make brain_gi use the early transforms for the gi.require_version thing. Is that okay?

marmarek avatar Jun 24 '24 10:06 marmarek

Thank you for the MR. I agree with the proposed early transform, it feels like a big API decision but applying the transform twice so it's possible to apply transform after delayed attr creation is a lot worse. Let's hear another maintainer opinion before committing to it, it's not like I'm a brain expert myself.

Pierre-Sassoulas avatar Jun 24 '24 17:06 Pierre-Sassoulas

Have you also tried running the pylint testsuite with this version of astroid? I'm wondering if this is a fix we can indeed make, the failing test doesn't make me too hopeful.

DanielNoord avatar Jun 24 '24 18:06 DanielNoord

When running pylint test suite on plain main branch I got 12 failures already, but my change introduces 13th: test_functional[assigning_non_slot_4509] (assigning-non-slot message is not raised). The failure here is also related to slots, so it's probably the same thing.

I'll change my patch to not affect other brains.

marmarek avatar Jun 25 '24 14:06 marmarek

While at it, I've added also some basic test for brain_gi.

marmarek avatar Jun 25 '24 17:06 marmarek

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Project coverage is 92.73%. Comparing base (453d307) to head (b1f540d). Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #2453   +/-   ##
=======================================
  Coverage   92.72%   92.73%           
=======================================
  Files          94       94           
  Lines       10993    11007   +14     
=======================================
+ Hits        10193    10207   +14     
  Misses        800      800           
Flag Coverage Δ
linux 92.61% <100.00%> (+<0.01%) :arrow_up:
pypy 92.73% <100.00%> (+<0.01%) :arrow_up:
windows 92.71% <100.00%> (+<0.01%) :arrow_up:

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
astroid/brain/brain_gi.py 23.02% <100.00%> (ø)
astroid/builder.py 94.27% <100.00%> (+0.07%) :arrow_up:
astroid/manager.py 90.23% <100.00%> (+0.39%) :arrow_up:
astroid/test_utils.py 85.71% <100.00%> (+0.29%) :arrow_up:

codecov[bot] avatar Jun 25 '24 17:06 codecov[bot]

tests\brain\test_gi.py s [ 20%]

So, the test I added doesn't run in CI (which also explain minimal test coverage of brain_gi.py). Is it worth installing "gi" python module + Gtk3 (and maybe Gtk4 too?) in there to make the test run? Or is it enough for it to run when called manually locally (assuming those dependencies are installed)?

marmarek avatar Jun 28 '24 00:06 marmarek

Yeah I don't think we want to add those dependencies to the CI.

I do wonder if this warrants the API change. I can't really comment on that part (and I think most maintainers are a bit afraid of making such a decision). @Pierre-Sassoulas @jacobtylerwalls Do you have any opinions here?

DanielNoord avatar Jul 15 '24 14:07 DanielNoord

I do wonder if this warrants the API change.

Yeah, I'm reluctant to add an early transforms API for this. We should consider alternatives:

  • in _register_require_version(): manipulate sys.modules or use importlib.reload to reimport gi if necessary
  • remove brain_gi in favor of a new plugin to be homed at pylint-dev/pylint-gi

jacobtylerwalls avatar Jul 27 '24 15:07 jacobtylerwalls