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

Reply via email to