Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,12 @@ jobs:
python_version:
# The last ~5 versions, once we're on schedule
# https://docs.stripe.com/sdks/versioning?lang=python#stripe-sdk-language-version-support-policy
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
- "pypy-3.7"
- "pypy-3.8"
- "pypy-3.9"
- "pypy-3.10"
- "pypy-3.11"
Expand All @@ -117,8 +113,7 @@ jobs:
name: Publish
if: >-
((github.event_name == 'workflow_dispatch') || (github.event_name == 'push')) &&
startsWith(github.ref, 'refs/tags/v') &&
endsWith(github.actor, '-stripe')
startsWith(github.ref, 'refs/tags/v')
needs: [build, test, lint]
runs-on: "ubuntu-24.04"
permissions:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ python -m pip install .

### Requirements

Per our [Language Version Support Policy](https://docs.stripe.com/sdks/versioning?lang=python#stripe-sdk-language-version-support-policy), we currently support **Python 3.7+**.
Per our [Language Version Support Policy](https://docs.stripe.com/sdks/versioning?lang=python#stripe-sdk-language-version-support-policy), we currently support **Python 3.9+**.

Support for Python 3.7 and 3.8 is deprecated and will be removed in an upcoming major version. Read more and see the full schedule in the docs: https://docs.stripe.com/sdks/versioning?lang=python#stripe-sdk-language-version-support-policy
Read more and see the full schedule in the docs: https://docs.stripe.com/sdks/versioning?lang=python#stripe-sdk-language-version-support-policy

#### Extended Support

Expand Down
10 changes: 3 additions & 7 deletions flake8_stripe/flake8_stripe.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,12 @@ class TypingImportsChecker:
version = "0.1.0"

# Rules:
# * typing_extensions v4.1.1 is the latest that supports Python 3.6
# so don't depend on anything from a more recent version than that.
#
# If we need something newer, maybe we can provide it for users on
# newer versions with a conditional import, but we'll cross that
# bridge when we come to it.

# If a symbol exists in both `typing` and `typing_extensions`, which
# should you use? Prefer `typing_extensions` if the symbol available there.
# in 4.1.1. In typing_extensions 4.7.0, `typing_extensions` started re-exporting
# EVERYTHING from `typing` but this is not the case in v4.1.1.

# now that we're into modern typing_extensions versions, we should probably prefer that over built-in typing _unless_ all of our `typing `needs are present in all supported Python versions. In that case, we could drop `typing_extensions`. See: https://go/j/DEVSDK-3046
allowed_typing_extensions_imports = [
"Literal",
"NoReturn",
Expand All @@ -36,6 +31,7 @@ class TypingImportsChecker:
"Awaitable",
"Never",
"override",
"deprecated",
]

allowed_typing_imports = [
Expand Down
10 changes: 4 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description = "Python bindings for the Stripe API"
authors = [{ name = "Stripe", email = "support@stripe.com" }]
license-files = ["LICENSE"]
keywords = ["stripe", "api", "payments"]
requires-python = ">=3.7"
requires-python = ">=3.9"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
Expand All @@ -27,11 +27,9 @@ classifiers = [
]

dependencies = [
"typing_extensions <= 4.2.0, > 3.7.2; python_version < '3.7'",
# The best typing support comes from 4.5.0+ but we can support down to
# 3.7.2 without throwing exceptions.
"typing_extensions >= 4.5.0; python_version >= '3.7'",
"requests >= 2.20; python_version >= '3.0'",
# this is the version where everything started getting re-exported, so it's a convenient backstop
"typing_extensions >= 4.7.0",
"requests >= 2.20",
]

[project.optional-dependencies]
Expand Down
5 changes: 2 additions & 3 deletions stripe/_api_resource.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from typing_extensions import Literal, Self
from typing_extensions import Literal, Self, deprecated

from stripe._error import InvalidRequestError
from stripe._stripe_object import StripeObject
from stripe._request_options import extract_options_from_dict
from stripe._api_mode import ApiMode
from stripe._base_address import BaseAddress
from stripe._api_requestor import _APIRequestor
from stripe import _util
from urllib.parse import quote_plus
from typing import (
Any,
Expand All @@ -26,7 +25,7 @@ class APIResource(StripeObject, Generic[T]):
OBJECT_NAME: ClassVar[str]

@classmethod
@_util.deprecated(
@deprecated(
"This method is deprecated and will be removed in a future version of stripe-python. Child classes of APIResource should define their own `retrieve` and use APIResource._request directly."
)
def retrieve(cls, id, **params) -> T:
Expand Down
3 changes: 2 additions & 1 deletion stripe/_custom_method.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from typing import Optional
from stripe import _util
from urllib.parse import quote_plus
from typing_extensions import deprecated


# TODO(major): 1704.
@_util.deprecated(
@deprecated(
"the custom_method class decorator will be removed in a future version of stripe-python. Define custom methods directly and use StripeObject._static_request within."
)
def custom_method(
Expand Down
3 changes: 1 addition & 2 deletions stripe/_exchange_rate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
# File generated from our OpenAPI spec
from stripe._list_object import ListObject
from stripe._listable_api_resource import ListableAPIResource
from stripe._util import deprecated
from typing import ClassVar, Dict
from typing_extensions import Literal, Unpack, TYPE_CHECKING
from typing_extensions import Literal, Unpack, deprecated, TYPE_CHECKING

if TYPE_CHECKING:
from stripe.params._exchange_rate_list_params import ExchangeRateListParams
Expand Down
5 changes: 2 additions & 3 deletions stripe/_search_result_object.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pyright: strict
from typing_extensions import Self, Unpack
from typing_extensions import Self, Unpack, deprecated
from typing import (
Generic,
List,
Expand All @@ -16,7 +16,6 @@
_APIRequestor, # pyright: ignore[reportPrivateUsage]
)
from stripe._stripe_object import StripeObject
from stripe import _util
import warnings
from stripe._request_options import RequestOptions, extract_options_from_dict
from stripe._any_iterator import AnyIterator
Expand Down Expand Up @@ -45,7 +44,7 @@ def _get_url_for_search(self) -> str:
)
return url

@_util.deprecated(
@deprecated(
"This will be removed in a future version of stripe-python. Please call the `search` method on the corresponding resource directly, instead of the generic search on SearchResultObject."
)
def search(self, **params: Mapping[str, Any]) -> Self:
Expand Down
4 changes: 2 additions & 2 deletions stripe/_stripe_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
from stripe._api_version import _ApiVersion
from stripe._stripe_object import StripeObject
from stripe._stripe_response import StripeResponse
from stripe._util import _convert_to_stripe_object, get_api_mode, deprecated # noqa: F401
from stripe._util import _convert_to_stripe_object, get_api_mode
from stripe._webhook import Webhook, WebhookSignature
from stripe._event import Event
from stripe.v2.core._event import EventNotification

from typing import Any, Dict, Optional, Union, cast
from typing_extensions import TYPE_CHECKING
from typing_extensions import TYPE_CHECKING, deprecated

if TYPE_CHECKING:
from stripe._stripe_context import StripeContext
Expand Down
6 changes: 2 additions & 4 deletions stripe/_stripe_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import datetime
import json
from copy import deepcopy
from typing_extensions import TYPE_CHECKING, Type, Literal, Self
from typing_extensions import TYPE_CHECKING, Type, Literal, Self, deprecated
from typing import (
Any,
Dict,
Expand Down Expand Up @@ -402,9 +402,7 @@ def _refresh_from(

self._previous = values

@_util.deprecated(
"This will be removed in a future version of stripe-python."
)
@deprecated("This will be removed in a future version of stripe-python.")
def request(
self,
method: Literal["get", "post", "delete"],
Expand Down
3 changes: 2 additions & 1 deletion stripe/_updateable_api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from urllib.parse import quote_plus
from typing import TypeVar, cast
from stripe._stripe_object import StripeObject
from typing_extensions import deprecated

T = TypeVar("T", bound=StripeObject)

Expand All @@ -13,7 +14,7 @@ def modify(cls, sid, **params) -> T:
url = "%s/%s" % (cls.class_url(), quote_plus(sid))
return cast(T, cls._static_request("post", url, params=params))

@_util.deprecated(
@deprecated(
"The `save` method is deprecated and will be removed in a future major version of the library. Use the class method `modify` on the resource instead."
)
def save(self, idempotency_key=None):
Expand Down
62 changes: 0 additions & 62 deletions stripe/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
import sys
import os
import re
import warnings

from stripe._api_mode import ApiMode

from urllib.parse import quote_plus

from typing_extensions import Type, TYPE_CHECKING
from typing import (
Callable,
TypeVar,
Union,
overload,
Expand All @@ -23,7 +21,6 @@
Optional,
Mapping,
)
import typing_extensions


# Used for global variables
Expand All @@ -38,65 +35,6 @@

logger: logging.Logger = logging.getLogger("stripe")

if TYPE_CHECKING:
deprecated = typing_extensions.deprecated
else:
_T = TypeVar("_T")

# Copied from python/typing_extensions, as this was added in typing_extensions 4.5.0 which is incompatible with
# python 3.6. We still need `deprecated = typing_extensions.deprecated` in addition to this fallback, as
# IDEs (pylance) specially detect references to symbols defined in `typing_extensions`
#
# https://github.com/python/typing_extensions/blob/5d20e9eed31de88667542ba5a6f66e6dc439b681/src/typing_extensions.py#L2289-L2370
def deprecated(
__msg: str,
*,
category: Optional[Type[Warning]] = DeprecationWarning,
stacklevel: int = 1,
) -> Callable[[_T], _T]:
def decorator(__arg: _T) -> _T:
if category is None:
__arg.__deprecated__ = __msg
return __arg
elif isinstance(__arg, type):
original_new = __arg.__new__
has_init = __arg.__init__ is not object.__init__

@functools.wraps(original_new)
def __new__(cls, *args, **kwargs):
warnings.warn(
__msg, category=category, stacklevel=stacklevel + 1
)
if original_new is not object.__new__:
return original_new(cls, *args, **kwargs)
# Mirrors a similar check in object.__new__.
elif not has_init and (args or kwargs):
raise TypeError(f"{cls.__name__}() takes no arguments")
else:
return original_new(cls)

__arg.__new__ = staticmethod(__new__)
__arg.__deprecated__ = __new__.__deprecated__ = __msg
return __arg
elif callable(__arg):

@functools.wraps(__arg)
def wrapper(*args, **kwargs):
warnings.warn(
__msg, category=category, stacklevel=stacklevel + 1
)
return __arg(*args, **kwargs)

__arg.__deprecated__ = wrapper.__deprecated__ = __msg
return wrapper
else:
raise TypeError(
"@deprecated decorator with non-None category must be applied to "
f"a class or callable, not {__arg!r}"
)

return decorator


def is_appengine_dev():
return "APPENGINE_RUNTIME" in os.environ and "Dev" in os.environ.get(
Expand Down
Loading