Description
I am interested in a typed version of parsy and would find it useful, the effort in typed-parsy
so far is a nice improvement. I read this blog post on this topic and had an idea for an alternative to seq
and combine
for the *args synatax (not **kwargs unfortunately). I have something working with Pyright (I haven't tried mypy) - see the linked PR below
By using tuple type unpacking from PEP 646, it's possible to add type information to both of these functions which enable creating a sequence of parsers with a flat tuple result type:
- A function which joins the results of two parsers into a tuple:
Parser[A], Parser[B] -> Parser[Tuple[A, B]]
. I've called thisjoin
for now. (This one doesn't need tuple type unpacking - it is just theParser.__and__
function.) - A function which takes a tuple result and appends a second parser's result to the end:
Parser[Tuple[A, B]], Parser[C] -> Parser[Tuple[A, B, C]]
. I've called thisappend
for now.
And it's also possible to create a combine
method which expects function whose arguments have the same type as the parser's result tuple. The type signature is like this:
from typing import TypeVar
from typing_extensions import TypeVarTuple, Unpack
OUT2 = TypeVar("OUT2")
OUT_T = TypeVarTuple("OUT_T")
# ... in the Parser class
def combine(self: Parser[Tuple[Unpack[OUT_T]]], combine_fn: Callable[[Unpack[OUT_T]], OUT2]) -> Parser[OUT2]:
...
The benefit is that Pyright will compare the Parser result type with the combine_fn
arguments and show an issue when they don't match. It also doesn't need the extra step of indexing tuples in a lambda function as shown in the blog post.
I've made these changes in a fork and they seem to be working nicely with Pyright - it's showing me mismatches between a sequence of parsers' results and a function's arguments with useful messages.
For example, in the screenshot below, the demo
function expects its first argument to have a type of str
. A parser of type Parser[int, str, bool]
can be made with the join
and append
functions. Then where combine
is called, VSCode shows that there's a problem - the parser result type doesn't match demo
's parameter type in the first argument.