fin-infra 0.1.63__tar.gz → 0.1.64__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.63 → fin_infra-0.1.64}/PKG-INFO +1 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/pyproject.toml +1 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/spending.py +8 -6
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/banking/__init__.py +5 -2
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/brokerage/__init__.py +4 -2
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/categorization/__init__.py +1 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/categorization/add.py +2 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/categorization/ease.py +1 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/categorization/engine.py +1 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/__init__.py +11 -4
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/ease.py +11 -7
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/models.py +1 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/providers/plaid.py +1 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/markets/__init__.py +8 -3
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/banking/teller_client.py +7 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/tax/mock.py +3 -3
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/security/token_store.py +3 -1
- {fin_infra-0.1.63 → fin_infra-0.1.64}/LICENSE +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/README.md +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/__main__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/cash_flow.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/ease.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/portfolio.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/projections.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/rebalancing.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/savings.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/analytics/scenarios.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/banking/history.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/banking/utils.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/alerts.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/ease.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/scaffold_templates/README.md +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/scaffold_templates/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/scaffold_templates/models.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/scaffold_templates/repository.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/scaffold_templates/schemas.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/templates.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/tracker.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/cashflows/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/cashflows/core.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/categorization/llm_layer.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/categorization/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/categorization/rules.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/categorization/taxonomy.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/chat/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/chat/ease.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/chat/planning.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/cli/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/cli/cmds/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/cli/cmds/scaffold_cmds.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/clients/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/clients/base.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/clients/plaid.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/compliance/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/credit/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/credit/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/credit/experian/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/credit/experian/auth.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/credit/experian/client.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/credit/experian/parser.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/credit/experian/provider.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/credit/mock.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/crypto/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/crypto/insights.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/documents/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/documents/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/documents/analysis.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/documents/ease.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/documents/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/documents/ocr.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/documents/storage.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/exceptions.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/funding.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/management.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/milestones.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/scaffold_templates/README.md +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/scaffold_templates/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/scaffold_templates/models.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/scaffold_templates/repository.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/scaffold_templates/schemas.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/insights/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/insights/aggregator.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/insights/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/providers/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/providers/base.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/providers/snaptrade.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/README.md +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/models.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/repository.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/schemas.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/accounts.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/brokerage.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/candle.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/credit.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/money.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/quotes.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/tax.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/models/transactions.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/aggregator.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/calculator.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/ease.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/goals.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/insights.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/README.md +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/models.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/repository.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/schemas.py.tmpl +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/normalization/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/normalization/currency_converter.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/normalization/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/normalization/providers/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/normalization/providers/exchangerate.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/normalization/providers/static_mappings.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/normalization/symbol_resolver.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/obs/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/obs/classifier.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/banking/base.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/banking/plaid_client.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/base.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/brokerage/alpaca.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/brokerage/base.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/credit/experian.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/identity/stripe_identity.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/market/alphavantage.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/market/base.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/market/ccxt_crypto.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/market/coingecko.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/market/yahoo.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/registry.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/tax/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/tax/irs.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/providers/tax/taxbit.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/py.typed +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/detector.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/detectors_llm.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/ease.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/insights.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/normalizer.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/normalizers.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/recurring/summary.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/scaffold/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/scaffold/budgets.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/scaffold/goals.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/security/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/security/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/security/audit.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/security/encryption.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/security/models.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/security/pii_filter.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/security/pii_patterns.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/settings.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/tax/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/tax/add.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/tax/tlh.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/utils/__init__.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/utils/http.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/utils/retry.py +0 -0
- {fin_infra-0.1.63 → fin_infra-0.1.64}/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.64
|
|
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.64"
|
|
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"
|
|
@@ -162,12 +162,13 @@ async def analyze_spending(
|
|
|
162
162
|
)
|
|
163
163
|
|
|
164
164
|
return SpendingInsight(
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
# Convert Decimal to float for model compatibility (intentional for Pydantic field types)
|
|
166
|
+
top_merchants=[(m, float(v)) for m, v in top_merchants],
|
|
167
|
+
category_breakdown={k: float(v) for k, v in category_totals.items()},
|
|
167
168
|
spending_trends=spending_trends,
|
|
168
169
|
anomalies=anomalies,
|
|
169
170
|
period_days=days,
|
|
170
|
-
total_spending=total_spending,
|
|
171
|
+
total_spending=float(total_spending) if total_spending else 0.0,
|
|
171
172
|
)
|
|
172
173
|
|
|
173
174
|
|
|
@@ -359,9 +360,10 @@ async def _detect_spending_anomalies(
|
|
|
359
360
|
anomalies.append(
|
|
360
361
|
SpendingAnomaly(
|
|
361
362
|
category=category,
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
363
|
+
# Convert Decimal to float for model compatibility (intentional for Pydantic field types)
|
|
364
|
+
current_amount=float(current_amount),
|
|
365
|
+
average_amount=float(average_amount),
|
|
366
|
+
deviation_percent=float(deviation_percent),
|
|
365
367
|
severity=severity,
|
|
366
368
|
)
|
|
367
369
|
)
|
|
@@ -397,10 +397,13 @@ def add_banking(
|
|
|
397
397
|
}
|
|
398
398
|
"""
|
|
399
399
|
# Get all transactions from provider
|
|
400
|
+
# Convert date to ISO string format as expected by BankingProvider.transactions()
|
|
401
|
+
start_date_str: str | None = start_date.isoformat() if start_date else None
|
|
402
|
+
end_date_str: str | None = end_date.isoformat() if end_date else None
|
|
400
403
|
transactions = banking.transactions(
|
|
401
404
|
access_token=access_token,
|
|
402
|
-
start_date=
|
|
403
|
-
end_date=
|
|
405
|
+
start_date=start_date_str,
|
|
406
|
+
end_date=end_date_str,
|
|
404
407
|
)
|
|
405
408
|
|
|
406
409
|
# Apply filters
|
|
@@ -212,7 +212,9 @@ def add_brokerage(
|
|
|
212
212
|
|
|
213
213
|
# Initialize provider if string or None
|
|
214
214
|
if isinstance(provider, str):
|
|
215
|
-
|
|
215
|
+
# Cast provider string to Literal type for type checker
|
|
216
|
+
provider_literal: Literal["alpaca"] | None = provider if provider == "alpaca" else None # type: ignore[assignment]
|
|
217
|
+
brokerage_provider = easy_brokerage(provider=provider_literal, mode=mode, **config)
|
|
216
218
|
elif provider is None:
|
|
217
219
|
brokerage_provider = easy_brokerage(mode=mode, **config)
|
|
218
220
|
else:
|
|
@@ -241,7 +243,7 @@ def add_brokerage(
|
|
|
241
243
|
Returns list of positions with symbol, quantity, P/L, etc.
|
|
242
244
|
"""
|
|
243
245
|
try:
|
|
244
|
-
positions = brokerage_provider.positions()
|
|
246
|
+
positions = list(brokerage_provider.positions()) # Convert Iterable to list for len()
|
|
245
247
|
return {"positions": positions, "count": len(positions)}
|
|
246
248
|
except Exception as e:
|
|
247
249
|
raise HTTPException(status_code=500, detail=f"Error fetching positions: {str(e)}")
|
|
@@ -44,7 +44,7 @@ from .taxonomy import Category, CategoryGroup, get_all_categories, get_category_
|
|
|
44
44
|
try:
|
|
45
45
|
from .llm_layer import LLMCategorizer
|
|
46
46
|
except ImportError:
|
|
47
|
-
LLMCategorizer = None
|
|
47
|
+
LLMCategorizer = None # type: ignore[assignment,misc]
|
|
48
48
|
|
|
49
49
|
__all__ = [
|
|
50
50
|
# Easy setup
|
|
@@ -96,7 +96,8 @@ def add_categorization(
|
|
|
96
96
|
start_time = time.perf_counter()
|
|
97
97
|
|
|
98
98
|
try:
|
|
99
|
-
|
|
99
|
+
# Await the async categorize method
|
|
100
|
+
prediction = await engine.categorize(
|
|
100
101
|
merchant_name=request.merchant_name,
|
|
101
102
|
user_id=request.user_id,
|
|
102
103
|
include_alternatives=request.include_alternatives,
|
|
@@ -51,7 +51,8 @@ from typing import TYPE_CHECKING, Literal
|
|
|
51
51
|
if TYPE_CHECKING:
|
|
52
52
|
from fastapi import FastAPI
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
# Use the local InvestmentProvider base class (same as providers use)
|
|
55
|
+
from .providers.base import InvestmentProvider
|
|
55
56
|
|
|
56
57
|
# Lazy imports to avoid loading provider SDKs unless needed
|
|
57
58
|
_provider_cache: dict[str, InvestmentProvider] = {}
|
|
@@ -114,6 +115,7 @@ def easy_investments(
|
|
|
114
115
|
return _provider_cache[cache_key]
|
|
115
116
|
|
|
116
117
|
# Lazy import and initialize provider
|
|
118
|
+
instance: InvestmentProvider
|
|
117
119
|
if provider == "plaid":
|
|
118
120
|
from .providers.plaid import PlaidInvestmentProvider
|
|
119
121
|
|
|
@@ -172,14 +174,19 @@ def add_investments(
|
|
|
172
174
|
>>> # GET /investments/transactions
|
|
173
175
|
>>> # etc.
|
|
174
176
|
"""
|
|
175
|
-
from .add import add_investments_impl
|
|
177
|
+
from .add import add_investments as add_investments_impl
|
|
178
|
+
from .providers.base import InvestmentProvider as InvestmentProviderBase
|
|
179
|
+
|
|
180
|
+
# Resolve provider from string Literal to actual InvestmentProvider instance
|
|
181
|
+
resolved_provider: InvestmentProviderBase | None = None
|
|
182
|
+
if provider is not None:
|
|
183
|
+
resolved_provider = easy_investments(provider=provider, **provider_config) # type: ignore[assignment]
|
|
176
184
|
|
|
177
185
|
return add_investments_impl(
|
|
178
186
|
app,
|
|
179
|
-
provider=
|
|
187
|
+
provider=resolved_provider,
|
|
180
188
|
prefix=prefix,
|
|
181
189
|
tags=tags or ["Investments"],
|
|
182
|
-
**provider_config,
|
|
183
190
|
)
|
|
184
191
|
|
|
185
192
|
|
|
@@ -112,19 +112,20 @@ def easy_investments(
|
|
|
112
112
|
- Most other SnapTrade brokerages support trading operations
|
|
113
113
|
"""
|
|
114
114
|
# Auto-detect provider from environment if not specified
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
detected_provider: str | None = provider
|
|
116
|
+
if detected_provider is None:
|
|
117
|
+
detected_provider = _detect_provider()
|
|
117
118
|
|
|
118
119
|
# Validate provider
|
|
119
|
-
if
|
|
120
|
+
if detected_provider not in ("plaid", "snaptrade"):
|
|
120
121
|
raise ValueError(
|
|
121
|
-
f"Invalid provider: {
|
|
122
|
+
f"Invalid provider: {detected_provider}. Must be 'plaid' or 'snaptrade'."
|
|
122
123
|
)
|
|
123
124
|
|
|
124
125
|
# Instantiate provider
|
|
125
|
-
if
|
|
126
|
+
if detected_provider == "plaid":
|
|
126
127
|
return _create_plaid_provider(**config)
|
|
127
|
-
elif
|
|
128
|
+
elif detected_provider == "snaptrade":
|
|
128
129
|
return _create_snaptrade_provider(**config)
|
|
129
130
|
|
|
130
131
|
# Should never reach here
|
|
@@ -233,10 +234,13 @@ def _create_snaptrade_provider(**config: Any) -> InvestmentProvider:
|
|
|
233
234
|
"Example: easy_investments(provider='snaptrade', client_id='...', consumer_key='...')"
|
|
234
235
|
)
|
|
235
236
|
|
|
237
|
+
# Ensure base_url is a string (default is set in SnapTradeInvestmentProvider)
|
|
238
|
+
resolved_base_url: str = base_url if isinstance(base_url, str) else "https://api.snaptrade.com/api/v1"
|
|
239
|
+
|
|
236
240
|
return SnapTradeInvestmentProvider(
|
|
237
241
|
client_id=client_id,
|
|
238
242
|
consumer_key=consumer_key,
|
|
239
|
-
base_url=
|
|
243
|
+
base_url=resolved_base_url,
|
|
240
244
|
)
|
|
241
245
|
|
|
242
246
|
|
|
@@ -370,7 +370,7 @@ class PlaidInvestmentProvider(InvestmentProvider):
|
|
|
370
370
|
isin=plaid_security.get("isin"),
|
|
371
371
|
sedol=plaid_security.get("sedol"),
|
|
372
372
|
ticker_symbol=plaid_security.get("ticker_symbol"),
|
|
373
|
-
name=plaid_security.get("name"),
|
|
373
|
+
name=plaid_security.get("name") or "Unknown Security",
|
|
374
374
|
type=self._normalize_security_type(plaid_security.get("type", "other")),
|
|
375
375
|
sector=plaid_security.get("sector"),
|
|
376
376
|
close_price=close_price,
|
|
@@ -193,7 +193,11 @@ def add_market_data(
|
|
|
193
193
|
if isinstance(provider, MarketDataProvider):
|
|
194
194
|
market = provider
|
|
195
195
|
else:
|
|
196
|
-
|
|
196
|
+
# Cast provider to Literal type for type checker
|
|
197
|
+
provider_literal: Literal["alphavantage", "yahoo"] | None = (
|
|
198
|
+
provider if provider in ("alphavantage", "yahoo", None) else None # type: ignore[assignment]
|
|
199
|
+
)
|
|
200
|
+
market = easy_market(provider=provider_literal, **config)
|
|
197
201
|
|
|
198
202
|
# Create router (public - no auth required)
|
|
199
203
|
router = public_router(prefix=prefix, tags=["Market Data"])
|
|
@@ -223,14 +227,15 @@ def add_market_data(
|
|
|
223
227
|
try:
|
|
224
228
|
candles = market.history(symbol, period=period, interval=interval)
|
|
225
229
|
# Convert to dicts if they're Pydantic models
|
|
226
|
-
candles_list = []
|
|
230
|
+
candles_list: list[dict] = []
|
|
227
231
|
for candle in candles:
|
|
228
232
|
if hasattr(candle, "model_dump"):
|
|
229
233
|
candles_list.append(candle.model_dump())
|
|
230
234
|
elif hasattr(candle, "dict"):
|
|
231
235
|
candles_list.append(candle.dict())
|
|
232
236
|
else:
|
|
233
|
-
|
|
237
|
+
# Cast to dict for type compatibility
|
|
238
|
+
candles_list.append(dict(candle) if hasattr(candle, "__iter__") else {"data": candle})
|
|
234
239
|
return {"candles": candles_list}
|
|
235
240
|
except Exception as e:
|
|
236
241
|
raise HTTPException(status_code=400, detail=str(e))
|
|
@@ -93,7 +93,13 @@ class TellerClient(BankingProvider):
|
|
|
93
93
|
ssl_context.load_cert_chain(certfile=cert_path, keyfile=key_path)
|
|
94
94
|
client_kwargs["verify"] = ssl_context
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
# Create client with explicit parameters to satisfy type checker
|
|
97
|
+
self.client = httpx.Client(
|
|
98
|
+
base_url=str(client_kwargs["base_url"]),
|
|
99
|
+
timeout=float(client_kwargs["timeout"]), # type: ignore[arg-type]
|
|
100
|
+
headers=client_kwargs["headers"], # type: ignore[arg-type]
|
|
101
|
+
verify=client_kwargs.get("verify", True), # type: ignore[arg-type]
|
|
102
|
+
)
|
|
97
103
|
|
|
98
104
|
def _request(self, method: str, path: str, **kwargs: Any) -> Any:
|
|
99
105
|
"""Make HTTP request to Teller API with error handling.
|
|
@@ -313,9 +313,9 @@ class MockTaxProvider(TaxProvider):
|
|
|
313
313
|
return CryptoTaxReport(
|
|
314
314
|
user_id=user_id,
|
|
315
315
|
tax_year=tax_year,
|
|
316
|
-
total_gain_loss=short_term + long_term,
|
|
317
|
-
short_term_gain_loss=short_term,
|
|
318
|
-
long_term_gain_loss=long_term,
|
|
316
|
+
total_gain_loss=Decimal(short_term + long_term),
|
|
317
|
+
short_term_gain_loss=Decimal(short_term),
|
|
318
|
+
long_term_gain_loss=Decimal(long_term),
|
|
319
319
|
transaction_count=len(crypto_transactions),
|
|
320
320
|
cost_basis_method=cost_basis_method,
|
|
321
321
|
transactions=crypto_transactions,
|
|
@@ -162,7 +162,9 @@ async def get_provider_token(
|
|
|
162
162
|
|
|
163
163
|
# Decrypt token
|
|
164
164
|
context = {"user_id": user_id, "provider": provider}
|
|
165
|
-
|
|
165
|
+
# Cast to str since SQLAlchemy Column[str] needs explicit conversion for type checker
|
|
166
|
+
encrypted_token_str: str = str(token_obj.encrypted_token)
|
|
167
|
+
token = encryption.decrypt(encrypted_token_str, context=context)
|
|
166
168
|
|
|
167
169
|
# Update last_used_at
|
|
168
170
|
update_stmt = (
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/scaffold_templates/models.py.tmpl
RENAMED
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/scaffold_templates/repository.py.tmpl
RENAMED
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/budgets/scaffold_templates/schemas.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/scaffold_templates/repository.py.tmpl
RENAMED
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/goals/scaffold_templates/schemas.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/README.md
RENAMED
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/__init__.py
RENAMED
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/models.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/investments/scaffold_templates/schemas.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/__init__.py
RENAMED
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/models.py.tmpl
RENAMED
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/repository.py.tmpl
RENAMED
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/net_worth/scaffold_templates/schemas.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fin_infra-0.1.63 → fin_infra-0.1.64}/src/fin_infra/normalization/providers/static_mappings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|