From 8565811b7c129a6df9e9e4e46333fbcac8299461 Mon Sep 17 00:00:00 2001 From: John Walz Date: Fri, 13 Dec 2024 11:55:57 -0500 Subject: [PATCH 1/6] feat: wait for description to be generated if a post-processing function needs to run --- validmind/ai/test_descriptions.py | 4 ---- validmind/tests/run.py | 7 ++++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/validmind/ai/test_descriptions.py b/validmind/ai/test_descriptions.py index b240b6206..b40ef9d7b 100644 --- a/validmind/ai/test_descriptions.py +++ b/validmind/ai/test_descriptions.py @@ -79,15 +79,11 @@ def generate_description( "No tables, unit metric or figures provided - cannot generate description" ) - # # TODO: fix circular import - # from validmind.ai.utils import get_client_and_model - client, model = get_client_and_model() # get last part of test id test_name = title or test_id.split(".")[-1] - # TODO: fully support metrics if metric is not None: tables = [] if not tables else tables tables.append( diff --git a/validmind/tests/run.py b/validmind/tests/run.py index c3b28f050..ec38b45bb 100644 --- a/validmind/tests/run.py +++ b/validmind/tests/run.py @@ -11,7 +11,7 @@ from uuid import uuid4 from validmind import __version__ -from validmind.ai.test_descriptions import get_result_description +from validmind.ai.test_descriptions import DescriptionFuture, get_result_description from validmind.errors import MissingRequiredTestInputError from validmind.input_registry import input_registry from validmind.logging import get_logger @@ -397,6 +397,11 @@ def run_test( result.metadata = _get_run_metadata(duration_seconds=end_time - start_time) if post_process_fn: + # wait for the description to be generated if necessary + if isinstance(result.description, DescriptionFuture): + result.description = result.description.get_description() + result._was_description_generated = True + result = post_process_fn(result) if show: From a18bee53196908041ed28151fffd53e47818a6c1 Mon Sep 17 00:00:00 2001 From: John Walz Date: Fri, 13 Dec 2024 12:01:43 -0500 Subject: [PATCH 2/6] feat: using __get_attribute__ instead of always waiting... this way its lazily retrieved --- validmind/tests/run.py | 5 ----- validmind/vm_models/result/result.py | 33 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/validmind/tests/run.py b/validmind/tests/run.py index ec38b45bb..7ac71ba6e 100644 --- a/validmind/tests/run.py +++ b/validmind/tests/run.py @@ -397,11 +397,6 @@ def run_test( result.metadata = _get_run_metadata(duration_seconds=end_time - start_time) if post_process_fn: - # wait for the description to be generated if necessary - if isinstance(result.description, DescriptionFuture): - result.description = result.description.get_description() - result._was_description_generated = True - result = post_process_fn(result) if show: diff --git a/validmind/vm_models/result/result.py b/validmind/vm_models/result/result.py index 8cea3641b..279f2d3af 100644 --- a/validmind/vm_models/result/result.py +++ b/validmind/vm_models/result/result.py @@ -171,10 +171,9 @@ class TestResult(Result): _was_description_generated: bool = False _unsafe: bool = False - @property - def test_name(self) -> str: - """Get the test name, using custom title if available.""" - return self.title or test_id_to_name(self.result_id) + def __post_init__(self): + if self.ref_id is None: + self.ref_id = str(uuid4()) def __repr__(self) -> str: attrs = [ @@ -197,9 +196,19 @@ def __repr__(self) -> str: return f'TestResult("{self.result_id}", {", ".join(attrs)})' - def __post_init__(self): - if self.ref_id is None: - self.ref_id = str(uuid4()) + # add special handling for result.description so it can be lazily retrieved + def __getattribute__(self, name): + if name == "description": + if isinstance(self.description, DescriptionFuture): + self._was_description_generated = True + return self.description.get_description() + + return super().__getattribute__(name) + + @property + def test_name(self) -> str: + """Get the test name, using custom title if available.""" + return self.title or test_id_to_name(self.result_id) def _get_flat_inputs(self): # remove duplicates by `input_id` @@ -290,10 +299,6 @@ def remove_figure(self, index: int = 0): self.figures.pop(index) def to_widget(self): - if isinstance(self.description, DescriptionFuture): - self.description = self.description.get_description() - self._was_description_generated = True - if self.metric is not None and not self.tables and not self.figures: return HTML(f"

{self.test_name}: {self.metric}

") @@ -308,8 +313,6 @@ def to_widget(self): ), "show_metric": self.metric is not None, "metric": self.metric, - "tables": self.tables, - "figures": self.figures, } rendered = get_result_template().render(**template_data) @@ -407,10 +410,6 @@ async def log_async( ) if self.description: - if isinstance(self.description, DescriptionFuture): - self.description = self.description.get_description() - self._was_description_generated = True - revision_name = ( AI_REVISION_NAME if self._was_description_generated From a18793a322cc8a2db90a4f5bfdd8b80980f91a54 Mon Sep 17 00:00:00 2001 From: John Walz Date: Fri, 13 Dec 2024 12:03:18 -0500 Subject: [PATCH 3/6] 2.6.12 --- pyproject.toml | 2 +- validmind/__version__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index baeee3750..e1360b17a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ description = "ValidMind Library" license = "Commercial License" name = "validmind" readme = "README.pypi.md" -version = "2.6.11" +version = "2.6.12" [tool.poetry.dependencies] aiohttp = {extras = ["speedups"], version = "*"} diff --git a/validmind/__version__.py b/validmind/__version__.py index 396adecc4..21c662b21 100644 --- a/validmind/__version__.py +++ b/validmind/__version__.py @@ -1 +1 @@ -__version__ = "2.6.11" +__version__ = "2.6.12" From f5db9079683227e8d34481fff5ca8c3b68f5da47 Mon Sep 17 00:00:00 2001 From: John Walz Date: Fri, 13 Dec 2024 12:04:11 -0500 Subject: [PATCH 4/6] chore: linter complaint --- validmind/tests/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validmind/tests/run.py b/validmind/tests/run.py index 7ac71ba6e..c3b28f050 100644 --- a/validmind/tests/run.py +++ b/validmind/tests/run.py @@ -11,7 +11,7 @@ from uuid import uuid4 from validmind import __version__ -from validmind.ai.test_descriptions import DescriptionFuture, get_result_description +from validmind.ai.test_descriptions import get_result_description from validmind.errors import MissingRequiredTestInputError from validmind.input_registry import input_registry from validmind.logging import get_logger From 56bda7a913e92cb4e412a9d8fcd4c5f3e7c22ac9 Mon Sep 17 00:00:00 2001 From: John Walz Date: Fri, 13 Dec 2024 12:13:28 -0500 Subject: [PATCH 5/6] feat: fix recursion issue from looping into itself when accessing self.description --- validmind/vm_models/result/result.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validmind/vm_models/result/result.py b/validmind/vm_models/result/result.py index 279f2d3af..edcebd1b4 100644 --- a/validmind/vm_models/result/result.py +++ b/validmind/vm_models/result/result.py @@ -199,9 +199,11 @@ def __repr__(self) -> str: # add special handling for result.description so it can be lazily retrieved def __getattribute__(self, name): if name == "description": - if isinstance(self.description, DescriptionFuture): + description = super().__getattribute__("description") + + if isinstance(description, DescriptionFuture): self._was_description_generated = True - return self.description.get_description() + self.description = description.get_description() return super().__getattribute__(name) From 7ebaf2440726785434c59a6c2bff70a26e44119a Mon Sep 17 00:00:00 2001 From: John Walz Date: Fri, 13 Dec 2024 12:26:28 -0500 Subject: [PATCH 6/6] feat: adding comment --- validmind/vm_models/result/result.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validmind/vm_models/result/result.py b/validmind/vm_models/result/result.py index edcebd1b4..17e6dd942 100644 --- a/validmind/vm_models/result/result.py +++ b/validmind/vm_models/result/result.py @@ -196,8 +196,8 @@ def __repr__(self) -> str: return f'TestResult("{self.result_id}", {", ".join(attrs)})' - # add special handling for result.description so it can be lazily retrieved def __getattribute__(self, name): + # lazy load description if its a DescriptionFuture (generated in background) if name == "description": description = super().__getattribute__("description")