Mypy 在调用函数时出错,返回类型为 TypeVar 的 List of TypedDict

时间:2021-01-13 14:32:40

标签: python python-3.x typing mypy

我试图在类中键入提示函数,但在 mypy 中出现以下错误

get_items 函数调用后台运行的scrapyRT API 并根据蜘蛛名和url 输出 蜘蛛espn-matches以List[Match]的形式返回输出,espn-players以List[Player]的形式返回输出

get_items 函数返回 Player dict 列表或 Matches dict 列表

app/fantasy_cricket/ScrapyRTClient.py:74: error: Incompatible return value type (got "List[Player]", expected "List[Match]")
Found 1 error in 1 file (checked 1 source file)

这是我的代码:

import requests
import sys
if sys.version_info >= (3, 8):
    from typing import TypedDict
else:
    from typing_extensions import TypedDict
from typing import TypeVar, List, Union, Optional

class Player(TypedDict):
    name: str
    role: str
    image: str
    player_id: str

class Match(TypedDict):
    runs: Optional[int]
    boundaries: Optional[int] 
    sixes: Optional[int]
    wicket : Optional[int]
    Maiden: Optional[int]
    Catch: Optional[int]
    Stump: Optional[int]
    match_id: str

Item = TypeVar("Item", Player, Match)

class espn_scrapyrt_client:
    def __init__(self) -> None:

        self.url = "http://localhost:9080/crawl.json"

    def get_items(self, spider_name: str, url: str) -> List[Item]:

        items = requests.get(self.url, params={"spider_name": spider_name, "url": url})

        return items.json()["items"]

    def get_player_dets(self, team: str, players: List[str]) -> List[Player]:

        team_map = {
            "India": "https://www.espncricinfo.com/ci/content/player/index.html?country=6",
            "Australia": "https://www.espncricinfo.com/ci/content/player/index.html?country=2",
            "England": "https://www.espncricinfo.com/ci/content/player/index.html?country=1",
            "Bangladesh": "https://www.espncricinfo.com/ci/content/player/index.html?country=25",
            "New Zealand": "https://www.espncricinfo.com/ci/content/player/index.html?country=5",
            "South Africa": "https://www.espncricinfo.com/ci/content/player/index.html?country=3",
            "Pakistan": "https://www.espncricinfo.com/ci/content/player/index.html?country=7",
            "Sri Lanka": "https://www.espncricinfo.com/ci/content/player/index.html?country=8",
            "West Indies": "https://www.espncricinfo.com/ci/content/player/index.html?country=4",
            "Afghanistan": "https://www.espncricinfo.com/ci/content/player/index.html?country=40",
        }

        team_players = self.get_items(spider_name="espn-players", url=team_map[team])
        names = {player["name"]: i for i, player in enumerate(team_players)}
        player_det = []
        for player in players:
            player_name = player.strip().split()
            if len(player_name) == 1:
                p = [names[name] for name in names if player.strip() in name]
            elif len(player_name) > 1:
                p = [
                    names[name]
                    for name in names
                    if player_name[0] in name and player_name[-1] in name
                ]
            if p!=[]:
                player_det.append(team_players[p[0]])
        return player_det

    def get_match_de(self, player_id: str) -> List[Match]:

        x = self.get_items(spider_name="espn-matches", url = "https://stats.espncricinfo.com/ci/engine/player/253802.html?class=1&orderby=start&orderbyad=reverse&template=results&type=allround&view=match")
        print(x)
        return x //error here

任何帮助将不胜感激! 谢谢!!

1 个答案:

答案 0 :(得分:0)

这里的问题在于您的 get_items 方法中的这两行:

items = requests.get(self.url, params={"spider_name": spider_name, "url": url})
return items.json()["items"]

MyPy 不知道调用 dict 产生的 items.json() 中键和值的类型是什么。 MyPy 在这里的混乱会渗透到您的其余代码中,并最终在第 74 行中产生错误。

我们可以通过使用 typing.cast 为 MyPy 提供有关此字典中键和值类型的一些信息来解决此问题。我们还可以使用 typing.overloadtyping.Literal 结合使用,以通知 MyPy 如果 get_items 使用 spider_name="espn-players" 调用,它将返回 list 的 {{ 1}} Player,而如果使用 dicts 调用它,它将返回 spider_name="espn-matches" listMatch

dicts