sovai 0.2.55__tar.gz → 0.2.57__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.
- {sovai-0.2.55 → sovai-0.2.57}/PKG-INFO +1 -1
- {sovai-0.2.55 → sovai-0.2.57}/pyproject.toml +1 -1
- sovai-0.2.57/sovai/__init__.py +167 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side_s3_part_high.py +87 -39
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/file_management.py +7 -0
- sovai-0.2.55/sovai/__init__.py +0 -43
- {sovai-0.2.55 → sovai-0.2.57}/LICENSE +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/README.md +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/data/codes.parq +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/data/tickers.parq +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/.DS_Store +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/api_config.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/assets/dropdown.css +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/assets/features_mapping.parq +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/basic_auth.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/computations/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/computations/functions.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/errors/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/errors/sovai_errors.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/anomalies.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/ask_df_llm.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/change_point_generator.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/clustering.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/core_kshape.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/cum_sum_torch.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/cusum.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/dimensionality_reduction.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/feature_extraction.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/feature_importance.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/feature_neutralizer.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/filter_df.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/fractional_differencing.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/nowcasting.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/pairwise.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/pandas_extensions.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/parallel_functions.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/pfa_feature_selector.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/regime_change.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/regime_change_pca.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/shapley_global_importance.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/shapley_importance.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/signal_evaluation.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/technical_indicators.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/time_decomposition.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/weight_optimization.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/get_compute.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/get_data copy.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/get_data.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/get_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/get_reports.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/get_tools.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/accounting/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/accounting/accounting_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/allocation/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/allocation/allocation_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/bankruptcy/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/breakout/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/breakout/breakout_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/corp_risk/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/earnings_surprise/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/insider/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/insider/insider_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/institutional/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/institutional/institutional_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/news/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/news/news_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/ratios/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/ratios/ratios_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/accounting/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/bankruptcy/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/general/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/general/general_plots.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/news/__inti__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/news/news_econometric_analysis.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/studies/nowcasting.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/token_auth.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/authentication/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/authentication/authentication.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/graphs.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/llm_code_generator.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/sec_edgar_search.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/__init__.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side_s3.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side_s3_part_high copy 2.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side_s3_part_high copy.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/converter.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/datetime_formats.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/get_tickers.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/helpers.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/pandas_extensions copy.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/plot.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/port_manager.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/stream.py +0 -0
- {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/verbose_utils.py +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main SovAI SDK Tool Kit package
|
|
3
|
+
"""
|
|
4
|
+
from .api_config import read_key, save_key, ApiConfig
|
|
5
|
+
from .basic_auth import basic_auth
|
|
6
|
+
from .token_auth import token_auth
|
|
7
|
+
from .utils.file_management import update_data_files # Keep update_data_files import
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import warnings
|
|
11
|
+
warnings.filterwarnings("ignore")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from importlib.metadata import version
|
|
16
|
+
__version__ = version("sovai")
|
|
17
|
+
except:
|
|
18
|
+
__version__ = "0.2.49" # Fallback to current version in pyproject.toml
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Lazy loading for core modules
|
|
22
|
+
_data_module = None
|
|
23
|
+
|
|
24
|
+
def data(*args, **kwargs):
|
|
25
|
+
"""Lazy-loaded access to the data function."""
|
|
26
|
+
global _data_module
|
|
27
|
+
if _data_module is None:
|
|
28
|
+
from .get_data import data as _loaded_data
|
|
29
|
+
_data_module = _loaded_data
|
|
30
|
+
return _data_module(*args, **kwargs)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Lazy loading for full installation modules
|
|
34
|
+
HAS_FULL_INSTALL = False
|
|
35
|
+
_plot_module = None
|
|
36
|
+
_report_module = None
|
|
37
|
+
_compute_module = None
|
|
38
|
+
_nowcast_module = None
|
|
39
|
+
_extension_module = None
|
|
40
|
+
_sec_search_module = None
|
|
41
|
+
_sec_filing_module = None
|
|
42
|
+
_code_module = None
|
|
43
|
+
_sec_graph_module = None
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
# Attempt to import a module from the full installation to check if it's installed
|
|
47
|
+
# This import is just to check for ImportError, the actual function is lazy-loaded below
|
|
48
|
+
from .get_plots import plot as _ # Use _ to indicate this import is just for the check
|
|
49
|
+
HAS_FULL_INSTALL = True
|
|
50
|
+
|
|
51
|
+
def plot(*args, **kwargs):
|
|
52
|
+
"""Lazy-loaded access to the plot function."""
|
|
53
|
+
global _plot_module
|
|
54
|
+
if _plot_module is None:
|
|
55
|
+
from .get_plots import plot as _loaded_plot
|
|
56
|
+
_plot_module = _loaded_plot
|
|
57
|
+
return _plot_module(*args, **kwargs)
|
|
58
|
+
|
|
59
|
+
def report(*args, **kwargs):
|
|
60
|
+
"""Lazy-loaded access to the report function."""
|
|
61
|
+
global _report_module
|
|
62
|
+
if _report_module is None:
|
|
63
|
+
from .get_reports import report as _loaded_report
|
|
64
|
+
_report_module = _loaded_report
|
|
65
|
+
return _report_module(*args, **kwargs)
|
|
66
|
+
|
|
67
|
+
def compute(*args, **kwargs):
|
|
68
|
+
"""Lazy-loaded access to the compute function."""
|
|
69
|
+
global _compute_module
|
|
70
|
+
if _compute_module is None:
|
|
71
|
+
from .get_compute import compute as _loaded_compute
|
|
72
|
+
_compute_module = _loaded_compute
|
|
73
|
+
return _compute_module(*args, **kwargs)
|
|
74
|
+
|
|
75
|
+
def nowcast(*args, **kwargs):
|
|
76
|
+
"""Lazy-loaded access to the nowcast function."""
|
|
77
|
+
global _nowcast_module
|
|
78
|
+
if _nowcast_module is None:
|
|
79
|
+
from .studies.nowcasting import nowcast as _loaded_nowcast
|
|
80
|
+
_nowcast_module = _loaded_nowcast
|
|
81
|
+
return _nowcast_module(*args, **kwargs)
|
|
82
|
+
|
|
83
|
+
# extension is likely a class, so the lazy loader needs to return the class itself
|
|
84
|
+
def extension(*args, **kwargs):
|
|
85
|
+
"""Lazy-loaded access to the CustomDataFrame extension class."""
|
|
86
|
+
global _extension_module
|
|
87
|
+
if _extension_module is None:
|
|
88
|
+
from .extensions.pandas_extensions import CustomDataFrame as _loaded_extension
|
|
89
|
+
_extension_module = _loaded_extension
|
|
90
|
+
# If called with args/kwargs, assume it's being instantiated
|
|
91
|
+
if args or kwargs:
|
|
92
|
+
return _extension_module(*args, **kwargs)
|
|
93
|
+
# Otherwise, return the class itself (e.g., for type checking or accessing class methods)
|
|
94
|
+
return _extension_module
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def sec_search(*args, **kwargs):
|
|
98
|
+
"""Lazy-loaded access to the sec_search function."""
|
|
99
|
+
global _sec_search_module
|
|
100
|
+
if _sec_search_module is None:
|
|
101
|
+
from .get_tools import sec_search as _loaded_sec_search
|
|
102
|
+
_sec_search_module = _loaded_sec_search
|
|
103
|
+
return _sec_search_module(*args, **kwargs)
|
|
104
|
+
|
|
105
|
+
def sec_filing(*args, **kwargs):
|
|
106
|
+
"""Lazy-loaded access to the sec_filing function."""
|
|
107
|
+
global _sec_filing_module
|
|
108
|
+
if _sec_filing_module is None:
|
|
109
|
+
from .get_tools import sec_filing as _loaded_sec_filing
|
|
110
|
+
_sec_filing_module = _loaded_sec_filing
|
|
111
|
+
return _sec_filing_module(*args, **kwargs)
|
|
112
|
+
|
|
113
|
+
def code(*args, **kwargs):
|
|
114
|
+
"""Lazy-loaded access to the code function."""
|
|
115
|
+
global _code_module
|
|
116
|
+
if _code_module is None:
|
|
117
|
+
from .get_tools import code as _loaded_code
|
|
118
|
+
_code_module = _loaded_code
|
|
119
|
+
return _code_module(*args, **kwargs)
|
|
120
|
+
|
|
121
|
+
def sec_graph(*args, **kwargs):
|
|
122
|
+
"""Lazy-loaded access to the sec_graph function."""
|
|
123
|
+
global _sec_graph_module
|
|
124
|
+
if _sec_graph_module is None:
|
|
125
|
+
from .get_tools import sec_graph as _loaded_sec_graph
|
|
126
|
+
_sec_graph_module = _loaded_sec_graph
|
|
127
|
+
return _sec_graph_module(*args, **kwargs)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
except ImportError as e:
|
|
131
|
+
print("this is the lean installation, for full use sovai[full]")
|
|
132
|
+
# print(f"ImportError: {e}")
|
|
133
|
+
HAS_FULL_INSTALL = False
|
|
134
|
+
|
|
135
|
+
# Define dummy functions/objects for lean installation to avoid AttributeErrors
|
|
136
|
+
def plot(*args, **kwargs):
|
|
137
|
+
raise ImportError("Plotting requires the full installation. Install with 'pip install sovai[full]'")
|
|
138
|
+
def report(*args, **kwargs):
|
|
139
|
+
raise ImportError("Reporting requires the full installation. Install with 'pip install sovai[full]'")
|
|
140
|
+
def compute(*args, **kwargs):
|
|
141
|
+
raise ImportError("Compute requires the full installation. Install with 'pip install sovai[full]'")
|
|
142
|
+
def nowcast(*args, **kwargs):
|
|
143
|
+
raise ImportError("Nowcasting requires the full installation. Install with 'pip install sovai[full]'")
|
|
144
|
+
def extension(*args, **kwargs):
|
|
145
|
+
raise ImportError("Extensions require the full installation. Install with 'pip install sovai[full]'")
|
|
146
|
+
def sec_search(*args, **kwargs):
|
|
147
|
+
raise ImportError("SEC tools require the full installation. Install with 'pip install sovai[full]'")
|
|
148
|
+
def sec_filing(*args, **kwargs):
|
|
149
|
+
raise ImportError("SEC tools require the full installation. Install with 'pip install sovai[full]'")
|
|
150
|
+
def code(*args, **kwargs):
|
|
151
|
+
raise ImportError("SEC tools require the full installation. Install with 'pip install sovai[full]'")
|
|
152
|
+
def sec_graph(*args, **kwargs):
|
|
153
|
+
raise ImportError("SEC tools require the full installation. Install with 'pip install sovai[full]'")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
__all__ = [
|
|
157
|
+
'read_key', 'save_key', 'ApiConfig', 'basic_auth', 'token_auth',
|
|
158
|
+
'update_data_files', # Keep update_data_files in __all__
|
|
159
|
+
'data', # Add data to __all__
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
# Add full installation lazy-loaded attributes to __all__ if available
|
|
163
|
+
if HAS_FULL_INSTALL:
|
|
164
|
+
__all__ += [
|
|
165
|
+
'plot', 'report', 'compute', 'nowcast', 'extension',
|
|
166
|
+
'sec_search', 'sec_filing', 'code', 'sec_graph'
|
|
167
|
+
]
|
|
@@ -115,7 +115,7 @@ class PartitionFinder:
|
|
|
115
115
|
|
|
116
116
|
@staticmethod
|
|
117
117
|
def find_ticker_partitions(
|
|
118
|
-
ticker_base_path: str,
|
|
118
|
+
ticker_base_path: str,
|
|
119
119
|
tickers: List[str],
|
|
120
120
|
has_year: bool = True,
|
|
121
121
|
start_year: Optional[int] = None,
|
|
@@ -123,93 +123,141 @@ class PartitionFinder:
|
|
|
123
123
|
) -> List[Tuple[str, str]]:
|
|
124
124
|
"""
|
|
125
125
|
Find all valid ticker partitions with optional year filtering.
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
Args:
|
|
128
128
|
ticker_base_path: Base path to ticker partitions
|
|
129
129
|
tickers: List of tickers to search for
|
|
130
130
|
has_year: Whether ticker partitions include year subdirectories
|
|
131
131
|
start_year: Optional starting year to filter by
|
|
132
132
|
end_year: Optional ending year to filter by
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
Returns:
|
|
135
135
|
List of tuples (path, ticker) for loading
|
|
136
136
|
"""
|
|
137
137
|
fs = get_s3_filesystem()
|
|
138
138
|
partitions = []
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
# Process each ticker
|
|
141
141
|
for ticker in tickers:
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
# Construct the base path for this ticker's partitions
|
|
143
|
+
ticker_path = f"{ticker_base_path}/ticker_partitioned={ticker}" # e.g., .../base/ticker_partitioned=AAPL
|
|
144
|
+
|
|
144
145
|
try:
|
|
145
|
-
# Case 1:
|
|
146
|
+
# Case 1: If the endpoint is configured with has_year=False
|
|
146
147
|
if not has_year:
|
|
148
|
+
# Add the base ticker path directly
|
|
147
149
|
partitions.append((ticker_path, ticker))
|
|
150
|
+
# Move to the next ticker
|
|
148
151
|
continue
|
|
149
|
-
|
|
150
|
-
# Case 2:
|
|
152
|
+
|
|
153
|
+
# Case 2: Endpoint has year partitioning (has_year=True)
|
|
154
|
+
# Call _extract_years. If start_year/end_year are None,
|
|
155
|
+
# _extract_years is responsible for returning ALL found years.
|
|
156
|
+
# If start_year/end_year have values, it returns filtered years.
|
|
157
|
+
verbose_mode.log(f"Extracting years for {ticker} at {ticker_path} (Range: {start_year}-{end_year})")
|
|
151
158
|
years = PartitionFinder._extract_years(
|
|
152
159
|
fs, ticker_path, start_year, end_year
|
|
153
160
|
)
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
verbose_mode.log(f"Found years for {ticker}: {years}")
|
|
162
|
+
|
|
163
|
+
# Generate specific year paths for EACH year returned by _extract_years
|
|
164
|
+
# If start_year/end_year were None, 'years' should contain ALL available years.
|
|
165
|
+
# If start_year/end_year were set, 'years' contains only the filtered years.
|
|
156
166
|
for year in years:
|
|
157
|
-
year_path = f"{ticker_path}/year={year}"
|
|
167
|
+
year_path = f"{ticker_path}/year={year}" # e.g., .../base/ticker_partitioned=AAPL/year=2023
|
|
158
168
|
partitions.append((year_path, ticker))
|
|
159
|
-
|
|
160
|
-
|
|
169
|
+
verbose_mode.log(f"Added partition task for: {year_path}")
|
|
170
|
+
|
|
171
|
+
# Fallback: This only runs if _extract_years found NO years AND a specific range WAS given.
|
|
172
|
+
# It does NOT run if start_year/end_year were None.
|
|
161
173
|
if not years and start_year and end_year:
|
|
174
|
+
verbose_mode.log(f"No years found via listing for {ticker} in range {start_year}-{end_year}. Constructing paths based on range.")
|
|
162
175
|
for year in range(start_year, end_year + 1):
|
|
163
176
|
year_path = f"{ticker_path}/year={year}"
|
|
177
|
+
# Note: These paths might not actually exist.
|
|
164
178
|
partitions.append((year_path, ticker))
|
|
165
|
-
|
|
179
|
+
verbose_mode.log(f"Added potential partition task (fallback): {year_path}")
|
|
180
|
+
|
|
166
181
|
except Exception as e:
|
|
167
|
-
|
|
168
|
-
|
|
182
|
+
# Log errors encountered for a specific ticker
|
|
183
|
+
logger.error(f"Error processing ticker {ticker} at path {ticker_path}: {e}", exc_info=True) # Use logger.error
|
|
184
|
+
|
|
169
185
|
if not partitions:
|
|
170
|
-
|
|
171
|
-
|
|
186
|
+
# Log if no partitions were found across ALL requested tickers matching the criteria
|
|
187
|
+
logger.warning(f"No ticker partitions ultimately found matching criteria. Base Path: {ticker_base_path}, Tickers: {tickers}, Has Year: {has_year}, Year Range: {start_year}-{end_year}") # Use logger.warning
|
|
188
|
+
|
|
172
189
|
return partitions
|
|
173
190
|
|
|
174
191
|
@staticmethod
|
|
175
192
|
def _extract_years(
|
|
176
|
-
fs: S3FileSystem,
|
|
177
|
-
ticker_path: str,
|
|
178
|
-
start_year: Optional[int],
|
|
193
|
+
fs: S3FileSystem,
|
|
194
|
+
ticker_path: str,
|
|
195
|
+
start_year: Optional[int],
|
|
179
196
|
end_year: Optional[int]
|
|
180
197
|
) -> List[int]:
|
|
181
198
|
"""
|
|
182
|
-
Extract valid years from ticker subdirectories.
|
|
183
|
-
|
|
199
|
+
Extract valid years from ticker subdirectories. [CORRECTED VERSION]
|
|
200
|
+
|
|
184
201
|
Args:
|
|
185
202
|
fs: S3 filesystem
|
|
186
|
-
ticker_path: Path to search for year directories
|
|
203
|
+
ticker_path: Path to search for year directories (e.g., .../ticker_partitioned=PFE)
|
|
187
204
|
start_year: Optional starting year filter
|
|
188
205
|
end_year: Optional ending year filter
|
|
189
|
-
|
|
206
|
+
|
|
190
207
|
Returns:
|
|
191
|
-
List of valid years within the specified range
|
|
208
|
+
List of valid years within the specified range, sorted.
|
|
192
209
|
"""
|
|
193
210
|
years = []
|
|
194
|
-
|
|
211
|
+
logger.debug(f"[_extract_years] Input: path='{ticker_path}', start={start_year}, end={end_year}")
|
|
195
212
|
try:
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
213
|
+
logger.debug(f"[_extract_years] Listing contents of: {ticker_path} using get_file_info")
|
|
214
|
+
# Correct way to list directory contents using pyarrow fs API
|
|
215
|
+
selector = pa.fs.FileSelector(ticker_path, recursive=False)
|
|
216
|
+
subdirs_info = fs.get_file_info(selector) # Get list of FileInfo objects
|
|
217
|
+
logger.info(f"[_extract_years] Found {len(subdirs_info)} items in '{ticker_path}'")
|
|
218
|
+
|
|
219
|
+
for item_info in subdirs_info:
|
|
220
|
+
# Process only items that are directories
|
|
221
|
+
if item_info.type != pa.fs.FileType.Directory:
|
|
222
|
+
logger.debug(f"[_extract_years] Skipping non-directory item: {item_info.path}")
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
subdir_path = item_info.path
|
|
226
|
+
basename = os.path.basename(subdir_path.rstrip('/')) # Get last component
|
|
227
|
+
logger.debug(f"[_extract_years] Processing directory item: '{basename}'")
|
|
228
|
+
|
|
199
229
|
if basename.startswith('year='):
|
|
200
|
-
|
|
230
|
+
logger.debug(f"[_extract_years] Found potential year directory: {basename}")
|
|
231
|
+
year_str = basename.split('=', 1)[1] # Extract year string
|
|
201
232
|
try:
|
|
202
233
|
year = int(year_str)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
234
|
+
logger.debug(f"[_extract_years] Parsed year: {year}. Checking range: start={start_year}, end={end_year}")
|
|
235
|
+
|
|
236
|
+
# Apply year filtering logic
|
|
237
|
+
start_ok = (start_year is None or year >= start_year)
|
|
238
|
+
end_ok = (end_year is None or year <= end_year)
|
|
239
|
+
logger.debug(f"[_extract_years] Filter check for year {year}: start_ok={start_ok}, end_ok={end_ok}")
|
|
240
|
+
|
|
241
|
+
if start_ok and end_ok:
|
|
242
|
+
logger.info(f"[_extract_years] Year {year} is WITHIN range/criteria. Appending.")
|
|
206
243
|
years.append(year)
|
|
244
|
+
else:
|
|
245
|
+
logger.debug(f"[_extract_years] Year {year} is OUTSIDE range. Skipping.")
|
|
246
|
+
|
|
207
247
|
except ValueError:
|
|
208
|
-
|
|
248
|
+
logger.warning(f"[_extract_years] Invalid year format: '{year_str}' in path {subdir_path}")
|
|
249
|
+
else:
|
|
250
|
+
logger.debug(f"[_extract_years] Directory '{basename}' does not start with 'year='. Skipping.")
|
|
251
|
+
|
|
252
|
+
except FileNotFoundError:
|
|
253
|
+
# If the base ticker_path itself doesn't exist
|
|
254
|
+
logger.warning(f"[_extract_years] Directory not found for listing: {ticker_path}")
|
|
209
255
|
except Exception as e:
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
256
|
+
# Catch any other errors during listing/processing
|
|
257
|
+
logger.error(f"[_extract_years] Error listing or processing directory {ticker_path}: {e}", exc_info=True)
|
|
258
|
+
|
|
259
|
+
logger.info(f"[_extract_years] Returning extracted years: {sorted(years)} for path '{ticker_path}'")
|
|
260
|
+
return sorted(years)
|
|
213
261
|
|
|
214
262
|
@staticmethod
|
|
215
263
|
def find_date_partitions(
|
|
@@ -70,3 +70,10 @@ def save_or_update_codes():
|
|
|
70
70
|
codes_meta = pd.read_parquet(download_url)
|
|
71
71
|
codes_meta.to_parquet(output_path)
|
|
72
72
|
|
|
73
|
+
|
|
74
|
+
def update_data_files():
|
|
75
|
+
"""
|
|
76
|
+
Manually updates the tickers and codes data files if they are outdated.
|
|
77
|
+
"""
|
|
78
|
+
save_or_update_tickers()
|
|
79
|
+
save_or_update_codes()
|
sovai-0.2.55/sovai/__init__.py
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Main SovAI SDK Tool Kit package
|
|
3
|
-
"""
|
|
4
|
-
from .api_config import read_key, save_key, ApiConfig
|
|
5
|
-
from .get_data import data
|
|
6
|
-
from .basic_auth import basic_auth
|
|
7
|
-
from .token_auth import token_auth
|
|
8
|
-
from .utils.file_management import save_or_update_tickers, save_or_update_codes
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import warnings
|
|
12
|
-
warnings.filterwarnings("ignore")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
try:
|
|
16
|
-
from importlib.metadata import version
|
|
17
|
-
__version__ = version("sovai")
|
|
18
|
-
except:
|
|
19
|
-
__version__ = "0.2.49" # Fallback to current version in pyproject.toml
|
|
20
|
-
|
|
21
|
-
# Call the function to ensure tickers data is up-to-date
|
|
22
|
-
save_or_update_tickers()
|
|
23
|
-
|
|
24
|
-
save_or_update_codes()
|
|
25
|
-
|
|
26
|
-
try:
|
|
27
|
-
from .get_plots import plot
|
|
28
|
-
from .get_reports import report
|
|
29
|
-
from .get_compute import compute
|
|
30
|
-
from .studies.nowcasting import nowcast
|
|
31
|
-
from .extensions.pandas_extensions import CustomDataFrame as extension
|
|
32
|
-
from .get_tools import sec_search, sec_filing, code, sec_graph
|
|
33
|
-
HAS_FULL_INSTALL = True
|
|
34
|
-
except ImportError as e:
|
|
35
|
-
print("this is the lean installation, for full use sovai[full]")
|
|
36
|
-
# print(f"ImportError: {e}")
|
|
37
|
-
HAS_FULL_INSTALL = False
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
__all__ = ['read_key', 'save_key', 'ApiConfig', 'data', 'basic_auth', 'token_auth']
|
|
41
|
-
|
|
42
|
-
if HAS_FULL_INSTALL:
|
|
43
|
-
__all__ += ['plot', 'report', 'compute', 'nowcast', 'extension', 'sec_search', 'sec_filing', 'code', 'sec_graph']
|
|
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
|
|
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
|