UncountablePythonSDK 0.0.20__py3-none-any.whl → 0.0.21__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.

Potentially problematic release.


This version of UncountablePythonSDK might be problematic. Click here for more details.

Files changed (50) hide show
  1. {UncountablePythonSDK-0.0.20.dist-info → UncountablePythonSDK-0.0.21.dist-info}/METADATA +3 -1
  2. {UncountablePythonSDK-0.0.20.dist-info → UncountablePythonSDK-0.0.21.dist-info}/RECORD +50 -31
  3. examples/upload_files.py +19 -0
  4. pkgs/type_spec/actions_registry/__main__.py +35 -23
  5. pkgs/type_spec/actions_registry/emit_typescript.py +71 -9
  6. pkgs/type_spec/builder.py +13 -0
  7. pkgs/type_spec/config.py +1 -0
  8. pkgs/type_spec/emit_open_api.py +11 -0
  9. pkgs/type_spec/emit_open_api_util.py +1 -0
  10. pkgs/type_spec/emit_python.py +241 -55
  11. pkgs/type_spec/type_info/emit_type_info.py +129 -8
  12. type_spec/external/api/entity/create_entities.yaml +12 -1
  13. type_spec/external/api/entity/create_entity.yaml +12 -1
  14. type_spec/external/api/entity/transition_entity_phase.yaml +44 -0
  15. type_spec/external/api/permissions/set_core_permissions.yaml +69 -0
  16. type_spec/external/api/recipes/associate_recipe_as_input.yaml +4 -4
  17. type_spec/external/api/recipes/create_recipe.yaml +2 -1
  18. type_spec/external/api/recipes/disassociate_recipe_as_input.yaml +16 -0
  19. type_spec/external/api/recipes/edit_recipe_inputs.yaml +88 -0
  20. type_spec/external/api/recipes/get_curve.yaml +4 -1
  21. type_spec/external/api/recipes/get_recipes_data.yaml +6 -0
  22. type_spec/external/api/recipes/set_recipe_metadata.yaml +1 -0
  23. type_spec/external/api/recipes/set_recipe_tags.yaml +62 -0
  24. uncountable/core/__init__.py +2 -1
  25. uncountable/core/client.py +11 -9
  26. uncountable/core/file_upload.py +95 -0
  27. uncountable/core/types.py +22 -0
  28. uncountable/types/__init__.py +18 -0
  29. uncountable/types/api/entity/create_entities.py +1 -1
  30. uncountable/types/api/entity/create_entity.py +1 -1
  31. uncountable/types/api/entity/transition_entity_phase.py +66 -0
  32. uncountable/types/api/permissions/__init__.py +1 -0
  33. uncountable/types/api/permissions/set_core_permissions.py +89 -0
  34. uncountable/types/api/recipes/associate_recipe_as_input.py +4 -3
  35. uncountable/types/api/recipes/create_recipe.py +1 -1
  36. uncountable/types/api/recipes/disassociate_recipe_as_input.py +35 -0
  37. uncountable/types/api/recipes/edit_recipe_inputs.py +107 -0
  38. uncountable/types/api/recipes/get_curve.py +2 -1
  39. uncountable/types/api/recipes/get_recipes_data.py +2 -0
  40. uncountable/types/api/recipes/set_recipe_tags.py +91 -0
  41. uncountable/types/async_batch.py +9 -0
  42. uncountable/types/async_batch_processor.py +154 -0
  43. uncountable/types/client_base.py +113 -48
  44. uncountable/types/permissions.py +46 -0
  45. uncountable/types/post_base.py +30 -0
  46. uncountable/types/recipe_inputs.py +30 -0
  47. uncountable/types/recipe_metadata.py +2 -0
  48. uncountable/types/recipe_workflow_steps.py +77 -0
  49. {UncountablePythonSDK-0.0.20.dist-info → UncountablePythonSDK-0.0.21.dist-info}/WHEEL +0 -0
  50. {UncountablePythonSDK-0.0.20.dist-info → UncountablePythonSDK-0.0.21.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,69 @@
1
+ $endpoint:
2
+ is_sdk: true
3
+ method: post
4
+ path: ${external}/permissions/external_set_core_permissions
5
+ function: main.site.app.external.permissions.set_core_permissions.set_core_permissions
6
+ desc: "Sets recipe related permissions"
7
+
8
+
9
+ PermissionsScopeProject:
10
+ type: Object
11
+ properties:
12
+ type:
13
+ type: Literal<'project'>
14
+ project_key:
15
+ type: identifier.IdentifierKey
16
+
17
+ PermissionsScopeRecipe:
18
+ type: Object
19
+ properties:
20
+ type:
21
+ type: Literal<'recipe'>
22
+ recipe_key:
23
+ type: identifier.IdentifierKey
24
+
25
+ PermissionsScopeMaterialFamily:
26
+ type: Object
27
+ properties:
28
+ type:
29
+ type: Literal<'material_family'>
30
+ material_family_key:
31
+ type: identifier.IdentifierKey
32
+
33
+ PermissionsScopeAllMaterialFamilies:
34
+ type: Object
35
+ properties:
36
+ type:
37
+ type: Literal<'all_material_families'>
38
+
39
+
40
+ PermissionsScope:
41
+ type: Alias
42
+ alias: |
43
+ Union<
44
+ PermissionsScopeProject,
45
+ PermissionsScopeRecipe,
46
+ PermissionsScopeMaterialFamily,
47
+ PermissionsScopeAllMaterialFamilies
48
+ >
49
+
50
+ Arguments:
51
+ type: Object
52
+ properties:
53
+ scope:
54
+ type: PermissionsScope
55
+ desc: Scope of permissions to change
56
+ user_group_ids?:
57
+ type: List<Integer>
58
+ desc: User group ids to grant permission to
59
+ user_ids?:
60
+ type: List<Integer>
61
+ desc: User ids to grant permission to
62
+ permissions_types:
63
+ type: List<permissions.CorePermissionType>
64
+ update_type:
65
+ type: post_base.UpdateType
66
+ desc: The type of update to perform
67
+
68
+ Data:
69
+ type: Object
@@ -11,9 +11,9 @@ Arguments:
11
11
  recipe_key:
12
12
  type: identifier.IdentifierKey
13
13
  desc: "Identifier for the recipe"
14
+ input_key?:
15
+ type: identifier.IdentifierKey
16
+ desc: "Identifier for an input to use for the association. Optionally supplied. If not supplied, one is created"
14
17
 
15
18
  Data:
16
- type: Object
17
- properties:
18
- result_id:
19
- type: ObjectId
19
+ type: async_batch.AsyncBatchActionReturn
@@ -1,5 +1,6 @@
1
1
  $endpoint:
2
2
  is_sdk: true
3
+ async_batch_path: create_recipe
3
4
  method: post
4
5
  path: ${external}/recipes/create_recipe
5
6
  function: main.site.app.external.recipes.create_recipe.create_recipe
@@ -24,7 +25,7 @@ Arguments:
24
25
  recipe_metadata?:
25
26
  type: List<recipe_metadata.MetadataValue>
26
27
  desc: Metadata values to populate the recipe with
27
- identifiers:
28
+ identifiers?:
28
29
  type: recipe_identifiers.RecipeIdentifiers
29
30
  desc: A recipe won't be created if it matches the identifier. An identifier must be unique in the schema
30
31
  definition_key?:
@@ -0,0 +1,16 @@
1
+ $endpoint:
2
+ is_sdk: true
3
+ method: post
4
+ path: ${external}/recipes/disassociate_recipe_as_input
5
+ function: main.site.app.external.recipes.disassociate_recipe_as_input.disassociate_recipe_as_input
6
+ desc: Remove any association between a recipe and ingredients
7
+
8
+ Arguments:
9
+ type: Object
10
+ properties:
11
+ recipe_key:
12
+ type: identifier.IdentifierKey
13
+ desc: "Identifier for the recipe"
14
+
15
+ Data:
16
+ type: async_batch.AsyncBatchActionReturn
@@ -0,0 +1,88 @@
1
+ $endpoint:
2
+ is_sdk: true
3
+ is_beta: true
4
+ async_batch_path: edit_recipe_inputs
5
+ method: post
6
+ path: ${external}/recipes/edit_recipe_inputs
7
+ function: main.site.app.external.recipes.edit_recipe_inputs.edit_recipe_inputs
8
+ desc: Clear, update, or add inputs on a recipe
9
+
10
+ RecipeInputEditType:
11
+ type: StringEnum
12
+ values:
13
+ - clear_inputs
14
+ - upsert_input
15
+ - add_input
16
+
17
+ RecipeInputEditBase:
18
+ type: Object
19
+ properties:
20
+ type:
21
+ type: RecipeInputEditType
22
+
23
+ RecipeInputEditClearInputs:
24
+ type: RecipeInputEditBase
25
+ desc: "Clears all inputs and steps from recipe workflow step to start from scratch"
26
+ properties:
27
+ type:
28
+ type: Literal<RecipeInputEditType.clear_inputs>
29
+
30
+ RecipeInputEditInputBase:
31
+ type: RecipeInputEditBase
32
+ properties:
33
+ ingredient_key:
34
+ type: identifier.IdentifierKey
35
+ quantity_basis:
36
+ type: recipe_inputs.QuantityBasis
37
+ desc: "The basis to set for this edit. Normally this should be mass for ingredients and arbitrary for process parameters"
38
+ default: mass
39
+ input_value_type:
40
+ type: recipe_inputs.InputValueType
41
+ default: value
42
+ value_numeric?:
43
+ type: Decimal
44
+ value_str?:
45
+ type: String
46
+ calculation_key?:
47
+ type: identifier.IdentifierKey
48
+ desc: The basis calculation to set
49
+
50
+ RecipeInputEditUpsertInput:
51
+ type: RecipeInputEditInputBase
52
+ desc: "If the input is already present in the recipe, modifies it otherwise adds a new one"
53
+ properties:
54
+ type:
55
+ type: Literal<RecipeInputEditType.upsert_input>
56
+ clear_first:
57
+ type: Boolean
58
+ desc: whether to clear the current value first or modify in place
59
+
60
+ RecipeInputEditAddInput:
61
+ type: RecipeInputEditInputBase
62
+ desc: "Add the input into the recipe. If it's already present and the recipe is not a mixorder, this call will fail"
63
+ properties:
64
+ type:
65
+ type: Literal<RecipeInputEditType.add_input>
66
+
67
+
68
+ RecipeInputEdit:
69
+ type: Alias
70
+ alias: Union<RecipeInputEditClearInputs, RecipeInputEditUpsertInput, RecipeInputEditAddInput>
71
+ discriminator: type
72
+
73
+ Arguments:
74
+ type: Object
75
+ properties:
76
+ recipe_key:
77
+ type: identifier.IdentifierKey
78
+ desc: "Identifier for the recipe"
79
+ recipe_workflow_step_identifier:
80
+ type: recipe_workflow_steps.RecipeWorkflowStepIdentifierType
81
+ edits:
82
+ type: List<RecipeInputEdit>
83
+
84
+ Data:
85
+ type: Object
86
+ properties:
87
+ result_id:
88
+ type: ObjectId
@@ -7,9 +7,12 @@ $endpoint:
7
7
  Arguments:
8
8
  type: Object
9
9
  properties:
10
- recipe_output_id:
10
+ recipe_output_id?:
11
11
  type: ObjectId
12
12
  desc: "The recipe output ID to fetch the curve for. This must be a curve recipe output. Recipe Outputs can be found from external_get_recipes_data"
13
+ recipe_input_id?:
14
+ type: ObjectId
15
+ desc: "The recipe input ID to fetch the curve for. This must be a curve recipe input. Recipe Inputs can be found from external_get_recipes_data"
13
16
 
14
17
  Data:
15
18
  type: Object
@@ -77,6 +77,9 @@ SimpleOutputCondition:
77
77
  RecipeInput:
78
78
  type: Object
79
79
  properties:
80
+ id:
81
+ type: ObjectId
82
+ desc: "The globally unique id for the recipe input"
80
83
  input_id:
81
84
  type: ObjectId
82
85
  desc: "The globally unique ID for the input, allowing for cross reference elsewhere"
@@ -92,6 +95,9 @@ RecipeInput:
92
95
  quantity_json:
93
96
  type: JsonValue
94
97
  desc: "The quantity of the input if it is not numeric or recipe type. If this is filled in, quantity_dec will not be filled in"
98
+ curve_id:
99
+ type: Optional<ObjectId>
100
+ desc: "The id of the curve associated with the input if the input is of curve type."
95
101
  actual_quantity_dec:
96
102
  type: Decimal
97
103
  desc: "The actual quantity of the input if it is numeric or recipe type. If this is filled in, actual_quantity_json will not be filled in"
@@ -1,5 +1,6 @@
1
1
  $endpoint:
2
2
  is_sdk: true
3
+ async_batch_path: set_recipe_metadata
3
4
  method: post
4
5
  path: ${external}/recipes/set_recipe_metadata
5
6
  function: main.site.app.external.recipes.set_recipe_metadata.set_recipe_metadata
@@ -0,0 +1,62 @@
1
+ $endpoint:
2
+ is_sdk: true
3
+ method: post
4
+ path: ${external}/recipes/set_recipe_tags
5
+ function: main.site.app.external.recipes.set_recipe_tags.set_recipe_tags
6
+ desc: Modifies recipes tags for a recipe
7
+
8
+ RecipeTagUpdateType:
9
+ type: StringEnum
10
+ values:
11
+ - append
12
+ - override
13
+ - remove
14
+
15
+ RecipeTagUpdateBase:
16
+ type: Object
17
+ properties:
18
+ type:
19
+ type: RecipeTagUpdateType
20
+
21
+ RecipeTagAppend:
22
+ type: RecipeTagUpdateBase
23
+ properties:
24
+ type:
25
+ type: Literal<RecipeTagUpdateType.append>
26
+ recipe_tag_ids:
27
+ type: List<ObjectId>
28
+
29
+ RecipeTagRemove:
30
+ type: RecipeTagUpdateBase
31
+ properties:
32
+ type:
33
+ type: Literal<RecipeTagUpdateType.remove>
34
+ recipe_tag_ids:
35
+ type: List<ObjectId>
36
+
37
+ RecipeTagOverride:
38
+ type: RecipeTagUpdateBase
39
+ properties:
40
+ type:
41
+ type: Literal<RecipeTagUpdateType.override>
42
+ recipe_tag_ids:
43
+ type: List<ObjectId>
44
+
45
+
46
+ RecipeTagUpdate:
47
+ type: Alias
48
+ alias: Union<RecipeTagAppend, RecipeTagRemove, RecipeTagOverride>
49
+
50
+
51
+ Arguments:
52
+ type: Object
53
+ properties:
54
+ recipe_key:
55
+ type: identifier.IdentifierKey
56
+ desc: Identifier for the recipe
57
+ recipe_tag_update:
58
+ type: RecipeTagUpdate
59
+ desc: The update to perform on the recipe tags
60
+
61
+ Data:
62
+ type: Object
@@ -1,3 +1,4 @@
1
1
  from .client import AuthDetailsApiKey, Client
2
+ from .file_upload import MediaFileUpload, UploadedFile
2
3
 
3
- __all__: list[str] = ["AuthDetailsApiKey", "Client"]
4
+ __all__: list[str] = ["AuthDetailsApiKey", "Client", "MediaFileUpload", "UploadedFile"]
@@ -11,6 +11,9 @@ from pkgs.argument_parser import CachedParser
11
11
  from pkgs.serialization_util import serialize_for_api
12
12
  from uncountable.types.client_base import APIRequest, ClientMethods
13
13
 
14
+ from .file_upload import FileUpload, FileUploader, UploadedFile
15
+ from .types import AuthDetails, AuthDetailsApiKey
16
+
14
17
  DT = typing.TypeVar("DT")
15
18
 
16
19
 
@@ -43,23 +46,16 @@ class HTTPPostRequest(HTTPRequestBase):
43
46
  HTTPRequest = HTTPPostRequest | HTTPGetRequest
44
47
 
45
48
 
46
- @dataclass(kw_only=True)
47
- class AuthDetailsApiKey:
48
- api_id: str
49
- api_secret_key: str
50
-
51
-
52
- AuthDetails = AuthDetailsApiKey
53
-
54
-
55
49
  class Client(ClientMethods):
56
50
  _parser_map: dict[type, CachedParser] = {}
57
51
  _auth_details: AuthDetails
58
52
  _base_url: str
53
+ _file_uploader: FileUploader
59
54
 
60
55
  def __init__(self, *, base_url: str, auth_details: AuthDetails):
61
56
  self._auth_details = auth_details
62
57
  self._base_url = base_url
58
+ self._file_uploader = FileUploader(self._base_url, self._auth_details)
63
59
 
64
60
  def do_request(self, *, api_request: APIRequest, return_type: type[DT]) -> DT:
65
61
  http_request = self._build_http_request(api_request=api_request)
@@ -125,3 +121,9 @@ class Client(ClientMethods):
125
121
  )
126
122
  case _:
127
123
  raise ValueError(f"unsupported request method: {method}")
124
+
125
+ def upload_files(
126
+ self: typing.Self, *, file_uploads: list[FileUpload]
127
+ ) -> list[UploadedFile]:
128
+ """Upload files to uncountable, returning file ids that are usable with other SDK operations."""
129
+ return self._file_uploader.upload_files(file_uploads=file_uploads)
@@ -0,0 +1,95 @@
1
+ import asyncio
2
+ from contextlib import contextmanager
3
+ from dataclasses import dataclass
4
+ from enum import StrEnum
5
+ from io import BytesIO
6
+ from pathlib import Path
7
+ from typing import Generator, Literal, Self
8
+
9
+ import aiohttp
10
+ import aiotus
11
+
12
+ from .types import AuthDetails
13
+
14
+ _CHUNK_SIZE = 5 * 1024 * 1024 # s3 requires 5MiB minimum
15
+
16
+
17
+ class FileUploadType(StrEnum):
18
+ MEDIA_FILE_UPLOAD = "MEDIA_FILE_UPLOAD"
19
+
20
+
21
+ @dataclass(kw_only=True)
22
+ class MediaFileUpload:
23
+ """Upload file from a path on disk"""
24
+
25
+ path: str
26
+ type: FileUploadType.MEDIA_FILE_UPLOAD = FileUploadType.MEDIA_FILE_UPLOAD
27
+
28
+
29
+ FileUpload = MediaFileUpload
30
+
31
+
32
+ @dataclass(kw_only=True)
33
+ class FileBytes:
34
+ name: str
35
+ bytes_data: BytesIO
36
+
37
+
38
+ @contextmanager
39
+ def file_upload_data(file_upload: FileUpload) -> Generator[FileBytes, None, None]:
40
+ match file_upload.type:
41
+ case FileUploadType.MEDIA_FILE_UPLOAD:
42
+ with open(file_upload.path, "rb") as f:
43
+ yield FileBytes(
44
+ name=Path(file_upload.path).name, bytes_data=BytesIO(f.read())
45
+ )
46
+
47
+
48
+ @dataclass(kw_only=True)
49
+ class UploadedFile:
50
+ name: str
51
+ file_id: int
52
+
53
+
54
+ class UploadFailed(Exception):
55
+ pass
56
+
57
+
58
+ class FileUploader:
59
+ _auth_details: AuthDetails
60
+ _base_url: str
61
+
62
+ def __init__(self: Self, base_url: str, auth_details: AuthDetails) -> None:
63
+ self._base_url = base_url
64
+ self._auth_details = auth_details
65
+
66
+ async def _upload_file(self: Self, file_upload: FileUpload) -> UploadedFile:
67
+ creation_url = f"{self._base_url}/api/external/file_upload/files"
68
+ auth = aiohttp.BasicAuth(
69
+ self._auth_details.api_id, self._auth_details.api_secret_key
70
+ )
71
+ async with (
72
+ aiohttp.ClientSession(
73
+ auth=auth, headers={"Origin": self._base_url}
74
+ ) as session,
75
+ ):
76
+ with file_upload_data(file_upload) as file_bytes:
77
+ location = await aiotus.upload(
78
+ creation_url,
79
+ file_bytes.bytes_data,
80
+ {"filename": file_bytes.name.encode()},
81
+ client_session=session,
82
+ chunksize=_CHUNK_SIZE,
83
+ )
84
+ if location is None:
85
+ raise UploadFailed(f"Failed to upload: {file_bytes.name}")
86
+ return UploadedFile(
87
+ name=file_bytes.name, file_id=int(location.path.split("/")[-1])
88
+ )
89
+
90
+ def upload_files(
91
+ self: Self, *, file_uploads: list[FileUpload]
92
+ ) -> list[UploadedFile]:
93
+ return [
94
+ asyncio.run(self._upload_file(file_upload)) for file_upload in file_uploads
95
+ ]
@@ -0,0 +1,22 @@
1
+ import base64
2
+ import json
3
+ import typing
4
+ from dataclasses import dataclass
5
+ from enum import StrEnum
6
+ from urllib.parse import urljoin
7
+
8
+ import aiohttp
9
+ import requests
10
+
11
+ from pkgs.argument_parser import CachedParser
12
+ from pkgs.serialization_util import serialize_for_api
13
+ from uncountable.types.client_base import APIRequest, ClientMethods
14
+
15
+
16
+ @dataclass(kw_only=True)
17
+ class AuthDetailsApiKey:
18
+ api_id: str
19
+ api_secret_key: str
20
+
21
+
22
+ AuthDetails = AuthDetailsApiKey
@@ -17,6 +17,8 @@ from .api.recipes import create_recipe as create_recipe_t
17
17
  from .api.recipe_links import create_recipe_link as create_recipe_link_t
18
18
  from .api.recipes import create_recipes as create_recipes_t
19
19
  from . import curves as curves_t
20
+ from .api.recipes import disassociate_recipe_as_input as disassociate_recipe_as_input_t
21
+ from .api.recipes import edit_recipe_inputs as edit_recipe_inputs_t
20
22
  from . import entity as entity_t
21
23
  from .api.batch import execute_batch as execute_batch_t
22
24
  from .api.batch import execute_batch_load_async as execute_batch_load_async_t
@@ -47,21 +49,28 @@ from .api.entity import list_entities as list_entities_t
47
49
  from .api.id_source import list_id_source as list_id_source_t
48
50
  from .api.id_source import match_id_source as match_id_source_t
49
51
  from . import outputs as outputs_t
52
+ from . import permissions as permissions_t
50
53
  from . import phases as phases_t
54
+ from . import post_base as post_base_t
51
55
  from . import recipe_identifiers as recipe_identifiers_t
56
+ from . import recipe_inputs as recipe_inputs_t
52
57
  from . import recipe_links as recipe_links_t
53
58
  from . import recipe_metadata as recipe_metadata_t
54
59
  from . import recipe_output_metadata as recipe_output_metadata_t
55
60
  from . import recipe_tags as recipe_tags_t
61
+ from . import recipe_workflow_steps as recipe_workflow_steps_t
56
62
  from .api.entity import resolve_entity_ids as resolve_entity_ids_t
57
63
  from .api.outputs import resolve_output_conditions as resolve_output_conditions_t
58
64
  from . import response as response_t
59
65
  from .api.triggers import run_trigger as run_trigger_t
66
+ from .api.permissions import set_core_permissions as set_core_permissions_t
60
67
  from .api.inputs import set_input_attribute_values as set_input_attribute_values_t
61
68
  from .api.recipes import set_recipe_inputs as set_recipe_inputs_t
62
69
  from .api.recipes import set_recipe_metadata as set_recipe_metadata_t
63
70
  from .api.recipes import set_recipe_outputs as set_recipe_outputs_t
71
+ from .api.recipes import set_recipe_tags as set_recipe_tags_t
64
72
  from .api.entity import set_values as set_values_t
73
+ from .api.entity import transition_entity_phase as transition_entity_phase_t
65
74
  from . import units as units_t
66
75
  from . import users as users_t
67
76
  from . import workflows as workflows_t
@@ -82,6 +91,8 @@ __all__: list[str] = [
82
91
  "create_recipe_link_t",
83
92
  "create_recipes_t",
84
93
  "curves_t",
94
+ "disassociate_recipe_as_input_t",
95
+ "edit_recipe_inputs_t",
85
96
  "entity_t",
86
97
  "execute_batch_t",
87
98
  "execute_batch_load_async_t",
@@ -112,21 +123,28 @@ __all__: list[str] = [
112
123
  "list_id_source_t",
113
124
  "match_id_source_t",
114
125
  "outputs_t",
126
+ "permissions_t",
115
127
  "phases_t",
128
+ "post_base_t",
116
129
  "recipe_identifiers_t",
130
+ "recipe_inputs_t",
117
131
  "recipe_links_t",
118
132
  "recipe_metadata_t",
119
133
  "recipe_output_metadata_t",
120
134
  "recipe_tags_t",
135
+ "recipe_workflow_steps_t",
121
136
  "resolve_entity_ids_t",
122
137
  "resolve_output_conditions_t",
123
138
  "response_t",
124
139
  "run_trigger_t",
140
+ "set_core_permissions_t",
125
141
  "set_input_attribute_values_t",
126
142
  "set_recipe_inputs_t",
127
143
  "set_recipe_metadata_t",
128
144
  "set_recipe_outputs_t",
145
+ "set_recipe_tags_t",
129
146
  "set_values_t",
147
+ "transition_entity_phase_t",
130
148
  "units_t",
131
149
  "users_t",
132
150
  "workflows_t",
@@ -34,7 +34,7 @@ class EntityToCreate:
34
34
  @dataclass(kw_only=True)
35
35
  class Arguments:
36
36
  definition_id: base_t.ObjectId
37
- entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS]]
37
+ entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK]]
38
38
  entities_to_create: list[EntityToCreate]
39
39
 
40
40
 
@@ -40,7 +40,7 @@ class EntityFieldInitialValue:
40
40
  @dataclass(kw_only=True)
41
41
  class Arguments:
42
42
  definition_id: base_t.ObjectId
43
- entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS]]
43
+ entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK]]
44
44
  field_values: typing.Optional[typing.Optional[list[field_values_t.FieldRefNameValue]]] = None
45
45
 
46
46
 
@@ -0,0 +1,66 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec
2
+ # flake8: noqa: F821
3
+ # ruff: noqa: E402
4
+ # fmt: off
5
+ # isort: skip_file
6
+ from __future__ import annotations
7
+ import typing # noqa: F401
8
+ import datetime # noqa: F401
9
+ from decimal import Decimal # noqa: F401
10
+ from dataclasses import dataclass
11
+ from pkgs.serialization import serial_class
12
+ from ... import entity as entity_t
13
+ from ... import identifier as identifier_t
14
+ from ... import response as response_t
15
+
16
+ __all__: list[str] = [
17
+ "Arguments",
18
+ "Data",
19
+ "ENDPOINT_METHOD",
20
+ "ENDPOINT_PATH",
21
+ "TransitionIdentifier",
22
+ "TransitionIdentifierPhases",
23
+ "TransitionIdentifierTransition",
24
+ ]
25
+
26
+ ENDPOINT_METHOD = "POST"
27
+ ENDPOINT_PATH = "api/external/entity/transition_entity_phase"
28
+
29
+
30
+ # DO NOT MODIFY -- This file is generated by type_spec
31
+ @serial_class(
32
+ parse_require={"type"},
33
+ )
34
+ @dataclass(kw_only=True)
35
+ class TransitionIdentifierPhases:
36
+ type: typing.Literal["phases"] = "phases"
37
+ phase_from_key: identifier_t.IdentifierKey
38
+ phase_to_key: identifier_t.IdentifierKey
39
+
40
+
41
+ # DO NOT MODIFY -- This file is generated by type_spec
42
+ @serial_class(
43
+ parse_require={"type"},
44
+ )
45
+ @dataclass(kw_only=True)
46
+ class TransitionIdentifierTransition:
47
+ type: typing.Literal["transition"] = "transition"
48
+ transition_key: identifier_t.IdentifierKey
49
+
50
+
51
+ # DO NOT MODIFY -- This file is generated by type_spec
52
+ TransitionIdentifier = typing.Union[TransitionIdentifierPhases, TransitionIdentifierTransition]
53
+
54
+
55
+ # DO NOT MODIFY -- This file is generated by type_spec
56
+ @dataclass(kw_only=True)
57
+ class Arguments:
58
+ entity: entity_t.Entity
59
+ transition: TransitionIdentifier
60
+
61
+
62
+ # DO NOT MODIFY -- This file is generated by type_spec
63
+ @dataclass(kw_only=True)
64
+ class Data(response_t.Response):
65
+ pass
66
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec