diff --git a/.wordlist.txt b/.wordlist.txt
index 69006a43..07460fd0 100644
--- a/.wordlist.txt
+++ b/.wordlist.txt
@@ -323,3 +323,12 @@ iadd
isub
repr
nanomobx
+OnCollision
+iter
+getitem
+getter
+delitem
+eq
+exc
+iterable
+denoms
diff --git a/cosmpy/aerial/coins.py b/cosmpy/aerial/coins.py
index 1ae7f5cd..07d09b8a 100644
--- a/cosmpy/aerial/coins.py
+++ b/cosmpy/aerial/coins.py
@@ -21,7 +21,10 @@
import re
from dataclasses import dataclass
-from typing import List, Optional, Union
+from enum import Enum
+from typing import Iterable, List, Optional, Union
+
+from sortedcontainers import SortedDict
from cosmpy.protos.cosmos.base.v1beta1.coin_pb2 import Coin as CoinProto
@@ -31,30 +34,53 @@
@dataclass
class Coin:
- """Coins."""
+ """Coins.
+
+ This class does not implicitly ensure that its value represents a valid coin based on Cosmos-SDK requirements.
+ This is by design to enable operations with the coin instance which might need to pass Coin instance as
+ by-reference and change coin value the way which will make it invalid from Cosmos-SDK requirements perspective.
+ For example, mathematical calculations/operations which might need to use Coin to store a relative rather than
+ an absolute amount value, what might result in to negative coin amount value.
+ This is to enable flexibility, rather than fail immediately when setting amount or denom values
+
+ The implication is that the validation needs to be executed explicitly by calling the `validate()` method.
+ """
amount: int
denom: str
+ def __repr__(self) -> str:
+ """Return Cosmos-SDK string representation of the coin this (self) instance holds."""
+ return f"{self.amount}{self.denom}"
+
def to_proto(self) -> CoinProto:
"""Convert this type to protobuf schema Coin type."""
return CoinProto(amount=str(self.amount), denom=self.denom)
- def __repr__(self) -> str:
- """Return string representation of coin."""
- return f"{self.amount}{self.denom}"
-
def validate(self):
- """Validate this type based on Cosmos-SDK requirements for Coin.
+ """Validate Coin instance based on Cosmos-SDK requirements.
+
+ Throws ValueError exception if coin instance is invalid based on Cosmos-SDK requirements.
+ """
+ self.validate_amount()
+ self.validate_denom()
- :raises ValueError: If amount is negative or denom does not conform to cosmos-sdk requirement for denomination.
+ def validate_amount(self):
+ """Validate coin amount value based on Cosmos-SDK requirements.
+
+ :raises ValueError: If coin amount value does not conform to cosmos-sdk requirement.
"""
if not self.is_amount_valid():
- raise ValueError("Coin amount must be greater than zero")
+ raise ValueError(f"Coin amount {self.amount} must be greater than zero")
+
+ def validate_denom(self):
+ """Validate coin denom value based on Cosmos-SDK requirements.
+ :raises ValueError: If coin denom value does not conform to cosmos-sdk requirement.
+ """
if not self.is_denom_valid():
raise ValueError(
- f'The "{self.denom}" denom does not conform to Cosmos-SDK requirements'
+ f'Coin denom "{self.denom}" does not conform to Cosmos-SDK requirements.'
)
def is_valid(self) -> bool:
@@ -67,10 +93,10 @@ def is_valid(self) -> bool:
def is_amount_valid(self) -> bool:
"""Validate amount value based on Cosmos-SDK requirements.
- :return: True if the amount conforms to cosmos-sdk requirement for Coin amount (when it is greater than zero),
- False otherwise.
+ :return: True if the amount conforms to cosmos-sdk requirement for Coin amount (when it is greater than
+ or equal to zero). False otherwise.
"""
- return self.amount > 0
+ return is_coin_amount_valid(self.amount)
def is_denom_valid(self) -> bool:
"""Validate denom value based on Cosmos-SDK requirements.
@@ -80,45 +106,33 @@ def is_denom_valid(self) -> bool:
return is_denom_valid(self.denom)
-class Coins(List[Coin]):
- """Coins.
+CoinsParamType = Union[
+ str, "Coins", Iterable[Coin], Iterable[CoinProto], Coin, CoinProto
+]
+
+
+class OnCollision(Enum):
+ """OnCollision Enum."""
+
+ Fail = 0
+ Override = 1
+
- It is required to call the 'canonicalise()' method in order to ensure that the Coins instance conforms to
- Cosmos-SDK requirements for Coins type!
- This is because one way or another, due to the nature of the base List type, it is possible to create such an
- instance of Coins which does not conform to Cosmos-SDK requirements.
+class Coins:
+ """This class implements the behaviour of Coins as defined by Cosmos-SDK.
+
+ Implementation of this class guarantees, that the value it represents/holds is *always* valid (= conforms to
+ Cosmos-SDK requirements), and all its methods ensure that the value always remains valid, or they fail with
+ an exception.
"""
def __init__(
self,
- coins: Optional[
- Union[str, "Coins", List[Coin], List[CoinProto], Coin, CoinProto]
- ] = None,
+ coins: Optional[CoinsParamType] = None,
):
- """Convert any coin representation into Coins."""
- if coins is None:
- super().__init__()
- return
-
- if isinstance(coins, str):
- _coins = Coins._from_string(coins)
- elif isinstance(coins, Coins):
- _coins = Coins._from_coins_list(coins)
- elif isinstance(coins, Coin):
- _coins = [coins]
- elif isinstance(coins, CoinProto):
- _coins = Coins._from_coins_list([coins])
- elif isinstance(coins, list):
- if len(coins) == 0:
- _coins = []
- elif isinstance(coins[0], (Coin, CoinProto)):
- _coins = Coins._from_coins_list(coins)
- else:
- raise TypeError(f"Invalid type {type(coins)}")
- else:
- raise ValueError(f"Invalid type {type(coins)}")
-
- super().__init__(_coins)
+ """Instantiate Coins from any of the supported coin(s) representation types."""
+ self._amounts: SortedDict[str, int] = SortedDict()
+ self.assign(coins)
def __repr__(self) -> str:
"""Return cosmos-sdk string representation of Coins.
@@ -129,79 +143,47 @@ def __repr__(self) -> str:
from cosmpy.aerial.client.coins import Coin, Coins
coins = Coins([Coin(1,"afet"), Coin(2,"uatom"), Coin(3,"nanomobx")])
- assert str(coins) == "1afet,2uatom,3nanomobx"
- """
- return ",".join([str(c) for c in self[:]])
-
- def to_proto(self) -> List[CoinProto]:
- """Convert this type to *protobuf schema* Coins type."""
- coins = Coins(self).canonicalise()
- return [CoinProto(amount=str(c.amount), denom=c.denom) for c in coins]
-
- def canonicalise(self) -> "Coins":
- """Reorganise the value of the 'self' instance in to canonical form defined by cosmos-sdk for `Coins`.
-
- This means dropping all coins with zero value, and alphabetically sorting (ascending) the coins based
- on denomination.
- The algorithm *fails* with exception *if* any of the denominations in the list is *not* unique = if some of the
- denominations are present in the coin list more than once, or if validation of any individual coin will fail.
- :returns: The 'self' instance.
- """
- coins = [c for c in self if c.amount > 0]
-
- self.clear()
- self.extend(coins)
-
- sort_coins(self)
- self.validate()
-
- return self
-
- def validate(self):
- """Validate whether current value conforms to canonical form for list of coins defined by cosmos-sdk.
-
- Raises ValueError exception *IF* denominations are not unique, or if validation of individual coins raises an
- exception.
+ assert repr(coins) == "1afet,2uatom,3nanomobx"
+ assert str(coins) == repr(coins)
"""
- validate_coins(self)
+ return ",".join([repr(c) for c in self])
- @classmethod
- def _from_coins_list(cls, coins: List[Union[Coin, CoinProto]]) -> List[Coin]:
- """Create aerial Coins from List of CoinProto objects."".
+ def __hash__(self) -> int:
+ """Hash."""
+ return hash(self._amounts)
- :param coins: input list of CoinsProto
- :return: List of Coin objects
- """
- return [Coin(amount=int(coin.amount), denom=coin.denom) for coin in coins]
+ def __len__(self) -> int:
+ """Get number of coins."""
+ return len(self._amounts)
- @classmethod
- def _from_string(cls, value: str) -> List[Coin]:
- """Parse the coins.
+ def __eq__(self, right) -> bool:
+ """Compare if two instances of Coins are equal."""
+ if not isinstance(right, Coins):
+ right = Coins(right)
- :param value: coins
- :raises RuntimeError: If unable to parse the value
- :return: coins
- """
- coins = []
+ return self._amounts == right._amounts
- parts = re.split(r",\s*", value)
- for part in parts:
- part = part.strip()
- if part == "":
- continue
+ def __getitem__(self, denom: str) -> Coin:
+ """Coins safe getter that prevents modifying of the reference."""
+ amount = self._amounts[denom]
+ return Coin(amount, denom)
- match = re.match(r"^(\d+)(.+)$", part)
- if match is None:
- raise RuntimeError(f"Unable to parse value {part}")
+ def __contains__(self, denom: str) -> bool:
+ """Return true if denom is present."""
+ return denom in self._amounts
- amount, denom = match.groups()
- coins.append(Coin(amount=int(amount), denom=denom))
+ def __delitem__(self, denom: str):
+ """Remove denom."""
+ del self._amounts[denom]
- return coins
+ def __iter__(self):
+ """Get coins iterator."""
+ for denom, amount in self._amounts.items():
+ yield Coin(amount, denom)
def __add__(self, other):
"""Perform algebraic vector addition of two coin lists."""
- result = Coins()
+ result = Coins(self)
for (left, right) in self._math_operation(other, result_inout=result):
left.amount += right.amount
@@ -209,7 +191,7 @@ def __add__(self, other):
def __sub__(self, other):
"""Perform algebraic vector subtraction of two coin lists, ensuring no coin has negative value."""
- result = Coins()
+ result = Coins(self)
for (left, right) in self._math_operation(other, result_inout=result):
if left.amount < right.amount:
raise RuntimeError(
@@ -239,31 +221,219 @@ def __isub__(self, other):
return result
- def _math_operation(self, other: List[Coin], result_inout: "Coins"):
- self.validate()
+ def clear(self) -> "Coins":
+ """Delete all coins."""
+ self._amounts.clear()
+ return self
- if isinstance(other, Coins):
- other.validate()
- else:
- Coins(other).validate()
+ def denoms(self) -> Iterable[str]:
+ """Return denominations of the coins in this(self) instance in ordered ascending alphabetically.
- res_dict = {c.denom: Coin(amount=c.amount, denom=c.denom) for c in self}
- for c in other:
- left = res_dict.get(c.denom, Coin(amount=0, denom=c.denom))
+ :return: iterable of denominations
+ """
+ return self._amounts.keys()
- yield left, c
+ def assign(
+ self,
+ coins: Optional[CoinsParamType] = None,
+ ) -> "Coins":
+ """Assign passed in `coins` *in to* this ('self') instance.
- if left.amount == 0:
- if left.denom in res_dict:
- del res_dict[left.denom]
- elif left.amount > 0:
- res_dict[left.denom] = left
+ This means that the current value of this ('self') instance will be completely *replaced* with the value
+ carried by the input `coins` parameter.
+
+ :param coins: Input coins in any of the supported types.
+
+ :raises TypeError: If coins or coin in a list has unexpected type
+
+ :return: self
+ """
+ self.clear()
+
+ if coins is None:
+ return self
+
+ if isinstance(coins, str):
+ self._from_string(coins)
+ elif isinstance(coins, Coins):
+ self._from_coins_list(coins)
+ elif isinstance(coins, (Coin, CoinProto)):
+ self._from_coins_list([coins])
+ elif isinstance(coins, list):
+ if len(coins) == 0:
+ pass
+ elif isinstance(coins[0], (Coin, CoinProto)):
+ self._from_coins_list(coins)
else:
- raise RuntimeError(f"Operation yielded negative amount {left}")
+ raise TypeError(f"Invalid type {type(coins)}")
+ else:
+ raise TypeError(f"Invalid type {type(coins)}")
- result_inout.clear()
- result_inout.extend(res_dict.values())
- result_inout.canonicalise()
+ return self
+
+ def merge_from(
+ self,
+ coins: CoinsParamType,
+ on_collision: OnCollision = OnCollision.Fail,
+ ) -> "Coins":
+ """Merge passed in coins in to this ('self') coins instance.
+
+ :param coins: Input coins in any of the supported types.
+ :param on_collision: Instructs what to do in the case of a denom collision = if this (self) already contains
+ one or more the denomination in the `coins` value:
+ - if `OnCollision.Override`: then the colliding coin amount in this (self) object will be
+ *overridden* with the colliding amount value from the `coins` parameter.
+ - if `OnCollision.Fail`: then the merge will *fail* with the `ValueError` exception when
+ the first collision is detected
+
+ :return: The `self` instance containing merged coins
+ """
+ cs = Coins(coins)
+
+ for c in cs:
+ self._merge_coin(c, on_collision)
+
+ return self
+
+ def delete(self, denominations: Iterable[str]) -> "Coins":
+ """Delete coins from this ('self') instance for each denom listed in `denominations` argument.
+
+ :param denominations: collection of denominations to drop
+ :return: deleted Coins
+ """
+ removed_coins = Coins()
+ for denom in denominations:
+ if denom in self:
+ removed_coins.merge_from(self[denom])
+
+ for c in removed_coins:
+ del self[c.denom]
+
+ return self
+
+ def get(self, denom: str, default_amount: int) -> Coin:
+ """Return Coin instance for the given `denom`.
+
+ If coin with the given `denom` is not present, the `default` will be returned.
+
+ Runtime complexity: `O(log(n))`
+
+ This method poses the same risk to validity of the Coins value as the `__getitem__(...)` method,
+ since at the moment it returns Coin instance *by-reference* what allows to change the `Coin.amount` value
+ from external context and so potentially invalidate the value represented by the `Coins` class/container.
+
+ :param denom: denomination of the coin to query.
+ :param default_amount: default amount used to construct returned Coin instance if there is *no* coin with
+ the given `denom` present in this coins instance.
+ :return: coin instance for the given `denom`, or the `default` value.
+
+ Example::
+ >>> from cosmpy.aerial.coins import Coin, Coins
+ >>> cs = Coins("1aaa,2baa,3caa")
+ >>> cs.get("baa", 0)
+ 2baa
+ >>> cs.get("ggg", 0)
+ 0ggg
+ """
+ amount = self._amounts[denom] if denom in self._amounts else default_amount
+ return Coin(amount, denom)
+
+ def get_by_index(self, index: int) -> Coin:
+ """Return Coin instance at given `index`.
+
+ If the `index` is out of range, raises :exc:`IndexError`.
+
+ Runtime complexity: `O(log(n))`
+
+ This method poses the same risk to validity of the Coins value as the `__getitem__(...)` method,
+ since at the moment it returns Coin instance *by-reference* what allows to change the `Coin.amount` value
+ from external context and so potentially invalidate the value represented by the `Coins` class/container.
+
+ Example::
+ >>> from cosmpy.aerial.coins import Coin, Coins
+ >>> cs = Coins("1aaa,2baa,3caa")
+ >>> cs.get_by_index(0)
+ 1aaa
+ >>> cs.get_by_index(2)
+ 3caa
+ >>> cs.get_by_index(3)
+ Traceback (most recent call last):
+ ...
+ IndexError: list index out of range
+
+ :param index: int index of item (default -1)
+ :return: key and value pair
+ """
+ denom, amount = self._amounts.peekitem(index)
+ return Coin(amount, denom)
+
+ def to_proto(self) -> List[CoinProto]:
+ """Convert this type to *protobuf schema* Coins type."""
+ return [c.to_proto() for c in self]
+
+ def _merge_coin(self, coin: Coin, on_collision: OnCollision = OnCollision.Fail):
+ """Merge singular aerial Coin in to this object.
+
+ :param coin: input coin to merged.
+ :param on_collision: If OnCollision.Override then the coin instance in this (self) object will be overridden
+ if it already contains the denomination, if OnCollision.Fail the merge will fail with
+ an exception.
+ :raises ValueError: If there is denom collision and the `on_collision` is set to `OnCollision.Fail`,
+ or if the `on_collision` has unknown enum value.
+ """
+ if on_collision == OnCollision.Override:
+ fail_on_collision = False
+ elif on_collision == OnCollision.Fail:
+ fail_on_collision = True
+ else:
+ raise ValueError(f"Unknown on_collision value: {on_collision}")
+
+ is_already_present = coin.denom in self
+
+ if coin.amount == 0:
+ if not fail_on_collision and is_already_present:
+ del self._amounts[coin.denom]
+
+ # Skipping if amount is zero
+ return
+
+ if fail_on_collision and is_already_present:
+ raise ValueError(
+ f'Attempt to merge a coin with the "{coin.denom}" denomination which already exists in the receiving coins instance'
+ )
+
+ coin.validate()
+ self._amounts[coin.denom] = coin.amount
+
+ def _from_coins_list(self, coins: Iterable[Union[Coin, CoinProto]]):
+ """Create aerial Coins from List of CoinProto objects."".
+
+ :param coins: input list of coins
+ """
+ for c in coins:
+ self._merge_coin(Coin(int(c.amount), c.denom))
+
+ def _from_string(self, value: str):
+ """Parse the coins string and merge it to self.
+
+ :param value: coins
+ """
+ for coin in from_string(value):
+ self._merge_coin(coin)
+
+ @staticmethod
+ def _math_operation(other: CoinsParamType, result_inout: "Coins"):
+ res: Coins = result_inout
+
+ if not isinstance(other, Coins):
+ other = Coins(other)
+
+ for c in other:
+ left: Coin = res.get(c.denom, 0)
+ yield left, c
+ res._merge_coin( # pylint: disable=protected-access
+ left, on_collision=OnCollision.Override
+ )
def parse_coins(value: str) -> List[CoinProto]:
@@ -275,97 +445,106 @@ def parse_coins(value: str) -> List[CoinProto]:
return Coins(value).to_proto()
-CoinsParamType = Union[str, Coins, List[Coin], List[CoinProto], Coin, CoinProto]
+def from_string(value: str):
+ """Parse the coins string and yields individual coins as Coin instances in order of their definition in input `value`.
+
+ :param value: coins
+
+ :yields: Coin objects one by one in the order they are specified in the input `value` string, where validation of
+ the yielded Coin instance is intentionally *NOT* executed => yielded coin instance might *NOT* be valid
+ when judged based on cosmos-sdk requirements.
+ This is by-design to enable just basic parsing focused exclusively on the format of the coins string value.
+ This leaves a degree of freedom for a caller on how the resulting/parsed coins should be used/consumed,
+ rather than forcing any checks/validation for individual coins instances, or coins collection as a whole,
+ here.
+
+ :raises RuntimeError: If unable to parse the value
+ """
+ parts = re.split(r",\s*", value)
+ for part in parts:
+ part = part.strip()
+ if part == "":
+ continue
+
+ match = re.match(r"^(\d+)(.+)$", part)
+ if match is None:
+ raise RuntimeError(f"Unable to parse value {part}")
+
+ amount, denom = match.groups()
+ yield Coin(int(amount), denom)
+
+
+def is_coin_amount_valid(amount: int) -> bool:
+ """Check if amount value conforms to Cosmos-SDK requirements.
+
+ :param amount: amount to be checked
+ :return: True if the amount conforms to cosmos-sdk requirement for Coin amount (when it is greater than zero),
+ False otherwise.
+ """
+ return amount > 0
def is_denom_valid(denom: str) -> bool:
- """Return true if coin denom name is valid.
+ """Check if denom value conforms to Cosmos-SDK requirements.
- :param denom: string denom
- :return: bool validity
+ :param denom: Denom to be checked
+ :return: True if the denom conforms to cosmos-sdk requirement
"""
return denom_regex.match(denom) is not None
-def is_coins_sorted(coins: Union[str, Coins, List[Coin], List[CoinProto]]) -> bool:
+def is_coins_sorted(
+ coins: Union[str, Coins, Iterable[Coin], Iterable[CoinProto]]
+) -> bool:
"""Return true if given coins representation is sorted in ascending order of denom.
:param coins: Any type representing coins
:return: bool is_sorted
"""
+ if coins is None:
+ return False
+
if not coins:
return True
if isinstance(coins, str):
- coins = Coins(coins)
+ coins = from_string(coins)
+
+ itr = iter(coins)
+ coin = next(itr, None)
- last_denom = coins[0].denom
+ if coin is None:
+ return True
+
+ last_denom = coin.denom
+ coin = next(itr, None)
- for c in coins[1:]:
- if last_denom >= c.denom:
+ while coin is not None:
+ if last_denom >= coin.denom:
return False
- last_denom = c.denom
+ last_denom = coin.denom
+ coin = next(itr, None)
return True
-def validate_coins(coins: Union[str, Coins, List[Coin], List[CoinProto]]):
+def validate_coins(coins: Union[str, Coins, Iterable[Coin], Iterable[CoinProto]]):
"""Return true if given coins representation is valid.
+ raises ValueError if there are multiple coins with the same denom
+
:param coins: Any type representing coins
- :raises ValueError: If there are multiple coins with the same denom
- :return: bool validity
+ :return: True if valid, False otherwise
"""
if not coins:
return
- if isinstance(coins, str):
- coins = Coins(coins)
-
- if len(coins) == 0:
- return
-
- def _validate_coin(coin: Union[Coin, CoinProto]):
- """Validate coin.
-
- :param coin: Coin or CoinProto
-
- """
- if isinstance(coin, CoinProto):
- coin = Coin(int(coin.amount), coin.denom)
-
- coin.validate()
-
- _validate_coin(coins[0])
-
- seen = set()
- last_denom = coins[0].denom
- seen.add(last_denom)
-
- for c in coins[1:]:
- if c.denom in seen:
- raise ValueError(f'Multiple occurrences of the "{c.denom}" denomination')
-
- if last_denom >= c.denom:
- raise ValueError(
- "Coins are not sorted as cosmos-sdk expects it (ascending based on denom)"
- )
-
- _validate_coin(c)
-
- last_denom = c.denom
- seen.add(c.denom)
-
-
-# def sort_coins(coins: Union[Coins, CoinsProto, List[Coin], List[CoinProto]]):
-def sort_coins(coins: Union[Coins, List[Coin], List[CoinProto]]):
- """Sort the collection of coins based on Cosmos-SDK definition of Coins validity.
-
- Coins collection is sorted ascending alphabetically based on denomination.
-
- NOTE: The resulting sorted collection of coins is *NOT* validated by calling the 'Coins.validate()'.
-
- :param coins: Coins to sort
- """
- coins.sort(key=lambda c: c.denom, reverse=False)
+ if isinstance(coins, Coins):
+ # Strictly speaking, this is not necessary, since API of the Coins class implicitly ensures validity of
+ # the value it holds.
+ for coin in coins:
+ coin.validate()
+ else:
+ # Conversion to Coins will verify everything, no need to do anything else:
+ _ = Coins(coins)
diff --git a/docs/api/aerial/coins.md b/docs/api/aerial/coins.md
index d9650f17..d2af0169 100644
--- a/docs/api/aerial/coins.md
+++ b/docs/api/aerial/coins.md
@@ -15,6 +15,25 @@ class Coin()
Coins.
+This class does not implicitly ensure that its value represents a valid coin based on Cosmos-SDK requirements.
+This is by design to enable operations with the coin instance which might need to pass Coin instance as
+by-reference and change coin value the way which will make it invalid from Cosmos-SDK requirements perspective.
+For example, mathematical calculations/operations which might need to use Coin to store a relative rather than
+an absolute amount value, what might result in to negative coin amount value.
+This is to enable flexibility, rather than fail immediately when setting amount or denom values
+
+The implication is that the validation needs to be executed explicitly by calling the `validate()` method.
+
+
+
+#### `__`repr`__`
+
+```python
+def __repr__() -> str
+```
+
+Return Cosmos-SDK string representation of the coin this (self) instance holds.
+
#### to`_`proto
@@ -25,29 +44,45 @@ def to_proto() -> CoinProto
Convert this type to protobuf schema Coin type.
-
+
-#### `__`repr`__`
+#### validate
```python
-def __repr__() -> str
+def validate()
```
-Return string representation of coin.
+Validate Coin instance based on Cosmos-SDK requirements.
-
+Throws ValueError exception if coin instance is invalid based on Cosmos-SDK requirements.
-#### validate
+
+
+#### validate`_`amount
```python
-def validate()
+def validate_amount()
```
-Validate this type based on Cosmos-SDK requirements for Coin.
+Validate coin amount value based on Cosmos-SDK requirements.
**Raises**:
-- `ValueError`: If amount is negative or denom does not conform to cosmos-sdk requirement for denomination.
+- `ValueError`: If coin amount value does not conform to cosmos-sdk requirement.
+
+
+
+#### validate`_`denom
+
+```python
+def validate_denom()
+```
+
+Validate coin denom value based on Cosmos-SDK requirements.
+
+**Raises**:
+
+- `ValueError`: If coin denom value does not conform to cosmos-sdk requirement.
@@ -75,8 +110,8 @@ Validate amount value based on Cosmos-SDK requirements.
**Returns**:
-True if the amount conforms to cosmos-sdk requirement for Coin amount (when it is greater than zero),
-False otherwise.
+True if the amount conforms to cosmos-sdk requirement for Coin amount (when it is greater than
+or equal to zero). False otherwise.
@@ -92,31 +127,39 @@ Validate denom value based on Cosmos-SDK requirements.
True if denom conforms to cosmos-sdk requirement for denomination, False otherwise.
+
+
+## OnCollision Objects
+
+```python
+class OnCollision(Enum)
+```
+
+OnCollision Enum.
+
## Coins Objects
```python
-class Coins(List[Coin])
+class Coins()
```
-Coins.
+This class implements the behaviour of Coins as defined by Cosmos-SDK.
-It is required to call the 'canonicalise()' method in order to ensure that the Coins instance conforms to
-Cosmos-SDK requirements for Coins type!
-This is because one way or another, due to the nature of the base List type, it is possible to create such an
-instance of Coins which does not conform to Cosmos-SDK requirements.
+Implementation of this class guarantees, that the value it represents/holds is *always* valid (= conforms to
+Cosmos-SDK requirements), and all its methods ensure that the value always remains valid, or they fail with
+an exception.
#### `__`init`__`
```python
-def __init__(coins: Optional[Union[str, "Coins", List[Coin], List[CoinProto],
- Coin, CoinProto]] = None)
+def __init__(coins: Optional[CoinsParamType] = None)
```
-Convert any coin representation into Coins.
+Instantiate Coins from any of the supported coin(s) representation types.
@@ -135,49 +178,78 @@ Example::
from cosmpy.aerial.client.coins import Coin, Coins
coins = Coins([Coin(1,"afet"), Coin(2,"uatom"), Coin(3,"nanomobx")])
-assert str(coins) == "1afet,2uatom,3nanomobx"
+assert repr(coins) == "1afet,2uatom,3nanomobx"
+assert str(coins) == repr(coins)
-
+
-#### to`_`proto
+#### `__`hash`__`
```python
-def to_proto() -> List[CoinProto]
+def __hash__() -> int
```
-Convert this type to *protobuf schema* Coins type.
+Hash.
-
+
-#### canonicalise
+#### `__`len`__`
```python
-def canonicalise() -> "Coins"
+def __len__() -> int
```
-Reorganise the value of the 'self' instance in to canonical form defined by cosmos-sdk for `Coins`.
+Get number of coins.
-This means dropping all coins with zero value, and alphabetically sorting (ascending) the coins based
-on denomination.
-The algorithm *fails* with exception *if* any of the denominations in the list is *not* unique = if some of the
-denominations are present in the coin list more than once, or if validation of any individual coin will fail.
+
-**Returns**:
+#### `__`eq`__`
-The 'self' instance.
+```python
+def __eq__(right) -> bool
+```
-
+Compare if two instances of Coins are equal.
-#### validate
+
+
+#### `__`getitem`__`
```python
-def validate()
+def __getitem__(denom: str) -> Coin
```
-Validate whether current value conforms to canonical form for list of coins defined by cosmos-sdk.
+Coins safe getter that prevents modifying of the reference.
-Raises ValueError exception *IF* denominations are not unique, or if validation of individual coins raises an
-exception.
+
+
+#### `__`contains`__`
+
+```python
+def __contains__(denom: str) -> bool
+```
+
+Return true if denom is present.
+
+
+
+#### `__`delitem`__`
+
+```python
+def __delitem__(denom: str)
+```
+
+Remove denom.
+
+
+
+#### `__`iter`__`
+
+```python
+def __iter__()
+```
+
+Get coins iterator.
@@ -219,6 +291,181 @@ def __isub__(other)
Perform *in-place* algebraic vector subtraction of two coin lists, ensuring no coin has negative value.
+
+
+#### clear
+
+```python
+def clear() -> "Coins"
+```
+
+Delete all coins.
+
+
+
+#### denoms
+
+```python
+def denoms() -> Iterable[str]
+```
+
+Return denominations of the coins in this(self) instance in ordered ascending alphabetically.
+
+**Returns**:
+
+iterable of denominations
+
+
+
+#### assign
+
+```python
+def assign(coins: Optional[CoinsParamType] = None) -> "Coins"
+```
+
+Assign passed in `coins` *in to* this ('self') instance.
+
+This means that the current value of this ('self') instance will be completely *replaced* with the value
+carried by the input `coins` parameter.
+
+**Arguments**:
+
+- `coins`: Input coins in any of the supported types.
+
+**Raises**:
+
+- `TypeError`: If coins or coin in a list has unexpected type
+
+**Returns**:
+
+self
+
+
+
+#### merge`_`from
+
+```python
+def merge_from(coins: CoinsParamType,
+ on_collision: OnCollision = OnCollision.Fail) -> "Coins"
+```
+
+Merge passed in coins in to this ('self') coins instance.
+
+**Arguments**:
+
+- `coins`: Input coins in any of the supported types.
+- `on_collision`: Instructs what to do in the case of a denom collision = if this (self) already contains
+one or more the denomination in the `coins` value:
+- if `OnCollision.Override`: then the colliding coin amount in this (self) object will be
+ *overridden* with the colliding amount value from the `coins` parameter.
+- if `OnCollision.Fail`: then the merge will *fail* with the `ValueError` exception when
+ the first collision is detected
+
+**Returns**:
+
+The `self` instance containing merged coins
+
+
+
+#### delete
+
+```python
+def delete(denominations: Iterable[str]) -> "Coins"
+```
+
+Delete coins from this ('self') instance for each denom listed in `denominations` argument.
+
+**Arguments**:
+
+- `denominations`: collection of denominations to drop
+
+**Returns**:
+
+deleted Coins
+
+
+
+#### get
+
+```python
+def get(denom: str, default_amount: int) -> Coin
+```
+
+Return Coin instance for the given `denom`.
+
+If coin with the given `denom` is not present, the `default` will be returned.
+
+Runtime complexity: `O(log(n))`
+
+This method poses the same risk to validity of the Coins value as the `__getitem__(...)` method,
+since at the moment it returns Coin instance *by-reference* what allows to change the `Coin.amount` value
+from external context and so potentially invalidate the value represented by the `Coins` class/container.
+
+**Arguments**:
+
+- `denom`: denomination of the coin to query.
+- `default_amount`: default amount used to construct returned Coin instance if there is *no* coin with
+the given `denom` present in this coins instance.
+
+**Returns**:
+
+coin instance for the given `denom`, or the `default` value.
+Example::
+>>> from cosmpy.aerial.coins import Coin, Coins
+>>> cs = Coins("1aaa,2baa,3caa")
+>>> cs.get("baa", 0)
+2baa
+>>> cs.get("ggg", 0)
+0ggg
+
+
+
+#### get`_`by`_`index
+
+```python
+def get_by_index(index: int) -> Coin
+```
+
+Return Coin instance at given `index`.
+
+If the `index` is out of range, raises :exc:`IndexError`.
+
+Runtime complexity: `O(log(n))`
+
+This method poses the same risk to validity of the Coins value as the `__getitem__(...)` method,
+since at the moment it returns Coin instance *by-reference* what allows to change the `Coin.amount` value
+from external context and so potentially invalidate the value represented by the `Coins` class/container.
+
+Example::
+>>> from cosmpy.aerial.coins import Coin, Coins
+>>> cs = Coins("1aaa,2baa,3caa")
+>>> cs.get_by_index(0)
+1aaa
+>>> cs.get_by_index(2)
+3caa
+>>> cs.get_by_index(3)
+Traceback (most recent call last):
+ ...
+IndexError: list index out of range
+
+**Arguments**:
+
+- `index`: int index of item (default -1)
+
+**Returns**:
+
+key and value pair
+
+
+
+#### to`_`proto
+
+```python
+def to_proto() -> List[CoinProto]
+```
+
+Convert this type to *protobuf schema* Coins type.
+
#### parse`_`coins
@@ -237,6 +484,53 @@ Parse the coins.
List of CoinProto objects
+
+
+#### from`_`string
+
+```python
+def from_string(value: str)
+```
+
+Parse the coins string and yields individual coins as Coin instances in order of their definition in input `value`.
+
+**Arguments**:
+
+- `value`: coins
+
+**Raises**:
+
+- `RuntimeError`: If unable to parse the value
+
+**Returns**:
+
+Coin objects one by one in the order they are specified in the input `value` string, where validation of
+the yielded Coin instance is intentionally *NOT* executed => yielded coin instance might *NOT* be valid
+when judged based on cosmos-sdk requirements.
+This is by-design to enable just basic parsing focused exclusively on the format of the coins string value.
+This leaves a degree of freedom for a caller on how the resulting/parsed coins should be used/consumed,
+rather than forcing any checks/validation for individual coins instances, or coins collection as a whole,
+here.
+
+
+
+#### is`_`coin`_`amount`_`valid
+
+```python
+def is_coin_amount_valid(amount: int) -> bool
+```
+
+Check if amount value conforms to Cosmos-SDK requirements.
+
+**Arguments**:
+
+- `amount`: amount to be checked
+
+**Returns**:
+
+True if the amount conforms to cosmos-sdk requirement for Coin amount (when it is greater than zero),
+False otherwise.
+
#### is`_`denom`_`valid
@@ -245,15 +539,15 @@ List of CoinProto objects
def is_denom_valid(denom: str) -> bool
```
-Return true if coin denom name is valid.
+Check if denom value conforms to Cosmos-SDK requirements.
**Arguments**:
-- `denom`: string denom
+- `denom`: Denom to be checked
**Returns**:
-bool validity
+True if the denom conforms to cosmos-sdk requirement
@@ -261,7 +555,7 @@ bool validity
```python
def is_coins_sorted(
- coins: Union[str, Coins, List[Coin], List[CoinProto]]) -> bool
+ coins: Union[str, Coins, Iterable[Coin], Iterable[CoinProto]]) -> bool
```
Return true if given coins representation is sorted in ascending order of denom.
@@ -279,38 +573,19 @@ bool is_sorted
#### validate`_`coins
```python
-def validate_coins(coins: Union[str, Coins, List[Coin], List[CoinProto]])
+def validate_coins(coins: Union[str, Coins, Iterable[Coin],
+ Iterable[CoinProto]])
```
Return true if given coins representation is valid.
+raises ValueError if there are multiple coins with the same denom
+
**Arguments**:
- `coins`: Any type representing coins
-**Raises**:
-
-- `ValueError`: If there are multiple coins with the same denom
-
**Returns**:
-bool validity
-
-
-
-#### sort`_`coins
-
-```python
-def sort_coins(coins: Union[Coins, List[Coin], List[CoinProto]])
-```
-
-Sort the collection of coins based on Cosmos-SDK definition of Coins validity.
-
-Coins collection is sorted ascending alphabetically based on denomination.
-
-NOTE: The resulting sorted collection of coins is *NOT* validated by calling the 'Coins.validate()'.
-
-**Arguments**:
-
-- `coins`: Coins to sort
+True if valid, False otherwise
diff --git a/poetry.lock b/poetry.lock
index 0b1d2ff2..5e8081b5 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
[[package]]
name = "annotated-types"
@@ -6,6 +6,7 @@ version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
@@ -17,6 +18,7 @@ version = "2.13.5"
description = "An abstract syntax tree for Python with inference support."
optional = false
python-versions = ">=3.7.2"
+groups = ["dev"]
files = [
{file = "astroid-2.13.5-py3-none-any.whl", hash = "sha256:6891f444625b6edb2ac798829b689e95297e100ddf89dbed5a8c610e34901501"},
{file = "astroid-2.13.5.tar.gz", hash = "sha256:df164d5ac811b9f44105a72b8f9d5edfb7b5b2d7e979b04ea377a77b3229114a"},
@@ -36,18 +38,19 @@ version = "25.3.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
{file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"},
{file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"},
]
[package.extras]
-benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"]
-tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
-tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
+tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""]
[[package]]
name = "authlib"
@@ -55,6 +58,7 @@ version = "1.5.2"
description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "authlib-1.5.2-py2.py3-none-any.whl", hash = "sha256:8804dd4402ac5e4a0435ac49e0b6e19e395357cfa632a3f624dcb4f6df13b4b1"},
{file = "authlib-1.5.2.tar.gz", hash = "sha256:fe85ec7e50c5f86f1e2603518bb3b4f632985eb4a355e52256530790e326c512"},
@@ -69,13 +73,14 @@ version = "2.17.0"
description = "Internationalization utilities"
optional = false
python-versions = ">=3.8"
+groups = ["docs"]
files = [
{file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"},
{file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"},
]
[package.extras]
-dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"]
+dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""]
[[package]]
name = "backrefs"
@@ -83,6 +88,7 @@ version = "5.8"
description = "A wrapper around re and regex that adds additional back references."
optional = false
python-versions = ">=3.9"
+groups = ["docs"]
files = [
{file = "backrefs-5.8-py310-none-any.whl", hash = "sha256:c67f6638a34a5b8730812f5101376f9d41dc38c43f1fdc35cb54700f6ed4465d"},
{file = "backrefs-5.8-py311-none-any.whl", hash = "sha256:2e1c15e4af0e12e45c8701bd5da0902d326b2e200cafcd25e49d9f06d44bb61b"},
@@ -101,6 +107,7 @@ version = "1.7.4"
description = "Security oriented static analyser for python code."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"},
{file = "bandit-1.7.4.tar.gz", hash = "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2"},
@@ -123,6 +130,7 @@ version = "1.2.0"
description = "Reference implementation for Bech32 and segwit addresses."
optional = false
python-versions = ">=3.5"
+groups = ["main"]
files = [
{file = "bech32-1.2.0-py3-none-any.whl", hash = "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981"},
{file = "bech32-1.2.0.tar.gz", hash = "sha256:7d6db8214603bd7871fcfa6c0826ef68b85b0abd90fa21c285a9c5e21d2bd899"},
@@ -134,6 +142,7 @@ version = "22.12.0"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"},
{file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"},
@@ -169,6 +178,7 @@ version = "1.2.2.post1"
description = "A simple, correct Python build frontend"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"},
{file = "build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"},
@@ -183,7 +193,7 @@ tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
[package.extras]
docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"]
-test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"]
+test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0) ; python_version < \"3.10\"", "setuptools (>=56.0.0) ; python_version == \"3.10\"", "setuptools (>=56.0.0) ; python_version == \"3.11\"", "setuptools (>=67.8.0) ; python_version >= \"3.12\"", "wheel (>=0.36.0)"]
typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"]
uv = ["uv (>=0.1.18)"]
virtualenv = ["virtualenv (>=20.0.35)"]
@@ -194,6 +204,7 @@ version = "2025.1.31"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
+groups = ["main", "dev", "docs"]
files = [
{file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"},
{file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"},
@@ -205,6 +216,8 @@ version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "platform_python_implementation != \"PyPy\""
files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
@@ -284,6 +297,7 @@ version = "3.4.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev", "docs"]
files = [
{file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"},
{file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"},
@@ -385,6 +399,7 @@ version = "0.50"
description = "Check MANIFEST.in in a Python source package for completeness"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "check_manifest-0.50-py3-none-any.whl", hash = "sha256:6ab3e3aa72a008da3314b432f4c768c9647b4d6d8032f9e1a4672a572118e48c"},
{file = "check_manifest-0.50.tar.gz", hash = "sha256:d300f9f292986aa1a30424af44eb45c5644e0a810e392e62d553b24bb3393494"},
@@ -396,7 +411,7 @@ setuptools = "*"
tomli = {version = "*", markers = "python_version < \"3.11\""}
[package.extras]
-test = ["mock (>=3.0.0)", "pytest", "wheel"]
+test = ["mock (>=3.0.0) ; python_version == \"3.7\"", "pytest", "wheel"]
[[package]]
name = "click"
@@ -404,6 +419,7 @@ version = "8.1.8"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
+groups = ["dev", "docs"]
files = [
{file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
{file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
@@ -418,10 +434,12 @@ version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+groups = ["dev", "docs", "test"]
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
+markers = {dev = "os_name == \"nt\" or platform_system == \"Windows\" or sys_platform == \"win32\"", test = "sys_platform == \"win32\""}
[[package]]
name = "configparser"
@@ -429,13 +447,14 @@ version = "7.2.0"
description = "Updated configparser from stdlib for earlier Pythons."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "configparser-7.2.0-py3-none-any.whl", hash = "sha256:fee5e1f3db4156dcd0ed95bc4edfa3580475537711f67a819c966b389d09ce62"},
{file = "configparser-7.2.0.tar.gz", hash = "sha256:b629cc8ae916e3afbd36d1b3d093f34193d851e11998920fdcfc4552218b7b70"},
]
[package.extras]
-check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
+check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
@@ -448,6 +467,7 @@ version = "7.8.0"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.9"
+groups = ["test"]
files = [
{file = "coverage-7.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe"},
{file = "coverage-7.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28"},
@@ -515,7 +535,7 @@ files = [
]
[package.extras]
-toml = ["tomli"]
+toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
[[package]]
name = "cryptography"
@@ -523,6 +543,7 @@ version = "43.0.3"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"},
{file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"},
@@ -572,6 +593,7 @@ version = "1.8.1"
description = "A utility for ensuring Google-style docstrings stay up to date with the source code."
optional = false
python-versions = ">=3.6,<4.0"
+groups = ["dev"]
files = [
{file = "darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d"},
{file = "darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da"},
@@ -583,6 +605,7 @@ version = "1.5.3"
description = "Databind is a library inspired by jackson-databind to de-/serialize Python dataclasses. The `databind` package will install the full suite of databind packages. Compatible with Python 3.7 and newer."
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["docs"]
files = [
{file = "databind-1.5.3-py3-none-any.whl", hash = "sha256:43d76e3b931ed9d986b5e35df60e37ccb0bcb2b3b57d6f44cce085c48abe7016"},
{file = "databind-1.5.3.tar.gz", hash = "sha256:a1986c1a2054d28d064cf7900c2d3f03850ace124331fa026e6049f390742122"},
@@ -598,6 +621,7 @@ version = "1.5.3"
description = "Databind is a library inspired by jackson-databind to de-/serialize Python dataclasses. Compatible with Python 3.7 and newer."
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["docs"]
files = [
{file = "databind.core-1.5.3-py3-none-any.whl", hash = "sha256:105665947e0b0b4709b6dab99cd3cea31d16f5c0d68fe867e4dc2f47585669fb"},
{file = "databind.core-1.5.3.tar.gz", hash = "sha256:663dd0ccfd1b181cbcfb8315226ec8df78bcd65c1b43875ba18d89702d15efbe"},
@@ -614,6 +638,7 @@ version = "1.5.3"
description = "De-/serialize Python dataclasses to or from JSON payloads. Compatible with Python 3.7 and newer."
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["docs"]
files = [
{file = "databind.json-1.5.3-py3-none-any.whl", hash = "sha256:fd6702ca9f67b15414e573935bf4a5ccb221f3f810553a054b832393c057df3d"},
{file = "databind.json-1.5.3.tar.gz", hash = "sha256:b8785ad9689b98d524d4c96e0756bc41166da0de44cc9d14ed2fa8aea5674507"},
@@ -630,6 +655,7 @@ version = "1.2.18"
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
+groups = ["docs"]
files = [
{file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"},
{file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"},
@@ -639,7 +665,7 @@ files = [
wrapt = ">=1.10,<2"
[package.extras]
-dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools", "tox"]
+dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"]
[[package]]
name = "dill"
@@ -647,6 +673,7 @@ version = "0.4.0"
description = "serialize all of Python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"},
{file = "dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0"},
@@ -662,6 +689,7 @@ version = "0.3.9"
description = "Distribution utilities"
optional = false
python-versions = "*"
+groups = ["main", "dev"]
files = [
{file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
{file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
@@ -673,6 +701,7 @@ version = "2.1.2"
description = "Docspec is a JSON object specification for representing API documentation of programming languages."
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["docs"]
files = [
{file = "docspec-2.1.2-py3-none-any.whl", hash = "sha256:19168242b1e6ca39553feba91b6284479e2bfdf6500949ce63e10c49354d00d7"},
{file = "docspec-2.1.2.tar.gz", hash = "sha256:0edb90f4c54edbd43170875dece7a50750a21e95a4c5faf3f7e655d01d483fa7"},
@@ -688,6 +717,7 @@ version = "2.0.2"
description = "A parser based on lib2to3 producing docspec data from Python source code."
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["docs"]
files = [
{file = "docspec-python-2.0.2.tar.gz", hash = "sha256:9bb1bcc2b1e6903d8ef00107607255285d1a1f763acb111f9d83c695878cacbc"},
{file = "docspec_python-2.0.2-py3-none-any.whl", hash = "sha256:ffb35751562d13271e2792f4fe3aba9d79aa0493f966897b77ad73ed9cd5f6a6"},
@@ -703,6 +733,7 @@ version = "0.11"
description = "\"Parse Python docstrings in reST, Google and Numpydoc format\""
optional = false
python-versions = ">=3.6"
+groups = ["docs"]
files = [
{file = "docstring_parser-0.11.tar.gz", hash = "sha256:93b3f8f481c7d24e37c5d9f30293c89e2933fa209421c8abd731dd3ef0715ecb"},
]
@@ -716,6 +747,7 @@ version = "0.6.4"
description = "A parser for Python dependency files"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "dparse-0.6.4-py3-none-any.whl", hash = "sha256:fbab4d50d54d0e739fbb4dedfc3d92771003a5b9aa8545ca7a7045e3b174af57"},
{file = "dparse-0.6.4.tar.gz", hash = "sha256:90b29c39e3edc36c6284c82c4132648eaf28a01863eb3c231c2512196132201a"},
@@ -737,6 +769,7 @@ version = "0.19.1"
description = "ECDSA cryptographic signature library (pure python)"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.6"
+groups = ["main"]
files = [
{file = "ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3"},
{file = "ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61"},
@@ -755,6 +788,7 @@ version = "2.3.0"
description = "Removes commented-out code."
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "eradicate-2.3.0-py3-none-any.whl", hash = "sha256:2b29b3dd27171f209e4ddd8204b70c02f0682ae95eecb353f10e8d72b149c63e"},
{file = "eradicate-2.3.0.tar.gz", hash = "sha256:06df115be3b87d0fc1c483db22a2ebb12bcf40585722810d809cc770f5031c37"},
@@ -766,6 +800,8 @@ version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
+groups = ["test"]
+markers = "python_version < \"3.11\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@@ -780,6 +816,7 @@ version = "3.16.1"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
{file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"},
{file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"},
@@ -788,7 +825,7 @@ files = [
[package.extras]
docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"]
testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"]
-typing = ["typing-extensions (>=4.12.2)"]
+typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""]
[[package]]
name = "flake8"
@@ -796,6 +833,7 @@ version = "5.0.4"
description = "the modular source code checker: pep8 pyflakes and co"
optional = false
python-versions = ">=3.6.1"
+groups = ["dev"]
files = [
{file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
{file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
@@ -812,6 +850,7 @@ version = "22.10.25"
description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "flake8-bugbear-22.10.25.tar.gz", hash = "sha256:89e51284eb929fbb7f23fbd428491e7427f7cdc8b45a77248daffe86a039d696"},
{file = "flake8_bugbear-22.10.25-py3-none-any.whl", hash = "sha256:584631b608dc0d7d3f9201046d5840a45502da4732d5e8df6c7ac1694a91cb9e"},
@@ -830,6 +869,7 @@ version = "0.2.3"
description = "Adds copyright checks to flake8"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "flake8-copyright-0.2.3.tar.gz", hash = "sha256:698840480d377e7c70172672636d898ad7b8af210492f431fff066e75b481d59"},
{file = "flake8_copyright-0.2.3-py3-none-any.whl", hash = "sha256:1f899782bedce6bf086419fd5fb66da6ae0698b0d7faa5269520b4c965d74883"},
@@ -844,6 +884,7 @@ version = "1.6.0"
description = "Extension for flake8 which uses pydocstyle to check docstrings"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "flake8-docstrings-1.6.0.tar.gz", hash = "sha256:9fe7c6a306064af8e62a055c2f61e9eb1da55f84bb39caef2b84ce53708ac34b"},
{file = "flake8_docstrings-1.6.0-py2.py3-none-any.whl", hash = "sha256:99cac583d6c7e32dd28bbfbef120a7c0d1b6dde4adb5a9fd441c4227a6534bde"},
@@ -859,6 +900,7 @@ version = "1.4.0"
description = "Flake8 plugin to find commented out code"
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["dev"]
files = [
{file = "flake8-eradicate-1.4.0.tar.gz", hash = "sha256:3088cfd6717d1c9c6c3ac45ef2e5f5b6c7267f7504d5a74b781500e95cb9c7e1"},
{file = "flake8_eradicate-1.4.0-py3-none-any.whl", hash = "sha256:e3bbd0871be358e908053c1ab728903c114f062ba596b4d40c852fd18f473d56"},
@@ -875,6 +917,7 @@ version = "5.0.0"
description = "flake8 plugin that integrates isort ."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "flake8-isort-5.0.0.tar.gz", hash = "sha256:e336f928c7edc509684930ab124414194b7f4e237c712af8fcbdf49d8747b10c"},
{file = "flake8_isort-5.0.0-py3-none-any.whl", hash = "sha256:c73f9cbd1bf209887f602a27b827164ccfeba1676801b2aa23cb49051a1be79c"},
@@ -893,6 +936,7 @@ version = "2.1.0"
description = "Copy your docs directly to the gh-pages branch."
optional = false
python-versions = "*"
+groups = ["docs"]
files = [
{file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
{file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
@@ -910,6 +954,7 @@ version = "4.0.12"
description = "Git Object Database"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf"},
{file = "gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571"},
@@ -924,6 +969,7 @@ version = "3.1.44"
description = "GitPython is a Python library used to interact with Git repositories"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110"},
{file = "gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269"},
@@ -934,7 +980,7 @@ gitdb = ">=4.0.1,<5"
[package.extras]
doc = ["sphinx (>=7.1.2,<7.2)", "sphinx-autodoc-typehints", "sphinx_rtd_theme"]
-test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"]
+test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock ; python_version < \"3.8\"", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions ; python_version < \"3.11\""]
[[package]]
name = "googleapis-common-protos"
@@ -942,6 +988,7 @@ version = "1.70.0"
description = "Common protobufs used in Google APIs"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
files = [
{file = "googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8"},
{file = "googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257"},
@@ -959,6 +1006,7 @@ version = "1.71.0"
description = "HTTP/2-based RPC framework"
optional = false
python-versions = ">=3.9"
+groups = ["main", "dev"]
files = [
{file = "grpcio-1.71.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:c200cb6f2393468142eb50ab19613229dcc7829b5ccee8b658a36005f6669fdd"},
{file = "grpcio-1.71.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b2266862c5ad664a380fbbcdbdb8289d71464c42a8c29053820ee78ba0119e5d"},
@@ -1022,6 +1070,7 @@ version = "1.71.0"
description = "Protobuf code generator for gRPC"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "grpcio_tools-1.71.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:f4ad7f0d756546902597053d70b3af2606fbd70d7972876cd75c1e241d22ae00"},
{file = "grpcio_tools-1.71.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:64bdb291df61cf570b5256777ad5fe2b1db6d67bc46e55dc56a0a862722ae329"},
@@ -1087,6 +1136,7 @@ version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
+groups = ["main", "dev", "docs"]
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
@@ -1101,21 +1151,23 @@ version = "8.6.1"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.9"
+groups = ["dev", "docs"]
files = [
{file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"},
{file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"},
]
+markers = {dev = "python_full_version < \"3.10.2\"", docs = "python_version == \"3.9\""}
[package.dependencies]
zipp = ">=3.20"
[package.extras]
-check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
+check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
perf = ["ipython"]
-test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
+test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
type = ["pytest-mypy"]
[[package]]
@@ -1124,6 +1176,7 @@ version = "2.1.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.8"
+groups = ["test"]
files = [
{file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"},
{file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"},
@@ -1135,6 +1188,7 @@ version = "5.10.1"
description = "A Python utility / library to sort Python imports."
optional = false
python-versions = ">=3.6.1,<4.0"
+groups = ["dev"]
files = [
{file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
{file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
@@ -1152,6 +1206,7 @@ version = "3.1.6"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
+groups = ["dev", "docs"]
files = [
{file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"},
{file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"},
@@ -1169,6 +1224,7 @@ version = "1.4.2"
description = "Lightweight pipelining with Python functions"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"},
{file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"},
@@ -1180,6 +1236,7 @@ version = "4.23.0"
description = "An implementation of JSON Schema validation for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
{file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"},
{file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"},
@@ -1201,6 +1258,7 @@ version = "2024.10.1"
description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
files = [
{file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"},
{file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"},
@@ -1215,6 +1273,7 @@ version = "1.10.0"
description = "A fast and thorough lazy object proxy."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"},
{file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"},
@@ -1261,6 +1320,7 @@ version = "0.7.2"
description = "Check python packages from requirement.txt and report issues"
optional = false
python-versions = ">=2.7"
+groups = ["dev"]
files = [
{file = "liccheck-0.7.2-py2.py3-none-any.whl", hash = "sha256:a50d212b943d119f61d822080e0b7bcefbae4c3b7cc7b54b47b465c191bfc8aa"},
{file = "liccheck-0.7.2.tar.gz", hash = "sha256:1961ee9bd9ae72c21f79da6db3a2048536f0912f4c5fde0f0c062d65ea5fbf0a"},
@@ -1277,6 +1337,7 @@ version = "3.8"
description = "Python implementation of John Gruber's Markdown."
optional = false
python-versions = ">=3.9"
+groups = ["docs"]
files = [
{file = "markdown-3.8-py3-none-any.whl", hash = "sha256:794a929b79c5af141ef5ab0f2f642d0f7b1872981250230e72682346f7cc90dc"},
{file = "markdown-3.8.tar.gz", hash = "sha256:7df81e63f0df5c4b24b7d156eb81e4690595239b7d70937d0409f1b0de319c6f"},
@@ -1295,6 +1356,7 @@ version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
@@ -1319,6 +1381,7 @@ version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
+groups = ["dev", "docs"]
files = [
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
@@ -1389,6 +1452,7 @@ version = "3.26.1"
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"},
{file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"},
@@ -1408,6 +1472,7 @@ version = "0.7.0"
description = "McCabe checker, plugin for flake8"
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
@@ -1419,6 +1484,7 @@ version = "0.1.2"
description = "Markdown URL utilities"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
@@ -1430,6 +1496,7 @@ version = "1.3.4"
description = "A deep merge function for 🐍."
optional = false
python-versions = ">=3.6"
+groups = ["docs"]
files = [
{file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"},
{file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"},
@@ -1441,6 +1508,7 @@ version = "1.6.1"
description = "Project documentation with Markdown."
optional = false
python-versions = ">=3.8"
+groups = ["docs"]
files = [
{file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"},
{file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"},
@@ -1464,7 +1532,7 @@ watchdog = ">=2.0"
[package.extras]
i18n = ["babel (>=2.9.0)"]
-min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"]
+min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4) ; platform_system == \"Windows\"", "ghp-import (==1.0)", "importlib-metadata (==4.4) ; python_version < \"3.10\"", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"]
[[package]]
name = "mkdocs-get-deps"
@@ -1472,6 +1540,7 @@ version = "0.2.0"
description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file"
optional = false
python-versions = ">=3.8"
+groups = ["docs"]
files = [
{file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"},
{file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"},
@@ -1489,6 +1558,7 @@ version = "9.6.11"
description = "Documentation that simply works"
optional = false
python-versions = ">=3.8"
+groups = ["docs"]
files = [
{file = "mkdocs_material-9.6.11-py3-none-any.whl", hash = "sha256:47f21ef9cbf4f0ebdce78a2ceecaa5d413581a55141e4464902224ebbc0b1263"},
{file = "mkdocs_material-9.6.11.tar.gz", hash = "sha256:0b7f4a0145c5074cdd692e4362d232fb25ef5b23328d0ec1ab287af77cc0deff"},
@@ -1518,6 +1588,7 @@ version = "1.3.1"
description = "Extension pack for Python Markdown and MkDocs Material."
optional = false
python-versions = ">=3.8"
+groups = ["docs"]
files = [
{file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"},
{file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"},
@@ -1525,45 +1596,56 @@ files = [
[[package]]
name = "mypy"
-version = "0.982"
+version = "1.15.0"
description = "Optional static typing for Python"
optional = false
-python-versions = ">=3.7"
-files = [
- {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"},
- {file = "mypy-0.982-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41fd1cf9bc0e1c19b9af13a6580ccb66c381a5ee2cf63ee5ebab747a4badeba3"},
- {file = "mypy-0.982-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f793e3dd95e166b66d50e7b63e69e58e88643d80a3dcc3bcd81368e0478b089c"},
- {file = "mypy-0.982-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86ebe67adf4d021b28c3f547da6aa2cce660b57f0432617af2cca932d4d378a6"},
- {file = "mypy-0.982-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:175f292f649a3af7082fe36620369ffc4661a71005aa9f8297ea473df5772046"},
- {file = "mypy-0.982-cp310-cp310-win_amd64.whl", hash = "sha256:8ee8c2472e96beb1045e9081de8e92f295b89ac10c4109afdf3a23ad6e644f3e"},
- {file = "mypy-0.982-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58f27ebafe726a8e5ccb58d896451dd9a662a511a3188ff6a8a6a919142ecc20"},
- {file = "mypy-0.982-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6af646bd46f10d53834a8e8983e130e47d8ab2d4b7a97363e35b24e1d588947"},
- {file = "mypy-0.982-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7aeaa763c7ab86d5b66ff27f68493d672e44c8099af636d433a7f3fa5596d40"},
- {file = "mypy-0.982-cp37-cp37m-win_amd64.whl", hash = "sha256:724d36be56444f569c20a629d1d4ee0cb0ad666078d59bb84f8f887952511ca1"},
- {file = "mypy-0.982-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14d53cdd4cf93765aa747a7399f0961a365bcddf7855d9cef6306fa41de01c24"},
- {file = "mypy-0.982-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26ae64555d480ad4b32a267d10cab7aec92ff44de35a7cd95b2b7cb8e64ebe3e"},
- {file = "mypy-0.982-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6389af3e204975d6658de4fb8ac16f58c14e1bacc6142fee86d1b5b26aa52bda"},
- {file = "mypy-0.982-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b35ce03a289480d6544aac85fa3674f493f323d80ea7226410ed065cd46f206"},
- {file = "mypy-0.982-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6e564f035d25c99fd2b863e13049744d96bd1947e3d3d2f16f5828864506763"},
- {file = "mypy-0.982-cp38-cp38-win_amd64.whl", hash = "sha256:cebca7fd333f90b61b3ef7f217ff75ce2e287482206ef4a8b18f32b49927b1a2"},
- {file = "mypy-0.982-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a705a93670c8b74769496280d2fe6cd59961506c64f329bb179970ff1d24f9f8"},
- {file = "mypy-0.982-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75838c649290d83a2b83a88288c1eb60fe7a05b36d46cbea9d22efc790002146"},
- {file = "mypy-0.982-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91781eff1f3f2607519c8b0e8518aad8498af1419e8442d5d0afb108059881fc"},
- {file = "mypy-0.982-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa97b9ddd1dd9901a22a879491dbb951b5dec75c3b90032e2baa7336777363b"},
- {file = "mypy-0.982-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a692a8e7d07abe5f4b2dd32d731812a0175626a90a223d4b58f10f458747dd8a"},
- {file = "mypy-0.982-cp39-cp39-win_amd64.whl", hash = "sha256:eb7a068e503be3543c4bd329c994103874fa543c1727ba5288393c21d912d795"},
- {file = "mypy-0.982-py3-none-any.whl", hash = "sha256:1021c241e8b6e1ca5a47e4d52601274ac078a89845cfde66c6d5f769819ffa1d"},
- {file = "mypy-0.982.tar.gz", hash = "sha256:85f7a343542dc8b1ed0a888cdd34dca56462654ef23aa673907305b260b3d746"},
-]
-
-[package.dependencies]
-mypy-extensions = ">=0.4.3"
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"},
+ {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"},
+ {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b"},
+ {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3"},
+ {file = "mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b"},
+ {file = "mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828"},
+ {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"},
+ {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"},
+ {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"},
+ {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"},
+ {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"},
+ {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"},
+ {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"},
+ {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"},
+ {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"},
+ {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"},
+ {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"},
+ {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"},
+ {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"},
+ {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"},
+ {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"},
+ {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"},
+ {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"},
+ {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"},
+ {file = "mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078"},
+ {file = "mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba"},
+ {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5"},
+ {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b"},
+ {file = "mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2"},
+ {file = "mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980"},
+ {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"},
+ {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"},
+]
+
+[package.dependencies]
+mypy_extensions = ">=1.0.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-typing-extensions = ">=3.10"
+typing_extensions = ">=4.6.0"
[package.extras]
dmypy = ["psutil (>=4.0)"]
-python2 = ["typed-ast (>=1.4.0,<2)"]
+faster-cache = ["orjson"]
+install-types = ["pip"]
+mypyc = ["setuptools (>=50)"]
reports = ["lxml"]
[[package]]
@@ -1572,6 +1654,7 @@ version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
+groups = ["dev"]
files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
@@ -1583,6 +1666,7 @@ version = "3.9.1"
description = "Natural Language Toolkit"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "nltk-3.9.1-py3-none-any.whl", hash = "sha256:4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1"},
{file = "nltk-3.9.1.tar.gz", hash = "sha256:87d127bd3de4bd89a4f81265e5fa59cb1b199b27440175370f7417d2bc7ae868"},
@@ -1608,6 +1692,7 @@ version = "0.8.12"
description = "General purpose Python utility library."
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["docs"]
files = [
{file = "nr.util-0.8.12-py3-none-any.whl", hash = "sha256:91da02ac9795eb8e015372275c1efe54bac9051231ee9b0e7e6f96b0b4e7d2bb"},
{file = "nr.util-0.8.12.tar.gz", hash = "sha256:a4549c2033d99d2f0379b3f3d233fd2a8ade286bbf0b3ad0cc7cea16022214f4"},
@@ -1623,6 +1708,7 @@ version = "24.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
+groups = ["dev", "docs", "test"]
files = [
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
@@ -1634,6 +1720,7 @@ version = "0.5.7"
description = "Divides large result sets into pages for easier browsing"
optional = false
python-versions = "*"
+groups = ["docs"]
files = [
{file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"},
{file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"},
@@ -1649,6 +1736,7 @@ version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
optional = false
python-versions = ">=3.8"
+groups = ["dev", "docs"]
files = [
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
@@ -1660,6 +1748,7 @@ version = "6.1.1"
description = "Python Build Reasonableness"
optional = false
python-versions = ">=2.6"
+groups = ["dev"]
files = [
{file = "pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76"},
{file = "pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b"},
@@ -1674,6 +1763,7 @@ version = "4.3.7"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
python-versions = ">=3.9"
+groups = ["main", "dev", "docs"]
files = [
{file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"},
{file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"},
@@ -1690,6 +1780,7 @@ version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
+groups = ["dev", "test"]
files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
@@ -1705,6 +1796,7 @@ version = "5.29.4"
description = ""
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
{file = "protobuf-5.29.4-cp310-abi3-win32.whl", hash = "sha256:13eb236f8eb9ec34e63fc8b1d6efd2777d062fa6aaa68268fb67cf77f6839ad7"},
{file = "protobuf-5.29.4-cp310-abi3-win_amd64.whl", hash = "sha256:bcefcdf3976233f8a502d265eb65ea740c989bacc6c30a58290ed0e519eb4b8d"},
@@ -1725,6 +1817,7 @@ version = "6.1.1"
description = "Cross-platform lib for process and system monitoring in Python."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
+groups = ["dev"]
files = [
{file = "psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8"},
{file = "psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777"},
@@ -1755,6 +1848,7 @@ version = "1.11.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+groups = ["dev"]
files = [
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
@@ -1766,6 +1860,7 @@ version = "2.9.1"
description = "Python style guide checker"
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"},
{file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"},
@@ -1777,6 +1872,8 @@ version = "2.22"
description = "C parser in Python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "platform_python_implementation != \"PyPy\""
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
@@ -1788,6 +1885,7 @@ version = "3.22.0"
description = "Cryptographic library for Python"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+groups = ["main"]
files = [
{file = "pycryptodome-3.22.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:96e73527c9185a3d9b4c6d1cfb4494f6ced418573150be170f6580cb975a7f5a"},
{file = "pycryptodome-3.22.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:9e1bb165ea1dc83a11e5dbbe00ef2c378d148f3a2d3834fb5ba4e0f6fd0afe4b"},
@@ -1826,6 +1924,7 @@ version = "2.9.2"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"},
{file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"},
@@ -1841,7 +1940,7 @@ typing-extensions = [
[package.extras]
email = ["email-validator (>=2.0.0)"]
-timezone = ["tzdata"]
+timezone = ["tzdata ; python_version >= \"3.9\" and sys_platform == \"win32\""]
[[package]]
name = "pydantic-core"
@@ -1849,6 +1948,7 @@ version = "2.23.4"
description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"},
{file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"},
@@ -1950,6 +2050,7 @@ version = "4.6.3"
description = "Create Python API documentation in Markdown format."
optional = false
python-versions = ">=3.7,<4.0"
+groups = ["docs"]
files = [
{file = "pydoc-markdown-4.6.3.tar.gz", hash = "sha256:82aa424de7e390e4a34ac200b189bb011e33be18bb089e83b15af5742cf21dc7"},
{file = "pydoc_markdown-4.6.3-py3-none-any.whl", hash = "sha256:b79da5b972be5c24db41ed5ce65fedd0031aa9cd023467d42cd47882a5e92f98"},
@@ -1976,6 +2077,7 @@ version = "6.3.0"
description = "Python docstring style checker"
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"},
{file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"},
@@ -1985,7 +2087,7 @@ files = [
snowballstemmer = ">=2.2.0"
[package.extras]
-toml = ["tomli (>=1.2.3)"]
+toml = ["tomli (>=1.2.3) ; python_version < \"3.11\""]
[[package]]
name = "pyflakes"
@@ -1993,6 +2095,7 @@ version = "2.5.0"
description = "passive checker of Python programs"
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
{file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
@@ -2004,6 +2107,7 @@ version = "2.19.1"
description = "Pygments is a syntax highlighting package written in Python."
optional = false
python-versions = ">=3.8"
+groups = ["dev", "docs"]
files = [
{file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"},
{file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"},
@@ -2018,6 +2122,7 @@ version = "2.15.5"
description = "python code static checker"
optional = false
python-versions = ">=3.7.2"
+groups = ["dev"]
files = [
{file = "pylint-2.15.5-py3-none-any.whl", hash = "sha256:c2108037eb074334d9e874dc3c783752cc03d0796c88c9a9af282d0f161a1004"},
{file = "pylint-2.15.5.tar.gz", hash = "sha256:3b120505e5af1d06a5ad76b55d8660d44bf0f2fc3c59c2bdd94e39188ee3a4df"},
@@ -2044,6 +2149,7 @@ version = "10.14.3"
description = "Extension pack for Python Markdown."
optional = false
python-versions = ">=3.8"
+groups = ["docs"]
files = [
{file = "pymdown_extensions-10.14.3-py3-none-any.whl", hash = "sha256:05e0bee73d64b9c71a4ae17c72abc2f700e8bc8403755a00580b49a4e9f189e9"},
{file = "pymdown_extensions-10.14.3.tar.gz", hash = "sha256:41e576ce3f5d650be59e900e4ceff231e0aed2a88cf30acaee41e02f063a061b"},
@@ -2062,6 +2168,7 @@ version = "1.2.0"
description = "Wrappers to call pyproject.toml-based build backend hooks."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"},
{file = "pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8"},
@@ -2073,6 +2180,7 @@ version = "8.3.5"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
+groups = ["test"]
files = [
{file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"},
{file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"},
@@ -2095,6 +2203,7 @@ version = "15.0"
description = "pytest plugin to re-run tests to eliminate flaky failures"
optional = false
python-versions = ">=3.9"
+groups = ["test"]
files = [
{file = "pytest-rerunfailures-15.0.tar.gz", hash = "sha256:2d9ac7baf59f4c13ac730b47f6fa80e755d1ba0581da45ce30b72fb3542b4474"},
{file = "pytest_rerunfailures-15.0-py3-none-any.whl", hash = "sha256:dd150c4795c229ef44320adc9a0c0532c51b78bb7a6843a8c53556b9a611df1a"},
@@ -2110,6 +2219,7 @@ version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+groups = ["main", "docs"]
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
@@ -2124,6 +2234,7 @@ version = "5.3.1"
description = "YAML parser and emitter for Python"
optional = false
python-versions = "*"
+groups = ["dev", "docs"]
files = [
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"},
{file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"},
@@ -2146,6 +2257,7 @@ version = "0.1"
description = "A custom YAML tag for referencing environment variables in YAML files. "
optional = false
python-versions = ">=3.6"
+groups = ["docs"]
files = [
{file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"},
{file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"},
@@ -2160,6 +2272,7 @@ version = "0.36.2"
description = "JSON Referencing + Python"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
files = [
{file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"},
{file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"},
@@ -2176,6 +2289,7 @@ version = "2024.11.6"
description = "Alternative regular expression module, to replace re."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"},
{file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"},
@@ -2279,6 +2393,7 @@ version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev", "docs"]
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
@@ -2300,6 +2415,7 @@ version = "14.0.0"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false
python-versions = ">=3.8.0"
+groups = ["dev"]
files = [
{file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"},
{file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"},
@@ -2319,6 +2435,7 @@ version = "0.24.0"
description = "Python bindings to Rust's persistent data structures (rpds)"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
files = [
{file = "rpds_py-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724"},
{file = "rpds_py-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b"},
@@ -2442,6 +2559,7 @@ version = "0.18.10"
description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "ruamel.yaml-0.18.10-py3-none-any.whl", hash = "sha256:30f22513ab2301b3d2b577adc121c6471f28734d3d9728581245f1e76468b4f1"},
{file = "ruamel.yaml-0.18.10.tar.gz", hash = "sha256:20c86ab29ac2153f80a428e1254a8adf686d3383df04490514ca3b79a362db58"},
@@ -2460,6 +2578,8 @@ version = "0.2.12"
description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""
files = [
{file = "ruamel.yaml.clib-0.2.12-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5"},
{file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969"},
@@ -2515,6 +2635,7 @@ version = "3.3.1"
description = "Scan dependencies for known vulnerabilities and licenses."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "safety-3.3.1-py3-none-any.whl", hash = "sha256:243355a961403b873c1504e3e6f79ce36b86881d559722595632d788aa92b7ea"},
{file = "safety-3.3.1.tar.gz", hash = "sha256:679834432d0ad64c54e0b864ac6715d4743a65f8db67512380ee7ee2011c206a"},
@@ -2549,6 +2670,7 @@ version = "0.0.11"
description = "Schemas for Safety tools"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "safety_schemas-0.0.11-py3-none-any.whl", hash = "sha256:2af940c1c992d6891a6b84403a7c12fd445e20651752b1818b86c205690b3e03"},
{file = "safety_schemas-0.0.11.tar.gz", hash = "sha256:10804372e077ca5a95e740cc507e73d9173663284006fcaaf5756179ba13ac9d"},
@@ -2567,13 +2689,14 @@ version = "2.10.0"
description = "A library implementing the 'SemVer' scheme."
optional = false
python-versions = ">=2.7"
+groups = ["dev"]
files = [
{file = "semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177"},
{file = "semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c"},
]
[package.extras]
-dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1)", "coverage", "flake8", "nose2", "readme-renderer (<25.0)", "tox", "wheel", "zest.releaser[recommended]"]
+dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1) ; python_version == \"3.4\"", "coverage", "flake8", "nose2", "readme-renderer (<25.0) ; python_version == \"3.4\"", "tox", "wheel", "zest.releaser[recommended]"]
doc = ["Sphinx", "sphinx-rtd-theme"]
[[package]]
@@ -2582,19 +2705,20 @@ version = "78.1.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "setuptools-78.1.0-py3-none-any.whl", hash = "sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8"},
{file = "setuptools-78.1.0.tar.gz", hash = "sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54"},
]
[package.extras]
-check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"]
-core = ["importlib_metadata (>=6)", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
+check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""]
+core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
enabler = ["pytest-enabler (>=2.2)"]
-test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"]
-type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"]
+test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"]
+type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"]
[[package]]
name = "shellingham"
@@ -2602,6 +2726,7 @@ version = "1.5.4"
description = "Tool to Detect Surrounding Shell"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
@@ -2613,6 +2738,7 @@ version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+groups = ["main", "dev", "docs"]
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
@@ -2624,6 +2750,7 @@ version = "5.0.2"
description = "A pure Python implementation of a sliding window memory map manager"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"},
{file = "smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5"},
@@ -2635,17 +2762,47 @@ version = "2.2.0"
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
{file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
{file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
]
+[[package]]
+name = "sortedcontainers"
+version = "2.4.0"
+description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
+optional = false
+python-versions = "*"
+groups = ["main", "dev"]
+files = [
+ {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"},
+ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
+]
+
+[[package]]
+name = "sortedcontainers-stubs"
+version = "2.4.3"
+description = "Type stubs for sortedcontainers"
+optional = false
+python-versions = "<4.0,>=3.9"
+groups = ["dev"]
+files = [
+ {file = "sortedcontainers_stubs-2.4.3-py3-none-any.whl", hash = "sha256:4496109dfa6645e4b675f57fbc7e42ec4d1bed2c74aab7fa379e0795e49fe406"},
+ {file = "sortedcontainers_stubs-2.4.3.tar.gz", hash = "sha256:ba172daceda4bd617d2f6ffd24582261a494da92705409651967faa40ebc75dd"},
+]
+
+[package.dependencies]
+sortedcontainers = ">=2,<3"
+typing-extensions = ">=4.1.0,<5.0.0"
+
[[package]]
name = "stevedore"
version = "5.4.1"
description = "Manage dynamic plugins for Python applications"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe"},
{file = "stevedore-5.4.1.tar.gz", hash = "sha256:3135b5ae50fe12816ef291baff420acb727fcd356106e3e9cbfa9e5985cd6f4b"},
@@ -2660,6 +2817,7 @@ version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+groups = ["dev"]
files = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
@@ -2671,6 +2829,7 @@ version = "2.2.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
+groups = ["dev", "docs", "test"]
files = [
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
@@ -2705,6 +2864,7 @@ files = [
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
]
+markers = {dev = "python_version < \"3.11\"", test = "python_version < \"3.11\""}
[[package]]
name = "tomli-w"
@@ -2712,6 +2872,7 @@ version = "1.2.0"
description = "A lil' TOML writer"
optional = false
python-versions = ">=3.9"
+groups = ["docs"]
files = [
{file = "tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90"},
{file = "tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021"},
@@ -2723,6 +2884,7 @@ version = "0.13.2"
description = "Style preserving TOML library"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"},
{file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"},
@@ -2734,6 +2896,7 @@ version = "3.28.0"
description = "tox is a generic virtualenv management and test command line tool"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+groups = ["dev"]
files = [
{file = "tox-3.28.0-py2.py3-none-any.whl", hash = "sha256:57b5ab7e8bb3074edc3c0c0b4b192a4f3799d3723b2c5b76f1fa9f2d40316eea"},
{file = "tox-3.28.0.tar.gz", hash = "sha256:d0d28f3fe6d6d7195c27f8b054c3e99d5451952b54abdae673b71609a581f640"},
@@ -2751,7 +2914,7 @@ virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,
[package.extras]
docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"]
-testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)"]
+testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3) ; python_version < \"3.4\"", "psutil (>=5.6.1) ; platform_python_implementation == \"cpython\"", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)"]
[[package]]
name = "tqdm"
@@ -2759,6 +2922,7 @@ version = "4.67.1"
description = "Fast, Extensible Progress Meter"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"},
{file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"},
@@ -2780,6 +2944,7 @@ version = "0.15.2"
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc"},
{file = "typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5"},
@@ -2797,10 +2962,12 @@ version = "4.13.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev", "docs"]
files = [
{file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"},
{file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"},
]
+markers = {main = "python_version < \"3.13\""}
[[package]]
name = "urllib3"
@@ -2808,13 +2975,14 @@ version = "2.4.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.9"
+groups = ["main", "dev", "docs"]
files = [
{file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"},
{file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"},
]
[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
+brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
@@ -2825,6 +2993,7 @@ version = "20.30.0"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
{file = "virtualenv-20.30.0-py3-none-any.whl", hash = "sha256:e34302959180fca3af42d1800df014b35019490b119eba981af27f2fa486e5d6"},
{file = "virtualenv-20.30.0.tar.gz", hash = "sha256:800863162bcaa5450a6e4d721049730e7f2dae07720e0902b0e4040bd6f9ada8"},
@@ -2837,7 +3006,7 @@ platformdirs = ">=3.9.1,<5"
[package.extras]
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
-test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
+test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""]
[[package]]
name = "vulture"
@@ -2845,6 +3014,7 @@ version = "2.6"
description = "Find dead code"
optional = false
python-versions = ">=3.6"
+groups = ["dev"]
files = [
{file = "vulture-2.6-py2.py3-none-any.whl", hash = "sha256:e792e903ccc063ec4873a8979dcf11b51ea3d65a2d3b31c113d47be48f0cdcae"},
{file = "vulture-2.6.tar.gz", hash = "sha256:2515fa848181001dc8a73aba6a01a1a17406f5d372f24ec7f7191866f9f4997e"},
@@ -2859,6 +3029,7 @@ version = "6.0.0"
description = "Filesystem events monitoring"
optional = false
python-versions = ">=3.9"
+groups = ["docs"]
files = [
{file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"},
{file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"},
@@ -2901,6 +3072,7 @@ version = "1.17.2"
description = "Module for decorators, wrappers and monkey patching."
optional = false
python-versions = ">=3.8"
+groups = ["dev", "docs"]
files = [
{file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"},
{file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"},
@@ -2989,6 +3161,7 @@ version = "0.43.0"
description = "A formatter for Python code"
optional = false
python-versions = ">=3.7"
+groups = ["docs"]
files = [
{file = "yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca"},
{file = "yapf-0.43.0.tar.gz", hash = "sha256:00d3aa24bfedff9420b2e0d5d9f5ab6d9d4268e72afbf59bb3fa542781d5218e"},
@@ -3004,20 +3177,22 @@ version = "3.21.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.9"
+groups = ["dev", "docs"]
files = [
{file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"},
{file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"},
]
+markers = {dev = "python_full_version < \"3.10.2\"", docs = "python_version == \"3.9\""}
[package.extras]
-check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
+check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
-test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"]
+test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"]
type = ["pytest-mypy"]
[metadata]
-lock-version = "2.0"
+lock-version = "2.1"
python-versions = "^3.9"
-content-hash = "1161c9e59011b9c14ead2344eb61fe846fe0e0b3a07de95f68486446906b7fc9"
+content-hash = "9a7d48b66ce5fe817d9f6f310495ae9e71a1bfd0ef3c5a3bdf8b96404d8713ca"
diff --git a/pyproject.toml b/pyproject.toml
index 502a23d7..478e7ba6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -45,6 +45,7 @@ python-dateutil = "*"
pycryptodome = "^3.18.0"
googleapis-common-protos = "*"
virtualenv = ">=20.26.6"
+sortedcontainers = "==2.4.0"
[tool.poetry.group.dev]
optional = true
@@ -54,7 +55,7 @@ check-manifest = "*"
tox = "^3.26"
flake8 = "==5.0.4"
black = "^22.10"
-mypy = "==0.982"
+mypy = "==1.15.0"
bandit = "==1.7.4"
safety = "==3.3.1"
isort = "==5.10.1"
@@ -72,6 +73,7 @@ pyyaml = "==5.3.1"
packaging = ">=23.0"
virtualenv = ">=20.26.6"
marshmallow = "<4.0.0"
+sortedcontainers-stubs = "2.4.3"
[tool.poetry.group.docs]
optional = true
@@ -113,7 +115,8 @@ module = [
"certifi.*",
"mbedtls.*",
"jsonschema.*",
- "dateutil.*"
+ "dateutil.*",
+ "sortedcontainers.*"
]
ignore_missing_imports = true
diff --git a/strategy.ini b/strategy.ini
index d8b5bb2e..56158dec 100644
--- a/strategy.ini
+++ b/strategy.ini
@@ -93,4 +93,6 @@ pycryptodome: >=3.15.0
attrs: >=19.2.0
referencing: >=0.28.4
typing-extensions: >=3.0.0
-urllib3: >=1.21.0
\ No newline at end of file
+urllib3: >=1.21.0
+jsonschema: >=3.2.0
+jsonschema-specifications: >=2023.3.6
\ No newline at end of file
diff --git a/tests/unit/test_aerial/coins_test.py b/tests/unit/test_aerial/coins_test.py
index f6ab5466..8300dd2d 100644
--- a/tests/unit/test_aerial/coins_test.py
+++ b/tests/unit/test_aerial/coins_test.py
@@ -20,7 +20,7 @@
# ------------------------------------------------------------------------------
import pytest
-from cosmpy.aerial.coins import Coin, Coins, is_coins_sorted, parse_coins, sort_coins
+from cosmpy.aerial.coins import Coin, Coins, OnCollision, parse_coins
from cosmpy.protos.cosmos.base.v1beta1.coin_pb2 import Coin as CoinProto
@@ -68,112 +68,11 @@ def test_parsing_coins_string(input_coins, expected_result):
"input_coins,expected_coins,validate_error",
[
([], [], None),
- ("4afet,5afet", [Coin(4, "afet"), Coin(5, "afet")], None),
- ("5ccc,2bcc,4acc", [Coin(5, "ccc"), Coin(2, "bcc"), Coin(4, "acc")], None),
(
- [
- CoinProto(amount="4", denom="bcc"),
- CoinProto(amount="2", denom="ccc"),
- CoinProto(amount="5", denom="acc"),
- ],
- [Coin(4, "bcc"), Coin(2, "ccc"), Coin(5, "acc")],
- None,
- ),
- (CoinProto(amount="4", denom="acc"), [Coin(4, "acc")], None),
- (Coin(4, "acc"), [Coin(4, "acc")], None),
- (
- [Coin(2, "acc"), CoinProto(amount="4", denom="bcc")],
- [Coin(2, "acc"), Coin(4, "bcc")],
- None,
- ),
- (
- "0bcc,2ccc,0acc",
- [Coin(0, "bcc"), Coin(2, "ccc"), Coin(0, "acc")],
+ "4afet,5afet",
None,
+ 'Attempt to merge a coin with the "afet" denomination which already exists in the receiving coins instance',
),
- ],
-)
-def test_coins_ordering_preserved_during_instantiation(
- input_coins, expected_coins, validate_error
-):
- """Test preservation of ordering during initialidation."""
- if validate_error:
- with pytest.raises(Exception) as exc_info:
- _ = Coins(input_coins)
- assert validate_error in str(exc_info.value)
-
- if not validate_error:
- _input_coins = Coins(input_coins)
- assert _input_coins == Coins(expected_coins)
-
- assert len(_input_coins) == len(expected_coins)
- for in_c, exp_c in zip(_input_coins, expected_coins):
- assert in_c == exp_c
-
-
-@pytest.mark.parametrize(
- "input_coins,expected_coins,validate_error",
- [
- ([], [], None),
- ("4afet,5afet", None, 'Multiple occurrences of the "afet" denomination'),
- ("4acc,2bcc,5ccc", [Coin(4, "acc"), Coin(2, "bcc"), Coin(5, "ccc")], None),
- (
- [
- CoinProto(amount="4", denom="acc"),
- CoinProto(amount="2", denom="bcc"),
- CoinProto(amount="5", denom="ccc"),
- ],
- [Coin(4, "acc"), Coin(2, "bcc"), Coin(5, "ccc")],
- None,
- ),
- (CoinProto(amount="4", denom="acc"), [Coin(4, "acc")], None),
- (Coin(4, "acc"), [Coin(4, "acc")], None),
- (
- [Coin(2, "acc"), CoinProto(amount="4", denom="bcc")],
- [Coin(2, "acc"), Coin(4, "bcc")],
- None,
- ),
- (
- "4acc,2ccc,5bcc",
- [Coin(4, "acc"), Coin(2, "ccc"), Coin(5, "bcc")],
- "Coins are not sorted",
- ),
- (
- "4cc",
- None,
- 'The "cc" denom does not conform to Cosmos-SDK requirements',
- ),
- (
- "4acc,0bcc,5ccc",
- None,
- "Coin amount must be greater than zero",
- ),
- (
- "4acc,1bcc,0ccc",
- None,
- "Coin amount must be greater than zero",
- ),
- ],
-)
-def test_coins_validate(input_coins, expected_coins, validate_error):
- """Test Coins validate."""
- if validate_error:
- with pytest.raises(Exception) as exc_info:
- test_coins = Coins(input_coins)
- test_coins.validate()
- assert validate_error in str(exc_info.value)
-
- if not validate_error:
- test_coins = Coins(input_coins)
- assert test_coins == expected_coins
- test_coins.validate()
-
-
-@pytest.mark.parametrize(
- "input_coins,expected_coins,validate_error",
- [
- ([], [], None),
- ("4afet,5afet", None, 'Multiple occurrences of the "afet" denomination'),
("4acc,2bcc,5ccc", [Coin(4, "acc"), Coin(2, "bcc"), Coin(5, "ccc")], None),
(
[
@@ -199,7 +98,7 @@ def test_coins_validate(input_coins, expected_coins, validate_error):
(
"4cc",
None,
- 'The "cc" denom does not conform to Cosmos-SDK requirements',
+ 'Coin denom "cc" does not conform to Cosmos-SDK requirements',
),
(
"4acc,5ccc,0bcc",
@@ -218,37 +117,16 @@ def test_coins_validate(input_coins, expected_coins, validate_error):
),
],
)
-def test_coins_canonicalise(input_coins, expected_coins, validate_error):
- """Test Coins canonicalise."""
+def test_coins_instantiate(input_coins, expected_coins, validate_error):
+ """Test Coins instantiate."""
if validate_error:
with pytest.raises(Exception) as exc_info:
- _ = Coins(input_coins).canonicalise()
+ _ = Coins(input_coins)
assert validate_error in str(exc_info.value)
if not validate_error:
- canonicalised_input_coins = Coins(input_coins).canonicalise()
- assert canonicalised_input_coins == Coins(expected_coins)
-
-
-@pytest.mark.parametrize(
- "input_coins,expected_sorted_coins",
- [([], []), ("4acc,2ccc,5bcc", "4acc,5bcc,2ccc")],
-)
-def test_coins_sort(input_coins, expected_sorted_coins):
- """Test Coins sort."""
- sorted_coins = Coins(input_coins)
- sort_coins(sorted_coins)
-
- input_coins = Coins(input_coins)
- expected_sorted_coins = Coins(expected_sorted_coins)
-
- if input_coins != sorted_coins:
- assert not is_coins_sorted(input_coins)
-
- sort_coins(input_coins)
-
- assert is_coins_sorted(input_coins)
- assert input_coins == expected_sorted_coins
+ instantiated_input_coins = Coins(input_coins)
+ assert instantiated_input_coins == Coins(expected_coins)
@pytest.mark.parametrize(
@@ -261,7 +139,7 @@ def test_add(coins_a, coins_b, expected_coins_res):
"""Test Coins add."""
coins_a = Coins(coins_a)
coins_b = Coins(coins_b)
- coins_res = coins_a.canonicalise() + coins_b.canonicalise()
+ coins_res = coins_a + coins_b
expected_coins_res = Coins(expected_coins_res)
@@ -284,8 +162,8 @@ def test_add(coins_a, coins_b, expected_coins_res):
)
def test_subtract(coins_a, coins_b, expected_coins_res, error):
"""Test Coins subtract."""
- coins_a = Coins(coins_a).canonicalise()
- coins_b = Coins(coins_b).canonicalise()
+ coins_a = Coins(coins_a)
+ coins_b = Coins(coins_b)
if error:
with pytest.raises(Exception) as exc_info:
@@ -297,3 +175,97 @@ def test_subtract(coins_a, coins_b, expected_coins_res, error):
expected_coins_res = Coins(expected_coins_res)
assert coins_res == expected_coins_res
+
+
+@pytest.mark.parametrize(
+ "coins_a,coins_b,expected_coins_res,error",
+ [
+ ("1ccc", "0ccc", "1ccc", None),
+ ("", "0ccc", "", None),
+ ("", "1ccc", "1ccc", None),
+ (None, "3gcc,1ccc", "1ccc,3gcc", None),
+ ("1ccc", "", "1ccc", None),
+ ("3gcc,1ccc", None, "1ccc,3gcc", None),
+ (
+ "4acc,2ccc",
+ "2ccc",
+ None,
+ 'Attempt to merge a coin with the "ccc" denomination which already exists in the receiving coins instance',
+ ),
+ ("4acc,2ccc", "1bcc", "4acc,1bcc,2ccc", None),
+ (
+ "4acc,2ccc,5ddd",
+ "1ccc",
+ None,
+ 'Attempt to merge a coin with the "ccc" denomination which already exists in the receiving coins instance',
+ ),
+ ("4acc,2ccc,5ddd", "1edd", "4acc,2ccc,5ddd,1edd", None),
+ ("4acc,2ccc,5ddd", "1edd,0acc,0ddd", "4acc,2ccc,5ddd,1edd", None),
+ ],
+)
+def test_merge_coins_fail_on_collision(coins_a, coins_b, expected_coins_res, error):
+ """Test Coins merge with fail on collision."""
+ coins_a1 = Coins(coins_a)
+ coins_a2 = Coins(coins_a)
+
+ if error:
+ with pytest.raises(Exception) as exc_info:
+ coins_a1.merge_from(coins_b)
+ assert error in str(exc_info.value)
+
+ with pytest.raises(Exception) as exc_info:
+ coins_a2.merge_from(coins_b, on_collision=OnCollision.Fail)
+ assert error in str(exc_info.value)
+ else:
+ expected_coins_res = Coins(expected_coins_res)
+
+ coins_a1.merge_from(coins_b)
+ assert coins_a1 == expected_coins_res
+
+ coins_a2.merge_from(coins_b, on_collision=OnCollision.Fail)
+ assert coins_a2 == expected_coins_res
+
+
+@pytest.mark.parametrize(
+ "coins_a,coins_b,expected_coins_res",
+ [
+ ("1ccc", "0ccc", "1ccc"),
+ ("", "0ccc", ""),
+ ("", "1ccc", "1ccc"),
+ (None, "3gcc,1ccc", "1ccc,3gcc"),
+ ("1ccc", "", "1ccc"),
+ ("3gcc,1ccc", None, "1ccc,3gcc"),
+ ("4acc,2ccc", "3gcc,1ccc", "4acc,1ccc,3gcc"),
+ ("4acc,2ccc", "1ccc", "4acc,1ccc"),
+ ("4acc,2ccc,5ddd,7ecc", "1acc,3ccc,6ddd", "1acc,3ccc,6ddd,7ecc"),
+ ("4acc,2ccc,5ddd", "1acc,3ccc,6ddd,7ecc", "1acc,3ccc,6ddd,7ecc"),
+ ("4acc,2ccc,5ddd", "1acc,7ecc", "1acc,2ccc,5ddd,7ecc"),
+ ("4acc,2ccc,5ddd", "1edd,0acc,0ddd", "4acc,2ccc,5ddd,1edd"),
+ ],
+)
+def test_merge_coins_override_on_collision(coins_a, coins_b, expected_coins_res):
+ """Test Coins merge with override on collision."""
+ expected_coins_res = Coins(expected_coins_res)
+
+ coins_a1 = Coins(coins_a)
+
+ coins_a1.merge_from(coins_b, on_collision=OnCollision.Override)
+ assert coins_a1 == expected_coins_res
+
+
+@pytest.mark.parametrize(
+ "coins_a",
+ [
+ None,
+ "",
+ "1ccc",
+ "4acc,2ccc,5ddd,7ecc",
+ ],
+)
+def test_clear(coins_a):
+ """Test Coins clear."""
+ coins = Coins(coins_a)
+
+ x = coins.clear()
+ assert len(coins) == 0
+ assert x == coins