tobgu/pyrsistent

PRecord field types in Python 3.7

Open

#181 创建于 2019年10月31日

在 GitHub 查看
 (4 评论) (0 反应) (0 负责人)Python (1,943 star) (141 fork)batch import
help wanted

描述

Consider the following code snippet contained in a python module named pyrsistent_test.py:

from typing import Mapping

from pyrsistent import field, PRecord

class MyPRecord(PRecord):
  f = field(type=Mapping)


def main():
  p = MyPRecord(f={})

  print(p)


if __name__ == '__main__':
  main()

When running this under Python 3.6 the output is as follows:

(python-3.6) $ python pyrsistent_test.py 
MyPRecord(f={})
(python-3.6) $

When running this under Python 3.7 the output is as follows:

(python-3.7) $ python pyrsistent_test.py 
Traceback (most recent call last):
  File "pyrsistent_test.py", line 5, in <module>
    class MyPRecord(PRecord):
  File "pyrsistent_test.py", line 6, in MyPRecord
    f = field(type=Mapping)
  File "/home/aaron/workspace/pyrsistent/pyrsistent/_field_common.py", line 120, in field
    types = set(maybe_parse_user_type(type))
  File "/home/aaron/workspace/pyrsistent/pyrsistent/_checked_types.py", line 88, in maybe_parse_user_type
    'Type specifications must be types or strings. Input: {}'.format(t)
TypeError: Type specifications must be types or strings. Input: typing.Mapping
(python-3.7) $

I've been using the typing module for defining most of my PRecord field types but have only begun to think about upgrading to Python 3.7 hence running into this problem now.

Is it not expected to use things from the typing module when defining the types for a PRecord field - not sure if I've missed another way of doing things?

I do notice that the type of things in the typing module has changed between 3.6 and 3.7:

Python 3.6.9 (default, Jul  3 2019, 15:36:16) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import typing
>>> type(typing.Mapping)
<class 'typing.GenericMeta'>
>>>
Python 3.7.5 (default, Oct 15 2019, 21:38:37) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import typing
>>> type(typing.Mapping)
<class 'typing._GenericAlias'>
>>>

I did have a go at adding another elif state to maybe_parse_user_type in https://github.com/tobgu/pyrsistent/blob/master/pyrsistent/_checked_types.py#L62-L89 which solved the issue though this doesn't really seem like the right thing to do and I haven't fully comprehended the implications of changing this function!:

elif isinstance(t, typing._VariadicGenericAlias) or isinstance(t, typing._GenericAlias):
        return [t.__origin__]

Happy to do a PR but feel I would need some guidance first.

贡献者指南