Python 扩展第三方库/模块的存根文件

Python 扩展第三方库/模块的存根文件,python,python-3.x,mypy,Python,Python 3.x,Mypy,我正在使用库的URL对象 它有一个准私有属性,。\u val,它是一个urllib.parse.SplitResult对象,但在yarl/\uuu init\uuuu.pyi中没有类型注释。(如果开发人员不想正式将其作为公共API的一部分,这是可以理解的。) 但是,我选择使用URL.\u val的风险由我自己承担。一个虚构的例子: # urltest.py from urllib.parse import SplitResult from typing import Tuple from ya

我正在使用库的
URL
对象

它有一个准私有属性,
。\u val
,它是一个
urllib.parse.SplitResult
对象,但在
yarl/\uuu init\uuuu.pyi
中没有类型注释。(如果开发人员不想正式将其作为公共API的一部分,这是可以理解的。)

但是,我选择使用
URL.\u val
的风险由我自己承担。一个虚构的例子:

# urltest.py
from urllib.parse import SplitResult
from typing import Tuple

from yarl import URL


def foo(u: URL) -> Tuple[str, str, str]:
    sr: SplitResult = u._val
    return sr[:3]
但是
mypy
不喜欢这样,因为它抱怨:

$ mypy urltest.py
"URL" has no attribute "_val"
那么,在我自己的项目中,如何将实例属性注释“附加”(或扩展)到
URL
,以便在项目的其余部分使用它呢?即

from yarl import URL

URL._val: SplitResult
# ...
(mypy也不喜欢这样;“不能在分配给非self属性时声明类型。”)


更新 我已经尝试在stubs/yarl/__init__.pyi中创建一个新的存根文件:

from urllib.parse import SplitResult

class URL:
    _val: SplitResult
然后设置
export MYPYPATH='../stubs'
,如中所述。但是,此会覆盖而不是扩展现有注释,因此除了
\u val
之外的所有内容都会抛出错误:

错误:“URL”没有“with_scheme”属性

错误:“URL”没有“主机”属性

错误:“URL”没有属性“片段”


…以此类推。

一种可能是忽略此作业的
u
类型:

def foo(u: URL) -> Tuple[str, str, str, str]:
    sr: SplitResult = typing.cast(typing.Any, u)._val
    return sr[:3]

mypy
将假定您知道自己在做什么,并且
u
具有类型为
str
val
属性。不幸的是,我认为没有办法对某些第三方库的类型提示进行“部分”更改,至少在mypy中没有

我会尝试以下三种选择之一:

  • 只需
    #键入:忽略属性访问:

    deffoo(u:URL)->元组[str,str,str]:
    sr:SplitResult=u._val#类型:忽略
    返回sr[:3]
    
    此类型忽略将抑制该行上生成的任何错误消息。如果您打算采用这种方法,我还建议使用
    --warn unused ignores
    标志运行mypy,该标志将报告任何冗余和未使用的
    #type:ignore
    语句。这个特殊的
    #type:ignore
    不太可能在mypy更新/作为第三方库更新的存根时变得多余,但它是一个很好的标志,可以在一般情况下启用

  • 与这个库的维护人员交谈,看看他们是否愿意为这个属性添加类型提示(即使它是私有的),或者通过一些新的API公开这些信息

    如果有帮助的话,在Typeshed(标准库的类型存储库)中添加类型提示(即使是私有或未记录的属性)也有一些先例——请参阅

  • 如果库维护人员不愿意添加此属性,您可以始终为该库分叉存根,对分叉存根进行更改,然后开始使用该属性


  • 我个人会先尝试解决方案2,然后再尝试解决方案1,但那只是我自己。

    为了它的价值,yarl开发人员遵循了(2)中的理念,但为了它的价值,我认为争论的双方都应该提供更多的背景,说明为什么部分更改没有如您所期望的那样起作用,Guido有,说部分重写在文件级受支持,而不是在功能级受支持,我们无意支持后者。