Created
April 18, 2020 15:37
-
-
Save pauleveritt/6cf726b72422e89d4e6e5a3fc1036e12 to your computer and use it in GitHub Desktop.
Protocols and dataclass-based components
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
https://github.com/python/mypy/issues/4717#issuecomment-454609539 | |
Hi Glyph, thanks for reading. This is going to take a while. | |
I'm interested in pluggable systems. Specifically a better Sphinx rendering | |
layer, which I've spent a lot of time on. Recently I've worked on Michael | |
Merickel's wired: | |
https://wired.readthedocs.io/ | |
Specifically I wrote the dataclass-based injector, which uses dataclass | |
field metadata to give instructions to the injector. | |
wired makes it easy to register multiple implementations for a class or | |
interface. But classes kind of suck, because the "interface" is an | |
implementation (class). However interfaces still have poor tooling | |
support, even with mypy-zope. | |
(I won't belabor the point about wired, DI, and the React-style component | |
stuff I'm working on. Not necessary to this.) | |
I'm interested in PEP 544 protocols because they have a chance to be more | |
adopted than interfaces. In the example | |
""" | |
from dataclasses import dataclass | |
# This starts the part that is in framework space, so civilians don't | |
# have to see it, their tooling, e.g. IDE autocomplete, just starts | |
# working. | |
from typing import Callable, Type, TypeVar | |
from typing_extensions import Protocol | |
protocol = TypeVar("protocol") | |
# In wired, this decorator also handles a registration in the registry, | |
# as well as a constructor which sniffs the dataclass fields to do the | |
# DI. | |
def component(c: Callable[[], protocol]) -> Callable[[Type[protocol]], Type[protocol]]: | |
def decor(input_value: Type[protocol]) -> Type[protocol]: | |
return input_value | |
return decor | |
# /end framework space | |
# This is done by the creator of some sexy library of ready-to-go | |
# components. The average consumer doesn't see this. | |
class Heading(Protocol): | |
x: int | |
@component(Heading) | |
@dataclass | |
class GoodHeading: | |
x: int | |
other: str | |
@component(Heading) | |
@dataclass | |
class BadHeading: | |
y: int | |
# /end component library author consumer | |
# I will leave out what the end-user will see, as it is specific to | |
# the work I'm doing. | |
if __name__ == '__main__': | |
good = GoodHeading(x=3, other='xyz') | |
bad = BadHeading(y=3) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment