Python typing for class that having methods from decorator

Question:

The dataclasses-json allows code such as:

from dataclasses import dataclass
from dataclasses_json import dataclass_json

@dataclass_json
@dataclass
class Person:
    name: str

lidatong = Person('lidatong')

# Encoding to JSON
lidatong.to_json()  # '{"name": "lidatong"}'

# Decoding from JSON
Person.from_json('{"name": "lidatong"}')  # Person(name='lidatong')

How could I use typing to annotate

  1. a function which takes an instance whose class has @dataclass_json applied, such that the existence of the to_json instance method is known to the type checker, and:
  2. a function which takes a class having @dataclass_json applied, such that the from_json class method is known to the type checker?
Asked By: davetapley

||

Answers:

Sounds like a good use for typing.Protocol and typing.Self (new in Python 3.11):

from typing import Protocol

class JsonAble(Protocol):
    def to_json(self) -> str: ...

    @classmethod
    def from_json(cls, json_text: str) -> Self: ...

You can then type a function as taking an argument of type JsonAble to indicate that it’s an object that implements those methods.

If you’re not on Python 3.11, there are workarounds involving typing.TypeVar; see PEP 673 for details.

Answered By: Samwise