Dedublizierung gefixt

- lange existierender Updatecode wurde in jeder 2. Version angezeigt
- UPDATEANALYSE.md ergänzt.
This commit is contained in:
2026-08-20 13:27:23 +02:00
parent 5d227d2f61
commit b549063ff6
138 changed files with 43143 additions and 1472 deletions
+75
View File
@@ -76,6 +76,15 @@ INTERESTING_OPS = {
"select",
}
# Aufrufe, die im "unresolved"-Log NICHT auftauchen sollen, weil sie entweder
# an anderer Stelle bereits sinnvoll aufgelöst werden (__table__,
# __table_handler__, pool.get) oder nachweislich nie eine DB-Operation sind
# (Listen-.append, Logging). Erste Fassung nach Sichtung von echten
# Tryton-Modulen (product.json) - bei Bedarf einfach erweitern.
IGNORED_UNRESOLVED_OPERATIONS = {"__table__", "__table_handler__", "append"}
IGNORED_UNRESOLVED_OBJECTS = {"logger"}
IGNORED_UNRESOLVED_CALLS = {("pool", "get")}
# --------------------------------------------------------------------------
# AST-Visitor
@@ -433,10 +442,76 @@ class RegisterExtractor(ast.NodeVisitor):
self.walk_into_helper(
method_name, func_node, node.lineno, operations, phase, condition
)
else:
unresolved = self.extract_unresolved_call(node)
if unresolved:
unresolved["phase"] = phase
if condition:
unresolved["condition"] = condition
if self.call_chain:
unresolved["via"] = [dict(entry) for entry in self.call_chain]
operations.append(unresolved)
for child in ast.iter_child_nodes(node):
self.walk_expression(child, operations, phase, condition)
def extract_unresolved_call(self, call):
"""
Rohmaterial-Eintrag für Aufrufe in __register__ (bzw. einem
verfolgten Helper), die weder eine erkannte DB-Operation noch ein
auflösbarer cls./self.-Helper sind. Über das Flag "unresolved": true
von echten Operationen unterscheidbar. Bewusst noch ungefiltert
gehalten - bis auf eine kleine, aus echten Modulen (siehe
IGNORED_UNRESOLVED_*) abgeleitete Liste von Aufrufen, die
nachweislich nie eine DB-Operation sind bzw. bereits an anderer
Stelle sinnvoll aufgelöst werden. Gibt None zurück, wenn der Aufruf
gefiltert werden soll.
"""
if isinstance(call.func, ast.Attribute):
operation = call.func.attr
if isinstance(call.func.value, ast.Name):
obj = call.func.value.id
else:
obj = ast.unparse(call.func.value)
elif isinstance(call.func, ast.Name):
operation = call.func.id
obj = ""
else:
operation = ast.unparse(call.func)
obj = ""
if (
operation in IGNORED_UNRESOLVED_OPERATIONS
or obj in IGNORED_UNRESOLVED_OBJECTS
or (obj, operation) in IGNORED_UNRESOLVED_CALLS
):
return None
args = []
for arg in call.args:
try:
args.append(ast.unparse(arg))
except Exception:
args.append("<unknown>")
kwargs = {}
for kw in call.keywords:
try:
kwargs[kw.arg] = ast.unparse(kw.value)
except Exception:
kwargs[kw.arg] = "<unknown>"
return {
"object": obj,
"operation": operation,
"tables": self.find_tables(call),
"line": call.lineno,
"args": args,
"kwargs": kwargs,
"code": self._render_code(call),
"unresolved": True,
}
def resolve_helper_call(self, node):
"""
Erkennt Aufrufe der Form `cls.<method>(...)` / `self.<method>(...)`