-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Refactor database helper functions so they can be checked by mypy #14002
Comments
I have tried the above out. There were more places passing in Running mypy on 907041c (See https://github.com/matrix-org/synapse/commits/dmr/typing/run-interaction) gives me the following output. The first one looks like a mypy bug(?). but I think the rest are all either incorrect annotations or bugs.
|
Can we instead ban the use of async def runInteraction(
self,
desc: str,
func: Callable[..., R],
*,
db_autocommit: bool = False,
isolation_level: Optional[int] = None,
**kwargs: Any,
) -> R:
... Though that method might involve so many changes that its not worth it? |
As written, that annotation doesn't get you any extra type checking, because there's nothing linking I don't think one can have
(emphasis mine). |
Ah yeah, I meant to add the I'd be slightly surprised if we couldn't have keyword argument only stuff, but I've not checked. |
This issue contains notes on a type annotation problem I spent some time thinking about. Comments are welcome.
Background
In #13892 I made a mistake where I tried invoke a function
f
usingrunInteraction
but gave it the arguments for another functiong
with a different signature. (This is the diff that corrected it.) I was surprised that mypy didn't catch it, since we've got better coverage of the source code and we make more use of mypy.Problem
Annotating some of these DB helper functions with ParamSpec doesn't work. E.g. given
synapse/synapse/storage/database.py
Lines 883 to 890 in ad4c14e
and the place where we use
func
synapse/synapse/storage/database.py
Lines 966 to 969 in ad4c14e
the annotations to use would be
But these don't work:
Mypy's error message is crap here. I think what's going on here is buried in PEP 612:
There are some examples---I find it tough to follow---but in short, I think you can only have *P.args and **P.kwargs directly adjacent in a function signature. Anything after
*args
, likes
above, has to be a keyword-only argument. But what happens iffunc
accepts a keyword parameter calleds
too? Ambiguity and pain.For an simplified example, see here.
Proposal
If we want to have mypy check these helper functions, I think their last three arguments need to be
func,
*args
and**kwargs
; everything else needs to be a mandatory(?) position parameter beforefunc
. The downside of doing this is that every call site needs to explicitly list out a bunch of mandatory arguments which weren't mandatory before.new_transaction
is an example of such a function taking its arguments in this way:synapse/synapse/storage/database.py
Lines 611 to 621 in ad4c14e
(though its call sites are quite verbose).
One way we could avoid the verbosity is to provide "simple" and "advanced" versions of a function. Take
runInteraction
for example.synapse/synapse/storage/database.py
Lines 801 to 809 in ad4c14e
The majority of its call sites don't specify
db_autocommit
orisolation_level
values. Maybe we could split the function up intoBoth of these are in a form that I think mypy can meaningfully process, and the former avoids us repeatedly passing in
False, None
at the majority of call sites.The text was updated successfully, but these errors were encountered: