diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3f63a672..79df23ff 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.22.1" + ".": "0.22.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 79645e1f..a314e21c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 0.22.2 (2023-11-06) + +Full Changelog: [v0.22.1...v0.22.2](https://github.com/lithic-com/lithic-python/compare/v0.22.1...v0.22.2) + +### Bug Fixes + +* prevent TypeError in Python 3.8 (ABC is not subscriptable) ([#233](https://github.com/lithic-com/lithic-python/issues/233)) ([55fd8a3](https://github.com/lithic-com/lithic-python/commit/55fd8a3315c546a4c83ff8e72b36aff78d7c7209)) + + +### Chores + +* **internal:** remove unused int/float conversion ([#231](https://github.com/lithic-com/lithic-python/issues/231)) ([1256055](https://github.com/lithic-com/lithic-python/commit/125605517acc43343c15a382c10ce535304c22d6)) + + +### Documentation + +* **api:** improve method signatures for named path params ([#228](https://github.com/lithic-com/lithic-python/issues/228)) ([476d296](https://github.com/lithic-com/lithic-python/commit/476d2960e890068e851c4d443533704178912431)) +* improve account holder control person documentation ([#230](https://github.com/lithic-com/lithic-python/issues/230)) ([36abfb0](https://github.com/lithic-com/lithic-python/commit/36abfb09f32eb367c6f4bba24c737bcf585defea)) +* **readme:** improve example snippets ([#232](https://github.com/lithic-com/lithic-python/issues/232)) ([ace36a4](https://github.com/lithic-com/lithic-python/commit/ace36a44b8f7fc05ebec0842d6be702150a71a3c)) + ## 0.22.1 (2023-11-03) Full Changelog: [v0.22.0...v0.22.1](https://github.com/lithic-com/lithic-python/compare/v0.22.0...v0.22.1) diff --git a/README.md b/README.md index 72f053ef..b47ac325 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ so that your API Key is not stored in source control. Simply import `AsyncLithic` instead of `Lithic` and use `await` with each API call: ```python +import asyncio from lithic import AsyncLithic client = AsyncLithic( @@ -56,7 +57,7 @@ client = AsyncLithic( ) -async def main(): +async def main() -> None: card = await client.cards.create( type="SINGLE_USE", ) @@ -146,11 +147,10 @@ from lithic import Lithic client = Lithic() -client.cards.create( - foo={ - "bar": True, - }, +card = client.cards.create( + type="VIRTUAL", ) +print(card.token) ``` ## Webhook Verification @@ -318,9 +318,8 @@ from lithic import Lithic client = Lithic() response = client.cards.with_raw_response.create( - type="VIRTUAL", + type="SINGLE_USE", ) - print(response.headers.get('X-My-Header')) card = response.parse() # get the object that `cards.create()` would have returned diff --git a/api.md b/api.md index 05499cda..c1b07da7 100644 --- a/api.md +++ b/api.md @@ -60,7 +60,7 @@ Methods: - client.account_holders.update(account_holder_token, \*\*params) -> AccountHolderUpdateResponse - client.account_holders.list_documents(account_holder_token) -> AccountHolderListDocumentsResponse - client.account_holders.resubmit(account_holder_token, \*\*params) -> AccountHolder -- client.account_holders.retrieve_document(account_holder_token, document_token) -> AccountHolderDocument +- client.account_holders.retrieve_document(document_token, \*, account_holder_token) -> AccountHolderDocument - client.account_holders.upload_document(account_holder_token, \*\*params) -> AccountHolderDocument # AuthRules @@ -169,7 +169,7 @@ Methods: Methods: -- client.cards.financial_transactions.retrieve(card_token, financial_transaction_token) -> FinancialTransaction +- client.cards.financial_transactions.retrieve(financial_transaction_token, \*, card_token) -> FinancialTransaction - client.cards.financial_transactions.list(card_token, \*\*params) -> SyncSinglePage[FinancialTransaction] # Balances @@ -211,10 +211,10 @@ Methods: - client.disputes.update(dispute_token, \*\*params) -> Dispute - client.disputes.list(\*\*params) -> SyncCursorPage[Dispute] - client.disputes.delete(dispute_token) -> Dispute -- client.disputes.delete_evidence(dispute_token, evidence_token) -> DisputeEvidence +- client.disputes.delete_evidence(evidence_token, \*, dispute_token) -> DisputeEvidence - client.disputes.initiate_evidence_upload(dispute_token, \*\*params) -> DisputeEvidence - client.disputes.list_evidences(dispute_token, \*\*params) -> SyncCursorPage[DisputeEvidence] -- client.disputes.retrieve_evidence(dispute_token, evidence_token) -> DisputeEvidence +- client.disputes.retrieve_evidence(evidence_token, \*, dispute_token) -> DisputeEvidence - client.disputes.upload_evidence(\*args) -> None # Events @@ -276,7 +276,7 @@ Methods: Methods: -- client.financial_accounts.financial_transactions.retrieve(financial_account_token, financial_transaction_token) -> FinancialTransaction +- client.financial_accounts.financial_transactions.retrieve(financial_transaction_token, \*, financial_account_token) -> FinancialTransaction - client.financial_accounts.financial_transactions.list(financial_account_token, \*\*params) -> SyncSinglePage[FinancialTransaction] ## Statements @@ -289,7 +289,7 @@ from lithic.types.financial_accounts import Statement Methods: -- client.financial_accounts.statements.retrieve(financial_account_token, statement_token) -> Statement +- client.financial_accounts.statements.retrieve(statement_token, \*, financial_account_token) -> Statement - client.financial_accounts.statements.list(financial_account_token, \*\*params) -> SyncCursorPage[Statement] ### LineItems @@ -302,7 +302,7 @@ from lithic.types.financial_accounts.statements import LineItemListResponse Methods: -- client.financial_accounts.statements.line_items.list(financial_account_token, statement_token, \*\*params) -> SyncCursorPage[LineItemListResponse] +- client.financial_accounts.statements.line_items.list(statement_token, \*, financial_account_token, \*\*params) -> SyncCursorPage[LineItemListResponse] # Transactions diff --git a/pyproject.toml b/pyproject.toml index 307cebd7..e8bbfa48 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lithic" -version = "0.22.1" +version = "0.22.2" description = "Client library for the lithic API" readme = "README.md" license = "Apache-2.0" diff --git a/src/lithic/_models.py b/src/lithic/_models.py index 40245ac9..00d787ca 100644 --- a/src/lithic/_models.py +++ b/src/lithic/_models.py @@ -313,16 +313,13 @@ def construct_type(*, value: object, type_: type) -> object: return [construct_type(value=entry, type_=inner_type) for entry in value] if origin == float: - try: - return float(cast(Any, value)) - except Exception: - return value + if isinstance(value, int): + coerced = float(value) + if coerced != value: + return value + return coerced - if origin == int: - try: - return int(cast(Any, value)) - except Exception: - return value + return value if type_ == datetime: try: diff --git a/src/lithic/_types.py b/src/lithic/_types.py index 0f250077..3952a70b 100644 --- a/src/lithic/_types.py +++ b/src/lithic/_types.py @@ -191,7 +191,10 @@ async def aclose(self) -> None: # while adding support for `PathLike` instances ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]] ProxiesTypes = Union[str, Proxy, ProxiesDict] -FileContent = Union[IO[bytes], bytes, PathLike[str]] +if TYPE_CHECKING: + FileContent = Union[IO[bytes], bytes, PathLike[str]] +else: + FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. FileTypes = Union[ # file (or bytes) FileContent, diff --git a/src/lithic/_version.py b/src/lithic/_version.py index 99c265b4..18497979 100644 --- a/src/lithic/_version.py +++ b/src/lithic/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. __title__ = "lithic" -__version__ = "0.22.1" # x-release-please-version +__version__ = "0.22.2" # x-release-please-version diff --git a/src/lithic/types/account_holder.py b/src/lithic/types/account_holder.py index 1b1f5c50..4bf1a194 100644 --- a/src/lithic/types/account_holder.py +++ b/src/lithic/types/account_holder.py @@ -211,10 +211,13 @@ class AccountHolder(BaseModel): """ control_person: Optional[ControlPerson] = None - """Information about an individual associated with an account holder. - - A subset of the information provided via KYC. For example, we do not return the - government id. + """ + Only present when user_type == "BUSINESS". An individual with significant + responsibility for managing the legal entity (e.g., a Chief Executive Officer, + Chief Financial Officer, Chief Operating Officer, Managing Member, General + Partner, President, Vice President, or Treasurer). This can be an executive, or + someone who will have program-wide access to the cards that Lithic will provide. + In some cases, this individual could also be a beneficial owner listed above. """ created: Optional[datetime] = None diff --git a/tests/test_models.py b/tests/test_models.py index 41f0cb1b..3c00abb2 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -439,21 +439,32 @@ class Model(BaseModel): assert model_json(model) == expected_json -def test_coerces_int() -> None: +def test_does_not_coerce_int() -> None: class Model(BaseModel): bar: int assert Model.construct(bar=1).bar == 1 - assert Model.construct(bar=10.9).bar == 10 - assert Model.construct(bar="19").bar == 19 - assert Model.construct(bar=False).bar == 0 + assert Model.construct(bar=10.9).bar == 10.9 + assert Model.construct(bar="19").bar == "19" # type: ignore[comparison-overlap] + assert Model.construct(bar=False).bar is False - # TODO: support this - # assert Model.construct(bar="True").bar == 1 - # mismatched types are left as-is - m = Model.construct(bar={"foo": "bar"}) - assert m.bar == {"foo": "bar"} # type: ignore[comparison-overlap] +def test_int_to_float_safe_conversion() -> None: + class Model(BaseModel): + float_field: float + + m = Model.construct(float_field=10) + assert m.float_field == 10.0 + assert isinstance(m.float_field, float) + + m = Model.construct(float_field=10.12) + assert m.float_field == 10.12 + assert isinstance(m.float_field, float) + + # number too big + m = Model.construct(float_field=2**53 + 1) + assert m.float_field == 2**53 + 1 + assert isinstance(m.float_field, int) def test_deprecated_alias() -> None: