validmind 2.13.4__tar.gz → 2.13.5__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 (376) hide show
  1. {validmind-2.13.4 → validmind-2.13.5}/PKG-INFO +3 -1
  2. {validmind-2.13.4 → validmind-2.13.5}/pyproject.toml +4 -2
  3. validmind-2.13.5/validmind/__version__.py +1 -0
  4. {validmind-2.13.4 → validmind-2.13.5}/validmind/ai/utils.py +92 -21
  5. {validmind-2.13.4 → validmind-2.13.5}/validmind/api_client.py +183 -13
  6. validmind-2.13.5/validmind/credentials_store.py +179 -0
  7. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/agent_dataset.py +8 -6
  8. {validmind-2.13.4 → validmind-2.13.5}/validmind/errors.py +4 -0
  9. validmind-2.13.5/validmind/oidc_device.py +421 -0
  10. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/AnswerRelevancy.py +2 -3
  11. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/ArgumentCorrectness.py +2 -3
  12. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/Bias.py +2 -3
  13. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/ContextualPrecision.py +2 -3
  14. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/ContextualRecall.py +2 -3
  15. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/ContextualRelevancy.py +2 -3
  16. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/Faithfulness.py +2 -3
  17. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/Hallucination.py +2 -3
  18. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/Summarization.py +2 -3
  19. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/ToolCorrectness.py +2 -3
  20. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/__init__.py +1 -1
  21. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/MissingValues.py +3 -3
  22. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/AnswerCorrectness.py +1 -1
  23. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/AspectCritic.py +1 -1
  24. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/ContextEntityRecall.py +1 -1
  25. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/ContextPrecision.py +1 -1
  26. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/ContextPrecisionWithoutReference.py +1 -1
  27. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/ContextRecall.py +1 -1
  28. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/Faithfulness.py +1 -1
  29. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/SemanticSimilarity.py +1 -1
  30. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/FeatureImportance.py +3 -3
  31. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/HyperParametersTuning.py +1 -3
  32. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/RobustnessDiagnosis.py +3 -3
  33. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/ai_powered_test.py +2 -1
  34. {validmind-2.13.4 → validmind-2.13.5}/validmind/utils.py +16 -15
  35. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/dataset/dataset.py +1 -1
  36. validmind-2.13.4/validmind/__version__.py +0 -1
  37. {validmind-2.13.4 → validmind-2.13.5}/.gitignore +0 -0
  38. {validmind-2.13.4 → validmind-2.13.5}/LICENSE +0 -0
  39. {validmind-2.13.4 → validmind-2.13.5}/README.pypi.md +0 -0
  40. {validmind-2.13.4 → validmind-2.13.5}/validmind/__init__.py +0 -0
  41. {validmind-2.13.4 → validmind-2.13.5}/validmind/ai/test_descriptions.py +0 -0
  42. {validmind-2.13.4 → validmind-2.13.5}/validmind/client.py +0 -0
  43. {validmind-2.13.4 → validmind-2.13.5}/validmind/client_config.py +0 -0
  44. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/__init__.py +0 -0
  45. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/classification/__init__.py +0 -0
  46. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/classification/config.json +0 -0
  47. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/classification/customer_churn.py +0 -0
  48. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/classification/datasets/bank_customer_churn.csv +0 -0
  49. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/classification/datasets/taiwan_credit.csv +0 -0
  50. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/classification/taiwan_credit.py +0 -0
  51. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/cluster/digits.py +0 -0
  52. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/credit_risk/__init__.py +0 -0
  53. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/credit_risk/datasets/lending_club_biased.csv.gz +0 -0
  54. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/credit_risk/datasets/lending_club_loan_data_2007_2014_clean.csv.gz +0 -0
  55. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/credit_risk/lending_club.py +0 -0
  56. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/credit_risk/lending_club_bias.py +0 -0
  57. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/__init__.py +0 -0
  58. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/rag/__init__.py +0 -0
  59. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_1.csv +0 -0
  60. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_2.csv +0 -0
  61. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_3.csv +0 -0
  62. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_4.csv +0 -0
  63. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_5.csv +0 -0
  64. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/llm/rag/rfp.py +0 -0
  65. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/nlp/__init__.py +0 -0
  66. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/nlp/cnn_dailymail.py +0 -0
  67. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/nlp/datasets/Covid_19.csv +0 -0
  68. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/nlp/datasets/cnn_dailymail_100_with_predictions.csv +0 -0
  69. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/nlp/datasets/cnn_dailymail_500_with_predictions.csv +0 -0
  70. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/nlp/datasets/sentiments_with_predictions.csv +0 -0
  71. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/nlp/twitter_covid_19.py +0 -0
  72. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/__init__.py +0 -0
  73. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/california_housing.py +0 -0
  74. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/california_housing.csv +0 -0
  75. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/CPIAUCSL.csv +0 -0
  76. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/CSUSHPISA.csv +0 -0
  77. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/DRSFRMACBS.csv +0 -0
  78. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/FEDFUNDS.csv +0 -0
  79. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/GDP.csv +0 -0
  80. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/GDPC1.csv +0 -0
  81. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/GS10.csv +0 -0
  82. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/GS3.csv +0 -0
  83. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/GS5.csv +0 -0
  84. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/MORTGAGE30US.csv +0 -0
  85. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred/UNRATE.csv +0 -0
  86. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred_loan_rates.csv +0 -0
  87. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred_loan_rates_test_1.csv +0 -0
  88. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred_loan_rates_test_2.csv +0 -0
  89. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred_loan_rates_test_3.csv +0 -0
  90. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred_loan_rates_test_4.csv +0 -0
  91. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/fred_loan_rates_test_5.csv +0 -0
  92. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/datasets/leanding_club_loan_rates.csv +0 -0
  93. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/fred.py +0 -0
  94. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/fred_timeseries.py +0 -0
  95. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/generate_california_housing_csv.py +0 -0
  96. {validmind-2.13.4 → validmind-2.13.5}/validmind/datasets/regression/lending_club.py +0 -0
  97. {validmind-2.13.4 → validmind-2.13.5}/validmind/experimental/__init__.py +0 -0
  98. {validmind-2.13.4 → validmind-2.13.5}/validmind/experimental/agents.py +0 -0
  99. {validmind-2.13.4 → validmind-2.13.5}/validmind/html_templates/__init__.py +0 -0
  100. {validmind-2.13.4 → validmind-2.13.5}/validmind/html_templates/content_blocks.py +0 -0
  101. {validmind-2.13.4 → validmind-2.13.5}/validmind/input_registry.py +0 -0
  102. {validmind-2.13.4 → validmind-2.13.5}/validmind/logging.py +0 -0
  103. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/__init__.py +0 -0
  104. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/foundation.py +0 -0
  105. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/function.py +0 -0
  106. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/huggingface.py +0 -0
  107. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/metadata.py +0 -0
  108. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/pipeline.py +0 -0
  109. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/pytorch.py +0 -0
  110. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/r_model.py +0 -0
  111. {validmind-2.13.4 → validmind-2.13.5}/validmind/models/sklearn.py +0 -0
  112. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/__init__.py +0 -0
  113. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/AbsoluteError.py +0 -0
  114. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/BrierScore.py +0 -0
  115. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/CalibrationError.py +0 -0
  116. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/ClassBalance.py +0 -0
  117. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/Confidence.py +0 -0
  118. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/Correctness.py +0 -0
  119. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/LogLoss.py +0 -0
  120. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/OutlierScore.py +0 -0
  121. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/ProbabilityError.py +0 -0
  122. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/Uncertainty.py +0 -0
  123. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/classification/__init__.py +0 -0
  124. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/GEval.py +0 -0
  125. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/PlanAdherence.py +0 -0
  126. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/PlanQuality.py +0 -0
  127. {validmind-2.13.4 → validmind-2.13.5}/validmind/scorers/llm/deepeval/TaskCompletion.py +0 -0
  128. {validmind-2.13.4 → validmind-2.13.5}/validmind/template.py +0 -0
  129. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/__init__.py +0 -0
  130. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/classifier.py +0 -0
  131. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/cluster.py +0 -0
  132. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/embeddings.py +0 -0
  133. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/llm.py +0 -0
  134. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/nlp.py +0 -0
  135. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/parameters_optimization.py +0 -0
  136. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/regression.py +0 -0
  137. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/statsmodels_timeseries.py +0 -0
  138. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/summarization.py +0 -0
  139. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/tabular_datasets.py +0 -0
  140. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/text_data.py +0 -0
  141. {validmind-2.13.4 → validmind-2.13.5}/validmind/test_suites/time_series.py +0 -0
  142. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/__init__.py +0 -0
  143. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/__types__.py +0 -0
  144. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/_store.py +0 -0
  145. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/comparison.py +0 -0
  146. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ACFandPACFPlot.py +0 -0
  147. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ADF.py +0 -0
  148. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/AutoAR.py +0 -0
  149. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/AutoMA.py +0 -0
  150. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/AutoStationarity.py +0 -0
  151. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/BivariateScatterPlots.py +0 -0
  152. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/BoxPierce.py +0 -0
  153. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ChiSquaredFeaturesTable.py +0 -0
  154. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ClassImbalance.py +0 -0
  155. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/DatasetDescription.py +0 -0
  156. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/DatasetSplit.py +0 -0
  157. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/DescriptiveStatistics.py +0 -0
  158. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/DickeyFullerGLS.py +0 -0
  159. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/Duplicates.py +0 -0
  160. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/EngleGrangerCoint.py +0 -0
  161. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/FeatureTargetCorrelationPlot.py +0 -0
  162. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/HighCardinality.py +0 -0
  163. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/HighPearsonCorrelation.py +0 -0
  164. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/IQROutliersBarPlot.py +0 -0
  165. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/IQROutliersTable.py +0 -0
  166. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/IsolationForestOutliers.py +0 -0
  167. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/JarqueBera.py +0 -0
  168. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/KPSS.py +0 -0
  169. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/LJungBox.py +0 -0
  170. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/LaggedCorrelationHeatmap.py +0 -0
  171. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/MissingValuesBarPlot.py +0 -0
  172. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/MutualInformation.py +0 -0
  173. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/PearsonCorrelationMatrix.py +0 -0
  174. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/PhillipsPerronArch.py +0 -0
  175. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ProtectedClassesCombination.py +0 -0
  176. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ProtectedClassesDescription.py +0 -0
  177. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ProtectedClassesDisparity.py +0 -0
  178. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ProtectedClassesThresholdOptimizer.py +0 -0
  179. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/RollingStatsPlot.py +0 -0
  180. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/RunsTest.py +0 -0
  181. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ScatterPlot.py +0 -0
  182. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ScoreBandDefaultRates.py +0 -0
  183. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/SeasonalDecompose.py +0 -0
  184. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ShapiroWilk.py +0 -0
  185. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/Skewness.py +0 -0
  186. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/SpreadPlot.py +0 -0
  187. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TabularCategoricalBarPlots.py +0 -0
  188. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TabularDateTimeHistograms.py +0 -0
  189. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TabularDescriptionTables.py +0 -0
  190. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TabularNumericalHistograms.py +0 -0
  191. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TargetRateBarPlots.py +0 -0
  192. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TimeSeriesDescription.py +0 -0
  193. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TimeSeriesDescriptiveStatistics.py +0 -0
  194. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TimeSeriesFrequency.py +0 -0
  195. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TimeSeriesHistogram.py +0 -0
  196. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TimeSeriesLinePlot.py +0 -0
  197. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TimeSeriesMissingValues.py +0 -0
  198. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TimeSeriesOutliers.py +0 -0
  199. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/TooManyZeroValues.py +0 -0
  200. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/UniqueRows.py +0 -0
  201. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/WOEBinPlots.py +0 -0
  202. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/WOEBinTable.py +0 -0
  203. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/ZivotAndrewsArch.py +0 -0
  204. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/__init__.py +0 -0
  205. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/CommonWords.py +0 -0
  206. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/Hashtags.py +0 -0
  207. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/LanguageDetection.py +0 -0
  208. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/Mentions.py +0 -0
  209. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/PolarityAndSubjectivity.py +0 -0
  210. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/Punctuations.py +0 -0
  211. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/Sentiment.py +0 -0
  212. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/StopWords.py +0 -0
  213. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/TextDescription.py +0 -0
  214. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/Toxicity.py +0 -0
  215. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/data_validation/nlp/__init__.py +0 -0
  216. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/decorator.py +0 -0
  217. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/load.py +0 -0
  218. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/BertScore.py +0 -0
  219. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/BleuScore.py +0 -0
  220. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ClusterSizeDistribution.py +0 -0
  221. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ContextualRecall.py +0 -0
  222. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/FeaturesAUC.py +0 -0
  223. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/MeteorScore.py +0 -0
  224. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ModelMetadata.py +0 -0
  225. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ModelPredictionResiduals.py +0 -0
  226. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/RegardScore.py +0 -0
  227. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/RegressionResidualsPlot.py +0 -0
  228. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/RougeScore.py +0 -0
  229. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/TimeSeriesPredictionWithCI.py +0 -0
  230. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/TimeSeriesPredictionsPlot.py +0 -0
  231. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/TimeSeriesR2SquareBySegments.py +0 -0
  232. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/TokenDisparity.py +0 -0
  233. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ToxicityScore.py +0 -0
  234. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/__init__.py +0 -0
  235. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/ClusterDistribution.py +0 -0
  236. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/CosineSimilarityComparison.py +0 -0
  237. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/CosineSimilarityDistribution.py +0 -0
  238. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/CosineSimilarityHeatmap.py +0 -0
  239. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/DescriptiveAnalytics.py +0 -0
  240. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/EmbeddingsVisualization2D.py +0 -0
  241. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/EuclideanDistanceComparison.py +0 -0
  242. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/EuclideanDistanceHeatmap.py +0 -0
  243. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/PCAComponentsPairwisePlots.py +0 -0
  244. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/StabilityAnalysisKeyword.py +0 -0
  245. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/StabilityAnalysisRandomNoise.py +0 -0
  246. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/StabilityAnalysisSynonyms.py +0 -0
  247. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/StabilityAnalysisTranslation.py +0 -0
  248. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/TSNEComponentsPairwisePlots.py +0 -0
  249. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/embeddings/utils.py +0 -0
  250. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/NoiseSensitivity.py +0 -0
  251. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/ResponseRelevancy.py +0 -0
  252. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/ragas/utils.py +0 -0
  253. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/AdjustedMutualInformation.py +0 -0
  254. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/AdjustedRandIndex.py +0 -0
  255. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/CalibrationCurve.py +0 -0
  256. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ClassifierPerformance.py +0 -0
  257. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ClassifierThresholdOptimization.py +0 -0
  258. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ClusterCosineSimilarity.py +0 -0
  259. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ClusterPerformanceMetrics.py +0 -0
  260. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/CompletenessScore.py +0 -0
  261. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ConfusionMatrix.py +0 -0
  262. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/FowlkesMallowsScore.py +0 -0
  263. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/HomogeneityScore.py +0 -0
  264. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/KMeansClustersOptimization.py +0 -0
  265. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/MinimumAccuracy.py +0 -0
  266. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/MinimumF1Score.py +0 -0
  267. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/MinimumROCAUCScore.py +0 -0
  268. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ModelParameters.py +0 -0
  269. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ModelsPerformanceComparison.py +0 -0
  270. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/OverfitDiagnosis.py +0 -0
  271. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/PermutationFeatureImportance.py +0 -0
  272. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/PopulationStabilityIndex.py +0 -0
  273. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/PrecisionRecallCurve.py +0 -0
  274. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ROCCurve.py +0 -0
  275. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/RegressionErrors.py +0 -0
  276. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/RegressionErrorsComparison.py +0 -0
  277. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/RegressionPerformance.py +0 -0
  278. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/RegressionR2Square.py +0 -0
  279. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/RegressionR2SquareComparison.py +0 -0
  280. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/SHAPGlobalImportance.py +0 -0
  281. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/ScoreProbabilityAlignment.py +0 -0
  282. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/SilhouettePlot.py +0 -0
  283. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/TrainingTestDegradation.py +0 -0
  284. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/VMeasure.py +0 -0
  285. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/WeakspotsDiagnosis.py +0 -0
  286. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/sklearn/__init__.py +0 -0
  287. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/AutoARIMA.py +0 -0
  288. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/CumulativePredictionProbabilities.py +0 -0
  289. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/DurbinWatsonTest.py +0 -0
  290. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/GINITable.py +0 -0
  291. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/KolmogorovSmirnov.py +0 -0
  292. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/Lilliefors.py +0 -0
  293. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/PredictionProbabilitiesHistogram.py +0 -0
  294. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/RegressionCoeffs.py +0 -0
  295. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/RegressionFeatureSignificance.py +0 -0
  296. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/RegressionModelForecastPlot.py +0 -0
  297. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/RegressionModelForecastPlotLevels.py +0 -0
  298. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/RegressionModelSensitivityPlot.py +0 -0
  299. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/RegressionModelSummary.py +0 -0
  300. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/RegressionPermutationFeatureImportance.py +0 -0
  301. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/ScorecardHistogram.py +0 -0
  302. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/__init__.py +0 -0
  303. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/model_validation/statsmodels/statsutils.py +0 -0
  304. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/CalibrationCurveDrift.py +0 -0
  305. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/ClassDiscriminationDrift.py +0 -0
  306. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/ClassImbalanceDrift.py +0 -0
  307. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/ClassificationAccuracyDrift.py +0 -0
  308. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/ConfusionMatrixDrift.py +0 -0
  309. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/CumulativePredictionProbabilitiesDrift.py +0 -0
  310. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/FeatureDrift.py +0 -0
  311. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/PredictionAcrossEachFeature.py +0 -0
  312. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/PredictionCorrelation.py +0 -0
  313. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/PredictionProbabilitiesHistogramDrift.py +0 -0
  314. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/PredictionQuantilesAcrossFeatures.py +0 -0
  315. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/ROCCurveDrift.py +0 -0
  316. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/ScoreBandsDrift.py +0 -0
  317. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/ScorecardHistogramDrift.py +0 -0
  318. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/ongoing_monitoring/TargetPredictionDistributionPlot.py +0 -0
  319. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/output.py +0 -0
  320. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/plots/BoxPlot.py +0 -0
  321. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/plots/CorrelationHeatmap.py +0 -0
  322. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/plots/HistogramPlot.py +0 -0
  323. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/plots/ViolinPlot.py +0 -0
  324. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/plots/__init__.py +0 -0
  325. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/Bias.py +0 -0
  326. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/Clarity.py +0 -0
  327. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/Conciseness.py +0 -0
  328. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/Delimitation.py +0 -0
  329. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/NegativeInstruction.py +0 -0
  330. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/Robustness.py +0 -0
  331. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/Specificity.py +0 -0
  332. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/prompt_validation/__init__.py +0 -0
  333. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/run.py +0 -0
  334. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/stats/CorrelationAnalysis.py +0 -0
  335. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/stats/DescriptiveStats.py +0 -0
  336. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/stats/NormalityTests.py +0 -0
  337. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/stats/OutlierDetection.py +0 -0
  338. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/stats/__init__.py +0 -0
  339. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/test_providers.py +0 -0
  340. {validmind-2.13.4 → validmind-2.13.5}/validmind/tests/utils.py +0 -0
  341. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/__init__.py +0 -0
  342. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/classification/Accuracy.py +0 -0
  343. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/classification/F1.py +0 -0
  344. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/classification/Precision.py +0 -0
  345. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/classification/ROC_AUC.py +0 -0
  346. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/classification/Recall.py +0 -0
  347. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/AdjustedRSquaredScore.py +0 -0
  348. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/GiniCoefficient.py +0 -0
  349. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/HuberLoss.py +0 -0
  350. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/KolmogorovSmirnovStatistic.py +0 -0
  351. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/MeanAbsoluteError.py +0 -0
  352. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/MeanAbsolutePercentageError.py +0 -0
  353. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/MeanBiasDeviation.py +0 -0
  354. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/MeanSquaredError.py +0 -0
  355. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/QuantileLoss.py +0 -0
  356. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/RSquaredScore.py +0 -0
  357. {validmind-2.13.4 → validmind-2.13.5}/validmind/unit_metrics/regression/RootMeanSquaredError.py +0 -0
  358. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/__init__.py +0 -0
  359. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/dataset/__init__.py +0 -0
  360. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/dataset/utils.py +0 -0
  361. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/figure.py +0 -0
  362. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/html_progress.py +0 -0
  363. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/html_renderer.py +0 -0
  364. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/input.py +0 -0
  365. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/model.py +0 -0
  366. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/result/__init__.py +0 -0
  367. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/result/pii_filter.py +0 -0
  368. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/result/result.jinja +0 -0
  369. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/result/result.py +0 -0
  370. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/result/utils.py +0 -0
  371. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/test_suite/__init__.py +0 -0
  372. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/test_suite/runner.py +0 -0
  373. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/test_suite/summary.py +0 -0
  374. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/test_suite/test.py +0 -0
  375. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/test_suite/test_suite.py +0 -0
  376. {validmind-2.13.4 → validmind-2.13.5}/validmind/vm_models/text_generation_summary.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: validmind
3
- Version: 2.13.4
3
+ Version: 2.13.5
4
4
  Summary: ValidMind Library
5
5
  Author-email: Andres Rodriguez <andres@validmind.ai>, Juan Martinez <juan@validmind.ai>, Anil Sorathiya <anil@validmind.ai>, Luis Pallares <luis@validmind.ai>, John Walz <john@validmind.ai>
6
6
  License: DUAL LICENSE NOTICE
@@ -707,8 +707,10 @@ Requires-Dist: pandas<3.0.0,>=2.0.3
707
707
  Requires-Dist: plotly>=6.0.0
708
708
  Requires-Dist: polars
709
709
  Requires-Dist: python-dotenv
710
+ Requires-Dist: requests<3.0.0,>=2.28.0
710
711
  Requires-Dist: scikit-learn
711
712
  Requires-Dist: seaborn
713
+ Requires-Dist: segno<2.0.0,>=1.6.6
712
714
  Requires-Dist: tabulate<0.10.0,>=0.9.0
713
715
  Requires-Dist: tiktoken
714
716
  Requires-Dist: tqdm
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "validmind"
3
- version = "2.13.4"
3
+ version = "2.13.5"
4
4
  description = "ValidMind Library"
5
5
  readme = "README.pypi.md"
6
6
  requires-python = ">=3.9,<3.15"
@@ -14,6 +14,7 @@ authors = [
14
14
  ]
15
15
  dependencies = [
16
16
  "aiohttp[speedups] (<3.13.1)",
17
+ "requests (>=2.28.0,<3.0.0)",
17
18
  "ipywidgets",
18
19
  "kaleido (>=1.2.0,<2.0.0)",
19
20
  "matplotlib",
@@ -33,6 +34,7 @@ dependencies = [
33
34
  "tqdm",
34
35
  "anywidget",
35
36
  "beautifulsoup4",
37
+ "segno (>=1.6.6,<2.0.0)",
36
38
  ]
37
39
 
38
40
  [project.optional-dependencies]
@@ -122,7 +124,7 @@ pii-detection = [
122
124
 
123
125
  [dependency-groups]
124
126
  dev = [
125
- "black>=22.1.0,<23",
127
+ "black>=22.1.0,<26",
126
128
  "click",
127
129
  "cython>=0.29.34,<0.30",
128
130
  "docstring-parser",
@@ -0,0 +1 @@
1
+ __version__ = "2.13.5"
@@ -20,7 +20,7 @@ __judge_embeddings = None
20
20
  OPENAI_MODEL = "gpt-4.1"
21
21
  OPENAI_EMBEDDINGS_MODEL = "text-embedding-3-small"
22
22
  GEMINI_MODEL = "gemini-2.5-pro"
23
- GEMINI_EMBEDDINGS_MODEL = "models/text-embedding-004"
23
+ GEMINI_EMBEDDINGS_MODEL = "gemini-embedding-001"
24
24
 
25
25
  # can be None, True or False (ternary to represent initial state, ack and failed ack)
26
26
  __ack = None
@@ -59,10 +59,7 @@ def _get_configured_provider():
59
59
  if os.getenv("AZURE_OPENAI_KEY"):
60
60
  return "azure"
61
61
 
62
- if _get_google_api_key():
63
- return "gemini"
64
-
65
- return None
62
+ return "gemini"
66
63
 
67
64
 
68
65
  def get_client_and_model():
@@ -104,18 +101,12 @@ def get_client_and_model():
104
101
 
105
102
  logger.debug(f"Using Azure OpenAI {__model} for generating descriptions")
106
103
 
107
- elif provider == "gemini":
104
+ else:
108
105
  __client = None
109
106
  __model = os.getenv("GEMINI_MODEL", GEMINI_MODEL)
110
107
 
111
108
  logger.debug(f"Using Gemini {__model} for generating descriptions")
112
109
 
113
- else:
114
- raise ValueError(
115
- "OPENAI_API_KEY, AZURE_OPENAI_KEY, GOOGLE_API_KEY, or GEMINI_API_KEY "
116
- "must be setup to use LLM features"
117
- )
118
-
119
110
  return __client, __model
120
111
 
121
112
 
@@ -202,16 +193,18 @@ def _build_gemini_judge_config(model):
202
193
  langchain_google_genai, "GoogleGenerativeAIEmbeddings"
203
194
  )
204
195
  google_api_key = _get_google_api_key()
196
+ chat_kwargs = {"model": model}
197
+ embeddings_kwargs = {
198
+ "model": os.getenv("GEMINI_EMBEDDINGS_MODEL", GEMINI_EMBEDDINGS_MODEL),
199
+ }
200
+
201
+ if google_api_key:
202
+ chat_kwargs["api_key"] = google_api_key
203
+ embeddings_kwargs["google_api_key"] = google_api_key
205
204
 
206
205
  return (
207
- ChatGoogleGenerativeAI(
208
- model=model,
209
- api_key=google_api_key,
210
- ),
211
- GoogleGenerativeAIEmbeddings(
212
- model=os.getenv("GEMINI_EMBEDDINGS_MODEL", GEMINI_EMBEDDINGS_MODEL),
213
- google_api_key=google_api_key,
214
- ),
206
+ ChatGoogleGenerativeAI(**chat_kwargs),
207
+ GoogleGenerativeAIEmbeddings(**embeddings_kwargs),
215
208
  )
216
209
 
217
210
 
@@ -230,6 +223,80 @@ def _build_openai_judge_config(client, model):
230
223
  )
231
224
 
232
225
 
226
+ def _import_deepeval_base_llm():
227
+ try:
228
+ deepeval_base_model = importlib.import_module("deepeval.models.base_model")
229
+ except ImportError:
230
+ raise ImportError(
231
+ "Please run `pip install validmind[llm]` to use Gemini DeepEval scorers"
232
+ )
233
+
234
+ return getattr(deepeval_base_model, "DeepEvalBaseLLM")
235
+
236
+
237
+ def _unwrap_deepeval_response(response):
238
+ return getattr(response, "content", response)
239
+
240
+
241
+ def _build_gemini_deepeval_model(model):
242
+ DeepEvalBaseLLM = _import_deepeval_base_llm()
243
+ judge_llm, _ = _build_gemini_judge_config(model)
244
+
245
+ class GeminiDeepEvalModel(DeepEvalBaseLLM):
246
+ def __init__(self, chat_model, model_name):
247
+ self._chat_model = chat_model
248
+ self._model_name = model_name
249
+ self.model = self.load_model()
250
+
251
+ def load_model(self, *args, **kwargs):
252
+ return self._chat_model
253
+
254
+ def generate(self, prompt: str, schema=None):
255
+ chat_model = self.load_model()
256
+ if schema is not None and hasattr(chat_model, "with_structured_output"):
257
+ response = chat_model.with_structured_output(schema).invoke(prompt)
258
+ else:
259
+ response = chat_model.invoke(prompt)
260
+
261
+ return _unwrap_deepeval_response(response)
262
+
263
+ async def a_generate(self, prompt: str, schema=None):
264
+ chat_model = self.load_model()
265
+ if schema is not None and hasattr(chat_model, "with_structured_output"):
266
+ response = await chat_model.with_structured_output(schema).ainvoke(
267
+ prompt
268
+ )
269
+ else:
270
+ response = await chat_model.ainvoke(prompt)
271
+
272
+ return _unwrap_deepeval_response(response)
273
+
274
+ def get_model_name(self, *args, **kwargs):
275
+ return self._model_name
276
+
277
+ return GeminiDeepEvalModel(judge_llm, model)
278
+
279
+
280
+ def run_deepeval_evaluation(*, test_cases, metrics):
281
+ try:
282
+ from deepeval import evaluate
283
+
284
+ deepeval_test_run = importlib.import_module("deepeval.test_run.test_run")
285
+ except ImportError:
286
+ raise ImportError(
287
+ "Please run `pip install validmind[llm]` to use Gemini DeepEval scorers"
288
+ )
289
+
290
+ original_is_confident = deepeval_test_run.is_confident
291
+
292
+ try:
293
+ # ValidMind scorers should run locally without depending on Confident AI login state.
294
+ deepeval_test_run.is_confident = lambda: False
295
+ return evaluate(test_cases=test_cases, metrics=metrics)
296
+ finally:
297
+ deepeval_test_run.is_confident = original_is_confident
298
+
299
+
233
300
  def get_judge_config(judge_llm=None, judge_embeddings=None):
234
301
  Embeddings, BaseChatModel, FunctionModel = _import_judge_dependencies()
235
302
 
@@ -270,6 +337,10 @@ def get_deepeval_model():
270
337
  _, model = get_client_and_model()
271
338
 
272
339
  if provider == "gemini":
340
+ google_api_key = _get_google_api_key()
341
+ if google_api_key is None:
342
+ return _build_gemini_deepeval_model(model)
343
+
273
344
  try:
274
345
  deepeval_models = importlib.import_module("deepeval.models")
275
346
  except ImportError:
@@ -280,7 +351,7 @@ def get_deepeval_model():
280
351
  GeminiModel = getattr(deepeval_models, "GeminiModel")
281
352
  return GeminiModel(
282
353
  model=model,
283
- api_key=_get_google_api_key(),
354
+ api_key=google_api_key,
284
355
  temperature=0,
285
356
  )
286
357
 
@@ -21,7 +21,12 @@ from aiohttp import FormData
21
21
 
22
22
  from .__version__ import __version__
23
23
  from .client_config import client_config
24
- from .errors import MissingAPICredentialsError, MissingModelIdError, raise_api_error
24
+ from .errors import (
25
+ MissingAPICredentialsError,
26
+ MissingModelIdError,
27
+ ValidMindAuthError,
28
+ raise_api_error,
29
+ )
25
30
  from .logging import get_logger, log_api_operation
26
31
  from .utils import NumpyEncoder, is_html, md_to_html, run_async
27
32
  from .vm_models.figure import Figure
@@ -34,10 +39,30 @@ _api_host = os.getenv("VM_API_HOST")
34
39
  _model_cuid = os.getenv("VM_API_MODEL")
35
40
  _document = None
36
41
  _monitoring = False
42
+ _auth_mode = "api_key"
43
+ _access_token: Optional[str] = None
44
+ _oidc_login_context: Optional[Dict[str, str]] = None
37
45
 
38
46
  __api_session: Optional[aiohttp.ClientSession] = None
39
47
 
40
48
 
49
+ def _invalidate_async_session() -> None:
50
+ """Drop the aiohttp session so the next request picks up new headers."""
51
+ global __api_session
52
+ sess = __api_session
53
+ __api_session = None
54
+ if sess is None or sess.closed:
55
+ return
56
+ try:
57
+ loop = asyncio.get_running_loop()
58
+ loop.create_task(sess.close())
59
+ except RuntimeError:
60
+ try:
61
+ asyncio.run(sess.close())
62
+ except RuntimeError:
63
+ pass
64
+
65
+
41
66
  @atexit.register
42
67
  def _close_session():
43
68
  """Closes the async client session at exit."""
@@ -70,14 +95,21 @@ def get_api_model() -> Optional[str]:
70
95
 
71
96
  def _get_api_headers() -> Dict[str, str]:
72
97
  headers = {
73
- "X-API-KEY": _api_key,
74
- "X-API-SECRET": _api_secret,
75
98
  "X-MODEL-CUID": _model_cuid,
76
99
  "X-MONITORING": str(_monitoring),
77
100
  "X-LIBRARY-VERSION": __version__,
78
101
  }
79
102
  if _document:
80
103
  headers["X-DOCUMENT-TYPE"] = _document
104
+ if _auth_mode == "oidc":
105
+ if not _access_token:
106
+ raise ValidMindAuthError(
107
+ "OAuth access token is missing. Run vm.init() again with issuer and client_id."
108
+ )
109
+ headers["Authorization"] = f"Bearer {_access_token}"
110
+ else:
111
+ headers["X-API-KEY"] = _api_key
112
+ headers["X-API-SECRET"] = _api_secret
81
113
  return headers
82
114
 
83
115
 
@@ -192,14 +224,71 @@ def _ping() -> Dict[str, Any]:
192
224
  )
193
225
 
194
226
 
227
+ def _obtain_oidc_tokens(
228
+ issuer: str,
229
+ client_id: str,
230
+ scope: str,
231
+ audience: Optional[str] = None,
232
+ ) -> Dict[str, Any]:
233
+ """Return a credentials entry dict with access_token, expires_at, refresh_token, etc."""
234
+ from .credentials_store import (
235
+ delete_cached_entry,
236
+ get_cached_entry,
237
+ is_expired,
238
+ normalize_client_id,
239
+ normalize_issuer,
240
+ upsert_cached_entry,
241
+ )
242
+ from .oidc_device import run_device_flow, try_refresh_cached_tokens
243
+
244
+ norm_issuer = normalize_issuer(issuer)
245
+ norm_client_id = normalize_client_id(client_id)
246
+ cached = get_cached_entry(norm_issuer, norm_client_id, audience=audience)
247
+ if cached and not is_expired(cached):
248
+ return cached
249
+ if cached and cached.get("refresh_token"):
250
+ try:
251
+ new_tokens = try_refresh_cached_tokens(
252
+ norm_issuer,
253
+ norm_client_id,
254
+ cached["refresh_token"],
255
+ scope,
256
+ audience=audience,
257
+ )
258
+ upsert_cached_entry(
259
+ norm_issuer, norm_client_id, new_tokens, audience=audience
260
+ )
261
+ return new_tokens
262
+ except ValidMindAuthError:
263
+ delete_cached_entry(norm_issuer, norm_client_id, audience=audience)
264
+ tokens = run_device_flow(norm_issuer, norm_client_id, scope, audience=audience)
265
+ upsert_cached_entry(norm_issuer, norm_client_id, tokens, audience=audience)
266
+ return tokens
267
+
268
+
269
+ def _is_entra_issuer(issuer: str) -> bool:
270
+ return "login.microsoftonline.com" in issuer.lower()
271
+
272
+
273
+ def _select_oidc_bearer_token(entry: Dict[str, Any]) -> str:
274
+ if _is_entra_issuer(entry.get("issuer", "")) and entry.get("id_token"):
275
+ return entry["id_token"]
276
+ return entry["access_token"]
277
+
278
+
195
279
  def init(
196
280
  api_key: Optional[str] = None,
197
281
  api_secret: Optional[str] = None,
198
282
  api_host: Optional[str] = None,
283
+ api_url: Optional[str] = None,
199
284
  model: Optional[str] = None,
200
285
  monitoring: bool = False,
201
286
  generate_descriptions: Optional[bool] = None,
202
287
  document: Optional[str] = None,
288
+ issuer: Optional[str] = None,
289
+ client_id: Optional[str] = None,
290
+ scope: Optional[str] = None,
291
+ audience: Optional[str] = None,
203
292
  ):
204
293
  """
205
294
  Initializes the API client instances and calls the /ping endpoint to ensure
@@ -208,36 +297,82 @@ def init(
208
297
  If the API key and secret are not provided, the client will attempt to
209
298
  retrieve them from the environment variables `VM_API_KEY` and `VM_API_SECRET`.
210
299
 
300
+ Alternatively, pass ``issuer`` and ``client_id`` or set their ``VM_OIDC_*``
301
+ environment variables to authenticate via the OIDC device authorization flow
302
+ (RFC 8628). Tokens are cached under ``~/.validmind/credentials.json``. Do not
303
+ combine API keys with OIDC parameters.
304
+
211
305
  Args:
212
306
  model (str, optional): The model CUID. Defaults to None.
213
307
  api_key (str, optional): The API key. Defaults to None.
214
308
  api_secret (str, optional): The API secret. Defaults to None.
215
- api_host (str, optional): The API host. Defaults to None.
309
+ api_host (str, optional): The API host (tracking base URL). Defaults to
310
+ env ``VM_API_HOST`` or ``VM_API_URL``.
311
+ api_url (str, optional): Alias for ``api_host``. Defaults to env
312
+ ``VM_API_URL`` or ``VM_API_HOST``.
216
313
  monitoring (bool): The ongoing monitoring flag. Defaults to False.
217
314
  generate_descriptions (bool, optional): Whether to use GenAI to generate test result descriptions. Defaults to True.
218
315
  document (str, optional): The name of the document. Omitting this argument is deprecated.
316
+ issuer (str, optional): OIDC issuer URL (e.g. Entra tenant ``.../v2.0``).
317
+ Can be set via env ``VM_OIDC_ISSUER``.
318
+ client_id (str, optional): OAuth public client id for device flow. Can be
319
+ set via env ``VM_OIDC_CLIENT_ID``.
320
+ scope (str, optional): OAuth scopes (default ``openid profile email``).
321
+ Can be set via env ``VM_OIDC_SCOPE``.
322
+ audience (str, optional): Resource / API identifier for the access token
323
+ (e.g. Auth0 API Identifier). Use the same value the ValidMind backend
324
+ expects as ``api_audience`` so the provider can issue RS256 API tokens.
325
+ Can be set via env ``VM_OIDC_AUDIENCE``.
326
+
219
327
  Raises:
220
- ValueError: If the API key and secret are not provided
328
+ MissingAPICredentialsError: If neither API keys nor OIDC parameters can be resolved.
329
+ MissingModelIdError: If model id is missing.
330
+ ValidMindAuthError: If OIDC configuration conflicts or login fails.
221
331
  """
222
332
  global _api_key, _api_secret, _api_host, _model_cuid, _monitoring, _document
333
+ global _auth_mode, _access_token, _oidc_login_context
223
334
 
224
335
  if api_key == "...":
225
336
  # special case to detect when running a notebook placeholder (...)
226
337
  # will override with environment variables for easier local development
227
- api_host = api_key = api_secret = model = None
338
+ api_host = api_url = api_key = api_secret = model = issuer = client_id = (
339
+ audience
340
+ ) = None
228
341
 
229
342
  _model_cuid = model or os.getenv("VM_API_MODEL")
230
343
  if _model_cuid is None:
231
344
  raise MissingModelIdError()
232
345
 
233
- _api_key = api_key or os.getenv("VM_API_KEY")
234
- _api_secret = api_secret or os.getenv("VM_API_SECRET")
235
- if _api_key is None or _api_secret is None:
236
- raise MissingAPICredentialsError()
237
-
238
- _api_host = api_host or os.getenv(
239
- "VM_API_HOST", "http://localhost:5000/api/v1/tracking/"
346
+ resolved_host = (
347
+ api_url
348
+ or api_host
349
+ or os.getenv("VM_API_URL")
350
+ or os.getenv("VM_API_HOST", "http://localhost:5000/api/v1/tracking/")
351
+ )
352
+ oidc_issuer = issuer if issuer is not None else os.getenv("VM_OIDC_ISSUER")
353
+ oidc_client_id = (
354
+ client_id if client_id is not None else os.getenv("VM_OIDC_CLIENT_ID")
355
+ )
356
+ oidc_scope = scope if scope is not None else os.getenv("VM_OIDC_SCOPE")
357
+
358
+ env_key = api_key if api_key is not None else os.getenv("VM_API_KEY")
359
+ env_secret = api_secret if api_secret is not None else os.getenv("VM_API_SECRET")
360
+ has_api_creds = (
361
+ env_key is not None
362
+ and env_secret is not None
363
+ and env_key != ""
364
+ and env_secret != ""
240
365
  )
366
+ has_oidc = bool(oidc_issuer and oidc_client_id)
367
+ if has_oidc and has_api_creds:
368
+ raise ValidMindAuthError(
369
+ "Provide either API credentials (api_key and api_secret) or OIDC "
370
+ "(issuer and client_id), not both."
371
+ )
372
+ if oidc_issuer and not oidc_client_id:
373
+ raise ValidMindAuthError("client_id is required when issuer is set.")
374
+ if oidc_client_id and not oidc_issuer:
375
+ raise ValidMindAuthError("issuer is required when client_id is set.")
241
376
 
242
377
  _monitoring = monitoring
243
378
 
@@ -251,6 +386,41 @@ def init(
251
386
  )
252
387
 
253
388
  _document = document
389
+
390
+ if has_oidc:
391
+ _auth_mode = "oidc"
392
+ _api_key = None
393
+ _api_secret = None
394
+ _api_host = resolved_host
395
+ scope_val = oidc_scope or "openid profile email"
396
+ from .credentials_store import normalize_audience
397
+
398
+ oidc_audience_val = normalize_audience(
399
+ audience if audience is not None else os.getenv("VM_OIDC_AUDIENCE")
400
+ )
401
+ oidc_audience_opt = oidc_audience_val or None
402
+ entry = _obtain_oidc_tokens(
403
+ oidc_issuer, oidc_client_id, scope_val, audience=oidc_audience_opt
404
+ )
405
+ _access_token = _select_oidc_bearer_token(entry)
406
+ _oidc_login_context = {
407
+ "issuer": entry["issuer"],
408
+ "client_id": entry["client_id"],
409
+ "scope": scope_val,
410
+ "audience": entry.get("audience") or oidc_audience_val,
411
+ }
412
+ _invalidate_async_session()
413
+ else:
414
+ if env_key is None or env_secret is None:
415
+ raise MissingAPICredentialsError()
416
+ _auth_mode = "api_key"
417
+ _access_token = None
418
+ _oidc_login_context = None
419
+ _api_key = env_key
420
+ _api_secret = env_secret
421
+ _api_host = resolved_host
422
+ _invalidate_async_session()
423
+
254
424
  reload()
255
425
 
256
426
 
@@ -0,0 +1,179 @@
1
+ # Copyright © 2023-2026 ValidMind Inc. All rights reserved.
2
+ # Refer to the LICENSE file in the root of this repository for details.
3
+ # SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
4
+
5
+ """Persist OIDC tokens for library authentication under ``~/.validmind/``."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import os
11
+ import tempfile
12
+ from datetime import datetime, timedelta, timezone
13
+ from pathlib import Path
14
+ from typing import Any, Dict, Optional
15
+
16
+ from .errors import ValidMindAuthError
17
+
18
+ _CREDENTIALS_VERSION = 1
19
+
20
+
21
+ def normalize_issuer(issuer: str) -> str:
22
+ """Strip whitespace, trailing slash, and matching outer quotes.
23
+
24
+ Surrounding quotes often appear when copying from ``.env`` or notebooks
25
+ (e.g. ``'https://idp.example.com'``), which would otherwise break HTTP clients.
26
+ """
27
+ base = issuer.strip().rstrip("/")
28
+ while len(base) >= 2 and base[0] == base[-1] and base[0] in ('"', "'"):
29
+ base = base[1:-1].strip().rstrip("/")
30
+ return base
31
+
32
+
33
+ def normalize_client_id(client_id: str) -> str:
34
+ """Strip whitespace and matching outer quotes from OAuth ``client_id``."""
35
+ base = client_id.strip()
36
+ while len(base) >= 2 and base[0] == base[-1] and base[0] in ('"', "'"):
37
+ base = base[1:-1].strip()
38
+ return base
39
+
40
+
41
+ def normalize_audience(audience: Optional[str]) -> str:
42
+ """Normalize OAuth resource/API ``audience`` (Identifier). Empty if unset."""
43
+ if not audience:
44
+ return ""
45
+ base = audience.strip()
46
+ while len(base) >= 2 and base[0] == base[-1] and base[0] in ('"', "'"):
47
+ base = base[1:-1].strip()
48
+ return base
49
+
50
+
51
+ def credential_key(issuer: str, client_id: str, audience: Optional[str] = None) -> str:
52
+ base = f"{normalize_issuer(issuer)}|{normalize_client_id(client_id)}"
53
+ aud = normalize_audience(audience)
54
+ if aud:
55
+ return f"{base}|{aud}"
56
+ return base
57
+
58
+
59
+ def credentials_path() -> Path:
60
+ return Path.home() / ".validmind" / "credentials.json"
61
+
62
+
63
+ def _empty_store() -> Dict[str, Any]:
64
+ return {"version": _CREDENTIALS_VERSION, "credentials": {}}
65
+
66
+
67
+ def load_credentials_file(path: Optional[Path] = None) -> Dict[str, Any]:
68
+ path = path or credentials_path()
69
+ if not path.is_file():
70
+ return _empty_store()
71
+ try:
72
+ with open(path, encoding="utf-8") as f:
73
+ data = json.load(f)
74
+ except (json.JSONDecodeError, OSError) as e:
75
+ raise ValidMindAuthError(f"Could not read credentials file {path}: {e}") from e
76
+ if not isinstance(data, dict):
77
+ raise ValidMindAuthError(f"Invalid credentials file format at {path}")
78
+ data.setdefault("version", _CREDENTIALS_VERSION)
79
+ data.setdefault("credentials", {})
80
+ return data
81
+
82
+
83
+ def _atomic_write(path: Path, payload: Dict[str, Any]) -> None:
84
+ path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
85
+ fd, tmp = tempfile.mkstemp(
86
+ dir=str(path.parent), prefix=".credentials-", suffix=".tmp", text=True
87
+ )
88
+ tmp_path = Path(tmp)
89
+ try:
90
+ with os.fdopen(fd, "w", encoding="utf-8") as handle:
91
+ json.dump(payload, handle, indent=2)
92
+ os.chmod(tmp_path, 0o600)
93
+ os.replace(tmp_path, path)
94
+ except Exception:
95
+ try:
96
+ tmp_path.unlink()
97
+ except OSError:
98
+ pass
99
+ raise
100
+
101
+
102
+ def save_credentials_file(data: Dict[str, Any], path: Optional[Path] = None) -> None:
103
+ path = path or credentials_path()
104
+ data = dict(data)
105
+ data["version"] = _CREDENTIALS_VERSION
106
+ if "credentials" not in data or not isinstance(data["credentials"], dict):
107
+ data["credentials"] = {}
108
+ _atomic_write(path, data)
109
+
110
+
111
+ def get_cached_entry(
112
+ issuer: str,
113
+ client_id: str,
114
+ path: Optional[Path] = None,
115
+ audience: Optional[str] = None,
116
+ ) -> Optional[Dict[str, Any]]:
117
+ key = credential_key(issuer, client_id, audience)
118
+ data = load_credentials_file(path)
119
+ entry = data.get("credentials", {}).get(key)
120
+ if not entry:
121
+ return None
122
+ return dict(entry)
123
+
124
+
125
+ def upsert_cached_entry(
126
+ issuer: str,
127
+ client_id: str,
128
+ entry: Dict[str, Any],
129
+ path: Optional[Path] = None,
130
+ audience: Optional[str] = None,
131
+ ) -> None:
132
+ key = credential_key(issuer, client_id, audience)
133
+ norm_issuer = normalize_issuer(issuer)
134
+ aud = normalize_audience(audience)
135
+ data = load_credentials_file(path)
136
+ credentials = dict(data.get("credentials", {}))
137
+ row = {
138
+ "issuer": norm_issuer,
139
+ "client_id": client_id,
140
+ **entry,
141
+ }
142
+ if aud:
143
+ row["audience"] = aud
144
+ credentials[key] = row
145
+ data["credentials"] = credentials
146
+ save_credentials_file(data, path)
147
+
148
+
149
+ def delete_cached_entry(
150
+ issuer: str,
151
+ client_id: str,
152
+ path: Optional[Path] = None,
153
+ audience: Optional[str] = None,
154
+ ) -> None:
155
+ key = credential_key(issuer, client_id, audience)
156
+ data = load_credentials_file(path)
157
+ credentials = dict(data.get("credentials", {}))
158
+ credentials.pop(key, None)
159
+ data["credentials"] = credentials
160
+ save_credentials_file(data, path)
161
+
162
+
163
+ def is_expired(entry: Dict[str, Any], skew_seconds: int = 120) -> bool:
164
+ raw = entry.get("expires_at")
165
+ if not raw:
166
+ return True
167
+ try:
168
+ expires = datetime.fromisoformat(raw.replace("Z", "+00:00"))
169
+ except ValueError:
170
+ return True
171
+ if expires.tzinfo is None:
172
+ expires = expires.replace(tzinfo=timezone.utc)
173
+ return datetime.now(timezone.utc) >= expires - timedelta(seconds=skew_seconds)
174
+
175
+
176
+ def expires_at_from_secs(expires_in: Optional[int]) -> str:
177
+ seconds = int(expires_in) if expires_in is not None else 3600
178
+ when = datetime.now(timezone.utc) + timedelta(seconds=seconds)
179
+ return when.isoformat()