luminarycloud 0.16.0__py3-none-any.whl → 0.16.2__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 (60) hide show
  1. luminarycloud/_client/client.py +6 -1
  2. luminarycloud/_helpers/_code_representation.py +5 -3
  3. luminarycloud/_helpers/warnings/__init__.py +0 -1
  4. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.py +88 -34
  5. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.pyi +100 -10
  6. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.py +68 -0
  7. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.pyi +24 -0
  8. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.py +128 -107
  9. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.pyi +48 -3
  10. luminarycloud/_proto/cad/shape_pb2.py +78 -19
  11. luminarycloud/_proto/cad/transformation_pb2.py +34 -15
  12. luminarycloud/_proto/client/simulation_pb2.py +348 -350
  13. luminarycloud/_proto/client/simulation_pb2.pyi +95 -95
  14. luminarycloud/_proto/geometry/geometry_pb2.py +68 -68
  15. luminarycloud/_proto/geometry/geometry_pb2.pyi +10 -6
  16. luminarycloud/_proto/hexmesh/hexmesh_pb2.py +40 -15
  17. luminarycloud/_proto/hexmesh/hexmesh_pb2.pyi +58 -1
  18. luminarycloud/_proto/lcstatus/codes_pb2.py +3 -2
  19. luminarycloud/_proto/lcstatus/codes_pb2.pyi +4 -0
  20. luminarycloud/_proto/upload/upload_pb2.py +25 -15
  21. luminarycloud/_proto/upload/upload_pb2.pyi +31 -2
  22. luminarycloud/enum/quantity_type.py +4 -0
  23. luminarycloud/enum/tables.py +1 -0
  24. luminarycloud/enum/vis_enums.py +20 -0
  25. luminarycloud/feature_modification.py +6 -7
  26. luminarycloud/geometry.py +26 -2
  27. luminarycloud/geometry_version.py +23 -0
  28. luminarycloud/named_variable_set.py +3 -4
  29. luminarycloud/outputs/stopping_conditions.py +0 -3
  30. luminarycloud/params/simulation/adjoint_.py +4 -4
  31. luminarycloud/params/simulation/material/material_fluid_.py +1 -1
  32. luminarycloud/params/simulation/material/material_solid_.py +1 -1
  33. luminarycloud/params/simulation/output_.py +1 -1
  34. luminarycloud/params/simulation/physics/fluid/initialization/fluid_existing_solution_.py +28 -0
  35. luminarycloud/params/simulation/simulation_param_.py +6 -0
  36. luminarycloud/physics_ai/architectures.py +0 -4
  37. luminarycloud/physics_ai/inference.py +0 -4
  38. luminarycloud/physics_ai/models.py +0 -4
  39. luminarycloud/physics_ai/solution.py +2 -2
  40. luminarycloud/pipelines/__init__.py +6 -0
  41. luminarycloud/pipelines/arguments.py +105 -0
  42. luminarycloud/pipelines/core.py +204 -20
  43. luminarycloud/pipelines/operators.py +11 -9
  44. luminarycloud/pipelines/parameters.py +25 -4
  45. luminarycloud/project.py +13 -12
  46. luminarycloud/simulation_param.py +29 -17
  47. luminarycloud/simulation_template.py +15 -13
  48. luminarycloud/solution.py +1 -3
  49. luminarycloud/tables.py +5 -4
  50. luminarycloud/thirdparty/__init__.py +12 -0
  51. luminarycloud/thirdparty/onshape.py +170 -0
  52. luminarycloud/vis/__init__.py +2 -0
  53. luminarycloud/vis/data_extraction.py +40 -1
  54. luminarycloud/vis/filters.py +128 -2
  55. luminarycloud/vis/visualization.py +1 -1
  56. luminarycloud/volume_selection.py +2 -2
  57. {luminarycloud-0.16.0.dist-info → luminarycloud-0.16.2.dist-info}/METADATA +6 -6
  58. {luminarycloud-0.16.0.dist-info → luminarycloud-0.16.2.dist-info}/RECORD +59 -57
  59. luminarycloud/_helpers/warnings/experimental.py +0 -48
  60. {luminarycloud-0.16.0.dist-info → luminarycloud-0.16.2.dist-info}/WHEEL +0 -0
@@ -126,6 +126,29 @@ class GeometryVersion(ProtoWrapperBase):
126
126
  )
127
127
  return list(res.features_issues)
128
128
 
129
+ def to_code(self) -> str:
130
+ """
131
+ Returns the Python code that creates (from scratch) an identical geometry of
132
+ this particular version.
133
+
134
+ Returns
135
+ -------
136
+ str
137
+ The SDK code that can be used to recreate this specific geometry version.
138
+
139
+ Examples
140
+ --------
141
+ >>> geometry_version = lc.get_geometry_version("version-id")
142
+ >>> python_code = geometry_version.to_code()
143
+ >>> print(python_code)
144
+ """
145
+ req = geometrypb.GetSdkCodeRequest(
146
+ geometry_id=self.geometry_id,
147
+ geometry_version_id=self.id,
148
+ )
149
+ res: geometrypb.GetSdkCodeResponse = get_default_client().GetSdkCode(req)
150
+ return res.sdk_code
151
+
129
152
 
130
153
  def get_geometry_version(id: str) -> GeometryVersion:
131
154
  """
@@ -4,7 +4,6 @@ from datetime import datetime
4
4
  from ._client import get_default_client
5
5
  from ._helpers._timestamp_to_datetime import timestamp_to_datetime
6
6
  from ._helpers.named_variables import _named_variables_from_proto, _named_variables_to_proto
7
- from ._helpers.warnings import experimental
8
7
  from ._proto.api.v0.luminarycloud.named_variable_set import (
9
8
  named_variable_set_pb2 as namedvariablepb,
10
9
  )
@@ -12,13 +11,12 @@ from ._wrapper import ProtoWrapper, ProtoWrapperBase
12
11
  from .types import ProjectID, NamedVariableSetID, LcFloat
13
12
 
14
13
 
15
- @experimental
16
14
  @ProtoWrapper(namedvariablepb.NamedVariableSet)
17
15
  class NamedVariableSet(ProtoWrapperBase):
18
16
  """
19
17
  Represents a named variable set object.
20
18
 
21
- Note: This class is experimental and may change in the future.
19
+ .. warning:: This feature is experimental and may change or be removed without notice.
22
20
 
23
21
  Attributes
24
22
  ----------
@@ -119,11 +117,12 @@ class NamedVariableSet(ProtoWrapperBase):
119
117
  return self._named_variables
120
118
 
121
119
 
122
- @experimental
123
120
  def get_named_variable_set(id: NamedVariableSetID) -> NamedVariableSet:
124
121
  """
125
122
  Retrieve a specific named variable set by ID.
126
123
 
124
+ .. warning:: This feature is experimental and may change or be removed without notice.
125
+
127
126
  Parameters
128
127
  ----------
129
128
  id : str
@@ -4,7 +4,6 @@ from .._client import get_default_client
4
4
  from .._proto.api.v0.luminarycloud.stopping_condition import stopping_condition_pb2 as stopcondpb
5
5
  from .._proto.output import output_pb2 as outputpb
6
6
  from dataclasses import dataclass
7
- from .._helpers.warnings import experimental
8
7
 
9
8
 
10
9
  @dataclass
@@ -155,7 +154,6 @@ def delete_stopping_condition(simulation_template_id: str, id: str) -> None:
155
154
  get_default_client().DeleteStoppingCondition(req)
156
155
 
157
156
 
158
- @experimental
159
157
  def get_general_stopping_conditions(simulation_template_id: str) -> GeneralStoppingConditions:
160
158
  """
161
159
  Get the general stopping conditions for a simulation template.
@@ -174,7 +172,6 @@ def get_general_stopping_conditions(simulation_template_id: str) -> GeneralStopp
174
172
  return GeneralStoppingConditions._from_proto(res.basic_stopping_conditions)
175
173
 
176
174
 
177
- @experimental
178
175
  def update_general_stopping_conditions(
179
176
  simulation_template_id: str,
180
177
  max_iterations: int | None = None,
@@ -22,7 +22,7 @@ from luminarycloud.params.simulation._lib import ParamGroupWrapper, create_uniqu
22
22
  class Adjoint(CodeRepr, ParamGroupWrapper[clientpb.Adjoint]):
23
23
  """Settings for adjoint sensitivity analysis."""
24
24
 
25
- output: Any | None = None
25
+ _output: Any | None = None
26
26
  "Function to differentiate."
27
27
  surfaces: list[str] = field(default_factory=list)
28
28
  ""
@@ -33,8 +33,8 @@ class Adjoint(CodeRepr, ParamGroupWrapper[clientpb.Adjoint]):
33
33
 
34
34
  def _to_proto(self) -> clientpb.Adjoint:
35
35
  _proto = clientpb.Adjoint()
36
- if self.output is not None:
37
- _proto.adjoint_output.CopyFrom(self.output)
36
+ if self._output is not None:
37
+ _proto.adjoint_output.CopyFrom(self._output)
38
38
  if self.surfaces is not None:
39
39
  _proto.surfaces.extend(self.surfaces)
40
40
  if self.deformed_coords_id is not None:
@@ -44,7 +44,7 @@ class Adjoint(CodeRepr, ParamGroupWrapper[clientpb.Adjoint]):
44
44
  return _proto
45
45
 
46
46
  def _from_proto(self, proto: clientpb.Adjoint) -> None:
47
- self.output = proto.adjoint_output
47
+ self._output = proto.adjoint_output
48
48
  self.surfaces.extend(proto.surfaces)
49
49
  self.deformed_coords_id = proto.deformed_coords_id
50
50
  self.primal_simulation_id = proto.primal_simulation_id
@@ -85,7 +85,7 @@ class MaterialFluid(CodeRepr, ParamGroupWrapper[clientpb.MaterialFluid]):
85
85
  "Model for the laminar thermal conductivity of a fluid. Possible types: ``PrescribedPrandtlNumber``, ``PrescribedConductivity``, ``TemperatureDependentConductivity`` from the ``thermal_conductivity_model`` module."
86
86
  boussinesq_approximation: BoussinesqApproximation = field(default_factory=BoussinesqOn)
87
87
  "Introduce a body force due to thermal expansion without modifying the material density. Possible types: ``BoussinesqOff``, ``BoussinesqOn`` from the ``boussinesq_approximation`` module."
88
- preset: enum.MaterialFluidPreset = enum.MaterialFluidPreset.CUSTOM_MATERIAL_FLUID
88
+ preset: enum.MaterialFluidPreset = enum.MaterialFluidPreset.STANDARD_AIR
89
89
  "Select a predefined set of material properties or allow a custom set of properties."
90
90
  viscosity_model: ViscosityModel = field(default_factory=Sutherland)
91
91
  "Models available for the dynamic viscosity of the fluid. Possible types: ``Sutherland``, ``PrescribedViscosity``, ``TemperatureDependentViscosity`` from the ``viscosity_model`` module."
@@ -30,7 +30,7 @@ class MaterialSolid(CodeRepr, ParamGroupWrapper[clientpb.MaterialSolid]):
30
30
  "The thermal conductivity of the material."
31
31
  thermal_conductivity_table: RectilinearTable | None = None
32
32
  "Correlation between thermal conductivity and temperature."
33
- preset: enum.MaterialSolidPreset = enum.MaterialSolidPreset.CUSTOM_MATERIAL_SOLID
33
+ preset: enum.MaterialSolidPreset = enum.MaterialSolidPreset.ALUMINUM
34
34
  "Select a predefined set of material properties or allow a custom set of properties."
35
35
 
36
36
  def _to_proto(self) -> clientpb.MaterialSolid:
@@ -22,7 +22,7 @@ from luminarycloud.params.simulation._lib import ParamGroupWrapper, create_uniqu
22
22
  class Output(CodeRepr, ParamGroupWrapper[clientpb.Output]):
23
23
  """Solution output settings."""
24
24
 
25
- iters_per_output: int = 1000
25
+ iters_per_output: int = 0
26
26
  "Number of (pseudo) timesteps between successive full solution output. If ≤0, only the final solution is written."
27
27
  include_residuals: bool = False
28
28
  "Include the residuals for each equation in the volume solution."
@@ -19,6 +19,10 @@ from luminarycloud.params.simulation._lib import ParamGroupWrapper, create_uniqu
19
19
 
20
20
  from luminarycloud.params.simulation.physics.fluid.initialization_fluid_ import InitializationFluid
21
21
  from luminarycloud.params.simulation.physics.fluid.initialization_fluid_ import *
22
+ from luminarycloud.params.simulation.physics.fluid.initialization.turbulence_initialization_ import (
23
+ TurbulenceInitialization,
24
+ )
25
+ from luminarycloud.params.simulation.physics.fluid.initialization.turbulence_initialization_ import *
22
26
 
23
27
 
24
28
  @dataclass(kw_only=True)
@@ -27,16 +31,40 @@ class FluidExistingSolution(InitializationFluid):
27
31
 
28
32
  solution_id: str = ""
29
33
  "ID for the existing solution to use for initialization."
34
+ turbulence: TurbulenceInitialization = field(default_factory=TurbulenceInitialization)
35
+ ""
30
36
 
31
37
  def _to_proto(self) -> clientpb.InitializationFluid:
32
38
  _proto = super()._to_proto()
33
39
  _proto.initialization_type = clientpb.InitializationType.EXISTING_SOLUTION
34
40
  if self.solution_id is not None:
35
41
  _proto.existing_solution_id = self.solution_id
42
+ _proto.turbulent_variable_initialization_type_sa = self.turbulence.spalart_allmaras.value
43
+ _proto.turbulent_variable_initialization_type_komega = self.turbulence.komega.value
44
+ _proto.init_turbulent_viscosity_ratio.CopyFrom(
45
+ _to_ad_proto(self.turbulence.viscosity_ratio)
46
+ )
47
+ _proto.init_turbulent_viscosity.CopyFrom(_to_ad_proto(self.turbulence.viscosity))
48
+ _proto.init_turbulence_intensity.CopyFrom(_to_ad_proto(self.turbulence.intensity))
49
+ _proto.uniform_nu_tilde.CopyFrom(_to_ad_proto(self.turbulence.sa_variable))
50
+ _proto.uniform_tke.CopyFrom(_to_ad_proto(self.turbulence.tke))
51
+ _proto.uniform_omega.CopyFrom(_to_ad_proto(self.turbulence.omega))
36
52
  return _proto
37
53
 
38
54
  def _from_proto(self, proto: clientpb.InitializationFluid) -> None:
39
55
  super()._from_proto(proto)
40
56
  assert proto.initialization_type == clientpb.InitializationType.EXISTING_SOLUTION
41
57
  self.solution_id = proto.existing_solution_id
58
+ self.turbulence.spalart_allmaras = enum.TurbulentVariableInitializationTypeSa(
59
+ proto.turbulent_variable_initialization_type_sa
60
+ )
61
+ self.turbulence.komega = enum.TurbulentVariableInitializationTypeKomega(
62
+ proto.turbulent_variable_initialization_type_komega
63
+ )
64
+ self.turbulence.viscosity_ratio = _from_ad_proto(proto.init_turbulent_viscosity_ratio)
65
+ self.turbulence.viscosity = _from_ad_proto(proto.init_turbulent_viscosity)
66
+ self.turbulence.intensity = _from_ad_proto(proto.init_turbulence_intensity)
67
+ self.turbulence.sa_variable = _from_ad_proto(proto.uniform_nu_tilde)
68
+ self.turbulence.tke = _from_ad_proto(proto.uniform_tke)
69
+ self.turbulence.omega = _from_ad_proto(proto.uniform_omega)
42
70
  return None
@@ -77,6 +77,8 @@ class SimulationParam(CodeRepr, ParamGroupWrapper[clientpb.SimulationParam]):
77
77
  "Body frame."
78
78
  surface_name: dict[str, SurfaceName] = field(default_factory=dict)
79
79
  "Surface name map."
80
+ _table_references: dict[str, Any] = field(default_factory=dict)
81
+ "Solution inputs - metadata for general n-dimensional rectilinear grid data (Monitor points, radial distribution, blade geometry, airfoil performance)."
80
82
  output: Output = field(default_factory=Output)
81
83
  "Solution output settings."
82
84
  entity_relationships: EntityRelationships = field(default_factory=EntityRelationships)
@@ -115,6 +117,9 @@ class SimulationParam(CodeRepr, ParamGroupWrapper[clientpb.SimulationParam]):
115
117
  if self.surface_name is not None:
116
118
  for k, v in self.surface_name.items():
117
119
  _proto.surface_name[k].CopyFrom(v._to_proto())
120
+ if self._table_references is not None:
121
+ for k, v in self._table_references.items():
122
+ _proto.table_references[k].CopyFrom(v)
118
123
  if self.output is not None:
119
124
  _proto.output.CopyFrom(self.output._to_proto())
120
125
  if self.entity_relationships is not None:
@@ -140,6 +145,7 @@ class SimulationParam(CodeRepr, ParamGroupWrapper[clientpb.SimulationParam]):
140
145
  self.monitor_plane = [MonitorPlane.from_proto(v) for v in proto.monitor_plane]
141
146
  self.body_frame = BodyFrame.from_proto(proto.body_frame)
142
147
  self.surface_name = {k: SurfaceName.from_proto(v) for k, v in proto.surface_name.items()}
148
+ self._table_references.update(proto.table_references)
143
149
  self.output = Output.from_proto(proto.output)
144
150
  self.entity_relationships = EntityRelationships.from_proto(proto.entity_relationships)
145
151
  self.adaptive_mesh_refinement = AdaptiveMeshRefinement.from_proto(
@@ -4,12 +4,10 @@ from typing import List, Optional
4
4
  from .._client import get_default_client
5
5
  from .._proto.api.v0.luminarycloud.physics_ai import physics_ai_pb2 as physaipb
6
6
  from .._wrapper import ProtoWrapper, ProtoWrapperBase
7
- from .._helpers.warnings import experimental
8
7
  from ..types.ids import PhysicsAiArchitectureID, PhysicsAiArchitectureVersionID
9
8
  from ..enum.physics_ai_lifecycle_state import PhysicsAiLifecycleState
10
9
 
11
10
 
12
- @experimental
13
11
  @ProtoWrapper(physaipb.PhysicsAiArchitectureVersion)
14
12
  class PhysicsAiArchitectureVersion(ProtoWrapperBase):
15
13
  """
@@ -25,7 +23,6 @@ class PhysicsAiArchitectureVersion(ProtoWrapperBase):
25
23
  _proto: physaipb.PhysicsAiArchitectureVersion
26
24
 
27
25
 
28
- @experimental
29
26
  @ProtoWrapper(physaipb.PhysicsAiArchitecture)
30
27
  class PhysicsAiArchitecture(ProtoWrapperBase):
31
28
  """
@@ -55,7 +52,6 @@ class PhysicsAiArchitecture(ProtoWrapperBase):
55
52
  return self.versions[0] if self.versions else None
56
53
 
57
54
 
58
- @experimental
59
55
  def list_architectures() -> List[PhysicsAiArchitecture]:
60
56
  """
61
57
  List available Physics AI architectures for model training.
@@ -14,7 +14,6 @@ from .._proto.api.v0.luminarycloud.inference import inference_pb2 as inferencepb
14
14
  from .._proto.inferenceservice import inferenceservice_pb2 as inferenceservicepb
15
15
  from .._wrapper import ProtoWrapper, ProtoWrapperBase
16
16
  from ..project import Project
17
- from .._helpers.warnings import experimental
18
17
  from ..project import Project
19
18
  from .._helpers import upload_file
20
19
  from .._proto.upload import upload_pb2 as uploadpb
@@ -48,7 +47,6 @@ class ExtAeroInferenceResult:
48
47
  self.pressure_surface = inference_result.get("pressure_surface", None)
49
48
 
50
49
 
51
- @experimental
52
50
  def external_aero_inference(
53
51
  project: Project, stl_file: str, checkpoint_file: str, config_name: str, stencil_size: int
54
52
  ) -> ExtAeroInferenceResult:
@@ -77,7 +75,6 @@ def external_aero_inference(
77
75
  return ExtAeroInferenceResult(result)
78
76
 
79
77
 
80
- @experimental
81
78
  def perform_inference(
82
79
  project: Project, stl_file: str, checkpoint_file: str, config_name: str, stencil_size: int
83
80
  ) -> dict[str, Any]:
@@ -144,7 +141,6 @@ def perform_inference(
144
141
  return currated
145
142
 
146
143
 
147
- @experimental
148
144
  def start_inference_job(
149
145
  project: Project,
150
146
  stl_url: str,
@@ -4,12 +4,10 @@ from typing import List, Optional
4
4
  from .._client import get_default_client
5
5
  from .._proto.api.v0.luminarycloud.physics_ai import physics_ai_pb2 as physaipb
6
6
  from .._wrapper import ProtoWrapper, ProtoWrapperBase
7
- from .._helpers.warnings import experimental
8
7
  from ..types.ids import PhysicsAiModelID, PhysicsAiModelVersionID
9
8
  from ..enum.physics_ai_lifecycle_state import PhysicsAiLifecycleState
10
9
 
11
10
 
12
- @experimental
13
11
  @ProtoWrapper(physaipb.PhysicsAiModelVersion)
14
12
  class PhysicsAiModelVersion(ProtoWrapperBase):
15
13
  """
@@ -24,7 +22,6 @@ class PhysicsAiModelVersion(ProtoWrapperBase):
24
22
  _proto: physaipb.PhysicsAiModelVersion
25
23
 
26
24
 
27
- @experimental
28
25
  @ProtoWrapper(physaipb.PhysicsAiModel)
29
26
  class PhysicsAiModel(ProtoWrapperBase):
30
27
  """
@@ -54,7 +51,6 @@ class PhysicsAiModel(ProtoWrapperBase):
54
51
  return self.versions[0] if self.versions else None
55
52
 
56
53
 
57
- @experimental
58
54
  def list_pretrained_models() -> List[PhysicsAiModel]:
59
55
  """
60
56
  List available pretrained Physics AI models.
@@ -4,12 +4,10 @@ import tarfile
4
4
  from typing import List, Optional, BinaryIO, cast
5
5
 
6
6
  from .._client import get_default_client
7
- from .._helpers.warnings import experimental
8
7
  from .._helpers.download import download_solution_physics_ai as _download_solution_physics_ai
9
8
  from ..enum.quantity_type import QuantityType
10
9
 
11
10
 
12
- @experimental
13
11
  def _download_processed_solution_physics_ai( # noqa: F841
14
12
  solution_id: str,
15
13
  exclude_surfaces: Optional[List[str]] = None,
@@ -25,6 +23,8 @@ def _download_processed_solution_physics_ai( # noqa: F841
25
23
  Returns a compressed archive containing processed solution files including
26
24
  merged surfaces (VTP/STL) and optionally volume data (VTU).
27
25
 
26
+ .. warning:: This feature is experimental and may change or be removed without notice.
27
+
28
28
  Args:
29
29
  solution_id: ID of the solution to download
30
30
  exclude_surfaces: List of surface names to exclude from processing
@@ -1,6 +1,7 @@
1
1
  # Copyright 2025 Luminary Cloud, Inc. All Rights Reserved.
2
2
  from .core import (
3
3
  Pipeline as Pipeline,
4
+ PipelineParameter as PipelineParameter,
4
5
  )
5
6
 
6
7
  from .parameters import (
@@ -27,3 +28,8 @@ from .operators import (
27
28
  Simulate as Simulate,
28
29
  SimulateOutputs as SimulateOutputs,
29
30
  )
31
+
32
+ from .arguments import (
33
+ PipelineArgs as PipelineArgs,
34
+ ArgNamedVariableSet as ArgNamedVariableSet,
35
+ )
@@ -0,0 +1,105 @@
1
+ # Copyright 2025 Luminary Cloud, Inc. All Rights Reserved.
2
+ from typing import Any, Type
3
+
4
+ from .core import PipelineParameter
5
+
6
+
7
+ class _NVS(PipelineParameter):
8
+ @classmethod
9
+ def _represented_type(cls) -> Type:
10
+ return str
11
+
12
+ @classmethod
13
+ def _type_name(cls) -> str:
14
+ return "Named Variable Set"
15
+
16
+ def _validate(self) -> None:
17
+ if self.name != "$named-variable-set":
18
+ raise ValueError(
19
+ "The Named Variable Set PipelineParameter must be named '$named-variable-set'"
20
+ )
21
+
22
+ def _add_to_params(self, params: dict) -> None:
23
+ raise ValueError(
24
+ "The NamedVariableSet parameter cannot be used explicitly in a Pipeline. It can only be used in PipelineArgs."
25
+ )
26
+
27
+ def _is_valid_value(self, value: Any) -> bool:
28
+ return isinstance(value, str) and value.startswith("namedvarset-")
29
+
30
+
31
+ ArgNamedVariableSet = _NVS("$named-variable-set")
32
+ """
33
+ This can be used in a PipelineArgs params list to add a Named Variable Set column to the args table.
34
+ There must be zero or one of these in a PipelineArgs params list.
35
+ """
36
+
37
+ # The types that are allowed as PipelineArgs values. This is a union of all concrete
38
+ # PipelineParameters' "represented types".
39
+ PipelineArgValueType = str | int | float | bool
40
+
41
+
42
+ class PipelineArgsRow:
43
+ def __init__(self, args: "PipelineArgs", row_values: list[PipelineArgValueType]):
44
+ self.args = args
45
+ self.row_values = row_values
46
+ self._validate()
47
+
48
+ def _validate(self) -> None:
49
+ if len(self.row_values) != len(self.args.params):
50
+ raise ValueError(
51
+ f"PipelineArgs row wrong size. Expected {len(self.args.params)}, got {len(self.row_values)}"
52
+ )
53
+ for i, v in enumerate(self.row_values):
54
+ param = self.args.params[i]
55
+ if not param._is_valid_value(v):
56
+ raise ValueError(f"PipelineArgs value {v} is invalid for parameter {param}")
57
+
58
+ def value_for(self, param_name: str) -> PipelineArgValueType:
59
+ return self.row_values[self.args.column_for(param_name)]
60
+
61
+ def has_column_for(self, param_name: str) -> bool:
62
+ return self.args.has_column_for(param_name)
63
+
64
+ def __str__(self) -> str:
65
+ s = "PipelineArgsRow("
66
+ for i, v in enumerate(self.row_values):
67
+ s += f"{self.args.params[i].name}={repr(v)}, "
68
+ s += ")"
69
+ return s
70
+
71
+
72
+ class PipelineArgs:
73
+ def __init__(self, params: list[PipelineParameter], args: list[list[PipelineArgValueType]]):
74
+ self.params = params
75
+ self._param_index_by_name = {p.name: i for i, p in enumerate(params)}
76
+ self._validate_params()
77
+ self.rows = [PipelineArgsRow(self, arg) for arg in args]
78
+
79
+ def has_column_for(self, param_name: str) -> bool:
80
+ return param_name in self._param_index_by_name
81
+
82
+ def column_for(self, param_name: str) -> int:
83
+ if not self.has_column_for(param_name):
84
+ raise ValueError(f'Parameter "{param_name}" not found')
85
+ return self._param_index_by_name[param_name]
86
+
87
+ def _validate_params(self) -> None:
88
+ has_nvs = False
89
+ seen_param_names = set()
90
+ for p in self.params:
91
+ if isinstance(p, _NVS):
92
+ if has_nvs:
93
+ raise ValueError(
94
+ "There can be at most one Named Variable Set column in a PipelineArgs"
95
+ )
96
+ has_nvs = True
97
+ else:
98
+ if p.name in seen_param_names:
99
+ raise ValueError(f'There is more than one parameter named "{p.name}"')
100
+ seen_param_names.add(p.name)
101
+
102
+ def __str__(self) -> str:
103
+ return (
104
+ f"PipelineArgs(param_names={[p.name for p in self.params]}, row_count={len(self.rows)})"
105
+ )