pinexq-client 1.1.0__py3-none-any.whl → 1.2.0__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.
@@ -19,7 +19,7 @@ from .hcos import (
19
19
  )
20
20
  from .known_relations import Relations
21
21
  from .model import JobSortPropertiesSortParameter, ProcessingView
22
- from .tool import Job, JobGroup, ProcessingStep, WorkData
22
+ from .tool import Job, JobGroup, JobQuery, ProcessingStep, ProcessingStepQuery, WorkData, WorkDataQuery
23
23
 
24
24
  # Protocol version the JMA is using
25
- __jma_version__ = [9, 2, 0]
25
+ __jma_version__ = [9, 3, 0]
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: openapi.json
3
- # timestamp: 2026-01-28T11:09:12+00:00
3
+ # timestamp: 2026-02-03T21:15:10+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -119,6 +119,8 @@ class DeploymentResourcePresets(StrEnum):
119
119
  medium = 'Medium'
120
120
  large = 'Large'
121
121
  x_large = 'XLarge'
122
+ xx_large = 'XXLarge'
123
+ x_small = 'XSmall'
122
124
 
123
125
 
124
126
  class DeploymentStates(StrEnum):
@@ -1184,7 +1186,7 @@ class ProcessingStepHtoOpenApiProperties(BaseModel):
1184
1186
  code_hash: str | None = Field(
1185
1187
  None,
1186
1188
  alias='CodeHash',
1187
- description='The hash of the code executing this function. This is intended to inhibit\r\nredeployment of different code for the same function version.',
1189
+ description='The hash of the code executing this function. This is intended to inhibit\nredeployment of different code for the same function version.',
1188
1190
  )
1189
1191
  has_parameters: bool | None = Field(None, alias='HasParameters')
1190
1192
  is_public: bool | None = Field(None, alias='IsPublic')
@@ -1,4 +1,4 @@
1
- from .job import Job
1
+ from .job import Job, JobQuery
2
2
  from .job_group import JobGroup
3
- from .processing_step import ProcessingStep
4
- from .workdata import WorkData
3
+ from .processing_step import ProcessingStep, ProcessingStepQuery
4
+ from .workdata import WorkData, WorkDataQuery
@@ -3,14 +3,15 @@ import json as json_
3
3
  import queue
4
4
  import warnings
5
5
  from datetime import datetime, timedelta
6
- from typing import Any, List, Self
6
+ from typing import Any, Iterator, List, Self
7
7
 
8
8
  import httpx
9
9
  from httpx import URL
10
- from pydantic import BaseModel, ConfigDict
10
+ from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict
11
11
 
12
12
  from ...core import ApiException, ClientException, Link, MediaTypes
13
13
  from ...core.api_event_manager import ApiEventManagerSingleton
14
+ from ...core.hco.unavailable import UnavailableLink
14
15
  from ...core.polling import PollingException, wait_until
15
16
  from ..enterjma import enter_jma
16
17
  from ..hcos import InputDataSlotHco, OutputDataSlotHco, ProcessingStepLink, WorkDataLink
@@ -27,8 +28,10 @@ from ..model import (
27
28
  InputDataSlotParameter,
28
29
  JobFilterParameter,
29
30
  JobQueryParameters,
31
+ JobSortProperties,
30
32
  JobSortPropertiesSortParameter,
31
33
  JobStates,
34
+ Pagination,
32
35
  ProcessingStepFilterParameter,
33
36
  ProcessingStepQueryParameters,
34
37
  ProcessingView,
@@ -37,6 +40,7 @@ from ..model import (
37
40
  SelectWorkDataCollectionForDataSlotParameters,
38
41
  SelectWorkDataForDataSlotParameters,
39
42
  SetJobTagsParameters,
43
+ SortTypes,
40
44
  )
41
45
  from ..tool.processing_step import ProcessingStep
42
46
  from ..tool.workdata import WorkData
@@ -53,10 +57,10 @@ class InputDataSlotParameterFlexible(BaseModel):
53
57
 
54
58
  @classmethod
55
59
  def create(cls, *,
56
- index: int,
57
- work_data_urls: List[WorkDataLink] | None = None,
58
- work_data_instances: List[WorkData] | None = None
59
- ) -> "InputDataSlotParameterFlexible":
60
+ index: int,
61
+ work_data_urls: List[WorkDataLink] | None = None,
62
+ work_data_instances: List[WorkData] | None = None
63
+ ) -> "InputDataSlotParameterFlexible":
60
64
  """Creates an instance of InputDataSlotParameterFlexible that can be used to assign work data to a job.
61
65
 
62
66
  Args:
@@ -81,6 +85,7 @@ class InputDataSlotParameterFlexible(BaseModel):
81
85
  work_data_instances=None
82
86
  )
83
87
 
88
+
84
89
  class Job:
85
90
  """Convenience wrapper for handling JobHcos in the JobManagement-Api.
86
91
 
@@ -322,7 +327,8 @@ class Job:
322
327
  result = self.job_hco.result
323
328
  return json_.loads(result) if result else None
324
329
 
325
- def wait_for_state_sse(self, state: JobStates, timeout_s: float | None = None, fallback_polling_interval_s: float = 300) -> Self:
330
+ def wait_for_state_sse(self, state: JobStates, timeout_s: float | None = None,
331
+ fallback_polling_interval_s: float = 300) -> Self:
326
332
  self._raise_if_no_hco()
327
333
 
328
334
  # early exit
@@ -391,10 +397,10 @@ class Job:
391
397
  try:
392
398
  wait_until(
393
399
  condition=lambda: self.get_state() == state,
394
- timeout_ms= int(timeout_s * 1000) if timeout_s is not None else None,
400
+ timeout_ms=int(timeout_s * 1000) if timeout_s is not None else None,
395
401
  timeout_message="Waiting for job completion",
396
402
  error_condition=lambda: self.job_hco.state == JobStates.error,
397
- polling_interval_ms= int(polling_interval_s * 1000)
403
+ polling_interval_ms=int(polling_interval_s * 1000)
398
404
  )
399
405
  except TimeoutError as timeout:
400
406
  raise TimeoutError(
@@ -578,15 +584,15 @@ class Job:
578
584
  """
579
585
  wait_until(
580
586
  condition=lambda: self.sub_jobs_in_state(JobStates.pending) == 0,
581
- timeout_ms= int(timeout_s * 1000),
587
+ timeout_ms=int(timeout_s * 1000),
582
588
  timeout_message=f"Timeout while waiting for sub-jobs to complete! [timeout: {timeout_s}s]",
583
- polling_interval_ms= int(polling_interval_s * 1000)
589
+ polling_interval_ms=int(polling_interval_s * 1000)
584
590
  )
585
591
  wait_until(
586
592
  condition=lambda: self.sub_jobs_in_state(JobStates.processing) == 0,
587
- timeout_ms= int(timeout_s * 1000),
593
+ timeout_ms=int(timeout_s * 1000),
588
594
  timeout_message=f"Timeout while waiting for sub-jobs to complete! [timeout: {timeout_s}ms]",
589
- polling_interval_ms= int(polling_interval_s * 1000)
595
+ polling_interval_ms=int(polling_interval_s * 1000)
590
596
  )
591
597
 
592
598
  error_count = self.sub_jobs_in_state(JobStates.error)
@@ -639,7 +645,7 @@ class Job:
639
645
  delete_output_workdata=delete_output_workdata,
640
646
  delete_input_workdata=delete_input_workdata,
641
647
  delete_subjobs_with_data=delete_subjobs_with_data,
642
- recursion_depth = 0)
648
+ recursion_depth=0)
643
649
 
644
650
  def _delete_with_associated_internal(
645
651
  self,
@@ -664,7 +670,7 @@ class Job:
664
670
  delete_output_workdata=delete_output_workdata,
665
671
  delete_input_workdata=delete_input_workdata,
666
672
  delete_subjobs_with_data=delete_subjobs_with_data,
667
- recursion_depth = recursion_depth + 1)
673
+ recursion_depth=recursion_depth + 1)
668
674
  if subjob.self_link.exists():
669
675
  warnings.warn(f"Could not delete subjob: {subjob.self_link.get_url()}")
670
676
  except (ClientException, ApiException) as e:
@@ -887,3 +893,138 @@ class Job:
887
893
  def _raise_if_no_hco(self):
888
894
  if self.job_hco is None:
889
895
  raise Exception("No job hco present. Maybe this class is used after resource deletion.")
896
+
897
+
898
+ class JobQuery:
899
+ """Convenience wrapper for querying Jobs.
900
+ """
901
+
902
+ _client: httpx.Client
903
+ _entrypoint: EntryPointHco
904
+ _jobs_root: JobsRootHco
905
+ parameters: JobQueryParameters
906
+
907
+ def __init__(self, client: httpx.Client, parameters: JobQueryParameters):
908
+ self._client = client
909
+ self._entrypoint = enter_jma(client)
910
+ self._jobs_root = self._entrypoint.job_root_link.navigate()
911
+ self.parameters = parameters
912
+
913
+ @classmethod
914
+ def from_parameters(cls, client: httpx.Client, parameters: JobQueryParameters) -> Self:
915
+ """Create a JobQuery from a JobQueryParameters object.
916
+ """
917
+ return cls(client, parameters)
918
+
919
+ @classmethod
920
+ def create(
921
+ cls,
922
+ client: httpx.Client,
923
+ *,
924
+ page_size: int | None = None,
925
+ page_offset: int | None = None,
926
+ sort_by_property_name: JobSortProperties | None = None,
927
+ sort_by_sort_type: SortTypes | None = None,
928
+ include_remaining_tags: bool | None = None,
929
+ state: JobStates | None = None,
930
+ name: str | None = None,
931
+ show_hidden: bool | None = None,
932
+ work_data_url: AnyUrl | None = None,
933
+ created_before: AwareDatetime | None = None,
934
+ created_after: AwareDatetime | None = None,
935
+ tags_by_and: list[str] | None = None,
936
+ tags_by_or: list[str] | None = None,
937
+ processing_step_url: AnyUrl | None = None,
938
+ is_sub_job: bool | None = None,
939
+ parent_job_url: AnyUrl | None = None
940
+ ) -> Self:
941
+ """Create a JobQuery from flat parameters.
942
+ """
943
+ filter_param = JobFilterParameter(
944
+ state=state,
945
+ name=name,
946
+ show_hidden=show_hidden,
947
+ work_data_url=work_data_url,
948
+ created_before=created_before,
949
+ created_after=created_after,
950
+ tags_by_and=tags_by_and,
951
+ tags_by_or=tags_by_or,
952
+ processing_step_url=processing_step_url,
953
+ is_sub_job=is_sub_job,
954
+ parent_job_url=parent_job_url
955
+ )
956
+
957
+ sort_by = None
958
+ if sort_by_property_name is not None or sort_by_sort_type is not None:
959
+ sort_by = JobSortPropertiesSortParameter(
960
+ property_name=sort_by_property_name,
961
+ sort_type=sort_by_sort_type
962
+ )
963
+
964
+ pagination = None
965
+ if page_size is not None or page_offset is not None:
966
+ pagination = Pagination(page_size=page_size, page_offset=page_offset)
967
+
968
+ parameters = JobQueryParameters(
969
+ sort_by=sort_by,
970
+ filter=filter_param,
971
+ pagination=pagination,
972
+ include_remaining_tags=include_remaining_tags
973
+ )
974
+ return cls(client, parameters)
975
+
976
+ def execute(self) -> JobQueryResultHco:
977
+ """Executes the query and returns a JobQueryResultHco.
978
+ """
979
+ return self._jobs_root.job_query_action.execute(self.parameters)
980
+
981
+ def count(self) -> int:
982
+ """Returns the total number of entities matching the query.
983
+ """
984
+ return self.execute().total_entities
985
+
986
+ def exists(self) -> bool:
987
+ """Returns True if there are any entities matching the query.
988
+ """
989
+ return self.count() > 0
990
+
991
+ def first(self) -> Job | None:
992
+ """Returns the first entity matching the query, or None if no entities match.
993
+ """
994
+ result = self.execute()
995
+ if result.jobs:
996
+ return Job.from_hco(result.jobs[0])
997
+ return None
998
+
999
+ def one(self) -> Job:
1000
+ """Returns exactly one entity matching the query.
1001
+ Raises an exception if no entities are found or if multiple entities match.
1002
+ """
1003
+ result = self.execute()
1004
+ if result.total_entities == 0:
1005
+ raise Exception("No entities found matching the query.")
1006
+ if result.total_entities > 1:
1007
+ raise Exception(f"Expected exactly one entity, but found {result.total_entities}.")
1008
+ return Job.from_hco(result.jobs[0])
1009
+
1010
+ def to_list(self) -> list[Job]:
1011
+ """Returns all entities matching the query as a list.
1012
+ """
1013
+ return list(self.iter())
1014
+
1015
+ def to_job_group(self) -> 'JobGroup':
1016
+ """Returns a JobGroup containing all jobs matching the query.
1017
+ """
1018
+ from .job_group import JobGroup
1019
+ return JobGroup.from_query_result(self.execute())
1020
+
1021
+ def iter(self) -> Iterator[Job]:
1022
+ """
1023
+ Returns an Iterator of `Job` so that all jobs can be processed in a loop.
1024
+
1025
+ Returns:
1026
+ An iterator of `Job` objects
1027
+ """
1028
+ for page in self.execute().iter():
1029
+ for job_hco in page.jobs:
1030
+ yield Job.from_hco(job_hco)
@@ -1,8 +1,10 @@
1
- from typing import Any, Optional, Self
1
+ from typing import Any, Iterator, Optional, Self
2
2
 
3
3
  import httpx
4
4
  from httpx import URL
5
5
 
6
+ from pydantic import AnyUrl, AwareDatetime
7
+
6
8
  from ...core import Link, MediaTypes
7
9
  from ...core.hco.upload_action_hco import UploadParameters
8
10
  from ..enterjma import enter_jma
@@ -23,10 +25,15 @@ from ..model import (
23
25
  DeploymentStates,
24
26
  DeprecatePsActionParameters,
25
27
  FunctionNameMatchTypes,
28
+ Pagination,
26
29
  ProcessingStepFilterParameter,
27
30
  ProcessingStepQueryParameters,
31
+ ProcessingStepSortProperties,
32
+ ProcessingStepSortPropertiesSortParameter,
28
33
  ScalingConfiguration,
29
- SetProcessingStepTagsParameters, SetProcessingStepTitleParameters,
34
+ SetProcessingStepTagsParameters,
35
+ SetProcessingStepTitleParameters,
36
+ SortTypes,
30
37
  )
31
38
 
32
39
 
@@ -469,3 +476,137 @@ class ProcessingStep:
469
476
  def _raise_if_no_hco(self):
470
477
  if self.processing_step_hco is None:
471
478
  raise Exception("No processing step hco present. Maybe this class is used after resource deletion.")
479
+
480
+
481
+ class ProcessingStepQuery:
482
+ """Convenience wrapper for querying ProcessingSteps.
483
+ """
484
+
485
+ _client: httpx.Client
486
+ _entrypoint: EntryPointHco
487
+ _processing_steps_root: ProcessingStepsRootHco
488
+ parameters: ProcessingStepQueryParameters
489
+
490
+ def __init__(self, client: httpx.Client, parameters: ProcessingStepQueryParameters):
491
+ self._client = client
492
+ self._entrypoint = enter_jma(client)
493
+ self._processing_steps_root = self._entrypoint.processing_step_root_link.navigate()
494
+ self.parameters = parameters
495
+
496
+ @classmethod
497
+ def from_parameters(cls, client: httpx.Client, parameters: ProcessingStepQueryParameters) -> Self:
498
+ """Create a ProcessingStepQuery from a ProcessingStepQueryParameters object.
499
+ """
500
+ return cls(client, parameters)
501
+
502
+ @classmethod
503
+ def create(
504
+ cls,
505
+ client: httpx.Client,
506
+ *,
507
+ page_size: int | None = None,
508
+ page_offset: int | None = None,
509
+ sort_by_property_name: ProcessingStepSortProperties | None = None,
510
+ sort_by_sort_type: SortTypes | None = None,
511
+ include_remaining_tags: bool | None = None,
512
+ function_name: str | None = None,
513
+ function_name_match_type: FunctionNameMatchTypes | None = None,
514
+ title_contains: str | None = None,
515
+ version: str | None = None,
516
+ description_contains: str | None = None,
517
+ tags_by_and: list[str] | None = None,
518
+ tags_by_or: list[str] | None = None,
519
+ is_public: bool | None = None,
520
+ show_hidden: bool | None = None,
521
+ show_deprecated: bool | None = None,
522
+ deployment_state: DeploymentStates | None = None,
523
+ show_prerelease: bool | None = None,
524
+ pro_con_version: str | None = None
525
+ ) -> Self:
526
+ """Create a ProcessingStepQuery from flat parameters.
527
+ """
528
+ filter_param = ProcessingStepFilterParameter(
529
+ function_name=function_name,
530
+ function_name_match_type=function_name_match_type,
531
+ title_contains=title_contains,
532
+ version=version,
533
+ description_contains=description_contains,
534
+ tags_by_and=tags_by_and,
535
+ tags_by_or=tags_by_or,
536
+ is_public=is_public,
537
+ show_hidden=show_hidden,
538
+ show_deprecated=show_deprecated,
539
+ deployment_state=deployment_state,
540
+ show_prerelease=show_prerelease,
541
+ pro_con_version=pro_con_version
542
+ )
543
+
544
+ sort_by = None
545
+ if sort_by_property_name is not None or sort_by_sort_type is not None:
546
+ sort_by = ProcessingStepSortPropertiesSortParameter(
547
+ property_name=sort_by_property_name,
548
+ sort_type=sort_by_sort_type
549
+ )
550
+
551
+ pagination = None
552
+ if page_size is not None or page_offset is not None:
553
+ pagination = Pagination(page_size=page_size, page_offset=page_offset)
554
+
555
+ parameters = ProcessingStepQueryParameters(
556
+ sort_by=sort_by,
557
+ filter=filter_param,
558
+ pagination=pagination,
559
+ include_remaining_tags=include_remaining_tags
560
+ )
561
+
562
+ return cls(client, parameters)
563
+
564
+ def execute(self) -> ProcessingStepQueryResultHco:
565
+ """Executes the query and returns a ProcessingStepQueryResultHco.
566
+ """
567
+ return self._processing_steps_root.query_action.execute(self.parameters)
568
+
569
+ def count(self) -> int:
570
+ """Returns the total number of entities matching the query.
571
+ """
572
+ return self.execute().total_entities
573
+
574
+ def exists(self) -> bool:
575
+ """Returns True if there are any entities matching the query.
576
+ """
577
+ return self.count() > 0
578
+
579
+ def first(self) -> ProcessingStep | None:
580
+ """Returns the first entity matching the query, or None if no entities match.
581
+ """
582
+ result = self.execute()
583
+ if result.processing_steps:
584
+ return ProcessingStep.from_hco(result.processing_steps[0])
585
+ return None
586
+
587
+ def one(self) -> ProcessingStep:
588
+ """Returns exactly one entity matching the query.
589
+ Raises an exception if no entities are found or if multiple entities match.
590
+ """
591
+ result = self.execute()
592
+ if result.total_entities == 0:
593
+ raise Exception("No entities found matching the query.")
594
+ if result.total_entities > 1:
595
+ raise Exception(f"Expected exactly one entity, but found {result.total_entities}.")
596
+ return ProcessingStep.from_hco(result.processing_steps[0])
597
+
598
+ def to_list(self) -> list[ProcessingStep]:
599
+ """Returns all entities matching the query as a list.
600
+ """
601
+ return list(self.iter())
602
+
603
+ def iter(self) -> Iterator[ProcessingStep]:
604
+ """
605
+ Returns an Iterator of `ProcessingStep` so that all processing steps can be processed in a loop.
606
+
607
+ Returns:
608
+ An iterator of `ProcessingStep` objects
609
+ """
610
+ for page in self.execute().iter():
611
+ for ps_hco in page.processing_steps:
612
+ yield ProcessingStep.from_hco(ps_hco)
@@ -1,15 +1,33 @@
1
1
  from io import IOBase
2
- from typing import Any, AsyncIterable, Iterable, Self
2
+ from typing import Any, AsyncIterable, Iterable, Iterator, Self
3
3
 
4
4
  import httpx
5
5
  from httpx import URL
6
6
 
7
+ from pydantic import AnyUrl, AwareDatetime
8
+
7
9
  from ...core import Link, MediaTypes
8
10
  from ...core.hco.upload_action_hco import UploadParameters
9
11
  from ..enterjma import enter_jma
10
- from ..hcos import EntryPointHco, WorkDataHco, WorkDataLink, WorkDataRootHco
12
+ from ..hcos import (
13
+ EntryPointHco,
14
+ WorkDataHco,
15
+ WorkDataLink,
16
+ WorkDataQueryResultHco,
17
+ WorkDataRootHco,
18
+ )
11
19
  from ..known_relations import Relations
12
- from ..model import CopyWorkDataFromUserToOrgActionParameters, SetTagsWorkDataParameters
20
+ from ..model import (
21
+ CopyWorkDataFromUserToOrgActionParameters,
22
+ Pagination,
23
+ SetTagsWorkDataParameters,
24
+ SortTypes,
25
+ WorkDataFilterParameter,
26
+ WorkDataKind,
27
+ WorkDataQueryParameters,
28
+ WorkDataSortProperties,
29
+ WorkDataSortPropertiesSortParameter,
30
+ )
13
31
 
14
32
 
15
33
  class WorkData:
@@ -188,4 +206,133 @@ class WorkData:
188
206
 
189
207
  def _raise_if_no_hco(self):
190
208
  if self.work_data_hco is None:
191
- raise Exception("No work data hco present. Maybe this class is used after resource deletion.")
209
+ raise Exception("No work data hco present. Maybe this class is used after resource deletion.")
210
+
211
+
212
+ class WorkDataQuery:
213
+ """Convenience wrapper for querying WorkData.
214
+ """
215
+
216
+ _client: httpx.Client
217
+ _entrypoint: EntryPointHco
218
+ _work_data_root: WorkDataRootHco
219
+ parameters: WorkDataQueryParameters
220
+
221
+ def __init__(self, client: httpx.Client, parameters: WorkDataQueryParameters):
222
+ self._client = client
223
+ self._entrypoint = enter_jma(client)
224
+ self._work_data_root = self._entrypoint.work_data_root_link.navigate()
225
+ self.parameters = parameters
226
+
227
+ @classmethod
228
+ def from_parameters(cls, client: httpx.Client, parameters: WorkDataQueryParameters) -> Self:
229
+ """Create a WorkDataQuery from a WorkDataQueryParameters object.
230
+ """
231
+ return cls(client, parameters)
232
+
233
+ @classmethod
234
+ def create(
235
+ cls,
236
+ client: httpx.Client,
237
+ *,
238
+ page_size: int | None = None,
239
+ page_offset: int | None = None,
240
+ sort_by_property_name: WorkDataSortProperties | None = None,
241
+ sort_by_sort_type: SortTypes | None = None,
242
+ include_remaining_tags: bool | None = None,
243
+ name_contains: str | None = None,
244
+ producer_processing_step_url: AnyUrl | None = None,
245
+ show_hidden: bool | None = None,
246
+ media_type_contains: str | None = None,
247
+ tags_by_and: list[str] | None = None,
248
+ tags_by_or: list[str] | None = None,
249
+ is_kind: WorkDataKind | None = None,
250
+ created_before: AwareDatetime | None = None,
251
+ created_after: AwareDatetime | None = None,
252
+ is_deletable: bool | None = None,
253
+ is_used: bool | None = None
254
+ ) -> Self:
255
+ """Create a WorkDataQuery from flat parameters.
256
+ """
257
+ filter_param = WorkDataFilterParameter(
258
+ name_contains=name_contains,
259
+ producer_processing_step_url=producer_processing_step_url,
260
+ show_hidden=show_hidden,
261
+ media_type_contains=media_type_contains,
262
+ tags_by_and=tags_by_and,
263
+ tags_by_or=tags_by_or,
264
+ is_kind=is_kind,
265
+ created_before=created_before,
266
+ created_after=created_after,
267
+ is_deletable=is_deletable,
268
+ is_used=is_used
269
+ )
270
+
271
+ sort_by = None
272
+ if sort_by_property_name is not None or sort_by_sort_type is not None:
273
+ sort_by = WorkDataSortPropertiesSortParameter(
274
+ property_name=sort_by_property_name,
275
+ sort_type=sort_by_sort_type
276
+ )
277
+
278
+ pagination = None
279
+ if page_size is not None or page_offset is not None:
280
+ pagination = Pagination(page_size=page_size, page_offset=page_offset)
281
+
282
+ parameters = WorkDataQueryParameters(
283
+ sort_by=sort_by,
284
+ filter=filter_param,
285
+ pagination=pagination,
286
+ include_remaining_tags=include_remaining_tags
287
+ )
288
+ return cls(client, parameters)
289
+
290
+ def execute(self) -> WorkDataQueryResultHco:
291
+ """Executes the query and returns a WorkDataQueryResultHco.
292
+ """
293
+ return self._work_data_root.query_action.execute(self.parameters)
294
+
295
+ def count(self) -> int:
296
+ """Returns the total number of entities matching the query.
297
+ """
298
+ return self.execute().total_entities
299
+
300
+ def exists(self) -> bool:
301
+ """Returns True if there are any entities matching the query.
302
+ """
303
+ return self.count() > 0
304
+
305
+ def first(self) -> WorkData | None:
306
+ """Returns the first entity matching the query, or None if no entities match.
307
+ """
308
+ result = self.execute()
309
+ if result.workdatas:
310
+ return WorkData.from_hco(result.workdatas[0])
311
+ return None
312
+
313
+ def one(self) -> WorkData:
314
+ """Returns exactly one entity matching the query.
315
+ Raises an exception if no entities are found or if multiple entities match.
316
+ """
317
+ result = self.execute()
318
+ if result.total_entities == 0:
319
+ raise Exception("No entities found matching the query.")
320
+ if result.total_entities > 1:
321
+ raise Exception(f"Expected exactly one entity, but found {result.total_entities}.")
322
+ return WorkData.from_hco(result.workdatas[0])
323
+
324
+ def to_list(self) -> list[WorkData]:
325
+ """Returns all entities matching the query as a list.
326
+ """
327
+ return list(self.iter())
328
+
329
+ def iter(self) -> Iterator[WorkData]:
330
+ """
331
+ Returns an Iterator of `WorkData` so that all work data can be processed in a loop.
332
+
333
+ Returns:
334
+ An iterator of `WorkData` objects
335
+ """
336
+ for page in self.execute().iter():
337
+ for work_data_hco in page.workdatas:
338
+ yield WorkData.from_hco(work_data_hco)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pinexq-client
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: A hypermedia-based client for the DataCybernetics PinexQ platform.
5
5
  Author: Sebastian Höfer, Mathias Reichardt, Pratik Poudel
6
6
  Author-email: Sebastian Höfer <hoefer@data-cybernetics.com>, Mathias Reichardt <reichardt@data-cybernetics.com>, Pratik Poudel <poudel@data-cybernetics.com>
@@ -18,7 +18,7 @@ pinexq/client/core/model/error.py,sha256=ZDbUlwsj7d8XPMolSSLTFwgs3RBLvOvgmlEtoBu
18
18
  pinexq/client/core/model/sirenmodels.py,sha256=vGRQlhM2cSa2caxQel91Jr48KWqM-vMYX32iaQCzIds,5547
19
19
  pinexq/client/core/polling.py,sha256=nNEDONEkB3Gu5WUMm2u9RFG1OIclnixaiy7l_U2Z4No,1146
20
20
  pinexq/client/core/sirenaccess.py,sha256=F7eZI5Pz79el0D30SYNGsiS2qWaAZF_jrCrUy-q2GgY,6992
21
- pinexq/client/job_management/__init__.py,sha256=8Q-qq_yIDFFDcb4GybEnEXKhyGfFRoI62zAuj-ios7s,598
21
+ pinexq/client/job_management/__init__.py,sha256=s2rP7K9AVbmSExyC8PF7rZ6U1tuvaO8-p4xY3okfYuc,644
22
22
  pinexq/client/job_management/enterjma.py,sha256=N_jNM2UhQmWL8e-xBrTHbjZzP7WkX98MyFuKsYgD-XQ,3252
23
23
  pinexq/client/job_management/hcos/__init__.py,sha256=TZgs5kuBk3lSBxPfn5ehgbdUgzPy2jn1PC3Ea6VQY-k,584
24
24
  pinexq/client/job_management/hcos/entrypoint_hco.py,sha256=omFPggY7XGRWI5ogR85I7BHUi5o6OBnLyMggYh76JEg,2204
@@ -40,13 +40,13 @@ pinexq/client/job_management/hcos/workdata_used_tags_query_result_hco.py,sha256=
40
40
  pinexq/client/job_management/hcos/workdataroot_hco.py,sha256=WRAFihgbyxJBrGKEhAzQwds57G_WndoS0EAW1AZ38tU,4221
41
41
  pinexq/client/job_management/known_relations.py,sha256=do-u2wjb6u_HK2-y604f2gs3rk9O19MTIZpvbkfTSpA,905
42
42
  pinexq/client/job_management/model/__init__.py,sha256=iuAKRXdW_Mxo0i3HsBfEzhJJZUKkNe3qs4gLW-ge1PU,63
43
- pinexq/client/job_management/model/open_api_generated.py,sha256=IVBfhLgDi4axgaXr7iQvFPbTBRBQBsWiS7ITDyRnpkA,41498
43
+ pinexq/client/job_management/model/open_api_generated.py,sha256=ydfwdMAoO1Bb9Cqmqmm5IhzMrEM6CUcZLVK-rhRdy_8,41544
44
44
  pinexq/client/job_management/model/sirenentities.py,sha256=E29Z2MSAYIO1RYvOW_rDpzUHZUMNMioQd_-k_S4KnbQ,3958
45
- pinexq/client/job_management/tool/__init__.py,sha256=zPobd-hQyANHzC0-TjJG91z9XrewvE54ZJ6VViymW5M,128
46
- pinexq/client/job_management/tool/job.py,sha256=w81-WVVjrdg4wNaQ1yoCqJLIvvcLAhCYi-gX4at70WY,34688
45
+ pinexq/client/job_management/tool/__init__.py,sha256=4cPlrnA3lhaqFH2OFB6wyMjidgMpr05QczVJU_59kx4,174
46
+ pinexq/client/job_management/tool/job.py,sha256=cSc-YJh96-ljEDWbx-JLjHCoIwzID8mk9lTQxvG3vDM,39624
47
47
  pinexq/client/job_management/tool/job_group.py,sha256=ZFUHTk6j3oZOD52D6SOsREdBm5hVn9iUhLykrN_Ghes,11117
48
- pinexq/client/job_management/tool/processing_step.py,sha256=vlByzSHNY-f_QwP3O__qKCBuI7QhQiY-G0pkhUC7aJ4,15595
49
- pinexq/client/job_management/tool/workdata.py,sha256=eDzinv70fa76xP0LjugGzicl8GxkQ6Ozq8rz-c4k5IU,6080
50
- pinexq_client-1.1.0.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
51
- pinexq_client-1.1.0.dist-info/METADATA,sha256=xeNcvqcRZkk83Un_haYkcBbWbbiqcZ4glZ7oEOrXBL8,3459
52
- pinexq_client-1.1.0.dist-info/RECORD,,
48
+ pinexq/client/job_management/tool/processing_step.py,sha256=9NzbE8btG3mKGiS6cRAqehgVoolvQQZZDi2MRgvW2mA,20920
49
+ pinexq/client/job_management/tool/workdata.py,sha256=_X-v0t6oIBK-0hwvnpFwcdcO4rEkXmyKwobjZtOfGl0,11131
50
+ pinexq_client-1.2.0.dist-info/WHEEL,sha256=5DEXXimM34_d4Gx1AuF9ysMr1_maoEtGKjaILM3s4w4,80
51
+ pinexq_client-1.2.0.dist-info/METADATA,sha256=bijOyvGFCPm4Z-svbDi_g1VDhjyyKr-aqbZ6TuroJt8,3459
52
+ pinexq_client-1.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.28
2
+ Generator: uv 0.9.29
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any