validmind 2.5.8__py3-none-any.whl → 2.5.15__py3-none-any.whl

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 (212) hide show
  1. validmind/__version__.py +1 -1
  2. validmind/ai/test_descriptions.py +26 -7
  3. validmind/api_client.py +89 -43
  4. validmind/client.py +2 -2
  5. validmind/client_config.py +11 -14
  6. validmind/datasets/regression/fred_timeseries.py +67 -138
  7. validmind/template.py +1 -0
  8. validmind/test_suites/__init__.py +0 -2
  9. validmind/test_suites/statsmodels_timeseries.py +1 -1
  10. validmind/test_suites/summarization.py +0 -1
  11. validmind/test_suites/time_series.py +0 -43
  12. validmind/tests/__types__.py +3 -13
  13. validmind/tests/data_validation/ACFandPACFPlot.py +15 -13
  14. validmind/tests/data_validation/ADF.py +31 -24
  15. validmind/tests/data_validation/AutoAR.py +9 -9
  16. validmind/tests/data_validation/AutoMA.py +23 -16
  17. validmind/tests/data_validation/AutoSeasonality.py +18 -16
  18. validmind/tests/data_validation/AutoStationarity.py +21 -16
  19. validmind/tests/data_validation/BivariateScatterPlots.py +67 -96
  20. validmind/tests/data_validation/ChiSquaredFeaturesTable.py +82 -124
  21. validmind/tests/data_validation/ClassImbalance.py +15 -12
  22. validmind/tests/data_validation/DFGLSArch.py +19 -13
  23. validmind/tests/data_validation/DatasetDescription.py +17 -11
  24. validmind/tests/data_validation/DatasetSplit.py +7 -5
  25. validmind/tests/data_validation/DescriptiveStatistics.py +28 -21
  26. validmind/tests/data_validation/Duplicates.py +33 -25
  27. validmind/tests/data_validation/EngleGrangerCoint.py +35 -33
  28. validmind/tests/data_validation/FeatureTargetCorrelationPlot.py +59 -71
  29. validmind/tests/data_validation/HighCardinality.py +19 -12
  30. validmind/tests/data_validation/HighPearsonCorrelation.py +27 -22
  31. validmind/tests/data_validation/IQROutliersBarPlot.py +13 -10
  32. validmind/tests/data_validation/IQROutliersTable.py +40 -36
  33. validmind/tests/data_validation/IsolationForestOutliers.py +21 -14
  34. validmind/tests/data_validation/KPSS.py +34 -29
  35. validmind/tests/data_validation/LaggedCorrelationHeatmap.py +22 -15
  36. validmind/tests/data_validation/MissingValues.py +32 -27
  37. validmind/tests/data_validation/MissingValuesBarPlot.py +25 -21
  38. validmind/tests/data_validation/PearsonCorrelationMatrix.py +71 -84
  39. validmind/tests/data_validation/PhillipsPerronArch.py +37 -30
  40. validmind/tests/data_validation/RollingStatsPlot.py +31 -23
  41. validmind/tests/data_validation/ScatterPlot.py +63 -78
  42. validmind/tests/data_validation/SeasonalDecompose.py +38 -34
  43. validmind/tests/data_validation/Skewness.py +35 -37
  44. validmind/tests/data_validation/SpreadPlot.py +35 -35
  45. validmind/tests/data_validation/TabularCategoricalBarPlots.py +23 -17
  46. validmind/tests/data_validation/TabularDateTimeHistograms.py +21 -13
  47. validmind/tests/data_validation/TabularDescriptionTables.py +51 -16
  48. validmind/tests/data_validation/TabularNumericalHistograms.py +25 -22
  49. validmind/tests/data_validation/TargetRateBarPlots.py +21 -14
  50. validmind/tests/data_validation/TimeSeriesDescription.py +25 -18
  51. validmind/tests/data_validation/TimeSeriesDescriptiveStatistics.py +23 -17
  52. validmind/tests/data_validation/TimeSeriesFrequency.py +24 -17
  53. validmind/tests/data_validation/TimeSeriesHistogram.py +33 -32
  54. validmind/tests/data_validation/TimeSeriesLinePlot.py +17 -10
  55. validmind/tests/data_validation/TimeSeriesMissingValues.py +15 -10
  56. validmind/tests/data_validation/TimeSeriesOutliers.py +37 -33
  57. validmind/tests/data_validation/TooManyZeroValues.py +16 -11
  58. validmind/tests/data_validation/UniqueRows.py +11 -6
  59. validmind/tests/data_validation/WOEBinPlots.py +23 -16
  60. validmind/tests/data_validation/WOEBinTable.py +35 -30
  61. validmind/tests/data_validation/ZivotAndrewsArch.py +34 -28
  62. validmind/tests/data_validation/nlp/CommonWords.py +21 -14
  63. validmind/tests/data_validation/nlp/Hashtags.py +27 -20
  64. validmind/tests/data_validation/nlp/LanguageDetection.py +33 -14
  65. validmind/tests/data_validation/nlp/Mentions.py +21 -15
  66. validmind/tests/data_validation/nlp/PolarityAndSubjectivity.py +32 -9
  67. validmind/tests/data_validation/nlp/Punctuations.py +24 -20
  68. validmind/tests/data_validation/nlp/Sentiment.py +27 -8
  69. validmind/tests/data_validation/nlp/StopWords.py +26 -19
  70. validmind/tests/data_validation/nlp/TextDescription.py +36 -35
  71. validmind/tests/data_validation/nlp/Toxicity.py +32 -9
  72. validmind/tests/decorator.py +81 -42
  73. validmind/tests/model_validation/BertScore.py +36 -27
  74. validmind/tests/model_validation/BleuScore.py +25 -19
  75. validmind/tests/model_validation/ClusterSizeDistribution.py +38 -34
  76. validmind/tests/model_validation/ContextualRecall.py +35 -13
  77. validmind/tests/model_validation/FeaturesAUC.py +32 -13
  78. validmind/tests/model_validation/MeteorScore.py +46 -33
  79. validmind/tests/model_validation/ModelMetadata.py +32 -64
  80. validmind/tests/model_validation/ModelPredictionResiduals.py +75 -73
  81. validmind/tests/model_validation/RegardScore.py +30 -14
  82. validmind/tests/model_validation/RegressionResidualsPlot.py +10 -5
  83. validmind/tests/model_validation/RougeScore.py +36 -30
  84. validmind/tests/model_validation/TimeSeriesPredictionWithCI.py +30 -14
  85. validmind/tests/model_validation/TimeSeriesPredictionsPlot.py +27 -30
  86. validmind/tests/model_validation/TimeSeriesR2SquareBySegments.py +68 -63
  87. validmind/tests/model_validation/TokenDisparity.py +31 -23
  88. validmind/tests/model_validation/ToxicityScore.py +26 -17
  89. validmind/tests/model_validation/embeddings/ClusterDistribution.py +24 -20
  90. validmind/tests/model_validation/embeddings/CosineSimilarityComparison.py +30 -27
  91. validmind/tests/model_validation/embeddings/CosineSimilarityDistribution.py +7 -5
  92. validmind/tests/model_validation/embeddings/CosineSimilarityHeatmap.py +32 -23
  93. validmind/tests/model_validation/embeddings/DescriptiveAnalytics.py +7 -5
  94. validmind/tests/model_validation/embeddings/EmbeddingsVisualization2D.py +15 -11
  95. validmind/tests/model_validation/embeddings/EuclideanDistanceComparison.py +29 -29
  96. validmind/tests/model_validation/embeddings/EuclideanDistanceHeatmap.py +34 -25
  97. validmind/tests/model_validation/embeddings/PCAComponentsPairwisePlots.py +38 -26
  98. validmind/tests/model_validation/embeddings/StabilityAnalysis.py +40 -1
  99. validmind/tests/model_validation/embeddings/StabilityAnalysisKeyword.py +18 -17
  100. validmind/tests/model_validation/embeddings/StabilityAnalysisRandomNoise.py +40 -45
  101. validmind/tests/model_validation/embeddings/StabilityAnalysisSynonyms.py +17 -19
  102. validmind/tests/model_validation/embeddings/StabilityAnalysisTranslation.py +29 -25
  103. validmind/tests/model_validation/embeddings/TSNEComponentsPairwisePlots.py +38 -28
  104. validmind/tests/model_validation/ragas/AnswerCorrectness.py +5 -4
  105. validmind/tests/model_validation/ragas/AnswerRelevance.py +5 -4
  106. validmind/tests/model_validation/ragas/AnswerSimilarity.py +5 -4
  107. validmind/tests/model_validation/ragas/AspectCritique.py +7 -0
  108. validmind/tests/model_validation/ragas/ContextEntityRecall.py +9 -8
  109. validmind/tests/model_validation/ragas/ContextPrecision.py +5 -4
  110. validmind/tests/model_validation/ragas/ContextRecall.py +5 -4
  111. validmind/tests/model_validation/ragas/Faithfulness.py +5 -4
  112. validmind/tests/model_validation/ragas/utils.py +6 -0
  113. validmind/tests/model_validation/sklearn/AdjustedMutualInformation.py +19 -12
  114. validmind/tests/model_validation/sklearn/AdjustedRandIndex.py +22 -17
  115. validmind/tests/model_validation/sklearn/ClassifierPerformance.py +27 -25
  116. validmind/tests/model_validation/sklearn/ClusterCosineSimilarity.py +7 -5
  117. validmind/tests/model_validation/sklearn/ClusterPerformance.py +40 -78
  118. validmind/tests/model_validation/sklearn/ClusterPerformanceMetrics.py +15 -17
  119. validmind/tests/model_validation/sklearn/CompletenessScore.py +17 -11
  120. validmind/tests/model_validation/sklearn/ConfusionMatrix.py +22 -15
  121. validmind/tests/model_validation/sklearn/FeatureImportance.py +95 -0
  122. validmind/tests/model_validation/sklearn/FowlkesMallowsScore.py +7 -7
  123. validmind/tests/model_validation/sklearn/HomogeneityScore.py +19 -12
  124. validmind/tests/model_validation/sklearn/HyperParametersTuning.py +35 -30
  125. validmind/tests/model_validation/sklearn/KMeansClustersOptimization.py +10 -5
  126. validmind/tests/model_validation/sklearn/MinimumAccuracy.py +32 -32
  127. validmind/tests/model_validation/sklearn/MinimumF1Score.py +23 -23
  128. validmind/tests/model_validation/sklearn/MinimumROCAUCScore.py +15 -10
  129. validmind/tests/model_validation/sklearn/ModelsPerformanceComparison.py +26 -19
  130. validmind/tests/model_validation/sklearn/OverfitDiagnosis.py +38 -18
  131. validmind/tests/model_validation/sklearn/PermutationFeatureImportance.py +31 -25
  132. validmind/tests/model_validation/sklearn/PopulationStabilityIndex.py +8 -6
  133. validmind/tests/model_validation/sklearn/PrecisionRecallCurve.py +24 -17
  134. validmind/tests/model_validation/sklearn/ROCCurve.py +12 -7
  135. validmind/tests/model_validation/sklearn/RegressionErrors.py +74 -130
  136. validmind/tests/model_validation/sklearn/RegressionErrorsComparison.py +27 -12
  137. validmind/tests/model_validation/sklearn/{RegressionModelsPerformanceComparison.py → RegressionPerformance.py} +18 -20
  138. validmind/tests/model_validation/sklearn/RegressionR2Square.py +55 -93
  139. validmind/tests/model_validation/sklearn/RegressionR2SquareComparison.py +32 -13
  140. validmind/tests/model_validation/sklearn/RobustnessDiagnosis.py +36 -32
  141. validmind/tests/model_validation/sklearn/SHAPGlobalImportance.py +7 -5
  142. validmind/tests/model_validation/sklearn/SilhouettePlot.py +27 -19
  143. validmind/tests/model_validation/sklearn/TrainingTestDegradation.py +25 -18
  144. validmind/tests/model_validation/sklearn/VMeasure.py +14 -13
  145. validmind/tests/model_validation/sklearn/WeakspotsDiagnosis.py +7 -5
  146. validmind/tests/model_validation/statsmodels/AutoARIMA.py +24 -18
  147. validmind/tests/model_validation/statsmodels/BoxPierce.py +14 -10
  148. validmind/tests/model_validation/statsmodels/CumulativePredictionProbabilities.py +73 -104
  149. validmind/tests/model_validation/statsmodels/DurbinWatsonTest.py +19 -12
  150. validmind/tests/model_validation/statsmodels/GINITable.py +44 -77
  151. validmind/tests/model_validation/statsmodels/JarqueBera.py +27 -22
  152. validmind/tests/model_validation/statsmodels/KolmogorovSmirnov.py +33 -34
  153. validmind/tests/model_validation/statsmodels/LJungBox.py +32 -28
  154. validmind/tests/model_validation/statsmodels/Lilliefors.py +27 -24
  155. validmind/tests/model_validation/statsmodels/PredictionProbabilitiesHistogram.py +87 -119
  156. validmind/tests/model_validation/statsmodels/RegressionCoeffs.py +100 -0
  157. validmind/tests/model_validation/statsmodels/RegressionFeatureSignificance.py +14 -9
  158. validmind/tests/model_validation/statsmodels/RegressionModelForecastPlot.py +17 -13
  159. validmind/tests/model_validation/statsmodels/RegressionModelForecastPlotLevels.py +46 -43
  160. validmind/tests/model_validation/statsmodels/RegressionModelSensitivityPlot.py +38 -36
  161. validmind/tests/model_validation/statsmodels/RegressionModelSummary.py +30 -28
  162. validmind/tests/model_validation/statsmodels/RegressionPermutationFeatureImportance.py +18 -11
  163. validmind/tests/model_validation/statsmodels/RunsTest.py +32 -28
  164. validmind/tests/model_validation/statsmodels/ScorecardHistogram.py +75 -107
  165. validmind/tests/model_validation/statsmodels/ShapiroWilk.py +15 -8
  166. validmind/tests/ongoing_monitoring/FeatureDrift.py +10 -6
  167. validmind/tests/ongoing_monitoring/PredictionAcrossEachFeature.py +31 -25
  168. validmind/tests/ongoing_monitoring/PredictionCorrelation.py +29 -21
  169. validmind/tests/ongoing_monitoring/TargetPredictionDistributionPlot.py +31 -23
  170. validmind/tests/prompt_validation/Bias.py +14 -11
  171. validmind/tests/prompt_validation/Clarity.py +16 -14
  172. validmind/tests/prompt_validation/Conciseness.py +7 -5
  173. validmind/tests/prompt_validation/Delimitation.py +23 -22
  174. validmind/tests/prompt_validation/NegativeInstruction.py +7 -5
  175. validmind/tests/prompt_validation/Robustness.py +12 -10
  176. validmind/tests/prompt_validation/Specificity.py +13 -11
  177. validmind/tests/prompt_validation/ai_powered_test.py +6 -0
  178. validmind/tests/run.py +68 -23
  179. validmind/unit_metrics/__init__.py +81 -144
  180. validmind/unit_metrics/classification/{sklearn/Accuracy.py → Accuracy.py} +1 -1
  181. validmind/unit_metrics/classification/{sklearn/F1.py → F1.py} +1 -1
  182. validmind/unit_metrics/classification/{sklearn/Precision.py → Precision.py} +1 -1
  183. validmind/unit_metrics/classification/{sklearn/ROC_AUC.py → ROC_AUC.py} +1 -2
  184. validmind/unit_metrics/classification/{sklearn/Recall.py → Recall.py} +1 -1
  185. validmind/unit_metrics/regression/{sklearn/AdjustedRSquaredScore.py → AdjustedRSquaredScore.py} +1 -1
  186. validmind/unit_metrics/regression/GiniCoefficient.py +1 -1
  187. validmind/unit_metrics/regression/HuberLoss.py +1 -1
  188. validmind/unit_metrics/regression/KolmogorovSmirnovStatistic.py +1 -1
  189. validmind/unit_metrics/regression/{sklearn/MeanAbsoluteError.py → MeanAbsoluteError.py} +1 -1
  190. validmind/unit_metrics/regression/MeanAbsolutePercentageError.py +1 -1
  191. validmind/unit_metrics/regression/MeanBiasDeviation.py +1 -1
  192. validmind/unit_metrics/regression/{sklearn/MeanSquaredError.py → MeanSquaredError.py} +1 -1
  193. validmind/unit_metrics/regression/QuantileLoss.py +1 -1
  194. validmind/unit_metrics/regression/{sklearn/RSquaredScore.py → RSquaredScore.py} +1 -1
  195. validmind/unit_metrics/regression/{sklearn/RootMeanSquaredError.py → RootMeanSquaredError.py} +1 -1
  196. validmind/vm_models/dataset/dataset.py +2 -0
  197. validmind/vm_models/figure.py +5 -0
  198. validmind/vm_models/test/result_wrapper.py +93 -132
  199. {validmind-2.5.8.dist-info → validmind-2.5.15.dist-info}/METADATA +1 -1
  200. {validmind-2.5.8.dist-info → validmind-2.5.15.dist-info}/RECORD +203 -210
  201. validmind/tests/data_validation/ANOVAOneWayTable.py +0 -138
  202. validmind/tests/data_validation/BivariateFeaturesBarPlots.py +0 -142
  203. validmind/tests/data_validation/BivariateHistograms.py +0 -117
  204. validmind/tests/data_validation/HeatmapFeatureCorrelations.py +0 -124
  205. validmind/tests/data_validation/MissingValuesRisk.py +0 -88
  206. validmind/tests/model_validation/ModelMetadataComparison.py +0 -59
  207. validmind/tests/model_validation/sklearn/FeatureImportanceComparison.py +0 -83
  208. validmind/tests/model_validation/statsmodels/RegressionCoeffsPlot.py +0 -135
  209. validmind/tests/model_validation/statsmodels/RegressionModelsCoeffs.py +0 -103
  210. {validmind-2.5.8.dist-info → validmind-2.5.15.dist-info}/LICENSE +0 -0
  211. {validmind-2.5.8.dist-info → validmind-2.5.15.dist-info}/WHEEL +0 -0
  212. {validmind-2.5.8.dist-info → validmind-2.5.15.dist-info}/entry_points.txt +0 -0
@@ -63,19 +63,63 @@ async def update_metadata(content_id: str, text: str, _json: Union[Dict, List] =
63
63
 
64
64
 
65
65
  def plot_figures(figures: List[Figure]) -> None:
66
- """
67
- Plot figures to a ipywidgets GridBox
68
- """
69
-
66
+ """Plot figures to a ipywidgets GridBox"""
70
67
  plots = [figure.to_widget() for figure in figures]
71
-
72
68
  num_columns = 2 if len(figures) > 1 else 1
69
+
73
70
  return GridBox(
74
71
  plots,
75
72
  layout=Layout(grid_template_columns=f"repeat({num_columns}, 1fr)"),
76
73
  )
77
74
 
78
75
 
76
+ def _summary_tables_to_widget(summary: ResultSummary):
77
+ """Convert summary (list of json tables) into ipywidgets"""
78
+ widgets = []
79
+
80
+ for table in summary.results:
81
+ if table.metadata and table.metadata.title:
82
+ widgets.append(HTML(f"<h4>{table.metadata.title}</h4>"))
83
+
84
+ df_html = (
85
+ pd.DataFrame(table.data)
86
+ .style.format(precision=4)
87
+ .hide(axis="index")
88
+ .set_table_styles(
89
+ [
90
+ {
91
+ "selector": "",
92
+ "props": [("width", "100%")],
93
+ },
94
+ {
95
+ "selector": "th",
96
+ "props": [("text-align", "left")],
97
+ },
98
+ {
99
+ "selector": "tbody tr:nth-child(even)",
100
+ "props": [("background-color", "#FFFFFF")],
101
+ },
102
+ {
103
+ "selector": "tbody tr:nth-child(odd)",
104
+ "props": [("background-color", "#F5F5F5")],
105
+ },
106
+ {
107
+ "selector": "td, th",
108
+ "props": [
109
+ ("padding-left", "5px"),
110
+ ("padding-right", "5px"),
111
+ ],
112
+ },
113
+ ]
114
+ )
115
+ .set_properties(**{"text-align": "left"})
116
+ .to_html(escape=False)
117
+ )
118
+ widgets.append(HTML(df_html))
119
+
120
+ return widgets
121
+
122
+
79
123
  @dataclass
80
124
  class ResultWrapper(ABC):
81
125
  """Base Class for test suite results"""
@@ -105,53 +149,6 @@ class ResultWrapper(ABC):
105
149
 
106
150
  return self.to_widget()
107
151
 
108
- def _summary_tables_to_widget(self, summary: ResultSummary):
109
- """
110
- Create an ipywdiget representation of the summary tables
111
- """
112
- tables = []
113
- for table in summary.results:
114
- # Explore advanced styling
115
- summary_table = (
116
- pd.DataFrame(table.data)
117
- .style.format(precision=4)
118
- .hide(axis="index")
119
- .set_table_styles(
120
- [
121
- {
122
- "selector": "",
123
- "props": [("width", "100%")],
124
- },
125
- {
126
- "selector": "th",
127
- "props": [("text-align", "left")],
128
- },
129
- {
130
- "selector": "tbody tr:nth-child(even)",
131
- "props": [("background-color", "#FFFFFF")],
132
- },
133
- {
134
- "selector": "tbody tr:nth-child(odd)",
135
- "props": [("background-color", "#F5F5F5")],
136
- },
137
- {
138
- "selector": "td, th",
139
- "props": [
140
- ("padding-left", "5px"),
141
- ("padding-right", "5px"),
142
- ],
143
- },
144
- ]
145
- )
146
- .set_properties(**{"text-align": "left"})
147
- .to_html(escape=False)
148
- ) # table.data is an orient=records dump
149
-
150
- if table.metadata and table.metadata.title:
151
- tables.append(HTML(value=f"<h3>{table.metadata.title}</h3>"))
152
- tables.append(HTML(value=summary_table))
153
- return tables
154
-
155
152
  def _validate_section_id_for_block(self, section_id: str, position: int = None):
156
153
  """
157
154
  Validate the section_id exits on the template before logging. We validate
@@ -244,9 +241,11 @@ class MetricResultWrapper(ResultWrapper):
244
241
  """
245
242
 
246
243
  name: str = "Metric"
247
- figures: Optional[List[Figure]] = None
244
+ scalar: Optional[Union[int, float]] = None
248
245
  metric: Optional[MetricResult] = None
249
- inputs: List[str] = None
246
+ figures: Optional[List[Figure]] = None
247
+ inputs: List[str] = None # List of input ids
248
+ params: Dict = None
250
249
 
251
250
  def __repr__(self) -> str:
252
251
  if self.metric:
@@ -254,18 +253,12 @@ class MetricResultWrapper(ResultWrapper):
254
253
  else:
255
254
  return f'{self.__class__.__name__}(result_id="{self.result_id}", figures)'
256
255
 
257
- def __str__(self) -> str:
258
- if self.metric:
259
- return f'{self.__class__.__name__}(result_id="{self.result_id}", metric, figures)'
260
- else:
261
- return f"{self.__class__.__name__}(result_id={self.result_id}, figures)"
262
-
263
256
  def to_widget(self):
264
257
  if self.metric and self.metric.key == "dataset_description":
265
258
  return ""
266
259
 
267
260
  vbox_children = [
268
- HTML(value=f"<h1>{test_id_to_name(self.result_id)}</h1>"),
261
+ HTML(f"<h1>{test_id_to_name(self.result_id)}</h1>"),
269
262
  ]
270
263
 
271
264
  if self.result_metadata:
@@ -274,70 +267,36 @@ class MetricResultWrapper(ResultWrapper):
274
267
  metric_description = metric_description.get_description()
275
268
  self.result_metadata[0]["text"] = metric_description
276
269
 
277
- vbox_children.append(HTML(value=metric_description))
270
+ vbox_children.append(HTML(metric_description))
271
+
272
+ if self.scalar is not None:
273
+ vbox_children.append(
274
+ HTML(
275
+ "<h3>Unit Metrics</h3>"
276
+ f"<p>{test_id_to_name(self.result_id)} "
277
+ f"(<i>{self.result_id}</i>): "
278
+ f"<code>{self.scalar}</code></p>"
279
+ )
280
+ )
278
281
 
279
282
  if self.metric:
283
+ vbox_children.append(HTML("<h3>Tables</h3>"))
280
284
  if self.output_template:
281
- rendered_output = OutputTemplate(self.output_template).render(
282
- value=self.metric.value
285
+ vbox_children.append(
286
+ HTML(
287
+ OutputTemplate(self.output_template).render(
288
+ value=self.metric.value
289
+ )
290
+ )
283
291
  )
284
- vbox_children.append(HTML(rendered_output))
285
292
  elif self.metric.summary:
286
- tables = self._summary_tables_to_widget(self.metric.summary)
287
- vbox_children.extend(tables)
293
+ vbox_children.extend(_summary_tables_to_widget(self.metric.summary))
288
294
 
289
295
  if self.figures:
290
- vbox_children.append(HTML(value="<h3>Plots</h3>"))
296
+ vbox_children.append(HTML("<h3>Plots</h3>"))
291
297
  plot_widgets = plot_figures(self.figures)
292
298
  vbox_children.append(plot_widgets)
293
299
 
294
- vbox_children.append(
295
- HTML(
296
- value="""
297
- <style>
298
- .metric-result {
299
- background-color: #F5F5F5;
300
- border: 1px solid #e0e0e0;
301
- border-radius: 4px;
302
- padding: 10px;
303
- margin: 10px 0;
304
- }
305
- .metric-result-body {
306
- display: flex;
307
- flex-direction: column;
308
- justify-content: space-between;
309
- gap: 10px;
310
- }
311
- .metric-body-column {
312
- display: flex;
313
- flex-direction: column;
314
- justify-content: space-between;
315
- width: 33%;
316
- }
317
- .metric-body-column-title {
318
- font-size: 16px;
319
- font-weight: 600;
320
- }
321
- .metric-value {
322
- display: flex;
323
- flex-direction: column;
324
- justify-content: space-between;
325
- margin-top: 15px;
326
- }
327
- .metric-value-title {
328
- font-size: 16px;
329
- font-weight: 600;
330
- }
331
- .metric-value-value {
332
- font-size: 14px;
333
- font-weight: 500;
334
- margin-top: 10px;
335
- }
336
- </style>
337
- """
338
- )
339
- )
340
-
341
300
  return VBox(vbox_children)
342
301
 
343
302
  def _get_filtered_summary(self):
@@ -379,6 +338,17 @@ class MetricResultWrapper(ResultWrapper):
379
338
  ):
380
339
  tasks = [] # collect tasks to run in parallel (async)
381
340
 
341
+ if self.scalar is not None:
342
+ # scalars (unit metrics) are logged as key-value pairs associated with the inventory model
343
+ tasks.append(
344
+ api_client.alog_metric(
345
+ key=self.result_id,
346
+ value=self.scalar,
347
+ inputs=self.inputs,
348
+ params=self.params,
349
+ )
350
+ )
351
+
382
352
  if self.metric:
383
353
  if self.metric.summary and not unsafe:
384
354
  self.metric.summary = self._get_filtered_summary()
@@ -411,7 +381,7 @@ class MetricResultWrapper(ResultWrapper):
411
381
  )
412
382
  )
413
383
 
414
- await asyncio.gather(*tasks)
384
+ return await asyncio.gather(*tasks)
415
385
 
416
386
 
417
387
  @dataclass
@@ -433,24 +403,13 @@ class ThresholdTestResultWrapper(ResultWrapper):
433
403
  else:
434
404
  return f'{self.__class__.__name__}(result_id="{self.result_id}", figures)'
435
405
 
436
- def __str__(self) -> str:
437
- if self.test_results:
438
- return (
439
- f'{self.__class__.__name__}(result_id="{self.result_id}", test_results)'
440
- )
441
- else:
442
- return f'{self.__class__.__name__}(result_id="{self.result_id}", figures)'
443
-
444
406
  def to_widget(self):
445
407
  vbox_children = []
446
408
  description_html = []
447
409
 
448
- test_params = json.dumps(self.test_results.params, cls=NumpyEncoder, indent=2)
449
-
450
- test_title = test_id_to_name(self.test_results.test_name)
451
410
  description_html.append(
452
411
  f"""
453
- <h1>{test_title} {"✅" if self.test_results.passed else "❌"}</h1>
412
+ <h1>{test_id_to_name(self.test_results.test_name)} {"✅" if self.test_results.passed else "❌"}</h1>
454
413
  """
455
414
  )
456
415
 
@@ -462,6 +421,7 @@ class ThresholdTestResultWrapper(ResultWrapper):
462
421
 
463
422
  description_html.append(metric_description)
464
423
 
424
+ test_params = json.dumps(self.test_results.params, cls=NumpyEncoder, indent=2)
465
425
  description_html.append(
466
426
  f"""
467
427
  <h4>Test Parameters</h4>
@@ -469,14 +429,14 @@ class ThresholdTestResultWrapper(ResultWrapper):
469
429
  """
470
430
  )
471
431
 
472
- vbox_children.append(HTML(value="".join(description_html)))
432
+ vbox_children.append(HTML("".join(description_html)))
473
433
 
474
434
  if self.test_results.summary:
475
- tables = self._summary_tables_to_widget(self.test_results.summary)
476
- vbox_children.extend(tables)
435
+ vbox_children.append(HTML("<h3>Tables</h3>"))
436
+ vbox_children.extend(_summary_tables_to_widget(self.test_results.summary))
477
437
 
478
438
  if self.figures:
479
- vbox_children.append(HTML(value="<h3>Plots</h3>"))
439
+ vbox_children.append(HTML("<h3>Plots</h3>"))
480
440
  plot_widgets = plot_figures(self.figures)
481
441
  vbox_children.append(plot_widgets)
482
442
 
@@ -491,6 +451,7 @@ class ThresholdTestResultWrapper(ResultWrapper):
491
451
 
492
452
  if self.figures:
493
453
  tasks.append(api_client.log_figures(self.figures))
454
+
494
455
  if hasattr(self, "result_metadata") and self.result_metadata:
495
456
  description = self.result_metadata[0].get("text", "")
496
457
  if isinstance(description, DescriptionFuture):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: validmind
3
- Version: 2.5.8
3
+ Version: 2.5.15
4
4
  Summary: ValidMind Developer Framework
5
5
  License: Commercial License
6
6
  Author: Andres Rodriguez