diff --git a/nominal/__init__.py b/nominal/__init__.py index 6bd50f3b..a2f7c808 100644 --- a/nominal/__init__.py +++ b/nominal/__init__.py @@ -5,9 +5,7 @@ Asset, Attachment, Channel, - Check, Checklist, - ChecklistBuilder, CheckViolation, Connection, DataReview, @@ -23,7 +21,6 @@ WriteStream, ) from nominal.nominal import ( - checklist_builder, create_asset, create_log_set, create_run, @@ -61,7 +58,6 @@ "create_asset", "create_run", "create_run_csv", - "checklist_builder", "download_attachment", "get_attachment", "create_streaming_connection", @@ -93,9 +89,7 @@ "Asset", "Attachment", "Channel", - "Check", "Checklist", - "ChecklistBuilder", "Connection", "Dataset", "NominalClient", diff --git a/nominal/core/__init__.py b/nominal/core/__init__.py index fdf5190f..bae9c905 100644 --- a/nominal/core/__init__.py +++ b/nominal/core/__init__.py @@ -1,7 +1,7 @@ from nominal.core.asset import Asset from nominal.core.attachment import Attachment from nominal.core.channel import Channel -from nominal.core.checklist import Check, Checklist, ChecklistBuilder +from nominal.core.checklist import Checklist from nominal.core.client import NominalClient from nominal.core.connection import Connection from nominal.core.data_review import CheckViolation, DataReview, DataReviewBuilder @@ -18,9 +18,7 @@ "Asset", "Attachment", "Channel", - "Check", "Checklist", - "ChecklistBuilder", "Connection", "Dataset", "FileType", diff --git a/nominal/core/_clientsbunch.py b/nominal/core/_clientsbunch.py index c5019320..d43c4f21 100644 --- a/nominal/core/_clientsbunch.py +++ b/nominal/core/_clientsbunch.py @@ -17,7 +17,6 @@ scout_checklistexecution_api, scout_checks_api, scout_compute_api, - scout_compute_representation_api, scout_dataexport_api, scout_datareview_api, scout_datasource, @@ -114,7 +113,6 @@ class ClientsBunch: authentication: authentication_api.AuthenticationServiceV2 catalog: scout_catalog.CatalogService checklist: scout_checks_api.ChecklistService - compute_representation: scout_compute_representation_api.ComputeRepresentationService connection: scout_datasource_connection.ConnectionService dataexport: scout_dataexport_api.DataExportService datasource: scout_datasource.DataSourceService @@ -145,7 +143,6 @@ def from_config(cls, cfg: ServiceConfiguration, agent: str, token: str) -> Self: authentication=client_factory(authentication_api.AuthenticationServiceV2), catalog=client_factory(scout_catalog.CatalogService), checklist=client_factory(scout_checks_api.ChecklistService), - compute_representation=client_factory(scout_compute_representation_api.ComputeRepresentationService), connection=client_factory(scout_datasource_connection.ConnectionService), dataexport=client_factory(scout_dataexport_api.DataExportService), datasource=client_factory(scout_datasource.DataSourceService), diff --git a/nominal/core/checklist.py b/nominal/core/checklist.py index eea33a1b..012b65d5 100644 --- a/nominal/core/checklist.py +++ b/nominal/core/checklist.py @@ -5,12 +5,8 @@ from typing import Literal, Mapping, Protocol, Sequence from nominal_api import ( - api, - scout_api, scout_checklistexecution_api, scout_checks_api, - scout_compute_api, - scout_compute_representation_api, scout_integrations_api, scout_run_api, ) @@ -21,85 +17,6 @@ from nominal.core.asset import Asset -# TODO(ritwikdixit): add support for more fields i.e. lineage -@dataclass(frozen=True) -class Check(HasRid): - rid: str - name: str - expression: str - priority: Priority - description: str - - -@dataclass(frozen=True) -class ChecklistVariable: - name: str - expression: str - - -@dataclass(frozen=True) -class ChecklistBuilder: - name: str - assignee_rid: str - description: str - _default_ref_name: str | None - # note that the ChecklistBuilder is immutable, but the lists/dicts it contains are mutable - _variables: list[_CreateChecklistVariable] - _checks: list[_CreateCheck] - _properties: dict[str, str] - _labels: list[str] - _clients: Checklist._Clients = field(repr=False) - - def add_properties(self, properties: Mapping[str, str]) -> Self: - self._properties.update(properties) - return self - - def add_labels(self, labels: Sequence[str]) -> Self: - self._labels.extend(labels) - return self - - def add_check(self, name: str, expression: str, priority: Priority = 2, description: str = "") -> Self: - self._checks.append(_CreateCheck(name=name, expression=expression, priority=priority, description=description)) - return self - - def add_variable(self, name: str, expression: str) -> Self: - self._variables.append(_CreateChecklistVariable(name=name, expression=expression)) - return self - - def publish(self, commit_message: str | None = None) -> Checklist: - conjure_variables = _batch_create_variable_to_conjure( - self._variables, - self._clients.auth_header, - self._clients.compute_representation, - self._default_ref_name, - ) - - conjure_checks = _batch_create_check_to_conjure( - self._checks, - self._clients.auth_header, - self._clients.compute_representation, - self._default_ref_name, - ) - - request = scout_checks_api.CreateChecklistRequest( - commit_message=commit_message if commit_message is not None else "", - assignee_rid=self.assignee_rid, - title=self.name, - description=self.description, - # TODO(ritwikdixit): support functions - functions={}, - properties=self._properties, - labels=self._labels, - checks=conjure_checks, - checklist_variables=conjure_variables, - # TODO(ritwikdixit): support checklist VCS - is_published=True, - ) - - response = self._clients.checklist.create(self._clients.auth_header, request) - return Checklist._from_conjure(self._clients, response) - - @dataclass(frozen=True) class Checklist(HasRid): rid: str @@ -107,16 +24,12 @@ class Checklist(HasRid): description: str properties: Mapping[str, str] labels: Sequence[str] - checklist_variables: Sequence[ChecklistVariable] - checks: Sequence[Check] _clients: _Clients = field(repr=False) class _Clients(HasAuthHeader, Protocol): @property def checklist(self) -> scout_checks_api.ChecklistService: ... @property - def compute_representation(self) -> scout_compute_representation_api.ComputeRepresentationService: ... - @property def checklist_execution(self) -> scout_checklistexecution_api.ChecklistExecutionService: ... @classmethod @@ -125,53 +38,12 @@ def _from_conjure(cls, clients: _Clients, checklist: scout_checks_api.VersionedC if not checklist.metadata.is_published: raise ValueError("cannot get a checklist that has not been published") - variable_name_to_graph_map = { - variable_name: compute_graph - for variable_name, compute_graph in ( - _conjure_checklist_variable_to_name_graph_pair(checklistVariable) - for checklistVariable in checklist.checklist_variables - ) - } - check_rid_to_graph_and_def_map = { - check_definition.rid: (check_definition, compute_graph) - for check_definition, compute_graph in ( - _conjure_check_to_check_definition_graph_pair(check) for check in checklist.checks - ) - } - - variable_names_to_expressions = clients.compute_representation.batch_compute_to_expression( - clients.auth_header, variable_name_to_graph_map - ) - check_rids_to_expressions = clients.compute_representation.batch_compute_to_expression( - clients.auth_header, {check_rid: graph for check_rid, (_, graph) in check_rid_to_graph_and_def_map.items()} - ) - check_rids_to_definitions = { - check_rid: check_def for check_rid, (check_def, _) in check_rid_to_graph_and_def_map.items() - } - return cls( rid=checklist.rid, name=checklist.metadata.title, description=checklist.metadata.description, properties=checklist.metadata.properties, labels=checklist.metadata.labels, - checklist_variables=[ - ChecklistVariable( - name=checklist_variable_name, - expression=expression, - ) - for checklist_variable_name, expression in variable_names_to_expressions.items() - ], - checks=[ - Check( - rid=check_rid, - name=check_definition.title, - description=check_definition.description, - expression=check_rids_to_expressions[check_rid], - priority=_conjure_priority_to_priority(check_definition.priority), - ) - for check_rid, check_definition in check_rids_to_definitions.items() - ], _clients=clients, ) @@ -240,20 +112,6 @@ def unarchive(self) -> None: Priority = Literal[0, 1, 2, 3, 4] -@dataclass(frozen=True) -class _CreateChecklistVariable: - name: str - expression: str - - -@dataclass(frozen=True) -class _CreateCheck: - name: str - expression: str - priority: Priority - description: str - - _priority_to_conjure_map: dict[Priority, scout_checks_api.Priority] = { 0: scout_checks_api.Priority.P0, 1: scout_checks_api.Priority.P1, @@ -263,12 +121,6 @@ class _CreateCheck: } -def _priority_to_conjure_priority(priority: Priority) -> scout_checks_api.Priority: - if priority in _priority_to_conjure_map: - return _priority_to_conjure_map[priority] - raise ValueError(f"unknown priority {priority}, expected one of {_priority_to_conjure_map.keys()}") - - def _conjure_priority_to_priority(priority: scout_checks_api.Priority) -> Priority: inverted_map = {v: k for k, v in _priority_to_conjure_map.items()} if priority in inverted_map: @@ -276,267 +128,5 @@ def _conjure_priority_to_priority(priority: scout_checks_api.Priority) -> Priori raise ValueError(f"unknown priority '{priority}', expected one of {_priority_to_conjure_map.values()}") -def _conjure_checklist_variable_to_name_graph_pair( - checklist_variable: scout_checks_api.ChecklistVariable, -) -> tuple[str, scout_compute_representation_api.CompiledNode]: - if checklist_variable.value.compute_node is None: - raise ValueError("checklist variable is not a compute node") - preprocessed = { - key: value.accept(visitor=_VariableLocatorVisitor()) - for key, value in checklist_variable.value.compute_node.context.variables.items() - } - - compute_graph = scout_compute_representation_api.CompiledNode( - node=checklist_variable.value.compute_node.series_node.accept(visitor=_ComputeNodeVisitor()), - context=scout_compute_representation_api.ComputeRepresentationContext( - variables={key: value for key, value in preprocessed.items() if value is not None}, - function_variables={}, - ), - ) - - return checklist_variable.name, compute_graph - - -def _conjure_check_to_check_definition_graph_pair( - conjure_check: scout_checks_api.ChecklistEntry, -) -> tuple[scout_checks_api.Check, scout_compute_representation_api.CompiledNode]: - if conjure_check.type != "check" or conjure_check.check is None: - raise ValueError("checklist entry is not a check") - - check_definition: scout_checks_api.Check = conjure_check.check - if check_definition.condition is None: - raise ValueError("check does not have a condition") - - check_condition: scout_checks_api.CheckCondition = check_definition.condition - if check_condition.num_ranges_v3 is None: - raise ValueError("check condition does not evaluate to a valid set of ranges") - - preprocessed = { - key: value.accept(visitor=_VariableLocatorVisitor()) - for key, value in check_condition.num_ranges_v3.variables.items() - } - - compute_graph = scout_compute_representation_api.CompiledNode( - node=scout_compute_representation_api.Node(range_series=check_condition.num_ranges_v3.ranges), - context=scout_compute_representation_api.ComputeRepresentationContext( - variables={key: value for key, value in preprocessed.items() if value is not None}, - function_variables={}, - ), - ) - - return check_definition, compute_graph - - -def _remove_newlines(s: str) -> str: - return s.replace("\n", "") - - -def _get_compute_condition_for_compiled_node( - node: scout_compute_representation_api.CompiledNode, -) -> scout_checks_api.UnresolvedCheckCondition: - if node.node.type == "rangeSeries" and node.node.range_series is not None: - return scout_checks_api.UnresolvedCheckCondition( - num_ranges_v3=scout_checks_api.UnresolvedNumRangesConditionV3( - function_spec={}, - operator=scout_compute_api.ThresholdOperator.GREATER_THAN, - threshold=0, - ranges=node.node.range_series, - variables={ - key: value.accept(visitor=_VariableValueVisitor()) for key, value in node.context.variables.items() - }, - function_variables={}, - ) - ) - raise ValueError(f"only range_series nodes are currently supported, got {node.node!r}") - - -def _batch_get_compute_condition( - expressions: list[str], - auth_header: str, - client: scout_compute_representation_api.ComputeRepresentationService, - default_ref_name: str | None = None, -) -> dict[str, scout_checks_api.UnresolvedCheckCondition]: - responses = client.batch_expression_to_compute( - auth_header, - scout_compute_representation_api.BatchExpressionToComputeRequest( - expressions=expressions, default_ref_name=default_ref_name - ), - ) - - condition_dict = {} - for expression, response in responses.items(): - if response.error is not None: - raise ValueError(f"error translating expression to compute: {response.error}") - elif response.success is not None: - condition_dict[expression] = _get_compute_condition_for_compiled_node(response.success.node) - else: - raise ValueError("expression_to_compute response is not a success or error") - - return condition_dict - - -def _batch_create_check_to_conjure( - create_checks: Sequence[_CreateCheck], - auth_header: str, - client: scout_compute_representation_api.ComputeRepresentationService, - default_ref_name: str | None = None, -) -> list[scout_checks_api.CreateChecklistEntryRequest]: - conditions = _batch_get_compute_condition( - [create_check.expression for create_check in create_checks], auth_header, client, default_ref_name - ) - return [ - scout_checks_api.CreateChecklistEntryRequest( - scout_checks_api.CreateCheckRequest( - title=check.name, - description=check.description, - priority=_priority_to_conjure_priority(check.priority), - condition=conditions[check.expression], - ) - ) - for check in create_checks - ] - - -def _create_unresolved_checklist_variable( - variable: _CreateChecklistVariable, - node: scout_compute_representation_api.CompiledNode, -) -> scout_checks_api.UnresolvedChecklistVariable: - return scout_checks_api.UnresolvedChecklistVariable( - name=variable.name, - value=scout_checks_api.UnresolvedVariableLocator( - compute_node=scout_checks_api.UnresolvedComputeNodeWithContext( - series_node=node.node.accept(visitor=_NodeVisitor()), - context=scout_checks_api.UnresolvedVariables( - sub_function_variables={}, - variables={ - key: value.accept(visitor=_VariableValueVisitor()) - for key, value in node.context.variables.items() - }, - ), - ) - ), - ) - - -def _batch_create_variable_to_conjure( - variables: Sequence[_CreateChecklistVariable], - auth_header: str, - client: scout_compute_representation_api.ComputeRepresentationService, - default_ref_name: str | None, -) -> list[scout_checks_api.UnresolvedChecklistVariable]: - responses = client.batch_expression_to_compute( - auth_header, - scout_compute_representation_api.BatchExpressionToComputeRequest( - expressions=[variable.expression for variable in variables], - default_ref_name=default_ref_name, - ), - ) - - unresolved_variables = [] - for variable in variables: - response = responses[variable.expression] - if response.error is not None: - raise ValueError(f"error translating expression to compute: {response.error}") - elif response.success is not None: - unresolved_variables.append(_create_unresolved_checklist_variable(variable, response.success.node)) - else: - raise ValueError("expression_to_compute response is not a success or error") - - return unresolved_variables - - -class _ComputeNodeVisitor(scout_compute_api.ComputeNodeVisitor): - def _enum(self, enum: scout_compute_api.EnumSeries) -> scout_compute_representation_api.Node: - return scout_compute_representation_api.Node(enumerated_series=enum) - - def _log(self, raw: scout_compute_api.LogSeries) -> scout_compute_representation_api.Node: - raise ValueError("Log nodes are not yet supported by the client library") - - def _numeric(self, numeric: scout_compute_api.NumericSeries) -> scout_compute_representation_api.Node: - return scout_compute_representation_api.Node(numeric_series=numeric) - - def _ranges(self, ranges: scout_compute_api.RangeSeries) -> scout_compute_representation_api.Node: - return scout_compute_representation_api.Node(range_series=ranges) - - def _raw(self, raw: scout_compute_api.Reference) -> scout_compute_representation_api.Node: - raise ValueError("Raw nodes are not yet supported by the client library") - - -class _NodeVisitor(scout_compute_representation_api.NodeVisitor): - def _enumerated_series(self, enumerated_series: scout_compute_api.EnumSeries) -> scout_compute_api.ComputeNode: - return scout_compute_api.ComputeNode(enum=enumerated_series) - - def _numeric_series(self, numeric_series: scout_compute_api.NumericSeries) -> scout_compute_api.ComputeNode: - return scout_compute_api.ComputeNode(numeric=numeric_series) - - def _range_series(self, range_series: scout_compute_api.RangeSeries) -> scout_compute_api.ComputeNode: - return scout_compute_api.ComputeNode(ranges=range_series) - - -class _VariableValueVisitor(scout_compute_representation_api.ComputeRepresentationVariableValueVisitor): - def _double(self, _double: float) -> scout_checks_api.UnresolvedVariableLocator: - raise ValueError("double variables are not yet supported by the client library") - - def _duration(self, _duration: scout_run_api.Duration) -> scout_checks_api.UnresolvedVariableLocator: - raise ValueError("Duration variables are not yet supported by the client library") - - def _integer(self, _integer: int) -> scout_checks_api.UnresolvedVariableLocator: - raise ValueError("integer variables are not yet supported by the client library") - - def _string_set(self, _string_set: list[str]) -> scout_checks_api.UnresolvedVariableLocator: - raise ValueError("string set variables are not yet supported by the client library") - - def _timestamp(self, _timestamp: api.Timestamp) -> scout_checks_api.UnresolvedVariableLocator: - raise ValueError("timestamp variables are not yet supported by the client library") - - def _function_rid(self, function_rid: str) -> scout_checks_api.UnresolvedVariableLocator: - raise ValueError("functions are not yet supported by the client library") - - def _series( - self, series: scout_compute_representation_api.ChannelLocator - ) -> scout_checks_api.UnresolvedVariableLocator: - return scout_checks_api.UnresolvedVariableLocator( - series=scout_api.ChannelLocator(channel=series.channel, data_source_ref=series.data_source_ref, tags={}) - ) - - def _external_variable_reference( - self, external_variable_reference: str - ) -> scout_checks_api.UnresolvedVariableLocator: - return scout_checks_api.UnresolvedVariableLocator(checklist_variable=external_variable_reference) - - -class _VariableLocatorVisitor(scout_checks_api.VariableLocatorVisitor): - def _series( - self, series: scout_api.ChannelLocator - ) -> scout_compute_representation_api.ComputeRepresentationVariableValue | None: - return scout_compute_representation_api.ComputeRepresentationVariableValue( - series=scout_compute_representation_api.ChannelLocator( - channel=series.channel, data_source_ref=series.data_source_ref - ) - ) - - def _checklist_variable( - self, checklist_variable: str - ) -> scout_compute_representation_api.ComputeRepresentationVariableValue | None: - return scout_compute_representation_api.ComputeRepresentationVariableValue( - external_variable_reference=checklist_variable - ) - - def _compute_node( - self, compute_node: scout_checks_api.ComputeNodeWithContext - ) -> scout_compute_representation_api.ComputeRepresentationVariableValue | None: - return None - - def _function_rid( - self, function_rid: str - ) -> scout_compute_representation_api.ComputeRepresentationVariableValue | None: - return None - - def _timestamp( - self, timestamp: scout_checks_api.TimestampLocator - ) -> scout_compute_representation_api.ComputeRepresentationVariableValue | None: - return None - - def _to_api_duration(duration: timedelta) -> scout_run_api.Duration: return scout_run_api.Duration(seconds=int(duration.total_seconds()), nanos=duration.microseconds * 1000) diff --git a/nominal/core/client.py b/nominal/core/client.py index 499c3f01..5b0e74f1 100644 --- a/nominal/core/client.py +++ b/nominal/core/client.py @@ -38,7 +38,7 @@ from nominal.core.asset import Asset from nominal.core.attachment import Attachment, _iter_get_attachments from nominal.core.channel import Channel -from nominal.core.checklist import Checklist, ChecklistBuilder +from nominal.core.checklist import Checklist from nominal.core.connection import Connection from nominal.core.data_review import DataReview, DataReviewBuilder from nominal.core.dataset import Dataset, _create_ingest_request, _create_mcap_channels, _get_dataset, _get_datasets @@ -46,7 +46,7 @@ from nominal.core.log import Log, LogSet, _get_log_set from nominal.core.run import Run from nominal.core.unit import Unit -from nominal.core.user import User, _get_user, _get_user_with_fallback +from nominal.core.user import User, _get_user from nominal.core.video import Video from nominal.core.workbook import Workbook from nominal.exceptions import NominalIngestError @@ -602,33 +602,6 @@ def get_checklist(self, rid: str) -> Checklist: response = self._clients.checklist.get(self._clients.auth_header, rid) return Checklist._from_conjure(self._clients, response) - def checklist_builder( - self, - name: str, - description: str = "", - assignee_email: str | None = None, - assignee_rid: str | None = None, - default_ref_name: str | None = None, - ) -> ChecklistBuilder: - """Creates a checklist builder. - - You can provide one of `assignee_email` or `assignee_rid`. If neither are provided, the rid for the user - executing the script will be used as the assignee. If both are provided, a ValueError is raised. - """ - return ChecklistBuilder( - name=name, - description=description, - assignee_rid=_get_user_with_fallback( - self._clients.auth_header, self._clients.authentication, assignee_email, assignee_rid - ), - _default_ref_name=default_ref_name, - _variables=[], - _checks=[], - _properties={}, - _labels=[], - _clients=self._clients, - ) - def create_attachment_from_io( self, attachment: BinaryIO, diff --git a/nominal/nominal.py b/nominal/nominal.py index 082a8e4e..dc7c6f33 100644 --- a/nominal/nominal.py +++ b/nominal/nominal.py @@ -12,7 +12,6 @@ Asset, Attachment, Checklist, - ChecklistBuilder, Dataset, FileType, FileTypes, @@ -522,38 +521,6 @@ def _get_start_end_timestamp_csv_file( ) -def checklist_builder( - name: str, - description: str = "", - assignee_email: str | None = None, - default_ref_name: str | None = None, -) -> ChecklistBuilder: - """Create a checklist builder to add checks and variables, and publish the checklist to Nominal. - - If assignee_email is None, the checklist is assigned to the user executing the code. - - Example: - ------- - ```python - builder = nm.checklist_builder("Programmatically created checklist") - builder.add_check( - name="derivative of cycle time is too high", - priority=2, - expression="derivative(numericChannel(channelName = 'Cycle_Time', refName = 'manufacturing')) > 0.05", - ) - checklist = builder.publish() - ``` - - """ - conn = get_default_client() - return conn.checklist_builder( - name=name, - description=description, - assignee_email=assignee_email, - default_ref_name=default_ref_name, - ) - - def get_checklist(checklist_rid: str) -> Checklist: conn = get_default_client() return conn.get_checklist(checklist_rid) diff --git a/tests/e2e/test_toplevel.py b/tests/e2e/test_toplevel.py index f3a862f7..c6fcb495 100644 --- a/tests/e2e/test_toplevel.py +++ b/tests/e2e/test_toplevel.py @@ -282,60 +282,3 @@ def test_get_video(mp4_data): assert v2.description == v.description == desc assert v2.properties == v.properties == {} assert v2.labels == v.labels == () - - -def test_create_checklist(): - name = f"checklist-{uuid4()}" - desc = f"top-level test to create a checklist {uuid4()}" - assignee_email = "demo@nominal.io" - builder = nm.checklist_builder(name, desc, assignee_email) - builder.add_check(name="Check 1", priority=1, description="Description of check 1", expression="10 > 5") - builder.add_variable(name="Variable 1", expression="10") - checklist = builder.publish() - - assert checklist.rid != "" - assert checklist.name == name - assert checklist.description == desc - - # Assert checklist variable details - assert len(checklist.checklist_variables) == 1 - variable = checklist.checklist_variables[0] - assert variable.name == "Variable 1" - assert variable.expression == "(10)" - - # Assert check details - assert len(checklist.checks) == 1 - check = checklist.checks[0] - assert check.name == "Check 1" - assert check.priority == 1 - assert check.description == "Description of check 1" - assert check.expression == "(10) > 5.0" - - -def test_get_checklist(): - # Create a checklist - name = f"checklist-{uuid4()}" - desc = f"top-level test to create & get a checklist {uuid4()}" - assignee_email = "demo@nominal.io" - - # Draft and create the checklist - builder = nm.checklist_builder(name, desc, assignee_email) - builder.add_variable(name="Variable 1", expression="10") - builder.add_check(name="Check 1", priority=1, description="Description of check 1", expression="10 > 5") - checklist = builder.publish() - - # Get the checklist using get_checklist - retrieved_checklist = nm.get_checklist(checklist.rid) - - # Assert checklist variable details - assert len(retrieved_checklist.checklist_variables) == len(checklist.checklist_variables) == 1 - variable, retrieved_variable = tuple(*zip(checklist.checklist_variables, retrieved_checklist.checklist_variables)) - assert retrieved_variable.name == variable.name == "Variable 1" - assert retrieved_variable.expression == variable.expression == "(10)" - - assert len(retrieved_checklist.checks) == len(checklist.checks) == 1 - check, retrieved_check = tuple(*zip(checklist.checks, retrieved_checklist.checks)) - assert retrieved_check.name == check.name == "Check 1" - assert retrieved_check.priority == check.priority == 1 - assert retrieved_check.description == check.description == "Description of check 1" - assert retrieved_check.expression == check.expression == "(10) > 5.0" diff --git a/uv.lock b/uv.lock index f204464b..2442d727 100644 --- a/uv.lock +++ b/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 1 requires-python = ">=3.9, <4" resolution-markers = [ "python_full_version < '3.11'", @@ -1611,6 +1612,7 @@ requires-dist = [ { name = "tabulate", specifier = ">=0.9.0,<0.10" }, { name = "typing-extensions", specifier = ">=4,<5" }, ] +provides-extras = ["hdf5", "protos"] [package.metadata.requires-dev] dev = [