Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mypy: annotating a variable with a class type

I am having some trouble assigning the variables in a Python 3.6 class to a particular type--a Pathlib path. Following an example from link, I tried to create a TypeVar, but mypy is still throwing errors. I want to make sure that the class variables initialized in the __init__.py only receive a particular type at compile time. So this is just a check to make sure I don't inadvertently set a string or something else to these class variables.

Can anyone suggest the correct way to do this?

Here is some simple code.

import pathlib
from typing import Union, Dict, TypeVar, Type

Pathtype = TypeVar('Pathtype', bound=pathlib.Path)

class Request:

    def __init__(self, argsdict):

        self._dir_file1: Type[Pathtype] = argsdict['dir_file1']
        self._dir_file2: Type[Pathtype] = argsdict['dir_file2']

The error that I am getting is:

Request.py:13: error: Invalid type "Request.Pathtype"
Request.py:14: error: Invalid type "Request.Pathtype"
like image 773
krishnab Avatar asked Mar 12 '19 01:03

krishnab


2 Answers

Neither Type, TypeVar nor NewType are correct to use here. What you simply want to do is use Path itself:

from pathlib import Path

class Request:
    def __init__(self, argsdict):
        self._dir_file1: Path = argsdict['dir_file1']
        self._dir_file2: Path = argsdict['dir_file2']

If you annotate your argsdict as being of type Dict[str, Path], you can skip having to annotate your fields entirely: mypy will infer the correct type:

from typing import Dict
from pathlib import Path

class Request:
    def __init__(self, argsdict: Dict[str, Path]):
        self._dir_file1 = argsdict['dir_file1']
        self._dir_file2 = argsdict['dir_file2']

Here's a brief explanation of what the various type constructs you were attempting to use/was suggested to you actually do:

  1. TypeVar is used when you are trying to create a generic data structure or function. For example, take List[int], which represents a list containing ints. List[...] is an example of a generic data structure: it can be parameterized by any arbitrary type.

    You use TypeVar as a way of adding "parameterizable holes" if you decide you want to create your own generic data structure.

    It's also possible to use TypeVars when writing generic functions. For example, suppose you want to declare that you have some function that can accept a value of any type -- but that function is guaranteed to return a value of the exact same type. You can express ideas like these using TypeVars.

  2. The Type[...] annotation is used to indicate that some expression must be the type of a type. For example, to declare that some variable must hold an int, we would write my_var: int = 4. But what if we want to write something like my_var = int? What sort of type hint could we give that variable? In this case, we could do my_var: Type[int] = int.

  3. NewType basically lets you "pretend" that you're taking some type and making a subclass of it -- but without requiring you to actually subclass anything at runtime. If you're careful, you can take advantage of this feature to help catch bugs where you mix different "kinds" of strings or ints or whatever -- e.g. passing in a string representing HTML into a function expecting a string representing SQL.

like image 185
Michael0x2a Avatar answered Oct 23 '22 21:10

Michael0x2a


Replace TypeVar with NewType and remove the Type[] modifier.

like image 44
Daniel Severo Avatar answered Oct 23 '22 22:10

Daniel Severo