From 4db792afa4fd65590a7ae4e0fdd782069917f78c Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 12 Oct 2023 01:25:00 +0100 Subject: [PATCH 01/22] chore: update README (#151) --- README.md | 4 ++-- tests/test_client.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 97e0f92d6..286f899a2 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ and offers both synchronous and asynchronous clients powered by [httpx](https:// ## Documentation -The API documentation can be found at [https://increase.com/documentation](https://increase.com/documentation). +The API documentation can be found [here](https://increase.com/documentation). ## Installation @@ -321,7 +321,7 @@ By default the library closes underlying HTTP connections whenever the client is ## Versioning -This package generally attempts to follow [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: +This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes that only affect static types, without breaking runtime behavior. 2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_. diff --git a/tests/test_client.py b/tests/test_client.py index afbdb51f8..3fd38b1d2 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -55,7 +55,7 @@ def test_copy(self) -> None: assert self.client.api_key == api_key def test_copy_default_options(self) -> None: - # options that have a default are overriden correctly + # options that have a default are overridden correctly copied = self.client.copy(max_retries=7) assert copied.max_retries == 7 assert self.client.max_retries == 2 @@ -673,7 +673,7 @@ def test_copy(self) -> None: assert self.client.api_key == api_key def test_copy_default_options(self) -> None: - # options that have a default are overriden correctly + # options that have a default are overridden correctly copied = self.client.copy(max_retries=7) assert copied.max_retries == 7 assert self.client.max_retries == 2 From acdfa121cec5604ef96fc8a580636e2f6d2c4927 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 12 Oct 2023 02:38:03 +0100 Subject: [PATCH 02/22] refactor(test): refactor authentication tests (#153) --- README.md | 10 +++--- src/increase/_base_client.py | 5 ++- src/increase/_client.py | 14 ++++---- src/increase/_utils/__init__.py | 3 ++ src/increase/_utils/_utils.py | 18 +++++++++++ .../entities/test_beneficial_owners.py | 2 +- .../entities/test_supplemental_documents.py | 2 +- .../simulations/test_account_statements.py | 2 +- .../simulations/test_account_transfers.py | 2 +- .../simulations/test_ach_transfers.py | 2 +- .../simulations/test_card_disputes.py | 2 +- .../simulations/test_card_profiles.py | 2 +- .../simulations/test_card_refunds.py | 2 +- tests/api_resources/simulations/test_cards.py | 2 +- .../simulations/test_check_deposits.py | 2 +- .../simulations/test_check_transfers.py | 2 +- .../test_digital_wallet_token_requests.py | 2 +- .../simulations/test_documents.py | 2 +- .../simulations/test_inbound_funds_holds.py | 2 +- .../test_inbound_wire_drawdown_requests.py | 2 +- .../simulations/test_interest_payments.py | 2 +- .../simulations/test_physical_cards.py | 2 +- .../simulations/test_programs.py | 2 +- .../test_real_time_payments_transfers.py | 2 +- .../simulations/test_wire_transfers.py | 2 +- tests/api_resources/test_account_numbers.py | 2 +- .../api_resources/test_account_statements.py | 2 +- tests/api_resources/test_account_transfers.py | 2 +- tests/api_resources/test_accounts.py | 2 +- .../test_ach_prenotifications.py | 2 +- tests/api_resources/test_ach_transfers.py | 2 +- tests/api_resources/test_balance_lookups.py | 2 +- .../test_bookkeeping_accounts.py | 2 +- .../api_resources/test_bookkeeping_entries.py | 2 +- .../test_bookkeeping_entry_sets.py | 2 +- tests/api_resources/test_card_disputes.py | 2 +- tests/api_resources/test_card_payments.py | 2 +- tests/api_resources/test_card_profiles.py | 2 +- .../test_card_purchase_supplements.py | 2 +- tests/api_resources/test_cards.py | 2 +- tests/api_resources/test_check_deposits.py | 2 +- tests/api_resources/test_check_transfers.py | 2 +- .../test_declined_transactions.py | 2 +- .../test_digital_wallet_tokens.py | 2 +- tests/api_resources/test_documents.py | 2 +- tests/api_resources/test_entities.py | 2 +- .../api_resources/test_event_subscriptions.py | 2 +- tests/api_resources/test_events.py | 2 +- tests/api_resources/test_exports.py | 2 +- tests/api_resources/test_external_accounts.py | 2 +- tests/api_resources/test_files.py | 2 +- tests/api_resources/test_groups.py | 2 +- .../test_inbound_ach_transfers.py | 2 +- .../test_inbound_wire_drawdown_requests.py | 2 +- tests/api_resources/test_oauth_connections.py | 2 +- .../test_pending_transactions.py | 2 +- tests/api_resources/test_physical_cards.py | 2 +- tests/api_resources/test_programs.py | 2 +- .../api_resources/test_real_time_decisions.py | 2 +- .../test_real_time_payments_transfers.py | 2 +- tests/api_resources/test_routing_numbers.py | 2 +- tests/api_resources/test_transactions.py | 2 +- .../test_wire_drawdown_requests.py | 2 +- tests/api_resources/test_wire_transfers.py | 2 +- tests/test_client.py | 32 +++++++++++++++---- 65 files changed, 121 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 286f899a2..badec297f 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ from increase import Increase client = Increase( # defaults to os.environ.get("INCREASE_API_KEY") - api_key="my api key", + api_key="My API Key", # defaults to "production". environment="sandbox", ) @@ -36,8 +36,10 @@ account = client.accounts.create( print(account.id) ``` -While you can provide an `api_key` keyword argument, we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) -and adding `INCREASE_API_KEY="my api key"` to your `.env` file so that your API Key is not stored in source control. +While you can provide an `api_key` keyword argument, +we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) +to add `INCREASE_API_KEY="My API Key"` to your `.env` file +so that your API Key is not stored in source control. ## Async usage @@ -48,7 +50,7 @@ from increase import AsyncIncrease client = AsyncIncrease( # defaults to os.environ.get("INCREASE_API_KEY") - api_key="my api key", + api_key="My API Key", # defaults to "production". environment="sandbox", ) diff --git a/src/increase/_base_client.py b/src/increase/_base_client.py index c49dad055..71b70bcda 100644 --- a/src/increase/_base_client.py +++ b/src/increase/_base_client.py @@ -811,7 +811,10 @@ def close(self) -> None: The client will *not* be usable after this. """ - self._client.close() + # If an error is thrown while constructing a client, self._client + # may not be present + if hasattr(self, "_client"): + self._client.close() def __enter__(self: _T) -> _T: return self diff --git a/src/increase/_client.py b/src/increase/_client.py index 663bda553..50d4b075d 100644 --- a/src/increase/_client.py +++ b/src/increase/_client.py @@ -101,9 +101,9 @@ class Increase(SyncAPIClient): def __init__( self, *, + api_key: str | None = os.environ.get("INCREASE_API_KEY", None), environment: Literal["production", "sandbox"] = "production", base_url: Optional[str] = None, - api_key: Optional[str] = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -130,8 +130,7 @@ def __init__( This automatically infers the `api_key` argument from the `INCREASE_API_KEY` environment variable if it is not provided. """ - api_key = api_key or os.environ.get("INCREASE_API_KEY", None) - if not api_key: + if api_key is None: raise IncreaseError( "The api_key client option must be set either by passing api_key to the client or by setting the INCREASE_API_KEY environment variable" ) @@ -269,9 +268,9 @@ def copy( http_client = http_client or self._client return self.__class__( + api_key=api_key or self.api_key, base_url=base_url or str(self.base_url), environment=environment or self._environment, - api_key=api_key or self.api_key, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, connection_pool_limits=connection_pool_limits, @@ -428,9 +427,9 @@ class AsyncIncrease(AsyncAPIClient): def __init__( self, *, + api_key: str | None = os.environ.get("INCREASE_API_KEY", None), environment: Literal["production", "sandbox"] = "production", base_url: Optional[str] = None, - api_key: Optional[str] = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -457,8 +456,7 @@ def __init__( This automatically infers the `api_key` argument from the `INCREASE_API_KEY` environment variable if it is not provided. """ - api_key = api_key or os.environ.get("INCREASE_API_KEY", None) - if not api_key: + if api_key is None: raise IncreaseError( "The api_key client option must be set either by passing api_key to the client or by setting the INCREASE_API_KEY environment variable" ) @@ -596,9 +594,9 @@ def copy( http_client = http_client or self._client return self.__class__( + api_key=api_key or self.api_key, base_url=base_url or str(self.base_url), environment=environment or self._environment, - api_key=api_key or self.api_key, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, connection_pool_limits=connection_pool_limits, diff --git a/src/increase/_utils/__init__.py b/src/increase/_utils/__init__.py index 679193bdb..6d13a3629 100644 --- a/src/increase/_utils/__init__.py +++ b/src/increase/_utils/__init__.py @@ -21,6 +21,9 @@ from ._utils import extract_type_arg as extract_type_arg from ._utils import is_required_type as is_required_type from ._utils import is_annotated_type as is_annotated_type +from ._utils import maybe_coerce_float as maybe_coerce_float +from ._utils import maybe_coerce_boolean as maybe_coerce_boolean +from ._utils import maybe_coerce_integer as maybe_coerce_integer from ._utils import strip_annotated_type as strip_annotated_type from ._transform import PropertyInfo as PropertyInfo from ._transform import transform as transform diff --git a/src/increase/_utils/_utils.py b/src/increase/_utils/_utils.py index 603f7c10b..e43ef6f89 100644 --- a/src/increase/_utils/_utils.py +++ b/src/increase/_utils/_utils.py @@ -309,6 +309,24 @@ def coerce_boolean(val: str) -> bool: return val == "true" or val == "1" or val == "on" +def maybe_coerce_integer(val: str | None) -> int | None: + if val is None: + return None + return coerce_integer(val) + + +def maybe_coerce_float(val: str | None) -> float | None: + if val is None: + return None + return coerce_float(val) + + +def maybe_coerce_boolean(val: str | None) -> bool | None: + if val is None: + return None + return coerce_boolean(val) + + def removeprefix(string: str, prefix: str) -> str: """Remove a prefix from a string. diff --git a/tests/api_resources/entities/test_beneficial_owners.py b/tests/api_resources/entities/test_beneficial_owners.py index bfbdf5186..6accc49db 100644 --- a/tests/api_resources/entities/test_beneficial_owners.py +++ b/tests/api_resources/entities/test_beneficial_owners.py @@ -12,7 +12,7 @@ from increase._utils import parse_date base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestBeneficialOwners: diff --git a/tests/api_resources/entities/test_supplemental_documents.py b/tests/api_resources/entities/test_supplemental_documents.py index 11746b64e..fafa35989 100644 --- a/tests/api_resources/entities/test_supplemental_documents.py +++ b/tests/api_resources/entities/test_supplemental_documents.py @@ -13,7 +13,7 @@ from increase.types.entities import SupplementalDocument base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestSupplementalDocuments: diff --git a/tests/api_resources/simulations/test_account_statements.py b/tests/api_resources/simulations/test_account_statements.py index 3c9b17744..6df2f992c 100644 --- a/tests/api_resources/simulations/test_account_statements.py +++ b/tests/api_resources/simulations/test_account_statements.py @@ -11,7 +11,7 @@ from increase.types import AccountStatement base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestAccountStatements: diff --git a/tests/api_resources/simulations/test_account_transfers.py b/tests/api_resources/simulations/test_account_transfers.py index 020f376a7..6cd6e2cd7 100644 --- a/tests/api_resources/simulations/test_account_transfers.py +++ b/tests/api_resources/simulations/test_account_transfers.py @@ -11,7 +11,7 @@ from increase.types import AccountTransfer base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestAccountTransfers: diff --git a/tests/api_resources/simulations/test_ach_transfers.py b/tests/api_resources/simulations/test_ach_transfers.py index 2605ce095..8dc84f6a8 100644 --- a/tests/api_resources/simulations/test_ach_transfers.py +++ b/tests/api_resources/simulations/test_ach_transfers.py @@ -13,7 +13,7 @@ from increase.types.simulations import ACHTransferSimulation base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestACHTransfers: diff --git a/tests/api_resources/simulations/test_card_disputes.py b/tests/api_resources/simulations/test_card_disputes.py index 146445045..deb22dee2 100644 --- a/tests/api_resources/simulations/test_card_disputes.py +++ b/tests/api_resources/simulations/test_card_disputes.py @@ -11,7 +11,7 @@ from increase.types import CardDispute base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCardDisputes: diff --git a/tests/api_resources/simulations/test_card_profiles.py b/tests/api_resources/simulations/test_card_profiles.py index c76158d4b..68feec8bd 100644 --- a/tests/api_resources/simulations/test_card_profiles.py +++ b/tests/api_resources/simulations/test_card_profiles.py @@ -11,7 +11,7 @@ from increase.types import CardProfile base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCardProfiles: diff --git a/tests/api_resources/simulations/test_card_refunds.py b/tests/api_resources/simulations/test_card_refunds.py index bfb00caea..9d6ac47f4 100644 --- a/tests/api_resources/simulations/test_card_refunds.py +++ b/tests/api_resources/simulations/test_card_refunds.py @@ -11,7 +11,7 @@ from increase.types import Transaction base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCardRefunds: diff --git a/tests/api_resources/simulations/test_cards.py b/tests/api_resources/simulations/test_cards.py index 6580e8fa1..47e1dfea9 100644 --- a/tests/api_resources/simulations/test_cards.py +++ b/tests/api_resources/simulations/test_cards.py @@ -12,7 +12,7 @@ from increase.types.simulations import CardAuthorizationSimulation base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCards: diff --git a/tests/api_resources/simulations/test_check_deposits.py b/tests/api_resources/simulations/test_check_deposits.py index 208e60471..0e393bb60 100644 --- a/tests/api_resources/simulations/test_check_deposits.py +++ b/tests/api_resources/simulations/test_check_deposits.py @@ -11,7 +11,7 @@ from increase.types import CheckDeposit base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCheckDeposits: diff --git a/tests/api_resources/simulations/test_check_transfers.py b/tests/api_resources/simulations/test_check_transfers.py index dfc16038d..667d754cc 100644 --- a/tests/api_resources/simulations/test_check_transfers.py +++ b/tests/api_resources/simulations/test_check_transfers.py @@ -11,7 +11,7 @@ from increase.types import CheckTransfer base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCheckTransfers: diff --git a/tests/api_resources/simulations/test_digital_wallet_token_requests.py b/tests/api_resources/simulations/test_digital_wallet_token_requests.py index 2f613fed2..908c05faf 100644 --- a/tests/api_resources/simulations/test_digital_wallet_token_requests.py +++ b/tests/api_resources/simulations/test_digital_wallet_token_requests.py @@ -11,7 +11,7 @@ from increase.types.simulations import DigitalWalletTokenRequestCreateResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestDigitalWalletTokenRequests: diff --git a/tests/api_resources/simulations/test_documents.py b/tests/api_resources/simulations/test_documents.py index b67c0b9e9..f3e6bf586 100644 --- a/tests/api_resources/simulations/test_documents.py +++ b/tests/api_resources/simulations/test_documents.py @@ -11,7 +11,7 @@ from increase.types import Document base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestDocuments: diff --git a/tests/api_resources/simulations/test_inbound_funds_holds.py b/tests/api_resources/simulations/test_inbound_funds_holds.py index 23fcd8569..a807a812d 100644 --- a/tests/api_resources/simulations/test_inbound_funds_holds.py +++ b/tests/api_resources/simulations/test_inbound_funds_holds.py @@ -11,7 +11,7 @@ from increase.types.simulations import InboundFundsHoldReleaseResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestInboundFundsHolds: diff --git a/tests/api_resources/simulations/test_inbound_wire_drawdown_requests.py b/tests/api_resources/simulations/test_inbound_wire_drawdown_requests.py index 8cfbd1f99..7e3fc1926 100644 --- a/tests/api_resources/simulations/test_inbound_wire_drawdown_requests.py +++ b/tests/api_resources/simulations/test_inbound_wire_drawdown_requests.py @@ -11,7 +11,7 @@ from increase.types import InboundWireDrawdownRequest base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestInboundWireDrawdownRequests: diff --git a/tests/api_resources/simulations/test_interest_payments.py b/tests/api_resources/simulations/test_interest_payments.py index 05c141b90..046f651f1 100644 --- a/tests/api_resources/simulations/test_interest_payments.py +++ b/tests/api_resources/simulations/test_interest_payments.py @@ -12,7 +12,7 @@ from increase.types.simulations import InterestPaymentSimulationResult base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestInterestPayments: diff --git a/tests/api_resources/simulations/test_physical_cards.py b/tests/api_resources/simulations/test_physical_cards.py index 1505aa89e..0d00b1b31 100644 --- a/tests/api_resources/simulations/test_physical_cards.py +++ b/tests/api_resources/simulations/test_physical_cards.py @@ -11,7 +11,7 @@ from increase.types import PhysicalCard base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestPhysicalCards: diff --git a/tests/api_resources/simulations/test_programs.py b/tests/api_resources/simulations/test_programs.py index 3f12cfacb..6df647374 100644 --- a/tests/api_resources/simulations/test_programs.py +++ b/tests/api_resources/simulations/test_programs.py @@ -11,7 +11,7 @@ from increase.types import Program base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestPrograms: diff --git a/tests/api_resources/simulations/test_real_time_payments_transfers.py b/tests/api_resources/simulations/test_real_time_payments_transfers.py index 5379ecc4d..c0e7c9994 100644 --- a/tests/api_resources/simulations/test_real_time_payments_transfers.py +++ b/tests/api_resources/simulations/test_real_time_payments_transfers.py @@ -12,7 +12,7 @@ from increase.types.simulations import InboundRealTimePaymentsTransferSimulationResult base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestRealTimePaymentsTransfers: diff --git a/tests/api_resources/simulations/test_wire_transfers.py b/tests/api_resources/simulations/test_wire_transfers.py index 3b062683c..b7e94dd29 100644 --- a/tests/api_resources/simulations/test_wire_transfers.py +++ b/tests/api_resources/simulations/test_wire_transfers.py @@ -11,7 +11,7 @@ from increase.types.simulations import WireTransferSimulation base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestWireTransfers: diff --git a/tests/api_resources/test_account_numbers.py b/tests/api_resources/test_account_numbers.py index ff53fdc5d..2a7eaf6cc 100644 --- a/tests/api_resources/test_account_numbers.py +++ b/tests/api_resources/test_account_numbers.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestAccountNumbers: diff --git a/tests/api_resources/test_account_statements.py b/tests/api_resources/test_account_statements.py index 2b0d1a257..941402837 100644 --- a/tests/api_resources/test_account_statements.py +++ b/tests/api_resources/test_account_statements.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestAccountStatements: diff --git a/tests/api_resources/test_account_transfers.py b/tests/api_resources/test_account_transfers.py index 42e3d988c..d921fd942 100644 --- a/tests/api_resources/test_account_transfers.py +++ b/tests/api_resources/test_account_transfers.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestAccountTransfers: diff --git a/tests/api_resources/test_accounts.py b/tests/api_resources/test_accounts.py index 6df8aa121..f6f57c456 100644 --- a/tests/api_resources/test_accounts.py +++ b/tests/api_resources/test_accounts.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestAccounts: diff --git a/tests/api_resources/test_ach_prenotifications.py b/tests/api_resources/test_ach_prenotifications.py index 6877d9436..6ad47d8a7 100644 --- a/tests/api_resources/test_ach_prenotifications.py +++ b/tests/api_resources/test_ach_prenotifications.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestACHPrenotifications: diff --git a/tests/api_resources/test_ach_transfers.py b/tests/api_resources/test_ach_transfers.py index 19849130e..780940af5 100644 --- a/tests/api_resources/test_ach_transfers.py +++ b/tests/api_resources/test_ach_transfers.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestACHTransfers: diff --git a/tests/api_resources/test_balance_lookups.py b/tests/api_resources/test_balance_lookups.py index b8b9a51c9..4f29f6dc0 100644 --- a/tests/api_resources/test_balance_lookups.py +++ b/tests/api_resources/test_balance_lookups.py @@ -12,7 +12,7 @@ from increase._utils import parse_datetime base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestBalanceLookups: diff --git a/tests/api_resources/test_bookkeeping_accounts.py b/tests/api_resources/test_bookkeeping_accounts.py index 9502d2df3..4d44f66ca 100644 --- a/tests/api_resources/test_bookkeeping_accounts.py +++ b/tests/api_resources/test_bookkeeping_accounts.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestBookkeepingAccounts: diff --git a/tests/api_resources/test_bookkeeping_entries.py b/tests/api_resources/test_bookkeeping_entries.py index 27012d0af..68152946c 100644 --- a/tests/api_resources/test_bookkeeping_entries.py +++ b/tests/api_resources/test_bookkeeping_entries.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestBookkeepingEntries: diff --git a/tests/api_resources/test_bookkeeping_entry_sets.py b/tests/api_resources/test_bookkeeping_entry_sets.py index dbf2869a9..c3534641c 100644 --- a/tests/api_resources/test_bookkeeping_entry_sets.py +++ b/tests/api_resources/test_bookkeeping_entry_sets.py @@ -12,7 +12,7 @@ from increase._utils import parse_datetime base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestBookkeepingEntrySets: diff --git a/tests/api_resources/test_card_disputes.py b/tests/api_resources/test_card_disputes.py index ed0f813c8..c19d3c5a7 100644 --- a/tests/api_resources/test_card_disputes.py +++ b/tests/api_resources/test_card_disputes.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCardDisputes: diff --git a/tests/api_resources/test_card_payments.py b/tests/api_resources/test_card_payments.py index ea3020bda..f15ed9ce2 100644 --- a/tests/api_resources/test_card_payments.py +++ b/tests/api_resources/test_card_payments.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCardPayments: diff --git a/tests/api_resources/test_card_profiles.py b/tests/api_resources/test_card_profiles.py index 83c0fc7f2..9c04c337a 100644 --- a/tests/api_resources/test_card_profiles.py +++ b/tests/api_resources/test_card_profiles.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCardProfiles: diff --git a/tests/api_resources/test_card_purchase_supplements.py b/tests/api_resources/test_card_purchase_supplements.py index 3df0e32f4..642b2ba92 100644 --- a/tests/api_resources/test_card_purchase_supplements.py +++ b/tests/api_resources/test_card_purchase_supplements.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCardPurchaseSupplements: diff --git a/tests/api_resources/test_cards.py b/tests/api_resources/test_cards.py index 221e5b0f7..edebd4579 100644 --- a/tests/api_resources/test_cards.py +++ b/tests/api_resources/test_cards.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCards: diff --git a/tests/api_resources/test_check_deposits.py b/tests/api_resources/test_check_deposits.py index 7a71b1ea1..4b97d245a 100644 --- a/tests/api_resources/test_check_deposits.py +++ b/tests/api_resources/test_check_deposits.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCheckDeposits: diff --git a/tests/api_resources/test_check_transfers.py b/tests/api_resources/test_check_transfers.py index 7733c41be..e723218f4 100644 --- a/tests/api_resources/test_check_transfers.py +++ b/tests/api_resources/test_check_transfers.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestCheckTransfers: diff --git a/tests/api_resources/test_declined_transactions.py b/tests/api_resources/test_declined_transactions.py index fa440a831..572cf740d 100644 --- a/tests/api_resources/test_declined_transactions.py +++ b/tests/api_resources/test_declined_transactions.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestDeclinedTransactions: diff --git a/tests/api_resources/test_digital_wallet_tokens.py b/tests/api_resources/test_digital_wallet_tokens.py index 32a6b9c59..4ade6d4fd 100644 --- a/tests/api_resources/test_digital_wallet_tokens.py +++ b/tests/api_resources/test_digital_wallet_tokens.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestDigitalWalletTokens: diff --git a/tests/api_resources/test_documents.py b/tests/api_resources/test_documents.py index 42645c4b7..ccd80ff8c 100644 --- a/tests/api_resources/test_documents.py +++ b/tests/api_resources/test_documents.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestDocuments: diff --git a/tests/api_resources/test_entities.py b/tests/api_resources/test_entities.py index 2939dd2a1..5edff3117 100644 --- a/tests/api_resources/test_entities.py +++ b/tests/api_resources/test_entities.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestEntities: diff --git a/tests/api_resources/test_event_subscriptions.py b/tests/api_resources/test_event_subscriptions.py index a475e451b..6ad17c8c9 100644 --- a/tests/api_resources/test_event_subscriptions.py +++ b/tests/api_resources/test_event_subscriptions.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestEventSubscriptions: diff --git a/tests/api_resources/test_events.py b/tests/api_resources/test_events.py index 1d569e2d1..897983b11 100644 --- a/tests/api_resources/test_events.py +++ b/tests/api_resources/test_events.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestEvents: diff --git a/tests/api_resources/test_exports.py b/tests/api_resources/test_exports.py index 1c19c4e4c..fd51d7e0f 100644 --- a/tests/api_resources/test_exports.py +++ b/tests/api_resources/test_exports.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestExports: diff --git a/tests/api_resources/test_external_accounts.py b/tests/api_resources/test_external_accounts.py index 803c0b472..64b2703b3 100644 --- a/tests/api_resources/test_external_accounts.py +++ b/tests/api_resources/test_external_accounts.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestExternalAccounts: diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index 7e13d0b76..35c606afc 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestFiles: diff --git a/tests/api_resources/test_groups.py b/tests/api_resources/test_groups.py index 0897a9168..4a06ba464 100644 --- a/tests/api_resources/test_groups.py +++ b/tests/api_resources/test_groups.py @@ -11,7 +11,7 @@ from increase.types import Group base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestGroups: diff --git a/tests/api_resources/test_inbound_ach_transfers.py b/tests/api_resources/test_inbound_ach_transfers.py index dd5178914..58163c252 100644 --- a/tests/api_resources/test_inbound_ach_transfers.py +++ b/tests/api_resources/test_inbound_ach_transfers.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestInboundACHTransfers: diff --git a/tests/api_resources/test_inbound_wire_drawdown_requests.py b/tests/api_resources/test_inbound_wire_drawdown_requests.py index 3610ff93a..32925b624 100644 --- a/tests/api_resources/test_inbound_wire_drawdown_requests.py +++ b/tests/api_resources/test_inbound_wire_drawdown_requests.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestInboundWireDrawdownRequests: diff --git a/tests/api_resources/test_oauth_connections.py b/tests/api_resources/test_oauth_connections.py index 561773b3c..5944a0c1a 100644 --- a/tests/api_resources/test_oauth_connections.py +++ b/tests/api_resources/test_oauth_connections.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestOauthConnections: diff --git a/tests/api_resources/test_pending_transactions.py b/tests/api_resources/test_pending_transactions.py index 27fb486e6..96e08a303 100644 --- a/tests/api_resources/test_pending_transactions.py +++ b/tests/api_resources/test_pending_transactions.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestPendingTransactions: diff --git a/tests/api_resources/test_physical_cards.py b/tests/api_resources/test_physical_cards.py index ab2cc7220..7c1a2f365 100644 --- a/tests/api_resources/test_physical_cards.py +++ b/tests/api_resources/test_physical_cards.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestPhysicalCards: diff --git a/tests/api_resources/test_programs.py b/tests/api_resources/test_programs.py index 565647541..a498ccac1 100644 --- a/tests/api_resources/test_programs.py +++ b/tests/api_resources/test_programs.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestPrograms: diff --git a/tests/api_resources/test_real_time_decisions.py b/tests/api_resources/test_real_time_decisions.py index aa4c495f9..316484a6d 100644 --- a/tests/api_resources/test_real_time_decisions.py +++ b/tests/api_resources/test_real_time_decisions.py @@ -11,7 +11,7 @@ from increase.types import RealTimeDecision base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestRealTimeDecisions: diff --git a/tests/api_resources/test_real_time_payments_transfers.py b/tests/api_resources/test_real_time_payments_transfers.py index a899c7a99..024694297 100644 --- a/tests/api_resources/test_real_time_payments_transfers.py +++ b/tests/api_resources/test_real_time_payments_transfers.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestRealTimePaymentsTransfers: diff --git a/tests/api_resources/test_routing_numbers.py b/tests/api_resources/test_routing_numbers.py index f063f6c07..1684a7770 100644 --- a/tests/api_resources/test_routing_numbers.py +++ b/tests/api_resources/test_routing_numbers.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestRoutingNumbers: diff --git a/tests/api_resources/test_transactions.py b/tests/api_resources/test_transactions.py index 1e8278792..338a4fe09 100644 --- a/tests/api_resources/test_transactions.py +++ b/tests/api_resources/test_transactions.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestTransactions: diff --git a/tests/api_resources/test_wire_drawdown_requests.py b/tests/api_resources/test_wire_drawdown_requests.py index 579fcba96..faff8d157 100644 --- a/tests/api_resources/test_wire_drawdown_requests.py +++ b/tests/api_resources/test_wire_drawdown_requests.py @@ -12,7 +12,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestWireDrawdownRequests: diff --git a/tests/api_resources/test_wire_transfers.py b/tests/api_resources/test_wire_transfers.py index 67579fc63..b5f1f26fa 100644 --- a/tests/api_resources/test_wire_transfers.py +++ b/tests/api_resources/test_wire_transfers.py @@ -13,7 +13,7 @@ from increase.pagination import SyncPage, AsyncPage base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" class TestWireTransfers: diff --git a/tests/test_client.py b/tests/test_client.py index 3fd38b1d2..02b60ad24 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -25,7 +25,7 @@ ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -api_key = os.environ.get("API_KEY", "something1234") +api_key = "My API Key" def _get_params(client: BaseClient) -> dict[str, str]: @@ -50,9 +50,9 @@ def test_copy(self) -> None: copied = self.client.copy() assert id(copied) != id(self.client) - copied = self.client.copy(api_key="my new api key") - assert copied.api_key == "my new api key" - assert self.client.api_key == api_key + copied = self.client.copy(api_key="another My API Key") + assert copied.api_key == "another My API Key" + assert self.client.api_key == "My API Key" def test_copy_default_options(self) -> None: # options that have a default are overridden correctly @@ -228,6 +228,15 @@ def test_default_headers_option(self) -> None: assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + def test_validate_headers(self) -> None: + client = Increase(base_url=base_url, api_key=api_key, _strict_response_validation=True) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("Authorization") == f"Bearer {api_key}" + + with pytest.raises(Exception): + client2 = Increase(base_url=base_url, api_key=None, _strict_response_validation=True) + _ = client2 + def test_default_query_option(self) -> None: client = Increase( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} @@ -668,9 +677,9 @@ def test_copy(self) -> None: copied = self.client.copy() assert id(copied) != id(self.client) - copied = self.client.copy(api_key="my new api key") - assert copied.api_key == "my new api key" - assert self.client.api_key == api_key + copied = self.client.copy(api_key="another My API Key") + assert copied.api_key == "another My API Key" + assert self.client.api_key == "My API Key" def test_copy_default_options(self) -> None: # options that have a default are overridden correctly @@ -846,6 +855,15 @@ def test_default_headers_option(self) -> None: assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + def test_validate_headers(self) -> None: + client = AsyncIncrease(base_url=base_url, api_key=api_key, _strict_response_validation=True) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("Authorization") == f"Bearer {api_key}" + + with pytest.raises(Exception): + client2 = AsyncIncrease(base_url=base_url, api_key=None, _strict_response_validation=True) + _ = client2 + def test_default_query_option(self) -> None: client = AsyncIncrease( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} From 712448e48baa1b25b5b556ae0a9a68a239c3b88d Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 12 Oct 2023 08:50:28 +0100 Subject: [PATCH 03/22] feat(client): add logging setup (#154) --- README.md | 10 ++++++++++ pyproject.toml | 2 -- src/increase/__init__.py | 3 +++ src/increase/_base_client.py | 17 +++++++++++++++-- src/increase/_compat.py | 20 +++++++++++++++++--- src/increase/_types.py | 3 +++ src/increase/_utils/_logs.py | 25 +++++++++++++++++++++++++ tests/conftest.py | 3 +++ 8 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 src/increase/_utils/_logs.py diff --git a/README.md b/README.md index badec297f..ee46644ca 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,16 @@ Note that requests that time out are [retried twice by default](#retries). ## Advanced +### Logging + +We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. + +You can enable logging by setting the environment variable `INCREASE_LOG` to `debug`. + +```shell +$ export INCREASE_LOG=debug +``` + ### How to tell whether `None` means `null` or missing In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: diff --git a/pyproject.toml b/pyproject.toml index ab2d14b04..3169a1adc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,8 +47,6 @@ target-version = ["py37"] testpaths = ["tests"] addopts = "--tb=short" xfail_strict = true -log_cli = true -log_level = "INFO" asyncio_mode = "auto" filterwarnings = [ "error" diff --git a/src/increase/__init__.py b/src/increase/__init__.py index 5f0270fea..442e3fa38 100644 --- a/src/increase/__init__.py +++ b/src/increase/__init__.py @@ -45,6 +45,7 @@ IdempotencyUnprocessableError, UniqueIdentifierAlreadyExistsError, ) +from ._utils._logs import setup_logging as _setup_logging __all__ = [ "types", @@ -92,6 +93,8 @@ "file_from_path", ] +_setup_logging() + # Update the __module__ attribute for exported symbols so that # error messages point to this module instead of the module # it was originally defined in, e.g. diff --git a/src/increase/_base_client.py b/src/increase/_base_client.py index 71b70bcda..858f2e700 100644 --- a/src/increase/_base_client.py +++ b/src/increase/_base_client.py @@ -5,6 +5,7 @@ import uuid import email import inspect +import logging import platform import warnings import email.utils @@ -60,7 +61,7 @@ ModelBuilderProtocol, ) from ._utils import is_dict, is_given, is_mapping -from ._compat import model_copy +from ._compat import model_copy, model_dump from ._models import ( BaseModel, GenericModel, @@ -76,6 +77,8 @@ APIResponseValidationError, ) +log: logging.Logger = logging.getLogger(__name__) + # TODO: make base page type vars covariant SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]") AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]") @@ -428,7 +431,8 @@ def _build_request( self, options: FinalRequestOptions, ) -> httpx.Request: - headers = self._build_headers(options) + if log.isEnabledFor(logging.DEBUG): + log.debug("Request options: %s", model_dump(options, exclude_unset=True)) kwargs: dict[str, Any] = {} @@ -441,6 +445,7 @@ def _build_request( else: raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") + headers = self._build_headers(options) params = _merge_mappings(self._custom_query, options.params) # If the given Content-Type header is multipart/form-data then it @@ -893,6 +898,9 @@ def _request( try: response = self._client.send(request, auth=self.custom_auth, stream=stream) + log.debug( + 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase + ) response.raise_for_status() except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code if retries > 0 and self._should_retry(err.response): @@ -941,6 +949,7 @@ def _retry_request( ) -> ResponseT | _StreamT: remaining = remaining_retries - 1 timeout = self._calculate_retry_timeout(remaining, options, response_headers) + log.info("Retrying request to %s in %f seconds", options.url, timeout) # In a synchronous context we are blocking the entire thread. Up to the library user to run the client in a # different thread if necessary. @@ -1292,6 +1301,9 @@ async def _request( try: response = await self._client.send(request, auth=self.custom_auth, stream=stream) + log.debug( + 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase + ) response.raise_for_status() except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code if retries > 0 and self._should_retry(err.response): @@ -1350,6 +1362,7 @@ async def _retry_request( ) -> ResponseT | _AsyncStreamT: remaining = remaining_retries - 1 timeout = self._calculate_retry_timeout(remaining, options, response_headers) + log.info("Retrying request to %s in %f seconds", options.url, timeout) await anyio.sleep(timeout) diff --git a/src/increase/_compat.py b/src/increase/_compat.py index fed1df050..5a7ce61b3 100644 --- a/src/increase/_compat.py +++ b/src/increase/_compat.py @@ -126,10 +126,24 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: return model.json(indent=indent) # type: ignore -def model_dump(model: pydantic.BaseModel) -> dict[str, Any]: +def model_dump( + model: pydantic.BaseModel, + *, + exclude_unset: bool = False, + exclude_defaults: bool = False, +) -> dict[str, Any]: if PYDANTIC_V2: - return model.model_dump() - return cast("dict[str, Any]", model.dict()) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + return model.model_dump( + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + ) + return cast( + "dict[str, Any]", + model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + ), + ) def model_parse(model: type[_ModelT], data: Any) -> _ModelT: diff --git a/src/increase/_types.py b/src/increase/_types.py index b6819b957..2b3cd8040 100644 --- a/src/increase/_types.py +++ b/src/increase/_types.py @@ -104,6 +104,9 @@ def get(timeout: Union[int, NotGiven, None] = NotGiven()) -> Response: ... def __bool__(self) -> Literal[False]: return False + def __repr__(self) -> str: + return "NOT_GIVEN" + NotGivenOr = Union[_T, NotGiven] NOT_GIVEN = NotGiven() diff --git a/src/increase/_utils/_logs.py b/src/increase/_utils/_logs.py new file mode 100644 index 000000000..578be3316 --- /dev/null +++ b/src/increase/_utils/_logs.py @@ -0,0 +1,25 @@ +import os +import logging + +logger: logging.Logger = logging.getLogger("increase") +httpx_logger: logging.Logger = logging.getLogger("httpx") + + +def _basic_config() -> None: + # e.g. [2023-10-05 14:12:26 - increase._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" + logging.basicConfig( + format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + +def setup_logging() -> None: + env = os.environ.get("INCREASE_LOG") + if env == "debug": + _basic_config() + logger.setLevel(logging.DEBUG) + httpx_logger.setLevel(logging.DEBUG) + elif env == "info": + _basic_config() + logger.setLevel(logging.INFO) + httpx_logger.setLevel(logging.INFO) diff --git a/tests/conftest.py b/tests/conftest.py index dd8bbe4c8..45450a3cd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,10 +1,13 @@ import asyncio +import logging from typing import Iterator import pytest pytest.register_assert_rewrite("tests.utils") +logging.getLogger("increase").setLevel(logging.DEBUG) + @pytest.fixture(scope="session") def event_loop() -> Iterator[asyncio.AbstractEventLoop]: From 9d757a11276040923f22ef6155840ab3bbb8b635 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 12 Oct 2023 14:00:40 +0100 Subject: [PATCH 04/22] fix(client): correctly handle arguments with env vars (#155) --- src/increase/_client.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/increase/_client.py b/src/increase/_client.py index 50d4b075d..891bc4022 100644 --- a/src/increase/_client.py +++ b/src/increase/_client.py @@ -101,7 +101,7 @@ class Increase(SyncAPIClient): def __init__( self, *, - api_key: str | None = os.environ.get("INCREASE_API_KEY", None), + api_key: str | None = None, environment: Literal["production", "sandbox"] = "production", base_url: Optional[str] = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, @@ -130,6 +130,8 @@ def __init__( This automatically infers the `api_key` argument from the `INCREASE_API_KEY` environment variable if it is not provided. """ + if api_key is None: + api_key = os.environ.get("INCREASE_API_KEY") if api_key is None: raise IncreaseError( "The api_key client option must be set either by passing api_key to the client or by setting the INCREASE_API_KEY environment variable" @@ -427,7 +429,7 @@ class AsyncIncrease(AsyncAPIClient): def __init__( self, *, - api_key: str | None = os.environ.get("INCREASE_API_KEY", None), + api_key: str | None = None, environment: Literal["production", "sandbox"] = "production", base_url: Optional[str] = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, @@ -456,6 +458,8 @@ def __init__( This automatically infers the `api_key` argument from the `INCREASE_API_KEY` environment variable if it is not provided. """ + if api_key is None: + api_key = os.environ.get("INCREASE_API_KEY") if api_key is None: raise IncreaseError( "The api_key client option must be set either by passing api_key to the client or by setting the INCREASE_API_KEY environment variable" From 1873cfe73a9496fd39534288f9db67ad169ef05e Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:49:59 +0100 Subject: [PATCH 05/22] ci: before first major release use a minor version update for feature changes (#156) --- release-please-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-please-config.json b/release-please-config.json index 11000413c..73f0c9cb1 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -6,7 +6,7 @@ "include-v-in-tag": true, "include-component-in-tag": false, "bump-minor-pre-major": true, - "bump-patch-for-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, "pull-request-header": "Automated Release PR", "pull-request-title-pattern": "release: ${version}", "changelog-sections": [ From 9240b3a492872bc2740dd57573c947b3b5047a97 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Fri, 13 Oct 2023 00:01:54 +0100 Subject: [PATCH 06/22] chore: add case insensitive get header function (#157) --- src/increase/_utils/__init__.py | 1 + src/increase/_utils/_utils.py | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/increase/_utils/__init__.py b/src/increase/_utils/__init__.py index 6d13a3629..26dc560b0 100644 --- a/src/increase/_utils/__init__.py +++ b/src/increase/_utils/__init__.py @@ -22,6 +22,7 @@ from ._utils import is_required_type as is_required_type from ._utils import is_annotated_type as is_annotated_type from ._utils import maybe_coerce_float as maybe_coerce_float +from ._utils import get_required_header as get_required_header from ._utils import maybe_coerce_boolean as maybe_coerce_boolean from ._utils import maybe_coerce_integer as maybe_coerce_integer from ._utils import strip_annotated_type as strip_annotated_type diff --git a/src/increase/_utils/_utils.py b/src/increase/_utils/_utils.py index e43ef6f89..d4eafd4c2 100644 --- a/src/increase/_utils/_utils.py +++ b/src/increase/_utils/_utils.py @@ -1,13 +1,14 @@ from __future__ import annotations import os +import re import inspect import functools from typing import Any, Mapping, TypeVar, Callable, Iterable, Sequence, cast, overload from pathlib import Path from typing_extensions import Required, Annotated, TypeGuard, get_args, get_origin -from .._types import NotGiven, FileTypes, NotGivenOr +from .._types import Headers, NotGiven, FileTypes, NotGivenOr, HeadersLike from .._compat import is_union as _is_union from .._compat import parse_date as parse_date from .._compat import parse_datetime as parse_datetime @@ -351,3 +352,22 @@ def file_from_path(path: str) -> FileTypes: contents = Path(path).read_bytes() file_name = os.path.basename(path) return (file_name, contents) + + +def get_required_header(headers: HeadersLike, header: str) -> str: + lower_header = header.lower() + if isinstance(headers, Mapping): + headers = cast(Headers, headers) + for k, v in headers.items(): + if k.lower() == lower_header and isinstance(v, str): + return v + + """ to deal with the case where the header looks like Finch-Event-Id """ + intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) + + for normalized_header in [header, lower_header, header.upper(), intercaps_header]: + value = headers.get(normalized_header) + if value: + return value + + raise ValueError(f"Could not find {header} header") From e75c268391ff2eaae0c050e8bcecea1d6d29bc24 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Fri, 13 Oct 2023 15:51:16 +0100 Subject: [PATCH 07/22] chore: update comment (#158) --- src/increase/_utils/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/increase/_utils/_utils.py b/src/increase/_utils/_utils.py index d4eafd4c2..992b016f9 100644 --- a/src/increase/_utils/_utils.py +++ b/src/increase/_utils/_utils.py @@ -362,7 +362,7 @@ def get_required_header(headers: HeadersLike, header: str) -> str: if k.lower() == lower_header and isinstance(v, str): return v - """ to deal with the case where the header looks like Finch-Event-Id """ + """ to deal with the case where the header looks like Stainless-Event-Id """ intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) for normalized_header in [header, lower_header, header.upper(), intercaps_header]: From 9b23b62b0ce84ba6b18a76e4121b971a42695c3b Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Fri, 13 Oct 2023 21:41:04 +0100 Subject: [PATCH 08/22] chore(internal): enable lint rule (#159) --- pyproject.toml | 2 ++ src/increase/_base_client.py | 13 ++++++++++--- src/increase/_compat.py | 14 +++++++------- src/increase/_exceptions.py | 2 +- tests/test_models.py | 2 +- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3169a1adc..3543c4df3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,6 +81,8 @@ select = [ "F401", # bare except statements "E722", + # unused arguments + "ARG", # print statements "T201", "T203", diff --git a/src/increase/_base_client.py b/src/increase/_base_client.py index 858f2e700..351324c99 100644 --- a/src/increase/_base_client.py +++ b/src/increase/_base_client.py @@ -405,7 +405,10 @@ def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: return headers - def _prepare_request(self, request: httpx.Request) -> None: + def _prepare_request( + self, + request: httpx.Request, # noqa: ARG002 + ) -> None: """This method is used as a callback for mutating the `Request` object after it has been constructed. @@ -509,7 +512,7 @@ def _process_response( self, *, cast_to: Type[ResponseT], - options: FinalRequestOptions, + options: FinalRequestOptions, # noqa: ARG002 response: httpx.Response, ) -> ResponseT: if cast_to is NoneType: @@ -616,7 +619,11 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } - def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + def _validate_headers( + self, + headers: Headers, # noqa: ARG002 + custom_headers: Headers, # noqa: ARG002 + ) -> None: """Validate the given default headers and custom headers. Does nothing by default. diff --git a/src/increase/_compat.py b/src/increase/_compat.py index 5a7ce61b3..34323c9b7 100644 --- a/src/increase/_compat.py +++ b/src/increase/_compat.py @@ -20,25 +20,25 @@ # v1 re-exports if TYPE_CHECKING: - def parse_date(value: date | StrBytesIntFloat) -> date: + def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 ... - def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 ... - def get_args(t: type[Any]) -> tuple[Any, ...]: + def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 ... - def is_union(tp: type[Any] | None) -> bool: + def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 ... - def get_origin(t: type[Any]) -> type[Any] | None: + def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 ... - def is_literal_type(type_: type[Any]) -> bool: + def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 ... - def is_typeddict(type_: type[Any]) -> bool: + def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 ... else: diff --git a/src/increase/_exceptions.py b/src/increase/_exceptions.py index 2dc9414fb..23cde1015 100644 --- a/src/increase/_exceptions.py +++ b/src/increase/_exceptions.py @@ -53,7 +53,7 @@ class APIError(IncreaseError): If there was no response associated with this error then it will be `None`. """ - def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: + def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: # noqa: ARG002 super().__init__(message) self.request = request self.message = message diff --git a/tests/test_models.py b/tests/test_models.py index 888f8c5fc..3eeab526c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -553,7 +553,7 @@ class Model(BaseModel): def test_type_compat() -> None: # our model type can be assigned to Pydantic's model type - def takes_pydantic(model: pydantic.BaseModel) -> None: + def takes_pydantic(model: pydantic.BaseModel) -> None: # noqa: ARG001 ... class OurModel(BaseModel): From 7bad83fa5931974df2d8249a0fc98f3ea9d2d5de Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Sat, 14 Oct 2023 16:38:40 +0100 Subject: [PATCH 09/22] fix(streaming): add additional overload for ambiguous stream param (#160) --- pyproject.toml | 2 -- src/increase/_base_client.py | 13 +++---------- src/increase/_compat.py | 14 +++++++------- src/increase/_exceptions.py | 2 +- tests/test_models.py | 2 +- 5 files changed, 12 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3543c4df3..3169a1adc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,8 +81,6 @@ select = [ "F401", # bare except statements "E722", - # unused arguments - "ARG", # print statements "T201", "T203", diff --git a/src/increase/_base_client.py b/src/increase/_base_client.py index 351324c99..858f2e700 100644 --- a/src/increase/_base_client.py +++ b/src/increase/_base_client.py @@ -405,10 +405,7 @@ def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: return headers - def _prepare_request( - self, - request: httpx.Request, # noqa: ARG002 - ) -> None: + def _prepare_request(self, request: httpx.Request) -> None: """This method is used as a callback for mutating the `Request` object after it has been constructed. @@ -512,7 +509,7 @@ def _process_response( self, *, cast_to: Type[ResponseT], - options: FinalRequestOptions, # noqa: ARG002 + options: FinalRequestOptions, response: httpx.Response, ) -> ResponseT: if cast_to is NoneType: @@ -619,11 +616,7 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } - def _validate_headers( - self, - headers: Headers, # noqa: ARG002 - custom_headers: Headers, # noqa: ARG002 - ) -> None: + def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: """Validate the given default headers and custom headers. Does nothing by default. diff --git a/src/increase/_compat.py b/src/increase/_compat.py index 34323c9b7..5a7ce61b3 100644 --- a/src/increase/_compat.py +++ b/src/increase/_compat.py @@ -20,25 +20,25 @@ # v1 re-exports if TYPE_CHECKING: - def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 + def parse_date(value: date | StrBytesIntFloat) -> date: ... - def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 + def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: ... - def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 + def get_args(t: type[Any]) -> tuple[Any, ...]: ... - def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 + def is_union(tp: type[Any] | None) -> bool: ... - def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 + def get_origin(t: type[Any]) -> type[Any] | None: ... - def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 + def is_literal_type(type_: type[Any]) -> bool: ... - def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 + def is_typeddict(type_: type[Any]) -> bool: ... else: diff --git a/src/increase/_exceptions.py b/src/increase/_exceptions.py index 23cde1015..2dc9414fb 100644 --- a/src/increase/_exceptions.py +++ b/src/increase/_exceptions.py @@ -53,7 +53,7 @@ class APIError(IncreaseError): If there was no response associated with this error then it will be `None`. """ - def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: # noqa: ARG002 + def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: super().__init__(message) self.request = request self.message = message diff --git a/tests/test_models.py b/tests/test_models.py index 3eeab526c..888f8c5fc 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -553,7 +553,7 @@ class Model(BaseModel): def test_type_compat() -> None: # our model type can be assigned to Pydantic's model type - def takes_pydantic(model: pydantic.BaseModel) -> None: # noqa: ARG001 + def takes_pydantic(model: pydantic.BaseModel) -> None: ... class OurModel(BaseModel): From 5325526dc4826a96a9f18ef95b2729d23842877d Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Sat, 14 Oct 2023 16:47:35 +0100 Subject: [PATCH 10/22] chore(internal): cleanup some redundant code (#161) --- pyproject.toml | 2 ++ src/increase/_base_client.py | 13 ++++++++++--- src/increase/_compat.py | 14 +++++++------- src/increase/_exceptions.py | 2 +- tests/test_models.py | 2 +- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3169a1adc..3543c4df3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,6 +81,8 @@ select = [ "F401", # bare except statements "E722", + # unused arguments + "ARG", # print statements "T201", "T203", diff --git a/src/increase/_base_client.py b/src/increase/_base_client.py index 858f2e700..351324c99 100644 --- a/src/increase/_base_client.py +++ b/src/increase/_base_client.py @@ -405,7 +405,10 @@ def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: return headers - def _prepare_request(self, request: httpx.Request) -> None: + def _prepare_request( + self, + request: httpx.Request, # noqa: ARG002 + ) -> None: """This method is used as a callback for mutating the `Request` object after it has been constructed. @@ -509,7 +512,7 @@ def _process_response( self, *, cast_to: Type[ResponseT], - options: FinalRequestOptions, + options: FinalRequestOptions, # noqa: ARG002 response: httpx.Response, ) -> ResponseT: if cast_to is NoneType: @@ -616,7 +619,11 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } - def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: + def _validate_headers( + self, + headers: Headers, # noqa: ARG002 + custom_headers: Headers, # noqa: ARG002 + ) -> None: """Validate the given default headers and custom headers. Does nothing by default. diff --git a/src/increase/_compat.py b/src/increase/_compat.py index 5a7ce61b3..34323c9b7 100644 --- a/src/increase/_compat.py +++ b/src/increase/_compat.py @@ -20,25 +20,25 @@ # v1 re-exports if TYPE_CHECKING: - def parse_date(value: date | StrBytesIntFloat) -> date: + def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 ... - def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 ... - def get_args(t: type[Any]) -> tuple[Any, ...]: + def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 ... - def is_union(tp: type[Any] | None) -> bool: + def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 ... - def get_origin(t: type[Any]) -> type[Any] | None: + def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 ... - def is_literal_type(type_: type[Any]) -> bool: + def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 ... - def is_typeddict(type_: type[Any]) -> bool: + def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 ... else: diff --git a/src/increase/_exceptions.py b/src/increase/_exceptions.py index 2dc9414fb..23cde1015 100644 --- a/src/increase/_exceptions.py +++ b/src/increase/_exceptions.py @@ -53,7 +53,7 @@ class APIError(IncreaseError): If there was no response associated with this error then it will be `None`. """ - def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: + def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: # noqa: ARG002 super().__init__(message) self.request = request self.message = message diff --git a/tests/test_models.py b/tests/test_models.py index 888f8c5fc..3eeab526c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -553,7 +553,7 @@ class Model(BaseModel): def test_type_compat() -> None: # our model type can be assigned to Pydantic's model type - def takes_pydantic(model: pydantic.BaseModel) -> None: + def takes_pydantic(model: pydantic.BaseModel) -> None: # noqa: ARG001 ... class OurModel(BaseModel): From 695f2bba42968196b058b6ff6c6ad2ec66fb1da3 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Mon, 16 Oct 2023 20:51:39 +0100 Subject: [PATCH 11/22] fix(client): accept io.IOBase instances in file params (#162) --- src/increase/_utils/_utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/increase/_utils/_utils.py b/src/increase/_utils/_utils.py index 992b016f9..cb660d16b 100644 --- a/src/increase/_utils/_utils.py +++ b/src/increase/_utils/_utils.py @@ -1,5 +1,6 @@ from __future__ import annotations +import io import os import re import inspect @@ -55,10 +56,10 @@ def _extract_items( return [] # We have exhausted the path, return the entry we found. - if not isinstance(obj, bytes) and not isinstance(obj, tuple): + if not isinstance(obj, bytes) and not isinstance(obj, tuple) and not isinstance(obj, io.IOBase): raise RuntimeError( - f"Expected entry at {flattened_key} to be bytes or a tuple but received {type(obj)} instead." - ) + f"Expected entry at {flattened_key} to be bytes, an io.IOBase instance or a tuple but received {type(obj)} instead." + ) from None # TODO: validate obj more? assert flattened_key is not None From bd21fa4e0c2648772066e3fa85a7adace525253a Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:21:27 +0100 Subject: [PATCH 12/22] docs: organisation -> organization (UK to US English) (#163) --- bin/check-release-environment | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/check-release-environment b/bin/check-release-environment index 86185436d..bc32397cf 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -3,11 +3,11 @@ errors=() if [ -z "${STAINLESS_API_KEY}" ]; then - errors+=("The STAINLESS_API_KEY secret has not been set. Please contact Stainless for an API key & set it in your organisation secrets on GitHub.") + errors+=("The STAINLESS_API_KEY secret has not been set. Please contact Stainless for an API key & set it in your organization secrets on GitHub.") fi if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The INCREASE_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organisation secrets.") + errors+=("The INCREASE_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") fi len=${#errors[@]} From e105b17235f182542a78ea13e5a2aaacdc937876 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 17 Oct 2023 15:16:00 +0100 Subject: [PATCH 13/22] docs: improve error message for invalid file param type (#164) --- src/increase/_utils/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/increase/_utils/_utils.py b/src/increase/_utils/_utils.py index cb660d16b..2a194ed7a 100644 --- a/src/increase/_utils/_utils.py +++ b/src/increase/_utils/_utils.py @@ -58,7 +58,7 @@ def _extract_items( # We have exhausted the path, return the entry we found. if not isinstance(obj, bytes) and not isinstance(obj, tuple) and not isinstance(obj, io.IOBase): raise RuntimeError( - f"Expected entry at {flattened_key} to be bytes, an io.IOBase instance or a tuple but received {type(obj)} instead." + f"Expected entry at {flattened_key} to be bytes, an io.IOBase instance or a tuple but received {type(obj)} instead. See https://github.com/increase/increase-python#file-uploads" ) from None # TODO: validate obj more? From 46c62bae4ca6684cfbfce0124101b8a556763b2d Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:10:54 +0100 Subject: [PATCH 14/22] feat(api): add addenda details for ACH transfers (#165) --- src/increase/types/check_transfer.py | 3 ++ .../beneficial_owner_create_params.py | 3 +- src/increase/types/entity_create_params.py | 3 +- src/increase/types/inbound_ach_transfer.py | 37 ++++++++++++++++++- .../simulations/ach_transfer_simulation.py | 30 +++++++++++++++ ...ime_payments_transfer_simulation_result.py | 3 ++ .../interest_payment_simulation_result.py | 3 ++ .../simulations/wire_transfer_simulation.py | 3 ++ src/increase/types/transaction.py | 3 ++ 9 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/increase/types/check_transfer.py b/src/increase/types/check_transfer.py index c910e7c35..09d85ef04 100644 --- a/src/increase/types/check_transfer.py +++ b/src/increase/types/check_transfer.py @@ -74,6 +74,9 @@ class Deposit(BaseModel): transaction_id: Optional[str] """The identifier of the Transaction object created when the check was deposited.""" + transfer_id: str + """The identifier of the Check Transfer object that was deposited.""" + type: Literal["check_transfer_deposit"] """A constant representing the object's type. diff --git a/src/increase/types/entities/beneficial_owner_create_params.py b/src/increase/types/entities/beneficial_owner_create_params.py index 3d9406cc8..bf512bb26 100644 --- a/src/increase/types/entities/beneficial_owner_create_params.py +++ b/src/increase/types/entities/beneficial_owner_create_params.py @@ -173,7 +173,8 @@ class BeneficialOwner(TypedDict, total=False): prongs: Required[List[Literal["ownership", "control"]]] """Why this person is considered a beneficial owner of the entity. - At least one option is required. + At least one option is required, if a person is both a control person and owner, + submit an array containing both. """ company_title: str diff --git a/src/increase/types/entity_create_params.py b/src/increase/types/entity_create_params.py index d395bf19f..102b1e04f 100644 --- a/src/increase/types/entity_create_params.py +++ b/src/increase/types/entity_create_params.py @@ -265,7 +265,8 @@ class CorporationBeneficialOwner(TypedDict, total=False): prongs: Required[List[Literal["ownership", "control"]]] """Why this person is considered a beneficial owner of the entity. - At least one option is required. + At least one option is required, if a person is both a control person and owner, + submit an array containing both. """ company_title: str diff --git a/src/increase/types/inbound_ach_transfer.py b/src/increase/types/inbound_ach_transfer.py index 68e1f991f..c41b25a63 100644 --- a/src/increase/types/inbound_ach_transfer.py +++ b/src/increase/types/inbound_ach_transfer.py @@ -1,12 +1,21 @@ # File generated from our OpenAPI spec by Stainless. -from typing import Optional +from typing import List, Optional from datetime import datetime from typing_extensions import Literal from .._models import BaseModel -__all__ = ["InboundACHTransfer", "Acceptance", "Decline", "NotificationOfChange", "TransferReturn"] +__all__ = [ + "InboundACHTransfer", + "Acceptance", + "Addenda", + "AddendaFreeform", + "AddendaFreeformEntry", + "Decline", + "NotificationOfChange", + "TransferReturn", +] class Acceptance(BaseModel): @@ -17,6 +26,27 @@ class Acceptance(BaseModel): """The id of the transaction for the accepted transfer.""" +class AddendaFreeformEntry(BaseModel): + payment_related_information: str + """The payment related information passed in the addendum.""" + + +class AddendaFreeform(BaseModel): + entries: List[AddendaFreeformEntry] + """Each entry represents an addendum received from the originator.""" + + +class Addenda(BaseModel): + category: Literal["freeform"] + """The type of addendum. + + - `freeform` - Unstructured addendum. + """ + + freeform: Optional[AddendaFreeform] + """Unstructured `payment_related_information` passed through by the originator.""" + + class Decline(BaseModel): declined_at: datetime """The time at which the transfer was declined.""" @@ -123,6 +153,9 @@ class InboundACHTransfer(BaseModel): account_number_id: str """The identifier of the Account Number to which this transfer was sent.""" + addenda: Optional[Addenda] + """Additional information sent from the originator.""" + amount: int """The transfer amount in USD cents.""" diff --git a/src/increase/types/simulations/ach_transfer_simulation.py b/src/increase/types/simulations/ach_transfer_simulation.py index bcf3f7fcf..a2e72ba1b 100644 --- a/src/increase/types/simulations/ach_transfer_simulation.py +++ b/src/increase/types/simulations/ach_transfer_simulation.py @@ -64,6 +64,9 @@ "TransactionSourceWireTransferRejection", "Transfer", "TransferAcceptance", + "TransferAddenda", + "TransferAddendaFreeform", + "TransferAddendaFreeformEntry", "TransferDecline", "TransferNotificationOfChange", "TransferTransferReturn", @@ -2373,6 +2376,9 @@ class TransactionSourceCheckTransferDeposit(BaseModel): transaction_id: Optional[str] """The identifier of the Transaction object created when the check was deposited.""" + transfer_id: str + """The identifier of the Check Transfer object that was deposited.""" + type: Literal["check_transfer_deposit"] """A constant representing the object's type. @@ -3579,6 +3585,27 @@ class TransferAcceptance(BaseModel): """The id of the transaction for the accepted transfer.""" +class TransferAddendaFreeformEntry(BaseModel): + payment_related_information: str + """The payment related information passed in the addendum.""" + + +class TransferAddendaFreeform(BaseModel): + entries: List[TransferAddendaFreeformEntry] + """Each entry represents an addendum received from the originator.""" + + +class TransferAddenda(BaseModel): + category: Literal["freeform"] + """The type of addendum. + + - `freeform` - Unstructured addendum. + """ + + freeform: Optional[TransferAddendaFreeform] + """Unstructured `payment_related_information` passed through by the originator.""" + + class TransferDecline(BaseModel): declined_at: datetime """The time at which the transfer was declined.""" @@ -3685,6 +3712,9 @@ class Transfer(BaseModel): account_number_id: str """The identifier of the Account Number to which this transfer was sent.""" + addenda: Optional[TransferAddenda] + """Additional information sent from the originator.""" + amount: int """The transfer amount in USD cents.""" diff --git a/src/increase/types/simulations/inbound_real_time_payments_transfer_simulation_result.py b/src/increase/types/simulations/inbound_real_time_payments_transfer_simulation_result.py index ccab080af..89715de8c 100644 --- a/src/increase/types/simulations/inbound_real_time_payments_transfer_simulation_result.py +++ b/src/increase/types/simulations/inbound_real_time_payments_transfer_simulation_result.py @@ -2368,6 +2368,9 @@ class TransactionSourceCheckTransferDeposit(BaseModel): transaction_id: Optional[str] """The identifier of the Transaction object created when the check was deposited.""" + transfer_id: str + """The identifier of the Check Transfer object that was deposited.""" + type: Literal["check_transfer_deposit"] """A constant representing the object's type. diff --git a/src/increase/types/simulations/interest_payment_simulation_result.py b/src/increase/types/simulations/interest_payment_simulation_result.py index 4ff0d961a..6445212fe 100644 --- a/src/increase/types/simulations/interest_payment_simulation_result.py +++ b/src/increase/types/simulations/interest_payment_simulation_result.py @@ -1500,6 +1500,9 @@ class TransactionSourceCheckTransferDeposit(BaseModel): transaction_id: Optional[str] """The identifier of the Transaction object created when the check was deposited.""" + transfer_id: str + """The identifier of the Check Transfer object that was deposited.""" + type: Literal["check_transfer_deposit"] """A constant representing the object's type. diff --git a/src/increase/types/simulations/wire_transfer_simulation.py b/src/increase/types/simulations/wire_transfer_simulation.py index be2b6876a..13ed66a80 100644 --- a/src/increase/types/simulations/wire_transfer_simulation.py +++ b/src/increase/types/simulations/wire_transfer_simulation.py @@ -1500,6 +1500,9 @@ class TransactionSourceCheckTransferDeposit(BaseModel): transaction_id: Optional[str] """The identifier of the Transaction object created when the check was deposited.""" + transfer_id: str + """The identifier of the Check Transfer object that was deposited.""" + type: Literal["check_transfer_deposit"] """A constant representing the object's type. diff --git a/src/increase/types/transaction.py b/src/increase/types/transaction.py index 066cde438..df0c0b5d7 100644 --- a/src/increase/types/transaction.py +++ b/src/increase/types/transaction.py @@ -1499,6 +1499,9 @@ class SourceCheckTransferDeposit(BaseModel): transaction_id: Optional[str] """The identifier of the Transaction object created when the check was deposited.""" + transfer_id: str + """The identifier of the Check Transfer object that was deposited.""" + type: Literal["check_transfer_deposit"] """A constant representing the object's type. From 3e81c88e0fa8bf0e3feae148b99e6f4d335c98f5 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 17 Oct 2023 18:28:12 +0100 Subject: [PATCH 15/22] chore(internal): migrate from Poetry to Rye (#166) --- .github/workflows/create-releases.yml | 12 +- .github/workflows/publish-pypi.yml | 12 +- .gitignore | 2 + bin/publish-pypi | 5 +- bin/test | 2 +- noxfile.py | 9 +- poetry.lock | 1057 ------------------------- pyproject.toml | 78 +- requirements-dev.lock | 53 ++ requirements.lock | 23 + src/increase/_models.py | 3 +- 11 files changed, 152 insertions(+), 1104 deletions(-) delete mode 100644 poetry.lock create mode 100644 requirements-dev.lock create mode 100644 requirements.lock diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 83bbb778e..fea978c43 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -19,16 +19,18 @@ jobs: repo: ${{ github.event.repository.full_name }} stainless-api-key: ${{ secrets.STAINLESS_API_KEY }} - - name: Set up Python + - name: Install Rye if: ${{ steps.release.outputs.releases_created }} - uses: actions/setup-python@v4 - with: - python-version: '3.7' + run: | + curl -sSf https://rye-up.com/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: 0.15.2 + RYE_INSTALL_OPTION: "--yes" - name: Publish to PyPI if: ${{ steps.release.outputs.releases_created }} run: | - pipx install poetry bash ./bin/publish-pypi env: PYPI_TOKEN: ${{ secrets.INCREASE_PYPI_TOKEN }} diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index d2204346e..3a8a33bf0 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -12,14 +12,16 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.7' + - name: Install Rye + run: | + curl -sSf https://rye-up.com/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: 0.15.2 + RYE_INSTALL_OPTION: "--yes" - name: Publish to PyPI run: | - pipx install poetry bash ./bin/publish-pypi env: PYPI_TOKEN: ${{ secrets.INCREASE_PYPI_TOKEN }} diff --git a/.gitignore b/.gitignore index de32a7e48..04a4e0397 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,7 @@ __pycache__ dist +.venv + .env codegen.log diff --git a/bin/publish-pypi b/bin/publish-pypi index ea5ab2caa..ad584347d 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -eux -poetry config pypi-token.pypi $PYPI_TOKEN -poetry publish --build +mkdir dist +rye build --clean +rye publish --yes --token=$PYPI_TOKEN diff --git a/bin/test b/bin/test index ac2844562..60ede7a84 100755 --- a/bin/test +++ b/bin/test @@ -1,3 +1,3 @@ #!/usr/bin/env bash -bin/check-test-server && poetry run pytest "$@" +bin/check-test-server && rye run pytest "$@" diff --git a/noxfile.py b/noxfile.py index 669f6af73..53bca7ff2 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,12 +1,9 @@ import nox -import nox_poetry -@nox_poetry.session(reuse_venv=True, name="test-pydantic-v1") +@nox.session(reuse_venv=True, name="test-pydantic-v1") def test_pydantic_v1(session: nox.Session) -> None: - session.run_always("poetry", "install", external=True) - - # https://github.com/cjolowicz/nox-poetry/issues/1116 - session._session.run("python", "-m", "pip", "install", "pydantic<2", external=True) # type: ignore + session.install("-r", "requirements-dev.lock") + session.install("pydantic<2") session.run("pytest", "--showlocals", "--ignore=tests/functional", *session.posargs) diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index ffedd33d6..000000000 --- a/poetry.lock +++ /dev/null @@ -1,1057 +0,0 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. - -[[package]] -name = "annotated-types" -version = "0.5.0" -description = "Reusable constraint types to use with typing.Annotated" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, - {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} - -[[package]] -name = "anyio" -version = "3.7.1" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, - {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, -] - -[package.dependencies] -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} -idna = ">=2.8" -sniffio = ">=1.1" -typing-extensions = {version = "*", markers = "python_version < \"3.8\""} - -[package.extras] -doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] -test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (<0.22)"] - -[[package]] -name = "argcomplete" -version = "3.1.1" -description = "Bash tab completion for argparse" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "argcomplete-3.1.1-py3-none-any.whl", hash = "sha256:35fa893a88deea85ea7b20d241100e64516d6af6d7b0ae2bed1d263d26f70948"}, - {file = "argcomplete-3.1.1.tar.gz", hash = "sha256:6c4c563f14f01440aaffa3eae13441c5db2357b5eec639abe7c0b15334627dff"}, -] - -[package.dependencies] -importlib-metadata = {version = ">=0.23,<7", markers = "python_version < \"3.8\""} - -[package.extras] -test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] - -[[package]] -name = "atomicwrites" -version = "1.4.1" -description = "Atomic file writes." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, -] - -[[package]] -name = "attrs" -version = "22.1.0" -description = "Classes Without Boilerplate" -category = "dev" -optional = false -python-versions = ">=3.5" -files = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, -] - -[package.extras] -dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] -docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] - -[[package]] -name = "black" -version = "23.3.0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, - {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, - {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, - {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, - {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, - {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, - {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, - {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, - {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, - {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, - {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, - {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, - {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, - {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "certifi" -version = "2023.7.22" -description = "Python package for providing Mozilla's CA Bundle." -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, -] - -[[package]] -name = "click" -version = "8.1.3" -description = "Composable command line interface toolkit" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "colorlog" -version = "6.7.0" -description = "Add colours to the output of Python's logging module." -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "colorlog-6.7.0-py2.py3-none-any.whl", hash = "sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662"}, - {file = "colorlog-6.7.0.tar.gz", hash = "sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} - -[package.extras] -development = ["black", "flake8", "mypy", "pytest", "types-colorama"] - -[[package]] -name = "distlib" -version = "0.3.7" -description = "Distribution utilities" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, - {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, -] - -[[package]] -name = "distro" -version = "1.8.0" -description = "Distro - an OS platform information API" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "distro-1.8.0-py3-none-any.whl", hash = "sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff"}, - {file = "distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8"}, -] - -[[package]] -name = "exceptiongroup" -version = "1.1.3" -description = "Backport of PEP 654 (exception groups)" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "filelock" -version = "3.12.2" -description = "A platform independent file lock." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, -] - -[package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] - -[[package]] -name = "h11" -version = "0.12.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, - {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, -] - -[[package]] -name = "httpcore" -version = "0.15.0" -description = "A minimal low-level HTTP client." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "httpcore-0.15.0-py3-none-any.whl", hash = "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6"}, - {file = "httpcore-0.15.0.tar.gz", hash = "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b"}, -] - -[package.dependencies] -anyio = ">=3.0.0,<4.0.0" -certifi = "*" -h11 = ">=0.11,<0.13" -sniffio = ">=1.0.0,<2.0.0" - -[package.extras] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] - -[[package]] -name = "httpx" -version = "0.23.0" -description = "The next generation HTTP client." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "httpx-0.23.0-py3-none-any.whl", hash = "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b"}, - {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, -] - -[package.dependencies] -certifi = "*" -httpcore = ">=0.15.0,<0.16.0" -rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} -sniffio = "*" - -[package.extras] -brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] - -[[package]] -name = "idna" -version = "3.4" -description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" -optional = false -python-versions = ">=3.5" -files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] - -[[package]] -name = "importlib-metadata" -version = "5.0.0" -description = "Read metadata from Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, - {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, -] - -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] - -[[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] - -[[package]] -name = "isort" -version = "5.10.1" -description = "A Python utility / library to sort Python imports." -category = "dev" -optional = false -python-versions = ">=3.6.1,<4.0" -files = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile-deprecated-finder = ["pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - -[[package]] -name = "mypy" -version = "1.4.1" -description = "Optional static typing for Python" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"}, - {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"}, - {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"}, - {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"}, - {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"}, - {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"}, - {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"}, - {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"}, - {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"}, - {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"}, - {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"}, - {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"}, - {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"}, - {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"}, - {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"}, - {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"}, - {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"}, - {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"}, - {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"}, - {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"}, - {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"}, - {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"}, - {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"}, - {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"}, - {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"}, - {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"}, -] - -[package.dependencies] -mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} -typing-extensions = ">=4.1.0" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -python2 = ["typed-ast (>=1.4.0,<2)"] -reports = ["lxml"] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "nodeenv" -version = "1.7.0" -description = "Node.js virtual environment builder" -category = "dev" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" -files = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, -] - -[package.dependencies] -setuptools = "*" - -[[package]] -name = "nox" -version = "2023.4.22" -description = "Flexible test automation." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "nox-2023.4.22-py3-none-any.whl", hash = "sha256:0b1adc619c58ab4fa57d6ab2e7823fe47a32e70202f287d78474adcc7bda1891"}, - {file = "nox-2023.4.22.tar.gz", hash = "sha256:46c0560b0dc609d7d967dc99e22cb463d3c4caf54a5fda735d6c11b5177e3a9f"}, -] - -[package.dependencies] -argcomplete = ">=1.9.4,<4.0" -colorlog = ">=2.6.1,<7.0.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -packaging = ">=20.9" -typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} -virtualenv = ">=14" - -[package.extras] -tox-to-nox = ["jinja2", "tox (<4)"] - -[[package]] -name = "nox-poetry" -version = "1.0.3" -description = "nox-poetry" -category = "dev" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "nox_poetry-1.0.3-py3-none-any.whl", hash = "sha256:a2fffeb70ae81840479e68287afe1c772bf376f70f1e92f99832a20b3c64d064"}, - {file = "nox_poetry-1.0.3.tar.gz", hash = "sha256:dc7ecbbd812a333a0c0b558f57e5b37f7c12926cddbcecaf2264957fd373824e"}, -] - -[package.dependencies] -nox = ">=2020.8.22" -packaging = ">=20.9" -tomlkit = ">=0.7" - -[[package]] -name = "packaging" -version = "23.1" -description = "Core utilities for Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, -] - -[[package]] -name = "pathspec" -version = "0.10.1" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, -] - -[[package]] -name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] - -[package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] - -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] - -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] - -[[package]] -name = "pydantic" -version = "2.2.0" -description = "Data validation using Python type hints" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pydantic-2.2.0-py3-none-any.whl", hash = "sha256:a479d511d1337ad091bd1ef90a7aaf707326968cff78a579108bc289b7f5ecdd"}, - {file = "pydantic-2.2.0.tar.gz", hash = "sha256:5f30f37a75bca15930e256da6a401f1cb953eb3bc578d454c0876f4e1459a7fa"}, -] - -[package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.6.0" -typing-extensions = ">=4.6.1" - -[package.extras] -email = ["email-validator (>=2.0.0)"] - -[[package]] -name = "pydantic-core" -version = "2.6.0" -description = "" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pydantic_core-2.6.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:2ae2d2aa91f442427d5d607f5bc07a6601aea7e9812c158b11dfac4fca28b24a"}, - {file = "pydantic_core-2.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cddecc97d923c3fae698820a788d6e7fda61538244dd2a0808d6263115fe5870"}, - {file = "pydantic_core-2.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:482a20567991170d0b55aa4d73084858ab8d54804ffef8061f254c0f8b9cf668"}, - {file = "pydantic_core-2.6.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:775710d825f2b2ffe8a0bfd8d17cb8de6a9e562e78f50171c5afa9c508faa45c"}, - {file = "pydantic_core-2.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4fd9661a30a370faae9303dfde31d09d5b6f28113f8dace9a63f51d205703a8d"}, - {file = "pydantic_core-2.6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e9430096484696a1837f55728c804917ad694f8e965ad0317ff896db21c3a7b"}, - {file = "pydantic_core-2.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:253d769ce88f6d5b8ae8965f08c486114e30b5e5478f327348b77615a2a543cb"}, - {file = "pydantic_core-2.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:959aa63057738b426137d3de99d8da118f5c8ba19a238fdb5e5f0717297e9da4"}, - {file = "pydantic_core-2.6.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c2c54ce857d0adb549fc735ffe84b9d1e77d1b460656fb2d3faa9050a85d8d37"}, - {file = "pydantic_core-2.6.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fe66139cfdd02ec4a0aad0cecf53bf9933c748097a97beb9042c03f236dd68b9"}, - {file = "pydantic_core-2.6.0-cp310-none-win32.whl", hash = "sha256:1781e985a9493f3fdca4c010fc6a009ab4fd40a61ab78e5cc9820eb8010c1c4c"}, - {file = "pydantic_core-2.6.0-cp310-none-win_amd64.whl", hash = "sha256:1d1b6c14c1116e797758bf1ff93ff18ab493279609aec6a60e6dee9de9065255"}, - {file = "pydantic_core-2.6.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:2f80f6790e87ec29ba28aab9a66b07ee789ec8fa6ea94aeac47e27f0019a061c"}, - {file = "pydantic_core-2.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:04d6de74f91ff1a88975bc5e3c7103b676106af380ce8d9b56649116e0855dc9"}, - {file = "pydantic_core-2.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c7507d40bd5d055dadba8ae9b6008356f380ce102942e0740228d97e8bd4152"}, - {file = "pydantic_core-2.6.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82e34dc040001f50bec1a7a5c09fb6566635078ce91943cd10445a560cb3fe23"}, - {file = "pydantic_core-2.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49848c89575d7768ea8762cc029f573a3d611452c41d05ae75bdcea8f77a9e5c"}, - {file = "pydantic_core-2.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04b0e91c338536e3e3f77c3ed5354d14c46163f1c6b0706037b0b4be409eb943"}, - {file = "pydantic_core-2.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6265372636a78bc6b8ba92f7d2dafca353c549edc8082a602d00a28f71a9155a"}, - {file = "pydantic_core-2.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:42caa59248750573efbce6a74f3e121f9def86dc2087772d51f0907c2ed6dc61"}, - {file = "pydantic_core-2.6.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fd29541fb6f7647f535c0067cabb50ec014f13fa599ac4e34152abb5cb046988"}, - {file = "pydantic_core-2.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e4d46cd802c163914f07124735371812e9bed8a39acbebcee5bd06d43f454e1a"}, - {file = "pydantic_core-2.6.0-cp311-none-win32.whl", hash = "sha256:75850d211015ae46e28b3e05ee0cc8687316505cad385170aff70ad60f143011"}, - {file = "pydantic_core-2.6.0-cp311-none-win_amd64.whl", hash = "sha256:ff462b08951adaf55dbcc623d9b57823e888ffa4886f902dfc2c69d6ddc1ce4b"}, - {file = "pydantic_core-2.6.0-cp311-none-win_arm64.whl", hash = "sha256:658f4e8afe60d8400526d6db28d4e88e76027cf6111716fc090de87d14b5c311"}, - {file = "pydantic_core-2.6.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:a7d7b5af9ee32517280228629daca013ecc9a7834075af3d928287539ccd54ec"}, - {file = "pydantic_core-2.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d03de66eda2c3a6eab2c2cf43eeece37e4cf811e891361b1fb8d8d3cd109f3a"}, - {file = "pydantic_core-2.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:693df3a922d94ba1c42ea732df7ab2f0492d6081b0170e86753a45e8822342a6"}, - {file = "pydantic_core-2.6.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf6cb8b9c23dbb074f2d97b02af4d9d5401bd8015daad3e92fc35f88c5c07ba6"}, - {file = "pydantic_core-2.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8aee2623180f736fc426925489e84bd244e45de4175dec76f10d4fda775721b"}, - {file = "pydantic_core-2.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582bfd6e7d09f5883f607b7171fcd2010d226497d9dfc9703c8aa8d58431fa84"}, - {file = "pydantic_core-2.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b52ce001eacd9906955576c71ee3fad9a442117b86dd84e5ea18e6ce287078d"}, - {file = "pydantic_core-2.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:179da6a5264d11cf2defba17c0003f6e27922d95f37b4818905115e2c9b8f7ed"}, - {file = "pydantic_core-2.6.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4118471f4ba0f92fbe84bb6c0f645b423eaa5453e0dc4b6c0a6759da818352ba"}, - {file = "pydantic_core-2.6.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:afd9d1ef2805729898f580ccde0e76a3edd39cf16778c2139222047c8d25893b"}, - {file = "pydantic_core-2.6.0-cp312-none-win32.whl", hash = "sha256:c029084413a8eeb7d7b179d647d1e1a5cbfd5e5a817862a0ba8c5024fc9febf2"}, - {file = "pydantic_core-2.6.0-cp312-none-win_amd64.whl", hash = "sha256:86a74d426ca995deb3c847a2b382775b93a306fce13ae7b66cdc5fb8090a3ac5"}, - {file = "pydantic_core-2.6.0-cp312-none-win_arm64.whl", hash = "sha256:5a878f37a144c5641ead8b0771164dd22237ed4013b9899f250f0992447114e0"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:f9ebd8c45c8729bb23bb902a5cff573996fe5d86c3fc8c17cde3443345533889"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:0faddd509ca1811d7e595cb48dc9b63d080a95f8434c5dc6660f268694f3c20f"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:859e11c4543bfd16b8033d50a2d7e4190fc5c6e182a6419b0d7c41109e3841b9"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f1a5fafbbadca467f426eb796bec61a908a670dfdcb984d300b9dd4d8b82433"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e3247b6d304226b12e240ff3fb0eb56b45520cd609d382fde6338a5556d44783"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67f7658ac47a88ea3859389c4a67713edce77ade653812e0a574bc8f0cb0d951"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:310a47d94895628d3563859cb970cad1b3ee7a5f2282d9bd5512b3c5a09d4379"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ee383e256a0e4b8bff1832fb31c530380a1421a714276ffd32609ce58a4c77a"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:148162967ede812466915bee671403dd2ded9822332df6c52866348129d4e58e"}, - {file = "pydantic_core-2.6.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d0d672be281d2e297f95ca301710aed9ad7e10c56a691337c2f22375feb60f29"}, - {file = "pydantic_core-2.6.0-cp37-none-win32.whl", hash = "sha256:ed683ff1663fd596ce84cf4d132f7ce7b94f0b60686ee06ca2c8e151ccb918e7"}, - {file = "pydantic_core-2.6.0-cp37-none-win_amd64.whl", hash = "sha256:301e47c7cabc1c435773fcf0c7278181add0f211ddaf4c683bbfb62e09457c33"}, - {file = "pydantic_core-2.6.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:14ec281d30dd1a7fbf62e0afe4bc7bfac4b5edcf8da7affef1a79e874f3899cb"}, - {file = "pydantic_core-2.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d13fc39e2d2957f32d8fa9d013bd7165d00c43890bdaea1e20a726873c50531b"}, - {file = "pydantic_core-2.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:905048671ef08f2a504cdf7e26ffbe88efd74494ba821f2cdb1e4b1506236047"}, - {file = "pydantic_core-2.6.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99b6004cd989bbcaf32e0794e6f42460b6f5ac047b2eb443a661cfdba29704e5"}, - {file = "pydantic_core-2.6.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bac3e606b7f8fffd5e3a0d7c5d6ab110075c9dc16b9f8932cb077b6d985f8de"}, - {file = "pydantic_core-2.6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77865eb89c646673bedc7de4acd0a076dd6bada2f01d010675031cd855b052cf"}, - {file = "pydantic_core-2.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdbc528c7c6fef0e9aa1b4ba620d707c9735cfc92e6b666b83862ee55faa9605"}, - {file = "pydantic_core-2.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7291e0e36c1bc5c3b20d3f3cf77ba9ac7a26423ec50781d4f0435c45ddfe18c2"}, - {file = "pydantic_core-2.6.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f693255ffec26a090c76adfb8f6286b76f5f3c9aa245f4bbe03aede102d815ef"}, - {file = "pydantic_core-2.6.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9e8d12016b2fdbf885e3c7580fa8f6d2e90838586faee511656f2022ebf71a2d"}, - {file = "pydantic_core-2.6.0-cp38-none-win32.whl", hash = "sha256:59420b2fe9edfdc640e79aac09461400862d2e699ca59e5b96e5595cc7554736"}, - {file = "pydantic_core-2.6.0-cp38-none-win_amd64.whl", hash = "sha256:757372e9b5c81cec72a077237d5d026ccd5ad9bf4931bebee4c92177d52b4eba"}, - {file = "pydantic_core-2.6.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:6798756a5bee9991af64763ee2f3580505932a3f432af9a73bc9fdaca460261f"}, - {file = "pydantic_core-2.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3170a13c8cdb564f544ce03a7f26962828cce3456413b325fca49d32ef47ed1f"}, - {file = "pydantic_core-2.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51eb518682898df170d3d2ddd9c1f2a9496d79e5bd611b508d1a698e50b13fc6"}, - {file = "pydantic_core-2.6.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe01f83bea0e4715c49449039b3c60a59408f0ceee61bb8c9a64699545e5b786"}, - {file = "pydantic_core-2.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11854f12f09d2a108d130645edbca7aecf24756455599b0b19dacd47499ccadc"}, - {file = "pydantic_core-2.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16c572a839eb584115185146a04b15986e19e3cbf00e3788f8296b16ec7b3fd5"}, - {file = "pydantic_core-2.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e89b0a3f05416a7e67ec7257cddcf44263a10cea618cfc89855d46997c13742"}, - {file = "pydantic_core-2.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5464f3d27376739c7fa0af47096ac3696db1d8996d086167b3643f0443a1a976"}, - {file = "pydantic_core-2.6.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ff7df99df6ae485e33afafc7adbfae2e133501b5debea4f0c20cd1f679fa321"}, - {file = "pydantic_core-2.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac4148c3bede4269f286c7d094e98c717f1101025145e89baacbafc7c5f7f74b"}, - {file = "pydantic_core-2.6.0-cp39-none-win32.whl", hash = "sha256:36d6211421a4dd6d11ccb08e9ac92d143132402403ab791688cfc01973ad3de1"}, - {file = "pydantic_core-2.6.0-cp39-none-win_amd64.whl", hash = "sha256:83f5a3e201fe16684c12e654423a0c293733a57a1f9a9f284dbfb1b59f0e79bb"}, - {file = "pydantic_core-2.6.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:eeb7b4e1dd925db174a410680c846cb7ab7eb1923f556b44cf53cea774dc42fa"}, - {file = "pydantic_core-2.6.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0b4bcc57b12980b67e5eed09732102b19380f79dcba09444faa7a5c1826a432"}, - {file = "pydantic_core-2.6.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5534040341ac6ad4d133023cd45da3654fff77795481c8e4d4508cafd248ba5"}, - {file = "pydantic_core-2.6.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:358f5d48aa850054ef1b148f4c3000b2ea216db4ab611039080bea294002349c"}, - {file = "pydantic_core-2.6.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f5ca934143857626de2423d65d487687c87931a62044ed5ee0deee55018569f4"}, - {file = "pydantic_core-2.6.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5b3159c893a1d6dc93080b882d7c4fa8651abbb228a4d920066f3f48b7a200ac"}, - {file = "pydantic_core-2.6.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5d9510004c4db5c683e349905c9700217da10b35d4447c7a1dfff1b6dd26192a"}, - {file = "pydantic_core-2.6.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fc54501cdffbc8a7dbe300d6e4745c910d767a1aa273febca965f5fa561036b1"}, - {file = "pydantic_core-2.6.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:6cc456fc3c7156b23866ab953d3ff57010ab6a4b79ba686109ef93581467f6c3"}, - {file = "pydantic_core-2.6.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aedc8671291d6ff17b9fc587fed982c4feeffdd28351c577695a5f07945c4625"}, - {file = "pydantic_core-2.6.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997fa26fd71c5d8676fa6dfefc06be1fac65fd578934d40e7546c047b7bdd019"}, - {file = "pydantic_core-2.6.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4f346c8fbd953f47711c388d9b856cad87cf72a714302bc04056f89d6ac55388"}, - {file = "pydantic_core-2.6.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d61acd378c38bdcc1c109605831695eb27bd755d1fc5c765e40878601bd0c66b"}, - {file = "pydantic_core-2.6.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3427ca73cffe42297bbb0ed712642d8484c42671b329441a2e51ce139f7e2f93"}, - {file = "pydantic_core-2.6.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:dabfdc82432499ceb33bb204fa0e5c0004a7dc1d85ba0250c5849ddfddd94819"}, - {file = "pydantic_core-2.6.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:10da8e685fe25be11089a666346461e01e23164688a224e33fee25d2a86da4e0"}, - {file = "pydantic_core-2.6.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:0dbd7262932b213b34f6c1bdd33b53b6ffc07e3cee21d63486d68e433020f452"}, - {file = "pydantic_core-2.6.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d6f16d771334c49a173403805ef874aff9800ea7c44f94ebf3817ae9c5631e"}, - {file = "pydantic_core-2.6.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:646324855acd153632bb86cbbd222771df7859b43d2891ace57c5b8c818ba8a7"}, - {file = "pydantic_core-2.6.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f52e9edca854804b780bba5c82f7a1aafebb7a7c496879a45423cf991c361f9e"}, - {file = "pydantic_core-2.6.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:95e569d8f702851ab48e349c5eb2f8ea673657b7ed5f2ac335d540ebc8519385"}, - {file = "pydantic_core-2.6.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b2ddc15cf29dc4b385c667064d7efb96431006dcf523527c3d749494b73e73a6"}, - {file = "pydantic_core-2.6.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0b52468b09ccee65bc96572345ec73dc89b42528874b626f7757000a6544d285"}, - {file = "pydantic_core-2.6.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:c020c5047b25e64c39006fa11f15d93adf4ae85154387f8e10232871ba78e7b2"}, - {file = "pydantic_core-2.6.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:892e7de51b8191929bf1246a04c13674a4d4b8dced8a4f86def85a1b0cb1a1e4"}, - {file = "pydantic_core-2.6.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d179b77fff4387a46ed0b63eb87ad6be58bb2a3a3415e69a44e918e8abcbd8c6"}, - {file = "pydantic_core-2.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b35585d14028c1afa41c1183906ce4128128d1114be9958b5ad0fb3721b50a4"}, - {file = "pydantic_core-2.6.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ffe8b2c8e30a87f6d7c1a78e23b8270a1acde9140cde425fa94688d302c8b2c9"}, - {file = "pydantic_core-2.6.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:6cc57fb772b48e5fd3691ca82d3756b6e64b885676d27d66bff551d951a18e5c"}, - {file = "pydantic_core-2.6.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3d72ebaa6451490ae05d3da858120b395b3bf1bebc8a5238ef803ff0f4f16f38"}, - {file = "pydantic_core-2.6.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:535f47fe0d2db647fdb0376cbbadd34fd00b3a5f56f772b0b0ef26928e8afa22"}, - {file = "pydantic_core-2.6.0.tar.gz", hash = "sha256:e50513d8dd8ea67259d45986e314f545f219ebb2496eea52269e457cdc7419f4"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - -[[package]] -name = "pyright" -version = "1.1.326" -description = "Command line wrapper for pyright" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyright-1.1.326-py3-none-any.whl", hash = "sha256:f3c5047465138558d3d106a9464cc097cf2c3611da6edcf5b535cc1fdebd45db"}, - {file = "pyright-1.1.326.tar.gz", hash = "sha256:cecbe026b14034ba0750db605718a8c2605552387c5772dfaf7f3e632cb7212a"}, -] - -[package.dependencies] -nodeenv = ">=1.6.0" -typing-extensions = {version = ">=3.7", markers = "python_version < \"3.8\""} - -[package.extras] -all = ["twine (>=3.4.1)"] -dev = ["twine (>=3.4.1)"] - -[[package]] -name = "pytest" -version = "7.1.1" -description = "pytest: simple powerful testing with Python" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-7.1.1-py3-none-any.whl", hash = "sha256:92f723789a8fdd7180b6b06483874feca4c48a5c76968e03bb3e7f806a1869ea"}, - {file = "pytest-7.1.1.tar.gz", hash = "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63"}, -] - -[package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] - -[[package]] -name = "pytest-asyncio" -version = "0.21.1" -description = "Pytest support for asyncio" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, - {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, -] - -[package.dependencies] -pytest = ">=7.0.0" -typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""} - -[package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] -testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "respx" -version = "0.19.2" -description = "A utility for mocking out the Python HTTPX and HTTP Core libraries." -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "respx-0.19.2-py2.py3-none-any.whl", hash = "sha256:417f986fec599b9cc6531e93e494b7a75d1cb7bccff9dde5b53edc51f7954494"}, - {file = "respx-0.19.2.tar.gz", hash = "sha256:f3d210bb4de0ccc4c5afabeb87c3c1b03b3765a9c1a73eb042a07bb18ac33705"}, -] - -[package.dependencies] -httpx = ">=0.21.0" - -[[package]] -name = "rfc3986" -version = "1.5.0" -description = "Validating URI References per RFC 3986" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, - {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, -] - -[package.dependencies] -idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} - -[package.extras] -idna2008 = ["idna"] - -[[package]] -name = "ruff" -version = "0.0.282" -description = "An extremely fast Python linter, written in Rust." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "ruff-0.0.282-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:01b76309ddab16eb258dabc5e86e73e6542f59f3ea6b4ab886ecbcfc80ce062c"}, - {file = "ruff-0.0.282-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e177cbb6dc0b1dbef5e999900d798b73e33602abf9b6c62d5d2cbe101026d931"}, - {file = "ruff-0.0.282-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5374b40b6d860d334d28678a53a92f0bf04b53acdf0395900361ad54ce71cd1d"}, - {file = "ruff-0.0.282-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1ccbceb44e94fe2205b63996166e98a513a19ed23ec01d7193b7494b94ba30d"}, - {file = "ruff-0.0.282-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eee9c8c50bc77eb9c0811c91d9d67ff39fe4f394c2f44ada37dac6d45e50c9f1"}, - {file = "ruff-0.0.282-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:826e4de98e91450a6fe699a4e4a7cf33b9a90a2c5c270dc5b202241c37359ff8"}, - {file = "ruff-0.0.282-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d99758f8bbcb8f8da99acabf711ffad5e7a015247adf27211100b3586777fd56"}, - {file = "ruff-0.0.282-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f30c9958ab9cb02bf0c574c629e87c19454cbbdb82750e49e3d1559a5a8f216"}, - {file = "ruff-0.0.282-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47a7a9366ab8e4ee20df9339bef172eec7b2e9e123643bf3ede005058f5b114e"}, - {file = "ruff-0.0.282-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1f05f5e6d6df6f8b1974c08f963c33f0a4d8cfa15cba12d35ca3ece8e9be5b1f"}, - {file = "ruff-0.0.282-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0710ea2cadc504b96c1d94c414a7802369d0fff2ab7c94460344bba69135cb40"}, - {file = "ruff-0.0.282-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2ca52536e1c7603fe4cbb5ad9dc141df47c3200df782f5ec559364716ea27f96"}, - {file = "ruff-0.0.282-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:aab9ed5bfba6b0a2242a7ec9a72858c802ceeaf0076fe72b2ad455639275f22c"}, - {file = "ruff-0.0.282-py3-none-win32.whl", hash = "sha256:f51bbb64f8f29e444c16d21b269ba82e25f8d536beda3df7c9fe1816297e508e"}, - {file = "ruff-0.0.282-py3-none-win_amd64.whl", hash = "sha256:bd25085c42ebaffe336ed7bda8a0ae7b6c454a5f386ec8b2299503f79bd12bdf"}, - {file = "ruff-0.0.282-py3-none-win_arm64.whl", hash = "sha256:f03fba9621533d67d7ab995847467d78b9337e3697779ef2cea6f1deaee5fbef"}, - {file = "ruff-0.0.282.tar.gz", hash = "sha256:ef677c26bae756e4c98af6d8972da83caea550bc92ffef97a6e939ca5b24ad06"}, -] - -[[package]] -name = "setuptools" -version = "67.4.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setuptools-67.4.0-py3-none-any.whl", hash = "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251"}, - {file = "setuptools-67.4.0.tar.gz", hash = "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sniffio" -version = "1.3.0" -description = "Sniff out which async library your code is running under" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, -] - -[[package]] -name = "time-machine" -version = "2.9.0" -description = "Travel through time in your tests." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "time-machine-2.9.0.tar.gz", hash = "sha256:60222d43f6e93a926adc36ed37a54bc8e4d0d8d1c4d449096afcfe85086129c2"}, - {file = "time_machine-2.9.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fd72c0b2e7443fff6e4481991742b72c17f73735e5fdd176406ca48df187a5c9"}, - {file = "time_machine-2.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5657e0e6077cf15b37f0d8cf78e868113bbb3ecccc60064c40fe52d8166ca8b1"}, - {file = "time_machine-2.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bfa82614a98ecee70272bb6038d210b2ad7b2a6b8a678b400c34bdaf776802a7"}, - {file = "time_machine-2.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4380bd6697cc7db3c9e6843f24779ac0550affa9d9a8e5f9e5d5cc139cb6583"}, - {file = "time_machine-2.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6211beee9f5dace08b1bbbb1fb09e34a69c52d87eea676729f14c8660481dff6"}, - {file = "time_machine-2.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:68ec8b83197db32c7a12da5f6b83c91271af3ed7f5dc122d2900a8de01dff9f0"}, - {file = "time_machine-2.9.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c5dbc8b87cdc7be070a499f2bd1cd405c7f647abeb3447dfd397639df040bc64"}, - {file = "time_machine-2.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:948ca690f9770ad4a93fa183061c11346505598f5f0b721965bc85ec83bb103d"}, - {file = "time_machine-2.9.0-cp310-cp310-win32.whl", hash = "sha256:f92d5d2eb119a6518755c4c9170112094c706d1c604460f50afc1308eeb97f0e"}, - {file = "time_machine-2.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb51432652ad663b4cbd631c73c90f9e94f463382b86c0b6b854173700512a70"}, - {file = "time_machine-2.9.0-cp310-cp310-win_arm64.whl", hash = "sha256:8976b7b1f7de13598b655d459f5640f90f3cd587283e1b914a22e45946c5485b"}, - {file = "time_machine-2.9.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6463e302c96eb8c691c4340e281bd54327a213b924fa189aea81accf7e7f78df"}, - {file = "time_machine-2.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6b632d60aa0883dc7292ac3d32050604d26ec2bbd5c4d42fb0de3b4ef17343e2"}, - {file = "time_machine-2.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d329578abe47ce95baa015ef3825acebb1b73b5fa6f818fdf2d4685a00ca457f"}, - {file = "time_machine-2.9.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ba5fc2655749066d68986de8368984dad4082db2fbeade78f40506dc5b65672"}, - {file = "time_machine-2.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49df5eea2160068e5b2bf28c22fc4c5aea00862ad88ddc3b62fc0f0683e97538"}, - {file = "time_machine-2.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8830510adbf0a231184da277db9de1d55ef93ed228a575d217aaee295505abf1"}, - {file = "time_machine-2.9.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b16a2129f9146faa080bfd1b53447761f7386ec5c72890c827a65f33ab200336"}, - {file = "time_machine-2.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a2cf80e5deaaa68c6cefb25303a4c870490b4e7591ed8e2435a65728920bc097"}, - {file = "time_machine-2.9.0-cp311-cp311-win32.whl", hash = "sha256:fe013942ab7f3241fcbe66ee43222d47f499d1e0cb69e913791c52e638ddd7f0"}, - {file = "time_machine-2.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:1d0ab46ce8a60baf9d86525694bf698fed9efefd22b8cbe1ca3e74abbb3239e1"}, - {file = "time_machine-2.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:4f3755d9342ca1f1019418db52072272dfd75eb818fa4726fa8aabe208b38c26"}, - {file = "time_machine-2.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9ee553f7732fa51e019e3329a6984593184c4e0410af1e73d91ce38a5d4b34ab"}, - {file = "time_machine-2.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:359c806e5b9a7a3c73dbb808d19dca297f5504a5eefdc5d031db8d918f43e364"}, - {file = "time_machine-2.9.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e2a90b8300812d8d774f2d2fc216fec3c7d94132ac589e062489c395061f16c"}, - {file = "time_machine-2.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36dde844d28549929fab171d683c28a8db1c206547bcf6b7aca77319847d2046"}, - {file = "time_machine-2.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:728263611d7940fda34d21573bd2b3f1491bdb52dbf75c5fe6c226dfe4655201"}, - {file = "time_machine-2.9.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8bcc86b5a07ea9745f26dfad958dde0a4f56748c2ae0c9a96200a334d1b55055"}, - {file = "time_machine-2.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b9c36240876622b7f2f9e11bf72f100857c0a1e1a59af2da3d5067efea62c37"}, - {file = "time_machine-2.9.0-cp37-cp37m-win32.whl", hash = "sha256:eaf334477bc0a9283d5150a56be8670a07295ef676e5b5a7f086952929d1a56b"}, - {file = "time_machine-2.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8e797e5a2a99d1b237183e52251abfc1ad85c376278b39d1aca76a451a97861a"}, - {file = "time_machine-2.9.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:69898aed9b2315a90f5855343d9aa34d05fa06032e2e3bb14f2528941ec89dc1"}, - {file = "time_machine-2.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c01dbc3671d0649023daf623e952f9f0b4d904d57ab546d6d35a4aeb14915e8d"}, - {file = "time_machine-2.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f080f6f7ca8cfca43bc5639288aebd0a273b4b5bd0acff609c2318728b13a18"}, - {file = "time_machine-2.9.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8670cb5cfda99f483d60de6ce56ceb0ec5d359193e79e4688e1c3c9db3937383"}, - {file = "time_machine-2.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f97ed8bc5b517844a71030f74e9561de92f4902c306e6ccc8331a5b0c8dd0e00"}, - {file = "time_machine-2.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bdbe785e046d124f73cca603ee37d5fae0b15dc4c13702488ad19de56aae08ba"}, - {file = "time_machine-2.9.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fcdef7687aed5c4331c9808f4a414a41987441c3e7a2ba554e4dccfa4218e788"}, - {file = "time_machine-2.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f6e79643368828d4651146a486be5a662846ac223ab5e2c73ddd519acfcc243c"}, - {file = "time_machine-2.9.0-cp38-cp38-win32.whl", hash = "sha256:bb15b2b79b00d3f6cf7d62096f5e782fa740ecedfe0540c09f1d1e4d3d7b81ba"}, - {file = "time_machine-2.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:3ff5148e2e73392db8418a1fe2f0b06f4a0e76772933502fb61e4c3000b5324e"}, - {file = "time_machine-2.9.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8367fd03f2d7349c7fc20f14de186974eaca2502c64b948212de663742c8fd11"}, - {file = "time_machine-2.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b55654aaeaba380fcd6c004b8ada2978fdd4ece1e61e6b9717c6d4cc7fbbcd9"}, - {file = "time_machine-2.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae4e3f02ab5dabb35adca606237c7e1a515c86d69c0b7092bbe0e1cfe5cffc61"}, - {file = "time_machine-2.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:010a58a8de1120308befae19e6c9de2ef5ca5206635cea33cb264998725cc027"}, - {file = "time_machine-2.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b32addbf56639a9a8261fb62f8ea83473447671c83ca2c017ab1eabf4841157f"}, - {file = "time_machine-2.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:372a97da01db89533d2f4ce50bbd908e5c56df7b8cfd6a005b177d0b14dc2938"}, - {file = "time_machine-2.9.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b8faff03231ee55d5a216ce3e9171c5205459f866f54d4b5ee8aa1d860e4ce11"}, - {file = "time_machine-2.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:748d701228e646c224f2adfa6a11b986cd4aa90f1b8c13ef4534a3919c796bc0"}, - {file = "time_machine-2.9.0-cp39-cp39-win32.whl", hash = "sha256:d79d374e32488c76cdb06fbdd4464083aeaa715ddca3e864bac7c7760eb03729"}, - {file = "time_machine-2.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:cc6bf01211b5ea40f633d5502c5aa495b415ebaff66e041820997dae70a508e1"}, - {file = "time_machine-2.9.0-cp39-cp39-win_arm64.whl", hash = "sha256:3ce445775fcf7cb4040cfdba4b7c4888e7fd98bbcccfe1dc3fa8a798ed1f1d24"}, -] - -[package.dependencies] -python-dateutil = "*" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "tomlkit" -version = "0.12.1" -description = "Style preserving TOML library" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, - {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, -] - -[[package]] -name = "typed-ast" -version = "1.5.4" -description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, -] - -[[package]] -name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, -] - -[[package]] -name = "virtualenv" -version = "20.21.1" -description = "Virtual Python Environment builder" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "virtualenv-20.21.1-py3-none-any.whl", hash = "sha256:09ddbe1af0c8ed2bb4d6ed226b9e6415718ad18aef9fa0ba023d96b7a8356049"}, - {file = "virtualenv-20.21.1.tar.gz", hash = "sha256:4c104ccde994f8b108163cf9ba58f3d11511d9403de87fb9b4f52bf33dbc8668"}, -] - -[package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""} -platformdirs = ">=2.4,<4" - -[package.extras] -docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] - -[[package]] -name = "zipp" -version = "3.10.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "zipp-3.10.0-py3-none-any.whl", hash = "sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1"}, - {file = "zipp-3.10.0.tar.gz", hash = "sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[metadata] -lock-version = "2.0" -python-versions = "^3.7" -content-hash = "f3a5042311972f24c3fb3c59a448c6f3ac3deec9c788271f0b726fbeb7c58250" diff --git a/pyproject.toml b/pyproject.toml index 3543c4df3..4d8ea4122 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,43 +1,69 @@ -[tool.poetry] +[project] name = "increase" version = "0.13.7" description = "Client library for the increase API" readme = "README.md" -authors = ["Increase "] license = "Apache-2.0" -repository = "https://github.com/increase/increase-python" -packages = [ - { include = "increase", from = "src" } +authors = [ +{ name = "Increase", email = "dev-feedback@increase.com" }, ] +dependencies = [ + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.5, <5", + "anyio>=3.5.0, <4", + "distro>=1.7.0, <2", + +] +requires-python = ">= 3.7" + -[tool.poetry.dependencies] -python = "^3.7" -httpx = ">= 0.23.0, < 1" -pydantic = ">= 1.9.0, < 3" -typing-extensions = ">= 4.5, < 5" -anyio = ">= 3.5.0, < 4" -distro = ">= 1.7.0, < 2" +[project.urls] +Homepage = "https://github.com/increase/increase-python" +Repository = "https://github.com/increase/increase-python" -[tool.poetry.group.dev.dependencies] -pyright = "1.1.326" -mypy = "1.4.1" -black = "23.3.0" -respx = "0.19.2" -pytest = "7.1.1" -pytest-asyncio = "0.21.1" -ruff = "0.0.282" -isort = "5.10.1" -time-machine = "^2.9.0" -nox = "^2023.4.22" -nox-poetry = "^1.0.3" +[tool.rye] +managed = true +dev-dependencies = [ + "pyright==1.1.326", + "mypy==1.4.1", + "black==23.3.0", + "respx==0.19.2", + "pytest==7.1.1", + "pytest-asyncio==0.21.1", + "ruff==0.0.282", + "isort==5.10.1", + "time-machine==2.9.0", + "nox==2023.4.22", + +] +[tool.rye.scripts] +format = { chain = [ + "format:black", + "format:docs", + "format:ruff", + "format:isort", +]} +"format:black" = "black ." +"format:docs" = "python bin/blacken-docs.py README.md api.md" +"format:ruff" = "ruff --fix ." +"format:isort" = "isort ." [build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build] +include = [ + "src/*" +] + +[tool.hatch.build.targets.wheel] +packages = ["src/increase"] [tool.black] line-length = 120 diff --git a/requirements-dev.lock b/requirements-dev.lock new file mode 100644 index 000000000..0cfe06db5 --- /dev/null +++ b/requirements-dev.lock @@ -0,0 +1,53 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: true + +-e file:. +annotated-types==0.6.0 +anyio==3.7.1 +argcomplete==3.1.2 +attrs==23.1.0 +black==23.3.0 +certifi==2023.7.22 +click==8.1.7 +colorlog==6.7.0 +distlib==0.3.7 +distro==1.8.0 +exceptiongroup==1.1.3 +filelock==3.12.4 +h11==0.12.0 +httpcore==0.15.0 +httpx==0.23.0 +idna==3.4 +iniconfig==2.0.0 +isort==5.10.1 +mypy==1.4.1 +mypy-extensions==1.0.0 +nodeenv==1.8.0 +nox==2023.4.22 +packaging==23.2 +pathspec==0.11.2 +platformdirs==3.11.0 +pluggy==1.3.0 +py==1.11.0 +pydantic==2.4.2 +pydantic-core==2.10.1 +pyright==1.1.326 +pytest==7.1.1 +pytest-asyncio==0.21.1 +python-dateutil==2.8.2 +respx==0.19.2 +rfc3986==1.5.0 +ruff==0.0.282 +six==1.16.0 +sniffio==1.3.0 +time-machine==2.9.0 +tomli==2.0.1 +typing-extensions==4.8.0 +virtualenv==20.24.5 +# The following packages are considered to be unsafe in a requirements file: +setuptools==68.2.2 diff --git a/requirements.lock b/requirements.lock new file mode 100644 index 000000000..0c8c2c2e6 --- /dev/null +++ b/requirements.lock @@ -0,0 +1,23 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: true + +-e file:. +annotated-types==0.6.0 +anyio==3.7.1 +certifi==2023.7.22 +distro==1.8.0 +exceptiongroup==1.1.3 +h11==0.12.0 +httpcore==0.15.0 +httpx==0.23.0 +idna==3.4 +pydantic==2.4.2 +pydantic-core==2.10.1 +rfc3986==1.5.0 +sniffio==1.3.0 +typing-extensions==4.8.0 diff --git a/src/increase/_models.py b/src/increase/_models.py index 5568ee97f..f663155ce 100644 --- a/src/increase/_models.py +++ b/src/increase/_models.py @@ -7,7 +7,6 @@ import pydantic import pydantic.generics -from pydantic import Extra from pydantic.fields import FieldInfo from ._types import ( @@ -56,7 +55,7 @@ def model_fields_set(self) -> set[str]: return self.__fields_set__ # type: ignore class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - extra: Any = Extra.allow # type: ignore + extra: Any = pydantic.Extra.allow # type: ignore def __str__(self) -> str: # mypy complains about an invalid self arg From 3d98ab9090ab87c40e0391d3bc80178e8d1c3483 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:26:58 +0100 Subject: [PATCH 16/22] chore(internal): improve publish script (#167) --- bin/publish-pypi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/publish-pypi b/bin/publish-pypi index ad584347d..826054e92 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -eux -mkdir dist +mkdir -p dist rye build --clean rye publish --yes --token=$PYPI_TOKEN From ba19c25d98cf522779ce08509834158b1d1df505 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:55:06 +0100 Subject: [PATCH 17/22] feat(client): support passing httpx.URL instances to base_url (#168) --- src/increase/_base_client.py | 6 +++--- src/increase/_client.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/increase/_base_client.py b/src/increase/_base_client.py index 351324c99..5cc06e6bd 100644 --- a/src/increase/_base_client.py +++ b/src/increase/_base_client.py @@ -331,7 +331,7 @@ def __init__( self, *, version: str, - base_url: str, + base_url: str | URL, _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, timeout: float | Timeout | None = DEFAULT_TIMEOUT, @@ -739,7 +739,7 @@ def __init__( self, *, version: str, - base_url: str, + base_url: str | URL, max_retries: int = DEFAULT_MAX_RETRIES, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, transport: Transport | None = None, @@ -1145,7 +1145,7 @@ def __init__( self, *, version: str, - base_url: str, + base_url: str | URL, _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, diff --git a/src/increase/_client.py b/src/increase/_client.py index 891bc4022..f105269c6 100644 --- a/src/increase/_client.py +++ b/src/increase/_client.py @@ -4,7 +4,7 @@ import os import asyncio -from typing import Dict, Union, Mapping, Optional +from typing import Dict, Union, Mapping from typing_extensions import Literal import httpx @@ -103,7 +103,7 @@ def __init__( *, api_key: str | None = None, environment: Literal["production", "sandbox"] = "production", - base_url: Optional[str] = None, + base_url: str | httpx.URL | None = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -217,7 +217,7 @@ def copy( *, api_key: str | None = None, environment: Literal["production", "sandbox"] | None = None, - base_url: str | None = None, + base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, http_client: httpx.Client | None = None, connection_pool_limits: httpx.Limits | None = None, @@ -431,7 +431,7 @@ def __init__( *, api_key: str | None = None, environment: Literal["production", "sandbox"] = "production", - base_url: Optional[str] = None, + base_url: str | httpx.URL | None = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -545,7 +545,7 @@ def copy( *, api_key: str | None = None, environment: Literal["production", "sandbox"] | None = None, - base_url: str | None = None, + base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, http_client: httpx.AsyncClient | None = None, connection_pool_limits: httpx.Limits | None = None, From 65434e9c8f9114087a6244c3447cf1c6a3199ae2 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Wed, 18 Oct 2023 09:16:40 -0400 Subject: [PATCH 18/22] chore(internal): update lock file (#169) --- requirements-dev.lock | 1 - requirements.lock | 1 - 2 files changed, 2 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 0cfe06db5..16b88e107 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -41,7 +41,6 @@ pytest==7.1.1 pytest-asyncio==0.21.1 python-dateutil==2.8.2 respx==0.19.2 -rfc3986==1.5.0 ruff==0.0.282 six==1.16.0 sniffio==1.3.0 diff --git a/requirements.lock b/requirements.lock index 0c8c2c2e6..a0736c813 100644 --- a/requirements.lock +++ b/requirements.lock @@ -18,6 +18,5 @@ httpx==0.23.0 idna==3.4 pydantic==2.4.2 pydantic-core==2.10.1 -rfc3986==1.5.0 sniffio==1.3.0 typing-extensions==4.8.0 From 7305ef97697154361747320e8b03fbfb29740ca3 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:00:29 -0400 Subject: [PATCH 19/22] chore(internal): update gitignore (#170) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 04a4e0397..cca06496d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ __pycache__ dist .venv +.idea .env codegen.log From ae01f6b5225ab37a44751d93eafe6949c7dcf513 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:15:20 +0100 Subject: [PATCH 20/22] chore(internal): update gitignore (#171) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cca06496d..a4b2f8c0b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ dist .idea .env +.envrc codegen.log From 420092d0e1b2a3a2fdcc75add256b266d87e31b1 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 19 Oct 2023 15:26:07 +0100 Subject: [PATCH 21/22] feat(api): updates (#172) --- .stats.yml | 2 +- api.md | 1 + .../resources/bookkeeping_accounts.py | 89 +++++++++++++++++++ src/increase/resources/event_subscriptions.py | 6 ++ src/increase/types/__init__.py | 3 + .../bookkeeping_account_update_params.py | 12 +++ src/increase/types/event.py | 3 + src/increase/types/event_list_params.py | 1 + src/increase/types/event_subscription.py | 3 + .../types/event_subscription_create_params.py | 3 + .../types/physical_card_create_params.py | 2 +- .../test_bookkeeping_accounts.py | 16 ++++ 12 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/increase/types/bookkeeping_account_update_params.py diff --git a/.stats.yml b/.stats.yml index a867372d4..c7af722ac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 147 +configured_endpoints: 148 diff --git a/api.md b/api.md index 4cd5d82e3..c199e6c89 100644 --- a/api.md +++ b/api.md @@ -40,6 +40,7 @@ from increase.types import BookkeepingAccount Methods: - client.bookkeeping_accounts.create(\*\*params) -> BookkeepingAccount +- client.bookkeeping_accounts.update(bookkeeping_account_id, \*\*params) -> BookkeepingAccount - client.bookkeeping_accounts.list(\*\*params) -> SyncPage[BookkeepingAccount] # BookkeepingEntrySets diff --git a/src/increase/resources/bookkeeping_accounts.py b/src/increase/resources/bookkeeping_accounts.py index 740640659..e9fa85a59 100644 --- a/src/increase/resources/bookkeeping_accounts.py +++ b/src/increase/resources/bookkeeping_accounts.py @@ -8,6 +8,7 @@ BookkeepingAccount, bookkeeping_account_list_params, bookkeeping_account_create_params, + bookkeeping_account_update_params, ) from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven from .._utils import maybe_transform @@ -80,6 +81,50 @@ def create( cast_to=BookkeepingAccount, ) + def update( + self, + bookkeeping_account_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> BookkeepingAccount: + """ + Update a Bookkeeping Account + + Args: + bookkeeping_account_id: The bookkeeping account you would like to update. + + name: The name you choose for the account. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + return self._patch( + f"/bookkeeping_accounts/{bookkeeping_account_id}", + body=maybe_transform({"name": name}, bookkeeping_account_update_params.BookkeepingAccountUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=BookkeepingAccount, + ) + def list( self, *, @@ -191,6 +236,50 @@ async def create( cast_to=BookkeepingAccount, ) + async def update( + self, + bookkeeping_account_id: str, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> BookkeepingAccount: + """ + Update a Bookkeeping Account + + Args: + bookkeeping_account_id: The bookkeeping account you would like to update. + + name: The name you choose for the account. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + return await self._patch( + f"/bookkeeping_accounts/{bookkeeping_account_id}", + body=maybe_transform({"name": name}, bookkeeping_account_update_params.BookkeepingAccountUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=BookkeepingAccount, + ) + def list( self, *, diff --git a/src/increase/resources/event_subscriptions.py b/src/increase/resources/event_subscriptions.py index 5c46173c1..3c825ac6d 100644 --- a/src/increase/resources/event_subscriptions.py +++ b/src/increase/resources/event_subscriptions.py @@ -37,6 +37,7 @@ def create( "ach_transfer.created", "ach_transfer.updated", "bookkeeping_account.created", + "bookkeeping_account.updated", "bookkeeping_entry_set.updated", "card.created", "card.updated", @@ -127,6 +128,8 @@ def create( - `ach_transfer.updated` - Occurs whenever an ACH Transfer is updated. - `bookkeeping_account.created` - Occurs whenever a Bookkeeping Account is created. + - `bookkeeping_account.updated` - Occurs whenever a Bookkeeping Account is + updated. - `bookkeeping_entry_set.updated` - Occurs whenever a Bookkeeping Entry Set is created. - `card.created` - Occurs whenever a Card is created. @@ -394,6 +397,7 @@ async def create( "ach_transfer.created", "ach_transfer.updated", "bookkeeping_account.created", + "bookkeeping_account.updated", "bookkeeping_entry_set.updated", "card.created", "card.updated", @@ -484,6 +488,8 @@ async def create( - `ach_transfer.updated` - Occurs whenever an ACH Transfer is updated. - `bookkeeping_account.created` - Occurs whenever a Bookkeeping Account is created. + - `bookkeeping_account.updated` - Occurs whenever a Bookkeeping Account is + updated. - `bookkeeping_entry_set.updated` - Occurs whenever a Bookkeeping Entry Set is created. - `card.created` - Occurs whenever a Card is created. diff --git a/src/increase/types/__init__.py b/src/increase/types/__init__.py index 764ced605..98cea0e77 100644 --- a/src/increase/types/__init__.py +++ b/src/increase/types/__init__.py @@ -176,6 +176,9 @@ from .bookkeeping_account_create_params import ( BookkeepingAccountCreateParams as BookkeepingAccountCreateParams, ) +from .bookkeeping_account_update_params import ( + BookkeepingAccountUpdateParams as BookkeepingAccountUpdateParams, +) from .wire_drawdown_request_list_params import ( WireDrawdownRequestListParams as WireDrawdownRequestListParams, ) diff --git a/src/increase/types/bookkeeping_account_update_params.py b/src/increase/types/bookkeeping_account_update_params.py new file mode 100644 index 000000000..440ff601c --- /dev/null +++ b/src/increase/types/bookkeeping_account_update_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BookkeepingAccountUpdateParams"] + + +class BookkeepingAccountUpdateParams(TypedDict, total=False): + name: Required[str] + """The name you choose for the account.""" diff --git a/src/increase/types/event.py b/src/increase/types/event.py index 297629345..afed696b4 100644 --- a/src/increase/types/event.py +++ b/src/increase/types/event.py @@ -31,6 +31,7 @@ class Event(BaseModel): "ach_transfer.created", "ach_transfer.updated", "bookkeeping_account.created", + "bookkeeping_account.updated", "bookkeeping_entry_set.updated", "card.created", "card.updated", @@ -107,6 +108,8 @@ class Event(BaseModel): - `ach_transfer.updated` - Occurs whenever an ACH Transfer is updated. - `bookkeeping_account.created` - Occurs whenever a Bookkeeping Account is created. + - `bookkeeping_account.updated` - Occurs whenever a Bookkeeping Account is + updated. - `bookkeeping_entry_set.updated` - Occurs whenever a Bookkeeping Entry Set is created. - `card.created` - Occurs whenever a Card is created. diff --git a/src/increase/types/event_list_params.py b/src/increase/types/event_list_params.py index a58b39b96..418c36266 100644 --- a/src/increase/types/event_list_params.py +++ b/src/increase/types/event_list_params.py @@ -46,6 +46,7 @@ class EventListParams(TypedDict, total=False): "ach_transfer.created", "ach_transfer.updated", "bookkeeping_account.created", + "bookkeeping_account.updated", "bookkeeping_entry_set.updated", "card.created", "card.updated", diff --git a/src/increase/types/event_subscription.py b/src/increase/types/event_subscription.py index b35851486..7c6174dec 100644 --- a/src/increase/types/event_subscription.py +++ b/src/increase/types/event_subscription.py @@ -30,6 +30,7 @@ class EventSubscription(BaseModel): "ach_transfer.created", "ach_transfer.updated", "bookkeeping_account.created", + "bookkeeping_account.updated", "bookkeeping_entry_set.updated", "card.created", "card.updated", @@ -106,6 +107,8 @@ class EventSubscription(BaseModel): - `ach_transfer.updated` - Occurs whenever an ACH Transfer is updated. - `bookkeeping_account.created` - Occurs whenever a Bookkeeping Account is created. + - `bookkeeping_account.updated` - Occurs whenever a Bookkeeping Account is + updated. - `bookkeeping_entry_set.updated` - Occurs whenever a Bookkeeping Entry Set is created. - `card.created` - Occurs whenever a Card is created. diff --git a/src/increase/types/event_subscription_create_params.py b/src/increase/types/event_subscription_create_params.py index e2ad76f4a..7196ae7b4 100644 --- a/src/increase/types/event_subscription_create_params.py +++ b/src/increase/types/event_subscription_create_params.py @@ -24,6 +24,7 @@ class EventSubscriptionCreateParams(TypedDict, total=False): "ach_transfer.created", "ach_transfer.updated", "bookkeeping_account.created", + "bookkeeping_account.updated", "bookkeeping_entry_set.updated", "card.created", "card.updated", @@ -99,6 +100,8 @@ class EventSubscriptionCreateParams(TypedDict, total=False): - `ach_transfer.updated` - Occurs whenever an ACH Transfer is updated. - `bookkeeping_account.created` - Occurs whenever a Bookkeeping Account is created. + - `bookkeeping_account.updated` - Occurs whenever a Bookkeeping Account is + updated. - `bookkeeping_entry_set.updated` - Occurs whenever a Bookkeeping Entry Set is created. - `card.created` - Occurs whenever a Card is created. diff --git a/src/increase/types/physical_card_create_params.py b/src/increase/types/physical_card_create_params.py index 378b68b9f..f81cce673 100644 --- a/src/increase/types/physical_card_create_params.py +++ b/src/increase/types/physical_card_create_params.py @@ -52,7 +52,7 @@ class ShipmentAddress(TypedDict, total=False): """The third line of the shipping address.""" phone_number: str - """The phone number of the receipient.""" + """The phone number of the recipient.""" class Shipment(TypedDict, total=False): diff --git a/tests/api_resources/test_bookkeeping_accounts.py b/tests/api_resources/test_bookkeeping_accounts.py index 4d44f66ca..be80b3a65 100644 --- a/tests/api_resources/test_bookkeeping_accounts.py +++ b/tests/api_resources/test_bookkeeping_accounts.py @@ -37,6 +37,14 @@ def test_method_create_with_all_params(self, client: Increase) -> None: ) assert_matches_type(BookkeepingAccount, bookkeeping_account, path=["response"]) + @parametrize + def test_method_update(self, client: Increase) -> None: + bookkeeping_account = client.bookkeeping_accounts.update( + "string", + name="Deprecated Account", + ) + assert_matches_type(BookkeepingAccount, bookkeeping_account, path=["response"]) + @parametrize def test_method_list(self, client: Increase) -> None: bookkeeping_account = client.bookkeeping_accounts.list() @@ -73,6 +81,14 @@ async def test_method_create_with_all_params(self, client: AsyncIncrease) -> Non ) assert_matches_type(BookkeepingAccount, bookkeeping_account, path=["response"]) + @parametrize + async def test_method_update(self, client: AsyncIncrease) -> None: + bookkeeping_account = await client.bookkeeping_accounts.update( + "string", + name="Deprecated Account", + ) + assert_matches_type(BookkeepingAccount, bookkeeping_account, path=["response"]) + @parametrize async def test_method_list(self, client: AsyncIncrease) -> None: bookkeeping_account = await client.bookkeeping_accounts.list() From 99f59c89f9dac57be94b28580743bf2dec6dd036 Mon Sep 17 00:00:00 2001 From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com> Date: Thu, 19 Oct 2023 15:26:25 +0100 Subject: [PATCH 22/22] release: 0.14.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/increase/_version.py | 2 +- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6529c7a61..a26ebfc1e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.13.7" + ".": "0.14.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 018271b49..fc8e9e23c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,48 @@ # Changelog +## 0.14.0 (2023-10-19) + +Full Changelog: [v0.13.7...v0.14.0](https://github.com/increase/increase-python/compare/v0.13.7...v0.14.0) + +### Features + +* **api:** add addenda details for ACH transfers ([#165](https://github.com/increase/increase-python/issues/165)) ([46c62ba](https://github.com/increase/increase-python/commit/46c62bae4ca6684cfbfce0124101b8a556763b2d)) +* **api:** updates ([#172](https://github.com/increase/increase-python/issues/172)) ([420092d](https://github.com/increase/increase-python/commit/420092d0e1b2a3a2fdcc75add256b266d87e31b1)) +* **client:** add logging setup ([#154](https://github.com/increase/increase-python/issues/154)) ([712448e](https://github.com/increase/increase-python/commit/712448e48baa1b25b5b556ae0a9a68a239c3b88d)) +* **client:** support passing httpx.URL instances to base_url ([#168](https://github.com/increase/increase-python/issues/168)) ([ba19c25](https://github.com/increase/increase-python/commit/ba19c25d98cf522779ce08509834158b1d1df505)) + + +### Bug Fixes + +* **client:** accept io.IOBase instances in file params ([#162](https://github.com/increase/increase-python/issues/162)) ([695f2bb](https://github.com/increase/increase-python/commit/695f2bba42968196b058b6ff6c6ad2ec66fb1da3)) +* **client:** correctly handle arguments with env vars ([#155](https://github.com/increase/increase-python/issues/155)) ([9d757a1](https://github.com/increase/increase-python/commit/9d757a11276040923f22ef6155840ab3bbb8b635)) +* **streaming:** add additional overload for ambiguous stream param ([#160](https://github.com/increase/increase-python/issues/160)) ([7bad83f](https://github.com/increase/increase-python/commit/7bad83fa5931974df2d8249a0fc98f3ea9d2d5de)) + + +### Chores + +* add case insensitive get header function ([#157](https://github.com/increase/increase-python/issues/157)) ([9240b3a](https://github.com/increase/increase-python/commit/9240b3a492872bc2740dd57573c947b3b5047a97)) +* **internal:** cleanup some redundant code ([#161](https://github.com/increase/increase-python/issues/161)) ([5325526](https://github.com/increase/increase-python/commit/5325526dc4826a96a9f18ef95b2729d23842877d)) +* **internal:** enable lint rule ([#159](https://github.com/increase/increase-python/issues/159)) ([9b23b62](https://github.com/increase/increase-python/commit/9b23b62b0ce84ba6b18a76e4121b971a42695c3b)) +* **internal:** improve publish script ([#167](https://github.com/increase/increase-python/issues/167)) ([3d98ab9](https://github.com/increase/increase-python/commit/3d98ab9090ab87c40e0391d3bc80178e8d1c3483)) +* **internal:** migrate from Poetry to Rye ([#166](https://github.com/increase/increase-python/issues/166)) ([3e81c88](https://github.com/increase/increase-python/commit/3e81c88e0fa8bf0e3feae148b99e6f4d335c98f5)) +* **internal:** update gitignore ([#170](https://github.com/increase/increase-python/issues/170)) ([7305ef9](https://github.com/increase/increase-python/commit/7305ef97697154361747320e8b03fbfb29740ca3)) +* **internal:** update gitignore ([#171](https://github.com/increase/increase-python/issues/171)) ([ae01f6b](https://github.com/increase/increase-python/commit/ae01f6b5225ab37a44751d93eafe6949c7dcf513)) +* **internal:** update lock file ([#169](https://github.com/increase/increase-python/issues/169)) ([65434e9](https://github.com/increase/increase-python/commit/65434e9c8f9114087a6244c3447cf1c6a3199ae2)) +* update comment ([#158](https://github.com/increase/increase-python/issues/158)) ([e75c268](https://github.com/increase/increase-python/commit/e75c268391ff2eaae0c050e8bcecea1d6d29bc24)) +* update README ([#151](https://github.com/increase/increase-python/issues/151)) ([4db792a](https://github.com/increase/increase-python/commit/4db792afa4fd65590a7ae4e0fdd782069917f78c)) + + +### Documentation + +* improve error message for invalid file param type ([#164](https://github.com/increase/increase-python/issues/164)) ([e105b17](https://github.com/increase/increase-python/commit/e105b17235f182542a78ea13e5a2aaacdc937876)) +* organisation -> organization (UK to US English) ([#163](https://github.com/increase/increase-python/issues/163)) ([bd21fa4](https://github.com/increase/increase-python/commit/bd21fa4e0c2648772066e3fa85a7adace525253a)) + + +### Refactors + +* **test:** refactor authentication tests ([#153](https://github.com/increase/increase-python/issues/153)) ([acdfa12](https://github.com/increase/increase-python/commit/acdfa121cec5604ef96fc8a580636e2f6d2c4927)) + ## 0.13.7 (2023-10-11) Full Changelog: [v0.13.6...v0.13.7](https://github.com/increase/increase-python/compare/v0.13.6...v0.13.7) diff --git a/pyproject.toml b/pyproject.toml index 4d8ea4122..722ff118e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "increase" -version = "0.13.7" +version = "0.14.0" description = "Client library for the increase API" readme = "README.md" license = "Apache-2.0" diff --git a/src/increase/_version.py b/src/increase/_version.py index b36f97d9f..3e9d630ea 100644 --- a/src/increase/_version.py +++ b/src/increase/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. __title__ = "increase" -__version__ = "0.13.7" # x-release-please-version +__version__ = "0.14.0" # x-release-please-version