aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-09-24 09:19:19 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-09-24 09:26:58 +0300
commit7b52d3a3ff9ea0bda3fb19634cdfb3a3ac6a52e2 (patch)
treec3546e6d2cb5edcb48c4dfeb7575c0e5952d679b /contrib
parent53f13049cb8f79b2b6ac95251fd6a03e4b8c7ba2 (diff)
downloadydb-7b52d3a3ff9ea0bda3fb19634cdfb3a3ac6a52e2.tar.gz
Intermediate changes
commit_hash:4fd110744a809cc923058a0e9949e65d8fa64e4d
Diffstat (limited to 'contrib')
-rw-r--r--contrib/python/executing/.dist-info/METADATA22
-rw-r--r--contrib/python/executing/executing/_position_node_finder.py130
-rw-r--r--contrib/python/executing/executing/executing.py11
-rw-r--r--contrib/python/executing/executing/version.py2
-rw-r--r--contrib/python/executing/ya.make2
5 files changed, 138 insertions, 29 deletions
diff --git a/contrib/python/executing/.dist-info/METADATA b/contrib/python/executing/.dist-info/METADATA
index b598e4907d..45ff9aa881 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: 2.0.1
+Version: 2.1.0
Summary: Get the currently executing AST node of a frame, and other information
Home-page: https://github.com/alexmojaki/executing
Author: Alex Hall
@@ -9,25 +9,23 @@ License: MIT
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
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
-Requires-Python: >=3.5
+Classifier: Programming Language :: Python :: 3.13
+Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Provides-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'
+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
diff --git a/contrib/python/executing/executing/_position_node_finder.py b/contrib/python/executing/executing/_position_node_finder.py
index 8ca21a67bd..7a814150da 100644
--- a/contrib/python/executing/executing/_position_node_finder.py
+++ b/contrib/python/executing/executing/_position_node_finder.py
@@ -72,7 +72,7 @@ def mangled_name(node: EnhancedAST) -> str:
@lru_cache(128) # pragma: no mutate
def get_instructions(code: CodeType) -> list[dis.Instruction]:
- return list(dis.get_instructions(code, show_caches=True))
+ return list(dis.get_instructions(code))
types_cmp_issue_fix = (
@@ -114,7 +114,7 @@ class PositionNodeFinder(object):
"""
def __init__(self, frame: FrameType, stmts: Set[EnhancedAST], tree: ast.Module, lasti: int, source: Source):
- self.bc_list = get_instructions(frame.f_code)
+ self.bc_dict={bc.offset:bc for bc in get_instructions(frame.f_code) }
self.source = source
self.decorator: Optional[EnhancedAST] = None
@@ -141,7 +141,7 @@ class PositionNodeFinder(object):
# we ignore here the start position and try to find the ast-node just by end position and expected node type
# This is save, because there can only be one attribute ending at a specific point in the source code.
typ = (ast.Attribute,)
- elif self.opname(lasti) == "CALL":
+ elif self.opname(lasti) in ("CALL", "CALL_KW"):
# A CALL instruction can be a method call, in which case the lineno and col_offset gets changed by the compiler.
# Therefore we ignoring here this attributes and searchnig for a Call-node only by end_col_offset and end_lineno.
# This is save, because there can only be one method ending at a specific point in the source code.
@@ -156,13 +156,18 @@ class PositionNodeFinder(object):
typ=typ,
)
- self.known_issues(self.result, self.instruction(lasti))
+ instruction = self.instruction(lasti)
+ assert instruction is not None
+
+ self.result = self.fix_result(self.result, instruction)
+
+ self.known_issues(self.result, instruction)
self.test_for_decorator(self.result, lasti)
# verify
if self.decorator is None:
- self.verify(self.result, self.instruction(lasti))
+ self.verify(self.result, instruction)
else:
assert_(self.decorator in self.result.decorator_list)
@@ -213,6 +218,32 @@ class PositionNodeFinder(object):
if sys.version_info < (3, 12):
index += 4
+ def fix_result(
+ self, node: EnhancedAST, instruction: dis.Instruction
+ ) -> EnhancedAST:
+ if (
+ sys.version_info >= (3, 12, 5)
+ and instruction.opname in ("GET_ITER", "FOR_ITER")
+ and isinstance(node.parent, ast.For)
+ and node is node.parent.iter
+ ):
+ # node positions have changed in 3.12.5
+ # https://github.com/python/cpython/issues/93691
+ # `for` calls __iter__ and __next__ during execution, the calling
+ # expression of these calls was the ast.For node since cpython 3.11 (see test_iter).
+ # cpython 3.12.5 changed this to the `iter` node of the loop, to make tracebacks easier to read.
+ # This keeps backward compatibility with older executing versions.
+
+ # there are also cases like:
+ #
+ # for a in iter(l): pass
+ #
+ # where `iter(l)` would be otherwise the resulting node for the `iter()` call and the __iter__ call of the for implementation.
+ # keeping the old behaviour makes it possible to distinguish both cases.
+
+ return node.parent
+ return node
+
def known_issues(self, node: EnhancedAST, instruction: dis.Instruction) -> None:
if instruction.opname in ("COMPARE_OP", "IS_OP", "CONTAINS_OP") and isinstance(
node, types_cmp_issue
@@ -324,6 +355,35 @@ class PositionNodeFinder(object):
):
raise KnownIssue("exception generation maps to condition")
+ if sys.version_info >= (3, 13):
+ if instruction.opname in (
+ "STORE_FAST_STORE_FAST",
+ "STORE_FAST_LOAD_FAST",
+ "LOAD_FAST_LOAD_FAST",
+ ):
+ raise KnownIssue(f"can not map {instruction.opname} to two ast nodes")
+
+ if instruction.opname == "LOAD_FAST" and instruction.argval == "__class__":
+ # example:
+ # class T:
+ # def a():
+ # super()
+ # some_node # <- there is a LOAD_FAST for this node because we use super()
+
+ raise KnownIssue(
+ f"loading of __class__ is accociated with a random node at the end of a class if you use super()"
+ )
+
+ if (
+ instruction.opname == "COMPARE_OP"
+ and isinstance(node, ast.UnaryOp)
+ and isinstance(node.operand,ast.Compare)
+ and isinstance(node.op, ast.Not)
+ ):
+ # work around for
+ # https://github.com/python/cpython/issues/114671
+ self.result = node.operand
+
@staticmethod
def is_except_cleanup(inst: dis.Instruction, node: EnhancedAST) -> bool:
if inst.opname not in (
@@ -703,6 +763,52 @@ class PositionNodeFinder(object):
if node_match(ast.FormattedValue) and inst_match("FORMAT_VALUE"):
return
+ if sys.version_info >= (3, 13):
+
+ if inst_match("NOP"):
+ return
+
+ if inst_match("TO_BOOL") and node_match(ast.BoolOp):
+ return
+
+ if inst_match("CALL_KW") and node_match((ast.Call, ast.ClassDef)):
+ return
+
+ if inst_match("LOAD_FAST", argval=".type_params"):
+ return
+
+ if inst_match("LOAD_FAST", argval="__classdict__"):
+ return
+
+ if inst_match("LOAD_FAST") and node_match(
+ (
+ ast.FunctionDef,
+ ast.ClassDef,
+ ast.TypeAlias,
+ ast.TypeVar,
+ ast.Lambda,
+ ast.AsyncFunctionDef,
+ )
+ ):
+ # These are loads for closure variables.
+ # It is difficult to check that this is actually closure variable, see:
+ # https://github.com/alexmojaki/executing/pull/80#discussion_r1716027317
+ return
+
+ if (
+ inst_match("LOAD_FAST")
+ and node_match(ast.TypeAlias)
+ and node.name.id == instruction.argval
+ ):
+ return
+
+ if inst_match("STORE_NAME",argval="__static_attributes__"):
+ # the node is the first node in the body
+ return
+
+ if inst_match("LOAD_FAST") and isinstance(node.parent,ast.TypeVar):
+ return
+
# old verifier
@@ -771,11 +877,14 @@ class PositionNodeFinder(object):
raise VerifierFailure(title, node, instruction)
- def instruction(self, index: int) -> dis.Instruction:
- return self.bc_list[index // 2]
+ def instruction(self, index: int) -> Optional[dis.Instruction]:
+ return self.bc_dict.get(index,None)
def opname(self, index: int) -> str:
- return self.instruction(index).opname
+ i=self.instruction(index)
+ if i is None:
+ return "CACHE"
+ return i.opname
extra_node_types=()
if sys.version_info >= (3,12):
@@ -798,7 +907,10 @@ class PositionNodeFinder(object):
*extra_node_types,
),
) -> EnhancedAST:
- position = self.instruction(index).positions
+ instruction = self.instruction(index)
+ assert instruction is not None
+
+ position = instruction.positions
assert position is not None and position.lineno is not None
return only(
diff --git a/contrib/python/executing/executing/executing.py b/contrib/python/executing/executing/executing.py
index 7727c42232..5cf117e18c 100644
--- a/contrib/python/executing/executing/executing.py
+++ b/contrib/python/executing/executing/executing.py
@@ -273,16 +273,15 @@ class Source(object):
node_finder = NodeFinder(frame, stmts, tree, lasti, source)
node = node_finder.result
decorator = node_finder.decorator
+
+ if node:
+ new_stmts = {statement_containing_node(node)}
+ assert_(new_stmts <= stmts)
+ stmts = new_stmts
except Exception:
if TESTING:
raise
- assert stmts is not None
- if node:
- new_stmts = {statement_containing_node(node)}
- assert_(new_stmts <= stmts)
- stmts = new_stmts
-
executing_cache[key] = args = source, node, stmts, decorator
return Executing(frame, *args)
diff --git a/contrib/python/executing/executing/version.py b/contrib/python/executing/executing/version.py
index 9d909dcc3c..b15121b0fe 100644
--- a/contrib/python/executing/executing/version.py
+++ b/contrib/python/executing/executing/version.py
@@ -1 +1 @@
-__version__ = '2.0.1' \ No newline at end of file
+__version__ = '2.1.0' \ No newline at end of file
diff --git a/contrib/python/executing/ya.make b/contrib/python/executing/ya.make
index b676502282..b437b26981 100644
--- a/contrib/python/executing/ya.make
+++ b/contrib/python/executing/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(2.0.1)
+VERSION(2.1.0)
LICENSE(MIT)