sovai 0.2.76__tar.gz → 0.2.77__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 (108) hide show
  1. {sovai-0.2.76 → sovai-0.2.77}/PKG-INFO +1 -1
  2. {sovai-0.2.76 → sovai-0.2.77}/pyproject.toml +1 -1
  3. {sovai-0.2.76 → sovai-0.2.77}/sovai/api_config.py +4 -1
  4. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/signal_evaluation.py +3 -0
  5. {sovai-0.2.76 → sovai-0.2.77}/sovai/get_data.py +164 -10
  6. {sovai-0.2.76 → sovai-0.2.77}/sovai/token_auth.py +24 -3
  7. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/client_side_s3_part_high.py +76 -1
  8. {sovai-0.2.76 → sovai-0.2.77}/LICENSE +0 -0
  9. {sovai-0.2.76 → sovai-0.2.77}/README.md +0 -0
  10. {sovai-0.2.76 → sovai-0.2.77}/sovai/.DS_Store +0 -0
  11. {sovai-0.2.76 → sovai-0.2.77}/sovai/__init__.py +0 -0
  12. {sovai-0.2.76 → sovai-0.2.77}/sovai/assets/dropdown.css +0 -0
  13. {sovai-0.2.76 → sovai-0.2.77}/sovai/basic_auth.py +0 -0
  14. {sovai-0.2.76 → sovai-0.2.77}/sovai/computations/__init__.py +0 -0
  15. {sovai-0.2.76 → sovai-0.2.77}/sovai/computations/functions.py +0 -0
  16. {sovai-0.2.76 → sovai-0.2.77}/sovai/errors/__init__.py +0 -0
  17. {sovai-0.2.76 → sovai-0.2.77}/sovai/errors/sovai_errors.py +0 -0
  18. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/__init__.py +0 -0
  19. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/anomalies.py +0 -0
  20. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/ask_df_llm.py +0 -0
  21. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/change_point_generator copy.py +0 -0
  22. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/change_point_generator.py +0 -0
  23. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/chart_explainer.py +0 -0
  24. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/clustering.py +0 -0
  25. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/core_kshape.py +0 -0
  26. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/cum_sum_torch.py +0 -0
  27. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/cusum.py +0 -0
  28. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/dimensionality_reduction.py +0 -0
  29. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/feature_extraction.py +0 -0
  30. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/feature_importance.py +0 -0
  31. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/feature_neutralizer.py +0 -0
  32. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/filter_df.py +0 -0
  33. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/fractional_differencing.py +0 -0
  34. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/nowcasting.py +0 -0
  35. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/overall_explainers.py +0 -0
  36. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/pairwise.py +0 -0
  37. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/pandas_extensions.py +0 -0
  38. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/parallel_functions.py +0 -0
  39. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/pfa_feature_selector.py +0 -0
  40. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/regime_change.py +0 -0
  41. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/regime_change_pca.py +0 -0
  42. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/shapley_global_importance.py +0 -0
  43. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/shapley_importance.py +0 -0
  44. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/signal_evaluation copy.py +0 -0
  45. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/signal_evaluation_old.py +0 -0
  46. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/table_explainer.py +0 -0
  47. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/technical_indicators.py +0 -0
  48. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/time_decomposition.py +0 -0
  49. {sovai-0.2.76 → sovai-0.2.77}/sovai/extensions/weight_optimization.py +0 -0
  50. {sovai-0.2.76 → sovai-0.2.77}/sovai/get_compute.py +0 -0
  51. {sovai-0.2.76 → sovai-0.2.77}/sovai/get_data copy 2.py +0 -0
  52. {sovai-0.2.76 → sovai-0.2.77}/sovai/get_data copy.py +0 -0
  53. {sovai-0.2.76 → sovai-0.2.77}/sovai/get_plots.py +0 -0
  54. {sovai-0.2.76 → sovai-0.2.77}/sovai/get_reports.py +0 -0
  55. {sovai-0.2.76 → sovai-0.2.77}/sovai/get_tools.py +0 -0
  56. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/__init__.py +0 -0
  57. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/accounting/__init__.py +0 -0
  58. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/accounting/accounting_plots.py +0 -0
  59. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/allocation/__init__.py +0 -0
  60. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/allocation/allocation_plots.py +0 -0
  61. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/bankruptcy/__init__.py +0 -0
  62. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/bankruptcy/bankruptcy_plots.py +0 -0
  63. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/breakout/__init__.py +0 -0
  64. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/breakout/breakout_plots.py +0 -0
  65. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/corp_risk/__init__.py +0 -0
  66. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/corp_risk/corp_risk_plots.py +0 -0
  67. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/earnings_surprise/__init__.py +0 -0
  68. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/earnings_surprise/earnings_surprise_plots.py +0 -0
  69. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/insider/__init__.py +0 -0
  70. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/insider/insider_plots.py +0 -0
  71. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/institutional/__init__.py +0 -0
  72. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/institutional/institutional_plots.py +0 -0
  73. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/news/__init__.py +0 -0
  74. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/news/news_plots.py +0 -0
  75. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/ratios/__init__.py +0 -0
  76. {sovai-0.2.76 → sovai-0.2.77}/sovai/plots/ratios/ratios_plots.py +0 -0
  77. {sovai-0.2.76 → sovai-0.2.77}/sovai/reports/accounting/__init__.py +0 -0
  78. {sovai-0.2.76 → sovai-0.2.77}/sovai/reports/accounting/accounting_balance_sheet.py +0 -0
  79. {sovai-0.2.76 → sovai-0.2.77}/sovai/reports/bankruptcy/__init__.py +0 -0
  80. {sovai-0.2.76 → sovai-0.2.77}/sovai/reports/bankruptcy/bankruptcy_monthly_top.py +0 -0
  81. {sovai-0.2.76 → sovai-0.2.77}/sovai/reports/general/__init__.py +0 -0
  82. {sovai-0.2.76 → sovai-0.2.77}/sovai/reports/general/general_plots.py +0 -0
  83. {sovai-0.2.76 → sovai-0.2.77}/sovai/reports/news/__inti__.py +0 -0
  84. {sovai-0.2.76 → sovai-0.2.77}/sovai/reports/news/news_econometric_analysis.py +0 -0
  85. {sovai-0.2.76 → sovai-0.2.77}/sovai/studies/nowcasting.py +0 -0
  86. {sovai-0.2.76 → sovai-0.2.77}/sovai/tools/authentication/__init__.py +0 -0
  87. {sovai-0.2.76 → sovai-0.2.77}/sovai/tools/authentication/authentication.py +0 -0
  88. {sovai-0.2.76 → sovai-0.2.77}/sovai/tools/explainers.py +0 -0
  89. {sovai-0.2.76 → sovai-0.2.77}/sovai/tools/sec/__init__.py +0 -0
  90. {sovai-0.2.76 → sovai-0.2.77}/sovai/tools/sec/graphs.py +0 -0
  91. {sovai-0.2.76 → sovai-0.2.77}/sovai/tools/sec/llm_code_generator.py +0 -0
  92. {sovai-0.2.76 → sovai-0.2.77}/sovai/tools/sec/sec_10_k_8_k_filings.py +0 -0
  93. {sovai-0.2.76 → sovai-0.2.77}/sovai/tools/sec/sec_edgar_search.py +0 -0
  94. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/__init__.py +0 -0
  95. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/client_side.py +0 -0
  96. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/client_side_s3.py +0 -0
  97. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/converter.py +0 -0
  98. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/datetime_formats.py +0 -0
  99. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/file_management copy.py +0 -0
  100. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/file_management.py +0 -0
  101. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/get_tickers.py +0 -0
  102. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/helpers.py +0 -0
  103. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/pandas_extensions copy.py +0 -0
  104. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/plot.py +0 -0
  105. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/port_manager copy.py +0 -0
  106. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/port_manager.py +0 -0
  107. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/stream.py +0 -0
  108. {sovai-0.2.76 → sovai-0.2.77}/sovai/utils/verbose_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sovai
3
- Version: 0.2.76
3
+ Version: 0.2.77
4
4
  Summary: python for asset management
5
5
  License: Proprietary License
6
6
  License-File: LICENSE
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "sovai"
7
- version = "0.2.76"
7
+ version = "0.2.77"
8
8
  description = "python for asset management"
9
9
  authors = [
10
10
  {name = "Derek Snow", email = "d.snow@outlook.com"}
@@ -14,6 +14,7 @@ class ApiConfig:
14
14
  base_url: str = "https://data.sov.ai"
15
15
  token_type: str = "Bearer"
16
16
  verify_ssl: bool = True
17
+ version: Optional[str] = None
17
18
 
18
19
 
19
20
  def read_key(envpath: Union[str, Path]) -> Optional[str]:
@@ -45,7 +46,9 @@ def save_key(envpath: Union[str, Path] = ".env") -> None:
45
46
  envpath = Path(envpath)
46
47
 
47
48
  with open(envpath, "w", encoding="utf8") as fh:
48
- fh.write(f"API_TOKEN={ApiConfig.token}")
49
+ fh.write(f"API_TOKEN={ApiConfig.token}\n")
50
+ if ApiConfig.version:
51
+ fh.write(f"API_VERSION={ApiConfig.version}\n")
49
52
 
50
53
 
51
54
  def _lookup_token(config: dict[str, Optional[str]]) -> Optional[str]:
@@ -1182,7 +1182,10 @@ def stress_plotting(portfolio_returns):
1182
1182
  start_date, end_date = min(all_dates), max(all_dates)
1183
1183
 
1184
1184
  # Add horizontal lines for average returns of selected events
1185
+ # Only process events that exist in event_avg_returns (handles shorter time series)
1185
1186
  for i, event in enumerate(selected_events):
1187
+ if event not in event_avg_returns:
1188
+ continue # Skip events not present in the data
1186
1189
  avg_return = event_avg_returns[event]
1187
1190
  color = color_map[list(event_returns.keys()).index(event) % len(color_map)]
1188
1191
  fig.add_trace(
@@ -1,4 +1,4 @@
1
- from typing import Optional, Union, Tuple, List, Dict, Any, Callable, TypeVar
1
+ from typing import Optional, Union, Tuple, List, Dict, Any, Callable, TypeVar, TYPE_CHECKING
2
2
  import re
3
3
  import time
4
4
  import functools
@@ -20,7 +20,6 @@ from requests.exceptions import RequestException, ConnectionError, Timeout, HTTP
20
20
  import boto3
21
21
  import polars as pl
22
22
  import pyarrow.parquet as pq
23
- import plotly.graph_objects as go
24
23
 
25
24
 
26
25
  # Local imports
@@ -41,16 +40,52 @@ logger = logging.getLogger(__name__)
41
40
  T = TypeVar('T')
42
41
  DataFrameType = Union[pd.DataFrame, pl.DataFrame, 'CustomDataFrame']
43
42
 
43
+ # Version-based column exclusions configuration
44
+ VERSION_COLUMN_EXCLUSIONS = {
45
+ "p72": {
46
+ "lobbying": {
47
+ "always": [
48
+ "registrant_name",
49
+ "registrant_address",
50
+ "registrant_contact_phone",
51
+ "registrant_contact_name",
52
+ "lobbyist_full_names",
53
+ "previous_government_positions",
54
+ "registrant_contact_telephone",
55
+ "lobbyist_ids",
56
+ "previous_goverment_positions"
57
+
58
+ ]
59
+ },
60
+ "cfpb": {
61
+ "always": ["consumer_complaint_narrative"]
62
+ },
63
+ "clinical_trials": {
64
+ "always": ["responsible_party_investigator_name"]
65
+ }
66
+ },
67
+ "sovai": {
68
+ # Define sovai version exclusions here if needed
69
+ # For now, no exclusions for sovai version
70
+ }
71
+ }
72
+
44
73
  # Check for full installation
45
74
  try:
46
75
  from sovai.extensions.pandas_extensions import CustomDataFrame
47
- from sovai.utils.plot import plotting_data
76
+ from sovai.utils.plot import plotting_data
77
+ import plotly.graph_objects as go
78
+
48
79
  HAS_FULL_INSTALL = True
49
80
  except ImportError:
50
81
  HAS_FULL_INSTALL = False
51
82
  CustomDataFrame = pd.DataFrame # Fallback if not available
52
83
  plotting_data = lambda x: None # Fallback
53
84
  logger.warning("Running with limited installation. Some features unavailable.")
85
+
86
+ # Create a mock go module for type hints when full install is not available
87
+ if TYPE_CHECKING:
88
+ import plotly.graph_objects as go
54
89
 
55
90
 
56
91
  def is_full_installation() -> bool:
@@ -337,6 +372,7 @@ ENDPOINT_TO_TICKER = {
337
372
  "/breakout/median": "",
338
373
  "/institutional/trading": "",
339
374
  "/institutional/flow_prediction": "",
375
+
340
376
  "/news/daily": "",
341
377
  "/news/match_quality": "",
342
378
  "/news/within_article": "",
@@ -353,6 +389,7 @@ ENDPOINT_TO_TICKER = {
353
389
  "/news/activeness": "",
354
390
  "/news/pronouns": "",
355
391
  "/news/word_count": "",
392
+
356
393
  "/news/sentiment_score": "", # was None before?
357
394
 
358
395
  "/insider/trading": "",
@@ -480,7 +517,24 @@ CLIENT_SIDE_ENDPOINTS_S3_PART_HIGH = {
480
517
  "short/maker",
481
518
  "short/over_shorted",
482
519
 
483
- "institutional/trading"
520
+ "institutional/trading",
521
+
522
+ "news/daily",
523
+ "news/match_quality",
524
+ "news/within_article",
525
+ "news/relevance",
526
+ "news/magnitude",
527
+ "news/sentiment",
528
+ "news/article_count",
529
+ "news/associated_people",
530
+ "news/associated_companies",
531
+ "news/tone",
532
+ "news/positive",
533
+ "news/negative",
534
+ "news/polarity",
535
+ "news/activeness",
536
+ "news/pronouns",
537
+ "news/word_count"
484
538
 
485
539
  }
486
540
 
@@ -691,6 +745,93 @@ def read_parquet(url: str, use_polars: bool = False) -> DataFrameType:
691
745
 
692
746
  DEFAULT_COLUMNS_TO_REMOVE = ['ticker_partitioned', 'date_partitioned', 'year_partitioned', 'month_partitioned', 'day_partitioned']
693
747
 
748
+
749
+ def detect_dataset_type(endpoint: str) -> Optional[str]:
750
+ """
751
+ Detect dataset type from endpoint URL for version-based column exclusions.
752
+
753
+ Args:
754
+ endpoint: The API endpoint path
755
+
756
+ Returns:
757
+ Dataset type string ('lobbying', 'cfpb', 'clinical_trials') or None
758
+ """
759
+ endpoint_lower = endpoint.lower().strip('/')
760
+
761
+ if 'lobbying' in endpoint_lower:
762
+ return 'lobbying'
763
+ elif 'complaint' in endpoint_lower or 'cfpb' in endpoint_lower:
764
+ return 'cfpb'
765
+ elif 'clinical' in endpoint_lower or 'trial' in endpoint_lower:
766
+ return 'clinical_trials'
767
+
768
+ return None
769
+
770
+
771
+ def apply_version_exclusions(
772
+ data: DataFrameType,
773
+ version: Optional[str],
774
+ endpoint: str,
775
+ use_polars: bool = False
776
+ ) -> DataFrameType:
777
+ """
778
+ Apply version-based column exclusions to a DataFrame.
779
+
780
+ Args:
781
+ data: Input DataFrame
782
+ version: Version parameter (e.g., 'p72', 'sovai')
783
+ endpoint: API endpoint to detect dataset type
784
+ use_polars: Whether using polars DataFrame
785
+
786
+ Returns:
787
+ DataFrame with excluded columns removed
788
+ """
789
+ if data is None or (hasattr(data, 'empty') and data.empty):
790
+ return data
791
+
792
+ if not version or version not in VERSION_COLUMN_EXCLUSIONS:
793
+ return data
794
+
795
+ dataset_type = detect_dataset_type(endpoint)
796
+ if not dataset_type:
797
+ return data
798
+
799
+ version_config = VERSION_COLUMN_EXCLUSIONS.get(version, {})
800
+ dataset_config = version_config.get(dataset_type, {})
801
+
802
+ if not dataset_config:
803
+ return data
804
+
805
+ # Get columns to exclude
806
+ columns_to_exclude = dataset_config.get('always', [])
807
+
808
+ if not columns_to_exclude:
809
+ return data
810
+
811
+ # Case-insensitive matching - find columns that exist in the DataFrame
812
+ data_columns = list(data.columns)
813
+ data_columns_lower = {col.lower(): col for col in data_columns}
814
+
815
+ actual_columns_to_exclude = []
816
+ for exclude_col in columns_to_exclude:
817
+ exclude_col_lower = exclude_col.lower()
818
+ if exclude_col_lower in data_columns_lower:
819
+ actual_columns_to_exclude.append(data_columns_lower[exclude_col_lower])
820
+
821
+ if not actual_columns_to_exclude:
822
+ verbose_mode.log(f"Version {version}: No matching columns found to exclude for {dataset_type}")
823
+ return data
824
+
825
+ verbose_mode.log(f"Version {version}: Excluding columns {actual_columns_to_exclude} from {dataset_type}")
826
+
827
+ # Remove the columns
828
+ if use_polars:
829
+ columns_to_keep = [col for col in data.columns if col not in actual_columns_to_exclude]
830
+ return data.select(columns_to_keep)
831
+ else: # pandas
832
+ return data.drop(columns=actual_columns_to_exclude, errors='ignore')
833
+
834
+
694
835
  def filter_data(
695
836
  data: DataFrameType,
696
837
  columns: Optional[Union[str, List[str]]] = None,
@@ -1156,7 +1297,7 @@ def _uniform_datetime_params(datetime_params: Dict[str, str]) -> None:
1156
1297
  logger.debug(f"Date parameter '{key}' with value '{original_val}' did not match any known formats: {datetime_format}. Leaving as is.")
1157
1298
 
1158
1299
 
1159
- def _draw_graphs(data: Union[Dict, List[Dict]]) -> Optional[go.Figure]:
1300
+ def _draw_graphs(data: Union[Dict, List[Dict]]) -> Optional['go.Figure']:
1160
1301
  """
1161
1302
  Generate plots from data.
1162
1303
 
@@ -1206,7 +1347,7 @@ def _draw_graphs(data: Union[Dict, List[Dict]]) -> Optional[go.Figure]:
1206
1347
  return None
1207
1348
 
1208
1349
 
1209
- def set_dark_mode(fig: go.Figure) -> go.Figure:
1350
+ def set_dark_mode(fig: 'go.Figure') -> 'go.Figure':
1210
1351
  """
1211
1352
  Apply dark mode styling to a Plotly figure.
1212
1353
 
@@ -1305,7 +1446,7 @@ def data(
1305
1446
  verbose: bool = False,
1306
1447
  full_history: bool = False,
1307
1448
  source: Optional[str] = None,
1308
- ) -> Union[DataFrameType, go.Figure, None]:
1449
+ ) -> Union[DataFrameType, 'go.Figure', None]:
1309
1450
  """
1310
1451
  Main function to retrieve data from the API.
1311
1452
  Caches results to disk in 'cache/' directory (Parquet for DataFrames, Pickle for Figures).
@@ -1594,7 +1735,20 @@ def data(
1594
1735
  except Exception as err: verbose_mode.log(f"General API/processing error: {err}"); raise
1595
1736
 
1596
1737
  if result_data is not None:
1597
- result_data = process_dataframe(result_data)
1738
+ result_data = process_dataframe(result_data)
1739
+
1740
+ # Apply version-based column exclusions if a version is set
1741
+ # Use the version from function parameter, or fall back to ApiConfig.version
1742
+ effective_version = version if version is not None else ApiConfig.version
1743
+
1744
+ if effective_version and isinstance(result_data, (pd.DataFrame, pl.DataFrame)):
1745
+ verbose_mode.log(f"Applying version-based exclusions for version: {effective_version}")
1746
+ result_data = apply_version_exclusions(
1747
+ result_data,
1748
+ effective_version,
1749
+ final_endpoint_path,
1750
+ use_polars
1751
+ )
1598
1752
 
1599
1753
  if forced_columns_list is not None and isinstance(result_data, (pd.DataFrame, pl.DataFrame)):
1600
1754
  current_data_cols = list(result_data.columns)
@@ -1617,7 +1771,7 @@ async def fetch_multiple_tickers(
1617
1771
  endpoint: str,
1618
1772
  tickers: List[str],
1619
1773
  **kwargs
1620
- ) -> Dict[str, Union[DataFrameType, go.Figure, None]]: # Updated return type hint
1774
+ ) -> Dict[str, Union[DataFrameType, 'go.Figure', None]]: # Updated return type hint
1621
1775
  """
1622
1776
  Fetch data for multiple tickers concurrently using asyncio.
1623
1777
 
@@ -1752,4 +1906,4 @@ ApiConfig.base_url = "your_api_base_url_here" # Ensure base_url is set
1752
1906
 
1753
1907
  # if __name__ == "__main__":
1754
1908
  # asyncio.run(main())
1755
- """
1909
+ """
@@ -1,16 +1,37 @@
1
+ from typing import Optional
1
2
  from sovai.api_config import ApiConfig, save_key
2
3
  # Removed verify_token import from top level
3
4
  from sovai.errors.sovai_errors import InvalidCredentialsError
4
5
 
6
+ # Valid version values
7
+ VALID_VERSIONS = ["p72", "sovai"]
5
8
 
6
- def token_auth(token: str):
7
- """Authenticates using a token, saves it, and verifies it."""
9
+
10
+ def token_auth(token: str, version: Optional[str] = None):
11
+ """
12
+ Authenticates using a token, saves it, and verifies it.
13
+
14
+ Args:
15
+ token: API authentication token
16
+ version: Optional version parameter for column exclusions (e.g., 'p72', 'sovai')
17
+
18
+ Raises:
19
+ InvalidCredentialsError: If token is invalid or expired
20
+ ValueError: If version is provided but not in the list of valid versions
21
+ """
22
+ # Validate version if provided
23
+ if version is not None and version not in VALID_VERSIONS:
24
+ raise ValueError(
25
+ f"Invalid version '{version}'. Must be one of: {', '.join(VALID_VERSIONS)}"
26
+ )
8
27
 
9
28
  # Lazy load verify_token here, just before use
10
29
  from sovai.utils.client_side import verify_token
11
30
 
12
31
  ApiConfig.token = token
13
32
  ApiConfig.token_type = "Bearer"
33
+ ApiConfig.version = version
34
+
14
35
  save_key() # Assumes save_key doesn't trigger heavy imports
15
36
 
16
37
  # Now call the imported function
@@ -22,4 +43,4 @@ def token_auth(token: str):
22
43
 
23
44
  # Optionally, you could return something useful, like the validity or user_id
24
45
  # print(f"Token verified successfully for user ID: {user_id}") # Or use logging
25
- # return is_valid, user_id
46
+ # return is_valid, user_id
@@ -875,10 +875,85 @@ ENDPOINT_CONFIG = {
875
875
  "date_path": "sovai/sovai-institutional/trading/partitioned/date",
876
876
  "has_year": False
877
877
  },
878
-
878
+ "news/match_quality": {
879
+ "ticker_path": "sovai/sovai-news/partitioned/match_quality/ticker",
880
+ "date_path": "sovai/sovai-news/partitioned/match_quality/date",
881
+ "has_year": False
882
+ },
883
+ "news/within_article": {
884
+ "ticker_path": "sovai/sovai-news/partitioned/within_article/ticker",
885
+ "date_path": "sovai/sovai-news/partitioned/within_article/date",
886
+ "has_year": False
887
+ },
888
+ "news/relevance": {
889
+ "ticker_path": "sovai/sovai-news/partitioned/relevance/ticker",
890
+ "date_path": "sovai/sovai-news/partitioned/relevance/date",
891
+ "has_year": False
892
+ },
893
+ "news/magnitude": {
894
+ "ticker_path": "sovai/sovai-news/partitioned/magnitude/ticker",
895
+ "date_path": "sovai/sovai-news/partitioned/magnitude/date",
896
+ "has_year": False
897
+ },
898
+ "news/sentiment": {
899
+ "ticker_path": "sovai/sovai-news/partitioned/sentiment/ticker",
900
+ "date_path": "sovai/sovai-news/partitioned/sentiment/date",
901
+ "has_year": False
902
+ },
903
+ "news/article_count": {
904
+ "ticker_path": "sovai/sovai-news/partitioned/article_count/ticker",
905
+ "date_path": "sovai/sovai-news/partitioned/article_count/date",
906
+ "has_year": False
907
+ },
908
+ "news/associated_people": {
909
+ "ticker_path": "sovai/sovai-news/partitioned/associated_people/ticker",
910
+ "date_path": "sovai/sovai-news/partitioned/associated_people/date",
911
+ "has_year": False
912
+ },
913
+ "news/associated_companies": {
914
+ "ticker_path": "sovai/sovai-news/partitioned/associated_companies/ticker",
915
+ "date_path": "sovai/sovai-news/partitioned/associated_companies/date",
916
+ "has_year": False
917
+ },
918
+ "news/tone": {
919
+ "ticker_path": "sovai/sovai-news/partitioned/tone/ticker",
920
+ "date_path": "sovai/sovai-news/partitioned/tone/date",
921
+ "has_year": False
922
+ },
923
+ "news/positive": {
924
+ "ticker_path": "sovai/sovai-news/partitioned/positive/ticker",
925
+ "date_path": "sovai/sovai-news/partitioned/positive/date",
926
+ "has_year": False
927
+ },
928
+ "news/negative": {
929
+ "ticker_path": "sovai/sovai-news/partitioned/negative/ticker",
930
+ "date_path": "sovai/sovai-news/partitioned/negative/date",
931
+ "has_year": False
932
+ },
933
+ "news/polarity": {
934
+ "ticker_path": "sovai/sovai-news/partitioned/polarity/ticker",
935
+ "date_path": "sovai/sovai-news/partitioned/polarity/date",
936
+ "has_year": False
937
+ },
938
+ "news/activeness": {
939
+ "ticker_path": "sovai/sovai-news/partitioned/activeness/ticker",
940
+ "date_path": "sovai/sovai-news/partitioned/activeness/date",
941
+ "has_year": False
942
+ },
943
+ "news/pronouns": {
944
+ "ticker_path": "sovai/sovai-news/partitioned/pronouns/ticker",
945
+ "date_path": "sovai/sovai-news/partitioned/pronouns/date",
946
+ "has_year": False
947
+ },
948
+ "news/word_count": {
949
+ "ticker_path": "sovai/sovai-news/partitioned/word_count/ticker",
950
+ "date_path": "sovai/sovai-news/partitioned/word_count/date",
951
+ "has_year": False
952
+ }
879
953
  }
880
954
 
881
955
 
956
+
882
957
  # =========================================================================
883
958
  # Public Interface
884
959
  # =========================================================================
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