aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.com>2023-10-17 22:08:28 +0300
committerrobot-contrib <robot-contrib@yandex-team.com>2023-10-17 22:26:26 +0300
commit35f4b62b12d72e4f7147e179e4e5f78a291acf60 (patch)
treed55e7660729d6de65c669186a8de86f9c4efe1c6
parentcff48010dc0763aea3c7a1233f7a7f75e04b37dd (diff)
downloadydb-35f4b62b12d72e4f7147e179e4e5f78a291acf60.tar.gz
Update contrib/python/executing to 2.0.0
-rw-r--r--contrib/python/executing/.dist-info/METADATA13
-rw-r--r--contrib/python/executing/README.md2
-rw-r--r--contrib/python/executing/executing/_position_node_finder.py286
-rw-r--r--contrib/python/executing/executing/executing.py139
-rw-r--r--contrib/python/executing/executing/version.py2
-rw-r--r--contrib/python/executing/ya.make2
6 files changed, 294 insertions, 150 deletions
diff --git a/contrib/python/executing/.dist-info/METADATA b/contrib/python/executing/.dist-info/METADATA
index bf103f9c95..5ec917a59e 100644
--- a/contrib/python/executing/.dist-info/METADATA
+++ b/contrib/python/executing/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: executing
-Version: 1.2.0
+Version: 2.0.0
Summary: Get the currently executing AST node of a frame, and other information
Home-page: https://github.com/alexmojaki/executing
Author: Alex Hall
@@ -8,8 +8,6 @@ Author-email: alex.mojaki@gmail.com
License: MIT
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
@@ -18,18 +16,21 @@ Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
Description-Content-Type: text/markdown
License-File: LICENSE.txt
-Requires-Dist: typing ; python_version < "3.5"
Provides-Extra: tests
-Requires-Dist: asttokens ; extra == 'tests'
+Requires-Dist: asttokens >=2.1.0 ; extra == 'tests'
+Requires-Dist: ipython ; extra == 'tests'
Requires-Dist: pytest ; extra == 'tests'
+Requires-Dist: coverage ; extra == 'tests'
+Requires-Dist: coverage-enable-subprocess ; extra == 'tests'
Requires-Dist: littleutils ; extra == 'tests'
Requires-Dist: rich ; (python_version >= "3.11") and extra == 'tests'
# executing
-[![Build Status](https://github.com/alexmojaki/executing/workflows/Tests/badge.svg?branch=master)](https://github.com/alexmojaki/executing/actions) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/executing/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/executing?branch=master) [![Supports Python versions 2.7 and 3.5+, including PyPy](https://img.shields.io/pypi/pyversions/executing.svg)](https://pypi.python.org/pypi/executing)
+[![Build Status](https://github.com/alexmojaki/executing/workflows/Tests/badge.svg?branch=master)](https://github.com/alexmojaki/executing/actions) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/executing/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/executing?branch=master) [![Supports Python versions 3.5+, including PyPy](https://img.shields.io/pypi/pyversions/executing.svg)](https://pypi.python.org/pypi/executing)
This mini-package lets you get information about what a frame is currently doing, particularly the AST node being executed.
diff --git a/contrib/python/executing/README.md b/contrib/python/executing/README.md
index 46bc01596a..1b4dbd8f07 100644
--- a/contrib/python/executing/README.md
+++ b/contrib/python/executing/README.md
@@ -1,6 +1,6 @@
# executing
-[![Build Status](https://github.com/alexmojaki/executing/workflows/Tests/badge.svg?branch=master)](https://github.com/alexmojaki/executing/actions) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/executing/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/executing?branch=master) [![Supports Python versions 2.7 and 3.5+, including PyPy](https://img.shields.io/pypi/pyversions/executing.svg)](https://pypi.python.org/pypi/executing)
+[![Build Status](https://github.com/alexmojaki/executing/workflows/Tests/badge.svg?branch=master)](https://github.com/alexmojaki/executing/actions) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/executing/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/executing?branch=master) [![Supports Python versions 3.5+, including PyPy](https://img.shields.io/pypi/pyversions/executing.svg)](https://pypi.python.org/pypi/executing)
This mini-package lets you get information about what a frame is currently doing, particularly the AST node being executed.
diff --git a/contrib/python/executing/executing/_position_node_finder.py b/contrib/python/executing/executing/_position_node_finder.py
index 8b3aec0866..8ca21a67bd 100644
--- a/contrib/python/executing/executing/_position_node_finder.py
+++ b/contrib/python/executing/executing/_position_node_finder.py
@@ -1,4 +1,5 @@
import ast
+import sys
import dis
from types import CodeType, FrameType
from typing import Any, Callable, Iterator, Optional, Sequence, Set, Tuple, Type, Union, cast
@@ -16,7 +17,8 @@ def parents(node: EnhancedAST) -> Iterator[EnhancedAST]:
node = node.parent
yield node
else:
- break
+ break # pragma: no mutate
+
def node_and_parents(node: EnhancedAST) -> Iterator[EnhancedAST]:
yield node
@@ -42,9 +44,12 @@ def mangled_name(node: EnhancedAST) -> str:
elif isinstance(node, (ast.FunctionDef, ast.ClassDef, ast.AsyncFunctionDef)):
name = node.name
elif isinstance(node, ast.ExceptHandler):
- name = node.name or "exc"
+ assert node.name
+ name = node.name
+ elif sys.version_info >= (3,12) and isinstance(node,ast.TypeVar):
+ name=node.name
else:
- raise TypeError("no node to mangle")
+ raise TypeError("no node to mangle for type "+repr(type(node)))
if name.startswith("__") and not name.endswith("__"):
@@ -52,7 +57,8 @@ def mangled_name(node: EnhancedAST) -> str:
while not (isinstance(parent,ast.ClassDef) and child not in parent.bases):
if not hasattr(parent,"parent"):
- break
+ break # pragma: no mutate
+
parent,child=parent.parent,parent
else:
class_name=parent.name.lstrip("_")
@@ -64,7 +70,7 @@ def mangled_name(node: EnhancedAST) -> str:
return name
-@lru_cache(128)
+@lru_cache(128) # pragma: no mutate
def get_instructions(code: CodeType) -> list[dis.Instruction]:
return list(dis.get_instructions(code, show_caches=True))
@@ -154,8 +160,11 @@ class PositionNodeFinder(object):
self.test_for_decorator(self.result, lasti)
+ # verify
if self.decorator is None:
self.verify(self.result, self.instruction(lasti))
+ else:
+ assert_(self.decorator in self.result.decorator_list)
def test_for_decorator(self, node: EnhancedAST, index: int) -> None:
if (
@@ -169,21 +178,24 @@ class PositionNodeFinder(object):
# index opname
# ------------------
- # index-4 PRECALL
+ # index-4 PRECALL (only in 3.11)
# index-2 CACHE
# index CALL <- the call instruction
# ... CACHE some CACHE instructions
# maybe multiple other bytecode blocks for other decorators
- # index-4 PRECALL
+ # index-4 PRECALL (only in 3.11)
# index-2 CACHE
# index CALL <- index of the next loop
# ... CACHE some CACHE instructions
# index+x STORE_* the ast-node of this instruction points to the decorated thing
- if self.opname(index - 4) != "PRECALL" or self.opname(index) != "CALL":
- break
+ if not (
+ (self.opname(index - 4) == "PRECALL" or sys.version_info >= (3, 12))
+ and self.opname(index) == "CALL"
+ ): # pragma: no mutate
+ break # pragma: no mutate
index += 2
@@ -198,7 +210,8 @@ class PositionNodeFinder(object):
self.decorator = node
return
- index += 4
+ if sys.version_info < (3, 12):
+ index += 4
def known_issues(self, node: EnhancedAST, instruction: dis.Instruction) -> None:
if instruction.opname in ("COMPARE_OP", "IS_OP", "CONTAINS_OP") and isinstance(
@@ -232,6 +245,16 @@ class PositionNodeFinder(object):
# Comprehension and generators get not fixed for now.
raise KnownIssue("chain comparison inside %s can not be fixed" % (node))
+ if (
+ sys.version_info[:3] == (3, 11, 1)
+ and isinstance(node, ast.Compare)
+ and instruction.opname == "CALL"
+ and any(isinstance(n, ast.Assert) for n in node_and_parents(node))
+ ):
+ raise KnownIssue(
+ "known bug in 3.11.1 https://github.com/python/cpython/issues/95921"
+ )
+
if isinstance(node, ast.Assert):
# pytest assigns the position of the assertion to all expressions of the rewritten assertion.
# All the rewritten expressions get mapped to ast.Assert, which is the wrong ast-node.
@@ -242,6 +265,40 @@ class PositionNodeFinder(object):
# TODO: investigate
raise KnownIssue("pattern matching ranges seems to be wrong")
+ if (
+ sys.version_info >= (3, 12)
+ and isinstance(node, ast.Call)
+ and isinstance(node.func, ast.Name)
+ and node.func.id == "super"
+ ):
+ # super is optimized to some instructions which do not map nicely to a Call
+
+ # find the enclosing function
+ func = node.parent
+ while hasattr(func, "parent") and not isinstance(
+ func, (ast.AsyncFunctionDef, ast.FunctionDef)
+ ):
+
+ func = func.parent
+
+ # get the first function argument (self/cls)
+ first_arg = None
+
+ if hasattr(func, "args"):
+ args = [*func.args.posonlyargs, *func.args.args]
+ if args:
+ first_arg = args[0].arg
+
+ if (instruction.opname, instruction.argval) in [
+ ("LOAD_DEREF", "__class__"),
+ ("LOAD_FAST", first_arg),
+ ("LOAD_DEREF", first_arg),
+ ]:
+ raise KnownIssue("super optimization")
+
+ if self.is_except_cleanup(instruction, node):
+ raise KnownIssue("exeption cleanup does not belong to the last node in a except block")
+
if instruction.opname == "STORE_NAME" and instruction.argval == "__classcell__":
# handle stores to __classcell__ as KnownIssue,
# because they get complicated if they are used in `if` or `for` loops
@@ -259,6 +316,14 @@ class PositionNodeFinder(object):
raise KnownIssue("store __classcell__")
+ if (
+ instruction.opname == "CALL"
+ and not isinstance(node,ast.Call)
+ and any(isinstance(p, ast.Assert) for p in parents(node))
+ and sys.version_info >= (3, 11, 2)
+ ):
+ raise KnownIssue("exception generation maps to condition")
+
@staticmethod
def is_except_cleanup(inst: dis.Instruction, node: EnhancedAST) -> bool:
if inst.opname not in (
@@ -268,6 +333,7 @@ class PositionNodeFinder(object):
"STORE_GLOBAL",
"DELETE_NAME",
"DELETE_FAST",
+ "DELETE_DEREF",
"DELETE_GLOBAL",
):
return False
@@ -291,8 +357,26 @@ class PositionNodeFinder(object):
# except TypeError as msg:
# print("Sorry:", msg, file=file)
+ if (
+ isinstance(node, ast.Name)
+ and isinstance(node.ctx,ast.Store)
+ and inst.opname.startswith("STORE_")
+ and mangled_name(node) == inst.argval
+ ):
+ # Storing the variable is valid and no exception cleanup, if the name is correct
+ return False
+
+ if (
+ isinstance(node, ast.Name)
+ and isinstance(node.ctx,ast.Del)
+ and inst.opname.startswith("DELETE_")
+ and mangled_name(node) == inst.argval
+ ):
+ # Deleting the variable is valid and no exception cleanup, if the name is correct
+ return False
+
return any(
- isinstance(n, ast.ExceptHandler) and mangled_name(n) == inst.argval
+ isinstance(n, ast.ExceptHandler) and n.name and mangled_name(n) == inst.argval
for n in parents(node)
)
@@ -353,6 +437,13 @@ class PositionNodeFinder(object):
# call to the generator function
return
+ if (
+ sys.version_info >= (3, 12)
+ and inst_match(("LOAD_FAST_AND_CLEAR", "STORE_FAST"))
+ and node_match((ast.ListComp, ast.SetComp, ast.DictComp))
+ ):
+ return
+
if inst_match(("CALL", "CALL_FUNCTION_EX")) and node_match(
(ast.ClassDef, ast.Call)
):
@@ -371,6 +462,7 @@ class PositionNodeFinder(object):
if (
(
inst_match("LOAD_METHOD", argval="join")
+ or inst_match("LOAD_ATTR", argval="join") # 3.12
or inst_match(("CALL", "BUILD_STRING"))
)
and node_match(ast.BinOp, left=ast.Constant, op=ast.Mod)
@@ -383,8 +475,6 @@ class PositionNodeFinder(object):
# data: int
return
- if self.is_except_cleanup(instruction, node):
- return
if inst_match(("DELETE_NAME", "DELETE_FAST")) and node_match(
ast.Name, id=instruction.argval, ctx=ast.Del
@@ -458,25 +548,162 @@ class PositionNodeFinder(object):
):
return
- if inst_match(("JUMP_IF_TRUE_OR_POP", "JUMP_IF_FALSE_OR_POP")) and node_match(
- ast.BoolOp
- ):
+ if inst_match(
+ (
+ "JUMP_IF_TRUE_OR_POP",
+ "JUMP_IF_FALSE_OR_POP",
+ "POP_JUMP_IF_TRUE",
+ "POP_JUMP_IF_FALSE",
+ )
+ ) and node_match(ast.BoolOp):
# and/or short circuit
return
if inst_match("DELETE_SUBSCR") and node_match(ast.Subscript, ctx=ast.Del):
return
- if node_match(ast.Name, ctx=ast.Load) and inst_match(
- ("LOAD_NAME", "LOAD_FAST", "LOAD_GLOBAL"), argval=mangled_name(node)
+ if (
+ node_match(ast.Name, ctx=ast.Load)
+ or (
+ node_match(ast.Name, ctx=ast.Store)
+ and isinstance(node.parent, ast.AugAssign)
+ )
+ ) and inst_match(
+ (
+ "LOAD_NAME",
+ "LOAD_FAST",
+ "LOAD_FAST_CHECK",
+ "LOAD_GLOBAL",
+ "LOAD_DEREF",
+ "LOAD_FROM_DICT_OR_DEREF",
+ ),
+ argval=mangled_name(node),
):
return
if node_match(ast.Name, ctx=ast.Del) and inst_match(
- ("DELETE_NAME", "DELETE_GLOBAL"), argval=mangled_name(node)
+ ("DELETE_NAME", "DELETE_GLOBAL", "DELETE_DEREF"), argval=mangled_name(node)
+ ):
+ return
+
+ if node_match(ast.Constant) and inst_match(
+ "LOAD_CONST", argval=cast(ast.Constant, node).value
):
return
+ if node_match(
+ (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp, ast.For)
+ ) and inst_match(("GET_ITER", "FOR_ITER")):
+ return
+
+ if sys.version_info >= (3, 12):
+ if node_match(ast.UnaryOp, op=ast.UAdd) and inst_match(
+ "CALL_INTRINSIC_1", argrepr="INTRINSIC_UNARY_POSITIVE"
+ ):
+ return
+
+ if node_match(ast.Subscript) and inst_match("BINARY_SLICE"):
+ return
+
+ if node_match(ast.ImportFrom) and inst_match(
+ "CALL_INTRINSIC_1", argrepr="INTRINSIC_IMPORT_STAR"
+ ):
+ return
+
+ if (
+ node_match(ast.Yield) or isinstance(node.parent, ast.GeneratorExp)
+ ) and inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_ASYNC_GEN_WRAP"):
+ return
+
+ if node_match(ast.Name) and inst_match("LOAD_DEREF",argval="__classdict__"):
+ return
+
+ if node_match(ast.TypeVar) and (
+ inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_TYPEVAR")
+ or inst_match(
+ "CALL_INTRINSIC_2", argrepr="INTRINSIC_TYPEVAR_WITH_BOUND"
+ )
+ or inst_match(
+ "CALL_INTRINSIC_2", argrepr="INTRINSIC_TYPEVAR_WITH_CONSTRAINTS"
+ )
+ or inst_match(("STORE_FAST", "STORE_DEREF"), argrepr=mangled_name(node))
+ ):
+ return
+
+ if node_match(ast.TypeVarTuple) and (
+ inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_TYPEVARTUPLE")
+ or inst_match(("STORE_FAST", "STORE_DEREF"), argrepr=node.name)
+ ):
+ return
+
+ if node_match(ast.ParamSpec) and (
+ inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_PARAMSPEC")
+
+ or inst_match(("STORE_FAST", "STORE_DEREF"), argrepr=node.name)):
+ return
+
+
+ if node_match(ast.TypeAlias):
+ if(
+ inst_match("CALL_INTRINSIC_1", argrepr="INTRINSIC_TYPEALIAS")
+ or inst_match(
+ ("STORE_NAME", "STORE_FAST", "STORE_DEREF"), argrepr=node.name.id
+ )
+ or inst_match("CALL")
+ ):
+ return
+
+
+ if node_match(ast.ClassDef) and node.type_params:
+ if inst_match(
+ ("STORE_DEREF", "LOAD_DEREF", "LOAD_FROM_DICT_OR_DEREF"),
+ argrepr=".type_params",
+ ):
+ return
+
+ if inst_match(("STORE_FAST", "LOAD_FAST"), argrepr=".generic_base"):
+ return
+
+ if inst_match(
+ "CALL_INTRINSIC_1", argrepr="INTRINSIC_SUBSCRIPT_GENERIC"
+ ):
+ return
+
+ if inst_match("LOAD_DEREF",argval="__classdict__"):
+ return
+
+ if node_match((ast.FunctionDef,ast.AsyncFunctionDef)) and node.type_params:
+ if inst_match("CALL"):
+ return
+
+ if inst_match(
+ "CALL_INTRINSIC_2", argrepr="INTRINSIC_SET_FUNCTION_TYPE_PARAMS"
+ ):
+ return
+
+ if inst_match("LOAD_FAST",argval=".defaults"):
+ return
+
+ if inst_match("LOAD_FAST",argval=".kwdefaults"):
+ return
+
+ if inst_match("STORE_NAME", argval="__classdictcell__"):
+ # this is a general thing
+ return
+
+
+ # f-strings
+
+ if node_match(ast.JoinedStr) and (
+ inst_match("LOAD_ATTR", argval="join")
+ or inst_match(("LIST_APPEND", "CALL"))
+ ):
+ return
+
+ if node_match(ast.FormattedValue) and inst_match("FORMAT_VALUE"):
+ return
+
+
# old verifier
typ: Type = type(None)
@@ -498,7 +725,7 @@ class PositionNodeFinder(object):
UNARY_INVERT=ast.Invert,
)[op_name]
extra_filter = lambda e: isinstance(cast(ast.UnaryOp, e).op, op_type)
- elif op_name in ("LOAD_ATTR", "LOAD_METHOD", "LOOKUP_METHOD"):
+ elif op_name in ("LOAD_ATTR", "LOAD_METHOD", "LOOKUP_METHOD","LOAD_SUPER_ATTR"):
typ = ast.Attribute
ctx = ast.Load
extra_filter = lambda e: mangled_name(e) == instruction.argval
@@ -550,11 +777,26 @@ class PositionNodeFinder(object):
def opname(self, index: int) -> str:
return self.instruction(index).opname
+ extra_node_types=()
+ if sys.version_info >= (3,12):
+ extra_node_types = (ast.type_param,)
+
def find_node(
self,
index: int,
- match_positions: Sequence[str]=("lineno", "end_lineno", "col_offset", "end_col_offset"),
- typ: tuple[Type, ...]=(ast.expr, ast.stmt, ast.excepthandler, ast.pattern),
+ match_positions: Sequence[str] = (
+ "lineno",
+ "end_lineno",
+ "col_offset",
+ "end_col_offset",
+ ),
+ typ: tuple[Type, ...] = (
+ ast.expr,
+ ast.stmt,
+ ast.excepthandler,
+ ast.pattern,
+ *extra_node_types,
+ ),
) -> EnhancedAST:
position = self.instruction(index).positions
assert position is not None and position.lineno is not None
diff --git a/contrib/python/executing/executing/executing.py b/contrib/python/executing/executing/executing.py
index c28091d3f8..7727c42232 100644
--- a/contrib/python/executing/executing/executing.py
+++ b/contrib/python/executing/executing/executing.py
@@ -25,115 +25,41 @@ SOFTWARE.
import __future__
import ast
import dis
-import functools
import inspect
import io
import linecache
import re
import sys
import types
-from collections import defaultdict, namedtuple
+from collections import defaultdict
from copy import deepcopy
+from functools import lru_cache
from itertools import islice
+from itertools import zip_longest
from operator import attrgetter
+from pathlib import Path
from threading import RLock
-from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Set, Sized, Tuple, Type, TypeVar, Union, cast
+from tokenize import detect_encoding
+from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Set, Sized, Tuple, \
+ Type, TypeVar, Union, cast
if TYPE_CHECKING: # pragma: no cover
from asttokens import ASTTokens, ASTText
from asttokens.asttokens import ASTTextBase
-function_node_types = (ast.FunctionDef,) # type: Tuple[Type, ...]
-if sys.version_info[0] == 3:
- function_node_types += (ast.AsyncFunctionDef,)
+function_node_types = (ast.FunctionDef, ast.AsyncFunctionDef) # type: Tuple[Type, ...]
-if sys.version_info[0] == 3:
- # noinspection PyUnresolvedReferences
- from functools import lru_cache
- # noinspection PyUnresolvedReferences
- from tokenize import detect_encoding
- from itertools import zip_longest
- # noinspection PyUnresolvedReferences,PyCompatibility
- from pathlib import Path
-
- cache = lru_cache(maxsize=None)
- text_type = str
-else:
- from lib2to3.pgen2.tokenize import detect_encoding, cookie_re as encoding_pattern # type: ignore[attr-defined]
- from itertools import izip_longest as zip_longest
-
- class Path(object):
- pass
-
-
- def cache(func):
- # type: (Callable) -> Callable
- d = {} # type: Dict[Tuple, Callable]
-
- @functools.wraps(func)
- def wrapper(*args):
- # type: (Any) -> Any
- if args in d:
- return d[args]
- result = d[args] = func(*args)
- return result
-
- return wrapper
-
-
- # noinspection PyUnresolvedReferences
- text_type = unicode
+cache = lru_cache(maxsize=None)
# Type class used to expand out the definition of AST to include fields added by this library
# It's not actually used for anything other than type checking though!
class EnhancedAST(ast.AST):
parent = None # type: EnhancedAST
-if sys.version_info >= (3, 4):
- # noinspection PyUnresolvedReferences
- _get_instructions = dis.get_instructions
- from dis import Instruction as _Instruction
-
- class Instruction(_Instruction):
- lineno = None # type: int
-else:
- class Instruction(namedtuple('Instruction', 'offset argval opname starts_line')):
- lineno = None # type: int
-
- from dis import HAVE_ARGUMENT, EXTENDED_ARG, hasconst, opname, findlinestarts, hasname
-
- # Based on dis.disassemble from 2.7
- # Left as similar as possible for easy diff
-
- def _get_instructions(co):
- # type: (types.CodeType) -> Iterator[Instruction]
- code = co.co_code
- linestarts = dict(findlinestarts(co))
- n = len(code)
- i = 0
- extended_arg = 0
- while i < n:
- offset = i
- c = code[i]
- op = ord(c)
- lineno = linestarts.get(i)
- argval = None
- i = i + 1
- if op >= HAVE_ARGUMENT:
- oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg
- extended_arg = 0
- i = i + 2
- if op == EXTENDED_ARG:
- extended_arg = oparg * 65536
-
- if op in hasconst:
- argval = co.co_consts[oparg]
- elif op in hasname:
- argval = co.co_names[oparg]
- elif opname[op] == 'LOAD_FAST':
- argval = co.co_varnames[oparg]
- yield Instruction(offset, argval, opname[op], lineno)
+
+class Instruction(dis.Instruction):
+ lineno = None # type: int
# Type class used to expand out the definition of AST to include fields added by this library
@@ -157,7 +83,7 @@ def assert_(condition, message=""):
def get_instructions(co):
# type: (types.CodeType) -> Iterator[EnhancedInstruction]
lineno = co.co_firstlineno
- for inst in _get_instructions(co):
+ for inst in dis.get_instructions(co):
inst = cast(EnhancedInstruction, inst)
lineno = inst.starts_line or lineno
assert_(lineno)
@@ -224,29 +150,9 @@ class Source(object):
"""
self.filename = filename
- text = ''.join(lines)
-
- if not isinstance(text, text_type):
- encoding = self.detect_encoding(text)
- # noinspection PyUnresolvedReferences
- text = text.decode(encoding)
- lines = [line.decode(encoding) for line in lines]
-
- self.text = text
+ self.text = ''.join(lines)
self.lines = [line.rstrip('\r\n') for line in lines]
- if sys.version_info[0] == 3:
- ast_text = text
- else:
- # In python 2 it's a syntax error to parse unicode
- # with an encoding declaration, so we remove it but
- # leave empty lines in its place to keep line numbers the same
- ast_text = ''.join([
- '\n' if i < 2 and encoding_pattern.match(line)
- else line
- for i, line in enumerate(lines)
- ])
-
self._nodes_by_line = defaultdict(list)
self.tree = None
self._qualnames = {}
@@ -254,7 +160,7 @@ class Source(object):
self._asttext = None # type: Optional[ASTText]
try:
- self.tree = ast.parse(ast_text, filename=filename)
+ self.tree = ast.parse(self.text, filename=filename)
except (SyntaxError, ValueError):
pass
else:
@@ -289,7 +195,7 @@ class Source(object):
def get_lines():
# type: () -> List[str]
- return linecache.getlines(cast(text_type, filename), module_globals)
+ return linecache.getlines(cast(str, filename), module_globals)
# Save the current linecache entry, then ensure the cache is up to date.
entry = linecache.cache.get(filename) # type: ignore[attr-defined]
@@ -320,8 +226,7 @@ class Source(object):
@classmethod
def lazycache(cls, frame):
# type: (types.FrameType) -> None
- if sys.version_info >= (3, 5):
- linecache.lazycache(frame.f_code.co_filename, frame.f_globals)
+ linecache.lazycache(frame.f_code.co_filename, frame.f_globals)
@classmethod
def executing(cls, frame_or_tb):
@@ -456,7 +361,7 @@ class Source(object):
@staticmethod
def decode_source(source):
- # type: (Union[str, bytes]) -> text_type
+ # type: (Union[str, bytes]) -> str
if isinstance(source, bytes):
encoding = Source.detect_encoding(source)
return source.decode(encoding)
@@ -548,10 +453,7 @@ class QualnameVisitor(ast.NodeVisitor):
def visit_FunctionDef(self, node, name=None):
# type: (ast.AST, Optional[str]) -> None
- if sys.version_info[0] == 3:
- assert isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda)), node
- else:
- assert isinstance(node, (ast.FunctionDef, ast.Lambda)), node
+ assert isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda)), node
self.add_qualname(node, name)
self.stack.append('<locals>')
children = [] # type: Sequence[ast.AST]
@@ -684,8 +586,7 @@ class SentinelNodeFinder(object):
elif op_name in ('LOAD_NAME', 'LOAD_GLOBAL', 'LOAD_FAST', 'LOAD_DEREF', 'LOAD_CLASSDEREF'):
typ = ast.Name
ctx = ast.Load
- if sys.version_info[0] == 3 or instruction.argval:
- extra_filter = lambda e: e.id == instruction.argval
+ extra_filter = lambda e: e.id == instruction.argval
elif op_name in ('COMPARE_OP', 'IS_OP', 'CONTAINS_OP'):
typ = ast.Compare
extra_filter = lambda e: len(e.ops) == 1
diff --git a/contrib/python/executing/executing/version.py b/contrib/python/executing/executing/version.py
index e916218b9c..d97070a2a7 100644
--- a/contrib/python/executing/executing/version.py
+++ b/contrib/python/executing/executing/version.py
@@ -1 +1 @@
-__version__ = '1.2.0' \ No newline at end of file
+__version__ = '2.0.0' \ No newline at end of file
diff --git a/contrib/python/executing/ya.make b/contrib/python/executing/ya.make
index 626c0fd559..2f9d4339d5 100644
--- a/contrib/python/executing/ya.make
+++ b/contrib/python/executing/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(1.2.0)
+VERSION(2.0.0)
LICENSE(MIT)