airwallex-sdk 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. airwallex/__init__.py +74 -0
  2. airwallex/api/__init__.py +37 -0
  3. airwallex/api/account.py +107 -0
  4. airwallex/api/account_detail.py +469 -0
  5. airwallex/api/base.py +488 -0
  6. airwallex/api/beneficiary.py +156 -0
  7. airwallex/api/financial_transaction.py +123 -0
  8. airwallex/api/invoice.py +257 -0
  9. airwallex/api/issuing_authorization.py +313 -0
  10. airwallex/api/issuing_card.py +411 -0
  11. airwallex/api/issuing_cardholder.py +234 -0
  12. airwallex/api/issuing_config.py +80 -0
  13. airwallex/api/issuing_digital_wallet_token.py +249 -0
  14. airwallex/api/issuing_transaction.py +231 -0
  15. airwallex/api/issuing_transaction_dispute.py +339 -0
  16. airwallex/api/payment.py +148 -0
  17. airwallex/client.py +396 -0
  18. airwallex/exceptions.py +222 -0
  19. airwallex/models/__init__.py +69 -0
  20. airwallex/models/account.py +51 -0
  21. airwallex/models/account_detail.py +259 -0
  22. airwallex/models/base.py +121 -0
  23. airwallex/models/beneficiary.py +70 -0
  24. airwallex/models/financial_transaction.py +30 -0
  25. airwallex/models/fx.py +58 -0
  26. airwallex/models/invoice.py +102 -0
  27. airwallex/models/issuing_authorization.py +41 -0
  28. airwallex/models/issuing_card.py +135 -0
  29. airwallex/models/issuing_cardholder.py +52 -0
  30. airwallex/models/issuing_common.py +83 -0
  31. airwallex/models/issuing_config.py +62 -0
  32. airwallex/models/issuing_digital_wallet_token.py +38 -0
  33. airwallex/models/issuing_transaction.py +42 -0
  34. airwallex/models/issuing_transaction_dispute.py +59 -0
  35. airwallex/models/payment.py +81 -0
  36. airwallex/utils.py +107 -0
  37. airwallex_sdk-0.1.0.dist-info/METADATA +202 -0
  38. airwallex_sdk-0.1.0.dist-info/RECORD +39 -0
  39. airwallex_sdk-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,81 @@
1
+ """
2
+ Models for the Airwallex payment API.
3
+ """
4
+ from typing import Optional, List, Dict, Any, Union
5
+ from datetime import datetime
6
+ from pydantic import Field, EmailStr
7
+ from .base import AirwallexModel
8
+
9
+
10
+ class PaymentAmount(AirwallexModel):
11
+ """Model for payment amount."""
12
+ value: float = Field(..., description="Payment amount value")
13
+ currency: str = Field(..., description="Currency code (ISO 4217)")
14
+
15
+
16
+ class PaymentSourceDetails(AirwallexModel):
17
+ """Model for payment source details."""
18
+ type: str = Field(..., description="Source type (e.g., 'account')")
19
+ account_id: Optional[str] = Field(None, description="Account ID for account sources")
20
+ card_id: Optional[str] = Field(None, description="Card ID for card sources")
21
+
22
+
23
+ class PaymentBeneficiary(AirwallexModel):
24
+ """Model for payment beneficiary."""
25
+ type: str = Field(..., description="Beneficiary type (e.g., 'bank_account', 'email')")
26
+ id: Optional[str] = Field(None, description="Beneficiary ID for saved beneficiaries")
27
+ name: Optional[str] = Field(None, description="Beneficiary name")
28
+ email: Optional[EmailStr] = Field(None, description="Beneficiary email")
29
+ country_code: Optional[str] = Field(None, description="Beneficiary country code (ISO 3166-1 alpha-2)")
30
+ bank_details: Optional[Dict[str, Any]] = Field(None, description="Bank details for bank transfers")
31
+
32
+
33
+ class Payment(AirwallexModel):
34
+ """Model for an Airwallex payment."""
35
+ resource_name: str = "payments"
36
+
37
+ id: str = Field(..., description="Unique payment ID")
38
+ request_id: Optional[str] = Field(None, description="Client-generated request ID")
39
+ amount: PaymentAmount = Field(..., description="Payment amount")
40
+ source: PaymentSourceDetails = Field(..., description="Payment source details")
41
+ beneficiary: PaymentBeneficiary = Field(..., description="Payment beneficiary details")
42
+ payment_method: str = Field(..., description="Payment method type")
43
+ status: str = Field(..., description="Payment status")
44
+ payment_date: Optional[datetime] = Field(None, description="Payment date")
45
+ reference: Optional[str] = Field(None, description="Payment reference")
46
+ description: Optional[str] = Field(None, description="Payment description")
47
+ metadata: Optional[Dict[str, str]] = Field(None, description="Additional metadata")
48
+ created_at: datetime = Field(..., description="Payment creation timestamp")
49
+ updated_at: Optional[datetime] = Field(None, description="Payment last update timestamp")
50
+
51
+
52
+ class PaymentCreateRequest(AirwallexModel):
53
+ """Model for payment creation request."""
54
+ request_id: str = Field(..., description="Client-generated unique ID for the request")
55
+ amount: PaymentAmount = Field(..., description="Payment amount")
56
+ source: PaymentSourceDetails = Field(..., description="Payment source details")
57
+ beneficiary: PaymentBeneficiary = Field(..., description="Payment beneficiary details")
58
+ payment_method: str = Field(..., description="Payment method type")
59
+ payment_date: Optional[datetime] = Field(None, description="Requested payment date")
60
+ reference: Optional[str] = Field(None, description="Payment reference visible to the beneficiary")
61
+ description: Optional[str] = Field(None, description="Internal payment description")
62
+ metadata: Optional[Dict[str, str]] = Field(None, description="Additional metadata")
63
+
64
+
65
+ class PaymentUpdateRequest(AirwallexModel):
66
+ """Model for payment update request."""
67
+ status: Optional[str] = Field(None, description="New payment status (for cancellation)")
68
+ payment_date: Optional[datetime] = Field(None, description="Updated payment date")
69
+ reference: Optional[str] = Field(None, description="Updated payment reference")
70
+ description: Optional[str] = Field(None, description="Updated payment description")
71
+ metadata: Optional[Dict[str, str]] = Field(None, description="Updated metadata")
72
+
73
+
74
+ class PaymentQuote(AirwallexModel):
75
+ """Model for payment quote details."""
76
+ id: str = Field(..., description="Quote ID")
77
+ source_amount: PaymentAmount = Field(..., description="Source amount")
78
+ target_amount: PaymentAmount = Field(..., description="Target amount")
79
+ fx_rate: float = Field(..., description="FX rate applied")
80
+ fee: Optional[PaymentAmount] = Field(None, description="Fee amount")
81
+ expires_at: datetime = Field(..., description="Quote expiration timestamp")
airwallex/utils.py ADDED
@@ -0,0 +1,107 @@
1
+ """
2
+ Utility functions for the Airwallex SDK.
3
+ """
4
+ import re
5
+ from datetime import datetime
6
+ from typing import Any, Dict, List, Union, TypeVar
7
+
8
+ T = TypeVar('T')
9
+
10
+
11
+ def snake_to_pascal_case(snake_str: str) -> str:
12
+ """Convert snake_case to PascalCase."""
13
+ return ''.join(word.title() for word in snake_str.split('_'))
14
+
15
+
16
+ def pascal_to_snake_case(pascal_str: str) -> str:
17
+ """Convert PascalCase to snake_case."""
18
+ return re.sub(r'(?<!^)(?=[A-Z])', '_', pascal_str).lower()
19
+
20
+
21
+ def camel_to_snake_case(camel_str: str) -> str:
22
+ """Convert camelCase to snake_case."""
23
+ pattern = re.compile(r'(?<!^)(?=[A-Z])')
24
+ return pattern.sub('_', camel_str).lower()
25
+
26
+
27
+ def snake_to_camel_case(snake_str: str) -> str:
28
+ """Convert snake_case to camelCase."""
29
+ components = snake_str.split('_')
30
+ return components[0] + ''.join(x.title() for x in components[1:])
31
+
32
+
33
+ def serialize(data: Union[Dict[str, Any], List[Dict[str, Any]]]) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
34
+ """
35
+ Serialize data for the Airwallex API.
36
+ Converts keys from snake_case to camelCase as required by the API.
37
+ Handles datetime objects, converting them to ISO format strings.
38
+ """
39
+ if isinstance(data, list):
40
+ return [serialize(item) for item in data]
41
+
42
+ if not isinstance(data, dict):
43
+ if isinstance(data, datetime):
44
+ return data.isoformat()
45
+ return data
46
+
47
+ result: Dict[str, Any] = {}
48
+ for key, value in data.items():
49
+ # Convert snake_case keys to camelCase
50
+ camel_key = snake_to_camel_case(key)
51
+
52
+ # Handle nested dictionaries and lists
53
+ if isinstance(value, dict):
54
+ result[camel_key] = serialize(value)
55
+ elif isinstance(value, list):
56
+ result[camel_key] = [serialize(item) for item in value]
57
+ elif isinstance(value, datetime):
58
+ # Convert datetime objects to ISO format strings
59
+ result[camel_key] = value.isoformat()
60
+ else:
61
+ result[camel_key] = value
62
+
63
+ return result
64
+
65
+
66
+ def deserialize(data: Union[Dict[str, Any], List[Dict[str, Any]]]) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
67
+ """
68
+ Deserialize data from the Airwallex API.
69
+ Converts keys from camelCase to snake_case for Python convention.
70
+ Attempts to parse ISO format date strings to datetime objects.
71
+ """
72
+ if isinstance(data, list):
73
+ return [deserialize(item) for item in data]
74
+
75
+ if not isinstance(data, dict):
76
+ # Try to parse ISO date strings
77
+ if isinstance(data, str):
78
+ try:
79
+ if 'T' in data and ('+' in data or 'Z' in data):
80
+ return datetime.fromisoformat(data.replace('Z', '+00:00'))
81
+ except ValueError:
82
+ pass
83
+ return data
84
+
85
+ result: Dict[str, Any] = {}
86
+ for key, value in data.items():
87
+ # Convert camelCase keys to snake_case
88
+ snake_key = camel_to_snake_case(key)
89
+
90
+ # Handle nested dictionaries and lists
91
+ if isinstance(value, dict):
92
+ result[snake_key] = deserialize(value)
93
+ elif isinstance(value, list):
94
+ result[snake_key] = [deserialize(item) for item in value]
95
+ elif isinstance(value, str):
96
+ # Try to parse ISO date strings
97
+ try:
98
+ if 'T' in value and ('+' in value or 'Z' in value):
99
+ result[snake_key] = datetime.fromisoformat(value.replace('Z', '+00:00'))
100
+ else:
101
+ result[snake_key] = value
102
+ except ValueError:
103
+ result[snake_key] = value
104
+ else:
105
+ result[snake_key] = value
106
+
107
+ return result
@@ -0,0 +1,202 @@
1
+ Metadata-Version: 2.1
2
+ Name: airwallex-sdk
3
+ Version: 0.1.0
4
+ Summary: Unofficial Airwallex SDK for Python
5
+ License: MIT
6
+ Author: duneraccoon
7
+ Author-email: benjamincsherro@hotmail.com
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Requires-Dist: httpx (>=0.28.1,<0.29.0)
15
+ Requires-Dist: pydantic (>=2.11.3,<3.0.0)
16
+ Project-URL: Source, https://github.com/DuneRaccoon/airwallex-sdk
17
+ Description-Content-Type: text/markdown
18
+
19
+ # UNOFFICIAL Airwallex Python SDK
20
+
21
+ A simple SDK for interacting with the [Airwallex API](https://www.airwallex.com/docs/api).
22
+
23
+ ## Features
24
+
25
+ - SOMEWHAT Comprehensive implementation of the Airwallex API
26
+ - Both synchronous and asynchronous client support
27
+ - Automatic authentication and token refresh
28
+ - Built-in rate limiting and retry logic
29
+ - Type checking with Pydantic models
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install airwallex-sdk
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ### Payments API
40
+
41
+ #### Synchronous Usage
42
+
43
+ ```python
44
+ from airwallex import AirwallexClient
45
+ from airwallex.models.payment import PaymentCreateRequest, PaymentAmount
46
+
47
+ # Initialize the client
48
+ client = AirwallexClient(
49
+ client_id="your_client_id",
50
+ api_key="your_api_key"
51
+ )
52
+
53
+ # List accounts
54
+ accounts = client.accounts.list()
55
+ for account in accounts:
56
+ print(f"Account: {account.account_name} ({account.id})")
57
+
58
+ # Fetch a specific account
59
+ account = client.accounts.fetch("account_id")
60
+ print(account.show()) # Print a formatted representation
61
+
62
+ # Create a payment
63
+ payment_request = PaymentCreateRequest(
64
+ request_id="unique_request_id",
65
+ amount=PaymentAmount(value=100.00, currency="USD"),
66
+ source={
67
+ "type": "account",
68
+ "account_id": "account_id"
69
+ },
70
+ beneficiary={
71
+ "type": "bank_account",
72
+ "id": "beneficiary_id"
73
+ },
74
+ payment_method="swift"
75
+ )
76
+
77
+ payment = client.payments.create_from_model(payment_request)
78
+ print(f"Payment created with ID: {payment.id}")
79
+
80
+ # Use generator to iterate through all payments
81
+ for payment in client.payments():
82
+ print(f"Payment {payment.id}: {payment.amount.value} {payment.amount.currency}")
83
+ ```
84
+
85
+ #### Asynchronous Usage
86
+
87
+ ```python
88
+ import asyncio
89
+ from airwallex import AirwallexAsyncClient
90
+ from airwallex.models.beneficiary import BeneficiaryCreateRequest, BankDetails
91
+
92
+ async def main():
93
+ # Initialize the async client
94
+ client = AirwallexAsyncClient(
95
+ client_id="your_client_id",
96
+ api_key="your_api_key"
97
+ )
98
+
99
+ # List accounts
100
+ accounts = await client.accounts.list_async()
101
+
102
+ # Create a beneficiary
103
+ beneficiary_request = BeneficiaryCreateRequest(
104
+ name="John Doe",
105
+ type="bank_account",
106
+ bank_details=BankDetails(
107
+ account_name="John Doe",
108
+ account_number="123456789",
109
+ swift_code="ABCDEFGH",
110
+ bank_country_code="US"
111
+ )
112
+ )
113
+
114
+ beneficiary = await client.beneficiaries.create_from_model_async(beneficiary_request)
115
+ print(f"Beneficiary created with ID: {beneficiary.id}")
116
+
117
+ # Async generator to iterate through all beneficiaries
118
+ async for ben in client.beneficiaries.paginate_async_generator():
119
+ print(f"Beneficiary: {ben.name}")
120
+
121
+ await client.close()
122
+
123
+ # Run the async function
124
+ asyncio.run(main())
125
+ ```
126
+
127
+ ### Issuing API
128
+
129
+ #### Working with Cardholders and Cards
130
+
131
+ ```python
132
+ from airwallex import AirwallexClient
133
+ from airwallex.models.issuing_cardholder import CardholderCreateRequest, Individual, Name, Address
134
+ from airwallex.models.issuing_card import CardCreateRequest, AuthorizationControls, CardProgram
135
+
136
+ # Initialize the client
137
+ client = AirwallexClient(
138
+ client_id="your_client_id",
139
+ api_key="your_api_key"
140
+ )
141
+
142
+ # Create a cardholder
143
+ cardholder_request = CardholderCreateRequest(
144
+ email="john.doe@example.com",
145
+ individual=Individual(
146
+ name=Name(
147
+ first_name="John",
148
+ last_name="Doe",
149
+ title="Mr"
150
+ ),
151
+ date_of_birth="1982-11-02",
152
+ address=Address(
153
+ city="Melbourne",
154
+ country="AU",
155
+ line1="44 Example St",
156
+ postcode="3121",
157
+ state="VIC"
158
+ ),
159
+ cardholder_agreement_terms_consent_obtained="yes",
160
+ express_consent_obtained="yes"
161
+ ),
162
+ type="INDIVIDUAL"
163
+ )
164
+
165
+ cardholder = client.issuing_cardholder.create_cardholder(cardholder_request)
166
+ print(f"Cardholder created with ID: {cardholder.cardholder_id}")
167
+
168
+ # Create a virtual card
169
+ card_request = CardCreateRequest(
170
+ cardholder_id=cardholder.cardholder_id,
171
+ request_id="unique-request-id",
172
+ created_by="API User",
173
+ form_factor="VIRTUAL",
174
+ is_personalized=True,
175
+ authorization_controls=AuthorizationControls(
176
+ allowed_currencies=["USD", "AUD"],
177
+ allowed_transaction_count="MULTIPLE"
178
+ ),
179
+ program=CardProgram(
180
+ id="your_program_id",
181
+ name="Default Program"
182
+ )
183
+ )
184
+
185
+ card = client.issuing_card.create_card(card_request)
186
+ print(f"Card created with ID: {card.card_id}")
187
+
188
+ # Get card details
189
+ card_details = client.issuing_card.get_card_details(card.card_id)
190
+ print(f"Card Number: {card_details.card_number}")
191
+ print(f"CVV: {card_details.cvv}")
192
+ print(f"Expiry: {card_details.expiry_month}/{card_details.expiry_year}")
193
+ ```
194
+
195
+ ## Documentation
196
+
197
+ For detailed documentation, see [https://www.airwallex.com/docs/api](https://www.airwallex.com/docs/api).
198
+
199
+ ## License
200
+
201
+ This project is licensed under the MIT License - see the LICENSE file for details.
202
+
@@ -0,0 +1,39 @@
1
+ airwallex/__init__.py,sha256=u37jsOHa_cPHZWNV2w5BIq65HPWimCCmMGeoCbJbzgQ,2389
2
+ airwallex/api/__init__.py,sha256=1T54Z3An7kgBNxHMhkQFv6jk2dnaT9OKL79MytcGhtg,1042
3
+ airwallex/api/account.py,sha256=kdIBXNoeAYl0p1gD6Oz1nCuQn1v6E_ESJfYxPwD5sF4,3760
4
+ airwallex/api/account_detail.py,sha256=XRrWlUm99jEhh4clqlJr3uCs6Awd2ZhXsr4h89A3eyc,17885
5
+ airwallex/api/base.py,sha256=x9WMly6i6hfX8bCy_xH0Yw77aYYdLe1NxhIm2OpBegk,20140
6
+ airwallex/api/beneficiary.py,sha256=4fprYXmqtBk5nHhp1ks3V-LXOIlV1dk0PEzoHM_sHwc,5580
7
+ airwallex/api/financial_transaction.py,sha256=6INPjTwLO99LL2ph0uVHcPSpIJ5Qyc4xW38KXrIq8TQ,4137
8
+ airwallex/api/invoice.py,sha256=JZSSqhqG5I2pATOlplvuRs70uW8JUYRU-Po08O3SW90,9488
9
+ airwallex/api/issuing_authorization.py,sha256=PSbf4MMalI7u3-xb6GGHzi2o9nh9xWTGyexgtPDvfQo,11297
10
+ airwallex/api/issuing_card.py,sha256=1SX1mMpeOsaKyICDtzuPO_E-3hwD5J0Fhai1nJuggEo,14691
11
+ airwallex/api/issuing_cardholder.py,sha256=JmblwrNN8dstzYr6Yie8FRGNuw5zcsLKu5eqJtZ4C3k,8422
12
+ airwallex/api/issuing_config.py,sha256=P_C_4hskUnwCpoxKro36xG3O6AN5Ena7dz-_NHgogPc,3015
13
+ airwallex/api/issuing_digital_wallet_token.py,sha256=CIEn15rsONkofChpOtZ_pAQnmHFwVaYlm_NF_wH3Fnk,9447
14
+ airwallex/api/issuing_transaction.py,sha256=3SjL3EtI9lMtlhCdufBrfi0qHhF7PgNjggkjwldBG50,8478
15
+ airwallex/api/issuing_transaction_dispute.py,sha256=C7rJO5LHSwq5mjsMCZlEqjWquxbZxGWFuNLBJrlpMZ8,13244
16
+ airwallex/api/payment.py,sha256=JfQJWwtvJpmYCzdLL4Sn5_FbFyd7ruez0zE5maRy_kU,5214
17
+ airwallex/client.py,sha256=21EjrBsXpdWWpvMvRz1OBpYpxiCOzlpWyRri5zm3pJM,14924
18
+ airwallex/exceptions.py,sha256=2LiIxn870uYnlKXl7AwFnNobUGBTeixbWRvNa1eLofE,6472
19
+ airwallex/models/__init__.py,sha256=6WNmWHnCm2HwtQlax1xU8S3pQH5RQtnij5OX6wLMkGQ,2119
20
+ airwallex/models/account.py,sha256=twIGjM_5eIO9AuE2RsvCHvFtJad8KmRazren9L6u2as,2393
21
+ airwallex/models/account_detail.py,sha256=rYz79PkKqg_aSRDMQFPl_hLcjaLLPkQtFlqctQ78VP0,15511
22
+ airwallex/models/base.py,sha256=eMddlaRdkhK0G7TgRUm7OMwzs7aPDRxe47_ksoGDQnM,5057
23
+ airwallex/models/beneficiary.py,sha256=X0jI2AnZHth5KMTWU5tPU_Xbkr_f2UPVmfsv5dx5GEs,4146
24
+ airwallex/models/financial_transaction.py,sha256=2XrKjwdCZrNg-mARZG8Sy1Q07psiNetbjZ8moFKCwH0,1863
25
+ airwallex/models/fx.py,sha256=pYzioeHf-5aqg7Q-BFCluyL-Z-cQUncKBcSlI_bx_AY,3172
26
+ airwallex/models/invoice.py,sha256=U3BG-RmAuygqiINymZBbWy3X0QVBlN99yadTbccZRnU,5801
27
+ airwallex/models/issuing_authorization.py,sha256=Kj5Xp7d4OtNW2wBaIRTMwMszjgLhaHnxnz9h6_DlVEM,2680
28
+ airwallex/models/issuing_card.py,sha256=nJQWcfgdlEK_CNMy6ArSHm8KE69nN3tTUtCSly81g0g,7458
29
+ airwallex/models/issuing_cardholder.py,sha256=2lwcGMWVpRycf3xCB9fHUMqgP75C6zQBV5Ca96BXjKE,2870
30
+ airwallex/models/issuing_common.py,sha256=vzZNOtLjX5quFcuT4sGxgvjYaDiKNcV8fgNzpNcqubQ,3741
31
+ airwallex/models/issuing_config.py,sha256=fJltwHT-aYOuVuAYJJfh_XDnAYtc0wshC8f0b50rMn0,3154
32
+ airwallex/models/issuing_digital_wallet_token.py,sha256=4Mycd-xOTVfRCeHpzBnPKWmaSxlf4Qzl67KMmftvVOw,2078
33
+ airwallex/models/issuing_transaction.py,sha256=SPprY12C6sLV5-fZqExzzFV3l6Llh-A93l1PrD8tcd0,2504
34
+ airwallex/models/issuing_transaction_dispute.py,sha256=OR78VtO9a5_C3FYyVrwH6UVsvW5ptym5SeDokWgoP4w,3062
35
+ airwallex/models/payment.py,sha256=Yxr2w8sesAEko7BccHR3Qwz5hly1OLfctzU3V-3levU,4393
36
+ airwallex/utils.py,sha256=qKiA1e7g-RcUs7yXpaYsUgcxoeYjCoGvytFohYwPV-Q,3685
37
+ airwallex_sdk-0.1.0.dist-info/METADATA,sha256=JpdVWVHJbs9pmpzXqHTy0KaNNMLB-Iif_b9oGAesVJQ,5600
38
+ airwallex_sdk-0.1.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
39
+ airwallex_sdk-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.8.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any