1

In implementation of an interop layer with several other languages I have run into the question of how to represent fixed and max-length sequences. While for Python it doesn't matter much the full type info needs to be available for the other languages. The user-facing API should look as follows:

@dataclass
class MyStruct:
    name: bounded_str[12]           # here 12 is a max length
    data: sequence[int8, 20]        # here 20 is the max length
    other_data: array[float32, 10]  # here 10 is a fixed length

Now I have no problem getting this to work with normal python. I let sequence and array generate Annotated types as follows:

class ArrayMeta(type):
    def __getitem__(cls, tup):
        if type(tup) != tuple or len(tup) != 2 or type(tup[1]) != int:
            return TypeError("An array takes two arguments: a subtype and a constant length.")
        return Annotated[Sequence[tup[0]], array(*tup)]


class array(metaclass=ArrayMeta):
    def __init__(self, subtype, length):
        self.subtype = subtype
        self.length = length

This leaves the dataclass with a perfectly acceptable Annotated[Sequence[subtype], ...] and I can inspect the annotation with get_type_hints and determine the 'true' type needed for interop, generating validators/serializers etc.

Now the problem comes in when we bring Mypy into the mix. Mypy doesn't recognize the array type as valid and that is fair enough. However, any of my attempts at making a valid version have been stumped so far, as Generic will not take a value types:

T = TypeVar('T')
V = TypeVar('V')

class MyArray(Protocol, Generic[T, V]):
    def __getitem__(self, key: int) -> T: ...
    def __len__(self):
        return V

a: MyArray[int, 5] = [0, 1, 2, 3, 4]
>>> TypeError: Parameters to generic types must be types. Got 5.

Is there a way to make Mypy happy about these sequence and array types?

Thijs Miedema
  • 53
  • 1
  • 5

2 Answers2

0

There's no "max length" check in mypy, that implies the collection is filled at runtime, so there's no way how to check this before that.

The only structure which can be defined with a fixed length is Tuple and you have to define each element, eg a tuple 4 ints in it would look like this:

from typing import Tuple
data: Tuple[int, int, int, int]
yedpodtrzitko
  • 9,035
  • 2
  • 40
  • 42
-2

You can use Literal[5], see typing.Literal:

A type that can be used to indicate to type checkers that the corresponding variable or function parameter has a value equivalent to the provided literal (or one of several literals).

  • 2
    `Literal[5]` means the value can be just and only the value, ie. int `5` in this example. OP wants a collection of certain length. – yedpodtrzitko May 18 '21 at 15:19