fin-infra 0.1.66__py3-none-any.whl → 0.1.68__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.
Files changed (50) hide show
  1. fin_infra/analytics/add.py +9 -11
  2. fin_infra/analytics/portfolio.py +12 -18
  3. fin_infra/analytics/rebalancing.py +2 -4
  4. fin_infra/analytics/savings.py +1 -1
  5. fin_infra/analytics/spending.py +3 -1
  6. fin_infra/banking/history.py +3 -3
  7. fin_infra/banking/utils.py +88 -82
  8. fin_infra/brokerage/__init__.py +1 -1
  9. fin_infra/budgets/tracker.py +2 -3
  10. fin_infra/categorization/ease.py +2 -3
  11. fin_infra/categorization/llm_layer.py +2 -2
  12. fin_infra/cli/cmds/scaffold_cmds.py +1 -1
  13. fin_infra/credit/experian/provider.py +14 -14
  14. fin_infra/crypto/__init__.py +1 -1
  15. fin_infra/documents/add.py +4 -4
  16. fin_infra/documents/ease.py +4 -3
  17. fin_infra/documents/models.py +3 -3
  18. fin_infra/documents/ocr.py +1 -1
  19. fin_infra/documents/storage.py +2 -1
  20. fin_infra/exceptions.py +1 -1
  21. fin_infra/goals/management.py +3 -3
  22. fin_infra/insights/__init__.py +0 -1
  23. fin_infra/investments/__init__.py +2 -4
  24. fin_infra/investments/add.py +37 -56
  25. fin_infra/investments/ease.py +7 -8
  26. fin_infra/investments/models.py +29 -17
  27. fin_infra/investments/providers/base.py +3 -8
  28. fin_infra/investments/providers/plaid.py +19 -29
  29. fin_infra/investments/providers/snaptrade.py +18 -36
  30. fin_infra/markets/__init__.py +4 -2
  31. fin_infra/models/accounts.py +2 -1
  32. fin_infra/models/transactions.py +2 -1
  33. fin_infra/net_worth/calculator.py +8 -6
  34. fin_infra/net_worth/ease.py +2 -2
  35. fin_infra/net_worth/insights.py +4 -4
  36. fin_infra/normalization/__init__.py +3 -1
  37. fin_infra/providers/banking/plaid_client.py +16 -16
  38. fin_infra/providers/base.py +5 -5
  39. fin_infra/providers/brokerage/alpaca.py +2 -2
  40. fin_infra/providers/market/ccxt_crypto.py +4 -1
  41. fin_infra/recurring/add.py +3 -1
  42. fin_infra/recurring/detector.py +1 -1
  43. fin_infra/recurring/normalizer.py +1 -1
  44. fin_infra/scaffold/__init__.py +1 -1
  45. fin_infra/tax/__init__.py +1 -1
  46. {fin_infra-0.1.66.dist-info → fin_infra-0.1.68.dist-info}/METADATA +1 -1
  47. {fin_infra-0.1.66.dist-info → fin_infra-0.1.68.dist-info}/RECORD +50 -50
  48. {fin_infra-0.1.66.dist-info → fin_infra-0.1.68.dist-info}/LICENSE +0 -0
  49. {fin_infra-0.1.66.dist-info → fin_infra-0.1.68.dist-info}/WHEEL +0 -0
  50. {fin_infra-0.1.66.dist-info → fin_infra-0.1.68.dist-info}/entry_points.txt +0 -0
@@ -34,7 +34,7 @@ class PlaidClient(BankingProvider):
34
34
  environment: str | None = None,
35
35
  ) -> None:
36
36
  """Initialize Plaid client with either Settings object or individual parameters.
37
-
37
+
38
38
  Args:
39
39
  settings: Settings object (legacy pattern)
40
40
  client_id: Plaid client ID (preferred - from env or passed directly)
@@ -45,14 +45,14 @@ class PlaidClient(BankingProvider):
45
45
  raise RuntimeError(
46
46
  "plaid-python SDK not available or import failed; check installed version (requires v25+)"
47
47
  )
48
-
48
+
49
49
  # Support both patterns: Settings object or individual params
50
50
  if settings is not None:
51
51
  # Legacy pattern with Settings object
52
52
  client_id = client_id or settings.plaid_client_id
53
53
  secret = secret or settings.plaid_secret
54
54
  environment = environment or settings.plaid_env
55
-
55
+
56
56
  # Map environment string to Plaid Environment enum
57
57
  # Note: Plaid only has Sandbox and Production (no Development in SDK)
58
58
  env_str = environment or "sandbox"
@@ -61,22 +61,22 @@ class PlaidClient(BankingProvider):
61
61
  "development": plaid.Environment.Sandbox, # Map development to sandbox (Plaid SDK limitation)
62
62
  "production": plaid.Environment.Production,
63
63
  }
64
-
64
+
65
65
  if env_str not in env_map:
66
66
  raise ValueError(
67
67
  f"Invalid Plaid environment: '{env_str}'. "
68
68
  f"Must be one of: sandbox, development, production"
69
69
  )
70
-
70
+
71
71
  host = env_map[env_str]
72
-
72
+
73
73
  # Configure Plaid client (v8.0.0+ API)
74
74
  configuration = plaid.Configuration(
75
75
  host=host,
76
76
  api_key={
77
77
  "clientId": client_id,
78
78
  "secret": secret,
79
- }
79
+ },
80
80
  )
81
81
  api_client = plaid.ApiClient(configuration)
82
82
  self.client = plaid_api.PlaidApi(api_client)
@@ -86,12 +86,12 @@ class PlaidClient(BankingProvider):
86
86
  user=LinkTokenCreateRequestUser(client_user_id=user_id),
87
87
  client_name="fin-infra",
88
88
  products=[
89
- Products("auth"), # Account/routing numbers for ACH
90
- Products("transactions"), # Transaction history
91
- Products("liabilities"), # Credit cards, loans, student loans
92
- Products("investments"), # Brokerage, retirement accounts
93
- Products("assets"), # Asset reports for lending/verification
94
- Products("identity"), # Account holder info (name, email, phone)
89
+ Products("auth"), # Account/routing numbers for ACH
90
+ Products("transactions"), # Transaction history
91
+ Products("liabilities"), # Credit cards, loans, student loans
92
+ Products("investments"), # Brokerage, retirement accounts
93
+ Products("assets"), # Asset reports for lending/verification
94
+ Products("identity"), # Account holder info (name, email, phone)
95
95
  ],
96
96
  country_codes=[CountryCode("US")],
97
97
  language="en",
@@ -122,7 +122,7 @@ class PlaidClient(BankingProvider):
122
122
  start = end - timedelta(days=30)
123
123
  start_date = start_date or start.isoformat()
124
124
  end_date = end_date or end.isoformat()
125
-
125
+
126
126
  request = TransactionsGetRequest(
127
127
  access_token=access_token,
128
128
  start_date=date.fromisoformat(start_date),
@@ -136,14 +136,14 @@ class PlaidClient(BankingProvider):
136
136
  request = AccountsBalanceGetRequest(access_token=access_token)
137
137
  response = self.client.accounts_balance_get(request)
138
138
  accounts = [acc.to_dict() for acc in response["accounts"]]
139
-
139
+
140
140
  if account_id:
141
141
  # Filter to specific account
142
142
  for account in accounts:
143
143
  if account.get("account_id") == account_id:
144
144
  return {"balances": [account.get("balances", {})]}
145
145
  return {"balances": []}
146
-
146
+
147
147
  # Return all balances
148
148
  return {"balances": [acc.get("balances", {}) for acc in accounts]}
149
149
 
@@ -205,27 +205,27 @@ class TaxProvider(ABC):
205
205
 
206
206
  class InvestmentProvider(ABC):
207
207
  """Provider for investment holdings and portfolio data (Plaid, SnapTrade).
208
-
208
+
209
209
  This is a minimal ABC for type checking. The full implementation with
210
210
  all abstract methods is in fin_infra.investments.providers.base.InvestmentProvider.
211
-
211
+
212
212
  Abstract Methods (defined in full implementation):
213
213
  - get_holdings(access_token, account_ids) -> List[Holding]
214
214
  - get_transactions(access_token, start_date, end_date, account_ids) -> List[InvestmentTransaction]
215
215
  - get_securities(access_token, security_ids) -> List[Security]
216
216
  - get_investment_accounts(access_token) -> List[InvestmentAccount]
217
-
217
+
218
218
  Example:
219
219
  >>> from fin_infra.investments import easy_investments
220
220
  >>> provider = easy_investments(provider="plaid")
221
221
  >>> holdings = await provider.get_holdings(access_token)
222
222
  """
223
-
223
+
224
224
  @abstractmethod
225
225
  async def get_holdings(self, access_token: str, account_ids: list[str] | None = None) -> list:
226
226
  """Fetch holdings for investment accounts."""
227
227
  pass
228
-
228
+
229
229
  @abstractmethod
230
230
  async def get_investment_accounts(self, access_token: str) -> list:
231
231
  """Fetch investment accounts with aggregated holdings."""
@@ -55,8 +55,7 @@ class AlpacaBrokerage(BrokerageProvider):
55
55
  ) -> None:
56
56
  if not ALPACA_AVAILABLE:
57
57
  raise ImportError(
58
- "alpaca-trade-api is not installed. "
59
- "Install it with: pip install alpaca-trade-api"
58
+ "alpaca-trade-api is not installed. Install it with: pip install alpaca-trade-api"
60
59
  )
61
60
 
62
61
  # Get credentials from args or environment
@@ -128,6 +127,7 @@ class AlpacaBrokerage(BrokerageProvider):
128
127
  # Without this, network retries can cause duplicate order execution = MONEY LOSS.
129
128
  if client_order_id is None:
130
129
  import uuid
130
+
131
131
  client_order_id = str(uuid.uuid4())
132
132
 
133
133
  order = self.client.submit_order(
@@ -27,4 +27,7 @@ class CCXTCryptoData(CryptoDataProvider):
27
27
  if not self._markets_loaded:
28
28
  self.exchange.load_markets()
29
29
  self._markets_loaded = True
30
- return cast(list[list[float]], self.exchange.fetch_ohlcv(symbol_pair, timeframe=timeframe, limit=limit))
30
+ return cast(
31
+ list[list[float]],
32
+ self.exchange.fetch_ohlcv(symbol_pair, timeframe=timeframe, limit=limit),
33
+ )
@@ -321,7 +321,9 @@ def add_recurring_detection(
321
321
  from .summary import get_recurring_summary
322
322
 
323
323
  # Get detected patterns for user
324
- transactions: list[dict[str, Any]] = [] # Placeholder - in production: get_user_transactions(user_id)
324
+ transactions: list[
325
+ dict[str, Any]
326
+ ] = [] # Placeholder - in production: get_user_transactions(user_id)
325
327
  patterns = detector.detect_patterns(transactions)
326
328
 
327
329
  # Generate summary
@@ -450,7 +450,7 @@ class PatternDetector:
450
450
  min_amt, max_amt = pattern.amount_range or (0, 0)
451
451
  return (
452
452
  f"Variable amount ${min_amt:.2f}-${max_amt:.2f} charged {pattern.cadence.value} "
453
- f"({pattern.amount_variance_pct*100:.1f}% variance, "
453
+ f"({pattern.amount_variance_pct * 100:.1f}% variance, "
454
454
  f"{pattern.occurrence_count} occurrences)"
455
455
  )
456
456
  else: # IRREGULAR
@@ -96,7 +96,7 @@ class FuzzyMatcher:
96
96
  """
97
97
  if not RAPIDFUZZ_AVAILABLE:
98
98
  raise ImportError(
99
- "rapidfuzz is required for fuzzy matching. " "Install with: pip install rapidfuzz"
99
+ "rapidfuzz is required for fuzzy matching. Install with: pip install rapidfuzz"
100
100
  )
101
101
  self.similarity_threshold = similarity_threshold
102
102
 
@@ -12,7 +12,7 @@ Typical usage:
12
12
  include_tenant=True,
13
13
  include_soft_delete=True,
14
14
  )
15
-
15
+
16
16
  result = scaffold_goals_core(
17
17
  dest_dir=Path("app/models/goals"),
18
18
  include_tenant=False,
fin_infra/tax/__init__.py CHANGED
@@ -144,7 +144,7 @@ def easy_tax(provider: str | TaxProvider = "mock", **config) -> TaxProvider:
144
144
 
145
145
  else:
146
146
  raise ValueError(
147
- f"Unknown tax provider: {provider}. " f"Supported providers: 'mock', 'irs', 'taxbit'"
147
+ f"Unknown tax provider: {provider}. Supported providers: 'mock', 'irs', 'taxbit'"
148
148
  )
149
149
 
150
150
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fin-infra
3
- Version: 0.1.66
3
+ Version: 0.1.68
4
4
  Summary: Financial infrastructure toolkit: banking connections, market data, credit, cashflows, and brokerage integrations
5
5
  License: MIT
6
6
  Keywords: finance,banking,plaid,brokerage,markets,credit,tax,cashflow,fintech,infra
@@ -1,20 +1,20 @@
1
1
  fin_infra/__init__.py,sha256=5vcHN0u9CE43mnK2VgiMyWTiyANupUISawvxx-2AfqE,480
2
2
  fin_infra/__main__.py,sha256=1qNP7j0ffw0wFs1dBwDcJ9TNXlC6FcYuulzoV87pMi8,262
3
3
  fin_infra/analytics/__init__.py,sha256=aiuNnii0vc34XlNzrSiMbz33lzgmR7W1nHkmAEXavCY,1870
4
- fin_infra/analytics/add.py,sha256=a8ZcVc0-3gxq64IFs9fN7XVMayzE6RCCnBWV3zzc7GU,12832
4
+ fin_infra/analytics/add.py,sha256=YhNxFAH0m-GiLxgNzwZY09wt6kmy4n88Xa9DrYBLB6E,12709
5
5
  fin_infra/analytics/cash_flow.py,sha256=lH-J6RIUzcV9Fuy56i12N6vuIdPaGz-rhWquSgjkldU,10300
6
6
  fin_infra/analytics/ease.py,sha256=p8WwFP4ivvFsvZzYRCZZVHgnPThiODve9r4-m0xnxQQ,14343
7
7
  fin_infra/analytics/models.py,sha256=cK6VKLZ763zXfn9REXOnLGx0v3Q8bUa-vH8aoNs2w-A,8215
8
- fin_infra/analytics/portfolio.py,sha256=_-whS-jwLpkhwSPmZOSipilcY2oujSItsvTzVtUsEbM,26497
8
+ fin_infra/analytics/portfolio.py,sha256=-QAG1HCTXPZPgZ0rD4076B-_jLxPcTJBjvseYeZ3Kqk,26459
9
9
  fin_infra/analytics/projections.py,sha256=7cuG6w1KXq8sd3UNufu5aOcxG5n-foswrHqrgWWKQUM,9186
10
- fin_infra/analytics/rebalancing.py,sha256=K3S7KQiIU2LwyAwWN9VrSly4AOl24vN9tz_JX7I9FJ8,14642
11
- fin_infra/analytics/savings.py,sha256=tavIRZtu9FjCm-DeWg5f060GcsdgD-cl-vgKOnieOUw,7574
10
+ fin_infra/analytics/rebalancing.py,sha256=VM8MgoJofmrCXPK1rbmVqWGB4FauNmHCL5HOEbrZR2g,14610
11
+ fin_infra/analytics/savings.py,sha256=n3rGNFP8TU5mW-uz9kOuqX_mDiVnDyAeDN06Q7Abotw,7570
12
12
  fin_infra/analytics/scenarios.py,sha256=LE_dZVkbxxAx5sxitGhiOhZfWTlYtVbIvS9pEXkijLc,12246
13
- fin_infra/analytics/spending.py,sha256=pubio9mFpTyVrebLsMYTYPPrgQ1_ML8ostwFenC7nb4,26225
13
+ fin_infra/analytics/spending.py,sha256=wCa8mhtdMTnI3eG9W28ljCgB_AQRVGxkrRA2ZwLi_RQ,26249
14
14
  fin_infra/banking/__init__.py,sha256=6brdnsK6ddLhypk4h0sblM1yv6BkQ46Nyq8Zvf5AewY,22570
15
- fin_infra/banking/history.py,sha256=1ufAwkTnXr-QJetFzJl4xA2e3dqd1-TkT8pf46MNfho,10630
16
- fin_infra/banking/utils.py,sha256=qQRJR0jUWXzRTBSy9vMYC4h7APub7Jb2drJH10vtY40,15678
17
- fin_infra/brokerage/__init__.py,sha256=2Qmiubu9kxouidrCcIHOMvYGHEgVDD5y2S2XRBAWng8,17263
15
+ fin_infra/banking/history.py,sha256=2C3R9rZMYSyPtR0oe-kCZ14SMhPAy_M9v_Xc5XzBVLs,10618
16
+ fin_infra/banking/utils.py,sha256=mCDwU34SpwTqeXoDYhNGAUqxooVxW6TAtqYorzFmPfQ,15341
17
+ fin_infra/brokerage/__init__.py,sha256=8-q1NfKZW9fUQ_2_49Vc19sskZkmHo67TJ5GQDcXqTQ,17259
18
18
  fin_infra/budgets/__init__.py,sha256=V6euagDkFHvWyjHeI64fxfddhOHDlIWwOc-PnTyyQb4,3986
19
19
  fin_infra/budgets/add.py,sha256=tdfNXD9deEEzy0xCRbTwbx70SX9wiJkWj0Huk_uCjFg,13584
20
20
  fin_infra/budgets/alerts.py,sha256=i0lQa3mLWuLQorWL-77VKhXQG2F_0U1cpdZnK3g1y3M,9720
@@ -26,14 +26,14 @@ fin_infra/budgets/scaffold_templates/models.py.tmpl,sha256=rpKhXwnx1gQjV_GGVqs8C
26
26
  fin_infra/budgets/scaffold_templates/repository.py.tmpl,sha256=khFgnQnVNnOo8DWYDmYz58MvdeSJpoS9QvTXcGhsa8g,10023
27
27
  fin_infra/budgets/scaffold_templates/schemas.py.tmpl,sha256=x5gSQ7Kiuq08tum5joKmeY0ib2r3ekLKk09dFOl0PS0,5658
28
28
  fin_infra/budgets/templates.py,sha256=Sbc7RcHXscq34g4t7J8OXM2Kfkt5DHuvqVnFU0Jiddc,12112
29
- fin_infra/budgets/tracker.py,sha256=U8C7k2VV8bOjtjPIWR8qXktsBNSyBAUnE9o2mjEs1MU,16490
29
+ fin_infra/budgets/tracker.py,sha256=mSa4K8_OxV0lZ9hIeBGrNh_5mytMaFDiPxQaehSODSE,16466
30
30
  fin_infra/cashflows/__init__.py,sha256=zwuST5PYHJHXwfqKaKo19ubvD0T3lR54RVOvzjOCNPI,8521
31
31
  fin_infra/cashflows/core.py,sha256=Or0hPqCvY_ypV0YiMXh-mle6xWK0tE8WuPPAqHGUp8E,532
32
32
  fin_infra/categorization/__init__.py,sha256=efLje12AW-ec9Vs5ynb41r4XCIWx5a-Z9WoGb3kQdIE,2030
33
33
  fin_infra/categorization/add.py,sha256=JDOvxngh-7oWHTddOyP4GAse9vLuxSTfoIhrDKUHOKg,6278
34
- fin_infra/categorization/ease.py,sha256=oIcPVuxXOPaAhSe_OcfO4eumCg9WpfIZUdg-k-Xx800,5859
34
+ fin_infra/categorization/ease.py,sha256=bomEtJAgwk9uiemNt1rk-IsTjJIhyJn0GJ_c58YEmJs,5836
35
35
  fin_infra/categorization/engine.py,sha256=Qk14HQQB6rBwEZ0cSz47l_jD4eFpWlSJzHg8kjC0KK8,12107
36
- fin_infra/categorization/llm_layer.py,sha256=5QjDcvYzzqFMsjYe-izl7QEp_SCe_qJ7P5I5gLa0vf8,12699
36
+ fin_infra/categorization/llm_layer.py,sha256=KbX7o2c-BqWDbPdQXD6qxk98gHRNtEDvf3-Q3kniT9k,12699
37
37
  fin_infra/categorization/models.py,sha256=-rGXR0RW2EU_FQ7ZfDWBIXxx8QGJDxeBF9zKGYyVgqY,5931
38
38
  fin_infra/categorization/rules.py,sha256=m3OogJY0hJe5BrmZqOvOKS2-HRdW4Y5jvvtlPDn9Pn8,12884
39
39
  fin_infra/categorization/taxonomy.py,sha256=qsgo7VJkM6GFBBOaTRHWP82vl5SinRKnMsj4ICarEyQ,13281
@@ -42,7 +42,7 @@ fin_infra/chat/ease.py,sha256=8T0BQUkWQVpaTooD5-ZtinackkciqGargXnzWzayj3M,3113
42
42
  fin_infra/chat/planning.py,sha256=eKUW6VDHJS-xQTks7bgjNQaO32Fr5gA_oP5NLt2y5Zs,19916
43
43
  fin_infra/cli/__init__.py,sha256=7M8gKULnui4__9kXRKRHgETuFwZlacK9xrq5rSZ31CM,376
44
44
  fin_infra/cli/cmds/__init__.py,sha256=BvL3wRoUl3cO5wesv1Cqoatup7VeYMhq82tS19iNZHE,136
45
- fin_infra/cli/cmds/scaffold_cmds.py,sha256=HZrnJ6NgTBYbt6LuJeoi7JKJgWE_umX9v7zjtwYfP-g,7659
45
+ fin_infra/cli/cmds/scaffold_cmds.py,sha256=SwNE8AnszmsjyUXDpmn-bauQx8HAQB_fw-6er2QaTCU,7655
46
46
  fin_infra/clients/__init__.py,sha256=EiKkAW8WY5dWtu7DDmpf3DBNcjJArxcQnE_wTAtVRho,129
47
47
  fin_infra/clients/base.py,sha256=K5nI4GJzT36oUUYGynV3b4eywJdTTa5EX26QK7XdTcc,970
48
48
  fin_infra/clients/plaid.py,sha256=jwcLdQe0G7afLO5JH5jsBosE4iz_cFsb04I8_hCbIb0,807
@@ -53,22 +53,22 @@ fin_infra/credit/experian/__init__.py,sha256=g3IJGvDOMsnB0er0Uwdvl6hGKKTOazqJxSD
53
53
  fin_infra/credit/experian/auth.py,sha256=e9AF-HCNga-561END4kOYtANUvPKLfK1HUoFA-jpBys,5608
54
54
  fin_infra/credit/experian/client.py,sha256=p_NUMNyEpXEAoXTQo91je12bysn_EswbJxJOzGIwsO0,8643
55
55
  fin_infra/credit/experian/parser.py,sha256=7ptdLyTWWqHWqCo1CXn6L7XaIn9ZRRuOaATbFmMZZ64,7489
56
- fin_infra/credit/experian/provider.py,sha256=l3NW6dppgxeUkrThftH-IB43bwuZGhNcW0jVBGF8XGY,13783
56
+ fin_infra/credit/experian/provider.py,sha256=QqnxFN0WIKyxV5y5jzIB_gv2djNpR-rTUiIhMtTWq8k,13701
57
57
  fin_infra/credit/mock.py,sha256=xKWZk3fhuIYRfiZkNc9fbHUNViNKjmOLSj0MTI1f4ik,5356
58
- fin_infra/crypto/__init__.py,sha256=HpplYEY8GiBz55ehYRDQxs8SWJIW1smBs9eFOKt_nzI,8318
58
+ fin_infra/crypto/__init__.py,sha256=p-gEoF59XzyV1RouubW4onl5mE62XvXSAw9isMc48qc,8314
59
59
  fin_infra/crypto/insights.py,sha256=BBC7SSxD6FJAXKPvOkC8KK4HNy7Gtzfn0egUx_wzVJM,11444
60
60
  fin_infra/documents/__init__.py,sha256=Ub1hbX3PTrBSsBdcbL8PFf6oq8jSH4pYxW45-qOYPqs,1909
61
- fin_infra/documents/add.py,sha256=qvy_TWAHhSUjEnvKGgtDTEc8YbRx97cxXtpkc7pU5uc,8145
61
+ fin_infra/documents/add.py,sha256=dxzhdCsDcVVyTYKrgM30j-Wr0BAG797p4xa4j9UXST8,8118
62
62
  fin_infra/documents/analysis.py,sha256=zY5OQEIlq3JLNND_cg2KheFdryUmIecPOR2lR6oKhPw,13992
63
- fin_infra/documents/ease.py,sha256=rnxEIMjf6vLvD-h5WD4wM6PwmcB4iUtAtnvGxbFA5zA,9625
64
- fin_infra/documents/models.py,sha256=5MK5Mvs7s6HfNuNldT4xxwLGV4z1f7vNJLwDD-jalgw,6889
65
- fin_infra/documents/ocr.py,sha256=cuXzrx6k3GIhiaB4-OMPyroB6GBdXuvXP7LAcs0ZV5o,9596
66
- fin_infra/documents/storage.py,sha256=GS_GtUXLMIYqe2yHb9IaQFloRER3xeQ8fla_loozP68,10177
67
- fin_infra/exceptions.py,sha256=woCazH0RxnGcrmsSA3NMZF4Ygr2dtI4tfzKNiFZ10AA,16953
63
+ fin_infra/documents/ease.py,sha256=YutA7EDYzysH6ppf6iVFhe4v1XOzhmUM3tDwtQPku28,9621
64
+ fin_infra/documents/models.py,sha256=h__Ln3lfQ50F5q3MurpThTrBEnoxJPbc_eL-NwzdZ7E,6877
65
+ fin_infra/documents/ocr.py,sha256=NxVWT4SB8bWK6EGXCWvATejYyIzZLZCh0fDCWT0KZ1Y,9594
66
+ fin_infra/documents/storage.py,sha256=AM2MjVYuZ-77MxXGuvV6NFcWAH6Y_kMRe7xH1lZ29qQ,10174
67
+ fin_infra/exceptions.py,sha256=va2rZnGhAkAi5LUqk93iGhpfkChUBaBLUNnCx6bykSM,16952
68
68
  fin_infra/goals/__init__.py,sha256=Vg8LKLlDoRiWHsJX7wu5Zcc-86NNLpHoLTjYVkGi2c4,2130
69
69
  fin_infra/goals/add.py,sha256=vhExYtXrIId4ZMBr3WH9iLsCT3gAvuAxeHHE8xNTT0U,20605
70
70
  fin_infra/goals/funding.py,sha256=6wn25N0VTYfKLzZWhEn0xdC0ft49qdElkQFc9IwmdPk,9334
71
- fin_infra/goals/management.py,sha256=72nYJjbzPNMU9TjmVZnL9wrwXCl9MlmGDfxQiVVBIqc,33865
71
+ fin_infra/goals/management.py,sha256=Rj-yCcXk4HK5Tg8VauRU3osbK3kRh5O-YR-tupULx8A,33865
72
72
  fin_infra/goals/milestones.py,sha256=LEJ9M7yOKJ-8thPuH0byHACabCUA9qW7mMATsPomaJA,9995
73
73
  fin_infra/goals/models.py,sha256=DxUrYJqlfKdrmFBucNikLbto3NgxoiJAmsL3v0LR4DQ,10237
74
74
  fin_infra/goals/scaffold_templates/README.md,sha256=CoE_3I2K32orOFH6CvfVBaJBTGDYIESd5-48V7vU1FI,9974
@@ -76,46 +76,46 @@ fin_infra/goals/scaffold_templates/__init__.py,sha256=rLFam-mRsj8LvJu5kRBEIJtw9r
76
76
  fin_infra/goals/scaffold_templates/models.py.tmpl,sha256=b23Nlwm05MFMQE4qkrylTPXqulsN6cuFzNev2liY7DI,5714
77
77
  fin_infra/goals/scaffold_templates/repository.py.tmpl,sha256=4BFy-fPBR412p8wb8VzsekxM3uGno-odqZP_BuMAXBU,11046
78
78
  fin_infra/goals/scaffold_templates/schemas.py.tmpl,sha256=M1hS1pK9UDXcNqPW-NGu9804hTFe4FPdUDVgDSMcQl4,5331
79
- fin_infra/insights/__init__.py,sha256=3rQvgC6a-4Nh_mv3HbS1bIN0Hc7IgRNncM0BVGo21NA,3959
79
+ fin_infra/insights/__init__.py,sha256=SNpgW8xe_wOKiGad5ubWCS-jRjqj6ODxe9dRsoAHxBc,3958
80
80
  fin_infra/insights/aggregator.py,sha256=XG32mN5w5Nc4AZllmfl1esL4q44mFAf0Fvj9mWev_zk,10249
81
81
  fin_infra/insights/models.py,sha256=xov_YV8oBLJt3YdyVjbryRfcXqmGeGiPvZsZHSbvtl8,3202
82
- fin_infra/investments/__init__.py,sha256=5B7m5gp9WRJHOzelYn29B4edDKIl_ZwN0kYiJ6c9LiA,6758
83
- fin_infra/investments/add.py,sha256=lC2oK6TnJN0wbw7j5k4AKKuV1bQwi67PHG5u2PwUkNw,17560
84
- fin_infra/investments/ease.py,sha256=7oyMcTVmnc8pn3lqriLRruBLEznI_grpDkH7hfXmGhE,9527
85
- fin_infra/investments/models.py,sha256=_ltCQNfQ8b34ywJvheEUhmXH-gSVwCGbmZlsaNNbznE,18305
82
+ fin_infra/investments/__init__.py,sha256=o4p_8slq-CzIK0ditVhNfcyoWsDdyFaxRl-IMBHtLNE,6732
83
+ fin_infra/investments/add.py,sha256=Yyh3VIjJ5OBJbvEZQboFDqlYkzrHoEPnWzSY2iBAJiM,17263
84
+ fin_infra/investments/ease.py,sha256=d5ISfxpCius6JM2LZNReztW6-IizaqoxNU4aEbXWA74,9487
85
+ fin_infra/investments/models.py,sha256=y3OgetML7OGRQqdESxt8eNv3ifPBHtBMtsFAf0vz5NQ,18424
86
86
  fin_infra/investments/providers/__init__.py,sha256=V1eIzz6EnGJ-pq-9L3S2-evmcExF-YdZfd5P6JMyDtc,383
87
- fin_infra/investments/providers/base.py,sha256=KaJdIdeWi2WaWAogcFZw7jcqQ_IzMZw6misBNk-n6bE,9890
88
- fin_infra/investments/providers/plaid.py,sha256=9alF6vQs41CO5D75anumhMzzBbQ_E3s1DzMMwHD9igc,18109
89
- fin_infra/investments/providers/snaptrade.py,sha256=gK4BMqMqqxFJWCyBNBdd5cllRTruVA_xvgZz4rWgxrM,23556
87
+ fin_infra/investments/providers/base.py,sha256=MwwwVaijq-8SpM6oR_HYwFWkONCiTV6zyteVP3RMM_s,9850
88
+ fin_infra/investments/providers/plaid.py,sha256=GWNRc2nFG2nWJw-JuWE49kzfi1TJ-tkjj4t_lx0UUgQ,17959
89
+ fin_infra/investments/providers/snaptrade.py,sha256=RMkYzmQba0NKw4xlaHT7w0j1e5zSqmlTfWL36M28zJE,23290
90
90
  fin_infra/investments/scaffold_templates/README.md,sha256=PhgxfMLrro2Jz83b7XEnBi7lexiWKqlMrd2UU2Rbs8A,12149
91
91
  fin_infra/investments/scaffold_templates/__init__.py,sha256=iR0oiAzXFYXHBnVJjaEnAzk6omncYOLg0TKMJ7xomBc,82
92
92
  fin_infra/investments/scaffold_templates/models.py.tmpl,sha256=5inP5-jw-qEfPYxSN71tn4AojZ9PesOIeuHTw181N-c,5849
93
93
  fin_infra/investments/scaffold_templates/repository.py.tmpl,sha256=XwOEpQZfuXut1WLiq-GSSvv0oX0iYCW54eJNL0Cav94,14656
94
94
  fin_infra/investments/scaffold_templates/schemas.py.tmpl,sha256=knWmn-Kyr7AdgPD4ZPMb6T49ZuPXeuOMqmjYNyA0CA0,5451
95
- fin_infra/markets/__init__.py,sha256=BKyJsqA0Da3L9KOgnOXYXq4LTgTMggD6KU-Sa7nFf24,9786
95
+ fin_infra/markets/__init__.py,sha256=NWIHMchN4tndjAsxvd8KMnu-pmVaW8Qc0Qu1ooqIZXY,9828
96
96
  fin_infra/models/__init__.py,sha256=q3SkGzDGFkoAMxwqJw8i4cHWt5NGU5ypjOgntxDGVKo,860
97
- fin_infra/models/accounts.py,sha256=PeobjGg6WM70OvOTe0JIo0zo7tBM0PDAcyClQT-Jo4o,1141
97
+ fin_infra/models/accounts.py,sha256=ExQimE2O5dyugFMW7nCboWbWcaX3Nnl5Gg-B1XLSdIk,1138
98
98
  fin_infra/models/brokerage.py,sha256=z6Zyf0N5zmmXtrN2y_4fNmtIP5wNq40H8lrHLBwY7rc,8311
99
99
  fin_infra/models/candle.py,sha256=7vrDxR1JFZodMUG8OGB0ft1_oaGW16gZtawjZ_2OwhA,535
100
100
  fin_infra/models/credit.py,sha256=rSdSURsMe9_i2gxmwPTDwNQWOuM2zutL-OhvHsnbtmw,12144
101
101
  fin_infra/models/money.py,sha256=5BX8IQZkrNtjjnGIQAK2tyKnVim0R-yc1F_EBxUhcr0,400
102
102
  fin_infra/models/quotes.py,sha256=_2cDJS8_RLo4tLpJlqWd32J8uFNP0bbf1V_0u3NuLwo,543
103
103
  fin_infra/models/tax.py,sha256=lhNVIW650CdtpfgmSyMMJdojV7QnpHOUFQKiwMLTT4A,15656
104
- fin_infra/models/transactions.py,sha256=-tLG9bYGRrV_ixaNmiJU0bf9BgngIRE7T6MD88r9rtA,868
104
+ fin_infra/models/transactions.py,sha256=NtIHk3RDM58wYHQiHNOsvU5K6lgpfZodrL7scDRKP6E,865
105
105
  fin_infra/net_worth/__init__.py,sha256=EjEuHNg8gEfFwbfko1-o5j-gSUZ2FcO9h7l05C-zAJM,3101
106
106
  fin_infra/net_worth/add.py,sha256=QWfHIHJs2CV99WRBqjQ2OteiOrn5cR9nurmxTF9v5rg,23191
107
107
  fin_infra/net_worth/aggregator.py,sha256=3iZGPE3AlS2Za90Mnw9XfKa2-BmCWLKkTUmDLztP9EQ,12779
108
- fin_infra/net_worth/calculator.py,sha256=JERDtZyFurw5x2NYqfHvJzv6qigamI3AFfR-wesTj_E,13133
109
- fin_infra/net_worth/ease.py,sha256=gioKs6uwatOXKubWtyLsg8W0bXDP9DwhBEGyzwhuj2k,15890
108
+ fin_infra/net_worth/calculator.py,sha256=SQJGJDok5HgvoAhKBxeeqt8vhGMchABU3zPmNRpqNy4,13139
109
+ fin_infra/net_worth/ease.py,sha256=ERdFrUjjb5l5BRp_c2tEfE1obTpRc_-FA9LnV7BTiEw,15883
110
110
  fin_infra/net_worth/goals.py,sha256=BJGxdsMjvgQDELFEJo-ai3DvsAzUNXvzMXkwovHr8yQ,1238
111
- fin_infra/net_worth/insights.py,sha256=vVK4BtfHNJGb1wyk9XD0fLpoadATTdorF8OxHOgD9b0,25222
111
+ fin_infra/net_worth/insights.py,sha256=CkZuNU-YaFeVAd6f37XNVYkqdVOaqgC7u0tq9i2Yuk4,25222
112
112
  fin_infra/net_worth/models.py,sha256=sZv3dGw5zwckE2XQ7n5ehK7sv4jdGCo9c2g4ZtZHwCI,26880
113
113
  fin_infra/net_worth/scaffold_templates/README.md,sha256=Wqd6ksqFjmtNdDFOWVV_duuAcePWwiu3_YgkVM9N_WY,14363
114
114
  fin_infra/net_worth/scaffold_templates/__init__.py,sha256=OKeMCC_JNw6m8rBWr_wesOIJ1OR9LCBeIkXKahbCGC4,132
115
115
  fin_infra/net_worth/scaffold_templates/models.py.tmpl,sha256=9BKsoD08RZbSdOm0wFTbx5OzKfAEtuA1NcWyS1Aywx4,5934
116
116
  fin_infra/net_worth/scaffold_templates/repository.py.tmpl,sha256=DSErnNxeAe4pWeefARRK3bU0hHltqdIFffENfVwdd7c,12798
117
117
  fin_infra/net_worth/scaffold_templates/schemas.py.tmpl,sha256=VkFsxyZx4DFDhXDhn-7KT0IgrXCvgaS5ZdWbjyezWj0,4709
118
- fin_infra/normalization/__init__.py,sha256=npvKMnCCAhbuPZAskN8PBIiq89MIU2FNpVxuOGG0DlY,6224
118
+ fin_infra/normalization/__init__.py,sha256=X3qXIxqWLW7t3O_H0HuW0rMSy1AO2uRsJj3--qBFZbw,6246
119
119
  fin_infra/normalization/currency_converter.py,sha256=uuu8ASa5ppEniWLEVEpiDxXjZzln9nopWrhrATcD6Z4,7058
120
120
  fin_infra/normalization/models.py,sha256=gNC9chpbQPRN58V2j__VEPVNReO1N8jH_AHObwGPWu0,1928
121
121
  fin_infra/normalization/providers/__init__.py,sha256=LFU1tB2hVO42Yrkw-IDpPexD4mIlxob9lRrJEeGYqpE,559
@@ -126,16 +126,16 @@ fin_infra/obs/__init__.py,sha256=kMMVl0fdwtJtZeKiusTuw0iO61Jo9-HNXsLmn3ffLRE,631
126
126
  fin_infra/obs/classifier.py,sha256=FEwL1lEV_f9bFBr36PaZsV4DxU3spwIXPoegwBgzSMc,5146
127
127
  fin_infra/providers/__init__.py,sha256=jxhQm79T6DVXf7Wpy7luL-p50cE_IMUbjt4o3apzJQU,768
128
128
  fin_infra/providers/banking/base.py,sha256=KeNU4ur3zLKHVsBF1LQifcs2AKX06IEE-Rx_SetFeAs,102
129
- fin_infra/providers/banking/plaid_client.py,sha256=21m6ZkovwXuUuj0-dgQVDLxSfxZVjhuXj8di_-q3jGc,6617
129
+ fin_infra/providers/banking/plaid_client.py,sha256=LiBIwQLJp-5bA98oEQtTZpkQMC7kwhShq0mPATa9wD8,6520
130
130
  fin_infra/providers/banking/teller_client.py,sha256=QmrsBlk3_rHT-pTQPrIAA74kjIjcgdi-gOb8NA3oBO8,10268
131
- fin_infra/providers/base.py,sha256=_Ez3WFGY4TwWks2juqt0yv2lR6VQxdIl3mh4z8I2kY0,6698
132
- fin_infra/providers/brokerage/alpaca.py,sha256=wRVfVmExiYXCk1pLRmHSrfo91714JIm3rrD0djrNfT8,9938
131
+ fin_infra/providers/base.py,sha256=_EmC37Bt8LA2JmVxMIy2poJyQsuD6FpAawkHPreq0M8,6678
132
+ fin_infra/providers/brokerage/alpaca.py,sha256=M8Z2i6dY9mgrU4-SDei2nYRKgbxHuPDMHubMb7ZMbEY,9920
133
133
  fin_infra/providers/brokerage/base.py,sha256=JJFH0Cqca4Rg4rmxfiwcQt-peRoBf4JpG3g6jx8DVks,106
134
134
  fin_infra/providers/credit/experian.py,sha256=r7lpFecgOdNEhb_Lxz2Z-BG8R3p2n0XlqDKL7y8NZ-0,482
135
135
  fin_infra/providers/identity/stripe_identity.py,sha256=JQGJRuQdWP5dWDcROgtz1RrmpkytRv95H6Fn-x1kifU,501
136
136
  fin_infra/providers/market/alphavantage.py,sha256=srZdkf-frBuKyPTdWasMmVrpnh76BEBDXa-nsYtLzNc,8963
137
137
  fin_infra/providers/market/base.py,sha256=ljBzZTfjYQS9tXahmxFic7JQSZeyoiDMUZ1NY0R7yto,108
138
- fin_infra/providers/market/ccxt_crypto.py,sha256=52WdAx106deCFqLvzhOzrToVH2xkNXGf0i5kymVIjEA,1141
138
+ fin_infra/providers/market/ccxt_crypto.py,sha256=knxcgTwZX0rRVoO7f-2eMVzFUbu-qIjtoIXdNulRvLQ,1176
139
139
  fin_infra/providers/market/coingecko.py,sha256=F1Bwdk28xSsIaFEuT7lhT3F6Vkd0Lp-CMp1rnYiLfaE,2702
140
140
  fin_infra/providers/market/yahoo.py,sha256=FNhqkCFC0In-Z3zpzmuknEORHLRK5Evk2KSk0yysKjg,4954
141
141
  fin_infra/providers/registry.py,sha256=yPFmHHaSQERXZTcGkdXAtMU7rL7VwAzW4FOr14o6KS8,8409
@@ -145,16 +145,16 @@ fin_infra/providers/tax/mock.py,sha256=AxI3RmEn3exdQeeUNkQYqZ-war5PS--WnLGXfRRee
145
145
  fin_infra/providers/tax/taxbit.py,sha256=DEA7vgQPYMjz4ZdC0DpY7112FLZJ2kvwgAbDZnpHFy0,4271
146
146
  fin_infra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
147
  fin_infra/recurring/__init__.py,sha256=ihMPywft8pGqzMu6EXxbQCU7ByoMl_dvad00gWV1mnk,2308
148
- fin_infra/recurring/add.py,sha256=cW1mqNwTWR8IUX3GIEeD-aLHnulorCqwG4H7iGvUJI4,19050
149
- fin_infra/recurring/detector.py,sha256=1e6PRoBAT2NxoGAgcVHAWwpPtznkJMaYSrJtvSq0YqM,20154
148
+ fin_infra/recurring/add.py,sha256=tnW-duL6k1Lk0Rxuq_6os2Cif1mkWd7uLNWnnD7gnes,19072
149
+ fin_infra/recurring/detector.py,sha256=FvxWSzvaGWByNpUgy_jN9Zjc2L8-qmU0ggqpSz-RXQA,20156
150
150
  fin_infra/recurring/detectors_llm.py,sha256=YNG3GOvto8ua9yNacmejYcDOHZzN9UUpDtRdrzDsLSY,11504
151
151
  fin_infra/recurring/ease.py,sha256=Vsg_AnTLjb5QXfFjijH2C50Or9hJGIVLtczk0U71h74,11189
152
152
  fin_infra/recurring/insights.py,sha256=a4fhASyiNQTdUl2ijaxi2HqhWDhf-aJND2c62d9lgEo,15886
153
153
  fin_infra/recurring/models.py,sha256=o0N8G-QhVb4zILEyry6M1VZ7liFJIOHwlejvn6p4K8M,8894
154
- fin_infra/recurring/normalizer.py,sha256=Rc1ntIDGir6X-I5lgv49kdLry_zHGJ8cys_Jf3F6Lhk,9761
154
+ fin_infra/recurring/normalizer.py,sha256=HZ4N7lXaeOZqphjSbjRmaneONJ5ELOSrqBlM5WM1tww,9758
155
155
  fin_infra/recurring/normalizers.py,sha256=37-ER4deeJhywrNVEe9KteecC_eH7xesTl2CWhRbdi0,15928
156
156
  fin_infra/recurring/summary.py,sha256=1Wte58ZZkEFulkb-nnpwfC5h7C_JrqByy47itdVdWwc,14665
157
- fin_infra/scaffold/__init__.py,sha256=OyD8ZtIC4eNTHqD16rbpT8KU0TpZUI6VV4xne4vpaHg,831
157
+ fin_infra/scaffold/__init__.py,sha256=IfL_CHHMpQB1efqY37BlIu07356tLaeVI2Mv3C0qYDs,827
158
158
  fin_infra/scaffold/budgets.py,sha256=XXOLlEcyBXVwdbJB__qObRXJ0oe1okwDT_-5tG8c9Yk,9515
159
159
  fin_infra/scaffold/goals.py,sha256=uVYzbbfbXGrf8qeGvq8mtY6o_YIk17aZ0DfSGQx6Y58,9690
160
160
  fin_infra/security/__init__.py,sha256=ZXGa7IeoOg50f41KsA7tt9rKTUeg910AagQYXh0MIbs,1363
@@ -166,15 +166,15 @@ fin_infra/security/pii_filter.py,sha256=lfARBmPRekkyXKJV0tWI_0KVaDsdV61VH-8RHxvb
166
166
  fin_infra/security/pii_patterns.py,sha256=SM-o7cL6NdgkOmtBedsN2nJZ5QPbeYehZdYmAujk8Y8,3070
167
167
  fin_infra/security/token_store.py,sha256=qgxhBKwhtVpchyHv30mM-cttuGZlzZvZLC4Oa-gTTeg,6075
168
168
  fin_infra/settings.py,sha256=xitpBQJmuvSy9prQhvXOW1scbwB1KAyGD8XqYgU_hQU,1388
169
- fin_infra/tax/__init__.py,sha256=NXUjV-k-rw4774pookY3UOwEXYRQauJze6Yift5RjW0,6107
169
+ fin_infra/tax/__init__.py,sha256=S0TijDOqENzRhZbh-byJuOaV6VB-ESsD1Hu9wQ5ZOo4,6103
170
170
  fin_infra/tax/add.py,sha256=8INSAv721ir9ICQxQ_oA0hL-Bjg6wLyrtj9tafrcCsA,14552
171
171
  fin_infra/tax/tlh.py,sha256=6OlZ3Gb13rSFrmW7vPqVTq_NB45D110iHgCwzYp2nTA,21523
172
172
  fin_infra/utils/__init__.py,sha256=gKacLSWMAis--pasd8AuVN7ap0e9Z1TjRGur0J23EDo,648
173
173
  fin_infra/utils/http.py,sha256=pvcxbNQ9oisoGPkNe3xX9aAgWzEN6mmdtr1w-L02Xj8,629
174
174
  fin_infra/utils/retry.py,sha256=ISBrup5XCuXqHZh9kjTGvGQYcuyYyqZE4u26wW7r3CM,1030
175
175
  fin_infra/version.py,sha256=4t_crzhrLum--oyowUMxtjBTzUtWp7oRTF22ewEvJG4,49
176
- fin_infra-0.1.66.dist-info/LICENSE,sha256=wK-Ya7Ylxa38dSIZRhvNj1ZVLIrHC-BAI8v38PNADiA,1061
177
- fin_infra-0.1.66.dist-info/METADATA,sha256=upSnMsATy_jVXRvZ_Qmw9lGY6D8mahLE6KpvSlPEGaI,10183
178
- fin_infra-0.1.66.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
179
- fin_infra-0.1.66.dist-info/entry_points.txt,sha256=Sr1uikvALZMeKm-DIkeKG4L9c4SNqysXGO_IRF8_9eU,53
180
- fin_infra-0.1.66.dist-info/RECORD,,
176
+ fin_infra-0.1.68.dist-info/LICENSE,sha256=wK-Ya7Ylxa38dSIZRhvNj1ZVLIrHC-BAI8v38PNADiA,1061
177
+ fin_infra-0.1.68.dist-info/METADATA,sha256=Vet5JZ-o-ltJjw6lXcPuvY2SDbOAa59BeTHE0Vrc-Kc,10183
178
+ fin_infra-0.1.68.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
179
+ fin_infra-0.1.68.dist-info/entry_points.txt,sha256=Sr1uikvALZMeKm-DIkeKG4L9c4SNqysXGO_IRF8_9eU,53
180
+ fin_infra-0.1.68.dist-info/RECORD,,