How to annotate a variable of an existing object? (working with mypy)

391 views Asked by At
def get_source(import_name: str) -> Optional[str]:
    spec = get_spec(import_name)
    # Now, here. The spec.loader might be one of several values.
    # But I *know* that it is gonna be importlib.machinery.SourceFileloader
    # I need to typecast the attribute of the spec.loader into the above
    if spec and spec.loader.path.endswith('.py'):
        return spec.loader.get_data(spec.loader.path).decode("utf-8")
    return None


def get_spec(import_name: str) -> importlib.machinery.ModuleSpec:
    try:
        return importlib.util.find_spec(import_name)
    except (ImportError, AttributeError, TypeError, ValueError):
        return None

Apparently PEP526 allows what I'm trying to do with the most basic syntax imaginable

obj.attr: annotation

However apparently type checkers do not have to support this syntax as far as I can tell from Rossum's comment. And mypy gives the error Type cannot be declared in assignment to non-self attribute.

Now, according to another issue I found on github on typeshed, you can do asserts to let mypy know the type that the object. Instead of typehitting.

assert isinstance(obj.attr, annotation)

However this, to me, feels wrong. I'm trying to use typing features if possible, and the project I'm trying to contribute uses mypy as their type checker.

The assert version that works but makes me hate myself is:

def get_source(import_name: str) -> Optional[str]:
    spec = get_spec(import_name)
    assert isinstance(spec.loader, importlib.machinery.SourceFileLoader)
    assert isinstance(spec.loader.path, str)
    if spec and spec.loader.path.endswith('.py'):
        return spec.loader.get_data(spec.loader.path).decode("utf-8")
    return None

Countless typeshed and mypy issues I've read didn't help, so I'm here.

0

There are 0 answers