From 798370fbbfcf255cebc636c1b381637a2c3da06e Mon Sep 17 00:00:00 2001 From: Taslim Oseni Date: Mon, 9 Feb 2026 14:43:08 +0100 Subject: [PATCH 1/8] Refactor functions, add test cases --- README.md | 80 +++++++++----- embed/resources/account.py | 159 +++++++++++++++++++++++++--- embed/resources/investment.py | 73 +++++++++++-- tests/resources/test_accounts.py | 2 + tests/resources/test_investments.py | 1 + 5 files changed, 265 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 9140293..ee751d9 100644 --- a/README.md +++ b/README.md @@ -28,48 +28,70 @@ $ pip install -U embedpy To get started, sign up for your developer credentials on the [Embed Dashboard](https://embed.cowrywise.com). Once you have signed up, you can retrieve your `client_id` and `client_secret` keys from the developer dashboard. Set your credentials in the environment variables before creating an instance of the Embed Client. -```python -# Set environment variables -CLIENT_ID = CWRY-substitute-yours-here -CLIENT_SECRET = CWRY-SECRET-substitute-yours-here +### Initialization -# Create an instance of the Embed Client +```python from embed.client import Client + +# Initialize with environment variables (CLIENT_ID, CLIENT_SECRET) client = Client() + +# Or initialize with explicit credentials +client = Client( + client_id='your_client_id', + client_secret='your_client_secret', + base_url="https://sandbox.cowrywise.com" # Optional +) ``` -Alternatively, you can use your credentials to instantiate the Embed Client. During this instantiation, you can specify a base URL. This is an optional parameter that defaults to the sandbox base URL. +### Example: Creating an Account and Investment ```python -from embed.client import Client -client = Client(client_id='****', client_secret='****', base_url="https://***.cowrywise.com") +# 1. Create a user account +account = client.account.create_account( + first_name="John", + last_name="Doe", + email="john.doe@example.com", + terms_of_use_accepted=True +) +account_id = account['data']['account_id'] + +# 2. List available assets +assets = client.asset.list_assets(asset_type="tbills") + +# 3. Create an investment +investment = client.investment.create_investment( + account_id=account_id, + asset_code="AST-TBILL-0001", + amount=10000.0 +) ``` ## Embed API REST Methods | Rest Method | Endpoint | |------------------------------------------------------------------|-------------------| -| create_account(first_name=None, last_name=None, email=None) | `POST /accounts` | -| get_account(account_id) | `GET /accounts/:id` | -| update_next_of_kin(account_id=None, email=None, first_name=None,/last_name=None, phone_number=None, relationship=None, gender=None) | `POST /accounts/:id/nok` | -| get_portfolio(account_id) | `GET /accounts/:id/portfolio` | -| get_asset(asset_id) | `GET /assets/:id/` | -| list_assets(country=None, asset_type=None) | `GET /assets?country=None&asset_type=None` | -| get_index(index_id) | `GET /indexes/:id` | -| create_custom_index(account_id=None, name=None, description=None, allocations=None) | `POST /indexes` | -| modify_custom_index(account_id=None, index_id=None, allocations=None) | `PUT /indexes/:index_id` | -| get_investment(investment_id) | `GET /investments/:id` | -| create_investment(account_id=None, asset_code=None) | `POST /investments` | -| liquidate_investment(investment_id=None, units=None) | `POST /investments/:id` | -| get_price_history(asset_id=None, from_date=None, to_date=None) | `GET /prices?asset_id=None&from_date=None&to_date=None` | -| create_savings(account_id=None, days=None, interest_enabled=None, currency_code=None) | `POST /savings` | -| buy_stock(account_id=None, symbol=None, amount=None, side=None, the_type=None, time_in_force=None) | `POST /stocks/buy` | -| sell_stock(account_id=None, symbol=None, amount=None, side=None, the_type=None, time_in_force=None) | `POST /stocks/sell` | -| list_transfers(account_id=None, email=None, from_date=None, to_date=None) | `GET /transfers/:id?email=None&from_date=None&to_date=None` | -| get_deposit(deposit_id) | `GET /deposits/:id` | -| create_wallet(account_id=None, currency_code=None) | `POST /wallets` | -| transfer(wallet_id=None, product_code=None, amount=None) | `POST /wallets/:wallet_id/transfer` | -| get_wallet(wallet_id) | `GET /wallets/:wallet_id` | +| `create_account(first_name=None, last_name=None, email=None, **kwargs)` | `POST /accounts` | +| `get_account(account_id)` | `GET /accounts/:id` | +| `update_next_of_kin(account_id, email, first_name, last_name, phone_number, relationship, gender)` | `POST /accounts/:id/nok` | +| `get_portfolio(account_id)` | `GET /accounts/:id/portfolio` | +| `get_asset(asset_id)` | `GET /assets/:id/` | +| `list_assets(country=None, asset_type=None)` | `GET /assets?country=None&asset_type=None` | +| `get_index(index_id)` | `GET /indexes/:id` | +| `create_custom_index(account_id=None, name=None, description=None, allocations=None)` | `POST /indexes` | +| `modify_custom_index(account_id=None, index_id=None, allocations=None)` | `PUT /indexes/:index_id` | +| `get_investment(investment_id)` | `GET /investments/:id` | +| `create_investment(account_id=None, asset_code=None, **kwargs)` | `POST /investments` | +| `liquidate_investment(investment_id=None, units=None, **kwargs)` | `POST /investments/:id/liquidate` | +| `get_price_history(asset_id=None, from_date=None, to_date=None)` | `GET /prices?asset_id=None&from_date=None&to_date=None` | +| `create_savings(account_id=None, days=None, interest_enabled=None, currency_code=None)` | `POST /savings` | +| `buy_stock(account_id=None, symbol=None, amount=None, side=None, the_type=None, time_in_force=None)` | `POST /stocks/buy` | +| `sell_stock(account_id=None, symbol=None, amount=None, side=None, the_type=None, time_in_force=None)` | `POST /stocks/sell` | +| `list_transfers(account_id=None, email=None, from_date=None, to_date=None)` | `GET /transfers/:id?email=None&from_date=None&to_date=None` | +| `get_deposit(deposit_id)` | `GET /deposits/:id` | +| `create_wallet(account_id=None, currency_code=None)` | `POST /wallets` | +| `transfer(wallet_id=None, product_code=None, amount=None)` | `POST /wallets/:wallet_id/transfer` | +| `get_wallet(wallet_id)` | `GET /wallets/:wallet_id` | Check the [API reference](https://developers.cowrywise.com/reference) document for all resources and their respective endpoints. diff --git a/embed/resources/account.py b/embed/resources/account.py index 5f91339..67df024 100644 --- a/embed/resources/account.py +++ b/embed/resources/account.py @@ -4,7 +4,8 @@ class Account(APIResponse): """ - Handles all queries for Account + Handles all queries for Account management including creation, profile updates, + identity verification, and risk profiling. """ def __init__(self, api_session): @@ -14,6 +15,21 @@ def __init__(self, api_session): self._headers.update({"Authorization": f"Bearer {self.token}"}) def create_account(self, **kwargs): + """ + Create a new investment account. + + Args: + **kwargs: Arbitrary keyword arguments. + first_name (str): Required. Customer's first name. + last_name (str): Required. Customer's last name. + email (str): Required. Customer's email address. + phone_number (str): Optional. Customer's phone number. + terms_of_use_accepted (bool): Optional. Defaults to False. If True, accepts T&C. + idempotency_key (str): Optional. Unique key to prevent duplicate requests. + + Returns: + dict: The API response containing account details. + """ required = ["first_name", "last_name", "email"] self._validate_kwargs(required, kwargs) if "idempotency_key" in kwargs.keys(): @@ -27,6 +43,17 @@ def create_account(self, **kwargs): return self.get_essential_details(method, url, payload) def list_accounts(self, **kwargs): + """ + List all accounts with optional filtering. + + Args: + **kwargs: Arbitrary keyword arguments for pagination and filtering. + page_size (int): Optional. Number of items per page. + page (int): Optional. Current page number. + + Returns: + dict: The API response containing a list of accounts. + """ query_path = self._format_query(kwargs) method = "GET" url = self.base_url + "accounts" @@ -35,14 +62,28 @@ def list_accounts(self, **kwargs): return self.get_essential_details(method, url) def get_account(self, account_id): + """ + Retrieve a single account by its ID. + + Args: + account_id (str): The unique identifier for the account. + + Returns: + dict: The API response containing account details. + """ method = "GET" url = self.base_url + f"accounts/{account_id}" return self.get_essential_details(method, url) def get_portfolio(self, account_id): """ - Get the portfolio that belongs to an account. - The asset_id comes from calling get_all_assets() of Asset + Get the investment portfolio belonging to an account. + + Args: + account_id (str): The unique identifier for the account. + + Returns: + dict: The API response containing portfolio details. """ method = "GET" url = self.base_url + f"accounts/{account_id}/portfolio" @@ -50,7 +91,17 @@ def get_portfolio(self, account_id): def get_portfolio_performance(self, **kwargs): """ - Get the performance of a portfolio + Get the performance history of a portfolio. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + currency (str): Required. Currency code (e.g., 'NGN', 'USD'). + start_date (str): Optional. Start date in YYYY-MM-DD format. + end_date (str): Optional. End date in YYYY-MM-DD format. + + Returns: + dict: The API response containing performance metrics. """ required = ["account_id", "currency"] # optional = ["start_date", "end_date"] @@ -67,8 +118,20 @@ def get_portfolio_performance(self, **kwargs): def update_address(self, **kwargs): """ - Update the address of an account - country options: NG, GH, etc + Update the physical address of an account holder. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + street (str): Required. Street address. + lga (str): Required. Local Government Area. + area_code (str): Required. Postal or area code. + city (str): Required. City name. + state (str): Required. State name. + country (str): Required. ISO country code (e.g., 'NG', 'GH'). + + Returns: + dict: The API response containing updated account details. """ required = [ "account_id", @@ -90,8 +153,20 @@ def update_address(self, **kwargs): def update_next_of_kin(self, **kwargs): """ - Update the next of kin details. - gender options: M or F + Update next of kin details for an account. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + email (str): Required. Email of the next of kin. + first_name (str): Required. First name of the next of kin. + last_name (str): Required. Last name of the next of kin. + phone_number (str): Required. Phone number of the next of kin. + relationship (str): Required. Relationship to the account holder. + gender (str): Required. Gender ('M' or 'F'). + + Returns: + dict: The API response containing updated account details. """ required = [ "account_id", @@ -113,8 +188,19 @@ def update_next_of_kin(self, **kwargs): def update_profile(self, **kwargs): """ - Update a profile. - Gender options: M or F + Update the profile information of an account holder. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + first_name (str): Optional. + last_name (str): Optional. + phone_number (str): Optional. + gender (str): Optional. 'M' or 'F'. + date_of_birth (str): Optional. YYYY-MM-DD. + + Returns: + dict: The API response containing updated profile details. """ required = ["account_id"] self._validate_kwargs(required, kwargs) @@ -127,6 +213,18 @@ def update_profile(self, **kwargs): return self.get_essential_details(method, url, payload) def update_identity(self, **kwargs): + """ + Verify the identity of an account holder. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + identity_type (str): Required. Type of ID (e.g., 'bvn', 'nin'). + identity_value (str): Required. ID number. + + Returns: + dict: The API response containing verification status. + """ required = ["account_id", "identity_type", "identity_value"] self._validate_kwargs(required, kwargs) @@ -140,8 +238,16 @@ def update_identity(self, **kwargs): def add_bank_account(self, **kwargs): """ - Add a bank account to profile. - The bank_code can be gotten from calling get_banks() of Misc + Link a bank account to the user's profile. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + bank_code (str): Required. Bank code from Misc.get_banks(). + account_number (str): Required. 10-digit NUBAN. + + Returns: + dict: The API response containing linked bank details. """ required = ["account_id", "bank_code", "account_number"] self._validate_kwargs(required, kwargs) @@ -155,7 +261,10 @@ def add_bank_account(self, **kwargs): def get_risk_profile_questions(self): """ - Get questions to used to determine risk profile of user + Fetch questions used to determine a user's risk profile. + + Returns: + dict: The API response containing risk profile questions. """ method = "GET" url = self.base_url + "accounts/risk-profile-questions" @@ -163,7 +272,20 @@ def get_risk_profile_questions(self): def update_risk_profile(self, **kwargs): """ - Post answers to risk profile questions and get risk score + Submit answers to risk profile questions and retrieve a risk score. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + q1 (int): Required. Answer to question 1. + q2 (int): Required. Answer to question 2. + q3 (int): Required. Answer to question 3. + q4 (int): Required. Answer to question 4. + q5 (int): Required. Answer to question 5. + q6 (int): Required. Answer to question 6. + + Returns: + dict: The API response containing the risk profile score. """ required = ["account_id", "q1", "q2", "q3", "q4", "q5", "q6"] self._validate_kwargs(required, kwargs) @@ -178,8 +300,15 @@ def update_risk_profile(self, **kwargs): def get_risk_profile(self, account_id): """ - Get a customer's risk profile + Retrieve a customer's calculated risk profile. + + Args: + account_id (str): The unique identifier for the account. + + Returns: + dict: The API response containing risk profile details. """ method = "GET" url = self.base_url + f"accounts/{account_id}/risk-profile" return self.get_essential_details(method, url) + diff --git a/embed/resources/investment.py b/embed/resources/investment.py index 26f6d4f..03fa2d6 100644 --- a/embed/resources/investment.py +++ b/embed/resources/investment.py @@ -4,7 +4,7 @@ class Investment(APIResponse): """ - Handles all queries for Investment + Handles all queries for Investment including listing, creation, and liquidation. """ def __init__(self, api_session): @@ -15,8 +15,16 @@ def __init__(self, api_session): def list_investments(self, **kwargs): """ - Gets a list of investments. Filter result by asset-type by supplying - the asset-type code as `asset_type` as kwarg + Retrieve a list of all investments. + + Args: + **kwargs: Arbitrary keyword arguments. + asset_type (str): Optional. Filter by asset type code (e.g., 'tbills', 'mutual_funds'). + page_size (int): Optional. Number of items per page. + page (int): Optional. Current page number. + + Returns: + dict: The API response containing a list of investments. """ query_path = "&".join(f"{k}={v}" for k, v in kwargs.items()) method = "GET" @@ -26,11 +34,33 @@ def list_investments(self, **kwargs): return self.get_essential_details(method, url) def get_investment(self, investment_id): + """ + Retrieve details of a specific investment. + + Args: + investment_id (str): The unique identifier for the investment. + + Returns: + dict: The API response containing investment details. + """ method = "GET" url = self.base_url + f"investments/{investment_id}" return self.get_essential_details(method, url) def create_investment(self, **kwargs): + """ + Create a new investment. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + asset_code (str): Required. The code of the asset to invest in. + amount (float): Optional. Amount to invest. + idempotency_key (str): Optional. Unique key to prevent duplicate requests. + + Returns: + dict: The API response containing the new investment details. + """ required = ["account_id", "asset_code"] self._validate_kwargs(required, kwargs) @@ -44,6 +74,18 @@ def create_investment(self, **kwargs): return self.get_essential_details(method, url, payload) def liquidate_investment(self, **kwargs): + """ + Liquidate an existing investment. + + Args: + **kwargs: Arbitrary keyword arguments. + investment_id (str): Required. The unique identifier for the investment. + units (str): Required. Number of units to liquidate. + idempotency_key (str): Optional. Unique key to prevent duplicate requests. + + Returns: + dict: The API response containing liquidation details. + """ required = ["investment_id", "units"] self._validate_kwargs(required, kwargs) @@ -61,7 +103,13 @@ def liquidate_investment(self, **kwargs): def get_investment_holdings(self, investment_id): """ - For Indexes + Retrieve holdings details for an investment (specifically for Indexes). + + Args: + investment_id (str): The unique identifier for the investment. + + Returns: + dict: The API response containing holdings information. """ method = "GET" url = self.base_url + f"investments/{investment_id}/holdings" @@ -69,7 +117,13 @@ def get_investment_holdings(self, investment_id): def get_investment_performance(self, investment_id): """ - Get investment performance timeseries + Retrieve performance timeseries for an investment. + + Args: + investment_id (str): The unique identifier for the investment. + + Returns: + dict: The API response containing performance data. """ method = "GET" url = self.base_url + f"investments/{investment_id}/performance" @@ -77,8 +131,15 @@ def get_investment_performance(self, investment_id): def get_investment_returns(self, investment_id): """ - Get investment performance timeseries + Retrieve returns history for an investment. + + Args: + investment_id (str): The unique identifier for the investment. + + Returns: + dict: The API response containing returns data. """ method = "GET" url = self.base_url + f"investments/{investment_id}/returns" return self.get_essential_details(method, url) + diff --git a/tests/resources/test_accounts.py b/tests/resources/test_accounts.py index 54e5d47..cc7ccbc 100644 --- a/tests/resources/test_accounts.py +++ b/tests/resources/test_accounts.py @@ -13,6 +13,8 @@ def test_can_create_account(mock_get_essential_details, api_session): "first_name": "test", "last_name": "tester", "email": "tester@abc.com", + "phone_number": "+2348123456789", + "terms_of_use_accepted": True, "idempotency_key": "test_idempotency_key", } account.create_account(**test_data) diff --git a/tests/resources/test_investments.py b/tests/resources/test_investments.py index c1ab470..82e5cdc 100644 --- a/tests/resources/test_investments.py +++ b/tests/resources/test_investments.py @@ -43,6 +43,7 @@ def test_can_create_investment(mock_get_essential_details, api_session): test_data = { "account_id": "bbaaaaaabbb6477f866b20161e003ebb", "asset_code": "AST-TBILL-0001000000", + "amount": 5000.0, "idempotency_key": "test_idempotency_key", } investment.create_investment(**test_data) From ea32cdb42e5b30bd50ac0909465e37e5f78ee668 Mon Sep 17 00:00:00 2001 From: Taslim Oseni Date: Mon, 9 Feb 2026 14:43:59 +0100 Subject: [PATCH 2/8] Update asset and saving.py --- embed/resources/asset.py | 22 ++++++++-- embed/resources/saving.py | 90 ++++++++++++++++++++++++++++++++++++++- embed/resources/wallet.py | 48 ++++++++++++++++++++- 3 files changed, 154 insertions(+), 6 deletions(-) diff --git a/embed/resources/asset.py b/embed/resources/asset.py index ef58266..3917522 100644 --- a/embed/resources/asset.py +++ b/embed/resources/asset.py @@ -4,7 +4,7 @@ class Asset(APIResponse): """ - Handles all queries for Asset + Handles all queries for Asset discovery. """ def __init__(self, api_session): @@ -15,8 +15,15 @@ def __init__(self, api_session): def list_assets(self, **kwargs): """ - Get all the known assets. Can also filter by country by supplying - two-letter country code as "country" in kwarg + Retrieve a list of all available investment assets. + + Args: + **kwargs: Arbitrary keyword arguments. + country (str): Optional. ISO 2-letter country code (e.g., 'NG', 'GH'). + asset_type (str): Optional. Filter by asset type (e.g., 'tbills', 'mutual_funds'). + + Returns: + dict: The API response containing a list of assets. """ query_path = "&".join(f"{k}={v}" for k, v in kwargs.items()) method = "GET" @@ -27,8 +34,15 @@ def list_assets(self, **kwargs): def get_asset(self, asset_id): """ - Get a single asset by id + Retrieve details of a single asset by its ID. + + Args: + asset_id (str): The unique identifier for the asset. + + Returns: + dict: The API response containing asset details. """ method = "GET" url = self.base_url + f"assets/{asset_id}" return self.get_essential_details(method, url) + diff --git a/embed/resources/saving.py b/embed/resources/saving.py index 146ba2d..3e76237 100644 --- a/embed/resources/saving.py +++ b/embed/resources/saving.py @@ -5,7 +5,7 @@ class Saving(APIResponse): """ - Handles all queries for Saving + Handles all queries for Savings management including creation, withdrawal, and performance tracking. """ def __init__(self, api_session): @@ -15,6 +15,20 @@ def __init__(self, api_session): self._headers.update({"Authorization": f"Bearer {self.token}"}) def create_savings(self, **kwargs): + """ + Create a new savings plan. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + days (int): Required. Duration of the savings plan in days. + interest_enabled (bool): Required. Whether interest should be enabled. + currency_code (str): Required. Currency code (e.g., 'NGN', 'USD'). + idempotency_key (str): Optional. Unique key to prevent duplicate requests. + + Returns: + dict: The API response containing new savings details. + """ required = ["account_id", "days", "interest_enabled", "currency_code"] self._validate_kwargs(required, kwargs) @@ -31,6 +45,17 @@ def create_savings(self, **kwargs): return self.get_essential_details(method, url, payload) def list_savings(self, **kwargs): + """ + Retrieve a list of all savings plans. + + Args: + **kwargs: Arbitrary keyword arguments for pagination. + page_size (int): Optional. + page (int): Optional. + + Returns: + dict: The API response containing a list of savings. + """ query_path = self._format_query(kwargs) method = "GET" url = self.base_url + "savings" @@ -39,11 +64,29 @@ def list_savings(self, **kwargs): return self.get_essential_details(method, url) def get_savings(self, savings_id): + """ + Retrieve details of a specific savings plan. + + Args: + savings_id (str): The unique identifier for the savings plan. + + Returns: + dict: The API response containing savings details. + """ method = "GET" url = self.base_url + f"savings/{savings_id}" return self.get_essential_details(method, url) def get_savings_rates(self, days: int): + """ + Retrieve savings rates for a specified duration. + + Args: + days (int): The duration in days to check rates for. + + Returns: + dict: The API response containing rate information. + """ method = "POST" url = self.base_url + "savings/rates" payload = json.dumps({"days": days}) @@ -52,6 +95,18 @@ def get_savings_rates(self, days: int): def get_savings_returns( self, savings_id: str, start_date: str = None, end_date: str = None, **kwargs ): + """ + Retrieve returns history for a savings plan. + + Args: + savings_id (str): The unique identifier for the savings plan. + start_date (str): Optional. YYYY-MM-DD. + end_date (str): Optional. YYYY-MM-DD. + **kwargs: Additional filtering parameters. + + Returns: + dict: The API response containing returns data. + """ if start_date: kwargs["start_date"] = self._validate_date_string(start_date) if end_date: @@ -67,6 +122,18 @@ def get_savings_returns( def get_savings_performance( self, savings_id: str, start_date: str = None, end_date: str = None, **kwargs ): + """ + Retrieve performance timeseries for a savings plan. + + Args: + savings_id (str): The unique identifier for the savings plan. + start_date (str): Optional. YYYY-MM-DD. + end_date (str): Optional. YYYY-MM-DD. + **kwargs: Additional filtering parameters. + + Returns: + dict: The API response containing performance data. + """ if start_date: kwargs["start_date"] = self._validate_date_string(start_date) if end_date: @@ -80,13 +147,34 @@ def get_savings_performance( return self.get_essential_details(method, url) def withdraw(self, savings_id, amount): + """ + Withdraw funds from a savings plan. + + Args: + savings_id (str): The unique identifier for the savings plan. + amount (float): The amount to withdraw. + + Returns: + dict: The API response containing withdrawal details. + """ method = "POST" url = self.base_url + f"savings/{savings_id}/withdraw" payload = json.dumps({"amount": amount}) return self.get_essential_details(method, url, payload) def rollover(self, savings_id, days): + """ + Rollover a savings plan for an additional duration. + + Args: + savings_id (str): The unique identifier for the savings plan. + days (int): Additional duration in days. + + Returns: + dict: The API response containing rollover details. + """ method = "POST" url = self.base_url + f"savings/{savings_id}/rollover" payload = json.dumps({"days": days}) return self.get_essential_details(method, url, payload) + diff --git a/embed/resources/wallet.py b/embed/resources/wallet.py index 062bf3f..814ae7b 100644 --- a/embed/resources/wallet.py +++ b/embed/resources/wallet.py @@ -4,7 +4,7 @@ class Wallet(APIResponse): """ - Handles all queries for Wallet + Handles all queries for Wallet management and transfers. """ def __init__(self, api_session): @@ -14,6 +14,17 @@ def __init__(self, api_session): self._headers.update({"Authorization": f"Bearer {self.token}"}) def list_wallets(self, **kwargs): + """ + Retrieve a list of all wallets. + + Args: + **kwargs: Arbitrary keyword arguments. + page_size (int): Optional. Number of items per page. + page (int): Optional. Current page number. + + Returns: + dict: The API response containing a list of wallets. + """ query_path = self._format_query(kwargs) method = "GET" url = self.base_url + "wallets" @@ -22,11 +33,32 @@ def list_wallets(self, **kwargs): return self.get_essential_details(method, url) def get_wallet(self, wallet_id): + """ + Retrieve details of a specific wallet. + + Args: + wallet_id (str): The unique identifier for the wallet. + + Returns: + dict: The API response containing wallet details. + """ method = "GET" url = self.base_url + f"wallets/{wallet_id}" return self.get_essential_details(method, url) def create_wallet(self, **kwargs): + """ + Create a new wallet for an account. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + currency_code (str): Required. Currency code (e.g., 'NGN', 'USD'). + idempotency_key (str): Optional. Unique key to prevent duplicate requests. + + Returns: + dict: The API response containing new wallet details. + """ required = ["account_id", "currency_code"] self._validate_kwargs(required, kwargs) @@ -42,6 +74,19 @@ def create_wallet(self, **kwargs): return self.get_essential_details(method, url, payload) def transfer(self, **kwargs): + """ + Transfer funds from a wallet to a product (e.g., investment). + + Args: + **kwargs: Arbitrary keyword arguments. + wallet_id (str): Required. The source wallet ID. + product_code (str): Required. The destination product code. + amount (float): Required. Amount to transfer. + idempotency_key (str): Optional. Unique key to prevent duplicate requests. + + Returns: + dict: The API response containing transfer details. + """ required = ["wallet_id", "product_code", "amount"] self._validate_kwargs(required, kwargs) @@ -55,3 +100,4 @@ def transfer(self, **kwargs): url = self.base_url + f"wallets/{wallet_id}/transfer" payload = json.dumps(kwargs) return self.get_essential_details(method, url, payload) + From f361fb708c3ec4583781b67debf50ee5b407062c Mon Sep 17 00:00:00 2001 From: Taslim Oseni Date: Mon, 9 Feb 2026 14:52:00 +0100 Subject: [PATCH 3/8] Fix failing tests --- embed/resources/index.py | 112 +++++++++++++++++++++++--------- tests/resources/test_indexes.py | 3 +- 2 files changed, 82 insertions(+), 33 deletions(-) diff --git a/embed/resources/index.py b/embed/resources/index.py index ca0d6f7..b840e19 100644 --- a/embed/resources/index.py +++ b/embed/resources/index.py @@ -1,9 +1,10 @@ +import json from embed.common import APIResponse class Index(APIResponse): """ - Handles all queries for Indices + Handles all queries for Indices management including custom index creation and modification. """ def __init__(self, api_session): @@ -13,6 +14,17 @@ def __init__(self, api_session): self._headers.update({"Authorization": f"Bearer {self.token}"}) def list_indexes(self, **kwargs): + """ + Retrieve a list of all available indices. + + Args: + **kwargs: Arbitrary keyword arguments for pagination. + page_size (int): Optional. + page (int): Optional. + + Returns: + dict: The API response containing a list of indices. + """ query_path = self._format_query(kwargs) method = "GET" url = self.base_url + "indexes" @@ -21,42 +33,80 @@ def list_indexes(self, **kwargs): return self.get_essential_details(method, url) def get_index(self, index_id): + """ + Retrieve details of a specific index. + + Args: + index_id (str): The unique identifier for the index. + + Returns: + dict: The API response containing index details. + """ method = "GET" url = self.base_url + f"indexes/{index_id}" return self.get_essential_details(method, url) def get_index_assets(self, asset_id): + """ + Retrieve assets contained within a specific index. + + Args: + asset_id (str): The unique identifier for the index (asset). + + Returns: + dict: The API response containing a list of assets in the index. + """ method = "GET" url = self.base_url + f"indexes/{asset_id}/assets" return self.get_essential_details(method, url) - # def create_custom_index(self, **kwargs): - # """TODO: future release""" - # required = ["account_id", "name", "description", "allocations"] - # for key in required: - # if key not in kwargs.keys(): - # raise ValidationError(f"{key} is required.") - # - # if "idempotency_key" in kwargs.keys(): - # self._headers.update( - # {"Embed-Idempotency-Key": str(kwargs.pop("idempotency_key"))} - # ) - # - # method = "POST" - # url = self.base_url + "indexes" - # payload = json.dumps(kwargs) - # return self.get_essential_details(method, url, payload) - # - # def modify_custom_index(self, **kwargs): - # """TODO: future release""" - # required = ["account_id", "index_id"] - # for key in required: - # if key not in kwargs.keys(): - # raise ValidationError(f"{key} is required.") - # - # method = "PUT" - # index_id = kwargs.get("index_id") - # url = self.base_url + f"indexes/{index_id}" - # - # payload = json.dumps(kwargs) - # return self.get_essential_details(method, url, payload) + def create_custom_index(self, **kwargs): + """ + Create a custom index for a user. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + name (str): Required. Name of the custom index. + description (str): Required. Description of the index. + allocations (list): Required. List of asset codes and their weights. + idempotency_key (str): Optional. Unique key to prevent duplicate requests. + + Returns: + dict: The API response containing new custom index details. + """ + required = ["account_id", "name", "description", "allocations"] + self._validate_kwargs(required, kwargs) + + if "idempotency_key" in kwargs.keys(): + self._headers.update( + {"Embed-Idempotency-Key": str(kwargs.pop("idempotency_key"))} + ) + + method = "POST" + url = self.base_url + "indexes" + payload = json.dumps(kwargs) + return self.get_essential_details(method, url, payload) + + def modify_custom_index(self, **kwargs): + """ + Modify an existing custom index. + + Args: + **kwargs: Arbitrary keyword arguments. + account_id (str): Required. The unique identifier for the account. + index_id (str): Required. The unique identifier for the index to modify. + allocations (list): Optional. Updated list of asset codes and weights. + + Returns: + dict: The API response containing updated index details. + """ + required = ["account_id", "index_id"] + self._validate_kwargs(required, kwargs) + + method = "PUT" + index_id = kwargs.pop("index_id") + url = self.base_url + f"indexes/{index_id}" + + payload = json.dumps(kwargs) + return self.get_essential_details(method, url, payload) diff --git a/tests/resources/test_indexes.py b/tests/resources/test_indexes.py index 0734869..35406bd 100644 --- a/tests/resources/test_indexes.py +++ b/tests/resources/test_indexes.py @@ -39,7 +39,6 @@ def test_can_get_index_assets(mock_get_essential_details, api_session): @patch("embed.common.APIResponse.get_essential_details") -@pytest.mark.skip(reason="Custom Index creation not yet implemented") def test_can_create_custom_index(mock_get_essential_details, api_session): index = Index(api_session) mock_get_essential_details.return_value = MagicMock() @@ -66,7 +65,6 @@ def test_can_create_custom_index(mock_get_essential_details, api_session): @patch("embed.common.APIResponse.get_essential_details") -@pytest.mark.skip(reason="Custom Index creation not yet implemented") def test_can_modify_custom_index(mock_get_essential_details, api_session): index = Index(api_session) mock_get_essential_details.return_value = MagicMock() @@ -84,6 +82,7 @@ def test_can_modify_custom_index(mock_get_essential_details, api_session): index_id=test_data.get("index_id"), allocations=test_data.get("allocations"), ) + test_data.pop("index_id") index.get_essential_details.assert_called_with( "PUT", f"{api_session.base_url}/api/{api_session.api_version}/indexes/fake-index-id", From 19b842dfc77cc81bd9403dbc040f60d3d907a8bc Mon Sep 17 00:00:00 2001 From: Taslim Oseni Date: Mon, 9 Feb 2026 16:12:09 +0100 Subject: [PATCH 4/8] Update GitHub actions --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b0dbdc..29922fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.9 @@ -24,7 +24,7 @@ jobs: # Getting only staged files can be tricky in case a new PR is opened # since the action is run on a branch in detached head state - name: Install and Run Pre-commit - uses: pre-commit/action@v2.0.3 + uses: pre-commit/action@v3.0.1 with: token: ${{ secrets.GITHUB_TOKEN }} #This would attempt to push back fixes @@ -33,13 +33,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 # with: # token: ${{ secrets.PAT }} # submodules: recursive - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.9 From 3d76b0936c47f43179d7e4fe40921713fdbfd5fa Mon Sep 17 00:00:00 2001 From: Taslim Oseni Date: Mon, 9 Feb 2026 16:16:38 +0100 Subject: [PATCH 5/8] Fix end-of-file-fixer pre-commit hook error --- embed/resources/account.py | 1 - embed/resources/asset.py | 1 - embed/resources/investment.py | 1 - embed/resources/saving.py | 1 - embed/resources/wallet.py | 1 - 5 files changed, 5 deletions(-) diff --git a/embed/resources/account.py b/embed/resources/account.py index 67df024..5275bb7 100644 --- a/embed/resources/account.py +++ b/embed/resources/account.py @@ -311,4 +311,3 @@ def get_risk_profile(self, account_id): method = "GET" url = self.base_url + f"accounts/{account_id}/risk-profile" return self.get_essential_details(method, url) - diff --git a/embed/resources/asset.py b/embed/resources/asset.py index 3917522..479be76 100644 --- a/embed/resources/asset.py +++ b/embed/resources/asset.py @@ -45,4 +45,3 @@ def get_asset(self, asset_id): method = "GET" url = self.base_url + f"assets/{asset_id}" return self.get_essential_details(method, url) - diff --git a/embed/resources/investment.py b/embed/resources/investment.py index 03fa2d6..5a89c0f 100644 --- a/embed/resources/investment.py +++ b/embed/resources/investment.py @@ -142,4 +142,3 @@ def get_investment_returns(self, investment_id): method = "GET" url = self.base_url + f"investments/{investment_id}/returns" return self.get_essential_details(method, url) - diff --git a/embed/resources/saving.py b/embed/resources/saving.py index 3e76237..affddb0 100644 --- a/embed/resources/saving.py +++ b/embed/resources/saving.py @@ -177,4 +177,3 @@ def rollover(self, savings_id, days): url = self.base_url + f"savings/{savings_id}/rollover" payload = json.dumps({"days": days}) return self.get_essential_details(method, url, payload) - diff --git a/embed/resources/wallet.py b/embed/resources/wallet.py index 814ae7b..2096d10 100644 --- a/embed/resources/wallet.py +++ b/embed/resources/wallet.py @@ -100,4 +100,3 @@ def transfer(self, **kwargs): url = self.base_url + f"wallets/{wallet_id}/transfer" payload = json.dumps(kwargs) return self.get_essential_details(method, url, payload) - From 3d0c672f8ae3ec257da60b24ecf1aebd88cd037c Mon Sep 17 00:00:00 2001 From: Taslim Oseni Date: Mon, 9 Feb 2026 16:22:41 +0100 Subject: [PATCH 6/8] Update Pipfile --- Pipfile | 2 +- Pipfile.lock | 623 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 438 insertions(+), 187 deletions(-) diff --git a/Pipfile b/Pipfile index 9e9d1c1..ca77fae 100644 --- a/Pipfile +++ b/Pipfile @@ -13,4 +13,4 @@ pytest = "*" pytest-cov = "*" [requires] -python_version = "3.8" +python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock index dc55b80..2118149 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "8e1fe5d5827d0cb9abe266f6dcd57d4e434ac5dc19c22a9a699b138077931319" + "sha256": "6b19db269a97c693642d0e6187e7837688dd88aa9551ef9b8727a45b998ecd58" }, "pipfile-spec": 6, "requires": { - "python_version": "3.8" + "python_version": "3.9" }, "sources": [ { @@ -18,290 +18,541 @@ "default": { "certifi": { "hashes": [ - "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", - "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", + "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120" ], - "version": "==2021.10.8" + "markers": "python_version >= '3.7'", + "version": "==2026.1.4" }, "charset-normalizer": { "hashes": [ - "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", - "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" + "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", + "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", + "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", + "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", + "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc", + "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", + "sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63", + "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d", + "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", + "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", + "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", + "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505", + "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", + "sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af", + "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", + "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318", + "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", + "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", + "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", + "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", + "sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576", + "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", + "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1", + "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", + "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1", + "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", + "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", + "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", + "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88", + "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", + "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", + "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", + "sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a", + "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", + "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", + "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", + "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", + "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", + "sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7", + "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", + "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", + "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", + "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", + "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", + "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", + "sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2", + "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", + "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", + "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", + "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", + "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf", + "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6", + "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", + "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", + "sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa", + "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", + "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", + "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", + "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", + "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", + "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", + "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", + "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", + "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", + "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", + "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", + "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", + "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", + "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", + "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", + "sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3", + "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9", + "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", + "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", + "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", + "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", + "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50", + "sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf", + "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", + "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", + "sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac", + "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", + "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", + "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c", + "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", + "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", + "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e", + "sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4", + "sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84", + "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", + "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", + "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", + "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", + "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", + "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", + "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", + "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", + "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", + "sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074", + "sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3", + "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", + "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", + "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", + "sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d", + "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", + "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", + "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", + "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", + "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966", + "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", + "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3", + "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", + "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608" ], - "markers": "python_version >= '3'", - "version": "==2.0.12" + "markers": "python_version >= '3.7'", + "version": "==3.4.4" }, "idna": { "hashes": [ - "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", - "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", + "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" ], - "markers": "python_version >= '3'", - "version": "==3.3" + "markers": "python_version >= '3.8'", + "version": "==3.11" }, "requests": { "hashes": [ - "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", - "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" + "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", + "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf" ], "index": "pypi", - "version": "==2.27.1" + "markers": "python_version >= '3.9'", + "version": "==2.32.5" }, "urllib3": { "hashes": [ - "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", - "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" + "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", + "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.9" + "markers": "python_version >= '3.9'", + "version": "==2.6.3" } }, "develop": { - "attrs": { - "hashes": [ - "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", - "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.4.0" - }, "cfgv": { "hashes": [ - "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426", - "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736" + "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", + "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560" ], - "markers": "python_full_version >= '3.6.1'", - "version": "==3.3.1" + "markers": "python_version >= '3.8'", + "version": "==3.4.0" }, "coverage": { "extras": [ "toml" ], "hashes": [ - "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9", - "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d", - "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf", - "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7", - "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6", - "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4", - "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059", - "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39", - "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536", - "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac", - "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c", - "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903", - "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d", - "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05", - "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684", - "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1", - "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f", - "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7", - "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca", - "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad", - "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca", - "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d", - "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92", - "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4", - "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf", - "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6", - "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1", - "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4", - "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359", - "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3", - "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620", - "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512", - "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69", - "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2", - "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518", - "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0", - "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa", - "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4", - "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e", - "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1", - "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2" + "sha256:03ffc58aacdf65d2a82bbeb1ffe4d01ead4017a21bfd0454983b88ca73af94b9", + "sha256:097c1591f5af4496226d5783d036bf6fd6cd0cbc132e071b33861de756efb880", + "sha256:0b944ee8459f515f28b851728ad224fa2d068f1513ef6b7ff1efafeb2185f999", + "sha256:0ebbaddb2c19b71912c6f2518e791aa8b9f054985a0769bdb3a53ebbc765c6a1", + "sha256:10b24412692df990dbc34f8fb1b6b13d236ace9dfdd68df5b28c2e39cafbba13", + "sha256:10b6ba00ab1132a0ce4428ff68cf50a25efd6840a42cdf4239c9b99aad83be8b", + "sha256:121da30abb574f6ce6ae09840dae322bef734480ceafe410117627aa54f76d82", + "sha256:18afb24843cbc175687225cab1138c95d262337f5473512010e46831aa0c2973", + "sha256:1b4fd784344d4e52647fd7857b2af5b3fbe6c239b0b5fa63e94eb67320770e0f", + "sha256:1ca6db7c8807fb9e755d0379ccc39017ce0a84dcd26d14b5a03b78563776f681", + "sha256:1ef2319dd15a0b009667301a3f84452a4dc6fddfd06b0c5c53ea472d3989fbf0", + "sha256:2120043f147bebb41c85b97ac45dd173595ff14f2a584f2963891cbcc3091541", + "sha256:212f8f2e0612778f09c55dd4872cb1f64a1f2b074393d139278ce902064d5b32", + "sha256:240af60539987ced2c399809bd34f7c78e8abe0736af91c3d7d0e795df633d17", + "sha256:2a78cd46550081a7909b3329e2266204d584866e8d97b898cd7fb5ac8d888b1a", + "sha256:2af88deffcc8a4d5974cf2d502251bc3b2db8461f0b66d80a449c33757aa9f40", + "sha256:2c8b9a0636f94c43cd3576811e05b89aa9bc2d0a85137affc544ae5cb0e4bfbd", + "sha256:2fafd773231dd0378fdba66d339f84904a8e57a262f583530f4f156ab83863e6", + "sha256:314f2c326ded3f4b09be11bc282eb2fc861184bc95748ae67b360ac962770be7", + "sha256:33a5e6396ab684cb43dc7befa386258acb2d7fae7f67330ebb85ba4ea27938eb", + "sha256:3445258bcded7d4aa630ab8296dea4d3f15a255588dd535f980c193ab6b95f3f", + "sha256:35f5e3f9e455bb17831876048355dca0f758b6df22f49258cb5a91da23ef437d", + "sha256:39508ffda4f343c35f3236fe8d1a6634a51f4581226a1262769d7f970e73bffe", + "sha256:399a0b6347bcd3822be369392932884b8216d0944049ae22925631a9b3d4ba4c", + "sha256:3a622ac801b17198020f09af3eaf45666b344a0d69fc2a6ffe2ea83aeef1d807", + "sha256:4376538f36b533b46f8971d3a3e63464f2c7905c9800db97361c43a2b14792ab", + "sha256:4b583b97ab2e3efe1b3e75248a9b333bd3f8b0b1b8e5b45578e05e5850dfb2c2", + "sha256:4b6f236edf6e2f9ae8fcd1332da4e791c1b6ba0dc16a2dc94590ceccb482e546", + "sha256:4da86b6d62a496e908ac2898243920c7992499c1712ff7c2b6d837cc69d9467e", + "sha256:50aa94fb1fb9a397eaa19c0d5ec15a5edd03a47bf1a3a6111a16b36e190cff65", + "sha256:567f5c155eda8df1d3d439d40a45a6a5f029b429b06648235f1e7e51b522b396", + "sha256:5a02d5a850e2979b0a014c412573953995174743a3f7fa4ea5a6e9a3c5617431", + "sha256:5e1e9802121405ede4b0133aa4340ad8186a1d2526de5b7c3eca519db7bb89fb", + "sha256:5f33166f0dfcce728191f520bd2692914ec70fac2713f6bf3ce59c3deacb4699", + "sha256:606cc265adc9aaedcc84f1f064f0e8736bc45814f15a357e30fca7ecc01504e0", + "sha256:635adb9a4507c9fd2ed65f39693fa31c9a3ee3a8e6dc64df033e8fdf52a7003f", + "sha256:65646bb0359386e07639c367a22cf9b5bf6304e8630b565d0626e2bdf329227a", + "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235", + "sha256:69212fbccdbd5b0e39eac4067e20a4a5256609e209547d86f740d68ad4f04911", + "sha256:6b8b09c1fad947c84bbbc95eca841350fad9cbfa5a2d7ca88ac9f8d836c92e23", + "sha256:6be8ed3039ae7f7ac5ce058c308484787c86e8437e72b30bf5e88b8ea10f3c87", + "sha256:6e16e07d85ca0cf8bafe5f5d23a0b850064e8e945d5677492b06bbe6f09cc699", + "sha256:736f227fb490f03c6488f9b6d45855f8e0fd749c007f9303ad30efab0e73c05a", + "sha256:73ab1601f84dc804f7812dc297e93cd99381162da39c47040a827d4e8dafe63b", + "sha256:77eb4c747061a6af8d0f7bdb31f1e108d172762ef579166ec84542f711d90256", + "sha256:78a384e49f46b80fb4c901d52d92abe098e78768ed829c673fbb53c498bef73a", + "sha256:7bb3b9ddb87ef7725056572368040c32775036472d5a033679d1fa6c8dc08417", + "sha256:7ea7c6c9d0d286d04ed3541747e6597cbe4971f22648b68248f7ddcd329207f0", + "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a", + "sha256:813922f35bd800dca9994c5971883cbc0d291128a5de6b167c7aa697fcf59360", + "sha256:83082a57783239717ceb0ad584de3c69cf581b2a95ed6bf81ea66034f00401c0", + "sha256:8421e088bc051361b01c4b3a50fd39a4b9133079a2229978d9d30511fd05231b", + "sha256:86b0e7308289ddde73d863b7683f596d8d21c7d8664ce1dee061d0bcf3fbb4bb", + "sha256:88127d40df529336a9836870436fc2751c339fbaed3a836d42c93f3e4bd1d0a2", + "sha256:8fb190658865565c549b6b4706856d6a7b09302c797eb2cf8e7fe9dabb043f0d", + "sha256:912e6ebc7a6e4adfdbb1aec371ad04c68854cd3bf3608b3514e7ff9062931d8a", + "sha256:925a1edf3d810537c5a3abe78ec5530160c5f9a26b1f4270b40e62cc79304a1e", + "sha256:93c1b03552081b2a4423091d6fb3787265b8f86af404cff98d1b5342713bdd69", + "sha256:972b9e3a4094b053a4e46832b4bc829fc8a8d347160eb39d03f1690316a99c14", + "sha256:981a651f543f2854abd3b5fcb3263aac581b18209be49863ba575de6edf4c14d", + "sha256:99e4aa63097ab1118e75a848a28e40d68b08a5e19ce587891ab7fd04475e780f", + "sha256:9fa6e4dd51fe15d8738708a973470f67a855ca50002294852e9571cdbd9433f2", + "sha256:a0ec07fd264d0745ee396b666d47cef20875f4ff2375d7c4f58235886cc1ef0c", + "sha256:a2d9a3b260cc1d1dbdb1c582e63ddcf5363426a1a68faa0f5da28d8ee3c722a0", + "sha256:a3cc8638b2480865eaa3926d192e64ce6c51e3d29c849e09d5b4ad95efae5399", + "sha256:a609f9c93113be646f44c2a0256d6ea375ad047005d7f57a5c15f614dc1b2f59", + "sha256:a62c6ef0d50e6de320c270ff91d9dd0a05e7250cac2a800b7784bae474506e63", + "sha256:a6442c59a8ac8b85812ce33bc4d05bde3fb22321fa8294e2a5b487c3505f611b", + "sha256:a7b55a944a7f43892e28ad4bc0561dfd5f0d73e605d1aa5c3c976b52aea121d2", + "sha256:a8b6f03672aa6734e700bbcd65ff050fd19cddfec4b031cc8cf1c6967de5a68e", + "sha256:affef7c76a9ef259187ef31599a9260330e0335a3011732c4b9effa01e1cd6e0", + "sha256:b06f260b16ead11643a5a9f955bd4b5fd76c1a4c6796aeade8520095b75de520", + "sha256:b1c81d0e5e160651879755c9c675b974276f135558cf4ba79fee7b8413a515df", + "sha256:b281d5eca50189325cfe1f365fafade89b14b4a78d9b40b05ddd1fc7d2a10a9c", + "sha256:b51dcd060f18c19290d9b8a9dd1e0181538df2ce0717f562fff6cf74d9fc0b5b", + "sha256:b7b8288eb7cdd268b0304632da8cb0bb93fadcfec2fe5712f7b9cc8f4d487be2", + "sha256:b9be91986841a75042b3e3243d0b3cb0b2434252b977baaf0cd56e960fe1e46f", + "sha256:ba58bbcd1b72f136080c0bccc2400d66cc6115f3f906c499013d065ac33a4b61", + "sha256:bb45474711ba385c46a0bfe696c695a929ae69ac636cda8f532be9e8c93d720a", + "sha256:bc01f57ca26269c2c706e838f6422e2a8788e41b3e3c65e2f41148212e57cd59", + "sha256:bc91b314cef27742da486d6839b677b3f2793dfe52b51bbbb7cf736d5c29281c", + "sha256:bda5e34f8a75721c96085903c6f2197dc398c20ffd98df33f866a9c8fd95f4bf", + "sha256:c134869d5ffe34547d14e174c866fd8fe2254918cc0a95e99052903bc1543e07", + "sha256:c41e71c9cfb854789dee6fc51e46743a6d138b1803fab6cb860af43265b42ea6", + "sha256:c4e16bd7761c5e454f4efd36f345286d6f7c5fa111623c355691e2755cae3b9e", + "sha256:c7315339eae3b24c2d2fa1ed7d7a38654cba34a13ef19fbcb9425da46d3dc594", + "sha256:c79124f70465a150e89340de5963f936ee97097d2ef76c869708c4248c63ca49", + "sha256:cac0fdca17b036af3881a9d2729a850b76553f3f716ccb0360ad4dbc06b3b843", + "sha256:cc87dd1b6eaf0b848eebb1c86469b9f72a1891cb42ac7adcfbce75eadb13dd14", + "sha256:cce2109b6219f22ece99db7644b9622f54a4e915dad65660ec435e89a3ea7cc3", + "sha256:d41213ea25a86f69efd1575073d34ea11aabe075604ddf3d148ecfec9e1e96a1", + "sha256:dc7c389dce432500273eaf48f410b37886be9208b2dd5710aaf7c57fd442c698", + "sha256:dd5e856ebb7bfb7672b0086846db5afb4567a7b9714b8a0ebafd211ec7ce6a15", + "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d", + "sha256:e201e015644e207139f7e2351980feb7040e6f4b2c2978892f3e3789d1c125e5", + "sha256:e28299d9f2e889e6d51b1f043f58d5f997c373cc12e6403b90df95b8b047c13e", + "sha256:f3c887f96407cea3916294046fc7dab611c2552beadbed4ea901cbc6a40cc7a0", + "sha256:f49a05acd3dfe1ce9715b657e28d138578bc40126760efb962322c56e9ca344b", + "sha256:f4ab143ab113be368a3e9b795f9cd7906c5ef407d6173fe9675a902e1fffc239", + "sha256:f51328ffe987aecf6d09f3cd9d979face89a617eacdaea43e7b3080777f647ba", + "sha256:f57b2a3c8353d3e04acf75b3fed57ba41f5c0646bbf1d10c7c282291c97936b4", + "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", + "sha256:fc04cc7a3db33664e0c2d10eb8990ff6b3536f6842c9590ae8da4c614b9ed05a", + "sha256:fff7b9c3f19957020cac546c70025331113d2e61537f6e2441bc7657913de7d3" ], - "markers": "python_version >= '3.7'", - "version": "==6.3.2" + "markers": "python_version >= '3.9'", + "version": "==7.10.7" }, "distlib": { "hashes": [ - "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b", - "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579" + "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", + "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d" ], - "version": "==0.3.4" + "version": "==0.4.0" }, - "filelock": { + "exceptiongroup": { "hashes": [ - "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85", - "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0" + "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", + "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598" ], "markers": "python_version >= '3.7'", - "version": "==3.6.0" + "version": "==1.3.1" + }, + "filelock": { + "hashes": [ + "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", + "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d" + ], + "markers": "python_version >= '3.9'", + "version": "==3.19.1" }, "identify": { "hashes": [ - "sha256:3f3244a559290e7d3deb9e9adc7b33594c1bc85a9dd82e0f1be519bf12a1ec17", - "sha256:5f06b14366bd1facb88b00540a1de05b69b310cbc2654db3c7e07fa3a4339323" + "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", + "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf" ], - "markers": "python_version >= '3.7'", - "version": "==2.4.12" + "markers": "python_version >= '3.9'", + "version": "==2.6.15" }, "iniconfig": { "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], - "version": "==1.1.1" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" }, "nodeenv": { "hashes": [ - "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b", - "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7" + "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", + "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb" ], - "version": "==1.6.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==1.10.0" }, "packaging": { "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", + "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529" ], - "markers": "python_version >= '3.6'", - "version": "==21.3" + "markers": "python_version >= '3.8'", + "version": "==26.0" }, "platformdirs": { "hashes": [ - "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d", - "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227" + "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", + "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf" ], - "markers": "python_version >= '3.7'", - "version": "==2.5.1" + "markers": "python_version >= '3.9'", + "version": "==4.4.0" }, "pluggy": { "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" + "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", + "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" ], - "markers": "python_version >= '3.6'", - "version": "==1.0.0" + "markers": "python_version >= '3.9'", + "version": "==1.6.0" }, "pre-commit": { "hashes": [ - "sha256:02226e69564ebca1a070bd1f046af866aa1c318dbc430027c50ab832ed2b73f2", - "sha256:5d445ee1fa8738d506881c5d84f83c62bb5be6b2838e32207433647e8e5ebe10" + "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8", + "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16" ], "index": "pypi", - "version": "==2.18.1" - }, - "py": { - "hashes": [ - "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", - "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.11.0" + "markers": "python_version >= '3.9'", + "version": "==4.3.0" }, - "pyparsing": { + "pygments": { "hashes": [ - "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", - "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" + "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", + "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" ], - "markers": "python_version >= '3.6'", - "version": "==3.0.7" + "markers": "python_version >= '3.8'", + "version": "==2.19.2" }, "pytest": { "hashes": [ - "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63", - "sha256:92f723789a8fdd7180b6b06483874feca4c48a5c76968e03bb3e7f806a1869ea" + "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", + "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79" ], "index": "pypi", - "version": "==7.1.1" + "markers": "python_version >= '3.9'", + "version": "==8.4.2" }, "pytest-cov": { "hashes": [ - "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6", - "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470" + "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", + "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861" ], "index": "pypi", - "version": "==3.0.0" + "markers": "python_version >= '3.9'", + "version": "==7.0.0" }, "pytest-mock": { "hashes": [ - "sha256:5112bd92cc9f186ee96e1a92efc84969ea494939c3aead39c50f421c4cc69534", - "sha256:6cff27cec936bf81dc5ee87f07132b807bcda51106b5ec4b90a04331cba76231" + "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", + "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f" ], "index": "pypi", - "version": "==3.7.0" + "markers": "python_version >= '3.9'", + "version": "==3.15.1" }, "pyyaml": { "hashes": [ - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", + "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", + "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", + "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", + "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", + "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", + "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", + "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", + "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", + "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", + "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", + "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6", + "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", + "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", + "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", + "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", + "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", + "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", + "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295", + "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", + "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", + "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", + "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", + "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", + "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", + "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", + "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", + "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b", + "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", + "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", + "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", + "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", + "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369", + "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", + "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", + "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", + "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", + "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", + "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", + "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", + "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", + "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", + "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", + "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", + "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", + "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", + "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", + "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", + "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", + "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4", + "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", + "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", + "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", + "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", + "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", + "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", + "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", + "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", + "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", + "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", + "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", + "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f", + "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", + "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", + "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", + "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", + "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", + "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", + "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", + "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3", + "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", + "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", + "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0" ], - "markers": "python_version >= '3.6'", - "version": "==6.0" + "markers": "python_version >= '3.8'", + "version": "==6.0.3" }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "toml": { + "tomli": { "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" + "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", + "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", + "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", + "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", + "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", + "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", + "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", + "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", + "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", + "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", + "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", + "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", + "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", + "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", + "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", + "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", + "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", + "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", + "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", + "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", + "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", + "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", + "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", + "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", + "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", + "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", + "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", + "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", + "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", + "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", + "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", + "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", + "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", + "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", + "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", + "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", + "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", + "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", + "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", + "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", + "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", + "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", + "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", + "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", + "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", + "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", + "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" + "markers": "python_version >= '3.8'", + "version": "==2.4.0" }, - "tomli": { + "typing-extensions": { "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", + "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.1" + "markers": "python_version >= '3.9'", + "version": "==4.15.0" }, "virtualenv": { "hashes": [ - "sha256:1e8588f35e8b42c6ec6841a13c5e88239de1e6e4e4cedfd3916b306dc826ec66", - "sha256:8e5b402037287126e81ccde9432b95a8be5b19d36584f64957060a3488c11ca8" + "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", + "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==20.14.0" + "markers": "python_version >= '3.8'", + "version": "==20.36.1" } } } From 6c8c14616305d1d1b944ce46c2f4d870277f6b86 Mon Sep 17 00:00:00 2001 From: Taslim Oseni Date: Mon, 9 Feb 2026 16:43:31 +0100 Subject: [PATCH 7/8] Bump app version --- Pipfile.lock | 2 +- embed/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 2118149..2af7e7b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -328,7 +328,7 @@ "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], "markers": "python_version >= '3.8'", - "version": "==2.1.0" + "version": "==2.1.1" }, "nodeenv": { "hashes": [ diff --git a/embed/version.py b/embed/version.py index 6b14445..d873269 100644 --- a/embed/version.py +++ b/embed/version.py @@ -1,4 +1,4 @@ -__version__ = "2.1.0" +__version__ = "2.1.1" __author__ = "Cowrywise Developers" __license__ = "MIT" __copyright__ = "Copyright 2021. Cowrywise" From e9314c52ec64885d697a73a1e83f2a2f68a993ab Mon Sep 17 00:00:00 2001 From: Taslim Oseni Date: Mon, 9 Feb 2026 16:46:38 +0100 Subject: [PATCH 8/8] Fix error from unknown library version --- Pipfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipfile.lock b/Pipfile.lock index 2af7e7b..2118149 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -328,7 +328,7 @@ "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], "markers": "python_version >= '3.8'", - "version": "==2.1.1" + "version": "==2.1.0" }, "nodeenv": { "hashes": [