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

Typing issue: CreateParams for StripeObjects should allow for Optional values #1287

Open
tetsujiono opened this issue Apr 1, 2024 · 3 comments

Comments

@tetsujiono
Copy link

Describe the bug

Many CreateParams attributes on StripeObjects are defined to be non-optional. This means that if that keyword argument is passed into the .create( function, it must be a non-null value (that also adheres to the defined typing).
However, the API supports passing null values on many of these attributes and that seems to contextually make sense.

One example is the promotion_code attribute on the Subscription CreateParams class.

The following call succeeds without issue:

import stripe

api_key = "***"  # loaded from env
api_version = "2023-10-16"  # At the time of writing this ticket, I am using this API version

customer_id = "cus_xxx"  # use any customer_id with a payment source in your own env
price_id = "price_xxx". # use an existing active price on a product in your stripe env
promotion_code = None

subscription = stripe.Subscription.create(
    customer=customer_id,
    items=[{"price": price_id}],
    payment_behavior="error_if_incomplete",
    promotion_code=promotion_code,
)

however, mypy will find issues with the fact that promotion_code is None and prefers it not to be passed at all.

The workaround at this current moment (other than ignoring the type issue) would be to add a conditional

if promotion_code:
    subscription = stripe.Subscription.create(
        customer=customer_id,
        items=[{"price": price_id}],
        payment_behavior="error_if_incomplete",
        promotion_code=promotion_code,
    )
else:
    subscription = stripe.Subscription.create(
        customer=customer_id,
        items=[{"price": price_id}],
        payment_behavior="error_if_incomplete",
    )

however, this is quite tedious and becomes unruly if you have more than one attribute you need to check (a permutation of checks will occur)

To Reproduce

  1. Write the follow or similar code
import stripe

api_key = "***"  # loaded from env
api_version = "2023-10-16"  # At the time of writing this ticket, I am using this API version

customer_id = "cus_xxx"  # use any customer_id with a payment source in your own env
price_id = "price_xxx". # use an existing active price on a product in your stripe env
promotion_code = None

subscription = stripe.Subscription.create(
    customer=customer_id,
    items=[{"price": price_id}],
    payment_behavior="error_if_incomplete",
    promotion_code=promotion_code,
)
  1. Run mypy checker
  2. You will see the following error: error: Argument "promotion_code" to "create" of "Subscription" has incompatible type "str | None"; expected "str" [arg-type]

Expected behavior

Using this line as an example, any nullable CreateParams attribute should be noted as Optional

Suggested Solution

promotion_code: NotRequired["str|None"]

^This solution most similarly reflects the way that Optional is implemented on the base RequestOptions class

Code snippets

Sample attribute to modify: https://github.com/stripe/stripe-python/blob/1657f036266412b7ef38d46c77f1b30f5455d83b/stripe/_subscription.py#L594
Existing way Optional is implemented: https://github.com/stripe/stripe-python/blob/1657f036266412b7ef38d46c77f1b30f5455d83b/stripe/_request_options.py#L7

OS

macOS

Language version

Python 3.11.3

Library version

stripe-python v8.9.0

API version

2023-10-16

Additional context

No response

@helenye-stripe
Copy link
Contributor

helenye-stripe commented Apr 3, 2024

Hi @tetsujiono! Thanks for pointing this out, we'll investigate whether or not to add this for QoL improvement. In the meantime, this is a small improvement:

subscription_params : stripe.Subscription.CreateParams = {
    "customer": customer_id,
    "items": [{"price": price_id}],
    "payment_behavior": "error_if_incomplete",
}
if promotion_code:
    subscription_params["promotion_code"] = promotion_code
subscription = stripe.Subscription.create(
    **subscription_params
)

@aahung
Copy link

aahung commented Apr 8, 2024

BTW, somehow it only complaints when running in ghaction, but not on my Mac with latest mypy and same stripe version (8.10.0)

@tetsujiono
Copy link
Author

BTW, somehow it only complaints when running in ghaction, but not on my Mac with latest mypy and same stripe version (8.10.0)

Interesting, for me it's affecting both my local mypy run and the remote mypy workflow step.

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

No branches or pull requests

3 participants