eth-portfolio-temp 0.0.35.dev0__cp310-cp310-win32.whl → 0.2.17__cp310-cp310-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. eth_portfolio/_argspec.cp310-win32.pyd +0 -0
  2. eth_portfolio/_cache.py +2 -2
  3. eth_portfolio/_config.cp310-win32.pyd +0 -0
  4. eth_portfolio/_db/utils.py +7 -9
  5. eth_portfolio/_decimal.py +11 -10
  6. eth_portfolio/_ledgers/address.py +1 -1
  7. eth_portfolio/_loaders/_nonce.cp310-win32.pyd +0 -0
  8. eth_portfolio/_loaders/_nonce.py +4 -4
  9. eth_portfolio/_loaders/balances.cp310-win32.pyd +0 -0
  10. eth_portfolio/_loaders/token_transfer.py +1 -1
  11. eth_portfolio/_loaders/transaction.py +1 -1
  12. eth_portfolio/_loaders/utils.cp310-win32.pyd +0 -0
  13. eth_portfolio/_loaders/utils.py +1 -1
  14. eth_portfolio/_shitcoins.cp310-win32.pyd +0 -0
  15. eth_portfolio/_shitcoins.py +54 -0
  16. eth_portfolio/_stableish.cp310-win32.pyd +0 -0
  17. eth_portfolio/_utils.py +12 -10
  18. eth_portfolio/_ydb/token_transfers.py +32 -23
  19. eth_portfolio/address.py +2 -1
  20. eth_portfolio/buckets.py +3 -3
  21. eth_portfolio/constants.cp310-win32.pyd +0 -0
  22. eth_portfolio/portfolio.py +1 -1
  23. eth_portfolio/protocols/lending/liquity.py +1 -1
  24. eth_portfolio/protocols/lending/maker.py +13 -14
  25. eth_portfolio/structs/structs.py +2 -2
  26. eth_portfolio/typing/__init__.py +6 -6
  27. eth_portfolio__mypyc.cp310-win32.pyd +0 -0
  28. eth_portfolio_scripts/_portfolio.py +54 -41
  29. eth_portfolio_scripts/_utils.py +20 -6
  30. eth_portfolio_scripts/balances.cp310-win32.pyd +0 -0
  31. eth_portfolio_scripts/balances.py +7 -4
  32. eth_portfolio_scripts/docker/__init__.cp310-win32.pyd +0 -0
  33. eth_portfolio_scripts/docker/check.cp310-win32.pyd +0 -0
  34. eth_portfolio_scripts/docker/check.py +28 -17
  35. eth_portfolio_scripts/docker/docker-compose.yaml +2 -2
  36. eth_portfolio_scripts/docker/docker_compose.cp310-win32.pyd +0 -0
  37. eth_portfolio_scripts/docker/docker_compose.py +38 -18
  38. eth_portfolio_scripts/main.py +6 -0
  39. eth_portfolio_scripts/victoria/__init__.py +3 -0
  40. {eth_portfolio_temp-0.0.35.dev0.dist-info → eth_portfolio_temp-0.2.17.dist-info}/METADATA +8 -7
  41. eth_portfolio_temp-0.2.17.dist-info/RECORD +83 -0
  42. {eth_portfolio_temp-0.0.35.dev0.dist-info → eth_portfolio_temp-0.2.17.dist-info}/top_level.txt +1 -1
  43. 295eace8438df6ec133b__mypyc.cp310-win32.pyd +0 -0
  44. eth_portfolio_temp-0.0.35.dev0.dist-info/RECORD +0 -83
  45. {eth_portfolio_temp-0.0.35.dev0.dist-info → eth_portfolio_temp-0.2.17.dist-info}/WHEEL +0 -0
  46. {eth_portfolio_temp-0.0.35.dev0.dist-info → eth_portfolio_temp-0.2.17.dist-info}/entry_points.txt +0 -0
@@ -80,7 +80,7 @@ class _LedgerEntryBase(DictStruct, kw_only=True, frozen=True, omit_defaults=True
80
80
  The USD value of the cryptocurrency transferred in the {cls_name}, if price is known.
81
81
  """
82
82
 
83
- def __init_subclass__(cls, **kwargs):
83
+ def __init_subclass__(cls, **kwargs: Any) -> None:
84
84
  super().__init_subclass__(**kwargs)
85
85
 
86
86
  # Replace {cls_name} in attribute-level docstrings
@@ -273,7 +273,7 @@ class _TransactionBase(
273
273
  return self.transaction.yParity
274
274
 
275
275
  @property
276
- def __db_primary_key__(self):
276
+ def __db_primary_key__(self) -> Dict[str, tuple[int, Address] | int]:
277
277
  return {"from_address": (chain.id, self.from_address), "nonce": self.nonce}
278
278
 
279
279
 
@@ -43,10 +43,10 @@ from typing import (
43
43
  )
44
44
 
45
45
  from checksum_dict import DefaultChecksumDict
46
- from eth_typing import BlockNumber
46
+ from eth_typing import BlockNumber, HexAddress
47
47
  from pandas import DataFrame, concat
48
48
  from typing_extensions import ParamSpec, Self
49
- from y import ERC20
49
+ from y import Contract, ERC20
50
50
  from y.datatypes import Address
51
51
 
52
52
  from eth_portfolio._decimal import Decimal
@@ -159,10 +159,10 @@ class TokenBalances(DefaultChecksumDict[Balance], _SummableNonNumericMixin): #
159
159
  raise
160
160
  self[token.address] += balance
161
161
 
162
- def __getitem__(self, key) -> Balance:
162
+ def __getitem__(self, key: HexAddress) -> Balance:
163
163
  return super().__getitem__(key) if key in self else Balance(token=key, block=self.block)
164
164
 
165
- def __setitem__(self, key, value):
165
+ def __setitem__(self, key: HexAddress, value: Balance) -> None:
166
166
  """
167
167
  Sets the balance for a given token address.
168
168
 
@@ -393,7 +393,7 @@ class RemoteTokenBalances(DefaultDict[ProtocolLabel, TokenBalances], _SummableNo
393
393
  )
394
394
  self[remote] += token_balances # type: ignore [has-type]
395
395
 
396
- def __setitem__(self, protocol: str, value: TokenBalances):
396
+ def __setitem__(self, protocol: str, value: TokenBalances) -> None:
397
397
  """
398
398
  Sets the token balances for a given protocol.
399
399
 
@@ -911,7 +911,7 @@ class PortfolioBalances(DefaultChecksumDict[WalletBalances], _SummableNonNumeric
911
911
  )
912
912
  self[wallet] += balances
913
913
 
914
- def __setitem__(self, key, value):
914
+ def __setitem__(self, key: HexAddress, value: WalletBalances) -> None:
915
915
  if not isinstance(value, WalletBalances):
916
916
  raise TypeError(
917
917
  f"value must be a `WalletBalances` object. You passed {value}"
Binary file
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  from datetime import datetime, timezone
2
3
  from logging import getLogger
3
4
  from math import floor
@@ -5,10 +6,11 @@ from typing import Awaitable, Callable, Final, Iterator, List, Optional, Tuple
5
6
 
6
7
  import a_sync
7
8
  import eth_retry
9
+ import y
8
10
  from a_sync.functools import cached_property_unsafe as cached_property
9
11
  from eth_typing import BlockNumber, ChecksumAddress
10
12
  from msgspec import ValidationError, json
11
- from y import ERC20, Network, NonStandardERC20, get_block_at_timestamp
13
+ from y import ERC20, Network, NonStandardERC20
12
14
  from y.constants import CHAINID
13
15
  from y.time import NoBlockFound
14
16
 
@@ -33,6 +35,19 @@ logger: Final = getLogger("eth_portfolio")
33
35
  log_debug: Final = logger.debug
34
36
  log_error: Final = logger.error
35
37
 
38
+ _block_at_timestamp_semaphore: Final = a_sync.Semaphore(
39
+ 50, name="eth-portfolio get_block_at_timestamp"
40
+ )
41
+
42
+
43
+ async def get_block_at_timestamp(dt: datetime) -> BlockNumber:
44
+ async with _block_at_timestamp_semaphore:
45
+ while True:
46
+ try:
47
+ return await y.get_block_at_timestamp(dt, sync=False)
48
+ except NoBlockFound:
49
+ await asyncio.sleep(10)
50
+
36
51
 
37
52
  class ExportablePortfolio(Portfolio):
38
53
  """Adds methods to export full portoflio data."""
@@ -40,8 +55,10 @@ class ExportablePortfolio(Portfolio):
40
55
  def __init__(
41
56
  self,
42
57
  addresses: Addresses,
58
+ *,
43
59
  start_block: int = 0,
44
60
  label: str = _DEFAULT_LABEL,
61
+ concurrency: int = 40,
45
62
  load_prices: bool = True,
46
63
  get_bucket: Callable[[ChecksumAddress], Awaitable[str]] = get_token_bucket,
47
64
  num_workers_transactions: int = 1000,
@@ -51,6 +68,7 @@ class ExportablePortfolio(Portfolio):
51
68
  addresses, start_block, label, load_prices, num_workers_transactions, asynchronous
52
69
  )
53
70
  self.get_bucket = get_bucket
71
+ self._semaphore = a_sync.Semaphore(concurrency)
54
72
 
55
73
  @cached_property
56
74
  def _data_queries(self) -> Tuple[str, str]:
@@ -71,53 +89,48 @@ class ExportablePortfolio(Portfolio):
71
89
  return True
72
90
  return False
73
91
 
74
- async def export_snapshot(self, dt: datetime):
92
+ async def export_snapshot(self, dt: datetime) -> None:
75
93
  log_debug("checking data at %s for %s", dt, self.label)
76
94
  try:
77
- if not await self.data_exists(dt, sync=False):
78
- while True:
79
- try:
80
- block = await get_block_at_timestamp(dt, sync=False)
81
- except NoBlockFound:
82
- pass
83
- else:
84
- break
85
- log_debug("block at %s: %s", dt, block)
86
- data = await self.get_data_for_export(block, dt, sync=False)
87
- await victoria.post_data(data)
95
+ if await self.data_exists(dt, sync=False):
96
+ return
97
+ block = await get_block_at_timestamp(dt)
98
+ log_debug("block at %s: %s", dt, block)
99
+ data = await self.get_data_for_export(block, dt, sync=False)
100
+ await victoria.post_data(data)
88
101
  except Exception as e:
89
102
  log_error("Error processing %s:", dt, exc_info=True)
90
103
 
91
- @a_sync.Semaphore(60)
92
104
  async def get_data_for_export(self, block: BlockNumber, ts: datetime) -> List[victoria.Metric]:
93
- print(f"exporting {ts} for {self.label}")
94
- start = datetime.now(tz=timezone.utc)
95
-
96
- metrics_to_export = []
97
- data: PortfolioBalances = await self.describe(block, sync=False)
98
-
99
- for wallet, wallet_data in dict.items(data):
100
- for section, section_data in wallet_data.items():
101
- if isinstance(section_data, TokenBalances):
102
- for token, bals in dict.items(section_data):
103
- metrics_to_export.extend(
104
- await self.__process_token(ts, section, wallet, token, bals)
105
- )
106
- elif isinstance(section_data, RemoteTokenBalances):
107
- if section == "external":
108
- section = "assets"
109
- for protocol, token_bals in section_data.items():
110
- for token, bals in dict.items(token_bals):
105
+ async with self._semaphore:
106
+ print(f"exporting {ts} for {self.label}")
107
+ start = datetime.now(tz=timezone.utc)
108
+
109
+ metrics_to_export = []
110
+ data: PortfolioBalances = await self.describe(block, sync=False)
111
+
112
+ for wallet, wallet_data in dict.items(data):
113
+ for section, section_data in wallet_data.items():
114
+ if isinstance(section_data, TokenBalances):
115
+ for token, bals in dict.items(section_data):
111
116
  metrics_to_export.extend(
112
- await self.__process_token(
113
- ts, section, wallet, token, bals, protocol=protocol
114
- )
117
+ await self.__process_token(ts, section, wallet, token, bals)
115
118
  )
116
- else:
117
- raise NotImplementedError()
119
+ elif isinstance(section_data, RemoteTokenBalances):
120
+ if section == "external":
121
+ section = "assets"
122
+ for protocol, token_bals in section_data.items():
123
+ for token, bals in dict.items(token_bals):
124
+ metrics_to_export.extend(
125
+ await self.__process_token(
126
+ ts, section, wallet, token, bals, protocol=protocol
127
+ )
128
+ )
129
+ else:
130
+ raise NotImplementedError()
118
131
 
119
- print(f"got data for {ts} in {datetime.now(tz=timezone.utc) - start}")
120
- return metrics_to_export
132
+ print(f"got data for {ts} in {datetime.now(tz=timezone.utc) - start}")
133
+ return metrics_to_export
121
134
 
122
135
  def __get_data_exists_coros(self, dt: datetime) -> Iterator[str]:
123
136
  for query in self._data_queries:
@@ -131,7 +144,7 @@ class ExportablePortfolio(Portfolio):
131
144
  token: ChecksumAddress,
132
145
  bal: Balance,
133
146
  protocol: Optional[str] = None,
134
- ):
147
+ ) -> Tuple[victoria.types.PrometheusItem, victoria.types.PrometheusItem]:
135
148
  # TODO wallet nicknames in grafana
136
149
  # wallet = KNOWN_ADDRESSES[wallet] if wallet in KNOWN_ADDRESSES else wallet
137
150
  if protocol is not None:
@@ -172,7 +185,7 @@ class ExportablePortfolio(Portfolio):
172
185
  )
173
186
 
174
187
 
175
- async def _get_symbol(token) -> str:
188
+ async def _get_symbol(token: str) -> str:
176
189
  if token == "ETH":
177
190
  return "ETH"
178
191
  try:
@@ -1,18 +1,18 @@
1
1
  import re
2
2
  from asyncio import Task, create_task, sleep
3
3
  from datetime import datetime, timedelta, timezone
4
- from typing import Any, AsyncGenerator, Dict, List, Optional
4
+ from typing import Any, AsyncGenerator, Dict, Final, List, Optional
5
5
 
6
6
  from brownie import chain
7
7
 
8
8
 
9
- def parse_timedelta(value: str) -> timedelta:
10
- regex = re.compile(r"(\d+)([dhms]?)")
11
- result = regex.findall(value)
9
+ timedelta_pattern: Final = re.compile(r"(\d+)([dhms]?)")
10
+
12
11
 
12
+ def parse_timedelta(value: str) -> timedelta:
13
13
  days, hours, minutes, seconds = 0, 0, 0, 0
14
14
 
15
- for val, unit in result:
15
+ for val, unit in timedelta_pattern.findall(value):
16
16
  val = int(val)
17
17
  if unit == "d":
18
18
  days = val
@@ -58,10 +58,24 @@ async def aiter_timestamps(
58
58
 
59
59
  timestamp = start
60
60
 
61
+ timestamps = []
61
62
  while timestamp <= datetime.now(tz=timezone.utc):
62
- yield timestamp
63
+ timestamps.append(timestamp)
63
64
  timestamp = timestamp + interval
64
65
 
66
+ # cycle between yielding earliest, latest, and middle from `timestamps` until complete
67
+ while timestamps:
68
+ # yield the earliest timestamp
69
+ yield timestamps.pop(0)
70
+ # yield the most recent timestamp if there is one
71
+ if timestamps:
72
+ yield timestamps.pop(-1)
73
+ # yield the most middle timestamp if there is one
74
+ if timestamps:
75
+ yield timestamps.pop(len(timestamps) // 2)
76
+
77
+ del timestamps
78
+
65
79
  while run_forever:
66
80
  while timestamp > datetime.now(tz=timezone.utc):
67
81
  await _get_waiter(timestamp)
@@ -26,13 +26,16 @@ async def export_balances(args: Namespace) -> None:
26
26
 
27
27
  interval = parse_timedelta(args.interval)
28
28
  portfolio = ExportablePortfolio(
29
- args.wallet, label=args.label, start_block=args.first_tx_block, load_prices=False
29
+ args.wallet,
30
+ label=args.label,
31
+ start_block=args.first_tx_block,
32
+ concurrency=args.concurrency,
33
+ load_prices=False,
30
34
  )
31
35
 
32
36
  if export_start_block := args.export_start_block or args.first_tx_block:
33
- start = datetime.fromtimestamp(
34
- await dank_mids.eth.get_block_timestamp(args.export_start_block), tz=timezone.utc
35
- )
37
+ start_ts = await dank_mids.eth.get_block_timestamp(export_start_block)
38
+ start = datetime.fromtimestamp(start_ts, tz=timezone.utc)
36
39
  else:
37
40
  start = None
38
41
 
@@ -1,5 +1,6 @@
1
1
  from functools import lru_cache
2
2
  from subprocess import CalledProcessError, check_output
3
+ from typing import List
3
4
 
4
5
 
5
6
  def check_docker() -> None:
@@ -9,48 +10,58 @@ def check_docker() -> None:
9
10
  Raises:
10
11
  RuntimeError: If docker is not installed.
11
12
  """
13
+ print(" 🔍 checking your computer for docker")
12
14
  try:
13
15
  check_output(["docker", "--version"])
14
- print("docker found!")
15
16
  except (CalledProcessError, FileNotFoundError):
16
- print("checking your computer for docker")
17
17
  raise RuntimeError(
18
18
  "Docker is not installed. You must install Docker before using dao-treasury."
19
19
  ) from None
20
+ else:
21
+ print(" ✔️ eth-portfolio found docker!")
20
22
 
21
23
 
22
- def check_docker_compose() -> None:
24
+ def check_docker_compose() -> List[str]:
23
25
  """
24
- Check that docker-compose is installed on the user's system.
26
+ Check that either `docker-compose` or `docker compose` is installed on the user's system.
27
+
28
+ Returns:
29
+ A valid compose command.
25
30
 
26
31
  Raises:
27
32
  RuntimeError: If docker-compose is not installed.
28
33
  """
29
- try:
30
- check_output(["docker-compose", "--version"])
31
- print("docker-compose found!")
32
- except (CalledProcessError, FileNotFoundError):
33
- print("checking your computer for docker-compose")
34
+ for cmd in ["docker-compose", "docker compose"]:
35
+ print(f" 🔍 checking your computer for {cmd}")
36
+
34
37
  try:
35
- check_output(["docker", "compose", "--version"])
36
- print("docker compose found!")
38
+ check_output([*cmd.split(" "), "--version"])
37
39
  except (CalledProcessError, FileNotFoundError):
38
- print("docker-compose not found, checking your computer for docker compose")
39
- raise RuntimeError(
40
- "Docker Compose is not installed. You must install Docker Compose before using dao-treasury."
41
- ) from None
40
+ print(f" ❌ {cmd} not found")
41
+ continue
42
+ else:
43
+ print(f" ✔️ eth-portfolio found {cmd}!")
44
+ return cmd.split(" ")
45
+
46
+ raise RuntimeError(
47
+ "Docker Compose is not installed. You must install Docker Compose before using dao-treasury."
48
+ ) from None
42
49
 
43
50
 
44
51
  @lru_cache(maxsize=None)
45
- def check_system() -> None:
52
+ def check_system() -> List[str]:
46
53
  """
47
54
  Check that docker and docker-compose is installed on the user's system.
48
55
 
56
+ Returns:
57
+ A valid compose command.
58
+
49
59
  Raises:
50
60
  RuntimeError: If docker-compose is not installed.
51
61
  """
62
+ print("eth-portfolio is checking for the required docker dependencies...")
52
63
  check_docker()
53
- check_docker_compose()
64
+ return check_docker_compose()
54
65
 
55
66
 
56
67
  __all__ = ["check_docker", "check_docker_compose", "check_system"]
@@ -3,7 +3,7 @@ networks:
3
3
 
4
4
  services:
5
5
  grafana:
6
- image: grafana/grafana:10.2.0
6
+ image: grafana/grafana:12.2.1
7
7
  ports:
8
8
  - 127.0.0.1:${GRAFANA_PORT:-3000}:3000
9
9
  environment:
@@ -47,7 +47,7 @@ services:
47
47
  restart: always
48
48
 
49
49
  victoria-metrics:
50
- image: victoriametrics/victoria-metrics:v1.81.1
50
+ image: victoriametrics/victoria-metrics:v1.129.1
51
51
  volumes:
52
52
  - ~/.eth-portfolio/data/victoria/:/victoria-metrics-data
53
53
  command:
@@ -3,7 +3,7 @@ from functools import wraps
3
3
  from importlib import resources
4
4
  from os import path
5
5
  from subprocess import CalledProcessError, check_output
6
- from typing import Callable, Final, Iterable, List, Tuple, TypeVar
6
+ from typing import Callable, Final, Iterable, List, Literal, Tuple, TypeVar
7
7
 
8
8
  from typing_extensions import ParamSpec
9
9
 
@@ -12,33 +12,33 @@ from eth_portfolio_scripts.docker.check import check_system
12
12
 
13
13
  logger: Final = logging.getLogger(__name__)
14
14
 
15
- compose_file: Final = str(
15
+ COMPOSE_FILE: Final = str(
16
16
  resources.files("eth_portfolio_scripts").joinpath("docker/docker-compose.yaml")
17
17
  )
18
18
 
19
19
 
20
20
  def up(*services: str) -> None:
21
+ """Build and start the specified docker-compose services."""
21
22
  build(*services)
22
- print("starting the infra containers...")
23
+ _print_notice("starting", services)
23
24
  _exec_command(["up", "-d", *services])
24
25
 
25
26
 
26
27
  def down() -> None:
28
+ """Stop all of eth-portfolio's docker-compose services."""
27
29
  _exec_command(["down"])
28
30
 
29
31
 
30
32
  def build(*services: str) -> None:
31
- print("building the grafana containers")
33
+ """Build the specified docker-compose services."""
34
+ _print_notice("building", services)
32
35
  _exec_command(["build", *services])
33
36
 
34
37
 
35
- def stop(container_name: str) -> None:
36
- """
37
- Stop the specified container if it is running.
38
- Defaults to stopping the 'renderer' container.
39
- """
40
- print(f"stopping the {container_name} container...")
41
- _exec_command(["stop", container_name])
38
+ def stop(*services: str) -> None:
39
+ """Stop the specified docker-compose services, if running."""
40
+ _print_notice("stopping", services)
41
+ _exec_command(["stop", *services])
42
42
 
43
43
 
44
44
  _P = ParamSpec("_P")
@@ -67,12 +67,32 @@ def ensure_containers(fn: Callable[_P, _T]) -> Callable[_P, _T]:
67
67
  return compose_wrap
68
68
 
69
69
 
70
- def _exec_command(command: List[str], *, compose_options: Tuple[str, ...] = ()) -> None:
71
- check_system()
70
+ def _print_notice(
71
+ doing: Literal["building", "starting", "stopping"],
72
+ services: Tuple[str, ...],
73
+ ) -> None:
74
+ if len(services) == 0:
75
+ print(f"{doing} the backend containers")
76
+ elif len(services) == 1:
77
+ container = services[0]
78
+ print(f"{doing} the {container} container")
79
+ elif len(services) == 2:
80
+ first, second = services
81
+ print(f"{doing} the {first} and {second} containers")
82
+ else:
83
+ *all_but_last, last = services
84
+ print(f"{doing} the {', '.join(all_but_last)}, and {last} containers")
85
+
86
+
87
+ def _exec_command(
88
+ command: List[str],
89
+ *,
90
+ compose_file: str = COMPOSE_FILE,
91
+ compose_options: Tuple[str, ...] = (),
92
+ ) -> None:
93
+ compose = check_system()
94
+ full_command = [*compose, *compose_options, "-f", compose_file, *command]
72
95
  try:
73
- check_output(["docker", "compose", *compose_options, "-f", compose_file, *command])
96
+ check_output(full_command)
74
97
  except (CalledProcessError, FileNotFoundError) as e:
75
- try:
76
- check_output(["docker-compose", *compose_options, "-f", compose_file, *command])
77
- except (CalledProcessError, FileNotFoundError) as _e:
78
- raise RuntimeError(f"Error occurred while running {' '.join(command)}: {_e}") from _e
98
+ raise RuntimeError(f"Error occurred while running `{' '.join(full_command)}`: {e}") from e
@@ -54,6 +54,12 @@ export_parser.add_argument(
54
54
  help="The time interval between datapoints. default: 6h",
55
55
  default="6h",
56
56
  )
57
+ export_parser.add_argument(
58
+ "--concurrency",
59
+ type=int,
60
+ help="The max number of historical blocks to export concurrently. default: 40",
61
+ default=40,
62
+ )
57
63
  export_parser.add_argument(
58
64
  "--first-tx-block",
59
65
  type=int,
@@ -68,3 +68,6 @@ async def post_data(metrics_to_export: List["Metric"]) -> None:
68
68
  def __set_session(sesh: ClientSession) -> None:
69
69
  global session
70
70
  session = sesh
71
+
72
+
73
+ __all__ = ["Metric", "get", "post_data"]
@@ -1,22 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eth_portfolio_temp
3
- Version: 0.0.35.dev0
3
+ Version: 0.2.17
4
4
  Summary: eth-portfolio makes it easy to analyze your portfolio.
5
5
  Home-page: https://github.com/BobTheBuidler/eth-portfolio
6
6
  Author: BobTheBuidler
7
7
  Author-email: bobthebuidlerdefi@gmail.com
8
- Requires-Python: >=3.9,<3.13
8
+ Requires-Python: >=3.10,<3.14
9
9
  Requires-Dist: checksum_dict>=2.1.7
10
10
  Requires-Dist: dank_mids>=4.20.154
11
- Requires-Dist: eth-brownie<1.22,>=1.21.0
11
+ Requires-Dist: eth-brownie<1.23,>=1.22.0.dev0
12
12
  Requires-Dist: eth_retry<1,>=0.3.4
13
13
  Requires-Dist: evmspec>=0.4.1
14
- Requires-Dist: ez-a-sync>=0.32.7
14
+ Requires-Dist: ez-a-sync>=0.32.27
15
+ Requires-Dist: faster-async-lru==2.0.5
15
16
  Requires-Dist: faster-eth-utils
16
- Requires-Dist: numpy<2
17
- Requires-Dist: pandas<1.6,>=1.4.3
17
+ Requires-Dist: numpy<3
18
+ Requires-Dist: pandas<3,>=1.4.3
18
19
  Requires-Dist: typed-envs>=0.0.9
19
- Requires-Dist: ypricemagic<5,>=4.6.11
20
+ Requires-Dist: ypricemagic<5,>=4.10.0
20
21
  Dynamic: author
21
22
  Dynamic: author-email
22
23
  Dynamic: home-page
@@ -0,0 +1,83 @@
1
+ eth_portfolio__mypyc.cp310-win32.pyd,sha256=vP2Arva-HjNQSr81H1atzjRWgnVVxEDZCSyiHycgqVE,234496
2
+ eth_portfolio/__init__.py,sha256=5GmHYzhUX2gOC4MScgXnqS8x2MawbpWOuWPmqlvCotA,525
3
+ eth_portfolio/_argspec.cp310-win32.pyd,sha256=DVYWzMUU3yeWYrnkKH2RgGfTuP1IYtvNSRTr6aESYzM,9216
4
+ eth_portfolio/_argspec.py,sha256=au8ycJ56-7UzbQVzYUOoMX9sToH0QNi2tS1O820xB3A,1637
5
+ eth_portfolio/_cache.py,sha256=OntwbiDOrBV5JzHHDzJlxcEVrmKK5GG0uXeLeoDDbpA,4926
6
+ eth_portfolio/_config.cp310-win32.pyd,sha256=dLCBGs3KBzk1g4R1bumN2aUR78N7GAdm1AAVPeKGK58,9216
7
+ eth_portfolio/_config.py,sha256=BSOvFS4D0oqgVTtBbtW2g2kpL8Mk6xiP0PipfXs_91A,102
8
+ eth_portfolio/_decimal.py,sha256=DwLUg8pzeTIREG2sHgRK48hoWmjelWNvpEKj10Ra7to,5002
9
+ eth_portfolio/_decorators.py,sha256=AvB-q69MvaFe0Ykh1os6hSewcUujURQ9onqobMaONOM,2899
10
+ eth_portfolio/_exceptions.py,sha256=xb5VmCtBtXy9WXu_1ofoG4j9BJsMQXMVydCJNUulrNY,2500
11
+ eth_portfolio/_shitcoins.cp310-win32.pyd,sha256=3Jkmma44-1z8R7TXAIYIUpT_Y3O3ubeczHCV5S-GMAk,9216
12
+ eth_portfolio/_shitcoins.py,sha256=9i7tcwZN620oQkDBa_gSE4jqZn0TK52AyqZh0MIP8m4,17351
13
+ eth_portfolio/_stableish.cp310-win32.pyd,sha256=gaC_d2KsAb7TzSxcvPnsLBaxe6cuUnxtzJ3RVHZeQqU,9216
14
+ eth_portfolio/_stableish.py,sha256=8pdlYe2YcZ8rTzdCzg-ihRQLPtSFXBNDjtnvuTgPRcQ,2063
15
+ eth_portfolio/_submodules.py,sha256=zne-2YyVFoKHwkLuHx8cdz5lpcwwSDw1edJ9v8G4c1A,2263
16
+ eth_portfolio/_utils.py,sha256=iGck5SKUwpfnuZvLnKDR1A00obZNKx622Y9GY_TYiZA,7886
17
+ eth_portfolio/address.py,sha256=RrFIWSx6jSITwh16Hqs6W6S9fz1KEaebQEk1vqL3HwI,14536
18
+ eth_portfolio/buckets.py,sha256=c5_RLfMyJbnK_PBx5mmdL3YlIX67dD6LqnBxiAr52N0,6896
19
+ eth_portfolio/constants.cp310-win32.pyd,sha256=Kf84IQgSHghjvWveM0IkKaSkwC-mFYEJMgKt6l5hpGM,9216
20
+ eth_portfolio/constants.py,sha256=rUXWFaCGrrF_qzIdDvVzakQJsLnrGtFNn2EgRbZh8fQ,3741
21
+ eth_portfolio/portfolio.py,sha256=FSJ1_FG120dN5vWSPyhbHfyuFHdmFqTHJ5_Ci-4Rts4,24909
22
+ eth_portfolio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ eth_portfolio/_db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ eth_portfolio/_db/decorators.py,sha256=RS-RiuOAgbrMKQpCwwAtP3lPRs8vKM6aPhh9LP4SwtI,5308
25
+ eth_portfolio/_db/entities.py,sha256=1Z1AsR400SJYzDrDGxUJt1HuSKB3ErvxIytFtju7UHU,10345
26
+ eth_portfolio/_db/utils.py,sha256=3P4EVQ5cHLbDrAnBESAIKhoDpJLXLS8IDJNnsh7T2Sc,21586
27
+ eth_portfolio/_ledgers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ eth_portfolio/_ledgers/address.py,sha256=wght92UXf6UIO9GNRzdMy3H43Em7kUk9ArtBsRF-xjw,33830
29
+ eth_portfolio/_ledgers/portfolio.py,sha256=rAr5S1tksgLPUOK1J1FbIWgvTQNzTqrRp8oukiP2BTo,13427
30
+ eth_portfolio/_loaders/__init__.py,sha256=YrBeRuA48cN2Bg2R2nXiNt1CsUIG_7N6ENIpY6aISPo,1735
31
+ eth_portfolio/_loaders/_nonce.cp310-win32.pyd,sha256=uhgNAicfH2hN6cV2wXdeF3bfFdqmoKLDHodQmeF3NDI,9216
32
+ eth_portfolio/_loaders/_nonce.py,sha256=bA-5fZG8ALuADgQGrnoxt6p6j7QEwI6vIGnZRF1Zx7M,6481
33
+ eth_portfolio/_loaders/balances.cp310-win32.pyd,sha256=AfhH5TxDCPmTZ1iHcgfmrev-lhhjd3WBSdVnvvaDWzs,9216
34
+ eth_portfolio/_loaders/balances.py,sha256=_v-x1M3lzDHPt8svHmCcpxZKw0BaGHfZimhkwgphY8A,3226
35
+ eth_portfolio/_loaders/token_transfer.py,sha256=itaWVDyotG0EYPb4o94UOpxYvTdE6YIuUR2pzpXAnwI,8748
36
+ eth_portfolio/_loaders/transaction.py,sha256=oOG3cFdLAa10k2hpN17GO7Wtq-rpUJ1oo7hLAKDjbDc,9393
37
+ eth_portfolio/_loaders/utils.cp310-win32.pyd,sha256=4jp-6fhYJAYtjAJGdJ2EuBx8CMmdoYo6URuxNb5lZmA,9216
38
+ eth_portfolio/_loaders/utils.py,sha256=gJvIikinjCPj-elQVep55VTya9slSARApx-FJKYwnkE,2333
39
+ eth_portfolio/_ydb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ eth_portfolio/_ydb/token_transfers.py,sha256=HUTeWShcQD4IzocTHmBOreml0jbVttLcaed1fNiJ2qg,5297
41
+ eth_portfolio/protocols/__init__.py,sha256=k1e4MI8KPALIg7awaVA9LbBuEjqxWZF7uGgxysQ4y90,2623
42
+ eth_portfolio/protocols/_base.py,sha256=nuMnnltg4HZ0Z5Nl83ofwAsTE3A9jLYhDZFkRhAKIIY,3793
43
+ eth_portfolio/protocols/convex.py,sha256=az8FhxLtXf0WKo25Ke0IDRGF8x1yMlffoCRz9aG2fGE,535
44
+ eth_portfolio/protocols/dsr.py,sha256=jn_4niDINXQxqu9Tfb77vsfbhv4oIRRFKsKvnMgEO4I,1806
45
+ eth_portfolio/protocols/liquity.py,sha256=Ptiem5zd1op6qmZj2d6PmcgSqrKCLhlTw3CmIwII1Dc,656
46
+ eth_portfolio/protocols/lending/README.md,sha256=0C941RnyfQwT1DE9bvxwLP-gBTHlQcQysF-75FXHINo,498
47
+ eth_portfolio/protocols/lending/__init__.py,sha256=4jKDPx3sb7Iyi9kOdJRpM6LJy_GhUpviLIbpV_6noYU,1693
48
+ eth_portfolio/protocols/lending/_base.py,sha256=_1zXroYHlliLP685xiRfw8I_tQOoZyaPlnxA_gzLytU,2311
49
+ eth_portfolio/protocols/lending/compound.py,sha256=1aoksFSvIIsk-cNDs2-Kdwl-RtIdTzh3QgpksXG1kEs,7439
50
+ eth_portfolio/protocols/lending/liquity.py,sha256=bJ5TKD-WTVn3S1tlbSGGVFCoKFvgStHVOzKBM2LbsRY,4294
51
+ eth_portfolio/protocols/lending/maker.py,sha256=zqi1E5yQ_QDFOk5OMR4gB5_Ag74RMIkp6u3TyX-P3fg,4073
52
+ eth_portfolio/protocols/lending/unit.py,sha256=OQGDZWdsTOUL4jOKJ1xef6wXhWLHnsRFJjAzn0XSBmM,2011
53
+ eth_portfolio/structs/__init__.py,sha256=x-9CdKe8XMukp8Kjr_lD49ohrSd0iGEvvsMAHtAPrLI,1486
54
+ eth_portfolio/structs/modified.py,sha256=QIuFh-u5VTHe0oborn3oHAiAGD0wqhUQW7XFJVZu2KI,1853
55
+ eth_portfolio/structs/structs.py,sha256=TDJ4u3E_H8uG7iX-C1Pux8TesY2zXRhQUJxmN7cp4cc,20490
56
+ eth_portfolio/typing/__init__.py,sha256=v_KbOgqTKcR4y-05Bel_mg6uAV-IsGurGR-jDW46SMg,58763
57
+ eth_portfolio/typing/balance/single.py,sha256=NmtWXqCWMIkaoyvfL67Rh0wWurLf55fVaDkyUxZ27oY,6501
58
+ eth_portfolio_scripts/__init__.py,sha256=DIBnQmjmhmNL1lO9Lq4QptrZmC7u6_N3p9zRjcZ9vbY,281
59
+ eth_portfolio_scripts/_args.py,sha256=M33vPkja62XEJeCZAqacNSBCqbzse07wepwyBOtkvVo,682
60
+ eth_portfolio_scripts/_logging.py,sha256=EgW8ozQZLAgt_cUgqe5BYZLMVQwB6X-0gq0T-BvqlTY,369
61
+ eth_portfolio_scripts/_portfolio.py,sha256=XP6fUfZfv2hBdW6PCBdpUyT3TRAU56u2QKWwhmHBTAE,7333
62
+ eth_portfolio_scripts/_utils.py,sha256=lj2B79G8YX21ATNp_v-onsU_kNFZF3unBclCVp3AIn8,3163
63
+ eth_portfolio_scripts/balances.cp310-win32.pyd,sha256=xeyimxldnzXayhj8VCJtg1shpA7CEGa3d2-d9Dg822A,9216
64
+ eth_portfolio_scripts/balances.py,sha256=Fr8NGCt5yhvu7LnLH27oOVKcL2XwowmAVezXUOIEzd0,1640
65
+ eth_portfolio_scripts/main.py,sha256=VfwWEVOu4oxp5M-rQLGo-XlDKlG_Q7Y4cLiXMUSXeZg,3804
66
+ eth_portfolio_scripts/py.typed,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
67
+ eth_portfolio_scripts/docker/__init__.cp310-win32.pyd,sha256=PbG45wiTNsF4eXS_1d9LtzdSDTR4QRvLRUTCs7HNJqo,9216
68
+ eth_portfolio_scripts/docker/__init__.py,sha256=R27uZPLUEK2--fb9IrxrDUk6R5_IVFJSv7s_ia7p5Xk,409
69
+ eth_portfolio_scripts/docker/check.cp310-win32.pyd,sha256=O626VmwWbI4iet7RK870vIkpNMbcbTDZ27zCMLSPpSs,9216
70
+ eth_portfolio_scripts/docker/check.py,sha256=mf853kj0_M2iI3d2KuWuwsXtSieP9qWhvTJdrqX8iU8,1997
71
+ eth_portfolio_scripts/docker/docker-compose.yaml,sha256=lCLNTFUYGty_ogZPrhiQMh-lHiw25hrhWXr7T7jyss4,1870
72
+ eth_portfolio_scripts/docker/docker_compose.cp310-win32.pyd,sha256=wvBdvtWvQcljKJYYKHXV-oxbttL5Tqeq2Un6Az14SgA,9216
73
+ eth_portfolio_scripts/docker/docker_compose.py,sha256=w1Z4XfSCC1vVLnss74XbkHUBVb0P2-zOIkMyidkZh38,2903
74
+ eth_portfolio_scripts/docker/.grafana/dashboards/dashboards.yaml,sha256=wktTI-OAdF_khhbciZFo4Gt2V9bUjbe7GLqwdzTKf0U,212
75
+ eth_portfolio_scripts/docker/.grafana/dashboards/Portfolio/Balances.json,sha256=XGMV8e4tDak53e9bmymwAB4uqZmAIcU5JlRT3OiwTeU,70750
76
+ eth_portfolio_scripts/docker/.grafana/datasources/datasources.yml,sha256=8PPH_QDhfbRRh3IidskW46rifJejloa1a9I1KCw2FTk,199
77
+ eth_portfolio_scripts/victoria/__init__.py,sha256=R0VvKiAC0e57zZNihcCptVkFO5CBHIbp2trFYuyY01M,2038
78
+ eth_portfolio_scripts/victoria/types.py,sha256=KNq8aIiNXeiDnCKL7xycmouo0YeKI-sbQkIcTymcSYk,745
79
+ eth_portfolio_temp-0.2.17.dist-info/METADATA,sha256=vZtFUNdKJF5u14oqr0klpNn_ik07bpj1J3jhovPi2Mw,840
80
+ eth_portfolio_temp-0.2.17.dist-info/WHEEL,sha256=GWZF0cboiU4MhsG0baPl8rrtCaXFSLW25384gp3vddM,97
81
+ eth_portfolio_temp-0.2.17.dist-info/entry_points.txt,sha256=yqoC6X3LU1NA_-oJ6mloEYEPNmS-0hPS9OtEwgIeDGU,66
82
+ eth_portfolio_temp-0.2.17.dist-info/top_level.txt,sha256=4MlbY-Yj8oGBGL8piXiO4SOpk2gZFF9ZXVTObTZOzqM,57
83
+ eth_portfolio_temp-0.2.17.dist-info/RECORD,,
@@ -1,3 +1,3 @@
1
- 295eace8438df6ec133b__mypyc
2
1
  eth_portfolio
2
+ eth_portfolio__mypyc
3
3
  eth_portfolio_scripts
Binary file