From 1f25ed44ea700c814fc306f423c605d5a26f0454 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Sat, 28 Sep 2019 13:21:36 -0400 Subject: [PATCH 01/30] compeltes the Stack implementation to yield ending line for each class. --- Lib/pyclbr.py | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 99a17343fb61fd..9a504e621cf5e2 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -51,6 +51,7 @@ class _Object: "Information about Python class or function." + def __init__(self, module, name, file, lineno, parent): self.module = module self.name = name @@ -65,12 +66,14 @@ def _addchild(self, name, obj): class Function(_Object): "Information about a Python function, including methods." + def __init__(self, module, name, file, lineno, parent=None): _Object.__init__(self, module, name, file, lineno, parent) class Class(_Object): "Information about a Python class." + def __init__(self, module, name, super, file, lineno, parent=None): _Object.__init__(self, module, name, file, lineno, parent) self.super = [] if super is None else super @@ -80,6 +83,20 @@ def _addmethod(self, name, lineno): self.methods[name] = lineno +class Stack(list): + + def __init__(self): + import inspect + super().__init__() + + def __delitem__(self, key): + import inspect + frames = inspect.stack() + setattr(self[key][0], 'endline', + frames[1].frame.f_locals['start'][0] - 1) + super().__delitem__(key) + + def _nest_function(ob, func_name, lineno): "Return a Function after nesting within ob." newfunc = Function(ob.module, func_name, ob.file, lineno, ob) @@ -88,12 +105,14 @@ def _nest_function(ob, func_name, lineno): ob._addmethod(func_name, lineno) return newfunc + def _nest_class(ob, class_name, lineno, super=None): "Return a Class after nesting within ob." newclass = Class(ob.module, class_name, super, ob.file, lineno, ob) ob._addchild(class_name, newclass) return newclass + def readmodule(module, path=None): """Return Class objects for the top-level classes in module. @@ -106,6 +125,7 @@ def readmodule(module, path=None): res[key] = value return res + def readmodule_ex(module, path=None): """Return a dictionary with all functions and classes in module. @@ -115,6 +135,7 @@ def readmodule_ex(module, path=None): """ return _readmodule(module, path or []) + def _readmodule(module, path, inpackage=None): """Do the hard work for readmodule[_ex]. @@ -161,7 +182,8 @@ def _readmodule(module, path, inpackage=None): search_path = path + sys.path spec = importlib.util._find_spec_from_path(fullmodule, search_path) if spec is None: - raise ModuleNotFoundError(f"no module named {fullmodule!r}", name=fullmodule) + raise ModuleNotFoundError( + f"no module named {fullmodule!r}", name=fullmodule) _modules[fullmodule] = tree # Is module a package? if spec.submodule_search_locations is not None: @@ -193,8 +215,8 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): """ f = io.StringIO(source) - stack = [] # Initialize stack of (class, indent) pairs. - + # stack = [] # Initialize stack of (class, indent) pairs. + stack = Stack() # changing the source code so as to get the ending line g = tokenize.generate_tokens(f.readline) try: for tokentype, token, start, _end, _line in g: @@ -227,14 +249,14 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): del stack[-1] tokentype, class_name, start = next(g)[0:3] if tokentype != NAME: - continue # Skip class with syntax error. + continue # Skip class with syntax error. # Parse what follows the class name. tokentype, token, start = next(g)[0:3] inherit = None if token == '(': - names = [] # Initialize list of superclasses. + names = [] # Initialize list of superclasses. level = 1 - super = [] # Tokens making up current superclass. + super = [] # Tokens making up current superclass. while True: tokentype, token, start = next(g)[0:3] if token in (')', ',') and level == 1: @@ -271,7 +293,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): if stack: cur_obj = stack[-1][0] cur_class = _nest_class( - cur_obj, class_name, lineno, inherit) + cur_obj, class_name, lineno, inherit) else: cur_class = Class(fullmodule, class_name, inherit, fname, lineno) @@ -377,7 +399,7 @@ def _main(): else: path = [] tree = readmodule_ex(mod, path) - lineno_key = lambda a: getattr(a, 'lineno', 0) + def lineno_key(a): return getattr(a, 'lineno', 0) objs = sorted(tree.values(), key=lineno_key, reverse=True) indent_level = 2 while objs: @@ -400,5 +422,6 @@ def _main(): elif isinstance(obj, Function): print("{}def {} {}".format(' ' * obj.indent, obj.name, obj.lineno)) + if __name__ == "__main__": _main() From 7d2354ac2f1a9b83f97d5602b0b910f20d823592 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Sun, 6 Oct 2019 15:42:30 -0400 Subject: [PATCH 02/30] reverts whitespace and unwanted changes including functions, comments and formatting --- Lib/pyclbr.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 9a504e621cf5e2..38e42f50f36531 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -43,6 +43,7 @@ import importlib.util import tokenize from token import NAME, DEDENT, OP +import inspect __all__ = ["readmodule", "readmodule_ex", "Class", "Function"] @@ -51,7 +52,6 @@ class _Object: "Information about Python class or function." - def __init__(self, module, name, file, lineno, parent): self.module = module self.name = name @@ -84,13 +84,8 @@ def _addmethod(self, name, lineno): class Stack(list): - - def __init__(self): - import inspect - super().__init__() - + def __delitem__(self, key): - import inspect frames = inspect.stack() setattr(self[key][0], 'endline', frames[1].frame.f_locals['start'][0] - 1) @@ -182,8 +177,7 @@ def _readmodule(module, path, inpackage=None): search_path = path + sys.path spec = importlib.util._find_spec_from_path(fullmodule, search_path) if spec is None: - raise ModuleNotFoundError( - f"no module named {fullmodule!r}", name=fullmodule) + raise ModuleNotFoundError(f"no module named {fullmodule!r}", name=fullmodule) _modules[fullmodule] = tree # Is module a package? if spec.submodule_search_locations is not None: @@ -215,8 +209,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): """ f = io.StringIO(source) - # stack = [] # Initialize stack of (class, indent) pairs. - stack = Stack() # changing the source code so as to get the ending line + stack = Stack() # Initialize stack of (class, indent) pairs. g = tokenize.generate_tokens(f.readline) try: for tokentype, token, start, _end, _line in g: @@ -249,14 +242,14 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): del stack[-1] tokentype, class_name, start = next(g)[0:3] if tokentype != NAME: - continue # Skip class with syntax error. + continue # Skip class with syntax error. # Parse what follows the class name. tokentype, token, start = next(g)[0:3] inherit = None if token == '(': - names = [] # Initialize list of superclasses. + names = [] # Initialize list of superclasses. level = 1 - super = [] # Tokens making up current superclass. + super = [] # Tokens making up current superclass. while True: tokentype, token, start = next(g)[0:3] if token in (')', ',') and level == 1: @@ -293,7 +286,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): if stack: cur_obj = stack[-1][0] cur_class = _nest_class( - cur_obj, class_name, lineno, inherit) + cur_obj, class_name, lineno, inherit) else: cur_class = Class(fullmodule, class_name, inherit, fname, lineno) @@ -399,7 +392,7 @@ def _main(): else: path = [] tree = readmodule_ex(mod, path) - def lineno_key(a): return getattr(a, 'lineno', 0) + lineno_key = lambda a: getattr(a, 'lineno', 0) objs = sorted(tree.values(), key=lineno_key, reverse=True) indent_level = 2 while objs: @@ -422,6 +415,5 @@ def lineno_key(a): return getattr(a, 'lineno', 0) elif isinstance(obj, Function): print("{}def {} {}".format(' ' * obj.indent, obj.name, obj.lineno)) - if __name__ == "__main__": _main() From c8a003d2264f7ddd1c4117c1558c07a09ccd5e25 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Sun, 6 Oct 2019 15:46:32 -0400 Subject: [PATCH 03/30] removes leftover whitespace in b/w functions: unwanted --- Lib/pyclbr.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 38e42f50f36531..06600a9024d8d3 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -66,14 +66,12 @@ def _addchild(self, name, obj): class Function(_Object): "Information about a Python function, including methods." - def __init__(self, module, name, file, lineno, parent=None): _Object.__init__(self, module, name, file, lineno, parent) class Class(_Object): "Information about a Python class." - def __init__(self, module, name, super, file, lineno, parent=None): _Object.__init__(self, module, name, file, lineno, parent) self.super = [] if super is None else super @@ -100,14 +98,12 @@ def _nest_function(ob, func_name, lineno): ob._addmethod(func_name, lineno) return newfunc - def _nest_class(ob, class_name, lineno, super=None): "Return a Class after nesting within ob." newclass = Class(ob.module, class_name, super, ob.file, lineno, ob) ob._addchild(class_name, newclass) return newclass - def readmodule(module, path=None): """Return Class objects for the top-level classes in module. @@ -120,7 +116,6 @@ def readmodule(module, path=None): res[key] = value return res - def readmodule_ex(module, path=None): """Return a dictionary with all functions and classes in module. @@ -130,7 +125,6 @@ def readmodule_ex(module, path=None): """ return _readmodule(module, path or []) - def _readmodule(module, path, inpackage=None): """Do the hard work for readmodule[_ex]. @@ -210,6 +204,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): f = io.StringIO(source) stack = Stack() # Initialize stack of (class, indent) pairs. + g = tokenize.generate_tokens(f.readline) try: for tokentype, token, start, _end, _line in g: From 7e6f079b7af7c5ada606797785934271c0cf9e20 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Mon, 3 Feb 2020 20:36:51 -0500 Subject: [PATCH 04/30] Initialize stack of (class, indent) pairs. --- Lib/pyclbr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 06600a9024d8d3..e7f109082fb8b3 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -203,7 +203,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): """ f = io.StringIO(source) - stack = Stack() # Initialize stack of (class, indent) pairs. + stack = Stack() g = tokenize.generate_tokens(f.readline) try: From b7c1ce7b7101196d33318350fe4b8553257e6a33 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Mon, 3 Feb 2020 20:44:36 -0500 Subject: [PATCH 05/30] removes Stack() custom class and adds direct attribute (end_lineno) instead to the stack --- Lib/pyclbr.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index e7f109082fb8b3..1910f2aa1b816e 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -81,15 +81,6 @@ def _addmethod(self, name, lineno): self.methods[name] = lineno -class Stack(list): - - def __delitem__(self, key): - frames = inspect.stack() - setattr(self[key][0], 'endline', - frames[1].frame.f_locals['start'][0] - 1) - super().__delitem__(key) - - def _nest_function(ob, func_name, lineno): "Return a Function after nesting within ob." newfunc = Function(ob.module, func_name, ob.file, lineno, ob) @@ -203,7 +194,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): """ f = io.StringIO(source) - stack = Stack() + stack = [] g = tokenize.generate_tokens(f.readline) try: @@ -212,11 +203,13 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: + stack[-1].end_lineno = start - 1 del stack[-1] elif token == 'def': lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: + stack[-1].end_lineno = start - 1 del stack[-1] tokentype, func_name, start = next(g)[0:3] if tokentype != NAME: @@ -234,6 +227,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: + stack[-1].end_lineno = start - 1 del stack[-1] tokentype, class_name, start = next(g)[0:3] if tokentype != NAME: From 3466f638f3d43e8dbe59d44ba977edb5d772cd39 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Fri, 7 Feb 2020 21:01:22 -0500 Subject: [PATCH 06/30] corrects the attribute name to end_lineno and sets the same without using subclass --- Lib/pyclbr.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 1910f2aa1b816e..9ef3a5f0336f9c 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -203,13 +203,13 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: - stack[-1].end_lineno = start - 1 + setattr(stack[-1][0], 'end_lineno', start[0] - 1) del stack[-1] elif token == 'def': lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: - stack[-1].end_lineno = start - 1 + setattr(stack[-1][0], 'end_lineno', start[0] - 1) del stack[-1] tokentype, func_name, start = next(g)[0:3] if tokentype != NAME: @@ -227,7 +227,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: - stack[-1].end_lineno = start - 1 + setattr(stack[-1][0], 'end_lineno', start[0] - 1) del stack[-1] tokentype, class_name, start = next(g)[0:3] if tokentype != NAME: From f2a58c68bfed1b0b5bac743f4bcb1b3069fdb08a Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Fri, 7 Feb 2020 21:03:13 -0500 Subject: [PATCH 07/30] removes unwanted module: inspect --- Lib/pyclbr.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 9ef3a5f0336f9c..8f885d6b31c5ca 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -43,7 +43,6 @@ import importlib.util import tokenize from token import NAME, DEDENT, OP -import inspect __all__ = ["readmodule", "readmodule_ex", "Class", "Function"] @@ -194,7 +193,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): """ f = io.StringIO(source) - stack = [] + stack = [] # Initialize stack of (class, indent) pairs. g = tokenize.generate_tokens(f.readline) try: From 94edb5bae1eb321049494276b1cdfeb6364d5c2d Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Sun, 16 Feb 2020 11:10:20 -0500 Subject: [PATCH 08/30] corrects the way of setting attribute --- Lib/pyclbr.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 8f885d6b31c5ca..f49cc1a8f79cb0 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -202,13 +202,13 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: - setattr(stack[-1][0], 'end_lineno', start[0] - 1) + stack[-1][0].end_lineno = start[0] - 1 del stack[-1] elif token == 'def': lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: - setattr(stack[-1][0], 'end_lineno', start[0] - 1) + stack[-1][0].end_lineno = start[0] - 1 del stack[-1] tokentype, func_name, start = next(g)[0:3] if tokentype != NAME: @@ -226,7 +226,7 @@ def _create_tree(fullmodule, path, fname, source, tree, inpackage): lineno, thisindent = start # Close previous nested classes and defs. while stack and stack[-1][1] >= thisindent: - setattr(stack[-1][0], 'end_lineno', start[0] - 1) + stack[-1][0].end_lineno = start[0] - 1 del stack[-1] tokentype, class_name, start = next(g)[0:3] if tokentype != NAME: From 454d30540799fede401779c1c32039f0c3283b4d Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2020 03:03:22 +0000 Subject: [PATCH 09/30] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst diff --git a/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst new file mode 100644 index 00000000000000..06d476a7326cd2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst @@ -0,0 +1,4 @@ +Adds end line no in class' use: generating dependency. +: `end_lineno` is added to denote the scope of a class +along with `lineno` which was already present in the codebase. +Patch by Aviral Srivastava. \ No newline at end of file From dc0166f6abd4e0a5254e333bd89a08df8f6e4e54 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Mon, 23 Mar 2020 20:49:43 -0400 Subject: [PATCH 10/30] wip: added end_lineno in tests --- Lib/test/test_pyclbr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 4385271cd0f2ba..653ae420a6a9a8 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -206,8 +206,8 @@ def compare(parent1, children1, parent2, children2): self.assertIs(ob.parent, parent2) for key in children1.keys(): o1, o2 = children1[key], children2[key] - t1 = type(o1), o1.name, o1.file, o1.module, o1.lineno - t2 = type(o2), o2.name, o2.file, o2.module, o2.lineno + t1 = type(o1), o1.name, o1.file, o1.module, o1.lineno, o1.end_lineno + t2 = type(o2), o2.name, o2.file, o2.module, o2.lineno, o2.end_lineno self.assertEqual(t1, t2) if type(o1) is mb.Class: self.assertEqual(o1.methods, o2.methods) From ea2090b89f1705646e78b999e34c0ac7b6e410dd Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Thu, 13 Aug 2020 19:44:18 -0400 Subject: [PATCH 11/30] wip --- Lib/pyclbr.py | 1 + Lib/test/test_pyclbr.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index f49cc1a8f79cb0..247d857651a471 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -21,6 +21,7 @@ name -- name of the object; file -- file in which the object is defined; lineno -- line in the file where the object's definition starts; + end_lineno -- line in the file where the object's definition ends; parent -- parent of this object, if any; children -- nested objects contained in this object. The 'children' attribute is a dictionary mapping names to objects. diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 653ae420a6a9a8..53a004dc1aef0a 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -199,6 +199,8 @@ def compare(parent1, children1, parent2, children2): linkage. We separate comparing string and number attributes from comparing the children of input children. """ + print("Children 1 is: {}".format(children1)) + print("Children 2 is: {}".format(children2)) self.assertEqual(children1.keys(), children2.keys()) for ob in children1.values(): self.assertIs(ob.parent, parent1) From 49d0695556704b850770b8bf9c7a094e82ba1832 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Sat, 28 Sep 2019 13:21:36 -0400 Subject: [PATCH 12/30] compeltes the Stack implementation to yield ending line for each class. --- Lib/pyclbr.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index f0c8381946c614..b75bd5d2170532 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -52,6 +52,7 @@ class _Object: "Information about Python class or function." + def __init__(self, module, name, file, lineno, parent): self.module = module self.name = name @@ -83,10 +84,12 @@ def _nest_function(ob, func_name, lineno, is_async=False): "Return a Function after nesting within ob." return Function(ob.module, func_name, ob.file, lineno, ob, is_async) + def _nest_class(ob, class_name, lineno, super=None): "Return a Class after nesting within ob." return Class(ob.module, class_name, super, ob.file, lineno, ob) + def readmodule(module, path=None): """Return Class objects for the top-level classes in module. @@ -99,6 +102,7 @@ def readmodule(module, path=None): res[key] = value return res + def readmodule_ex(module, path=None): """Return a dictionary with all functions and classes in module. @@ -108,6 +112,7 @@ def readmodule_ex(module, path=None): """ return _readmodule(module, path or []) + def _readmodule(module, path, inpackage=None): """Do the hard work for readmodule[_ex]. @@ -154,7 +159,8 @@ def _readmodule(module, path, inpackage=None): search_path = path + sys.path spec = importlib.util._find_spec_from_path(fullmodule, search_path) if spec is None: - raise ModuleNotFoundError(f"no module named {fullmodule!r}", name=fullmodule) + raise ModuleNotFoundError( + f"no module named {fullmodule!r}", name=fullmodule) _modules[fullmodule] = tree # Is module a package? if spec.submodule_search_locations is not None: @@ -278,7 +284,7 @@ def _main(): else: path = [] tree = readmodule_ex(mod, path) - lineno_key = lambda a: getattr(a, 'lineno', 0) + def lineno_key(a): return getattr(a, 'lineno', 0) objs = sorted(tree.values(), key=lineno_key, reverse=True) indent_level = 2 while objs: @@ -301,5 +307,6 @@ def _main(): elif isinstance(obj, Function): print("{}def {} {}".format(' ' * obj.indent, obj.name, obj.lineno)) + if __name__ == "__main__": _main() From 33aa14c0f325b4c075203e8101441cd6eeaa51bf Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Sun, 6 Oct 2019 15:42:30 -0400 Subject: [PATCH 13/30] reverts whitespace and unwanted changes including functions, comments and formatting --- Lib/pyclbr.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index b75bd5d2170532..eee2a635667c2b 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -52,7 +52,6 @@ class _Object: "Information about Python class or function." - def __init__(self, module, name, file, lineno, parent): self.module = module self.name = name @@ -159,8 +158,7 @@ def _readmodule(module, path, inpackage=None): search_path = path + sys.path spec = importlib.util._find_spec_from_path(fullmodule, search_path) if spec is None: - raise ModuleNotFoundError( - f"no module named {fullmodule!r}", name=fullmodule) + raise ModuleNotFoundError(f"no module named {fullmodule!r}", name=fullmodule) _modules[fullmodule] = tree # Is module a package? if spec.submodule_search_locations is not None: @@ -284,7 +282,7 @@ def _main(): else: path = [] tree = readmodule_ex(mod, path) - def lineno_key(a): return getattr(a, 'lineno', 0) + lineno_key = lambda a: getattr(a, 'lineno', 0) objs = sorted(tree.values(), key=lineno_key, reverse=True) indent_level = 2 while objs: @@ -307,6 +305,5 @@ def lineno_key(a): return getattr(a, 'lineno', 0) elif isinstance(obj, Function): print("{}def {} {}".format(' ' * obj.indent, obj.name, obj.lineno)) - if __name__ == "__main__": _main() From 2f9579af2cf6dcc728e896688a37223795f09dce Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Sun, 6 Oct 2019 15:46:32 -0400 Subject: [PATCH 14/30] removes leftover whitespace in b/w functions: unwanted --- Lib/pyclbr.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index eee2a635667c2b..f0c8381946c614 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -83,12 +83,10 @@ def _nest_function(ob, func_name, lineno, is_async=False): "Return a Function after nesting within ob." return Function(ob.module, func_name, ob.file, lineno, ob, is_async) - def _nest_class(ob, class_name, lineno, super=None): "Return a Class after nesting within ob." return Class(ob.module, class_name, super, ob.file, lineno, ob) - def readmodule(module, path=None): """Return Class objects for the top-level classes in module. @@ -101,7 +99,6 @@ def readmodule(module, path=None): res[key] = value return res - def readmodule_ex(module, path=None): """Return a dictionary with all functions and classes in module. @@ -111,7 +108,6 @@ def readmodule_ex(module, path=None): """ return _readmodule(module, path or []) - def _readmodule(module, path, inpackage=None): """Do the hard work for readmodule[_ex]. From 668fe22576a783fca3e9452cb34b5c6b8d426d71 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Mon, 23 Mar 2020 20:49:43 -0400 Subject: [PATCH 15/30] wip: added end_lineno in tests --- Lib/test/test_pyclbr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 2c7afa994f3058..dfad75a456bde0 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -203,8 +203,8 @@ def compare(parent1, children1, parent2, children2): self.assertIs(ob.parent, parent2) for key in children1.keys(): o1, o2 = children1[key], children2[key] - t1 = type(o1), o1.name, o1.file, o1.module, o1.lineno - t2 = type(o2), o2.name, o2.file, o2.module, o2.lineno + t1 = type(o1), o1.name, o1.file, o1.module, o1.lineno, o1.end_lineno + t2 = type(o2), o2.name, o2.file, o2.module, o2.lineno, o2.end_lineno self.assertEqual(t1, t2) if type(o1) is mb.Class: self.assertEqual(o1.methods, o2.methods) From efb49ea0eb1b5ef1a6c840b9600915be6d45314a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2020 03:03:22 +0000 Subject: [PATCH 16/30] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst diff --git a/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst new file mode 100644 index 00000000000000..06d476a7326cd2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst @@ -0,0 +1,4 @@ +Adds end line no in class' use: generating dependency. +: `end_lineno` is added to denote the scope of a class +along with `lineno` which was already present in the codebase. +Patch by Aviral Srivastava. \ No newline at end of file From 963b7834c7d3c3954802073dced0f5bdec89d54e Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Thu, 13 Aug 2020 19:44:18 -0400 Subject: [PATCH 17/30] wip --- Lib/pyclbr.py | 1 + Lib/test/test_pyclbr.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index f0c8381946c614..ad0c9e49c29bb6 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -21,6 +21,7 @@ name -- name of the object; file -- file in which the object is defined; lineno -- line in the file where the object's definition starts; + end_lineno -- line in the file where the object's definition ends; parent -- parent of this object, if any; children -- nested objects contained in this object. The 'children' attribute is a dictionary mapping names to objects. diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index dfad75a456bde0..4ebfe27ea16861 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -196,6 +196,8 @@ def compare(parent1, children1, parent2, children2): linkage. We separate comparing string and number attributes from comparing the children of input children. """ + print("Children 1 is: {}".format(children1)) + print("Children 2 is: {}".format(children2)) self.assertEqual(children1.keys(), children2.keys()) for ob in children1.values(): self.assertIs(ob.parent, parent1) From d924d4ab86ae537a15615f2e2fb76e717d05bd68 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Tue, 26 Jan 2021 21:19:40 -0800 Subject: [PATCH 18/30] adds end_lineno as an attribute for Class and Functions objects --- Lib/pyclbr.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index ad0c9e49c29bb6..d257274e7c1a3e 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -53,11 +53,12 @@ class _Object: "Information about Python class or function." - def __init__(self, module, name, file, lineno, parent): + def __init__(self, module, name, file, lineno, end_lineno, parent): self.module = module self.name = name self.file = file self.lineno = lineno + self.end_lineno = end_lineno self.parent = parent self.children = {} if parent is not None: @@ -65,16 +66,16 @@ def __init__(self, module, name, file, lineno, parent): class Function(_Object): "Information about a Python function, including methods." - def __init__(self, module, name, file, lineno, parent=None, is_async=False): - super().__init__(module, name, file, lineno, parent) + def __init__(self, module, name, file, lineno, end_lineno, parent=None, is_async=False): + super().__init__(module, name, file, lineno, end_lineno, parent) self.is_async = is_async if isinstance(parent, Class): parent.methods[name] = lineno class Class(_Object): "Information about a Python class." - def __init__(self, module, name, super_, file, lineno, parent=None): - super().__init__(module, name, file, lineno, parent) + def __init__(self, module, name, super_, file, lineno, end_lineno, parent=None): + super().__init__(module, name, file, lineno, end_lineno, parent) self.super = super_ or [] self.methods = {} @@ -82,11 +83,11 @@ def __init__(self, module, name, super_, file, lineno, parent=None): # Lib/test/test_pyclbr, Lib/idlelib/idle_test/test_browser.py def _nest_function(ob, func_name, lineno, is_async=False): "Return a Function after nesting within ob." - return Function(ob.module, func_name, ob.file, lineno, ob, is_async) + return Function(ob.module, func_name, ob.file, lineno, end_lineno, ob, is_async) def _nest_class(ob, class_name, lineno, super=None): "Return a Class after nesting within ob." - return Class(ob.module, class_name, super, ob.file, lineno, ob) + return Class(ob.module, class_name, super, ob.file, lineno, end_lineno, ob) def readmodule(module, path=None): """Return Class objects for the top-level classes in module. @@ -200,7 +201,7 @@ def visit_ClassDef(self, node): parent = self.stack[-1] if self.stack else None class_ = Class( - self.module, node.name, bases, self.file, node.lineno, parent + self.module, node.name, bases, self.file, node.lineno, node.end_lineno, parent ) if parent is None: self.tree[node.name] = class_ @@ -211,7 +212,7 @@ def visit_ClassDef(self, node): def visit_FunctionDef(self, node, *, is_async=False): parent = self.stack[-1] if self.stack else None function = Function( - self.module, node.name, self.file, node.lineno, parent, is_async + self.module, node.name, self.file, node.lineno, node.end_lineno, parent, is_async ) if parent is None: self.tree[node.name] = function From 78f166fa1e3fefd721bd0c07b84f3d958fc6f5aa Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Tue, 26 Jan 2021 21:28:27 -0800 Subject: [PATCH 19/30] adds the news. --- .../next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst index 06d476a7326cd2..56f62806f6ab33 100644 --- a/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst +++ b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst @@ -1,4 +1,4 @@ Adds end line no in class' use: generating dependency. -: `end_lineno` is added to denote the scope of a class +: `end_lineno` is added to denote the scope of a class and a function along with `lineno` which was already present in the codebase. Patch by Aviral Srivastava. \ No newline at end of file From fc74ec7cc7a2c63b1e2abf2bc537334efb7c9458 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Tue, 26 Jan 2021 22:22:53 -0800 Subject: [PATCH 20/30] adds positional arguments in the tests and end_lineno as an argument in the nest functions --- Lib/pyclbr.py | 4 ++-- Lib/test/test_pyclbr.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index d257274e7c1a3e..37673bd5d7a958 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -81,11 +81,11 @@ def __init__(self, module, name, super_, file, lineno, end_lineno, parent=None): # These 2 functions are used in these tests # Lib/test/test_pyclbr, Lib/idlelib/idle_test/test_browser.py -def _nest_function(ob, func_name, lineno, is_async=False): +def _nest_function(ob, func_name, lineno, end_lineno, is_async=False): "Return a Function after nesting within ob." return Function(ob.module, func_name, ob.file, lineno, end_lineno, ob, is_async) -def _nest_class(ob, class_name, lineno, super=None): +def _nest_class(ob, class_name, lineno, end_lineno, super=None): "Return a Class after nesting within ob." return Class(ob.module, class_name, super, ob.file, lineno, end_lineno, ob) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 4ebfe27ea16861..7642b4b075e0ea 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -176,15 +176,15 @@ def F3(): return 1+1 actual = mb._create_tree(m, p, f, source, t, i) # Create descriptors, linked together, and expected dict. - f0 = mb.Function(m, 'f0', f, 1) - f1 = mb._nest_function(f0, 'f1', 2) - f2 = mb._nest_function(f1, 'f2', 3) - c1 = mb._nest_class(f0, 'c1', 5) - C0 = mb.Class(m, 'C0', None, f, 6) - F1 = mb._nest_function(C0, 'F1', 8) - C1 = mb._nest_class(C0, 'C1', 11) - C2 = mb._nest_class(C1, 'C2', 12) - F3 = mb._nest_function(C2, 'F3', 14) + f0 = mb.Function(m, 'f0', f, 1, 5) + f1 = mb._nest_function(f0, 'f1', 2, 4) + f2 = mb._nest_function(f1, 'f2', 3, 3) + c1 = mb._nest_class(f0, 'c1', 5, 5) + C0 = mb.Class(m, 'C0', None, f, 6, 14) + F1 = mb._nest_function(C0, 'F1', 8, 10) + C1 = mb._nest_class(C0, 'C1', 11, 14) + C2 = mb._nest_class(C1, 'C2', 12, 14) + F3 = mb._nest_function(C2, 'F3', 14, 14) expected = {'f0':f0, 'C0':C0} def compare(parent1, children1, parent2, children2): From b5f29c080f797194aa7a7b81ec3913e9a933bd46 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Tue, 26 Jan 2021 22:24:28 -0800 Subject: [PATCH 21/30] removes debugging print statements. --- Lib/test/test_pyclbr.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 7642b4b075e0ea..5939523072903a 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -196,8 +196,6 @@ def compare(parent1, children1, parent2, children2): linkage. We separate comparing string and number attributes from comparing the children of input children. """ - print("Children 1 is: {}".format(children1)) - print("Children 2 is: {}".format(children2)) self.assertEqual(children1.keys(), children2.keys()) for ob in children1.values(): self.assertIs(ob.parent, parent1) From f3c09fe38d110a587bd5d8f34b6700f41a6d7c58 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Wed, 27 Jan 2021 11:11:51 -0800 Subject: [PATCH 22/30] adds endline no in all the tests for the dummy tree" --- Lib/idlelib/idle_test/test_browser.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/idlelib/idle_test/test_browser.py b/Lib/idlelib/idle_test/test_browser.py index 25d6dc6630364b..9ba8b284a71064 100644 --- a/Lib/idlelib/idle_test/test_browser.py +++ b/Lib/idlelib/idle_test/test_browser.py @@ -61,15 +61,15 @@ def test_close(self): # Nested tree same as in test_pyclbr.py except for supers on C0. C1. mb = pyclbr module, fname = 'test', 'test.py' -C0 = mb.Class(module, 'C0', ['base'], fname, 1) -F1 = mb._nest_function(C0, 'F1', 3) -C1 = mb._nest_class(C0, 'C1', 6, ['']) -C2 = mb._nest_class(C1, 'C2', 7) -F3 = mb._nest_function(C2, 'F3', 9) -f0 = mb.Function(module, 'f0', fname, 11) -f1 = mb._nest_function(f0, 'f1', 12) -f2 = mb._nest_function(f1, 'f2', 13) -c1 = mb._nest_class(f0, 'c1', 15) +C0 = mb.Class(module, 'C0', ['base'], fname, 1, 9) +F1 = mb._nest_function(C0, 'F1', 3, 5) +C1 = mb._nest_class(C0, 'C1', 6, 9, ['']) +C2 = mb._nest_class(C1, 'C2', 7, 9) +F3 = mb._nest_function(C2, 'F3', 9, 9) +f0 = mb.Function(module, 'f0', fname, 11, 15) +f1 = mb._nest_function(f0, 'f1', 12, 14) +f2 = mb._nest_function(f1, 'f2', 13, 13) +c1 = mb._nest_class(f0, 'c1', 15, 15) mock_pyclbr_tree = {'C0': C0, 'f0': f0} # Adjust C0.name, C1.name so tests do not depend on order. From 7337551a88db4bc5598eef5bdb8a77a65b0af030 Mon Sep 17 00:00:00 2001 From: Aviral Srivastava Date: Wed, 27 Jan 2021 11:11:51 -0800 Subject: [PATCH 23/30] adds endline no in all the tests for the dummy tree --- Lib/idlelib/idle_test/test_browser.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/idlelib/idle_test/test_browser.py b/Lib/idlelib/idle_test/test_browser.py index 25d6dc6630364b..9ba8b284a71064 100644 --- a/Lib/idlelib/idle_test/test_browser.py +++ b/Lib/idlelib/idle_test/test_browser.py @@ -61,15 +61,15 @@ def test_close(self): # Nested tree same as in test_pyclbr.py except for supers on C0. C1. mb = pyclbr module, fname = 'test', 'test.py' -C0 = mb.Class(module, 'C0', ['base'], fname, 1) -F1 = mb._nest_function(C0, 'F1', 3) -C1 = mb._nest_class(C0, 'C1', 6, ['']) -C2 = mb._nest_class(C1, 'C2', 7) -F3 = mb._nest_function(C2, 'F3', 9) -f0 = mb.Function(module, 'f0', fname, 11) -f1 = mb._nest_function(f0, 'f1', 12) -f2 = mb._nest_function(f1, 'f2', 13) -c1 = mb._nest_class(f0, 'c1', 15) +C0 = mb.Class(module, 'C0', ['base'], fname, 1, 9) +F1 = mb._nest_function(C0, 'F1', 3, 5) +C1 = mb._nest_class(C0, 'C1', 6, 9, ['']) +C2 = mb._nest_class(C1, 'C2', 7, 9) +F3 = mb._nest_function(C2, 'F3', 9, 9) +f0 = mb.Function(module, 'f0', fname, 11, 15) +f1 = mb._nest_function(f0, 'f1', 12, 14) +f2 = mb._nest_function(f1, 'f2', 13, 13) +c1 = mb._nest_class(f0, 'c1', 15, 15) mock_pyclbr_tree = {'C0': C0, 'f0': f0} # Adjust C0.name, C1.name so tests do not depend on order. From 77784e387b3176898bd21381b6db2a28fa0988ed Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Wed, 27 Jan 2021 17:59:50 -0500 Subject: [PATCH 24/30] Update 2020-03-16-03-03-21.bpo-38307.2cmw2i.rst --- .../next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst index 56f62806f6ab33..95f87354a142ba 100644 --- a/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst +++ b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst @@ -1,4 +1,3 @@ -Adds end line no in class' use: generating dependency. -: `end_lineno` is added to denote the scope of a class and a function -along with `lineno` which was already present in the codebase. -Patch by Aviral Srivastava. \ No newline at end of file +Add an `end_lineno` attribute to the Class and Function objects that appear in the +tree returned by pyclbr functions. This completes the existing (start) `lineno` +attribute to define the extent of class and def statements. Patch by Aviral Srivastava. From d73395af184e48887009bcfe65e47dc66cda8f2e Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Wed, 27 Jan 2021 18:24:00 -0500 Subject: [PATCH 25/30] Update 2020-03-16-03-03-21.bpo-38307.2cmw2i.rst --- .../next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst index 95f87354a142ba..358089915fb6c4 100644 --- a/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst +++ b/Misc/NEWS.d/next/Library/2020-03-16-03-03-21.bpo-38307.2cmw2i.rst @@ -1,3 +1,3 @@ -Add an `end_lineno` attribute to the Class and Function objects that appear in the -tree returned by pyclbr functions. This completes the existing (start) `lineno` -attribute to define the extent of class and def statements. Patch by Aviral Srivastava. +Add an 'end_lineno' attribute to the Class and Function objects that appear in the +tree returned by pyclbr functions. This and the existing 'lineno' +attribute define the extent of class and def statements. Patch by Aviral Srivastava. From 9238fcd7de4097b90cb5f632f629c7b4b42cda94 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 1 Feb 2021 10:11:38 -0500 Subject: [PATCH 26/30] Fix end_lineno. --- Lib/pyclbr.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py index 37673bd5d7a958..ebcc23c29da215 100644 --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -64,30 +64,39 @@ def __init__(self, module, name, file, lineno, end_lineno, parent): if parent is not None: parent.children[name] = self + +# Odd Function and Class signatures are for back-compatibility. class Function(_Object): "Information about a Python function, including methods." - def __init__(self, module, name, file, lineno, end_lineno, parent=None, is_async=False): + def __init__(self, module, name, file, lineno, + parent=None, is_async=False, *, end_lineno=None): super().__init__(module, name, file, lineno, end_lineno, parent) self.is_async = is_async if isinstance(parent, Class): parent.methods[name] = lineno + class Class(_Object): "Information about a Python class." - def __init__(self, module, name, super_, file, lineno, end_lineno, parent=None): + def __init__(self, module, name, super_, file, lineno, + parent=None, *, end_lineno=None): super().__init__(module, name, file, lineno, end_lineno, parent) self.super = super_ or [] self.methods = {} + # These 2 functions are used in these tests # Lib/test/test_pyclbr, Lib/idlelib/idle_test/test_browser.py def _nest_function(ob, func_name, lineno, end_lineno, is_async=False): "Return a Function after nesting within ob." - return Function(ob.module, func_name, ob.file, lineno, end_lineno, ob, is_async) + return Function(ob.module, func_name, ob.file, lineno, + parent=ob, is_async=is_async, end_lineno=end_lineno) def _nest_class(ob, class_name, lineno, end_lineno, super=None): "Return a Class after nesting within ob." - return Class(ob.module, class_name, super, ob.file, lineno, end_lineno, ob) + return Class(ob.module, class_name, super, ob.file, lineno, + parent=ob, end_lineno=end_lineno) + def readmodule(module, path=None): """Return Class objects for the top-level classes in module. @@ -110,6 +119,7 @@ def readmodule_ex(module, path=None): """ return _readmodule(module, path or []) + def _readmodule(module, path, inpackage=None): """Do the hard work for readmodule[_ex]. @@ -200,9 +210,8 @@ def visit_ClassDef(self, node): bases.append(name) parent = self.stack[-1] if self.stack else None - class_ = Class( - self.module, node.name, bases, self.file, node.lineno, node.end_lineno, parent - ) + class_ = Class(self.module, node.name, bases, self.file, node.lineno, + parent=parent, end_lineno=node.end_lineno) if parent is None: self.tree[node.name] = class_ self.stack.append(class_) @@ -211,9 +220,8 @@ def visit_ClassDef(self, node): def visit_FunctionDef(self, node, *, is_async=False): parent = self.stack[-1] if self.stack else None - function = Function( - self.module, node.name, self.file, node.lineno, node.end_lineno, parent, is_async - ) + function = Function(self.module, node.name, self.file, node.lineno, + parent, is_async, end_lineno=node.end_lineno) if parent is None: self.tree[node.name] = function self.stack.append(function) From ed20fa4425153b5962787c01abb259b5f1e5b791 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 1 Feb 2021 10:27:03 -0500 Subject: [PATCH 27/30] Add What's New in 3.10 entry --- Doc/whatsnew/3.10.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 3dccb7c50019b4..5c54d6aa77577b 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -435,6 +435,13 @@ py_compile Added ``--quiet`` option to command-line interface of :mod:`py_compile`. (Contributed by Gregory Schevchenko in :issue:`38731`.) +pyclbr +------ +Added an ``end_lineno`` attribute to the ``Function`` and ``Class`` +objects in the tree returned by :func:`pyclbr.readline` and +:func:`pyclbr.readline_ex`. It matches the existing (start) ``lineno``. +(Contributed by Aviral Srivastava in :issue:`38307`.) + shelve ------ From 48b73414c98172a17f2feb321c995583a0176c03 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 1 Feb 2021 10:37:03 -0500 Subject: [PATCH 28/30] Update Doc/whatsnew/3.10.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Araujo --- Doc/whatsnew/3.10.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 5c54d6aa77577b..d80ceeca85a895 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -437,6 +437,7 @@ Added ``--quiet`` option to command-line interface of :mod:`py_compile`. pyclbr ------ + Added an ``end_lineno`` attribute to the ``Function`` and ``Class`` objects in the tree returned by :func:`pyclbr.readline` and :func:`pyclbr.readline_ex`. It matches the existing (start) ``lineno``. From 9172efc60231429ab0994fb3284201edfcf8c0a3 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 1 Feb 2021 11:54:09 -0500 Subject: [PATCH 29/30] Direct calls by by keyword --- Lib/idlelib/idle_test/test_browser.py | 4 ++-- Lib/test/test_pyclbr.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/idle_test/test_browser.py b/Lib/idlelib/idle_test/test_browser.py index 9ba8b284a71064..03a50f22ca1e82 100644 --- a/Lib/idlelib/idle_test/test_browser.py +++ b/Lib/idlelib/idle_test/test_browser.py @@ -61,12 +61,12 @@ def test_close(self): # Nested tree same as in test_pyclbr.py except for supers on C0. C1. mb = pyclbr module, fname = 'test', 'test.py' -C0 = mb.Class(module, 'C0', ['base'], fname, 1, 9) +C0 = mb.Class(module, 'C0', ['base'], fname, 1, end_lineno=9) F1 = mb._nest_function(C0, 'F1', 3, 5) C1 = mb._nest_class(C0, 'C1', 6, 9, ['']) C2 = mb._nest_class(C1, 'C2', 7, 9) F3 = mb._nest_function(C2, 'F3', 9, 9) -f0 = mb.Function(module, 'f0', fname, 11, 15) +f0 = mb.Function(module, 'f0', fname, 11, end_lineno=15) f1 = mb._nest_function(f0, 'f1', 12, 14) f2 = mb._nest_function(f1, 'f2', 13, 13) c1 = mb._nest_class(f0, 'c1', 15, 15) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 5939523072903a..82c1ebb5b070fa 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -176,11 +176,11 @@ def F3(): return 1+1 actual = mb._create_tree(m, p, f, source, t, i) # Create descriptors, linked together, and expected dict. - f0 = mb.Function(m, 'f0', f, 1, 5) + f0 = mb.Function(m, 'f0', f, 1, end_lineno=5) f1 = mb._nest_function(f0, 'f1', 2, 4) f2 = mb._nest_function(f1, 'f2', 3, 3) c1 = mb._nest_class(f0, 'c1', 5, 5) - C0 = mb.Class(m, 'C0', None, f, 6, 14) + C0 = mb.Class(m, 'C0', None, f, 6, end_lineno=14) F1 = mb._nest_function(C0, 'F1', 8, 10) C1 = mb._nest_class(C0, 'C1', 11, 14) C2 = mb._nest_class(C1, 'C2', 12, 14) From d0ca986a66820e20541cb9ca501f80f681967d0e Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 1 Feb 2021 11:55:11 -0500 Subject: [PATCH 30/30] blank line --- Doc/whatsnew/3.10.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 5c54d6aa77577b..d80ceeca85a895 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -437,6 +437,7 @@ Added ``--quiet`` option to command-line interface of :mod:`py_compile`. pyclbr ------ + Added an ``end_lineno`` attribute to the ``Function`` and ``Class`` objects in the tree returned by :func:`pyclbr.readline` and :func:`pyclbr.readline_ex`. It matches the existing (start) ``lineno``.