From: Mike Bayer Date: Wed, 15 Sep 2021 20:43:45 +0000 (-0400) Subject: render 3rd party module annotations as forward references X-Git-Tag: rel_1_7_2~1^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b08447862388ae4064c36dcc1f0c91d84fa3c06f;p=thirdparty%2Fsqlalchemy%2Falembic.git render 3rd party module annotations as forward references Fixed issue where registration of custom ops was prone to failure due to the registration process running ``exec()`` on generated code that as of the 1.7 series includes pep-484 annotations, which in the case of end user code would result in name resolution errors when the exec occurs. The logic in question has been altered so that the annotations are rendered as forward references so that the ``exec()`` can proceed. Change-Id: I142b89e2f6354b2ce253f3b8109f59fa3aae68ef Fixes: #920 --- diff --git a/alembic/operations/base.py b/alembic/operations/base.py index 59bbfc48..07ddd5af 100644 --- a/alembic/operations/base.py +++ b/alembic/operations/base.py @@ -17,9 +17,11 @@ from . import batch from . import schemaobj from .. import util from ..util import sqla_compat +from ..util.compat import formatannotation_fwdref from ..util.compat import inspect_formatargspec from ..util.compat import inspect_getfullargspec + NoneType = type(None) if TYPE_CHECKING: @@ -121,7 +123,9 @@ class Operations(util.ModuleClsProxy): name_args[0:2] = ["self"] - args = inspect_formatargspec(*spec) + args = inspect_formatargspec( + *spec, formatannotation=formatannotation_fwdref + ) num_defaults = len(spec[3]) if spec[3] else 0 if num_defaults: defaulted_vals = name_args[0 - num_defaults :] @@ -134,6 +138,7 @@ class Operations(util.ModuleClsProxy): spec[2], defaulted_vals, formatvalue=lambda x: "=" + x, + formatannotation=formatannotation_fwdref, ) args = re.sub( diff --git a/alembic/util/compat.py b/alembic/util/compat.py index 1e435a82..91b5cf9f 100644 --- a/alembic/util/compat.py +++ b/alembic/util/compat.py @@ -41,3 +41,16 @@ def importlib_metadata_get(group): return ep.select(group=group) else: return ep.get(group, ()) + + +def formatannotation_fwdref(annotation, base_module=None): + """the python 3.7 _formatannotation with an extra repr() for 3rd party + modules""" + + if getattr(annotation, "__module__", None) == "typing": + return repr(annotation).replace("typing.", "") + if isinstance(annotation, type): + if annotation.__module__ in ("builtins", base_module): + return annotation.__qualname__ + return repr(annotation.__module__ + "." + annotation.__qualname__) + return repr(annotation) diff --git a/docs/build/unreleased/920.rst b/docs/build/unreleased/920.rst new file mode 100644 index 00000000..017ce890 --- /dev/null +++ b/docs/build/unreleased/920.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, regression, ops + :tickets: 920 + + Fixed issue where registration of custom ops was prone to failure due to + the registration process running ``exec()`` on generated code that as of + the 1.7 series includes pep-484 annotations, which in the case of end user + code would result in name resolution errors when the exec occurs. The logic + in question has been altered so that the annotations are rendered as + forward references so that the ``exec()`` can proceed.