Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 000cde5

Browse files
bpo-38307: Add end_lineno attribute to pyclbr Objects (GH-24348)
For back-compatibility, make the new constructor parameter for public classes Function and Class keyword-only with a default of None. Co-authored-by: Aviral Srivastava <[email protected] Co-authored-by: Terry Jan Reedy <[email protected]>
1 parent b5931f1 commit 000cde5

File tree

5 files changed

+56
-35
lines changed

5 files changed

+56
-35
lines changed

Doc/whatsnew/3.10.rst

+8
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,14 @@ py_compile
435435
Added ``--quiet`` option to command-line interface of :mod:`py_compile`.
436436
(Contributed by Gregory Schevchenko in :issue:`38731`.)
437437
438+
pyclbr
439+
------
440+
441+
Added an ``end_lineno`` attribute to the ``Function`` and ``Class``
442+
objects in the tree returned by :func:`pyclbr.readline` and
443+
:func:`pyclbr.readline_ex`. It matches the existing (start) ``lineno``.
444+
(Contributed by Aviral Srivastava in :issue:`38307`.)
445+
438446
shelve
439447
------
440448

Lib/idlelib/idle_test/test_browser.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,15 @@ def test_close(self):
6161
# Nested tree same as in test_pyclbr.py except for supers on C0. C1.
6262
mb = pyclbr
6363
module, fname = 'test', 'test.py'
64-
C0 = mb.Class(module, 'C0', ['base'], fname, 1)
65-
F1 = mb._nest_function(C0, 'F1', 3)
66-
C1 = mb._nest_class(C0, 'C1', 6, [''])
67-
C2 = mb._nest_class(C1, 'C2', 7)
68-
F3 = mb._nest_function(C2, 'F3', 9)
69-
f0 = mb.Function(module, 'f0', fname, 11)
70-
f1 = mb._nest_function(f0, 'f1', 12)
71-
f2 = mb._nest_function(f1, 'f2', 13)
72-
c1 = mb._nest_class(f0, 'c1', 15)
64+
C0 = mb.Class(module, 'C0', ['base'], fname, 1, end_lineno=9)
65+
F1 = mb._nest_function(C0, 'F1', 3, 5)
66+
C1 = mb._nest_class(C0, 'C1', 6, 9, [''])
67+
C2 = mb._nest_class(C1, 'C2', 7, 9)
68+
F3 = mb._nest_function(C2, 'F3', 9, 9)
69+
f0 = mb.Function(module, 'f0', fname, 11, end_lineno=15)
70+
f1 = mb._nest_function(f0, 'f1', 12, 14)
71+
f2 = mb._nest_function(f1, 'f2', 13, 13)
72+
c1 = mb._nest_class(f0, 'c1', 15, 15)
7373
mock_pyclbr_tree = {'C0': C0, 'f0': f0}
7474

7575
# Adjust C0.name, C1.name so tests do not depend on order.

Lib/pyclbr.py

+25-15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
name -- name of the object;
2222
file -- file in which the object is defined;
2323
lineno -- line in the file where the object's definition starts;
24+
end_lineno -- line in the file where the object's definition ends;
2425
parent -- parent of this object, if any;
2526
children -- nested objects contained in this object.
2627
The 'children' attribute is a dictionary mapping names to objects.
@@ -52,40 +53,50 @@
5253

5354
class _Object:
5455
"Information about Python class or function."
55-
def __init__(self, module, name, file, lineno, parent):
56+
def __init__(self, module, name, file, lineno, end_lineno, parent):
5657
self.module = module
5758
self.name = name
5859
self.file = file
5960
self.lineno = lineno
61+
self.end_lineno = end_lineno
6062
self.parent = parent
6163
self.children = {}
6264
if parent is not None:
6365
parent.children[name] = self
6466

67+
68+
# Odd Function and Class signatures are for back-compatibility.
6569
class Function(_Object):
6670
"Information about a Python function, including methods."
67-
def __init__(self, module, name, file, lineno, parent=None, is_async=False):
68-
super().__init__(module, name, file, lineno, parent)
71+
def __init__(self, module, name, file, lineno,
72+
parent=None, is_async=False, *, end_lineno=None):
73+
super().__init__(module, name, file, lineno, end_lineno, parent)
6974
self.is_async = is_async
7075
if isinstance(parent, Class):
7176
parent.methods[name] = lineno
7277

78+
7379
class Class(_Object):
7480
"Information about a Python class."
75-
def __init__(self, module, name, super_, file, lineno, parent=None):
76-
super().__init__(module, name, file, lineno, parent)
81+
def __init__(self, module, name, super_, file, lineno,
82+
parent=None, *, end_lineno=None):
83+
super().__init__(module, name, file, lineno, end_lineno, parent)
7784
self.super = super_ or []
7885
self.methods = {}
7986

87+
8088
# These 2 functions are used in these tests
8189
# Lib/test/test_pyclbr, Lib/idlelib/idle_test/test_browser.py
82-
def _nest_function(ob, func_name, lineno, is_async=False):
90+
def _nest_function(ob, func_name, lineno, end_lineno, is_async=False):
8391
"Return a Function after nesting within ob."
84-
return Function(ob.module, func_name, ob.file, lineno, ob, is_async)
92+
return Function(ob.module, func_name, ob.file, lineno,
93+
parent=ob, is_async=is_async, end_lineno=end_lineno)
8594

86-
def _nest_class(ob, class_name, lineno, super=None):
95+
def _nest_class(ob, class_name, lineno, end_lineno, super=None):
8796
"Return a Class after nesting within ob."
88-
return Class(ob.module, class_name, super, ob.file, lineno, ob)
97+
return Class(ob.module, class_name, super, ob.file, lineno,
98+
parent=ob, end_lineno=end_lineno)
99+
89100

90101
def readmodule(module, path=None):
91102
"""Return Class objects for the top-level classes in module.
@@ -108,6 +119,7 @@ def readmodule_ex(module, path=None):
108119
"""
109120
return _readmodule(module, path or [])
110121

122+
111123
def _readmodule(module, path, inpackage=None):
112124
"""Do the hard work for readmodule[_ex].
113125
@@ -198,9 +210,8 @@ def visit_ClassDef(self, node):
198210
bases.append(name)
199211

200212
parent = self.stack[-1] if self.stack else None
201-
class_ = Class(
202-
self.module, node.name, bases, self.file, node.lineno, parent
203-
)
213+
class_ = Class(self.module, node.name, bases, self.file, node.lineno,
214+
parent=parent, end_lineno=node.end_lineno)
204215
if parent is None:
205216
self.tree[node.name] = class_
206217
self.stack.append(class_)
@@ -209,9 +220,8 @@ def visit_ClassDef(self, node):
209220

210221
def visit_FunctionDef(self, node, *, is_async=False):
211222
parent = self.stack[-1] if self.stack else None
212-
function = Function(
213-
self.module, node.name, self.file, node.lineno, parent, is_async
214-
)
223+
function = Function(self.module, node.name, self.file, node.lineno,
224+
parent, is_async, end_lineno=node.end_lineno)
215225
if parent is None:
216226
self.tree[node.name] = function
217227
self.stack.append(function)

Lib/test/test_pyclbr.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,15 @@ def F3(): return 1+1
176176
actual = mb._create_tree(m, p, f, source, t, i)
177177

178178
# Create descriptors, linked together, and expected dict.
179-
f0 = mb.Function(m, 'f0', f, 1)
180-
f1 = mb._nest_function(f0, 'f1', 2)
181-
f2 = mb._nest_function(f1, 'f2', 3)
182-
c1 = mb._nest_class(f0, 'c1', 5)
183-
C0 = mb.Class(m, 'C0', None, f, 6)
184-
F1 = mb._nest_function(C0, 'F1', 8)
185-
C1 = mb._nest_class(C0, 'C1', 11)
186-
C2 = mb._nest_class(C1, 'C2', 12)
187-
F3 = mb._nest_function(C2, 'F3', 14)
179+
f0 = mb.Function(m, 'f0', f, 1, end_lineno=5)
180+
f1 = mb._nest_function(f0, 'f1', 2, 4)
181+
f2 = mb._nest_function(f1, 'f2', 3, 3)
182+
c1 = mb._nest_class(f0, 'c1', 5, 5)
183+
C0 = mb.Class(m, 'C0', None, f, 6, end_lineno=14)
184+
F1 = mb._nest_function(C0, 'F1', 8, 10)
185+
C1 = mb._nest_class(C0, 'C1', 11, 14)
186+
C2 = mb._nest_class(C1, 'C2', 12, 14)
187+
F3 = mb._nest_function(C2, 'F3', 14, 14)
188188
expected = {'f0':f0, 'C0':C0}
189189

190190
def compare(parent1, children1, parent2, children2):
@@ -203,8 +203,8 @@ def compare(parent1, children1, parent2, children2):
203203
self.assertIs(ob.parent, parent2)
204204
for key in children1.keys():
205205
o1, o2 = children1[key], children2[key]
206-
t1 = type(o1), o1.name, o1.file, o1.module, o1.lineno
207-
t2 = type(o2), o2.name, o2.file, o2.module, o2.lineno
206+
t1 = type(o1), o1.name, o1.file, o1.module, o1.lineno, o1.end_lineno
207+
t2 = type(o2), o2.name, o2.file, o2.module, o2.lineno, o2.end_lineno
208208
self.assertEqual(t1, t2)
209209
if type(o1) is mb.Class:
210210
self.assertEqual(o1.methods, o2.methods)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add an 'end_lineno' attribute to the Class and Function objects that appear in the
2+
tree returned by pyclbr functions. This and the existing 'lineno'
3+
attribute define the extent of class and def statements. Patch by Aviral Srivastava.

0 commit comments

Comments
 (0)