mm-sol 0.2.6__tar.gz → 0.2.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. {mm_sol-0.2.6 → mm_sol-0.2.8}/PKG-INFO +3 -3
  2. {mm_sol-0.2.6 → mm_sol-0.2.8}/pyproject.toml +4 -4
  3. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/account.py +5 -5
  4. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/calcs.py +25 -17
  5. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cli.py +20 -1
  6. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/balances_cmd.py +3 -3
  7. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/transfer_sol_cmd.py +16 -14
  8. mm_sol-0.2.8/src/mm_sol/cli/cmd/transfer_token_cmd.py +135 -0
  9. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/validators.py +6 -0
  10. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/token.py +3 -1
  11. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/test_account.py +4 -4
  12. {mm_sol-0.2.6 → mm_sol-0.2.8}/uv.lock +103 -27
  13. {mm_sol-0.2.6 → mm_sol-0.2.8}/.env.example +0 -0
  14. {mm_sol-0.2.6 → mm_sol-0.2.8}/.gitignore +0 -0
  15. {mm_sol-0.2.6 → mm_sol-0.2.8}/README.txt +0 -0
  16. {mm_sol-0.2.6 → mm_sol-0.2.8}/dict.dic +0 -0
  17. {mm_sol-0.2.6 → mm_sol-0.2.8}/justfile +0 -0
  18. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/__init__.py +0 -0
  19. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/balance.py +0 -0
  20. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/block.py +0 -0
  21. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/__init__.py +0 -0
  22. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cli_utils.py +0 -0
  23. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/__init__.py +0 -0
  24. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/balance_cmd.py +0 -0
  25. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/example_cmd.py +0 -0
  26. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/node_cmd.py +0 -0
  27. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/wallet/__init__.py +0 -0
  28. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/wallet/keypair_cmd.py +0 -0
  29. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/cmd/wallet/new_cmd.py +0 -0
  30. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/examples/balances.yml +0 -0
  31. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/cli/examples/transfer-sol.yml +0 -0
  32. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/converters.py +0 -0
  33. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/py.typed +0 -0
  34. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/rpc.py +0 -0
  35. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/solana_cli.py +0 -0
  36. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/transfer.py +0 -0
  37. {mm_sol-0.2.6 → mm_sol-0.2.8}/src/mm_sol/utils.py +0 -0
  38. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/__init__.py +0 -0
  39. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/cli/__init__.py +0 -0
  40. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/cli/cmd/__init__.py +0 -0
  41. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/cli/cmd/wallet/__init__.py +0 -0
  42. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/cli/cmd/wallet/test_keypair_cmd.py +0 -0
  43. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/cli/cmd/wallet/test_new_cmd.py +0 -0
  44. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/cli/test_calcs.py +0 -0
  45. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/conftest.py +0 -0
  46. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/test_balance.py +0 -0
  47. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/test_client.py +0 -0
  48. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/test_converters.py +0 -0
  49. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/test_rpc.py +0 -0
  50. {mm_sol-0.2.6 → mm_sol-0.2.8}/tests/test_token.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-sol
3
- Version: 0.2.6
4
- Requires-Python: >=3.13
3
+ Version: 0.2.8
4
+ Requires-Python: >=3.12
5
5
  Requires-Dist: base58~=2.1.1
6
6
  Requires-Dist: jinja2>=3.1.5
7
- Requires-Dist: mm-crypto-utils>=0.0.13
7
+ Requires-Dist: mm-crypto-utils>=0.0.15
8
8
  Requires-Dist: solana~=0.36.3
9
9
  Requires-Dist: typer>=0.15.1
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "mm-sol"
3
- version = "0.2.6"
3
+ version = "0.2.8"
4
4
  description = ""
5
- requires-python = ">=3.13"
5
+ requires-python = ">=3.12"
6
6
  dependencies = [
7
- "mm-crypto-utils>=0.0.13",
7
+ "mm-crypto-utils>=0.0.15",
8
8
  "solana~=0.36.3",
9
9
  "base58~=2.1.1",
10
10
  "typer>=0.15.1",
@@ -21,7 +21,7 @@ build-backend = "hatchling.build"
21
21
  dev-dependencies = [
22
22
  "pytest~=8.3.4",
23
23
  "pytest-xdist~=3.6.1",
24
- "ruff~=0.9.3",
24
+ "ruff~=0.9.4",
25
25
  "pip-audit~=2.7.3",
26
26
  "bandit~=1.8.2",
27
27
  "mypy~=1.14.1",
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import random
2
3
 
3
4
  import base58
@@ -84,9 +85,8 @@ def is_empty_account(*, address: str, node: str | None = None, nodes: list[str]
84
85
  return Err(error or "unknown response", data=data)
85
86
 
86
87
 
87
- def is_valid_pubkey(pubkey: str) -> bool:
88
- try:
88
+ def is_address(pubkey: str) -> bool:
89
+ with contextlib.suppress(Exception):
89
90
  Pubkey.from_string(pubkey)
90
- return True # noqa: TRY300
91
- except Exception:
92
- return False
91
+ return True
92
+ return False
@@ -4,10 +4,10 @@ from decimal import Decimal
4
4
  import mm_crypto_utils
5
5
  from loguru import logger
6
6
  from mm_crypto_utils import Nodes, Proxies
7
- from mm_std import Err
7
+ from mm_std import Ok, Result
8
8
  from mm_std.str import split_on_plus_minus_tokens
9
9
 
10
- from mm_sol.balance import get_sol_balance_with_retries
10
+ from mm_sol.balance import get_sol_balance_with_retries, get_token_balance_with_retries
11
11
  from mm_sol.converters import lamports_to_sol, sol_to_lamports, to_lamports
12
12
 
13
13
 
@@ -69,25 +69,33 @@ def is_sol_value_less_min_limit(value_min_limit: str | None, value: int, log_pre
69
69
  return False
70
70
 
71
71
 
72
- def calc_sol_value(
73
- *,
74
- nodes: Nodes,
75
- value_str: str,
76
- address: str,
77
- proxies: Proxies,
78
- fee: int = 5000,
79
- log_prefix: str | None = None,
80
- ) -> int | None:
72
+ def calc_sol_value(*, nodes: Nodes, value_str: str, address: str, proxies: Proxies, fee: int = 5000) -> Result[int]:
81
73
  balance_value = None
82
74
  if "balance" in value_str.lower():
83
- prefix = mm_crypto_utils.get_log_prefix(log_prefix)
84
75
  res = get_sol_balance_with_retries(nodes, address, proxies=proxies, retries=5)
85
- logger.debug(f"{prefix}balance={res.ok_or_err()}")
86
- if isinstance(res, Err):
87
- logger.info(f"{prefix}balance error, {res.err}")
88
- return None
76
+ if res.is_err():
77
+ return res
89
78
  balance_value = res.ok
90
79
  value = calc_var_value(value_str, var_name="balance", var_value=balance_value)
91
80
  if "balance" in value_str.lower():
92
81
  value = value - fee
93
- return value
82
+ return Ok(value)
83
+
84
+
85
+ def calc_token_value(
86
+ *, nodes: Nodes, value_str: str, wallet_address: str, token_mint_address: str, token_decimals: int, proxies: Proxies
87
+ ) -> Result[int]:
88
+ balance_value = None
89
+ if "balance" in value_str.lower():
90
+ res = get_token_balance_with_retries(
91
+ nodes=nodes,
92
+ owner_address=wallet_address,
93
+ token_mint_address=token_mint_address,
94
+ proxies=proxies,
95
+ retries=5,
96
+ )
97
+ if res.is_err():
98
+ return res
99
+ balance_value = res.ok
100
+ value = calc_var_value(value_str, var_name="balance", var_value=balance_value, decimals=token_decimals)
101
+ return Ok(value)
@@ -5,7 +5,7 @@ import typer
5
5
  from mm_std import print_plain
6
6
 
7
7
  from . import cli_utils
8
- from .cmd import balance_cmd, balances_cmd, example_cmd, node_cmd, transfer_sol_cmd
8
+ from .cmd import balance_cmd, balances_cmd, example_cmd, node_cmd, transfer_sol_cmd, transfer_token_cmd
9
9
  from .cmd.wallet import keypair_cmd, new_cmd
10
10
 
11
11
  app = typer.Typer(no_args_is_help=True, pretty_exceptions_enable=False, add_completion=False)
@@ -73,6 +73,25 @@ def transfer_sol_command(
73
73
  )
74
74
 
75
75
 
76
+ @app.command(name="transfer-token", help="Transfer token from one or many accounts")
77
+ def transfer_token_command(
78
+ config_path: str,
79
+ print_balances: bool = typer.Option(False, "--balances", "-b", help="Print balances and exit"),
80
+ print_config: bool = typer.Option(False, "--config", "-c", help="Print config and exit"),
81
+ emulate: bool = typer.Option(False, "--emulate", "-e", help="Emulate transaction posting"),
82
+ no_confirmation: bool = typer.Option(False, "--no-confirmation", "-nc", help="Do not wait for confirmation"),
83
+ debug: bool = typer.Option(False, "--debug", "-d", help="Print debug info"),
84
+ ) -> None:
85
+ transfer_token_cmd.run(
86
+ config_path,
87
+ print_balances=print_balances,
88
+ print_config=print_config,
89
+ debug=debug,
90
+ no_confirmation=no_confirmation,
91
+ emulate=emulate,
92
+ )
93
+
94
+
76
95
  @app.command(name="node", help="Check RPC urls")
77
96
  def node_command(
78
97
  urls: Annotated[list[str], typer.Argument()],
@@ -10,14 +10,14 @@ from pydantic import BeforeValidator, Field, model_validator
10
10
 
11
11
  import mm_sol.converters
12
12
  from mm_sol import balance
13
- from mm_sol.account import is_valid_pubkey
13
+ from mm_sol.account import is_address
14
14
  from mm_sol.balance import get_token_balance_with_retries
15
15
 
16
16
 
17
17
  class Config(BaseConfig):
18
- accounts: Annotated[list[str], BeforeValidator(ConfigValidators.addresses(unique=True, is_address=is_valid_pubkey))]
18
+ accounts: Annotated[list[str], BeforeValidator(ConfigValidators.addresses(unique=True, is_address=is_address))]
19
19
  nodes: Annotated[list[str], BeforeValidator(ConfigValidators.nodes())]
20
- tokens: Annotated[list[str], BeforeValidator(ConfigValidators.addresses(unique=True, is_address=is_valid_pubkey))]
20
+ tokens: Annotated[list[str], BeforeValidator(ConfigValidators.addresses(unique=True, is_address=is_address))]
21
21
  proxies_url: str | None = None
22
22
  proxies: list[str] = Field(default_factory=list)
23
23
 
@@ -6,25 +6,26 @@ from typing import Annotated, Self
6
6
 
7
7
  import mm_crypto_utils
8
8
  from loguru import logger
9
- from mm_crypto_utils import AddressToPrivate, ConfigValidators, TxRoute
9
+ from mm_crypto_utils import AddressToPrivate, TxRoute
10
10
  from mm_std import BaseConfig, Err, utc_now
11
11
  from pydantic import BeforeValidator, Field, model_validator
12
12
  from solders.signature import Signature
13
13
 
14
14
  from mm_sol import transfer
15
- from mm_sol.account import get_public_key, is_valid_pubkey
15
+ from mm_sol.account import get_public_key, is_address
16
16
  from mm_sol.cli import calcs, cli_utils, validators
17
+ from mm_sol.cli.validators import Validators
17
18
  from mm_sol.converters import lamports_to_sol
18
19
  from mm_sol.utils import get_client
19
20
 
20
21
 
21
22
  class Config(BaseConfig):
22
- nodes: Annotated[list[str], BeforeValidator(ConfigValidators.nodes())]
23
- routes: Annotated[list[TxRoute], BeforeValidator(ConfigValidators.routes(is_valid_pubkey))]
23
+ nodes: Annotated[list[str], BeforeValidator(Validators.nodes())]
24
+ routes: Annotated[list[TxRoute], BeforeValidator(Validators.routes(is_address))]
24
25
  routes_from_file: Path | None = None
25
26
  routes_to_file: Path | None = None
26
27
  private_keys: Annotated[
27
- AddressToPrivate, Field(default_factory=AddressToPrivate), BeforeValidator(ConfigValidators.private_keys(get_public_key))
28
+ AddressToPrivate, Field(default_factory=AddressToPrivate), BeforeValidator(Validators.private_keys(get_public_key))
28
29
  ]
29
30
  private_keys_file: Path | None = None
30
31
  proxies_url: str | None = None
@@ -33,8 +34,8 @@ class Config(BaseConfig):
33
34
  value_min_limit: str | None = None
34
35
  delay: str | None = None # in seconds
35
36
  round_ndigits: int = 5
36
- log_debug: Annotated[Path | None, BeforeValidator(ConfigValidators.log_file())] = None
37
- log_info: Annotated[Path | None, BeforeValidator(ConfigValidators.log_file())] = None
37
+ log_debug: Annotated[Path | None, BeforeValidator(Validators.log_file())] = None
38
+ log_info: Annotated[Path | None, BeforeValidator(Validators.log_file())] = None
38
39
 
39
40
  @property
40
41
  def from_addresses(self) -> list[str]:
@@ -44,7 +45,7 @@ class Config(BaseConfig):
44
45
  def final_validator(self) -> Self:
45
46
  # routes_files
46
47
  if self.routes_from_file and self.routes_to_file:
47
- self.routes += TxRoute.from_files(self.routes_from_file, self.routes_to_file, is_valid_pubkey)
48
+ self.routes += TxRoute.from_files(self.routes_from_file, self.routes_to_file, is_address)
48
49
  if not self.routes:
49
50
  raise ValueError("routes is empty")
50
51
 
@@ -101,9 +102,7 @@ def run(
101
102
 
102
103
  def _run_transfers(config: Config, *, no_confirmation: bool, emulate: bool) -> None:
103
104
  logger.info(f"started at {utc_now()} UTC")
104
- logger.debug(
105
- f"config={config.model_dump(exclude={'private_keys', 'addresses_map', 'proxies'}) | {'version': cli_utils.get_version()}}"
106
- )
105
+ logger.debug(f"config={config.model_dump(exclude={'private_keys'}) | {'version': cli_utils.get_version()}}")
107
106
  for i, route in enumerate(config.routes):
108
107
  _transfer(
109
108
  from_address=route.from_address,
@@ -123,11 +122,14 @@ def _transfer(*, from_address: str, to_address: str, config: Config, no_confirma
123
122
  log_prefix = f"{from_address}->{to_address}"
124
123
  fee = 5000
125
124
  # get value
126
- value = calcs.calc_sol_value(
127
- nodes=config.nodes, value_str=config.value, address=from_address, proxies=config.proxies, log_prefix=log_prefix, fee=fee
125
+ value_res = calcs.calc_sol_value(
126
+ nodes=config.nodes, value_str=config.value, address=from_address, proxies=config.proxies, fee=fee
128
127
  )
129
- if value is None:
128
+ logger.debug(f"{log_prefix}value={value_res.ok_or_err()}")
129
+ if isinstance(value_res, Err):
130
+ logger.info(f"{log_prefix}calc value error, {value_res.err}")
130
131
  return
132
+ value = value_res.ok
131
133
 
132
134
  # value_min_limit
133
135
  if calcs.is_sol_value_less_min_limit(config.value_min_limit, value, log_prefix=log_prefix):
@@ -0,0 +1,135 @@
1
+ import os
2
+ import sys
3
+ import time
4
+ from pathlib import Path
5
+ from typing import Annotated, Self
6
+
7
+ import mm_crypto_utils
8
+ import typer
9
+ from loguru import logger
10
+ from mm_crypto_utils import AddressToPrivate, TxRoute
11
+ from mm_std import BaseConfig, Err, fatal, utc_now
12
+ from pydantic import AfterValidator, BeforeValidator, Field, model_validator
13
+
14
+ from mm_sol.account import get_public_key, is_address
15
+ from mm_sol.cli import calcs, cli_utils
16
+ from mm_sol.cli.validators import Validators
17
+ from mm_sol.token import get_decimals_with_retries
18
+
19
+
20
+ class Config(BaseConfig):
21
+ nodes: Annotated[list[str], BeforeValidator(Validators.nodes())]
22
+ routes: Annotated[list[TxRoute], BeforeValidator(Validators.routes(is_address))]
23
+ routes_from_file: Path | None = None
24
+ routes_to_file: Path | None = None
25
+ private_keys: Annotated[
26
+ AddressToPrivate, Field(default_factory=AddressToPrivate), BeforeValidator(Validators.private_keys(get_public_key))
27
+ ]
28
+ private_keys_file: Path | None = None
29
+ proxies_url: str | None = None
30
+ proxies: list[str] = Field(default_factory=list)
31
+ token: Annotated[str, AfterValidator(Validators.address(is_address))]
32
+ value: str
33
+ value_min_limit: str | None = None
34
+ delay: str | None = None # in seconds
35
+ round_ndigits: int = 5
36
+ log_debug: Annotated[Path | None, BeforeValidator(Validators.log_file())] = None
37
+ log_info: Annotated[Path | None, BeforeValidator(Validators.log_file())] = None
38
+
39
+ @property
40
+ def from_addresses(self) -> list[str]:
41
+ return [r.from_address for r in self.routes]
42
+
43
+ @model_validator(mode="after")
44
+ def final_validator(self) -> Self:
45
+ # routes_files
46
+ if self.routes_from_file and self.routes_to_file:
47
+ self.routes += TxRoute.from_files(self.routes_from_file, self.routes_to_file, is_address)
48
+ if not self.routes:
49
+ raise ValueError("routes is empty")
50
+
51
+ # load private keys from file
52
+ if self.private_keys_file:
53
+ self.private_keys.update(AddressToPrivate.from_file(self.private_keys_file, get_public_key))
54
+
55
+ # check all private keys exist
56
+ if not self.private_keys.contains_all_addresses(self.from_addresses):
57
+ raise ValueError("private keys are not set for all addresses")
58
+
59
+ # fetch proxies from proxies_url
60
+ proxies_url = self.proxies_url or os.getenv("MM_PROXIES_URL", "")
61
+ if proxies_url:
62
+ self.proxies += mm_crypto_utils.fetch_proxies_or_fatal(proxies_url)
63
+
64
+ return self
65
+
66
+
67
+ def run(
68
+ config_path: str,
69
+ *,
70
+ print_balances: bool,
71
+ print_config: bool,
72
+ debug: bool,
73
+ no_confirmation: bool,
74
+ emulate: bool,
75
+ ) -> None:
76
+ config = Config.read_config_or_exit(config_path)
77
+
78
+ if print_config:
79
+ config.print_and_exit({"private_keys", "proxies"})
80
+
81
+ mm_crypto_utils.init_logger(debug, config.log_debug, config.log_info)
82
+
83
+ decimals_res = get_decimals_with_retries(config.nodes, config.token, retries=3, proxies=config.proxies)
84
+ if isinstance(decimals_res, Err):
85
+ fatal(f"can't get decimals for token={config.token}, error={decimals_res.err}")
86
+
87
+ token_decimals = decimals_res.ok
88
+ logger.debug(f"token decimals={token_decimals}")
89
+
90
+ if print_balances:
91
+ # cli_utils.print_balances(config.nodes, config.from_addresses, round_ndigits=config.round_ndigits, proxies=config.proxies) # noqa: E501
92
+ typer.echo("Not implemented yet")
93
+ sys.exit(0)
94
+
95
+ _run_transfers(config, token_decimals, no_confirmation=no_confirmation, emulate=emulate)
96
+
97
+
98
+ def _run_transfers(config: Config, token_decimals: int, *, no_confirmation: bool, emulate: bool) -> None:
99
+ logger.info(f"started at {utc_now()} UTC")
100
+ logger.debug(f"config={config.model_dump(exclude={'private_keys'}) | {'version': cli_utils.get_version()}}")
101
+ for i, route in enumerate(config.routes):
102
+ _transfer(
103
+ route=route,
104
+ token_decimals=token_decimals,
105
+ config=config,
106
+ no_confirmation=no_confirmation,
107
+ emulate=emulate,
108
+ )
109
+ if not emulate and config.delay is not None and i < len(config.routes) - 1:
110
+ delay_value = mm_crypto_utils.calc_decimal_value(config.delay)
111
+ logger.debug(f"delay {delay_value} seconds")
112
+ time.sleep(float(delay_value))
113
+ logger.info(f"finished at {utc_now()} UTC")
114
+
115
+
116
+ def _transfer(*, route: TxRoute, config: Config, token_decimals: int, no_confirmation: bool, emulate: bool) -> None:
117
+ log_prefix = f"{route.from_address}->{route.to_address}"
118
+ fee = 5000
119
+
120
+ # get value
121
+ value_res = calcs.calc_token_value(
122
+ nodes=config.nodes,
123
+ value_str=config.value,
124
+ wallet_address=route.from_address,
125
+ proxies=config.proxies,
126
+ token_mint_address=config.token,
127
+ token_decimals=token_decimals,
128
+ )
129
+ logger.debug(f"{log_prefix}: value={value_res.ok_or_err()}")
130
+ if isinstance(value_res, Err):
131
+ logger.info(f"{log_prefix}: calc value error, {value_res.err}")
132
+ return
133
+ value = value_res.ok
134
+
135
+ logger.debug(f"{log_prefix}: value={value}, fee={fee}, no_confirmation={no_confirmation}, emulate={emulate}")
@@ -1,3 +1,5 @@
1
+ from mm_crypto_utils import ConfigValidators
2
+
1
3
  from mm_sol.cli import calcs
2
4
 
3
5
 
@@ -9,3 +11,7 @@ def is_valid_var_lamports(value: str | None, base_name: str = "var", decimals: i
9
11
  return True # noqa: TRY300
10
12
  except ValueError:
11
13
  return False
14
+
15
+
16
+ class Validators(ConfigValidators):
17
+ pass
@@ -7,12 +7,14 @@ from mm_sol.utils import get_client
7
7
 
8
8
 
9
9
  def get_decimals(node: str, token_mint_address: str, timeout: float = 10, proxy: str | None = None) -> Result[int]:
10
+ data = None
10
11
  try:
11
12
  client = get_client(node, proxy=proxy, timeout=timeout)
12
13
  res = client.get_token_supply(Pubkey.from_string(token_mint_address))
14
+ data = res
13
15
  return Ok(res.value.decimals)
14
16
  except Exception as e:
15
- return Err(e)
17
+ return Err(e, data=data)
16
18
 
17
19
 
18
20
  def get_decimals_with_retries(
@@ -5,7 +5,7 @@ from mm_sol.account import (
5
5
  get_private_key_arr_str,
6
6
  get_private_key_base58,
7
7
  get_public_key,
8
- is_valid_pubkey,
8
+ is_address,
9
9
  )
10
10
 
11
11
 
@@ -124,6 +124,6 @@ def test_get_private_key_arr_str():
124
124
 
125
125
 
126
126
  def test_is_valid_pubkey():
127
- assert is_valid_pubkey("9nmjQrSpmf51BxcQu6spWD8w4jUzPVrtmtPbDGLyDuan")
128
- assert is_valid_pubkey("9nmjQrSpmf51BxcQu6spWD8w4jUzPVrtmtPbDGLyDuaN")
129
- assert not is_valid_pubkey("9nmjQrSpmf51BxcQu6spWD8w4jUzPVrtmtPbDGLyDuama")
127
+ assert is_address("9nmjQrSpmf51BxcQu6spWD8w4jUzPVrtmtPbDGLyDuan")
128
+ assert is_address("9nmjQrSpmf51BxcQu6spWD8w4jUzPVrtmtPbDGLyDuaN")
129
+ assert not is_address("9nmjQrSpmf51BxcQu6spWD8w4jUzPVrtmtPbDGLyDuama")
@@ -1,5 +1,5 @@
1
1
  version = 1
2
- requires-python = ">=3.13"
2
+ requires-python = ">=3.12"
3
3
 
4
4
  [[package]]
5
5
  name = "annotated-types"
@@ -92,6 +92,17 @@ dependencies = [
92
92
  ]
93
93
  sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 }
94
94
  wheels = [
95
+ { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 },
96
+ { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 },
97
+ { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 },
98
+ { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 },
99
+ { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 },
100
+ { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 },
101
+ { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 },
102
+ { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 },
103
+ { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 },
104
+ { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 },
105
+ { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 },
95
106
  { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 },
96
107
  { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 },
97
108
  { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 },
@@ -111,6 +122,21 @@ version = "3.4.0"
111
122
  source = { registry = "https://pypi.org/simple" }
112
123
  sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 }
113
124
  wheels = [
125
+ { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 },
126
+ { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 },
127
+ { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 },
128
+ { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 },
129
+ { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 },
130
+ { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 },
131
+ { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 },
132
+ { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 },
133
+ { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 },
134
+ { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 },
135
+ { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 },
136
+ { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 },
137
+ { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 },
138
+ { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 },
139
+ { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 },
114
140
  { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 },
115
141
  { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 },
116
142
  { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 },
@@ -412,6 +438,16 @@ version = "3.0.2"
412
438
  source = { registry = "https://pypi.org/simple" }
413
439
  sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 }
414
440
  wheels = [
441
+ { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 },
442
+ { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 },
443
+ { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 },
444
+ { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 },
445
+ { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 },
446
+ { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 },
447
+ { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 },
448
+ { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 },
449
+ { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 },
450
+ { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 },
415
451
  { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 },
416
452
  { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 },
417
453
  { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 },
@@ -445,19 +481,19 @@ wheels = [
445
481
 
446
482
  [[package]]
447
483
  name = "mm-crypto-utils"
448
- version = "0.0.13"
484
+ version = "0.0.15"
449
485
  source = { registry = "https://pypi.org/simple" }
450
486
  dependencies = [
451
487
  { name = "loguru" },
452
488
  { name = "mm-std" },
453
489
  ]
454
490
  wheels = [
455
- { url = "https://files.pythonhosted.org/packages/4a/70/5234ec9451f69d1299525193414d03200a8ec9b76c94e51fbad9ce394839/mm_crypto_utils-0.0.13-py3-none-any.whl", hash = "sha256:452b3c3fe0f3f6d8cd96a82437cfb4e97a0d5e4b7faa5faa796522e58736b69f", size = 6024 },
491
+ { url = "https://files.pythonhosted.org/packages/22/50/1bbb9d11d0f799b71ae2a1a6f2d3724288e3d3698f0de5832f8ac86db482/mm_crypto_utils-0.0.15-py3-none-any.whl", hash = "sha256:950f7c11e43c17e9de8574def0e1b5d0a2d21db6027a77c8bbd91bded1be43c7", size = 6121 },
456
492
  ]
457
493
 
458
494
  [[package]]
459
495
  name = "mm-sol"
460
- version = "0.2.6"
496
+ version = "0.2.8"
461
497
  source = { editable = "." }
462
498
  dependencies = [
463
499
  { name = "base58" },
@@ -482,7 +518,7 @@ dev = [
482
518
  requires-dist = [
483
519
  { name = "base58", specifier = "~=2.1.1" },
484
520
  { name = "jinja2", specifier = ">=3.1.5" },
485
- { name = "mm-crypto-utils", specifier = ">=0.0.13" },
521
+ { name = "mm-crypto-utils", specifier = ">=0.0.15" },
486
522
  { name = "solana", specifier = "~=0.36.3" },
487
523
  { name = "typer", specifier = ">=0.15.1" },
488
524
  ]
@@ -494,7 +530,7 @@ dev = [
494
530
  { name = "pip-audit", specifier = "~=2.7.3" },
495
531
  { name = "pytest", specifier = "~=8.3.4" },
496
532
  { name = "pytest-xdist", specifier = "~=3.6.1" },
497
- { name = "ruff", specifier = "~=0.9.3" },
533
+ { name = "ruff", specifier = "~=0.9.4" },
498
534
  { name = "types-pyyaml", specifier = "~=6.0.12.20241230" },
499
535
  ]
500
536
 
@@ -521,6 +557,17 @@ version = "1.1.0"
521
557
  source = { registry = "https://pypi.org/simple" }
522
558
  sdist = { url = "https://files.pythonhosted.org/packages/cb/d0/7555686ae7ff5731205df1012ede15dd9d927f6227ea151e901c7406af4f/msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e", size = 167260 }
523
559
  wheels = [
560
+ { url = "https://files.pythonhosted.org/packages/e1/d6/716b7ca1dbde63290d2973d22bbef1b5032ca634c3ff4384a958ec3f093a/msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d", size = 152421 },
561
+ { url = "https://files.pythonhosted.org/packages/70/da/5312b067f6773429cec2f8f08b021c06af416bba340c912c2ec778539ed6/msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2", size = 85277 },
562
+ { url = "https://files.pythonhosted.org/packages/28/51/da7f3ae4462e8bb98af0d5bdf2707f1b8c65a0d4f496e46b6afb06cbc286/msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420", size = 82222 },
563
+ { url = "https://files.pythonhosted.org/packages/33/af/dc95c4b2a49cff17ce47611ca9ba218198806cad7796c0b01d1e332c86bb/msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2", size = 392971 },
564
+ { url = "https://files.pythonhosted.org/packages/f1/54/65af8de681fa8255402c80eda2a501ba467921d5a7a028c9c22a2c2eedb5/msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39", size = 401403 },
565
+ { url = "https://files.pythonhosted.org/packages/97/8c/e333690777bd33919ab7024269dc3c41c76ef5137b211d776fbb404bfead/msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f", size = 385356 },
566
+ { url = "https://files.pythonhosted.org/packages/57/52/406795ba478dc1c890559dd4e89280fa86506608a28ccf3a72fbf45df9f5/msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247", size = 383028 },
567
+ { url = "https://files.pythonhosted.org/packages/e7/69/053b6549bf90a3acadcd8232eae03e2fefc87f066a5b9fbb37e2e608859f/msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c", size = 391100 },
568
+ { url = "https://files.pythonhosted.org/packages/23/f0/d4101d4da054f04274995ddc4086c2715d9b93111eb9ed49686c0f7ccc8a/msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", size = 394254 },
569
+ { url = "https://files.pythonhosted.org/packages/1c/12/cf07458f35d0d775ff3a2dc5559fa2e1fcd06c46f1ef510e594ebefdca01/msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b", size = 69085 },
570
+ { url = "https://files.pythonhosted.org/packages/73/80/2708a4641f7d553a63bc934a3eb7214806b5b39d200133ca7f7afb0a53e8/msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f", size = 75347 },
524
571
  { url = "https://files.pythonhosted.org/packages/c8/b0/380f5f639543a4ac413e969109978feb1f3c66e931068f91ab6ab0f8be00/msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf", size = 151142 },
525
572
  { url = "https://files.pythonhosted.org/packages/c8/ee/be57e9702400a6cb2606883d55b05784fada898dfc7fd12608ab1fdb054e/msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330", size = 84523 },
526
573
  { url = "https://files.pythonhosted.org/packages/7e/3a/2919f63acca3c119565449681ad08a2f84b2171ddfcff1dba6959db2cceb/msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734", size = 81556 },
@@ -544,6 +591,12 @@ dependencies = [
544
591
  ]
545
592
  sdist = { url = "https://files.pythonhosted.org/packages/b9/eb/2c92d8ea1e684440f54fa49ac5d9a5f19967b7b472a281f419e69a8d228e/mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6", size = 3216051 }
546
593
  wheels = [
594
+ { url = "https://files.pythonhosted.org/packages/43/1b/b38c079609bb4627905b74fc6a49849835acf68547ac33d8ceb707de5f52/mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14", size = 11266668 },
595
+ { url = "https://files.pythonhosted.org/packages/6b/75/2ed0d2964c1ffc9971c729f7a544e9cd34b2cdabbe2d11afd148d7838aa2/mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9", size = 10254060 },
596
+ { url = "https://files.pythonhosted.org/packages/a1/5f/7b8051552d4da3c51bbe8fcafffd76a6823779101a2b198d80886cd8f08e/mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11", size = 11933167 },
597
+ { url = "https://files.pythonhosted.org/packages/04/90/f53971d3ac39d8b68bbaab9a4c6c58c8caa4d5fd3d587d16f5927eeeabe1/mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e", size = 12864341 },
598
+ { url = "https://files.pythonhosted.org/packages/03/d2/8bc0aeaaf2e88c977db41583559319f1821c069e943ada2701e86d0430b7/mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89", size = 12972991 },
599
+ { url = "https://files.pythonhosted.org/packages/6f/17/07815114b903b49b0f2cf7499f1c130e5aa459411596668267535fe9243c/mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b", size = 9879016 },
547
600
  { url = "https://files.pythonhosted.org/packages/9e/15/bb6a686901f59222275ab228453de741185f9d54fecbaacec041679496c6/mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255", size = 11252097 },
548
601
  { url = "https://files.pythonhosted.org/packages/f8/b3/8b0f74dfd072c802b7fa368829defdf3ee1566ba74c32a2cb2403f68024c/mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34", size = 10239728 },
549
602
  { url = "https://files.pythonhosted.org/packages/c5/9b/4fd95ab20c52bb5b8c03cc49169be5905d931de17edfe4d9d2986800b52e/mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a", size = 11924965 },
@@ -696,6 +749,20 @@ dependencies = [
696
749
  ]
697
750
  sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 }
698
751
  wheels = [
752
+ { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 },
753
+ { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 },
754
+ { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 },
755
+ { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 },
756
+ { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 },
757
+ { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 },
758
+ { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 },
759
+ { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 },
760
+ { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 },
761
+ { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 },
762
+ { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 },
763
+ { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 },
764
+ { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 },
765
+ { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 },
699
766
  { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 },
700
767
  { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 },
701
768
  { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 },
@@ -785,6 +852,15 @@ version = "6.0.2"
785
852
  source = { registry = "https://pypi.org/simple" }
786
853
  sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 }
787
854
  wheels = [
855
+ { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 },
856
+ { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 },
857
+ { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 },
858
+ { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 },
859
+ { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 },
860
+ { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 },
861
+ { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 },
862
+ { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 },
863
+ { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 },
788
864
  { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 },
789
865
  { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 },
790
866
  { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 },
@@ -826,27 +902,27 @@ wheels = [
826
902
 
827
903
  [[package]]
828
904
  name = "ruff"
829
- version = "0.9.3"
830
- source = { registry = "https://pypi.org/simple" }
831
- sdist = { url = "https://files.pythonhosted.org/packages/1e/7f/60fda2eec81f23f8aa7cbbfdf6ec2ca11eb11c273827933fb2541c2ce9d8/ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a", size = 3586740 }
832
- wheels = [
833
- { url = "https://files.pythonhosted.org/packages/f9/77/4fb790596d5d52c87fd55b7160c557c400e90f6116a56d82d76e95d9374a/ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624", size = 11656815 },
834
- { url = "https://files.pythonhosted.org/packages/a2/a8/3338ecb97573eafe74505f28431df3842c1933c5f8eae615427c1de32858/ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c", size = 11594821 },
835
- { url = "https://files.pythonhosted.org/packages/8e/89/320223c3421962762531a6b2dd58579b858ca9916fb2674874df5e97d628/ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4", size = 11040475 },
836
- { url = "https://files.pythonhosted.org/packages/b2/bd/1d775eac5e51409535804a3a888a9623e87a8f4b53e2491580858a083692/ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439", size = 11856207 },
837
- { url = "https://files.pythonhosted.org/packages/7f/c6/3e14e09be29587393d188454064a4aa85174910d16644051a80444e4fd88/ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5", size = 11420460 },
838
- { url = "https://files.pythonhosted.org/packages/ef/42/b7ca38ffd568ae9b128a2fa76353e9a9a3c80ef19746408d4ce99217ecc1/ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4", size = 12605472 },
839
- { url = "https://files.pythonhosted.org/packages/a6/a1/3167023f23e3530fde899497ccfe239e4523854cb874458ac082992d206c/ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1", size = 13243123 },
840
- { url = "https://files.pythonhosted.org/packages/d0/b4/3c600758e320f5bf7de16858502e849f4216cb0151f819fa0d1154874802/ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5", size = 12744650 },
841
- { url = "https://files.pythonhosted.org/packages/be/38/266fbcbb3d0088862c9bafa8b1b99486691d2945a90b9a7316336a0d9a1b/ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4", size = 14458585 },
842
- { url = "https://files.pythonhosted.org/packages/63/a6/47fd0e96990ee9b7a4abda62de26d291bd3f7647218d05b7d6d38af47c30/ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6", size = 12419624 },
843
- { url = "https://files.pythonhosted.org/packages/84/5d/de0b7652e09f7dda49e1a3825a164a65f4998175b6486603c7601279baad/ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730", size = 11843238 },
844
- { url = "https://files.pythonhosted.org/packages/9e/be/3f341ceb1c62b565ec1fb6fd2139cc40b60ae6eff4b6fb8f94b1bb37c7a9/ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2", size = 11484012 },
845
- { url = "https://files.pythonhosted.org/packages/a3/c8/ff8acbd33addc7e797e702cf00bfde352ab469723720c5607b964491d5cf/ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519", size = 12038494 },
846
- { url = "https://files.pythonhosted.org/packages/73/b1/8d9a2c0efbbabe848b55f877bc10c5001a37ab10aca13c711431673414e5/ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b", size = 12473639 },
847
- { url = "https://files.pythonhosted.org/packages/cb/44/a673647105b1ba6da9824a928634fe23186ab19f9d526d7bdf278cd27bc3/ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c", size = 9834353 },
848
- { url = "https://files.pythonhosted.org/packages/c3/01/65cadb59bf8d4fbe33d1a750103e6883d9ef302f60c28b73b773092fbde5/ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4", size = 10821444 },
849
- { url = "https://files.pythonhosted.org/packages/69/cb/b3fe58a136a27d981911cba2f18e4b29f15010623b79f0f2510fd0d31fd3/ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b", size = 10038168 },
905
+ version = "0.9.4"
906
+ source = { registry = "https://pypi.org/simple" }
907
+ sdist = { url = "https://files.pythonhosted.org/packages/c0/17/529e78f49fc6f8076f50d985edd9a2cf011d1dbadb1cdeacc1d12afc1d26/ruff-0.9.4.tar.gz", hash = "sha256:6907ee3529244bb0ed066683e075f09285b38dd5b4039370df6ff06041ca19e7", size = 3599458 }
908
+ wheels = [
909
+ { url = "https://files.pythonhosted.org/packages/b6/f8/3fafb7804d82e0699a122101b5bee5f0d6e17c3a806dcbc527bb7d3f5b7a/ruff-0.9.4-py3-none-linux_armv6l.whl", hash = "sha256:64e73d25b954f71ff100bb70f39f1ee09e880728efb4250c632ceed4e4cdf706", size = 11668400 },
910
+ { url = "https://files.pythonhosted.org/packages/2e/a6/2efa772d335da48a70ab2c6bb41a096c8517ca43c086ea672d51079e3d1f/ruff-0.9.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6ce6743ed64d9afab4fafeaea70d3631b4d4b28b592db21a5c2d1f0ef52934bf", size = 11628395 },
911
+ { url = "https://files.pythonhosted.org/packages/dc/d7/cd822437561082f1c9d7225cc0d0fbb4bad117ad7ac3c41cd5d7f0fa948c/ruff-0.9.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:54499fb08408e32b57360f6f9de7157a5fec24ad79cb3f42ef2c3f3f728dfe2b", size = 11090052 },
912
+ { url = "https://files.pythonhosted.org/packages/9e/67/3660d58e893d470abb9a13f679223368ff1684a4ef40f254a0157f51b448/ruff-0.9.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37c892540108314a6f01f105040b5106aeb829fa5fb0561d2dcaf71485021137", size = 11882221 },
913
+ { url = "https://files.pythonhosted.org/packages/79/d1/757559995c8ba5f14dfec4459ef2dd3fcea82ac43bc4e7c7bf47484180c0/ruff-0.9.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de9edf2ce4b9ddf43fd93e20ef635a900e25f622f87ed6e3047a664d0e8f810e", size = 11424862 },
914
+ { url = "https://files.pythonhosted.org/packages/c0/96/7915a7c6877bb734caa6a2af424045baf6419f685632469643dbd8eb2958/ruff-0.9.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87c90c32357c74f11deb7fbb065126d91771b207bf9bfaaee01277ca59b574ec", size = 12626735 },
915
+ { url = "https://files.pythonhosted.org/packages/0e/cc/dadb9b35473d7cb17c7ffe4737b4377aeec519a446ee8514123ff4a26091/ruff-0.9.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56acd6c694da3695a7461cc55775f3a409c3815ac467279dfa126061d84b314b", size = 13255976 },
916
+ { url = "https://files.pythonhosted.org/packages/5f/c3/ad2dd59d3cabbc12df308cced780f9c14367f0321e7800ca0fe52849da4c/ruff-0.9.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0c93e7d47ed951b9394cf352d6695b31498e68fd5782d6cbc282425655f687a", size = 12752262 },
917
+ { url = "https://files.pythonhosted.org/packages/c7/17/5f1971e54bd71604da6788efd84d66d789362b1105e17e5ccc53bba0289b/ruff-0.9.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d4c8772670aecf037d1bf7a07c39106574d143b26cfe5ed1787d2f31e800214", size = 14401648 },
918
+ { url = "https://files.pythonhosted.org/packages/30/24/6200b13ea611b83260501b6955b764bb320e23b2b75884c60ee7d3f0b68e/ruff-0.9.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfc5f1d7afeda8d5d37660eeca6d389b142d7f2b5a1ab659d9214ebd0e025231", size = 12414702 },
919
+ { url = "https://files.pythonhosted.org/packages/34/cb/f5d50d0c4ecdcc7670e348bd0b11878154bc4617f3fdd1e8ad5297c0d0ba/ruff-0.9.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faa935fc00ae854d8b638c16a5f1ce881bc3f67446957dd6f2af440a5fc8526b", size = 11859608 },
920
+ { url = "https://files.pythonhosted.org/packages/d6/f4/9c8499ae8426da48363bbb78d081b817b0f64a9305f9b7f87eab2a8fb2c1/ruff-0.9.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a6c634fc6f5a0ceae1ab3e13c58183978185d131a29c425e4eaa9f40afe1e6d6", size = 11485702 },
921
+ { url = "https://files.pythonhosted.org/packages/18/59/30490e483e804ccaa8147dd78c52e44ff96e1c30b5a95d69a63163cdb15b/ruff-0.9.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:433dedf6ddfdec7f1ac7575ec1eb9844fa60c4c8c2f8887a070672b8d353d34c", size = 12067782 },
922
+ { url = "https://files.pythonhosted.org/packages/3d/8c/893fa9551760b2f8eb2a351b603e96f15af167ceaf27e27ad873570bc04c/ruff-0.9.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d612dbd0f3a919a8cc1d12037168bfa536862066808960e0cc901404b77968f0", size = 12483087 },
923
+ { url = "https://files.pythonhosted.org/packages/23/15/f6751c07c21ca10e3f4a51ea495ca975ad936d780c347d9808bcedbd7182/ruff-0.9.4-py3-none-win32.whl", hash = "sha256:db1192ddda2200671f9ef61d9597fcef89d934f5d1705e571a93a67fb13a4402", size = 9852302 },
924
+ { url = "https://files.pythonhosted.org/packages/12/41/2d2d2c6a72e62566f730e49254f602dfed23019c33b5b21ea8f8917315a1/ruff-0.9.4-py3-none-win_amd64.whl", hash = "sha256:05bebf4cdbe3ef75430d26c375773978950bbf4ee3c95ccb5448940dc092408e", size = 10850051 },
925
+ { url = "https://files.pythonhosted.org/packages/c6/e6/3d6ec3bc3d254e7f005c543a661a41c3e788976d0e52a1ada195bd664344/ruff-0.9.4-py3-none-win_arm64.whl", hash = "sha256:585792f1e81509e38ac5123492f8875fbc36f3ede8185af0a26df348e5154f41", size = 10078251 },
850
926
  ]
851
927
 
852
928
  [[package]]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes