Search code examples
pythonpython-3.xmypy

MyPy error: Expected type in class pattern; found "Any"


Want to add MyPy checker to my html scraper. I manage to fix all errors except this one Expected type in class pattern.

Source code:

from bs4 import BeautifulSoup

from bs4.element import Tag, NavigableString

soup = BeautifulSoup("""
    <!DOCTYPE html>
    <html>
        <body>
            EXTRA TEXT
            <p>
            first <b>paragraph</b>
            <br>
            <br>
            second paragraph
            </p>
        </body>
    </html>
    """, "lxml")

tag = soup.select_one('body')

for el in tag.children:
    match el:
        case NavigableString():
            ...
        case Tag(name="p"):
            ...
        case Tag():
            ...

mypy example.py

Errors:

example.py:24: error: Expected type in class pattern; found "Any"
example.py:26: error: Expected type in class pattern; found "Any"
example.py:28: error: Expected type in class pattern; found "Any"
Found 3 errors in 1 file (checked 1 source file)

So, what does this error mean? And how can I fix it?


Solution

  • You can use TYPE_CHECKING to load classes that have the typing

    from typing import TYPE_CHECKING
    
    if TYPE_CHECKING:
    
        class NavigableString:
            ...
    
        class Tag:
            children: list[NavigableString | Tag]
            name: str
    
        class BeautifulSoup:
            def __init__(self, markup: str, features: str | None) -> None:
                ...
    
            def select_one(self, text: str) -> Tag:
                ...
    
    else:
        from bs4 import BeautifulSoup
        from bs4.element import Tag, NavigableString
    
    soup = BeautifulSoup(
        """
        <!DOCTYPE html>
        <html>
            <body>
                EXTRA TEXT
                <p>
                first <b>paragraph</b>
                <br>
                <br>
                second paragraph
                </p>
            </body>
        </html>
        """,
        "lxml",
    )
    
    tag = soup.select_one("body")
    
    for el in tag.children:
        match el:
            case NavigableString():
                ...
            case Tag(name="p"):
                ...
            case Tag():
                ...