在 Python 3.6 数据类上使用 enforce_types 时出错:没有属性 _SpecialForm

Error using enforce_types on a Python 3.6 dataclass: no attribute _SpecialForm

我正在使用 enforce_typingdataclasses 创建一个简单的 - 希望是健壮的 - 对象来配置模型。我正在使用 Travis 测试项目的代码,并在 3.6、3.7 和 3.8 上构建。

在 3.6 上构建失败并出现错误:

AttributeError: module 'typing' has no attribute '_SpecialForm'

我在下面放了一个简单的 reprex 来显示实践中的错误。我能做些什么来解决这个问题?可能我只是应该停止尝试支持 3.6!

Python 3.6.7 (default, Aug 12 2021, 12:48:47) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.16.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import enforce_typing
In [3]: import dataclasses
In [5]: @enforce_typing.enforce_types
   ...: @dataclasses.dataclass
   ...: class Test():
   ...:     x: str = 'a'
   ...: 

In [6]: Test()
Out[6]: Test(x='a')

In [7]: Test(x='c')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-54c6f8c04751> in <module>
----> 1 Test(x='c')

~/.pyenv/versions/3.6.7/lib/python3.6/site-packages/enforce_typing/decorator.py in wrapper(*args, **kwargs)
     26         @wraps(func)
     27         def wrapper(*args, **kwargs):
---> 28             check_types(*args, **kwargs)
     29             return func(*args, **kwargs)
     30 

~/.pyenv/versions/3.6.7/lib/python3.6/site-packages/enforce_typing/decorator.py in check_types(*args, **kwargs)
     14             with suppress(KeyError):
     15                 type_hint = spec.annotations[name]
---> 16                 if isinstance(type_hint, typing._SpecialForm):
     17                     continue
     18                 actual_type = getattr(type_hint, "__origin__", type_hint)

AttributeError: module 'typing' has no attribute '_SpecialForm'


错误消息清楚地表明 enforce_typing 库假定 Python 的 typing 模块中有一个 _SpecialForm class。对于该库来说,这是一个非常不明智的假设,因为 class 的名称以单个下划线开头,因此 _SpecialForm 被明确标记为模块的实现细节。对于 typing 模块尤其如此,它仍然是新的并且正在非常积极的开发中,许多实现细节在 python.

的每个版本中都发生了重大变化

顺便说一句,我实际上并没有在此处批评 enforce_typing 图书馆。不幸的是,由于 typing 模块中的很多东西都被标记为实现细节,因此(目前)没有一种特别安全的方法来概括这种运行时类型检查。