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.
Files changed (104) hide show
  1. {sovai-0.2.55 → sovai-0.2.57}/PKG-INFO +1 -1
  2. {sovai-0.2.55 → sovai-0.2.57}/pyproject.toml +1 -1
  3. sovai-0.2.57/sovai/__init__.py +167 -0
  4. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side_s3_part_high.py +87 -39
  5. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/file_management.py +7 -0
  6. sovai-0.2.55/sovai/__init__.py +0 -43
  7. {sovai-0.2.55 → sovai-0.2.57}/LICENSE +0 -0
  8. {sovai-0.2.55 → sovai-0.2.57}/README.md +0 -0
  9. {sovai-0.2.55 → sovai-0.2.57}/data/codes.parq +0 -0
  10. {sovai-0.2.55 → sovai-0.2.57}/data/tickers.parq +0 -0
  11. {sovai-0.2.55 → sovai-0.2.57}/sovai/.DS_Store +0 -0
  12. {sovai-0.2.55 → sovai-0.2.57}/sovai/api_config.py +0 -0
  13. {sovai-0.2.55 → sovai-0.2.57}/sovai/assets/dropdown.css +0 -0
  14. {sovai-0.2.55 → sovai-0.2.57}/sovai/assets/features_mapping.parq +0 -0
  15. {sovai-0.2.55 → sovai-0.2.57}/sovai/basic_auth.py +0 -0
  16. {sovai-0.2.55 → sovai-0.2.57}/sovai/computations/__init__.py +0 -0
  17. {sovai-0.2.55 → sovai-0.2.57}/sovai/computations/functions.py +0 -0
  18. {sovai-0.2.55 → sovai-0.2.57}/sovai/errors/__init__.py +0 -0
  19. {sovai-0.2.55 → sovai-0.2.57}/sovai/errors/sovai_errors.py +0 -0
  20. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/__init__.py +0 -0
  21. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/anomalies.py +0 -0
  22. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/ask_df_llm.py +0 -0
  23. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/change_point_generator.py +0 -0
  24. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/clustering.py +0 -0
  25. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/core_kshape.py +0 -0
  26. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/cum_sum_torch.py +0 -0
  27. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/cusum.py +0 -0
  28. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/dimensionality_reduction.py +0 -0
  29. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/feature_extraction.py +0 -0
  30. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/feature_importance.py +0 -0
  31. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/feature_neutralizer.py +0 -0
  32. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/filter_df.py +0 -0
  33. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/fractional_differencing.py +0 -0
  34. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/nowcasting.py +0 -0
  35. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/pairwise.py +0 -0
  36. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/pandas_extensions.py +0 -0
  37. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/parallel_functions.py +0 -0
  38. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/pfa_feature_selector.py +0 -0
  39. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/regime_change.py +0 -0
  40. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/regime_change_pca.py +0 -0
  41. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/shapley_global_importance.py +0 -0
  42. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/shapley_importance.py +0 -0
  43. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/signal_evaluation.py +0 -0
  44. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/technical_indicators.py +0 -0
  45. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/time_decomposition.py +0 -0
  46. {sovai-0.2.55 → sovai-0.2.57}/sovai/extensions/weight_optimization.py +0 -0
  47. {sovai-0.2.55 → sovai-0.2.57}/sovai/get_compute.py +0 -0
  48. {sovai-0.2.55 → sovai-0.2.57}/sovai/get_data copy.py +0 -0
  49. {sovai-0.2.55 → sovai-0.2.57}/sovai/get_data.py +0 -0
  50. {sovai-0.2.55 → sovai-0.2.57}/sovai/get_plots.py +0 -0
  51. {sovai-0.2.55 → sovai-0.2.57}/sovai/get_reports.py +0 -0
  52. {sovai-0.2.55 → sovai-0.2.57}/sovai/get_tools.py +0 -0
  53. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/__init__.py +0 -0
  54. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/accounting/__init__.py +0 -0
  55. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/accounting/accounting_plots.py +0 -0
  56. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/allocation/__init__.py +0 -0
  57. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/allocation/allocation_plots.py +0 -0
  58. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/bankruptcy/__init__.py +0 -0
  59. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
  60. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/breakout/__init__.py +0 -0
  61. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/breakout/breakout_plots.py +0 -0
  62. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/corp_risk/__init__.py +0 -0
  63. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
  64. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/earnings_surprise/__init__.py +0 -0
  65. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
  66. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/insider/__init__.py +0 -0
  67. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/insider/insider_plots.py +0 -0
  68. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/institutional/__init__.py +0 -0
  69. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/institutional/institutional_plots.py +0 -0
  70. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/news/__init__.py +0 -0
  71. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/news/news_plots.py +0 -0
  72. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/ratios/__init__.py +0 -0
  73. {sovai-0.2.55 → sovai-0.2.57}/sovai/plots/ratios/ratios_plots.py +0 -0
  74. {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/accounting/__init__.py +0 -0
  75. {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
  76. {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/bankruptcy/__init__.py +0 -0
  77. {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
  78. {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/general/__init__.py +0 -0
  79. {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/general/general_plots.py +0 -0
  80. {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/news/__inti__.py +0 -0
  81. {sovai-0.2.55 → sovai-0.2.57}/sovai/reports/news/news_econometric_analysis.py +0 -0
  82. {sovai-0.2.55 → sovai-0.2.57}/sovai/studies/nowcasting.py +0 -0
  83. {sovai-0.2.55 → sovai-0.2.57}/sovai/token_auth.py +0 -0
  84. {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/authentication/__init__.py +0 -0
  85. {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/authentication/authentication.py +0 -0
  86. {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/__init__.py +0 -0
  87. {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/graphs.py +0 -0
  88. {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/llm_code_generator.py +0 -0
  89. {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
  90. {sovai-0.2.55 → sovai-0.2.57}/sovai/tools/sec/sec_edgar_search.py +0 -0
  91. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/__init__.py +0 -0
  92. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side.py +0 -0
  93. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side_s3.py +0 -0
  94. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side_s3_part_high copy 2.py +0 -0
  95. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/client_side_s3_part_high copy.py +0 -0
  96. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/converter.py +0 -0
  97. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/datetime_formats.py +0 -0
  98. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/get_tickers.py +0 -0
  99. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/helpers.py +0 -0
  100. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/pandas_extensions copy.py +0 -0
  101. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/plot.py +0 -0
  102. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/port_manager.py +0 -0
  103. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/stream.py +0 -0
  104. {sovai-0.2.55 → sovai-0.2.57}/sovai/utils/verbose_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sovai
3
- Version: 0.2.55
3
+ Version: 0.2.57
4
4
  Summary: python for asset management
5
5
  License: Proprietary License
6
6
  Author: Derek Snow
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "sovai"
7
- version = "0.2.55"
7
+ version = "0.2.57"
8
8
  description = "python for asset management"
9
9
  authors = [
10
10
  {name = "Derek Snow", email = "d.snow@outlook.com"}
@@ -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
- ticker_path = f"{ticker_base_path}/ticker_partitioned={ticker}"
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: No year partitioning
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: Year partitioning
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
- # Generate specific year paths
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
- # If no years found but we know they exist, generate paths for requested years
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
- verbose_mode.log(f"Error processing ticker {ticker}: {e}")
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
- verbose_mode.log(f"No ticker partitions found at {ticker_base_path} for tickers {tickers}")
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
- subdirs = fs.ls(ticker_path)
197
- for subdir in subdirs:
198
- basename = os.path.basename(subdir.rstrip('/'))
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
- year_str = basename.split('=')[1]
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
- # Apply year filtering if needed
204
- if ((start_year is None or year >= start_year) and
205
- (end_year is None or year <= end_year)):
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
- verbose_mode.log(f"Invalid year format: {year_str}")
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
- verbose_mode.log(f"Error listing years: {e}")
211
-
212
- return years
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()
@@ -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