sovai 0.2.55__tar.gz → 0.2.56__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 (103) hide show
  1. {sovai-0.2.55 → sovai-0.2.56}/PKG-INFO +1 -1
  2. {sovai-0.2.55 → sovai-0.2.56}/pyproject.toml +1 -1
  3. {sovai-0.2.55 → sovai-0.2.56}/sovai/__init__.py +2 -6
  4. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/client_side_s3_part_high.py +87 -39
  5. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/file_management.py +7 -0
  6. {sovai-0.2.55 → sovai-0.2.56}/LICENSE +0 -0
  7. {sovai-0.2.55 → sovai-0.2.56}/README.md +0 -0
  8. {sovai-0.2.55 → sovai-0.2.56}/data/codes.parq +0 -0
  9. {sovai-0.2.55 → sovai-0.2.56}/data/tickers.parq +0 -0
  10. {sovai-0.2.55 → sovai-0.2.56}/sovai/.DS_Store +0 -0
  11. {sovai-0.2.55 → sovai-0.2.56}/sovai/api_config.py +0 -0
  12. {sovai-0.2.55 → sovai-0.2.56}/sovai/assets/dropdown.css +0 -0
  13. {sovai-0.2.55 → sovai-0.2.56}/sovai/assets/features_mapping.parq +0 -0
  14. {sovai-0.2.55 → sovai-0.2.56}/sovai/basic_auth.py +0 -0
  15. {sovai-0.2.55 → sovai-0.2.56}/sovai/computations/__init__.py +0 -0
  16. {sovai-0.2.55 → sovai-0.2.56}/sovai/computations/functions.py +0 -0
  17. {sovai-0.2.55 → sovai-0.2.56}/sovai/errors/__init__.py +0 -0
  18. {sovai-0.2.55 → sovai-0.2.56}/sovai/errors/sovai_errors.py +0 -0
  19. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/__init__.py +0 -0
  20. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/anomalies.py +0 -0
  21. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/ask_df_llm.py +0 -0
  22. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/change_point_generator.py +0 -0
  23. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/clustering.py +0 -0
  24. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/core_kshape.py +0 -0
  25. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/cum_sum_torch.py +0 -0
  26. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/cusum.py +0 -0
  27. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/dimensionality_reduction.py +0 -0
  28. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/feature_extraction.py +0 -0
  29. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/feature_importance.py +0 -0
  30. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/feature_neutralizer.py +0 -0
  31. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/filter_df.py +0 -0
  32. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/fractional_differencing.py +0 -0
  33. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/nowcasting.py +0 -0
  34. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/pairwise.py +0 -0
  35. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/pandas_extensions.py +0 -0
  36. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/parallel_functions.py +0 -0
  37. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/pfa_feature_selector.py +0 -0
  38. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/regime_change.py +0 -0
  39. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/regime_change_pca.py +0 -0
  40. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/shapley_global_importance.py +0 -0
  41. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/shapley_importance.py +0 -0
  42. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/signal_evaluation.py +0 -0
  43. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/technical_indicators.py +0 -0
  44. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/time_decomposition.py +0 -0
  45. {sovai-0.2.55 → sovai-0.2.56}/sovai/extensions/weight_optimization.py +0 -0
  46. {sovai-0.2.55 → sovai-0.2.56}/sovai/get_compute.py +0 -0
  47. {sovai-0.2.55 → sovai-0.2.56}/sovai/get_data copy.py +0 -0
  48. {sovai-0.2.55 → sovai-0.2.56}/sovai/get_data.py +0 -0
  49. {sovai-0.2.55 → sovai-0.2.56}/sovai/get_plots.py +0 -0
  50. {sovai-0.2.55 → sovai-0.2.56}/sovai/get_reports.py +0 -0
  51. {sovai-0.2.55 → sovai-0.2.56}/sovai/get_tools.py +0 -0
  52. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/__init__.py +0 -0
  53. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/accounting/__init__.py +0 -0
  54. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/accounting/accounting_plots.py +0 -0
  55. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/allocation/__init__.py +0 -0
  56. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/allocation/allocation_plots.py +0 -0
  57. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/bankruptcy/__init__.py +0 -0
  58. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
  59. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/breakout/__init__.py +0 -0
  60. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/breakout/breakout_plots.py +0 -0
  61. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/corp_risk/__init__.py +0 -0
  62. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
  63. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/earnings_surprise/__init__.py +0 -0
  64. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
  65. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/insider/__init__.py +0 -0
  66. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/insider/insider_plots.py +0 -0
  67. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/institutional/__init__.py +0 -0
  68. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/institutional/institutional_plots.py +0 -0
  69. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/news/__init__.py +0 -0
  70. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/news/news_plots.py +0 -0
  71. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/ratios/__init__.py +0 -0
  72. {sovai-0.2.55 → sovai-0.2.56}/sovai/plots/ratios/ratios_plots.py +0 -0
  73. {sovai-0.2.55 → sovai-0.2.56}/sovai/reports/accounting/__init__.py +0 -0
  74. {sovai-0.2.55 → sovai-0.2.56}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
  75. {sovai-0.2.55 → sovai-0.2.56}/sovai/reports/bankruptcy/__init__.py +0 -0
  76. {sovai-0.2.55 → sovai-0.2.56}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
  77. {sovai-0.2.55 → sovai-0.2.56}/sovai/reports/general/__init__.py +0 -0
  78. {sovai-0.2.55 → sovai-0.2.56}/sovai/reports/general/general_plots.py +0 -0
  79. {sovai-0.2.55 → sovai-0.2.56}/sovai/reports/news/__inti__.py +0 -0
  80. {sovai-0.2.55 → sovai-0.2.56}/sovai/reports/news/news_econometric_analysis.py +0 -0
  81. {sovai-0.2.55 → sovai-0.2.56}/sovai/studies/nowcasting.py +0 -0
  82. {sovai-0.2.55 → sovai-0.2.56}/sovai/token_auth.py +0 -0
  83. {sovai-0.2.55 → sovai-0.2.56}/sovai/tools/authentication/__init__.py +0 -0
  84. {sovai-0.2.55 → sovai-0.2.56}/sovai/tools/authentication/authentication.py +0 -0
  85. {sovai-0.2.55 → sovai-0.2.56}/sovai/tools/sec/__init__.py +0 -0
  86. {sovai-0.2.55 → sovai-0.2.56}/sovai/tools/sec/graphs.py +0 -0
  87. {sovai-0.2.55 → sovai-0.2.56}/sovai/tools/sec/llm_code_generator.py +0 -0
  88. {sovai-0.2.55 → sovai-0.2.56}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
  89. {sovai-0.2.55 → sovai-0.2.56}/sovai/tools/sec/sec_edgar_search.py +0 -0
  90. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/__init__.py +0 -0
  91. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/client_side.py +0 -0
  92. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/client_side_s3.py +0 -0
  93. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/client_side_s3_part_high copy 2.py +0 -0
  94. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/client_side_s3_part_high copy.py +0 -0
  95. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/converter.py +0 -0
  96. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/datetime_formats.py +0 -0
  97. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/get_tickers.py +0 -0
  98. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/helpers.py +0 -0
  99. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/pandas_extensions copy.py +0 -0
  100. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/plot.py +0 -0
  101. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/port_manager.py +0 -0
  102. {sovai-0.2.55 → sovai-0.2.56}/sovai/utils/stream.py +0 -0
  103. {sovai-0.2.55 → sovai-0.2.56}/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.56
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.56"
8
8
  description = "python for asset management"
9
9
  authors = [
10
10
  {name = "Derek Snow", email = "d.snow@outlook.com"}
@@ -5,7 +5,7 @@ from .api_config import read_key, save_key, ApiConfig
5
5
  from .get_data import data
6
6
  from .basic_auth import basic_auth
7
7
  from .token_auth import token_auth
8
- from .utils.file_management import save_or_update_tickers, save_or_update_codes
8
+ from .utils.file_management import save_or_update_tickers, save_or_update_codes, update_data_files
9
9
 
10
10
 
11
11
  import warnings
@@ -18,10 +18,6 @@ try:
18
18
  except:
19
19
  __version__ = "0.2.49" # Fallback to current version in pyproject.toml
20
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
21
 
26
22
  try:
27
23
  from .get_plots import plot
@@ -37,7 +33,7 @@ except ImportError as e:
37
33
  HAS_FULL_INSTALL = False
38
34
 
39
35
 
40
- __all__ = ['read_key', 'save_key', 'ApiConfig', 'data', 'basic_auth', 'token_auth']
36
+ __all__ = ['read_key', 'save_key', 'ApiConfig', 'data', 'basic_auth', 'token_auth', 'update_data_files']
41
37
 
42
38
  if HAS_FULL_INSTALL:
43
39
  __all__ += ['plot', 'report', 'compute', 'nowcast', 'extension', 'sec_search', 'sec_filing', 'code', 'sec_graph']
@@ -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()
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