updates
This commit is contained in:
452
Backend/venv/lib/python3.12/site-packages/stripe/_util.py
Normal file
452
Backend/venv/lib/python3.12/site-packages/stripe/_util.py
Normal file
@@ -0,0 +1,452 @@
|
||||
import functools
|
||||
import hmac
|
||||
import logging
|
||||
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,
|
||||
Dict,
|
||||
List,
|
||||
cast,
|
||||
Any,
|
||||
Optional,
|
||||
Mapping,
|
||||
)
|
||||
import typing_extensions
|
||||
|
||||
|
||||
# Used for global variables
|
||||
import stripe # noqa: IMP101
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from stripe._stripe_response import StripeResponse
|
||||
from stripe._stripe_object import StripeObject
|
||||
from stripe._api_requestor import _APIRequestor
|
||||
|
||||
STRIPE_LOG = os.environ.get("STRIPE_LOG")
|
||||
|
||||
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(
|
||||
"SERVER_SOFTWARE", ""
|
||||
)
|
||||
|
||||
|
||||
def _console_log_level():
|
||||
if stripe.log in ["debug", "info"]:
|
||||
return stripe.log
|
||||
elif STRIPE_LOG in ["debug", "info"]:
|
||||
return STRIPE_LOG
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def log_debug(message, **params):
|
||||
msg = logfmt(dict(message=message, **params))
|
||||
if _console_log_level() == "debug":
|
||||
print(msg, file=sys.stderr)
|
||||
logger.debug(msg)
|
||||
|
||||
|
||||
def log_info(message, **params):
|
||||
msg = logfmt(dict(message=message, **params))
|
||||
if _console_log_level() in ["debug", "info"]:
|
||||
print(msg, file=sys.stderr)
|
||||
logger.info(msg)
|
||||
|
||||
|
||||
def _test_or_live_environment():
|
||||
if stripe.api_key is None:
|
||||
return
|
||||
match = re.match(r"sk_(live|test)_", stripe.api_key)
|
||||
if match is None:
|
||||
return
|
||||
return match.groups()[0]
|
||||
|
||||
|
||||
def dashboard_link(request_id):
|
||||
return "https://dashboard.stripe.com/{env}/logs/{reqid}".format(
|
||||
env=_test_or_live_environment() or "test", reqid=request_id
|
||||
)
|
||||
|
||||
|
||||
def logfmt(props):
|
||||
def fmt(key, val):
|
||||
# Handle case where val is a bytes or bytesarray
|
||||
if hasattr(val, "decode"):
|
||||
val = val.decode("utf-8")
|
||||
# Check if val is already a string to avoid re-encoding into
|
||||
# ascii. Since the code is sent through 2to3, we can't just
|
||||
# use unicode(val, encoding='utf8') since it will be
|
||||
# translated incorrectly.
|
||||
if not isinstance(val, str):
|
||||
val = str(val)
|
||||
if re.search(r"\s", val):
|
||||
val = repr(val)
|
||||
# key should already be a string
|
||||
if re.search(r"\s", key):
|
||||
key = repr(key)
|
||||
return "{key}={val}".format(key=key, val=val)
|
||||
|
||||
return " ".join([fmt(key, val) for key, val in sorted(props.items())])
|
||||
|
||||
|
||||
# Borrowed from Django's source code
|
||||
if hasattr(hmac, "compare_digest"):
|
||||
# Prefer the stdlib implementation, when available.
|
||||
def secure_compare(val1, val2):
|
||||
return hmac.compare_digest(val1, val2)
|
||||
|
||||
else:
|
||||
|
||||
def secure_compare(val1, val2):
|
||||
"""
|
||||
Returns True if the two strings are equal, False otherwise.
|
||||
The time taken is independent of the number of characters that match.
|
||||
For the sake of simplicity, this function executes in constant time
|
||||
only when the two strings have the same length. It short-circuits when
|
||||
they have different lengths.
|
||||
"""
|
||||
if len(val1) != len(val2):
|
||||
return False
|
||||
result = 0
|
||||
if isinstance(val1, bytes) and isinstance(val2, bytes):
|
||||
for x, y in zip(val1, val2):
|
||||
result |= x ^ y
|
||||
else:
|
||||
for x, y in zip(val1, val2):
|
||||
result |= ord(cast(str, x)) ^ ord(cast(str, y))
|
||||
return result == 0
|
||||
|
||||
|
||||
Resp = Union["StripeResponse", Dict[str, Any], List["Resp"]]
|
||||
|
||||
|
||||
@overload
|
||||
def convert_to_stripe_object(
|
||||
resp: Union["StripeResponse", Dict[str, Any]],
|
||||
api_key: Optional[str] = None,
|
||||
stripe_version: Optional[str] = None,
|
||||
stripe_account: Optional[str] = None,
|
||||
params: Optional[Mapping[str, Any]] = None,
|
||||
klass_: Optional[Type["StripeObject"]] = None,
|
||||
*,
|
||||
api_mode: ApiMode = "V1",
|
||||
) -> "StripeObject": ...
|
||||
|
||||
|
||||
@overload
|
||||
def convert_to_stripe_object(
|
||||
resp: List[Resp],
|
||||
api_key: Optional[str] = None,
|
||||
stripe_version: Optional[str] = None,
|
||||
stripe_account: Optional[str] = None,
|
||||
params: Optional[Mapping[str, Any]] = None,
|
||||
klass_: Optional[Type["StripeObject"]] = None,
|
||||
*,
|
||||
api_mode: ApiMode = "V1",
|
||||
) -> List["StripeObject"]: ...
|
||||
|
||||
|
||||
def convert_to_stripe_object(
|
||||
resp: Resp,
|
||||
api_key: Optional[str] = None,
|
||||
stripe_version: Optional[str] = None,
|
||||
stripe_account: Optional[str] = None,
|
||||
params: Optional[Mapping[str, Any]] = None,
|
||||
klass_: Optional[Type["StripeObject"]] = None,
|
||||
*,
|
||||
api_mode: ApiMode = "V1",
|
||||
) -> Union["StripeObject", List["StripeObject"]]:
|
||||
from stripe._api_requestor import _APIRequestor
|
||||
|
||||
return _convert_to_stripe_object(
|
||||
resp=resp,
|
||||
params=params,
|
||||
klass_=klass_,
|
||||
requestor=_APIRequestor._global_with_options(
|
||||
api_key=api_key,
|
||||
stripe_version=stripe_version,
|
||||
stripe_account=stripe_account,
|
||||
),
|
||||
api_mode=api_mode,
|
||||
)
|
||||
|
||||
|
||||
@overload
|
||||
def _convert_to_stripe_object(
|
||||
*,
|
||||
resp: Union["StripeResponse", Dict[str, Any]],
|
||||
params: Optional[Mapping[str, Any]] = None,
|
||||
klass_: Optional[Type["StripeObject"]] = None,
|
||||
requestor: "_APIRequestor",
|
||||
api_mode: ApiMode,
|
||||
is_v2_deleted_object: bool = False,
|
||||
) -> "StripeObject": ...
|
||||
|
||||
|
||||
@overload
|
||||
def _convert_to_stripe_object(
|
||||
*,
|
||||
resp: List[Resp],
|
||||
params: Optional[Mapping[str, Any]] = None,
|
||||
klass_: Optional[Type["StripeObject"]] = None,
|
||||
requestor: "_APIRequestor",
|
||||
api_mode: ApiMode,
|
||||
is_v2_deleted_object: bool = False,
|
||||
) -> List["StripeObject"]: ...
|
||||
|
||||
|
||||
def _convert_to_stripe_object(
|
||||
*,
|
||||
resp: Resp,
|
||||
params: Optional[Mapping[str, Any]] = None,
|
||||
klass_: Optional[Type["StripeObject"]] = None,
|
||||
requestor: "_APIRequestor",
|
||||
api_mode: ApiMode,
|
||||
# if true, we should ignore the `object` field for finding the class name. This is set by the API requestor
|
||||
is_v2_deleted_object: bool = False,
|
||||
) -> Union["StripeObject", List["StripeObject"]]:
|
||||
# If we get a StripeResponse, we'll want to return a
|
||||
# StripeObject with the last_response field filled out with
|
||||
# the raw API response information
|
||||
stripe_response = None
|
||||
|
||||
# Imports here at runtime to avoid circular dependencies
|
||||
from stripe._stripe_response import StripeResponse
|
||||
from stripe._stripe_object import StripeObject
|
||||
|
||||
if isinstance(resp, StripeResponse):
|
||||
stripe_response = resp
|
||||
resp = cast(Resp, stripe_response.data)
|
||||
|
||||
if isinstance(resp, list):
|
||||
return [
|
||||
_convert_to_stripe_object(
|
||||
resp=cast("Union[StripeResponse, Dict[str, Any]]", i),
|
||||
requestor=requestor,
|
||||
api_mode=api_mode,
|
||||
klass_=klass_,
|
||||
)
|
||||
for i in resp
|
||||
]
|
||||
elif isinstance(resp, dict) and not isinstance(resp, StripeObject):
|
||||
resp = resp.copy()
|
||||
klass_name = resp.get("object")
|
||||
if isinstance(klass_name, str):
|
||||
if is_v2_deleted_object:
|
||||
# circular import
|
||||
from stripe.v2._deleted_object import DeletedObject
|
||||
|
||||
klass = DeletedObject
|
||||
elif api_mode == "V2" and klass_name == "v2.core.event":
|
||||
from stripe.events._event_classes import get_v2_event_class
|
||||
|
||||
event_type = resp.get("type", "")
|
||||
klass = get_v2_event_class(event_type)
|
||||
else:
|
||||
from stripe._object_classes import get_object_class
|
||||
|
||||
klass = get_object_class(api_mode, klass_name)
|
||||
# TODO: this is a horrible hack. The API needs
|
||||
# to return something for `object` here.
|
||||
|
||||
elif "data" in resp and "next_page_url" in resp:
|
||||
klass = stripe.v2.ListObject
|
||||
elif klass_ is not None:
|
||||
klass = klass_
|
||||
else:
|
||||
klass = StripeObject
|
||||
|
||||
obj = klass._construct_from(
|
||||
values=resp,
|
||||
last_response=stripe_response,
|
||||
requestor=requestor,
|
||||
api_mode=api_mode,
|
||||
)
|
||||
|
||||
# We only need to update _retrieve_params when special params were
|
||||
# actually passed. Otherwise, leave it as is as the list / search result
|
||||
# constructors will instantiate their own params.
|
||||
if (
|
||||
params is not None
|
||||
and hasattr(obj, "object")
|
||||
and (
|
||||
(getattr(obj, "object") == "list")
|
||||
or (getattr(obj, "object") == "search_result")
|
||||
)
|
||||
):
|
||||
obj._retrieve_params = params
|
||||
|
||||
return obj
|
||||
else:
|
||||
return cast("StripeObject", resp)
|
||||
|
||||
|
||||
def convert_to_dict(obj):
|
||||
"""Converts a StripeObject back to a regular dict.
|
||||
|
||||
Nested StripeObjects are also converted back to regular dicts.
|
||||
|
||||
:param obj: The StripeObject to convert.
|
||||
|
||||
:returns: The StripeObject as a dict.
|
||||
"""
|
||||
if isinstance(obj, list):
|
||||
return [convert_to_dict(i) for i in obj]
|
||||
# This works by virtue of the fact that StripeObjects _are_ dicts. The dict
|
||||
# comprehension returns a regular dict and recursively applies the
|
||||
# conversion to each value.
|
||||
elif isinstance(obj, dict):
|
||||
return {k: convert_to_dict(v) for k, v in obj.items()}
|
||||
else:
|
||||
return obj
|
||||
|
||||
|
||||
@overload
|
||||
def populate_headers(
|
||||
idempotency_key: str,
|
||||
) -> Dict[str, str]: ...
|
||||
|
||||
|
||||
@overload
|
||||
def populate_headers(idempotency_key: None) -> None: ...
|
||||
|
||||
|
||||
def populate_headers(
|
||||
idempotency_key: Union[str, None],
|
||||
) -> Union[Dict[str, str], None]:
|
||||
if idempotency_key is not None:
|
||||
return {"Idempotency-Key": idempotency_key}
|
||||
return None
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def merge_dicts(x, y):
|
||||
z = x.copy()
|
||||
z.update(y)
|
||||
return z
|
||||
|
||||
|
||||
def sanitize_id(id):
|
||||
quotedId = quote_plus(id)
|
||||
return quotedId
|
||||
|
||||
|
||||
def get_api_mode(url: str) -> ApiMode:
|
||||
if url.startswith("/v2"):
|
||||
return "V2"
|
||||
|
||||
# if urls aren't explicitly marked as v1, they're assumed to be v1
|
||||
else:
|
||||
return "V1"
|
||||
|
||||
|
||||
class class_method_variant(object):
|
||||
def __init__(self, class_method_name):
|
||||
self.class_method_name = class_method_name
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
method: Any
|
||||
|
||||
def __call__(self, method: T) -> T:
|
||||
self.method = method
|
||||
return cast(T, self)
|
||||
|
||||
def __get__(self, obj, objtype: Optional[Type[Any]] = None):
|
||||
@functools.wraps(self.method)
|
||||
def _wrapper(*args, **kwargs):
|
||||
if obj is not None:
|
||||
# Method was called as an instance method, e.g.
|
||||
# instance.method(...)
|
||||
return self.method(obj, *args, **kwargs)
|
||||
elif (
|
||||
len(args) > 0
|
||||
and objtype is not None
|
||||
and isinstance(args[0], objtype)
|
||||
):
|
||||
# Method was called as a class method with the instance as the
|
||||
# first argument, e.g. Class.method(instance, ...) which in
|
||||
# Python is the same thing as calling an instance method
|
||||
return self.method(args[0], *args[1:], **kwargs)
|
||||
else:
|
||||
# Method was called as a class method, e.g. Class.method(...)
|
||||
class_method = getattr(objtype, self.class_method_name)
|
||||
return class_method(*args, **kwargs)
|
||||
|
||||
return _wrapper
|
||||
Reference in New Issue
Block a user