Larry Hastings <la...@hastings.org> added the comment:
Just over twelve hours ago, the Python Steering Committee announced that stringized annotations would no longer be default behavior in Python 3.10. They will go back to being gated with "from __future__ import annotations". I think we still need this function, but naturally the implementation will now be a bit different. It's going to take time to change the default semantics of annotations back to the way they were in Python 3.9. In the meantime, I've coded up a first draft of inspect.get_annotations(), written assuming stringized annotations are optional. It's attached below. I'll also paste in the definition and the docstring into the text box here for your reading convenience. I assert that get_annotations() should definitely try to un-stringize stringized annotations by default. The default behavior of eval_str is sliightly magical, but I'm not sure I can do anything any smarter (apart from "resist the temptation to guess"). Unsophisticated users will want to see real values, and it may be important to give sophisticated users control over whether or not eval() is called. By the same token: if eval_str stays as part of the interface, I propose exposing it from the library functions that will call get_annotations(): * inspect.signature() * functools.singledispatch() That way, a project using stringized annotations due to gnarly circular imports/definitions problems could still use inspect.signature(), without having to worry about worrying about whether or not all the symbols were defined at runtime. I'll interpret a lack of feedback as a sort of mumbled encouraging consensus. ----- def get_annotations(obj, globals=None, locals=None, *, eval_str=ONLY_IF_ALL_STR): Compute the annotations dict for an object. obj may be a callable, class, or module. Passing in any other type of object raises TypeError. This function handles several details for you: * Values of type str may be un-stringized using eval(), depending on the value of eval_str. This is intended for use with stringized annotations (from __future__ import annotations). * If obj doesn't have an annotations dict, returns an empty dict. (Functions and methods always have an annotations dict; classes, modules, and other types of callables may not.) * Ignores inherited annotations on classes. If a class doesn't have its own annotations dict, returns an empty dict. * Always, always, always returns a dict. eval_str controls whether or not values of type str are replaced with the result of calling eval() on those values: * If eval_str is true, eval() is called on values of type str. * If eval_str is false, values of type str are unchanged. * If eval_str is the special value inspect.ONLY_IF_ALL_STR, which is the default, eval() is called on values of type str only if *every* value in the dict is of type str. This is a heuristic; the goal is to only eval() stringized annotations. (If, in a future version of Python, get_annotations() is able to determine authoritatively whether or not an annotations dict contains stringized annotations, inspect.ONLY_IF_ALL_STR will use that authoritative source instead of the heuristic.) globals and locals are passed in to eval(); see the documentation for eval() for more information. If globals is None, get_annotations() uses a context-specific default value, contingent on type(obj): * If obj is a module, globals defaults to obj.__dict__. * If obj is a class, globals defaults to sys.modules[obj.__module__].__dict__. * If obj is a callable, globals defaults to obj.__globals__, although if obj is a wrapped function (using functools.update_wrapper()) it is first unwrapped. ---------- Added file: https://bugs.python.org/file49968/get_annotations.py _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue43817> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com