Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
pauleveritt opened this issue Jan 10, 2024 · 4 comments
Closed

Comments

@pauleveritt
Copy link
Collaborator

Jim and I were chatting about a change:

  • Rename Thunk to Interpolation to focus its name on its use
  • Rename Chunk to Decoded for the same reason
  • Do both as protocols:
    • Make the actual implementation choice less important during PEP discussion
    • Ease tag function test writing by constructing inputs without going through tag string machinery

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
Copy link
Collaborator

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
Copy link
Collaborator Author

@gvanrossum You ok with defining them as protocols?

@gvanrossum
Copy link
Collaborator

@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
Copy link
Collaborator Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants