mm-balance 0.1.7__py3-none-any.whl → 0.1.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mm_balance/balances.py CHANGED
@@ -4,9 +4,11 @@ from decimal import Decimal
4
4
 
5
5
  from mm_std import ConcurrentTasks, Result
6
6
  from pydantic import BaseModel
7
+ from rich.progress import Progress, TaskID
7
8
 
8
- from mm_balance import btc, eth, solana
9
+ from mm_balance import output
9
10
  from mm_balance.config import Config
11
+ from mm_balance.rpc import btc, eth, solana
10
12
  from mm_balance.types import Network
11
13
 
12
14
 
@@ -47,32 +49,37 @@ class Balances(BaseModel):
47
49
  return [b for b in network_balances if b.group_index == group_index]
48
50
 
49
51
  def process(self) -> None:
50
- job = ConcurrentTasks()
51
- job.add_task("btc", self._process_btc)
52
- job.add_task("eth", self._process_eth)
53
- job.add_task("sol", self._process_sol)
54
- job.execute()
52
+ progress = output.create_progress_bar()
53
+ task_btc = output.create_progress_task(progress, "btc", len(self.btc))
54
+ task_eth = output.create_progress_task(progress, "eth", len(self.eth))
55
+ task_sol = output.create_progress_task(progress, "sol", len(self.sol))
56
+ with progress:
57
+ job = ConcurrentTasks()
58
+ job.add_task("btc", self._process_btc, args=(progress, task_btc))
59
+ job.add_task("eth", self._process_eth, args=(progress, task_eth))
60
+ job.add_task("sol", self._process_sol, args=(progress, task_sol))
61
+ job.execute()
55
62
 
56
- def _process_btc(self) -> None:
63
+ def _process_btc(self, progress: Progress, task_id: TaskID) -> None:
57
64
  job = ConcurrentTasks(max_workers=self.config.workers.btc)
58
65
  for idx, task in enumerate(self.btc):
59
- job.add_task(str(idx), btc.get_balance, args=(task.address, self.config))
66
+ job.add_task(str(idx), btc.get_balance, args=(task.address, self.config, progress, task_id))
60
67
  job.execute()
61
68
  for idx, _task in enumerate(self.btc):
62
69
  self.btc[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
63
70
 
64
- def _process_eth(self) -> None:
71
+ def _process_eth(self, progress: Progress, task_id: TaskID) -> None:
65
72
  job = ConcurrentTasks(max_workers=self.config.workers.eth)
66
73
  for idx, task in enumerate(self.eth):
67
- job.add_task(str(idx), eth.get_balance, args=(task.address, task.token_address, self.config))
74
+ job.add_task(str(idx), eth.get_balance, args=(task.address, task.token_address, self.config, progress, task_id))
68
75
  job.execute()
69
76
  for idx, _task in enumerate(self.eth):
70
77
  self.eth[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
71
78
 
72
- def _process_sol(self) -> None:
79
+ def _process_sol(self, progress: Progress, task_id: TaskID) -> None:
73
80
  job = ConcurrentTasks(max_workers=self.config.workers.sol)
74
81
  for idx, task in enumerate(self.sol):
75
- job.add_task(str(idx), solana.get_balance, args=(task.address, self.config))
82
+ job.add_task(str(idx), solana.get_balance, args=(task.address, self.config, progress, task_id))
76
83
  job.execute()
77
84
  for idx, _task in enumerate(self.sol):
78
85
  self.sol[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
mm_balance/cli.py CHANGED
@@ -34,8 +34,8 @@ def cli(
34
34
  balances = Balances.from_config(config)
35
35
  balances.process()
36
36
 
37
- output.print_groups(balances, config, prices)
38
37
  output.print_prices(config, prices)
38
+ output.print_groups(balances, config, prices)
39
39
  output.print_total(config, balances, prices)
40
40
 
41
41
 
mm_balance/config.py CHANGED
@@ -98,7 +98,7 @@ class Config(BaseConfig):
98
98
  def sol_groups(self) -> list[Group]:
99
99
  return [g for g in self.groups if g.network == Network.SOL]
100
100
 
101
- def has_sum_share(self) -> bool:
101
+ def has_share(self) -> bool:
102
102
  return any(g.share != Decimal(1) for g in self.groups)
103
103
 
104
104
  @model_validator(mode="after")
@@ -122,7 +122,7 @@ class Config(BaseConfig):
122
122
  # load token decimals
123
123
  for group in self.groups:
124
124
  if group.network == Network.ETH and group.token_address is not None:
125
- from mm_balance import eth
125
+ from mm_balance.rpc import eth
126
126
 
127
127
  decimals_res = eth.get_token_decimals(group.token_address, self)
128
128
  if isinstance(decimals_res, Err):
mm_balance/output.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from decimal import Decimal
2
2
 
3
3
  from mm_std import Ok, print_table
4
+ from rich.progress import BarColumn, MofNCompleteColumn, Progress, TaskID, TextColumn
4
5
 
5
6
  from mm_balance.balances import Balances
6
7
  from mm_balance.config import Config
@@ -25,18 +26,18 @@ def _print_group(group: Config.Group, group_balances: list[Balances.Balance], co
25
26
  if config.price:
26
27
  balance_usd = round(address_task.balance.ok * prices[group.coin], config.round_ndigits)
27
28
  usd_sum += balance_usd
28
- row.append(balance_usd)
29
+ row.append(f"${balance_usd}")
29
30
  rows.append(row)
30
31
 
31
32
  sum_row = ["sum", round(balance_sum, config.round_ndigits)]
32
33
  if config.price:
33
- sum_row.append(round(usd_sum, config.round_ndigits))
34
+ sum_row.append(f"${round(usd_sum, config.round_ndigits)}")
34
35
  rows.append(sum_row)
35
36
 
36
37
  if group.share < Decimal(1):
37
38
  sum_share_row = [f"sum_share, {group.share}", round(balance_sum * group.share, config.round_ndigits)]
38
39
  if config.price:
39
- sum_share_row.append(round(usd_sum * group.share, config.round_ndigits))
40
+ sum_share_row.append(f"${round(usd_sum * group.share, config.round_ndigits)}")
40
41
  rows.append(sum_share_row)
41
42
 
42
43
  table_headers = ["address", "balance"]
@@ -48,9 +49,21 @@ def _print_group(group: Config.Group, group_balances: list[Balances.Balance], co
48
49
  def print_prices(config: Config, prices: Prices) -> None:
49
50
  if config.price:
50
51
  rows = [[k, round(v, config.round_ndigits)] for (k, v) in prices.items()]
51
- print_table("price", ["coin", "usd"], rows)
52
+ print_table("Prices", ["coin", "usd"], rows)
52
53
 
53
54
 
54
55
  def print_total(config: Config, balances: Balances, prices: Prices) -> None:
55
56
  total = Total.calc(balances, prices, config)
56
57
  total.print()
58
+
59
+
60
+ def create_progress_bar() -> Progress:
61
+ return Progress(
62
+ TextColumn("[progress.description]{task.description}"),
63
+ BarColumn(),
64
+ MofNCompleteColumn(),
65
+ )
66
+
67
+
68
+ def create_progress_task(progress: Progress, description: str, total: int) -> TaskID:
69
+ return progress.add_task("[green]" + description, total=total)
mm_balance/price.py CHANGED
@@ -5,6 +5,7 @@ import pydash
5
5
  from mm_std import Err, Ok, Result, fatal, hr
6
6
  from mm_std.random_ import random_str_choice
7
7
 
8
+ from mm_balance import output
8
9
  from mm_balance.config import Config
9
10
  from mm_balance.types import EthTokenAddress, Network
10
11
 
@@ -20,17 +21,25 @@ class Prices(dict[str, Decimal]):
20
21
 
21
22
  def get_prices(config: Config) -> Prices:
22
23
  result = Prices()
23
- for group in config.groups:
24
- if group.coin in result:
25
- continue
26
-
27
- coingecko_id = get_coingecko_id(group)
28
- res = get_asset_price(coingecko_id, config.proxies)
29
- if isinstance(res, Ok):
30
- result[group.coin] = res.ok
31
- else:
32
- fatal(res.err)
33
- # raise ValueError(res.err)
24
+ coins_total = len(pydash.uniq([group.coin for group in config.groups]))
25
+
26
+ progress = output.create_progress_bar()
27
+
28
+ with progress:
29
+ task_id = output.create_progress_task(progress, "prices", total=coins_total)
30
+
31
+ for group in config.groups:
32
+ if group.coin in result:
33
+ continue
34
+
35
+ coingecko_id = get_coingecko_id(group)
36
+ res = get_asset_price(coingecko_id, config.proxies)
37
+ if isinstance(res, Ok):
38
+ result[group.coin] = res.ok
39
+ progress.update(task_id, advance=1)
40
+ else:
41
+ fatal(res.err)
42
+ # raise ValueError(res.err)
34
43
 
35
44
  return result
36
45
 
File without changes
@@ -2,15 +2,19 @@ from decimal import Decimal
2
2
 
3
3
  from mm_btc.blockstream import BlockstreamClient
4
4
  from mm_std import Ok, Result
5
+ from rich.progress import Progress, TaskID
5
6
 
6
7
  from mm_balance.config import Config
7
8
 
8
9
 
9
- def get_balance(address: str, config: Config) -> Result[Decimal]:
10
- return (
10
+ def get_balance(address: str, config: Config, progress: Progress | None = None, task_id: TaskID | None = None) -> Result[Decimal]:
11
+ res: Result[Decimal] = (
11
12
  BlockstreamClient(proxies=config.proxies, attempts=3)
12
13
  .get_confirmed_balance(address)
13
14
  .and_then(
14
15
  lambda b: Ok(round(Decimal(b / 100_000_000), config.round_ndigits)),
15
16
  )
16
17
  )
18
+ if task_id is not None and progress is not None:
19
+ progress.update(task_id, advance=1)
20
+ return res
@@ -2,14 +2,19 @@ from decimal import Decimal
2
2
 
3
3
  from mm_eth import erc20, rpc
4
4
  from mm_std import Ok, Result
5
+ from rich.progress import Progress, TaskID
5
6
 
6
7
  from mm_balance.config import Config
7
8
  from mm_balance.types import Network
8
9
 
9
10
 
10
- def get_balance(address: str, token_address: str | None, config: Config) -> Result[Decimal]:
11
+ def get_balance(
12
+ address: str, token_address: str | None, config: Config, progress: Progress | None = None, task_id: TaskID | None = None
13
+ ) -> Result[Decimal]:
14
+ res: Result[Decimal]
15
+
11
16
  if token_address is not None:
12
- return erc20.get_balance(
17
+ res = erc20.get_balance(
13
18
  config.nodes[Network.ETH],
14
19
  token_address,
15
20
  address,
@@ -20,10 +25,14 @@ def get_balance(address: str, token_address: str | None, config: Config) -> Resu
20
25
  lambda b: Ok(round(Decimal(b / 10 ** config.token_decimals.eth[token_address]), config.round_ndigits)),
21
26
  )
22
27
  else:
23
- return rpc.eth_get_balance(config.nodes[Network.ETH], address, proxies=config.proxies, attempts=5, timeout=10).and_then(
28
+ res = rpc.eth_get_balance(config.nodes[Network.ETH], address, proxies=config.proxies, attempts=5, timeout=10).and_then(
24
29
  lambda b: Ok(round(Decimal(b / 10**18), config.round_ndigits)),
25
30
  )
26
31
 
32
+ if task_id is not None and progress is not None:
33
+ progress.update(task_id, advance=1)
34
+ return res
35
+
27
36
 
28
37
  def get_token_decimals(token_address: str, config: Config) -> Result[int]:
29
38
  return erc20.get_decimals(config.nodes[Network.ETH], token_address, timeout=10, proxies=config.proxies, attempts=5)
@@ -0,0 +1,19 @@
1
+ from decimal import Decimal
2
+
3
+ from mm_solana.balance import sol_balance
4
+ from mm_std import Ok, Result
5
+ from rich.progress import Progress, TaskID
6
+
7
+ from mm_balance.config import Config
8
+ from mm_balance.types import Network
9
+
10
+
11
+ def get_balance(address: str, config: Config, progress: Progress | None = None, task_id: TaskID | None = None) -> Result[Decimal]:
12
+ res: Result[Decimal] = sol_balance(
13
+ address=address, nodes=config.nodes[Network.SOL], proxies=config.proxies, attempts=5, timeout=10
14
+ ).and_then(
15
+ lambda b: Ok(round(Decimal(b / 1_000_000_000), config.round_ndigits)),
16
+ )
17
+ if task_id is not None and progress is not None:
18
+ progress.update(task_id, advance=1)
19
+ return res
mm_balance/total.py CHANGED
@@ -67,10 +67,14 @@ class Total:
67
67
  if self.config.print_format == PrintFormat.TABLE:
68
68
  if self.config.price:
69
69
  self._print_total_total_with_price()
70
- self._print_share_total_with_price()
70
+
71
+ if self.config.has_share():
72
+ self._print_share_total_with_price()
71
73
  else:
72
74
  self._print_total_total_without_price()
73
- self._print_share_total_without_price()
75
+
76
+ if self.config.has_share():
77
+ self._print_share_total_without_price()
74
78
 
75
79
  def _print_total_total_with_price(self) -> None:
76
80
  if self.config.print_format == PrintFormat.TABLE:
@@ -81,16 +85,16 @@ class Total:
81
85
  usd_share = round(self.stablecoin_sum * 100 / self.usd_sum, self.config.round_ndigits)
82
86
  else:
83
87
  usd_share = round(usd_value * 100 / self.usd_sum, self.config.round_ndigits)
84
- rows.append([key, value, usd_value, usd_share])
85
- rows.append(["usd_sum", self.usd_sum])
86
- print_table("total", ["coin", "balance", "usd", "usd_share"], rows)
88
+ rows.append([key, value, f"${usd_value}", f"{usd_share}%"])
89
+ rows.append(["usd_sum", f"${self.usd_sum}"])
90
+ print_table("Total", ["coin", "balance", "usd", "usd_share"], rows)
87
91
 
88
92
  def _print_total_total_without_price(self) -> None:
89
93
  if self.config.print_format == PrintFormat.TABLE:
90
94
  rows = []
91
95
  for key, value in self.coins.items():
92
96
  rows.append([key, value])
93
- print_table("total", ["coin", "balance"], rows)
97
+ print_table("Total", ["coin", "balance"], rows)
94
98
 
95
99
  def _print_share_total_with_price(self) -> None:
96
100
  rows = []
@@ -100,12 +104,12 @@ class Total:
100
104
  usd_share = round(self.stablecoin_sum_share * 100 / self.usd_sum_share, self.config.round_ndigits)
101
105
  else:
102
106
  usd_share = round(usd_value * 100 / self.usd_sum_share, self.config.round_ndigits)
103
- rows.append([key, self.coins_share[key], usd_value, usd_share])
104
- rows.append(["usd_sum", self.usd_sum_share])
105
- print_table("total / share", ["coin", "balance", "usd", "usd_share"], rows)
107
+ rows.append([key, self.coins_share[key], f"${usd_value}", f"{usd_share}%"])
108
+ rows.append(["usd_sum", f"${self.usd_sum_share}"])
109
+ print_table("Total, share", ["coin", "balance", "usd", "usd_share"], rows)
106
110
 
107
111
  def _print_share_total_without_price(self) -> None:
108
112
  rows = []
109
113
  for key, _ in self.coins.items():
110
114
  rows.append([key, self.coins_share[key]])
111
- print_table("total / share", ["coin", "balance"], rows)
115
+ print_table("Total, share", ["coin", "balance"], rows)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mm-balance
3
- Version: 0.1.7
3
+ Version: 0.1.9
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: mm-btc==0.1.0
6
6
  Requires-Dist: mm-eth==0.1.3
@@ -0,0 +1,17 @@
1
+ mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ mm_balance/balances.py,sha256=lagu1y8OosgOPnMnp7DpY1vZmaarQZZABvvM3fK8Zjw,4053
3
+ mm_balance/cli.py,sha256=VpiNJdwels7qWuklpV7kNEYm0lhsN4NJ7yENIsQLdK8,1250
4
+ mm_balance/config.py,sha256=WH1YjOJxofv2jgklupd7sCzgz2nZtHDYCYhoSaZTHl0,5918
5
+ mm_balance/output.py,sha256=Sb0pccEBNOCR9fuMigO9GJcyTNw9XPRZXTg8iznJKFQ,2568
6
+ mm_balance/price.py,sha256=KyMx1T57SczKbYmbghpGty9BrPebrZdjBW0_BaabKDk,2926
7
+ mm_balance/total.py,sha256=gdH9BzFgc-akVVrsCJ6NqN6cIS9mkEfp-TTKcn01I0U,4944
8
+ mm_balance/types.py,sha256=8TflwL3KJ8HQW31qa8xrh-gyJT232lN1XznuNnIR6zM,662
9
+ mm_balance/config/example.yml,sha256=6_S0hBdh7gMyO1ZPTGxmL21bBSzzmXuJHB0eWqKGueU,1225
10
+ mm_balance/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ mm_balance/rpc/btc.py,sha256=OozGSF8CzR13jxTYjvBqkC8d0pdKkyEHxM7e7M_WbV0,681
12
+ mm_balance/rpc/eth.py,sha256=yx31pwjvlu6MJUuWxtZtiK1vQvIkfMFwu5cNKaz1Yks,1317
13
+ mm_balance/rpc/solana.py,sha256=tL51r_T1hNUDSB8vdjp9QB4ToLjd6yRLXE1RW0-eauw,710
14
+ mm_balance-0.1.9.dist-info/METADATA,sha256=evs4MY6DDuZgIJKPbuVSqG87m7AguX5ExfdABT1gnk0,197
15
+ mm_balance-0.1.9.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
16
+ mm_balance-0.1.9.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
17
+ mm_balance-0.1.9.dist-info/RECORD,,
mm_balance/solana.py DELETED
@@ -1,13 +0,0 @@
1
- from decimal import Decimal
2
-
3
- from mm_solana.balance import sol_balance
4
- from mm_std import Ok, Result
5
-
6
- from mm_balance.config import Config
7
- from mm_balance.types import Network
8
-
9
-
10
- def get_balance(address: str, config: Config) -> Result[Decimal]:
11
- return sol_balance(address=address, nodes=config.nodes[Network.SOL], proxies=config.proxies, attempts=5, timeout=10).and_then(
12
- lambda b: Ok(round(Decimal(b / 1_000_000_000), config.round_ndigits)),
13
- )
@@ -1,16 +0,0 @@
1
- mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- mm_balance/balances.py,sha256=UGhJBecq-2CfNYdXE2EWjDcKkfPG30MERawOtWq5D5E,3399
3
- mm_balance/btc.py,sha256=h8hjcRk6BM0JwhAnB_V39wzeRO94s_hsOlzG7XpE9nk,445
4
- mm_balance/cli.py,sha256=GaxqhQ-uPguZRKieNGrIPoye8VZKAqg6-nbOExqtG9g,1250
5
- mm_balance/config.py,sha256=oeA5Oaru6pumzNws287dXvvj7CmOMQAjjqiRpYCb5PE,5918
6
- mm_balance/eth.py,sha256=wFpbqo4wHupTeMc9ybCPUkBBaJWxiWCBYJO3LvvU39s,1066
7
- mm_balance/output.py,sha256=j-kxENWcYEtv56UvEl_uKDF-92ALPZPJkvXqYmlBojs,2125
8
- mm_balance/price.py,sha256=xKwF0bWySfnryDYxsPTd2c8C82mrm1TXxIRzRmu_0MA,2577
9
- mm_balance/solana.py,sha256=tK1JHGo9ioIz-jXZ9pRDbACjQh_3vhgqFx1wZKVot6M,460
10
- mm_balance/total.py,sha256=RLwE_WrlO4TMftscoVuBHATmHXeV08IAukaU76wB75U,4812
11
- mm_balance/types.py,sha256=8TflwL3KJ8HQW31qa8xrh-gyJT232lN1XznuNnIR6zM,662
12
- mm_balance/config/example.yml,sha256=6_S0hBdh7gMyO1ZPTGxmL21bBSzzmXuJHB0eWqKGueU,1225
13
- mm_balance-0.1.7.dist-info/METADATA,sha256=WJLGieTEgyhR3azJl1ifA_hNdOuMnqGZSPAr3FoVlGM,197
14
- mm_balance-0.1.7.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
15
- mm_balance-0.1.7.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
16
- mm_balance-0.1.7.dist-info/RECORD,,