Skip to content

Commit dfd88f5

Browse files
authored
Fix PyPy ClassDef.fromlino with decorators (#1979)
1 parent 0c9ab0f commit dfd88f5

File tree

5 files changed

+18
-23
lines changed

5 files changed

+18
-23
lines changed

ChangeLog

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Release date: TBA
1515
* Fix issues with ``typing_extensions.TypeVar``.
1616

1717

18+
* Fix ``ClassDef.fromlino`` for PyPy 3.8 (v7.3.11) if class is wrapped by a decorator.
19+
1820

1921
What's New in astroid 2.13.3?
2022
=============================

astroid/const.py

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
IS_PYPY = sys.implementation.name == "pypy"
1919
IS_JYTHON = sys.implementation.name == "jython"
2020

21+
# pylint: disable-next=no-member
22+
PYPY_7_3_11_PLUS = IS_PYPY and sys.pypy_version_info >= (7, 3, 11) # type: ignore[attr-defined]
23+
2124

2225
class Context(enum.Enum):
2326
Load = 1

astroid/nodes/scoped_nodes/scoped_nodes.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from astroid import bases
2323
from astroid import decorators as decorators_mod
2424
from astroid import util
25-
from astroid.const import IS_PYPY, PY38, PY38_PLUS, PY39_PLUS
25+
from astroid.const import IS_PYPY, PY38, PY38_PLUS, PY39_PLUS, PYPY_7_3_11_PLUS
2626
from astroid.context import (
2727
CallContext,
2828
InferenceContext,
@@ -2139,9 +2139,10 @@ def _newstyle_impl(self, context: InferenceContext | None = None):
21392139
@cached_property
21402140
def fromlineno(self) -> int | None:
21412141
"""The first line that this node appears on in the source code."""
2142-
if not PY38_PLUS or PY38 and IS_PYPY:
2142+
if not PY38_PLUS or IS_PYPY and PY38 and not PYPY_7_3_11_PLUS:
21432143
# For Python < 3.8 the lineno is the line number of the first decorator.
21442144
# We want the class statement lineno. Similar to 'FunctionDef.fromlineno'
2145+
# PyPy (3.8): Fixed with version v7.3.11
21452146
lineno = self.lineno
21462147
if self.decorators is not None:
21472148
lineno += sum(

tests/unittest_builder.py

+7-15
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import pytest
2020

2121
from astroid import Instance, builder, nodes, test_utils, util
22-
from astroid.const import IS_PYPY, PY38, PY38_PLUS, PY39_PLUS
22+
from astroid.const import IS_PYPY, PY38, PY38_PLUS, PY39_PLUS, PYPY_7_3_11_PLUS
2323
from astroid.exceptions import (
2424
AstroidBuildingError,
2525
AstroidSyntaxError,
@@ -130,18 +130,18 @@ def function(
130130
def test_decorated_class_lineno() -> None:
131131
code = textwrap.dedent(
132132
"""
133-
class A:
133+
class A: # L2
134134
...
135135
136136
@decorator
137-
class B:
137+
class B: # L6
138138
...
139139
140140
@deco1
141141
@deco2(
142142
var=42
143143
)
144-
class C:
144+
class C: # L13
145145
...
146146
"""
147147
)
@@ -155,23 +155,15 @@ class C:
155155

156156
b = ast_module.body[1]
157157
assert isinstance(b, nodes.ClassDef)
158-
if PY38 and IS_PYPY:
159-
# Not perfect, but best we can do for PyPy 3.8
160-
assert b.fromlineno == 7
161-
else:
162-
assert b.fromlineno == 6
158+
assert b.fromlineno == 6
163159
assert b.tolineno == 7
164160

165161
c = ast_module.body[2]
166162
assert isinstance(c, nodes.ClassDef)
167-
if not PY38_PLUS:
168-
# Not perfect, but best we can do for Python 3.7
163+
if not PY38_PLUS or IS_PYPY and PY38 and not PYPY_7_3_11_PLUS:
164+
# Not perfect, but best we can do for Python 3.7 and PyPy 3.8 (< v7.3.11).
169165
# Can't detect closing bracket on new line.
170166
assert c.fromlineno == 12
171-
elif PY38 and IS_PYPY:
172-
# Not perfect, but best we can do for PyPy 3.8
173-
# Can't detect closing bracket on new line.
174-
assert c.fromlineno == 16
175167
else:
176168
assert c.fromlineno == 13
177169
assert c.tolineno == 14

tests/unittest_nodes_position.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import textwrap
88

99
from astroid import builder, nodes
10-
from astroid.const import IS_PYPY, PY38
1110

1211

1312
class TestNodePosition:
@@ -65,11 +64,9 @@ class F: #@
6564
assert isinstance(e, nodes.ClassDef)
6665
assert e.position == (13, 0, 13, 7)
6766

68-
if not PY38 or not IS_PYPY:
69-
# The new (2022-12) version of pypy 3.8 broke this
70-
f = ast_nodes[5]
71-
assert isinstance(f, nodes.ClassDef)
72-
assert f.position == (18, 0, 18, 7)
67+
f = ast_nodes[5]
68+
assert isinstance(f, nodes.ClassDef)
69+
assert f.position == (18, 0, 18, 7)
7370

7471
@staticmethod
7572
def test_position_function() -> None:

0 commit comments

Comments
 (0)