fin-infra 0.1.58__tar.gz → 0.1.60__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.
- {fin_infra-0.1.58 → fin_infra-0.1.60}/PKG-INFO +1 -1
- {fin_infra-0.1.58 → fin_infra-0.1.60}/pyproject.toml +5 -3
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/__init__.py +11 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/spending.py +8 -7
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/categorization/llm_layer.py +1 -1
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/credit/experian/client.py +14 -26
- fin_infra-0.1.60/src/fin_infra/exceptions.py +613 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/add.py +46 -21
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/normalization/currency_converter.py +8 -10
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/normalization/providers/exchangerate.py +6 -5
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/normalization/symbol_resolver.py +7 -6
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/market/coingecko.py +6 -2
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/registry.py +11 -6
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/utils/__init__.py +6 -1
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/utils/retry.py +4 -3
- fin_infra-0.1.58/src/fin_infra/utils.py +0 -36
- {fin_infra-0.1.58 → fin_infra-0.1.60}/LICENSE +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/README.md +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/__main__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/cash_flow.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/ease.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/portfolio.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/projections.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/rebalancing.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/savings.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/analytics/scenarios.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/banking/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/banking/history.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/banking/utils.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/brokerage/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/alerts.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/ease.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/scaffold_templates/README.md +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/scaffold_templates/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/scaffold_templates/models.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/scaffold_templates/repository.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/scaffold_templates/schemas.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/templates.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/budgets/tracker.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/cashflows/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/cashflows/core.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/categorization/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/categorization/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/categorization/ease.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/categorization/engine.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/categorization/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/categorization/rules.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/categorization/taxonomy.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/chat/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/chat/ease.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/chat/planning.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/cli/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/cli/cmds/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/cli/cmds/scaffold_cmds.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/clients/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/clients/base.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/clients/plaid.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/compliance/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/credit/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/credit/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/credit/experian/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/credit/experian/auth.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/credit/experian/parser.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/credit/experian/provider.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/credit/mock.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/crypto/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/crypto/insights.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/documents/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/documents/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/documents/analysis.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/documents/ease.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/documents/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/documents/ocr.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/documents/storage.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/funding.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/management.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/milestones.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/scaffold_templates/README.md +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/scaffold_templates/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/scaffold_templates/models.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/scaffold_templates/repository.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/goals/scaffold_templates/schemas.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/insights/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/insights/aggregator.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/insights/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/ease.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/providers/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/providers/base.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/providers/plaid.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/providers/snaptrade.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/scaffold_templates/README.md +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/scaffold_templates/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/scaffold_templates/models.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/scaffold_templates/repository.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/investments/scaffold_templates/schemas.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/markets/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/accounts.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/brokerage.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/candle.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/credit.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/money.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/quotes.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/tax.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/models/transactions.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/aggregator.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/calculator.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/ease.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/goals.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/insights.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/scaffold_templates/README.md +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/scaffold_templates/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/scaffold_templates/models.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/scaffold_templates/repository.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/net_worth/scaffold_templates/schemas.py.tmpl +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/normalization/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/normalization/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/normalization/providers/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/normalization/providers/static_mappings.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/obs/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/obs/classifier.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/banking/base.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/banking/plaid_client.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/banking/teller_client.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/base.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/brokerage/alpaca.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/brokerage/base.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/credit/experian.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/identity/stripe_identity.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/market/alphavantage.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/market/base.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/market/ccxt_crypto.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/market/yahoo.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/tax/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/tax/irs.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/tax/mock.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/providers/tax/taxbit.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/py.typed +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/detector.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/detectors_llm.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/ease.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/insights.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/normalizer.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/normalizers.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/recurring/summary.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/scaffold/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/scaffold/budgets.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/scaffold/goals.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/security/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/security/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/security/audit.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/security/encryption.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/security/models.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/security/pii_filter.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/security/pii_patterns.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/security/token_store.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/settings.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/tax/__init__.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/tax/add.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/tax/tlh.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/utils/http.py +0 -0
- {fin_infra-0.1.58 → fin_infra-0.1.60}/src/fin_infra/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: fin-infra
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.60
|
|
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,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "fin-infra"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.60"
|
|
4
4
|
description = "Financial infrastructure toolkit: banking connections, market data, credit, cashflows, and brokerage integrations"
|
|
5
5
|
authors = ["Ali Khatami <aliikhatami94@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -87,10 +87,12 @@ target-version = "py311"
|
|
|
87
87
|
[tool.mypy]
|
|
88
88
|
python_version = "3.13"
|
|
89
89
|
ignore_missing_imports = true
|
|
90
|
-
no_implicit_optional =
|
|
90
|
+
no_implicit_optional = true
|
|
91
91
|
install_types = true
|
|
92
92
|
non_interactive = true
|
|
93
|
-
check_untyped_defs =
|
|
93
|
+
check_untyped_defs = true
|
|
94
|
+
warn_return_any = true
|
|
95
|
+
warn_unused_ignores = true
|
|
94
96
|
files = "src"
|
|
95
97
|
exclude = '^(\.venv|venv|build|dist|node_modules|tests)/'
|
|
96
98
|
plugins = ["pydantic.mypy"]
|
|
@@ -4,8 +4,19 @@ Public surface is intentionally small at this stage. Import from submodules for
|
|
|
4
4
|
specific domains (clients, models, markets, credit).
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from .exceptions import (
|
|
8
|
+
FinInfraError,
|
|
9
|
+
ProviderError,
|
|
10
|
+
ProviderNotFoundError,
|
|
11
|
+
ValidationError,
|
|
12
|
+
)
|
|
7
13
|
from .version import __version__
|
|
8
14
|
|
|
9
15
|
__all__ = [
|
|
10
16
|
"__version__",
|
|
17
|
+
# Base errors
|
|
18
|
+
"FinInfraError",
|
|
19
|
+
"ProviderError",
|
|
20
|
+
"ProviderNotFoundError",
|
|
21
|
+
"ValidationError",
|
|
11
22
|
]
|
|
@@ -44,6 +44,7 @@ Examples:
|
|
|
44
44
|
|
|
45
45
|
from collections import defaultdict
|
|
46
46
|
from datetime import timedelta
|
|
47
|
+
from decimal import Decimal
|
|
47
48
|
from typing import Optional
|
|
48
49
|
|
|
49
50
|
from fin_infra.analytics.models import (
|
|
@@ -132,7 +133,7 @@ async def analyze_spending(
|
|
|
132
133
|
]
|
|
133
134
|
|
|
134
135
|
# Calculate top merchants
|
|
135
|
-
merchant_totals: dict[str,
|
|
136
|
+
merchant_totals: dict[str, Decimal] = defaultdict(Decimal)
|
|
136
137
|
for t in expense_transactions:
|
|
137
138
|
merchant = _extract_merchant_name(t.description or "Unknown")
|
|
138
139
|
merchant_totals[merchant] += abs(t.amount)
|
|
@@ -142,7 +143,7 @@ async def analyze_spending(
|
|
|
142
143
|
] # Top 10 merchants
|
|
143
144
|
|
|
144
145
|
# Calculate category breakdown
|
|
145
|
-
category_totals: dict[str,
|
|
146
|
+
category_totals: dict[str, Decimal] = defaultdict(Decimal)
|
|
146
147
|
for t in expense_transactions:
|
|
147
148
|
category = _get_transaction_category(t)
|
|
148
149
|
category_totals[category] += abs(t.amount)
|
|
@@ -261,7 +262,7 @@ def _get_transaction_category(transaction: Transaction) -> str:
|
|
|
261
262
|
|
|
262
263
|
async def _calculate_spending_trends(
|
|
263
264
|
user_id: str,
|
|
264
|
-
current_category_totals: dict[str,
|
|
265
|
+
current_category_totals: dict[str, Decimal],
|
|
265
266
|
current_period_days: int,
|
|
266
267
|
banking_provider=None,
|
|
267
268
|
categorization_provider=None,
|
|
@@ -288,7 +289,7 @@ async def _calculate_spending_trends(
|
|
|
288
289
|
for category, current_amount in current_category_totals.items():
|
|
289
290
|
# Mock: assume previous period was 10% lower on average
|
|
290
291
|
# In reality, would fetch historical data
|
|
291
|
-
previous_amount = current_amount * 0.9
|
|
292
|
+
previous_amount = current_amount * Decimal("0.9")
|
|
292
293
|
|
|
293
294
|
change_percent = (
|
|
294
295
|
((current_amount - previous_amount) / previous_amount) * 100
|
|
@@ -311,7 +312,7 @@ async def _calculate_spending_trends(
|
|
|
311
312
|
|
|
312
313
|
async def _detect_spending_anomalies(
|
|
313
314
|
user_id: str,
|
|
314
|
-
current_category_totals: dict[str,
|
|
315
|
+
current_category_totals: dict[str, Decimal],
|
|
315
316
|
current_period_days: int,
|
|
316
317
|
banking_provider=None,
|
|
317
318
|
categorization_provider=None,
|
|
@@ -339,7 +340,7 @@ async def _detect_spending_anomalies(
|
|
|
339
340
|
for category, current_amount in current_category_totals.items():
|
|
340
341
|
# Mock: assume historical average is current amount * 0.8
|
|
341
342
|
# In reality, would calculate from historical data
|
|
342
|
-
average_amount = current_amount * 0.8
|
|
343
|
+
average_amount = current_amount * Decimal("0.8")
|
|
343
344
|
|
|
344
345
|
deviation_percent = (
|
|
345
346
|
((current_amount - average_amount) / average_amount) * 100 if average_amount > 0 else 0
|
|
@@ -409,7 +410,7 @@ def _generate_mock_transactions(days: int) -> list[Transaction]:
|
|
|
409
410
|
Transaction(
|
|
410
411
|
id=f"mock_{i}",
|
|
411
412
|
account_id="mock_account",
|
|
412
|
-
amount=
|
|
413
|
+
amount=Decimal(str(amount)),
|
|
413
414
|
date=base_date - timedelta(days=days_ago),
|
|
414
415
|
description=description,
|
|
415
416
|
)
|
|
@@ -20,7 +20,7 @@ from pydantic import BaseModel, Field
|
|
|
20
20
|
|
|
21
21
|
# ai-infra imports
|
|
22
22
|
try:
|
|
23
|
-
from ai_infra.llm import LLM
|
|
23
|
+
from ai_infra.llm import CoreLLM as LLM
|
|
24
24
|
from ai_infra.llm.providers import Providers
|
|
25
25
|
except ImportError:
|
|
26
26
|
raise ImportError("ai-infra not installed. Install with: pip install ai-infra")
|
|
@@ -25,33 +25,21 @@ from tenacity import (
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
from fin_infra.credit.experian.auth import ExperianAuthManager
|
|
28
|
+
from fin_infra.exceptions import (
|
|
29
|
+
ExperianAPIError,
|
|
30
|
+
ExperianAuthError,
|
|
31
|
+
ExperianNotFoundError,
|
|
32
|
+
ExperianRateLimitError,
|
|
33
|
+
)
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
""
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class ExperianRateLimitError(ExperianAPIError):
|
|
40
|
-
"""Raised when rate limit is exceeded (429)."""
|
|
41
|
-
|
|
42
|
-
pass
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class ExperianAuthError(ExperianAPIError):
|
|
46
|
-
"""Raised when authentication fails (401)."""
|
|
47
|
-
|
|
48
|
-
pass
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class ExperianNotFoundError(ExperianAPIError):
|
|
52
|
-
"""Raised when user not found in bureau (404)."""
|
|
53
|
-
|
|
54
|
-
pass
|
|
35
|
+
# Re-export for backward compatibility
|
|
36
|
+
__all__ = [
|
|
37
|
+
"ExperianAPIError",
|
|
38
|
+
"ExperianAuthError",
|
|
39
|
+
"ExperianNotFoundError",
|
|
40
|
+
"ExperianRateLimitError",
|
|
41
|
+
"ExperianClient",
|
|
42
|
+
]
|
|
55
43
|
|
|
56
44
|
|
|
57
45
|
class ExperianClient:
|