sovai 0.2.40__tar.gz → 0.2.42__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 (100) hide show
  1. {sovai-0.2.40 → sovai-0.2.42}/PKG-INFO +4 -1
  2. {sovai-0.2.40 → sovai-0.2.42}/pyproject.toml +4 -3
  3. {sovai-0.2.40 → sovai-0.2.42}/sovai/get_data.py +220 -165
  4. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/client_side_s3_part_high.py +63 -4
  5. {sovai-0.2.40 → sovai-0.2.42}/LICENSE +0 -0
  6. {sovai-0.2.40 → sovai-0.2.42}/README.md +0 -0
  7. {sovai-0.2.40 → sovai-0.2.42}/data/codes.parq +0 -0
  8. {sovai-0.2.40 → sovai-0.2.42}/data/tickers.parq +0 -0
  9. {sovai-0.2.40 → sovai-0.2.42}/sovai/.DS_Store +0 -0
  10. {sovai-0.2.40 → sovai-0.2.42}/sovai/__init__.py +0 -0
  11. {sovai-0.2.40 → sovai-0.2.42}/sovai/api_config.py +0 -0
  12. {sovai-0.2.40 → sovai-0.2.42}/sovai/assets/dropdown.css +0 -0
  13. {sovai-0.2.40 → sovai-0.2.42}/sovai/assets/features_mapping.parq +0 -0
  14. {sovai-0.2.40 → sovai-0.2.42}/sovai/basic_auth.py +0 -0
  15. {sovai-0.2.40 → sovai-0.2.42}/sovai/computations/__init__.py +0 -0
  16. {sovai-0.2.40 → sovai-0.2.42}/sovai/computations/functions.py +0 -0
  17. {sovai-0.2.40 → sovai-0.2.42}/sovai/errors/__init__.py +0 -0
  18. {sovai-0.2.40 → sovai-0.2.42}/sovai/errors/sovai_errors.py +0 -0
  19. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/__init__.py +0 -0
  20. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/anomalies.py +0 -0
  21. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/ask_df_llm.py +0 -0
  22. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/change_point_generator.py +0 -0
  23. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/clustering.py +0 -0
  24. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/core_kshape.py +0 -0
  25. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/cum_sum_torch.py +0 -0
  26. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/cusum.py +0 -0
  27. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/dimensionality_reduction.py +0 -0
  28. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/feature_extraction.py +0 -0
  29. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/feature_importance.py +0 -0
  30. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/feature_neutralizer.py +0 -0
  31. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/filter_df.py +0 -0
  32. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/fractional_differencing.py +0 -0
  33. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/nowcasting.py +0 -0
  34. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/pairwise.py +0 -0
  35. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/pandas_extensions.py +0 -0
  36. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/parallel_functions.py +0 -0
  37. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/pfa_feature_selector.py +0 -0
  38. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/regime_change.py +0 -0
  39. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/regime_change_pca.py +0 -0
  40. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/shapley_global_importance.py +0 -0
  41. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/shapley_importance.py +0 -0
  42. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/signal_evaluation.py +0 -0
  43. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/technical_indicators.py +0 -0
  44. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/time_decomposition.py +0 -0
  45. {sovai-0.2.40 → sovai-0.2.42}/sovai/extensions/weight_optimization.py +0 -0
  46. {sovai-0.2.40 → sovai-0.2.42}/sovai/get_compute.py +0 -0
  47. {sovai-0.2.40 → sovai-0.2.42}/sovai/get_data copy.py +0 -0
  48. {sovai-0.2.40 → sovai-0.2.42}/sovai/get_plots.py +0 -0
  49. {sovai-0.2.40 → sovai-0.2.42}/sovai/get_reports.py +0 -0
  50. {sovai-0.2.40 → sovai-0.2.42}/sovai/get_tools.py +0 -0
  51. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/__init__.py +0 -0
  52. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/accounting/__init__.py +0 -0
  53. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/accounting/accounting_plots.py +0 -0
  54. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/allocation/__init__.py +0 -0
  55. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/allocation/allocation_plots.py +0 -0
  56. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/bankruptcy/__init__.py +0 -0
  57. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
  58. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/breakout/__init__.py +0 -0
  59. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/breakout/breakout_plots.py +0 -0
  60. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/corp_risk/__init__.py +0 -0
  61. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
  62. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/earnings_surprise/__init__.py +0 -0
  63. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
  64. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/insider/__init__.py +0 -0
  65. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/insider/insider_plots.py +0 -0
  66. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/institutional/__init__.py +0 -0
  67. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/institutional/institutional_plots.py +0 -0
  68. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/news/__init__.py +0 -0
  69. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/news/news_plots.py +0 -0
  70. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/ratios/__init__.py +0 -0
  71. {sovai-0.2.40 → sovai-0.2.42}/sovai/plots/ratios/ratios_plots.py +0 -0
  72. {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/accounting/__init__.py +0 -0
  73. {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
  74. {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/bankruptcy/__init__.py +0 -0
  75. {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
  76. {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/general/__init__.py +0 -0
  77. {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/general/general_plots.py +0 -0
  78. {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/news/__inti__.py +0 -0
  79. {sovai-0.2.40 → sovai-0.2.42}/sovai/reports/news/news_econometric_analysis.py +0 -0
  80. {sovai-0.2.40 → sovai-0.2.42}/sovai/studies/nowcasting.py +0 -0
  81. {sovai-0.2.40 → sovai-0.2.42}/sovai/token_auth.py +0 -0
  82. {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/authentication/__init__.py +0 -0
  83. {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/authentication/authentication.py +0 -0
  84. {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/__init__.py +0 -0
  85. {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/graphs.py +0 -0
  86. {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/llm_code_generator.py +0 -0
  87. {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
  88. {sovai-0.2.40 → sovai-0.2.42}/sovai/tools/sec/sec_edgar_search.py +0 -0
  89. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/__init__.py +0 -0
  90. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/client_side.py +0 -0
  91. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/client_side_s3.py +0 -0
  92. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/converter.py +0 -0
  93. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/datetime_formats.py +0 -0
  94. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/file_management.py +0 -0
  95. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/get_tickers.py +0 -0
  96. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/helpers.py +0 -0
  97. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/pandas_extensions copy.py +0 -0
  98. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/plot.py +0 -0
  99. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/port_manager.py +0 -0
  100. {sovai-0.2.40 → sovai-0.2.42}/sovai/utils/stream.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sovai
3
- Version: 0.2.40
3
+ Version: 0.2.42
4
4
  Summary: python for asset management
5
5
  License: Proprietary License
6
6
  Author: Derek Snow
@@ -17,6 +17,9 @@ Requires-Dist: boto3 (>=1.20)
17
17
  Requires-Dist: dash (>=2.0) ; extra == "full"
18
18
  Requires-Dist: dash-bootstrap-components (>=1.6.0) ; extra == "full"
19
19
  Requires-Dist: edgar-tool (>=1.3.3,<2.0.0)
20
+ Requires-Dist: fastapi-cache (>=0.1.0,<0.2.0)
21
+ Requires-Dist: fastapi-cache2[redis] (>=0.2.1,<0.3.0)
22
+ Requires-Dist: gcsfs (>=2024.10.0,<2025.0.0)
20
23
  Requires-Dist: great-tables (>=0.9) ; extra == "full"
21
24
  Requires-Dist: ipywidgets (>=8.1.3) ; extra == "full"
22
25
  Requires-Dist: joblib (>=1.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "sovai"
3
- version = "0.2.40"
3
+ version = "0.2.42"
4
4
  description = "python for asset management"
5
5
  authors = ["Derek Snow <d.snow@outlook.com>"]
6
6
  license = "Proprietary License"
@@ -66,6 +66,9 @@ pyvis = "^0.3.2"
66
66
  networkx = "^3.3"
67
67
  seaborn = "^0.13.2"
68
68
  s3fs = "^2024.10.0"
69
+ gcsfs = "^2024.10.0"
70
+ fastapi-cache = "^0.1.0"
71
+ fastapi-cache2 = {extras = ["redis"], version = "^0.2.1"}
69
72
 
70
73
 
71
74
  [tool.poetry.extras]
@@ -103,5 +106,3 @@ black = "^22.0"
103
106
 
104
107
 
105
108
  [build-system]
106
- requires = ["poetry-core"]
107
- build-backend = "poetry.core.masonry.api"
@@ -23,7 +23,7 @@ import plotly.graph_objects as go
23
23
  # Local imports
24
24
  from sovai.api_config import ApiConfig
25
25
  from sovai.errors.sovai_errors import InvalidInputData
26
- from sovai.utils.converter import convert_data2df
26
+ from sovai.utils.converter import convert_data2df, process_dataframe
27
27
  from sovai.utils.stream import stream_data, stream_data_pyarrow
28
28
  from sovai.utils.datetime_formats import datetime_format
29
29
  from sovai.utils.client_side import client_side_frame
@@ -307,7 +307,7 @@ ENDPOINT_TO_TICKER = {
307
307
  "/news/activeness": "",
308
308
  "/news/pronouns": "",
309
309
  "/news/word_count": "",
310
- "/news/sentiment_score": None,
310
+ "/news/sentiment_score": "", # was None before?
311
311
  "/insider/trading": "",
312
312
  "/wikipedia/views": "",
313
313
  "/accounting/weekly": "",
@@ -343,7 +343,9 @@ ENDPOINT_TO_TICKER = {
343
343
 
344
344
  "/patents/applications": "",
345
345
  "/patents/grants": "",
346
- "/clinical_trials": "",
346
+
347
+ "/clinical/trials": "",
348
+
347
349
  "/spending/awards": "",
348
350
  "/spending/compensation": "",
349
351
  "/spending/competition": "",
@@ -358,11 +360,11 @@ ENDPOINT_TO_TICKER = {
358
360
 
359
361
  # Define endpoint sets for different processing methods
360
362
  CLIENT_SIDE_ENDPOINTS_GCS = {
361
- "ratios/relative",
363
+ # "ratios/relative",
362
364
  "market/prices",
363
365
  "market/closeadj",
364
366
  "short/volume",
365
- "complaints/public",
367
+ # "complaints/public",
366
368
  "complaints/private",
367
369
  "lobbying/public",
368
370
  }
@@ -379,7 +381,10 @@ CLIENT_SIDE_ENDPOINTS_S3 = {
379
381
  CLIENT_SIDE_ENDPOINTS_S3_PART_HIGH = {
380
382
  "patents/applications",
381
383
  "patents/grants",
382
- "clinical_trials",
384
+
385
+ "clinical/trials",
386
+
387
+
383
388
  "spending/awards",
384
389
  "spending/compensation",
385
390
  "spending/competition",
@@ -387,8 +392,29 @@ CLIENT_SIDE_ENDPOINTS_S3_PART_HIGH = {
387
392
  "spending/entities",
388
393
  "spending/location",
389
394
  "spending/product",
395
+
390
396
  "spending/transactions",
391
- "lobbying/data"
397
+ "lobbying/data",
398
+
399
+ "accounting/weekly",
400
+ "ratios/normal",
401
+ "ratios/relative",
402
+
403
+ "complaints/public",
404
+
405
+ "factors/accounting",
406
+ "factors/alternative",
407
+ "factors/comprehensive",
408
+ "factors/coefficients",
409
+ "factors/standard_errors",
410
+ "factors/t_statistics",
411
+ "factors/model_metrics",
412
+
413
+ "breakout",
414
+
415
+ "corprisk/risks",
416
+
417
+ "visas/h1b"
392
418
  }
393
419
 
394
420
 
@@ -999,7 +1025,6 @@ def get_api_handler() -> ApiRequestHandler:
999
1025
  logger=logger
1000
1026
  )
1001
1027
 
1002
-
1003
1028
  def data(
1004
1029
  endpoint: str,
1005
1030
  tickers: Optional[Union[str, List[str]]] = None,
@@ -1018,6 +1043,7 @@ def data(
1018
1043
  frequency: Optional[str] = None,
1019
1044
  verbose: bool = False,
1020
1045
  full_history: bool = False,
1046
+ source: Optional[str] = None,
1021
1047
  ) -> Union[DataFrameType, go.Figure, None]:
1022
1048
  """
1023
1049
  Main function to retrieve data from the API.
@@ -1057,6 +1083,8 @@ def data(
1057
1083
  # Set verbose mode based on parameter
1058
1084
  verbose_mode.toggle_verbose(verbose)
1059
1085
  verbose_mode.log(f"Starting data request for endpoint: {endpoint}")
1086
+
1087
+ result_data = None # Initialize the return value
1060
1088
 
1061
1089
  # Initialize and process parameters
1062
1090
  params = params or {}
@@ -1081,6 +1109,7 @@ def data(
1081
1109
  parquet=params.get("parquet", parquet),
1082
1110
  frequency=params.get("frequency", frequency),
1083
1111
  full_history=params.get("full_history", full_history),
1112
+ source=params.get("source", source), # Add source parameter here
1084
1113
  )
1085
1114
  )
1086
1115
  except Exception as e:
@@ -1109,169 +1138,195 @@ def data(
1109
1138
 
1110
1139
  if not purge_cache and cache_key in _query_cache:
1111
1140
  verbose_mode.log("Using cached data")
1112
- return _query_cache[cache_key]
1113
-
1114
- # Process normalized endpoint for handler matching
1115
- normalized_endpoint = normalize_endpoint(endpoint)
1116
-
1117
- # Try client-side handlers for specific endpoints
1118
- for endpoint_set, handler_func, message in ENDPOINT_HANDLERS:
1119
- if (
1120
- normalized_endpoint in endpoint_set and
1121
- (tickers is not None or start_date is not None or end_date is not None) and
1122
- frequency is None
1123
- ):
1124
- verbose_mode.log(message)
1125
- verbose_mode.log(f"Calling client-side handler with tickers={tickers}, start_date={start_date}, end_date={end_date}")
1126
- try:
1127
- result = handler_func(
1128
- normalized_endpoint, tickers, columns, start_date, end_date
1129
- )
1130
- _query_cache[cache_key] = result
1131
- return result
1132
- except Exception as e:
1133
- logger.error(f"Client-side handler error for {normalized_endpoint}: {e}")
1134
- # Fall through to API request if client-side handler fails
1135
-
1136
- try:
1137
- # Perform ticker mapping if needed
1138
- if tickers is not None and not is_all(tickers):
1139
- verbose_mode.log("Mapping ticker symbols")
1140
- params = ticker_mapper(params, verbose)
1141
-
1142
- # Create API request handler
1143
- api_handler = get_api_handler()
1144
-
1145
- # Make API request with retry logic
1146
- verbose_mode.log("Sending API request")
1147
- res = api_handler.get(
1148
- endpoint=endpoint,
1149
- params=params,
1150
- body=body,
1151
- stream=True
1152
- )
1153
-
1154
- verbose_mode.log(f"Response received - Status: {res.status_code}, Content-Type: {res.headers.get('content-type')}")
1155
-
1156
- # Get appropriate ticker for endpoint
1157
- tickers = get_ticker_from_endpoint(endpoint, tickers, ENDPOINT_TO_TICKER)
1158
- verbose_mode.log(f"Using tickers: {tickers}")
1159
-
1160
- # Get response metadata
1161
- data_format = res.headers.get("X-Data-Format")
1162
- content_type = res.headers["content-type"]
1163
- plot_header = res.headers.get("X-Plotly-Data")
1164
- result_data = None
1165
-
1166
- # Handle binary data (parquet)
1167
- if (content_type == "application/octet-stream") and not plot_header:
1168
- if data_format == "pyarrow":
1169
- verbose_mode.log("Processing pyarrow data stream")
1170
- result_data = stream_data_pyarrow(res)
1171
- else:
1172
- verbose_mode.log("Processing binary data stream")
1173
- result_data = stream_data(res)
1174
-
1175
- # Wrap in CustomDataFrame if available
1176
- if HAS_FULL_INSTALL:
1177
- result_data = CustomDataFrame(result_data)
1178
- else:
1179
- result_data = pd.DataFrame(result_data)
1180
-
1181
- _query_cache[cache_key] = result_data
1182
- return result_data
1183
-
1184
- # Handle 'all tickers' case
1185
- if is_all(tickers):
1186
- verbose_mode.log("Processing 'all tickers' response")
1187
- urls = [u.strip() for u in res.text.strip('"').split(',') if u.strip()]
1188
- result_data = None
1189
-
1190
- # Try each URL until successful
1191
- for i, url in enumerate(urls):
1192
- verbose_mode.log(f"Attempting URL {i+1}/{len(urls)}: {url}")
1141
+ result_data = _query_cache[cache_key]
1142
+ else:
1143
+ # Process normalized endpoint for handler matching
1144
+ normalized_endpoint = normalize_endpoint(endpoint)
1145
+
1146
+ # Try client-side handlers for specific endpoints
1147
+ handler_result = None
1148
+ for endpoint_set, handler_func, message in ENDPOINT_HANDLERS:
1149
+ if (
1150
+ normalized_endpoint in endpoint_set and
1151
+ (tickers is not None or start_date is not None or end_date is not None) and
1152
+ frequency is None
1153
+ ):
1154
+ verbose_mode.log(message)
1155
+ verbose_mode.log(f"Calling client-side handler with tickers={tickers}, start_date={start_date}, end_date={end_date}")
1193
1156
  try:
1194
- result_data = read_parquet(url, use_polars=use_polars)
1195
- verbose_mode.log(f"Successfully downloaded data from URL {i+1}")
1157
+ handler_result = handler_func(
1158
+ normalized_endpoint, tickers, columns, start_date, end_date
1159
+ )
1160
+ _query_cache[cache_key] = handler_result
1161
+ result_data = handler_result
1196
1162
  break
1197
1163
  except Exception as e:
1198
- verbose_mode.log(f"Failed to download from URL {i+1}: {str(e)}")
1199
-
1200
- if result_data is None:
1201
- error_msg = "Failed to download data from all provided URLs"
1202
- logger.error(error_msg)
1203
- raise Exception(error_msg)
1204
-
1205
- # Apply filters
1206
- verbose_mode.log("Applying filters to data")
1207
- result_data = filter_data(
1208
- result_data,
1209
- columns=columns,
1210
- start_date=start_date,
1211
- end_date=end_date,
1212
- use_polars=use_polars
1213
- )
1164
+ logger.error(f"Client-side handler error for {normalized_endpoint}: {e}")
1165
+ # Fall through to API request if client-side handler fails
1214
1166
 
1215
- # Wrap in CustomDataFrame if available
1216
- if HAS_FULL_INSTALL and not use_polars:
1217
- result_data = CustomDataFrame(result_data)
1167
+ # Only proceed with API request if no handler result
1168
+ if result_data is None:
1169
+ try:
1170
+ # Perform ticker mapping if needed
1171
+ if tickers is not None and not is_all(tickers):
1172
+ verbose_mode.log("Mapping ticker symbols")
1173
+ params = ticker_mapper(params, verbose)
1218
1174
 
1219
- _query_cache[cache_key] = result_data
1220
-
1221
- # Handle JSON data
1222
- elif not plot_header:
1223
- verbose_mode.log("Processing JSON response")
1224
- json_data = res.json()
1225
- if HAS_FULL_INSTALL:
1226
- result_data = CustomDataFrame(convert_data2df(json_data))
1227
- else:
1228
- result_data = pd.DataFrame(convert_data2df(json_data))
1229
-
1230
- _query_cache[cache_key] = result_data
1231
-
1232
- # Handle plot data
1233
- if plot_header:
1234
- verbose_mode.log("Processing plot data")
1235
- if HAS_FULL_INSTALL:
1236
- import pickle
1237
- try:
1238
- # Unpickle the data
1239
- pickle_bytes = res.content
1240
- fig = pickle.loads(pickle_bytes)
1241
- fig = go.Figure(json.loads(fig))
1242
- fig = set_dark_mode(fig)
1243
- return fig
1244
- except Exception as e:
1245
- logger.error(f"Failed to process plot data: {e}")
1246
- return None
1247
- else:
1248
- logger.warning("Plotting is only available with the full installation. Please install 'sovai[full]' to use this feature.")
1249
- return None
1250
-
1251
- # Generate plot if requested
1252
- if plot:
1253
- verbose_mode.log("Generating plot from data")
1254
- if HAS_FULL_INSTALL and result_data is not None:
1255
- return _draw_graphs(result_data)
1256
- else:
1257
- logger.warning("Plotting is only available with the full installation. Please install 'sovai[full]' to use this feature.")
1258
- return None
1175
+ # Create API request handler
1176
+ api_handler = get_api_handler()
1259
1177
 
1260
- return result_data
1261
-
1262
- except InvalidInputData as err:
1263
- logger.error(f"Invalid input data: {err}")
1264
- raise
1265
-
1266
- except (ConnectionError, TimeoutError) as err:
1267
- logger.error(f"Network error: {err}")
1268
- raise ConnectionError(f"Could not connect to API: {err}")
1269
-
1270
- except Exception as err:
1271
- logger.error(f"API request error: {err}")
1272
- raise
1273
-
1274
- return None
1178
+ # Make API request with retry logic
1179
+ verbose_mode.log("Sending API request")
1180
+ res = api_handler.get(
1181
+ endpoint=endpoint,
1182
+ params=params,
1183
+ body=body,
1184
+ stream=True
1185
+ )
1186
+
1187
+ verbose_mode.log(f"Response received - Status: {res.status_code}, Content-Type: {res.headers.get('content-type')}")
1188
+
1189
+ # Get appropriate ticker for endpoint
1190
+ tickers = get_ticker_from_endpoint(endpoint, tickers, ENDPOINT_TO_TICKER)
1191
+ verbose_mode.log(f"Using tickers: {tickers}")
1192
+
1193
+ # Get response metadata
1194
+ data_format = res.headers.get("X-Data-Format")
1195
+ content_type = res.headers["content-type"]
1196
+ plot_header = res.headers.get("X-Plotly-Data")
1197
+
1198
+ # Handle binary data (parquet)
1199
+ if (content_type == "application/octet-stream") and not plot_header:
1200
+ if data_format == "pyarrow":
1201
+ verbose_mode.log("Processing pyarrow data stream")
1202
+ data_result = stream_data_pyarrow(res)
1203
+ else:
1204
+ verbose_mode.log("Processing binary data stream")
1205
+ data_result = stream_data(res)
1206
+
1207
+ # Wrap in CustomDataFrame if available
1208
+ if HAS_FULL_INSTALL:
1209
+ data_result = CustomDataFrame(data_result)
1210
+ else:
1211
+ data_result = pd.DataFrame(data_result)
1212
+
1213
+ _query_cache[cache_key] = data_result
1214
+ result_data = data_result
1215
+
1216
+
1217
+
1218
+ # Handle 'all tickers' case
1219
+ elif is_all(tickers):
1220
+ verbose_mode.log("Processing 'all tickers' response")
1221
+ urls = [u.strip() for u in res.text.strip('"').split(',') if u.strip()]
1222
+ data_result = None
1223
+
1224
+ # Try each URL until successful
1225
+ for i, url in enumerate(urls):
1226
+ verbose_mode.log(f"Attempting URL {i+1}/{len(urls)}: {url}")
1227
+ try:
1228
+ data_result = read_parquet(url, use_polars=use_polars)
1229
+ verbose_mode.log(f"Successfully downloaded data from URL {i+1}")
1230
+ break
1231
+ except Exception as e:
1232
+ verbose_mode.log(f"Failed to download from URL {i+1}: {str(e)}")
1233
+
1234
+ if data_result is None:
1235
+ error_msg = "Failed to download data from all provided URLs"
1236
+ logger.error(error_msg)
1237
+ raise Exception(error_msg)
1238
+
1239
+ # Apply filters
1240
+ verbose_mode.log("Applying filters to data")
1241
+ data_result = filter_data(
1242
+ data_result,
1243
+ columns=columns,
1244
+ start_date=start_date,
1245
+ end_date=end_date,
1246
+ use_polars=use_polars
1247
+ )
1248
+
1249
+ # Wrap in CustomDataFrame if available
1250
+ if HAS_FULL_INSTALL and not use_polars:
1251
+ data_result = CustomDataFrame(data_result)
1252
+
1253
+ _query_cache[cache_key] = data_result
1254
+ result_data = data_result
1255
+
1256
+
1257
+ # result_data = process_dataframe(result_data)
1258
+
1259
+
1260
+ # Before returning, apply source filtering if applicable
1261
+ if (result_data is not None and
1262
+ source is not None and
1263
+ hasattr(result_data, 'filter') and
1264
+ 'source' not in result_data.columns):
1265
+
1266
+ if source == "delisted":
1267
+ verbose_mode.log("Filtering for delisted securities")
1268
+ result_data = result_data.filter(["isdelisted=Y"])
1269
+ elif source == "listed":
1270
+ verbose_mode.log("Filtering for listed securities")
1271
+ result_data = result_data.filter(["isdelisted=N"])
1272
+
1273
+ # Handle JSON data
1274
+ elif not plot_header:
1275
+ verbose_mode.log("Processing JSON response")
1276
+ json_data = res.json()
1277
+ if HAS_FULL_INSTALL:
1278
+ data_result = CustomDataFrame(convert_data2df(json_data))
1279
+ else:
1280
+ data_result = pd.DataFrame(convert_data2df(json_data))
1281
+
1282
+ _query_cache[cache_key] = data_result
1283
+ result_data = data_result
1284
+
1285
+
1286
+ # Handle plot data
1287
+ if plot_header:
1288
+ verbose_mode.log("Processing plot data")
1289
+ if HAS_FULL_INSTALL:
1290
+ import pickle
1291
+ try:
1292
+ # Unpickle the data
1293
+ pickle_bytes = res.content
1294
+ fig = pickle.loads(pickle_bytes)
1295
+ fig = go.Figure(json.loads(fig))
1296
+ fig = set_dark_mode(fig)
1297
+ result_data = fig
1298
+ except Exception as e:
1299
+ logger.error(f"Failed to process plot data: {e}")
1300
+ result_data = None
1301
+ else:
1302
+ logger.warning("Plotting is only available with the full installation. Please install 'sovai[full]' to use this feature.")
1303
+ result_data = None
1304
+
1305
+ # Generate plot if requested
1306
+ if plot and result_data is not None and not plot_header:
1307
+ verbose_mode.log("Generating plot from data")
1308
+ if HAS_FULL_INSTALL:
1309
+ result_data = _draw_graphs(result_data)
1310
+ else:
1311
+ logger.warning("Plotting is only available with the full installation. Please install 'sovai[full]' to use this feature.")
1312
+ result_data = None
1313
+
1314
+ except InvalidInputData as err:
1315
+ logger.error(f"Invalid input data: {err}")
1316
+ raise
1317
+
1318
+ except (ConnectionError, TimeoutError) as err:
1319
+ logger.error(f"Network error: {err}")
1320
+ raise ConnectionError(f"Could not connect to API: {err}")
1321
+
1322
+ except Exception as err:
1323
+ logger.error(f"API request error: {err}")
1324
+ raise
1325
+
1326
+
1327
+ result_data = process_dataframe(result_data)
1328
+
1329
+ return result_data
1275
1330
 
1276
1331
 
1277
1332
  async def fetch_multiple_tickers(
@@ -585,7 +585,7 @@ ENDPOINT_CONFIG = {
585
585
  "date_path": "sovai/sovai-patents-bulk/grants/date",
586
586
  "has_year": True
587
587
  },
588
- "clinical_trials": {
588
+ "clinical/trials": {
589
589
  "ticker_path": "sovai/sovai-clinical-trials-export/partitioned/ticker/ticker",
590
590
  "date_path": "sovai/sovai-clinical-trials-export/partitioned/date/date",
591
591
  "has_year": False
@@ -610,10 +610,9 @@ ENDPOINT_CONFIG = {
610
610
  "date_path": "sovai/sovai-government/partitioned/contract/date",
611
611
  "has_year": False
612
612
  },
613
-
614
613
  "spending/product": {
615
614
  "ticker_path": "sovai/sovai-government/partitioned/product/ticker",
616
- "date_path": "sovai/sovai-government/partitioned/product/date",
615
+ "date_path": "sovai/sovai-government/partitioned/product/date",
617
616
  "has_year": False
618
617
  },
619
618
  "spending/transactions": {
@@ -631,9 +630,69 @@ ENDPOINT_CONFIG = {
631
630
  },
632
631
  "lobbying/data": {
633
632
  "ticker_path": "sovai/sovai-lobbying/partitioned/ticker",
634
- "date_path": "sovai/sovai-lobbying/partitioned/date",
633
+ "date_path": "sovai/sovai-lobbying/partitioned/date",
634
+ "has_year": False
635
+ },
636
+ "accounting/weekly": {
637
+ "ticker_path": "sovai/sovai-accounting/partitioned/ticker",
638
+ "date_path": "sovai/sovai-accounting/partitioned/date",
639
+ "has_year": False
640
+ },
641
+ "ratios/normal": {
642
+ "ticker_path": "sovai/sovai-ratios/partitioned/ticker",
643
+ "date_path": "sovai/sovai-ratios/partitioned/date",
644
+ "has_year": False
645
+ },
646
+ "complaints/public": {
647
+ "ticker_path": "sovai/sovai-complaints/partitioned/ticker",
648
+ "date_path": "sovai/sovai-complaints/partitioned/date",
649
+ "has_year": False
650
+ },
651
+ "factors/accounting": {
652
+ "ticker_path": "sovai/sovai-factors/accounting/partitioned/ticker",
653
+ "date_path": "sovai/sovai-factors/accounting/partitioned/date",
654
+ "has_year": False
655
+ },
656
+ "factors/alternative": {
657
+ "ticker_path": "sovai/sovai-factors/alternative/partitioned/ticker",
658
+ "date_path": "sovai/sovai-factors/alternative/partitioned/date",
659
+ "has_year": False
660
+ },
661
+ "factors/comprehensive": {
662
+ "ticker_path": "sovai/sovai-factors/comprehensive/partitioned/ticker",
663
+ "date_path": "sovai/sovai-factors/comprehensive/partitioned/date",
664
+ "has_year": False
665
+ },
666
+ "factors/coefficients": {
667
+ "ticker_path": "sovai/sovai-factors/coefficients/partitioned/ticker",
668
+ "date_path": "sovai/sovai-factors/coefficients/partitioned/date",
669
+ "has_year": False
670
+ },
671
+ "factors/standard_errors": {
672
+ "ticker_path": "sovai/sovai-factors/standard_errors/partitioned/ticker",
673
+ "date_path": "sovai/sovai-factorss/standard_errors/partitioned/date",
674
+ "has_year": False
675
+ },
676
+ "factors/t_statistics": {
677
+ "ticker_path": "sovai/sovai-factors/t_statistics/partitioned/ticker",
678
+ "date_path": "sovai/sovai-factors/t_statistics/partitioned/date",
679
+ "has_year": False
680
+ },
681
+ "factors/model_metrics": {
682
+ "ticker_path": "sovai/sovai-factors/model_metrics/partitioned/ticker",
683
+ "date_path": "sovai/sovai-factors/model_metrics/partitioned/date",
635
684
  "has_year": False
636
685
  },
686
+ "breakout": {
687
+ "ticker_path": "sovai/sovai-breakout-price/partitioned/ticker",
688
+ "date_path": "sovai/sovai-breakout-price/partitioned/date",
689
+ "has_year": False
690
+ },
691
+ "visas/h1b": {
692
+ "ticker_path": "sovai/sovai-employment/partitioned/ticker",
693
+ "date_path": "sovai/sovai-employment/partitioned/date",
694
+ "has_year": False
695
+ }
637
696
  }
638
697
 
639
698
 
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