From f8e99c7b2112b6c2a62171e06117fc11963daafa Mon Sep 17 00:00:00 2001 From: Amirabbas Jalali <258926044+amirabbas-jalali-bentley@users.noreply.github.com> Date: Thu, 29 Oct 2026 11:54:17 -0600 Subject: [PATCH 1/2] Remove explicit-null serializers for tail extrapolation The conditioned simulation and simulation report tasks now treat `distribution.tail_extrapolation` and `tail_extrapolation.lower` as optional, so the SDK no longer needs to force explicit nulls for them. Drop the custom model serializers on `TailExtrapolationParams`, `DistributionParams` and `SimulationReportDistribution`. Unset values are now omitted from the request, like every other optional field. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../geostatistics/conditioned_simulator.py | 20 ++----------------- .../tasks/geostatistics/simulation_report.py | 12 ++--------- .../test_conditioned_simulator_tasks.py | 10 ++++------ .../test_simulation_report_tasks.py | 8 +++----- 4 files changed, 11 insertions(+), 39 deletions(-) diff --git a/packages/evo-compute/src/evo/compute/tasks/geostatistics/conditioned_simulator.py b/packages/evo-compute/src/evo/compute/tasks/geostatistics/conditioned_simulator.py index a53ad9872..2b66f7fe3 100644 --- a/packages/evo-compute/src/evo/compute/tasks/geostatistics/conditioned_simulator.py +++ b/packages/evo-compute/src/evo/compute/tasks/geostatistics/conditioned_simulator.py @@ -41,13 +41,13 @@ from __future__ import annotations -from typing import Any, ClassVar, Literal, Protocol, runtime_checkable +from typing import ClassVar, Literal, Protocol, runtime_checkable import pandas as pd from evo.common import IContext, IFeedback from evo.objects import ObjectSchema from evo.objects.typed import BaseObject, object_from_reference -from pydantic import BaseModel, Field, SerializerFunctionWrapHandler, field_validator, model_serializer +from pydantic import BaseModel, Field, field_validator from ..common import ( AttributeExpression, @@ -103,14 +103,6 @@ class TailExtrapolationParams(BaseModel): upper: UpperTailParams lower: LowerTailParams | None = None - @model_serializer(mode="wrap") - def _serialize(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]: - result = handler(self) - # The service requires this key even when null; TaskRunner dumps with exclude_none=True. - if self.lower is None: - result["lower"] = None - return result - class DistributionParams(BaseModel): """Parameters for the continuous distribution used for normal-score transformation.""" @@ -124,14 +116,6 @@ class DistributionParams(BaseModel): tail_extrapolation: TailExtrapolationParams | None = None """Optional tail extrapolation parameters.""" - @model_serializer(mode="wrap") - def _serialize(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]: - result = handler(self) - # The service requires this key even when null; TaskRunner dumps with exclude_none=True. - if self.tail_extrapolation is None: - result["tail_extrapolation"] = None - return result - class ConSimMaterialCategory(BaseModel): """Material category for loss calculation within simulation.""" diff --git a/packages/evo-compute/src/evo/compute/tasks/geostatistics/simulation_report.py b/packages/evo-compute/src/evo/compute/tasks/geostatistics/simulation_report.py index 46d7ab0a7..580c20aa0 100644 --- a/packages/evo-compute/src/evo/compute/tasks/geostatistics/simulation_report.py +++ b/packages/evo-compute/src/evo/compute/tasks/geostatistics/simulation_report.py @@ -46,10 +46,10 @@ from __future__ import annotations -from typing import Any, ClassVar, Literal +from typing import ClassVar, Literal from evo.common import IContext -from pydantic import BaseModel, Field, SerializerFunctionWrapHandler, field_validator, model_serializer +from pydantic import BaseModel, Field, field_validator from ..common import ( AttributeExpression, @@ -107,14 +107,6 @@ class SimulationReportDistribution(BaseModel): weights: AttributeExpression | None = None """Optional sample weights. Accepts a typed attribute or an attribute expression.""" - @model_serializer(mode="wrap") - def _serialize(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]: - result = handler(self) - # The service requires this key even when null; TaskRunner dumps with exclude_none=True. - if self.tail_extrapolation is None: - result["tail_extrapolation"] = None - return result - class SimReportContextItem(BaseModel): """Single key-value detail for a simulation report.""" diff --git a/packages/evo-compute/tests/geostatistics/test_conditioned_simulator_tasks.py b/packages/evo-compute/tests/geostatistics/test_conditioned_simulator_tasks.py index a76608f1b..7fce228ce 100644 --- a/packages/evo-compute/tests/geostatistics/test_conditioned_simulator_tasks.py +++ b/packages/evo-compute/tests/geostatistics/test_conditioned_simulator_tasks.py @@ -176,20 +176,18 @@ def test_distribution_params(self): d = _dump(params) self.assertEqual(d["distribution"]["tail_extrapolation"]["upper"]["power"], 0.5) - def test_distribution_without_tail_extrapolation_sends_null(self): + def test_distribution_without_tail_extrapolation_omits_key(self): d = _dump(_params(distribution=DistributionParams(weights="declustering_weights"))) - self.assertEqual(d["distribution"], {"weights": "declustering_weights", "tail_extrapolation": None}) + self.assertEqual(d["distribution"], {"weights": "declustering_weights"}) - def test_tail_extrapolation_without_lower_sends_null(self): + def test_tail_extrapolation_without_lower_omits_key(self): params = _params( distribution=DistributionParams( tail_extrapolation=TailExtrapolationParams(upper=UpperTailParams(power=0.5, max=100.0)), ), ) d = _dump(params) - self.assertEqual( - d["distribution"]["tail_extrapolation"], {"upper": {"power": 0.5, "max": 100.0}, "lower": None} - ) + self.assertEqual(d["distribution"]["tail_extrapolation"], {"upper": {"power": 0.5, "max": 100.0}}) def test_tail_extrapolation_with_lower(self): params = _params( diff --git a/packages/evo-compute/tests/geostatistics/test_simulation_report_tasks.py b/packages/evo-compute/tests/geostatistics/test_simulation_report_tasks.py index d129e2962..29f017b38 100644 --- a/packages/evo-compute/tests/geostatistics/test_simulation_report_tasks.py +++ b/packages/evo-compute/tests/geostatistics/test_simulation_report_tasks.py @@ -180,16 +180,14 @@ def test_distribution_with_weights(self): d = _dump(_params(distribution=SimulationReportDistribution(weights="declustering_weights"))) self.assertEqual(d["distribution"]["weights"], "declustering_weights") - def test_distribution_without_tail_extrapolation_sends_null(self): + def test_distribution_without_tail_extrapolation_omits_key(self): d = _dump(_params(distribution=SimulationReportDistribution(weights="declustering_weights"))) - self.assertEqual(d["distribution"], {"weights": "declustering_weights", "tail_extrapolation": None}) + self.assertEqual(d["distribution"], {"weights": "declustering_weights"}) def test_distribution_with_tail_extrapolation(self): tail = TailExtrapolationParams(upper=UpperTailParams(power=0.5, max=100.0)) d = _dump(_params(distribution=SimulationReportDistribution(tail_extrapolation=tail))) - self.assertEqual( - d["distribution"]["tail_extrapolation"], {"upper": {"power": 0.5, "max": 100.0}, "lower": None} - ) + self.assertEqual(d["distribution"]["tail_extrapolation"], {"upper": {"power": 0.5, "max": 100.0}}) def test_report_context(self): d = _dump( From 3699c5717442ccc28591a46653c8be9a130f4609 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:57:22 +0000 Subject: [PATCH 2/2] Update to MkDocs documentation --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index cc72d803b..b14423b38 100644 --- a/uv.lock +++ b/uv.lock @@ -1409,7 +1409,7 @@ test = [ [[package]] name = "evo-widgets" -version = "0.2.2" +version = "0.2.3" source = { editable = "packages/evo-widgets" } dependencies = [ { name = "evo-sdk-common" },