Skip to content

Commit

Permalink
Merge branch 'beta' into richardm-async-wip
Browse files Browse the repository at this point in the history
  • Loading branch information
richardm-stripe committed Dec 12, 2023
2 parents 288a34a + f6747ea commit 9f4273d
Show file tree
Hide file tree
Showing 18 changed files with 229 additions and 54 deletions.
4 changes: 4 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ per-file-ignores =
stripe/oauth_error.py: IMP102
# setup.py is required for tooling
setup.py: IMP102
# should not raise a deprecation warning since it needs
# to be imported early in `stripe/__init__.py` to avoid
# a name conflict
stripe/app_info.py: IMP102

[flake8:local-plugins]
extension =
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
* [#1163](https://github.com/stripe/stripe-python/pull/1163) Update generated code for beta
* Add support for `retrieve` method on resource `FinancialConnections.Transaction`

## 7.8.2 - 2023-12-11
* [#1168](https://github.com/stripe/stripe-python/pull/1168) Do not raise a DeprecationWarning in `stripe.app_info`

## 7.8.1 - 2023-12-08
* [#1159](https://github.com/stripe/stripe-python/pull/1159) Fix __getattr__ to raise AttributeError rather than returning None. This fixes a regression in 7.8.0 that caused `stripe.checkout`/`stripe.issuing` etc. to return `None`.
* [#1157](https://github.com/stripe/stripe-python/pull/1157) Add missing explicit reexport for `OAuth`, `Webhook`, `WebhookSignature`
Expand Down
5 changes: 3 additions & 2 deletions stripe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
# Configuration variables
from stripe._api_version import _ApiVersion

# We must import the app_info module eagerly before defining the app_info global
# otherwise the late import will overwrite the global
# We must import the app_info module early to populate it into
# `sys.modules`; otherwise doing `import stripe.app_info` will end up
# importing that module, and not the global `AppInfo` name from below.
import stripe.app_info
from stripe._app_info import AppInfo as AppInfo
from stripe._version import VERSION as VERSION
Expand Down
9 changes: 8 additions & 1 deletion stripe/_api_requestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,14 @@ def __init__(
self._client_async = stripe.default_http_client_async

@classmethod
@_util.deprecated(
"This method is internal to stripe-python and the public interface will be removed in a future stripe-python version"
)
def format_app_info(cls, info):
return cls._format_app_info(info)

@classmethod
def _format_app_info(cls, info):
str = info["name"]
if info["version"]:
str += "/%s" % (info["version"],)
Expand Down Expand Up @@ -319,7 +326,7 @@ def specific_oauth_error(self, rbody, rcode, resp, rheaders, error_code):
def request_headers(self, api_key, method, api_mode) -> Dict[str, str]:
user_agent = "Stripe/v1 PythonBindings/%s" % (_version.VERSION,)
if stripe.app_info:
user_agent += " " + self.format_app_info(stripe.app_info)
user_agent += " " + self._format_app_info(stripe.app_info)

ua = {
"bindings_version": _version.VERSION,
Expand Down
4 changes: 4 additions & 0 deletions stripe/_api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
)
from stripe._api_requestor import APIRequestor
from stripe._stripe_object import StripeObject
from stripe import _util
from urllib.parse import quote_plus
from typing import (
Any,
Expand All @@ -28,6 +29,9 @@ class APIResource(StripeObject, Generic[T]):
OBJECT_NAME: ClassVar[str]

@classmethod
@_util.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, api_key=None, **params) -> T:
instance = cls(id, api_key, **params)
instance.refresh()
Expand Down
4 changes: 4 additions & 0 deletions stripe/_custom_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from urllib.parse import quote_plus


# TODO(major): 1704.
@_util.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(
name: str,
http_verb: str,
Expand Down
13 changes: 12 additions & 1 deletion stripe/_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import stripe # noqa: IMP101
from stripe._error_object import ErrorObject

from stripe import _util
import warnings


class StripeError(Exception):
_message: Optional[str]
Expand Down Expand Up @@ -43,7 +46,7 @@ def __init__(
self.headers = headers or {}
self.code = code
self.request_id = self.headers.get("request-id", None)
self.error = self.construct_error_object()
self.error = self._construct_error_object()

def __str__(self):
msg = self._message or "<empty message>"
Expand All @@ -68,6 +71,9 @@ def __repr__(self):
self.request_id,
)

@_util.deprecated(
"For internal stripe-python use only. The public interface will be removed in a future version."
)
def construct_error_object(self) -> Optional[ErrorObject]:
if (
self.json_body is None
Expand All @@ -81,6 +87,11 @@ def construct_error_object(self) -> Optional[ErrorObject]:
self.json_body["error"], stripe.api_key
)

def _construct_error_object(self):
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
return self.construct_error_object()


class APIError(StripeError):
pass
Expand Down
36 changes: 29 additions & 7 deletions stripe/_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

try:
import requests
from requests import Session
except ImportError:
requests = None
else:
Expand Down Expand Up @@ -416,8 +417,16 @@ async def close(self):
class RequestsClient(HTTPClient):
name = "requests"

def __init__(self, timeout=80, session=None, **kwargs):
super(RequestsClient, self).__init__(**kwargs)
def __init__(
self,
timeout: int = 80,
session: Optional["Session"] = None,
verify_ssl_certs: bool = True,
proxy: Optional[Union[str, HTTPClient._Proxy]] = None,
):
super(RequestsClient, self).__init__(
verify_ssl_certs=verify_ssl_certs, proxy=proxy
)
self._session = session
self._timeout = timeout

Expand Down Expand Up @@ -549,7 +558,12 @@ def close(self):
class UrlFetchClient(HTTPClient):
name = "urlfetch"

def __init__(self, verify_ssl_certs=True, proxy=None, deadline=55):
def __init__(
self,
verify_ssl_certs: bool = True,
proxy: Optional[HTTPClient._Proxy] = None,
deadline: int = 55,
):
super(UrlFetchClient, self).__init__(
verify_ssl_certs=verify_ssl_certs, proxy=proxy
)
Expand Down Expand Up @@ -641,7 +655,11 @@ class _ParsedProxy(TypedDict, total=False):
name = "pycurl"
_parsed_proxy: Optional[_ParsedProxy]

def __init__(self, verify_ssl_certs=True, proxy=None):
def __init__(
self,
verify_ssl_certs: bool = True,
proxy: Optional[HTTPClient._Proxy] = None,
):
super(PycurlClient, self).__init__(
verify_ssl_certs=verify_ssl_certs, proxy=proxy
)
Expand Down Expand Up @@ -793,7 +811,11 @@ def close(self):
class Urllib2Client(HTTPClient):
name = "urllib.request"

def __init__(self, verify_ssl_certs=True, proxy=None):
def __init__(
self,
verify_ssl_certs: bool = True,
proxy: Optional[HTTPClient._Proxy] = None,
):
super(Urllib2Client, self).__init__(
verify_ssl_certs=verify_ssl_certs, proxy=proxy
)
Expand All @@ -802,10 +824,10 @@ def __init__(self, verify_ssl_certs=True, proxy=None):
if self._proxy:
# We have to cast _Proxy to Dict[str, str] because pyright is not smart enough to
# realize that all the value types are str.
proxy = urllibrequest.ProxyHandler(
proxy_handler = urllibrequest.ProxyHandler(
cast(Dict[str, str], self._proxy)
)
self._opener = urllibrequest.build_opener(proxy)
self._opener = urllibrequest.build_opener(proxy_handler)

def request(self, method, url, headers, post_data=None):
return self._request_internal(
Expand Down
52 changes: 47 additions & 5 deletions stripe/_list_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
cast,
Mapping,
)
from stripe import _util
from stripe._stripe_object import StripeObject

from urllib.parse import quote_plus
import warnings

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

Expand All @@ -26,6 +28,25 @@ class ListObject(StripeObject, Generic[T]):
has_more: bool
url: str

def _list(
self,
api_key: Optional[str] = None,
stripe_version: Optional[str] = None,
stripe_account: Optional[str] = None,
**params: Mapping[str, Any]
) -> Self:
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=DeprecationWarning)
return self.list( # pyright: ignore[reportDeprecated]
api_key=api_key,
stripe_version=stripe_version,
stripe_account=stripe_account,
**params,
)

@_util.deprecated(
"This will be removed in a future version of stripe-python. Please call the `list` method on the corresponding resource directly, instead of using `list` from the list object."
)
def list(
self,
api_key: Optional[str] = None,
Expand All @@ -50,6 +71,9 @@ def list(
),
)

@_util.deprecated(
"This will be removed in a future version of stripe-python. Please call the `create` method on the corresponding resource directly, instead of using `create` from the list object."
)
def create(
self,
api_key: Optional[str] = None,
Expand All @@ -76,6 +100,9 @@ def create(
),
)

@_util.deprecated(
"This will be removed in a future version of stripe-python. Please call the `retrieve` method on the corresponding resource directly, instead of using `retrieve` from the list object."
)
def retrieve(
self,
id: str,
Expand Down Expand Up @@ -148,11 +175,27 @@ def auto_paging_iter(self) -> Iterator[T]:
break

@classmethod
@_util.deprecated(
"This method is for internal stripe-python use only. The public interface will be removed in a future version."
)
def empty_list(
cls,
api_key: Optional[str] = None,
stripe_version: Optional[str] = None,
stripe_account: Optional[str] = None,
) -> Self:
return cls._empty_list(
api_key=api_key,
stripe_version=stripe_version,
stripe_account=stripe_account,
)

@classmethod
def _empty_list(
cls,
api_key: Optional[str] = None,
stripe_version: Optional[str] = None,
stripe_account: Optional[str] = None,
) -> Self:
return cls.construct_from(
{"data": []},
Expand All @@ -174,7 +217,7 @@ def next_page(
**params: Mapping[str, Any]
) -> Self:
if not self.has_more:
return self.empty_list(
return self._empty_list(
api_key=api_key,
stripe_version=stripe_version,
stripe_account=stripe_account,
Expand All @@ -190,13 +233,12 @@ def next_page(
params_with_filters.update({"starting_after": last_id})
params_with_filters.update(params)

result = self.list(
return self._list(
api_key=api_key,
stripe_version=stripe_version,
stripe_account=stripe_account,
**params_with_filters,
)
return result

def previous_page(
self,
Expand All @@ -206,7 +248,7 @@ def previous_page(
**params: Mapping[str, Any]
) -> Self:
if not self.has_more:
return self.empty_list(
return self._empty_list(
api_key=api_key,
stripe_version=stripe_version,
stripe_account=stripe_account,
Expand All @@ -222,7 +264,7 @@ def previous_page(
params_with_filters.update({"ending_before": first_id})
params_with_filters.update(params)

result = self.list(
result = self._list(
api_key=api_key,
stripe_version=stripe_version,
stripe_account=stripe_account,
Expand Down
3 changes: 3 additions & 0 deletions stripe/_listable_api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

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

# TODO(major): 1704 - remove this class and all internal usages. `.list` is already inlined into the resource classes.
# Although we should inline .auto_paging_iter into the resource classes as well.


class ListableAPIResource(APIResource[T]):
@classmethod
Expand Down
4 changes: 2 additions & 2 deletions stripe/_nested_resource_class_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from stripe._api_resource import APIResource


# TODO(major): Remove this. It is no longer used except for "nested_resource_url" and "nested_resource_request",
# which are unnecessary ande deprecated.
# TODO(major): 1704. Remove this. It is no longer used except for "nested_resource_url" and "nested_resource_request",
# which are unnecessary and deprecated and should also be removed.
def nested_resource_class_methods(
resource: str,
path: Optional[str] = None,
Expand Down
Loading

0 comments on commit 9f4273d

Please sign in to comment.