[Python-ideas] Proposal: Use mypy syntax for function annotations
Yann Kaiser
kaiser.yann at gmail.com
Tue Aug 26 12:49:02 CEST 2014
Given / assuming that most annotated functions will only concern themselves
with one use of annotations (either typing, web forms, cli parameters),
maybe inspect could be extended to have an annotation-filtering function.
Given a namespace(could be any python object), its protocol regarding
annotations for each parameter could be:
* If the annotation is a mapping(c.abc.Mapping): assume the namespace
object is a key of that mapping. If the key is not present, return None for
that annotation.
* If the annotation is not a mapping, it is always returned whole.
The implications would be:
* A stdlib-approved way of namespacing annotations would exist. Annotations
for different introspectors can coexist.
* inspect.signature's purpose remains unchanged and still tells the whole
truth
* Most annotated functions, typing-related or not are unchanged. (except
those that consist of a mapping ☹)
In Python:
import inspect
import collections.abc
def filter_annotation(annotation, namespace):
if isinstance(annotation, collections.abc.Mapping):
return annotation.get(namespace, inspect.Signature.empty)
return annotation
def filter_annotations(signature, namespace):
params = [
p.replace(annotation=filter_annotation(p.annotation, namespace))
for p in signature.parameters.values()
]
ret = filter_annotation(signature.return_annotation, namespace)
return signature.replace(parameters=params, return_annotation=ret)
>>> def classic(param:'annot'): pass
...
>>> cliparser = object()
>>> typing = object()
>>> def namespaced(*, param:{typing:int, cliparser:'p'}): pass
...
>>> s_classic = inspect.signature(classic)
>>> s_namespaced = inspect.signature(namespaced)
>>> print(filter_annotations(s_classic, cliparser))
(param:'annot')
>>> print(filter_annotations(s_classic, typing))
(param:'annot')
>>> print(filter_annotations(s_namespaced, cliparser))
(*, param:'p')
>>> print(filter_annotations(s_namespaced, typing))
(*, param:int)
On 26 August 2014 07:47, Jukka Lehtosalo <jlehtosalo at gmail.com> wrote:
> On Mon, Aug 25, 2014 at 10:26 AM, Guido van Rossum <guido at python.org>
> wrote:
>
>> On Mon, Aug 25, 2014 at 6:57 AM, Antoine Pitrou <antoine at python.org>
>> wrote:
>>
>>> PEP 3107 doesn't say anything about that (or rather, it says that
>>> annotations can be looked up on the function, but function objects only
>>> exist at run-time). Actually, the bytecode isn't very practical to work
>>> with to extract annotations,
>>>
>> I don't know at which point mypy changed goals (if it has), but there are
>>> still signs in the website of the goal of building a separate runtime (not
>>> necessarily a separate syntax), e.g.
>>>
>>>
>>> """Also some language features that are evaluated at runtime in Python
>>> may happen during compilation in mypy when using the native semantics.
>>> For example, mypy base classes may be bound during compilation (or
>>> program loading, before evaluation), unlike Python."""
>>>
>>
>> I have talked to Jukka about this, and he is definitely on board with
>> reducing mypy's functionality to that of a linter; I think there's even an
>> issue in mypy's tracker about removing the ability to execute the code
>> (currently there's a flag you must pass to prevent it from trying to run
>> the code). Updating the website is an ongoing low-priority project (you can
>> probably send him pull requests for it).
>>
>
> Yeah, the website wasn't very up-to-date. The project goals have shifted a
> lot in the last 18 months. I just updated the tutorial and the FAQ to not
> talk about the native semantics.
>
>
>> mypy complains about the unannotated initialization of sqs. The two ways
>> to currently address this are
>>
>> sqs = [] # type: List[float]
>>
>> or
>>
>> sqs = List[float]()
>>
>> Neither is very attractive; mypy should just infer the type of sqs.
>>
>
> Agreed, but this is very difficult to do in all possible contexts. For
> example, __init__ methods often use an empty list as an attribute
> initializer, and here it's more tricky to infer the item type, as we'd have
> to look into other methods to figure out the item type.
>
>
>>
>> Nevertheless, I don't want to use call syntax to set parameters for
>> generic types, since a generic type still "feels" sufficiently like a class
>> that calling it is easily confused with instantiation -- even though ABCs
>> are typically not instantiable. (There's no hard rule for that though -- it
>> is merely the result of typical ABCs having at least one abstract method.)
>>
>
> Generic types don't need to be abstract, and for those the call syntax
> would be ambiguous (and confusing).
>
> Jukka
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20140826/74b2d370/attachment.html>
More information about the Python-ideas
mailing list