fix annotation evaluation error backtrace

This commit is contained in:
Shiz 2021-06-25 18:14:59 +02:00
parent f532df7d5f
commit cea7e8733f
2 changed files with 37 additions and 6 deletions

View File

@ -1,7 +1,8 @@
import os
import math
import inspect
import ast
import collections
from typing import BinaryIO, Generator, Callable, Union as U, Any, cast
from typing import BinaryIO, Generator, Callable, Union as U, Tuple, Mapping, Any, cast
from contextlib import contextmanager
@ -65,3 +66,24 @@ def format_value(value: Any, formatter: Callable[[Any], str], indentation: int =
fmt = '{}'
values = [formatter(value)]
return indent(fmt.format(*values), indentation)
def get_annot_locations(cls: type) -> Tuple[str, Mapping[str, int]]:
""" why """
fn = inspect.getsourcefile(cls)
slines, start = inspect.getsourcelines(cls)
mdef = ast.parse(''.join(slines))
lines = {}
for b in mdef.body[0].body:
if isinstance(b, ast.Assign):
ts = b.targets
elif isinstance(b, (ast.AnnAssign, ast.AugAssign)):
ts = [b.target]
else:
continue
for t in ts:
if isinstance(t, ast.Name):
lines[t.id] = start + b.lineno - 2
return fn, lines

View File

@ -12,7 +12,7 @@ import sx
from ..core import to_type
from ..core.base import Context, Type, PathElement
from ..core.io import Stream, Pos, add_sizes
from ..core.util import indent, format_value
from ..core.util import indent, format_value, get_annot_locations
from ..core.meta import Generic
from ..core.expr import IndirectExpr, TypeSource
@ -227,8 +227,16 @@ class Struct:
annots = {}
localns = {'Self': cls}
for c in reversed(cls.__mro__):
try:
fn, lines = get_annot_locations(c)
except:
fn = None
lines = {}
globalns = sys.modules[c.__module__].__dict__
annots.update({k: (globalns, v) for k, v in getattr(c, '__annotations__', {}).items()})
annots.update({
k: (fn or f'<annotation:{k}>', lines.get(k, 0), globalns, v)
for k, v in getattr(c, '__annotations__', {}).items()
})
localns[c.__name__] = c
if inject:
localns.update({x: getattr(sx, x) for x in sx.__all__})
@ -238,8 +246,9 @@ class Struct:
proxy = StructProxy()
localns['self'] = proxy
fields = {}
for name, (globalns, value) in annots.items():
val = eval(value, globalns, localns)
for name, (fn, line, globalns, value) in annots.items():
code = compile('\n' * line + value, fn, 'eval')
val = eval(code, globalns, localns)
if isinstance(val, Annotated):
val = next(v for v in val.__metadata__ if isinstance(v, Type))
fields[name] = val