jimbaker / tagstr

This repo contains an issue tracker, examples, and early work related to PEP 999: Tag Strings
51 stars 6 forks source link

PROPOSAL: Thunk and Chunk types to Interpolation and Decoded protocols #41

Closed pauleveritt closed 3 months ago

pauleveritt commented 8 months ago

Jim and I were chatting about a change:

Jim re-read previous discussions, made a couple of passes through it, and proposes the following code.

from typing import Any, Callable, Literal, NamedTuple, Protocol

class DecodedConcrete(str):
    _raw: str

    def __new__(cls, raw: str):
        decoded = raw.encode('utf-8').decode('unicode-escape')
        if decoded == raw:
            decoded = raw
        chunk = super().__new__(cls, decoded)
        chunk._raw = raw
        return chunk

    @property
    def raw(self):
        return self._raw

class InterpolationConcrete(NamedTuple):
    getvalue: Callable[[], Any]
    expr: str
    conv: Literal['a', 'r', 's'] | None = None
    formatspec: str | None = None

class Interpolation(Protocol):
    def __len__(self):
        ...

    def __getitem__(self, index: int):
        ...

    @property
    def getvalue(self) -> Callable[[], Any]:
        ...

    @property
    def expr(self) -> str:
        ...

    @property
    def conv(self) -> Literal['a', 'r', 's'] | None:
        ...

    @property
    def formatspec(self) -> str | None:
        ...

class Decoded(Protocol):
    def __str__(self) -> str:
        ...

    @property
    def raw(self) -> str:
        ...

class TagFunction(Protocol):
    def __call__(self, *args: Interpolation | Decoded) -> Any:
        ...

def f(i: Interpolation) -> Any:
    return i.getvalue()

def g(s: Decoded) -> str:
    return s.raw

y = InterpolationConcrete(lambda: 42, '42', None, None)
print(f'{f(y)=}')

z = DecodedConcrete(r'raw\t\t')
print(f'{z.raw=}')

def mytag(*args: Interpolation | Decoded) -> str:
    return 'foo'

tag: TagFunction = mytag
gvanrossum commented 7 months ago

Sorry for the slow response. That looks good to me. Agreed that Thunk and Chunk are probably better as names for children's cartoon characters than standard Python types! :-)

pauleveritt commented 7 months ago

@gvanrossum You ok with defining them as protocols?

gvanrossum commented 7 months ago

@gvanrossum You ok with defining them as protocols?

Totally. That's the spirit of duck typing. (Not that I'm about to dive back into the implementation for now. :-)

pauleveritt commented 3 months ago

Closing as this has been woven into the in-progress PEP update.