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

[Enhancement] Kwargs TypeChecking Fails When Using **dict #242

Closed
stevenjackson121 opened this issue Mar 5, 2020 · 2 comments
Closed

[Enhancement] Kwargs TypeChecking Fails When Using **dict #242

stevenjackson121 opened this issue Mar 5, 2020 · 2 comments
Assignees

Comments

@stevenjackson121
Copy link

MyPy doesn't handle this either, but it might be a smaller lift to add support in pyre because (superficially anyways) it seems related to ParameterSpecification and https://www.python.org/dev/peps/pep-0612/.

The issue is that there's no way to annotate the params dictonary such that errors will be raised on line 19 (invoke(**params)) if and only if they'd be raised on line 11 (invoke(FunctionName=<...>)

from typing import Mapping

import boto3
from mypy_boto3.lambda_ import LambdaClient
import logging

from typing_extensions import TypedDict, Literal, Final

lambda_client: LambdaClient = boto3.client("lambda")

lambda_client.invoke(FunctionName="foobar", InvocationType="RequestResponse", Payload=b"")

params = {
    "FunctionName": "foobar",
    "InvocationType": "RequestResponse",
    "Payload": b"",
}
try:
    lambda_client.invoke(**params)
except:
    logging.error(f"Failed to invoke lambda with parameters {params}")

I know ParameterSpecification is currently only usable in function definitions, but it would be wonderful to either broaden the scope slightly or to have a related ArgumentSpecification that borrows heavily on the design and would enable syntax like InvokeArgs = ParameterSpecification("InvokeArgs", lambda_client.invoke) which could then be used like:

InvokeArgs = ArgumentSpecification("InvokeArgs", lambda_client.invoke)
params:InvokeArgs.kwargs = {
    "FunctionName": "foobar",
    "InvocationType": "RequestResponse",
    "Payload": b"",
}
try:
    lambda_client.invoke(**params)
except:
    logging.error(f"Failed to invoke lambda with parameters {params}")

This may be overkill for the situation where you're only handling kwargs in a dictionary (a workaround like I asked for in mypy might be easier, which is using a Final[frozendict] annotation to let the typechecker know the dictionary will not change at all before being used as kwargs and some special case rules), but I think a solution patterned after ParameterSpecification might be cleaner for related use cases.

For example, python now has positional only arguments. If we needed to pass in both positional and keyword arguments, we could use something like:

InvokeArgs = ArgumentSpecification("InvokeArgs", lambda_client.invoke)
positional_args:InvokeArgs.args = ("foobar",)
params:InvokeArgs.kwargs = {
    "InvocationType": "RequestResponse",
    "Payload": b"",
}
try:
    lambda_client.invoke(*positional_args, **params)
except:
    logging.error(f"Failed to invoke lambda with parameters {positional_args} and {params}")

I'll admit I didn't fully understand the ParameterSpecification Pep, although I did try to read all of it. They seem related to me as a user, but I know that doesn't necessarily mean that it would be a related implementation.

@MaggieMoss
Copy link
Contributor

cc: @mrkmndz do you have some context here?

@yangdanny97 yangdanny97 self-assigned this Jul 25, 2024
@yangdanny97
Copy link
Contributor

Precise typechecking for heterogeneous kwargs should be easier with PEP 692 (https://peps.python.org/pep-0692/) which was recently added to Pyre and will be available in the next release.

But for the first example with a regular dictionary, Pyre will typecheck it correctly if you use the actual literal inside the **.

For example

 lambda_client.invoke(**{
    "FunctionName": "foobar",
    "InvocationType": "RequestResponse",
    "Payload": b"",
})

If the issue persists after the next release, please reopen

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

3 participants