Typehint googleapiclient.discovery.build 返回值

问题描述 投票:0回答:1

我为特定类型创建了 Google API

Resource
类(在本例中为
blogger
)。

from googleapiclient.discovery import Resource, build

def get_google_service(api_type) -> Resource:
    credentials = ...

    return build(api_type, 'v3', credentials=credentials)

def blog_service():
    return get_google_service('blogger')

def list_blogs():
    return blog_service().blogs()

使用

list_blogs
函数时会出现问题。 由于我提供了特定的服务名称,我知道
blog_service
的返回值有一个
blogs
方法,但我的 IDE 无法识别它。 有没有办法注释
blog_service
函数(或代码的任何其他部分)以告知我的 IDE
blogs
方法的存在?

python type-hinting google-api-python-client
1个回答
1
投票

这里的问题是

Resource
动态根据底层API提供的集合设置任意属性/方法。

在您的情况下,显然有一个

blogs
集合,这意味着
blogs
方法是在该
Resource
对象上动态构造的。

期望静态类型注释,当你的类型被动态创建时是一个艰巨的任务。 (我认为这是

google-api-python-client
的维护者甚至不关心该包中的类型提示的原因之一。)

但是,根据您对这些功能的目标,您可以通过使用 协议来改善您的 IDE 体验。

如果您知道您的

blog_service
函数返回一个具有
blogs
方法的对象,您可以定义相应的 协议。这个问题当然被解决了,因为无论
blogs
方法返回什么,也可能有任意方法。但取决于这对您是否重要,您可以再次应用相同的原则。

好处是

Resource
本身实际上似乎只有很少的公共方法,基本上只有
close
和上下文管理器协议。因此,您可以在某种基本协议中进行模拟,并使用继承来构造不同的资源协议。

这里举个例子来说明:

from typing import Any, Protocol, Self

from googleapiclient.discovery import build  # type: ignore[import]


class ResourceProtocol(Protocol):
    def close(self) -> None: ...

    def __enter__(self) -> Self: ...

    def __exit__(self, *args: Any) -> None: ...


class BloggerProtocol(ResourceProtocol):
    def blogs(self) -> Any: ...


def get_google_service(api_type: str) -> Any:
    credentials = ...
    return build(api_type, 'v3', credentials=credentials)


def blog_service() -> BloggerProtocol:
    return get_google_service('blogger')  # type: ignore[no-any-return]


def list_blogs() -> Any:
    return blog_service().blogs()

(请注意,这些都是 literal 省略号

...
。此外,如果您使用的是 Python
<3.11
,您应该能够从 Self
 导入 
typing_extensions
。)

现在您的 IDE 应该能够检测到

blog_service
返回的对象具有
blogs
方法 并且 可以用作上下文管理器(使用
with
)。

请注意,我将

blogs
的返回类型注释为
Any
,因为我不知道它应该返回什么类型。

© www.soinside.com 2019 - 2024. All rights reserved.