UncountablePythonSDK 0.0.24__py3-none-any.whl → 0.0.26__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 (42) hide show
  1. {UncountablePythonSDK-0.0.24.dist-info → UncountablePythonSDK-0.0.26.dist-info}/METADATA +1 -1
  2. {UncountablePythonSDK-0.0.24.dist-info → UncountablePythonSDK-0.0.26.dist-info}/RECORD +42 -26
  3. examples/create_entity.py +3 -4
  4. pkgs/argument_parser/argument_parser.py +41 -6
  5. pkgs/type_spec/builder.py +6 -1
  6. pkgs/type_spec/emit_open_api.py +14 -5
  7. pkgs/type_spec/emit_open_api_util.py +1 -0
  8. type_spec/external/api/entity/list_entities.yaml +2 -2
  9. type_spec/external/api/entity/lock_entity.yaml +21 -0
  10. type_spec/external/api/entity/unlock_entity.yaml +18 -0
  11. type_spec/external/api/field_options/upsert_field_options.yaml +37 -0
  12. type_spec/external/api/id_source/list_id_source.yaml +2 -2
  13. type_spec/external/api/inputs/get_input_data.yaml +2 -2
  14. type_spec/external/api/inputs/get_input_names.yaml +2 -2
  15. type_spec/external/api/inputs/set_input_category.yaml +23 -0
  16. type_spec/external/api/inputs/set_input_subcategories.yaml +23 -0
  17. type_spec/external/api/material_families/update_entity_material_families.yaml +33 -0
  18. type_spec/external/api/outputs/get_output_data.yaml +2 -2
  19. type_spec/external/api/outputs/get_output_names.yaml +2 -2
  20. type_spec/external/api/project/get_projects_data.yaml +2 -2
  21. type_spec/external/api/recipe_metadata/get_recipe_metadata_data.yaml +2 -2
  22. type_spec/external/api/recipes/create_recipe.yaml +3 -0
  23. type_spec/external/api/recipes/get_recipes_data.yaml +2 -2
  24. type_spec/external/api/recipes/unarchive_recipes.yaml +17 -0
  25. uncountable/core/__init__.py +3 -2
  26. uncountable/core/client.py +83 -20
  27. uncountable/core/types.py +7 -13
  28. uncountable/types/__init__.py +14 -0
  29. uncountable/types/api/entity/lock_entity.py +38 -0
  30. uncountable/types/api/entity/unlock_entity.py +37 -0
  31. uncountable/types/api/field_options/__init__.py +1 -0
  32. uncountable/types/api/field_options/upsert_field_options.py +45 -0
  33. uncountable/types/api/inputs/set_input_category.py +37 -0
  34. uncountable/types/api/inputs/set_input_subcategories.py +38 -0
  35. uncountable/types/api/material_families/__init__.py +1 -0
  36. uncountable/types/api/material_families/update_entity_material_families.py +41 -0
  37. uncountable/types/api/recipes/create_recipe.py +1 -0
  38. uncountable/types/api/recipes/unarchive_recipes.py +34 -0
  39. uncountable/types/async_batch_processor.py +3 -0
  40. uncountable/types/client_base.py +192 -18
  41. {UncountablePythonSDK-0.0.24.dist-info → UncountablePythonSDK-0.0.26.dist-info}/WHEEL +0 -0
  42. {UncountablePythonSDK-0.0.24.dist-info → UncountablePythonSDK-0.0.26.dist-info}/top_level.txt +0 -0
@@ -13,10 +13,10 @@ Arguments:
13
13
  desc: "The material family ID to get the output values from"
14
14
  offset?:
15
15
  type: Integer
16
- desc: "Used for pagination, where the number of results returned exceeds the limit. Results are always ordered by the output ID"
16
+ desc: Used for pagination, where the number of results returned exceeds the limit. Results are always ordered by the output ID. [Pagination More Info](#pagination)
17
17
  limit?:
18
18
  type: Integer
19
- desc: "The maximum number of results to return. By default this is set to 20,000 and it cannot be set higher than 20,000"
19
+ desc: The maximum number of results to return. By default this is set to 20,000 and it cannot be set higher than 20,000. [Pagination More Info](#pagination)
20
20
 
21
21
  OutputWithName:
22
22
  type: Object
@@ -12,10 +12,10 @@ Arguments:
12
12
  desc: "The projects to get the data from"
13
13
  offset?:
14
14
  type: Optional<Integer>
15
- desc: "Used for pagination. All pagination is done in order of Project ID"
15
+ desc: Used for pagination. All pagination is done in order of Project ID. [Pagination More Info](#pagination)
16
16
  limit?:
17
17
  type: Optional<Integer>
18
- desc: "The number of data points to return. If not filled in, it will be set to 100, and cannot be set higher than 100"
18
+ desc: The number of data points to return. If not filled in, it will be set to 100, and cannot be set higher than 100. [Pagination More Info](#pagination)
19
19
 
20
20
  ProjectDetailed:
21
21
  type: Object
@@ -16,10 +16,10 @@ Arguments:
16
16
  desc: "The recipe metadata IDs to get the data from. If this is not filled in, all metadata from a material family will be returned (in paginated form)."
17
17
  offset?:
18
18
  type: Optional<Integer>
19
- desc: "Used for pagination, where the number of results returned exceeds the limit. Results are always ordered by the metadata ID"
19
+ desc: Used for pagination, where the number of results returned exceeds the limit. Results are always ordered by the metadata ID. [Pagination More Info](#pagination)
20
20
  limit?:
21
21
  type: Optional<Integer>
22
- desc: "The maximum number of results to return. By default this is set to 1,000 and it cannot be set higher than 1,000"
22
+ desc: The maximum number of results to return. By default this is set to 1,000 and it cannot be set higher than 1,000. [Pagination More Info](#pagination)
23
23
 
24
24
  FullRecipeMetadataField:
25
25
  type: Object
@@ -16,6 +16,9 @@ Arguments:
16
16
  material_family_id:
17
17
  type: ObjectId
18
18
  desc: The material family for the recipe
19
+ project_id?:
20
+ type: ObjectId
21
+ desc: The identifier of the project to create the recipe in
19
22
  workflow_id:
20
23
  type: ObjectId
21
24
  desc: The identifier of the workflow to create the recipe with
@@ -15,10 +15,10 @@ Arguments:
15
15
  desc: "The projects to get the data from. Either these or recipe_ids must be filled in"
16
16
  offset?:
17
17
  type: Optional<Integer>
18
- desc: "Used for pagination. All pagination is done in order of Recipe ID"
18
+ desc: Used for pagination. All pagination is done in order of Recipe ID. [Pagination More Info](#pagination)
19
19
  limit?:
20
20
  type: Optional<Integer>
21
- desc: "The number of data points to return. If not filled in, it will be set to 100, and cannot be set higher than 100"
21
+ desc: The number of data points to return. If not filled in, it will be set to 100, and cannot be set higher than 100. [Pagination More Info](#pagination)
22
22
 
23
23
  RecipeOutput:
24
24
  type: Object
@@ -0,0 +1,17 @@
1
+ $endpoint:
2
+ is_sdk: true
3
+ method: post
4
+ path: ${external}/recipes/unarchive
5
+ function: main.site.app.external.recipes.unarchive_recipes.unarchive_recipes
6
+ desc: Unarchive/restore the provided recipes
7
+
8
+ Arguments:
9
+ type: Object
10
+ properties:
11
+ recipes:
12
+ type: List<identifier.IdentifierKey>
13
+ desc: Identifier for the recipe
14
+
15
+
16
+ Data:
17
+ type: Object
@@ -1,5 +1,6 @@
1
- from .client import AuthDetailsApiKey, Client
1
+ from .client import Client
2
+ from .types import AuthDetailsApiKey, AuthDetailsOAuth
2
3
  from .file_upload import MediaFileUpload, UploadedFile
3
4
  from .async_batch import AsyncBatchProcessor
4
5
 
5
- __all__: list[str] = ["AuthDetailsApiKey", "AsyncBatchProcessor", "Client", "MediaFileUpload", "UploadedFile"]
6
+ __all__: list[str] = ["AuthDetailsApiKey", "AuthDetailsOAuth", "AsyncBatchProcessor", "Client", "MediaFileUpload", "UploadedFile"]
@@ -1,4 +1,5 @@
1
1
  import base64
2
+ from datetime import datetime, timedelta
2
3
  import json
3
4
  import typing
4
5
  from dataclasses import dataclass
@@ -14,7 +15,7 @@ from pkgs.serialization_util.serialization_helpers import JsonValue
14
15
  from uncountable.types.client_base import APIRequest, ClientMethods
15
16
 
16
17
  from .file_upload import FileUpload, FileUploader, UploadedFile
17
- from .types import AuthDetails, AuthDetailsApiKey
18
+ from .types import AuthDetails, AuthDetailsApiKey, AuthDetailsOAuth
18
19
 
19
20
  DT = typing.TypeVar("DT")
20
21
 
@@ -48,11 +49,13 @@ class HTTPPostRequest(HTTPRequestBase):
48
49
  HTTPRequest = HTTPPostRequest | HTTPGetRequest
49
50
 
50
51
 
51
-
52
52
  @dataclass(kw_only=True)
53
- class ClientConfig():
53
+ class ClientConfig:
54
54
  allow_insecure_tls: bool = False
55
-
55
+
56
+
57
+ OAUTH_REFRESH_WINDOW_SECONDS = 60 * 5
58
+
56
59
 
57
60
  class APIResponseError(BaseException):
58
61
  status_code: int
@@ -107,19 +110,60 @@ class SDKError(BaseException):
107
110
  return f"internal SDK error, please contact Uncountable support: {self.message}"
108
111
 
109
112
 
113
+ @dataclass(kw_only=True)
114
+ class OAuthBearerTokenCache:
115
+ token: str
116
+ expires_at: datetime
117
+
118
+
119
+ @dataclass(kw_only=True)
120
+ class GetOauthBearerTokenData:
121
+ access_token: str
122
+ expires_in: int
123
+ token_type: str
124
+ scope: str
125
+
126
+
127
+ oauth_bearer_token_data_parser = CachedParser(GetOauthBearerTokenData)
128
+
129
+
110
130
  class Client(ClientMethods):
111
131
  _parser_map: dict[type, CachedParser] = {}
112
132
  _auth_details: AuthDetails
113
133
  _base_url: str
114
134
  _file_uploader: FileUploader
115
135
  _cfg: ClientConfig
136
+ _oauth_bearer_token_cache: OAuthBearerTokenCache | None = None
116
137
 
117
- def __init__(self, *, base_url: str, auth_details: AuthDetails, config: ClientConfig | None = None):
138
+ def __init__(
139
+ self,
140
+ *,
141
+ base_url: str,
142
+ auth_details: AuthDetails,
143
+ config: ClientConfig | None = None,
144
+ ):
118
145
  self._auth_details = auth_details
119
146
  self._base_url = base_url
120
147
  self._file_uploader = FileUploader(self._base_url, self._auth_details)
121
148
  self._cfg = config or ClientConfig()
122
149
 
150
+ def _get_response_json(self, response: requests.Response) -> dict[str, JsonValue]:
151
+ if response.status_code < 200 or response.status_code > 299:
152
+ extra_details: dict[str, JsonValue] | None = None
153
+ try:
154
+ data = response.json()
155
+ if "error" in data:
156
+ extra_details = data["error"]
157
+ except JSONDecodeError:
158
+ pass
159
+ raise APIResponseError.construct_error(
160
+ status_code=response.status_code, extra_details=extra_details
161
+ )
162
+ try:
163
+ return response.json()
164
+ except JSONDecodeError:
165
+ raise SDKError("unable to process response")
166
+
123
167
  def do_request(self, *, api_request: APIRequest, return_type: type[DT]) -> DT:
124
168
  http_request = self._build_http_request(api_request=api_request)
125
169
  match http_request:
@@ -128,7 +172,7 @@ class Client(ClientMethods):
128
172
  http_request.url,
129
173
  headers=http_request.headers,
130
174
  params=http_request.query_params,
131
- verify=not self._cfg.allow_insecure_tls
175
+ verify=not self._cfg.allow_insecure_tls,
132
176
  )
133
177
  case HTTPPostRequest():
134
178
  response = requests.post(
@@ -136,26 +180,16 @@ class Client(ClientMethods):
136
180
  headers=http_request.headers,
137
181
  data=http_request.body,
138
182
  params=http_request.query_params,
139
- verify=not self._cfg.allow_insecure_tls
183
+ verify=not self._cfg.allow_insecure_tls,
140
184
  )
141
185
  case _:
142
186
  typing.assert_never(http_request)
143
- if response.status_code < 200 or response.status_code > 299:
144
- extra_details: dict[str, JsonValue] | None = None
145
- try:
146
- data = response.json()
147
- if "error" in data:
148
- extra_details = data["error"]
149
- except JSONDecodeError:
150
- pass
151
- raise APIResponseError.construct_error(
152
- status_code=response.status_code, extra_details=extra_details
153
- )
187
+ response_data = self._get_response_json(response)
154
188
  cached_parser = self._get_cached_parser(return_type)
155
189
  try:
156
- data = response.json()["data"]
190
+ data = response_data["data"]
157
191
  return cached_parser.parse_api(data)
158
- except ValueError | JSONDecodeError:
192
+ except ValueError | JSONDecodeError | KeyError:
159
193
  raise SDKError("unable to process response")
160
194
 
161
195
  def _get_cached_parser(self, data_type: type[DT]) -> CachedParser[DT]:
@@ -163,6 +197,32 @@ class Client(ClientMethods):
163
197
  self._parser_map[data_type] = CachedParser(data_type)
164
198
  return self._parser_map[data_type]
165
199
 
200
+ def _get_oauth_bearer_token(self, *, oauth_details: AuthDetailsOAuth) -> str:
201
+ if (
202
+ self._oauth_bearer_token_cache is None
203
+ or (
204
+ self._oauth_bearer_token_cache.expires_at - datetime.now()
205
+ ).total_seconds()
206
+ < OAUTH_REFRESH_WINDOW_SECONDS
207
+ ):
208
+ refresh_url = urljoin(self._base_url, "/token/get_bearer_token")
209
+ response = requests.post(
210
+ refresh_url,
211
+ data={
212
+ "client_secret": oauth_details.refresh_token,
213
+ "scope": oauth_details.scope,
214
+ "grant_type": "client_credentials",
215
+ },
216
+ )
217
+ data = self._get_response_json(response)
218
+ token_data = oauth_bearer_token_data_parser.parse_storage(data)
219
+ self._oauth_bearer_token_cache = OAuthBearerTokenCache(
220
+ token=token_data.access_token,
221
+ expires_at=datetime.now() + timedelta(seconds=token_data.expires_in),
222
+ )
223
+
224
+ return self._oauth_bearer_token_cache.token
225
+
166
226
  def _build_auth_headers(self) -> dict[str, str]:
167
227
  match self._auth_details:
168
228
  case AuthDetailsApiKey():
@@ -170,6 +230,9 @@ class Client(ClientMethods):
170
230
  f"{self._auth_details.api_id}:{self._auth_details.api_secret_key}".encode()
171
231
  ).decode("utf-8")
172
232
  return {"Authorization": f"Basic {encoded}"}
233
+ case AuthDetailsOAuth():
234
+ token = self._get_oauth_bearer_token(oauth_details=self._auth_details)
235
+ return {"Authorization": f"Bearer {token}"}
173
236
  typing.assert_never(self._auth_details)
174
237
 
175
238
  def _build_http_request(self, *, api_request: APIRequest) -> HTTPRequest:
uncountable/core/types.py CHANGED
@@ -1,16 +1,4 @@
1
- import base64
2
- import json
3
- import typing
4
1
  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
2
 
15
3
 
16
4
  @dataclass(kw_only=True)
@@ -19,4 +7,10 @@ class AuthDetailsApiKey:
19
7
  api_secret_key: str
20
8
 
21
9
 
22
- AuthDetails = AuthDetailsApiKey
10
+ @dataclass(kw_only=True)
11
+ class AuthDetailsOAuth:
12
+ refresh_token: str
13
+ scope: str = "unc.rnd"
14
+
15
+
16
+ AuthDetails = AuthDetailsApiKey | AuthDetailsOAuth
@@ -48,6 +48,7 @@ from . import input_attributes as input_attributes_t
48
48
  from . import inputs as inputs_t
49
49
  from .api.entity import list_entities as list_entities_t
50
50
  from .api.id_source import list_id_source as list_id_source_t
51
+ from .api.entity import lock_entity as lock_entity_t
51
52
  from .api.id_source import match_id_source as match_id_source_t
52
53
  from . import outputs as outputs_t
53
54
  from . import permissions as permissions_t
@@ -66,13 +67,19 @@ from . import response as response_t
66
67
  from .api.triggers import run_trigger as run_trigger_t
67
68
  from .api.permissions import set_core_permissions as set_core_permissions_t
68
69
  from .api.inputs import set_input_attribute_values as set_input_attribute_values_t
70
+ from .api.inputs import set_input_category as set_input_category_t
71
+ from .api.inputs import set_input_subcategories as set_input_subcategories_t
69
72
  from .api.recipes import set_recipe_inputs as set_recipe_inputs_t
70
73
  from .api.recipes import set_recipe_metadata as set_recipe_metadata_t
71
74
  from .api.recipes import set_recipe_outputs as set_recipe_outputs_t
72
75
  from .api.recipes import set_recipe_tags as set_recipe_tags_t
73
76
  from .api.entity import set_values as set_values_t
74
77
  from .api.entity import transition_entity_phase as transition_entity_phase_t
78
+ from .api.recipes import unarchive_recipes as unarchive_recipes_t
75
79
  from . import units as units_t
80
+ from .api.entity import unlock_entity as unlock_entity_t
81
+ from .api.material_families import update_entity_material_families as update_entity_material_families_t
82
+ from .api.field_options import upsert_field_options as upsert_field_options_t
76
83
  from . import users as users_t
77
84
  from . import workflows as workflows_t
78
85
 
@@ -123,6 +130,7 @@ __all__: list[str] = [
123
130
  "inputs_t",
124
131
  "list_entities_t",
125
132
  "list_id_source_t",
133
+ "lock_entity_t",
126
134
  "match_id_source_t",
127
135
  "outputs_t",
128
136
  "permissions_t",
@@ -141,13 +149,19 @@ __all__: list[str] = [
141
149
  "run_trigger_t",
142
150
  "set_core_permissions_t",
143
151
  "set_input_attribute_values_t",
152
+ "set_input_category_t",
153
+ "set_input_subcategories_t",
144
154
  "set_recipe_inputs_t",
145
155
  "set_recipe_metadata_t",
146
156
  "set_recipe_outputs_t",
147
157
  "set_recipe_tags_t",
148
158
  "set_values_t",
149
159
  "transition_entity_phase_t",
160
+ "unarchive_recipes_t",
150
161
  "units_t",
162
+ "unlock_entity_t",
163
+ "update_entity_material_families_t",
164
+ "upsert_field_options_t",
151
165
  "users_t",
152
166
  "workflows_t",
153
167
  ]
@@ -0,0 +1,38 @@
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 ... import async_batch as async_batch_t
12
+ from ... import entity as entity_t
13
+ from ... import identifier as identifier_t
14
+
15
+ __all__: list[str] = [
16
+ "Arguments",
17
+ "Data",
18
+ "ENDPOINT_METHOD",
19
+ "ENDPOINT_PATH",
20
+ ]
21
+
22
+ ENDPOINT_METHOD = "POST"
23
+ ENDPOINT_PATH = "api/external/entity/external_lock_entity"
24
+
25
+
26
+ # DO NOT MODIFY -- This file is generated by type_spec
27
+ @dataclass(kw_only=True)
28
+ class Arguments:
29
+ entity_key: identifier_t.IdentifierKey
30
+ entity_type: entity_t.EntityType
31
+ globally_removable: typing.Optional[bool] = None
32
+
33
+
34
+ # DO NOT MODIFY -- This file is generated by type_spec
35
+ @dataclass(kw_only=True)
36
+ class Data(async_batch_t.AsyncBatchActionReturn):
37
+ pass
38
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1,37 @@
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 ... import async_batch as async_batch_t
12
+ from ... import entity as entity_t
13
+ from ... import identifier as identifier_t
14
+
15
+ __all__: list[str] = [
16
+ "Arguments",
17
+ "Data",
18
+ "ENDPOINT_METHOD",
19
+ "ENDPOINT_PATH",
20
+ ]
21
+
22
+ ENDPOINT_METHOD = "POST"
23
+ ENDPOINT_PATH = "api/external/entity/external_unlock_entity"
24
+
25
+
26
+ # DO NOT MODIFY -- This file is generated by type_spec
27
+ @dataclass(kw_only=True)
28
+ class Arguments:
29
+ entity_key: identifier_t.IdentifierKey
30
+ entity_type: entity_t.EntityType
31
+
32
+
33
+ # DO NOT MODIFY -- This file is generated by type_spec
34
+ @dataclass(kw_only=True)
35
+ class Data(async_batch_t.AsyncBatchActionReturn):
36
+ pass
37
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1,45 @@
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 ... import identifier as identifier_t
12
+
13
+ __all__: list[str] = [
14
+ "Arguments",
15
+ "Data",
16
+ "ENDPOINT_METHOD",
17
+ "ENDPOINT_PATH",
18
+ "FieldOption",
19
+ ]
20
+
21
+ ENDPOINT_METHOD = "POST"
22
+ ENDPOINT_PATH = "api/external/field_options/upsert_field_options"
23
+
24
+
25
+ # DO NOT MODIFY -- This file is generated by type_spec
26
+ @dataclass(kw_only=True)
27
+ class FieldOption:
28
+ option_id: str
29
+ option_value: typing.Optional[str] = None
30
+ archived: typing.Optional[bool] = None
31
+ subsets: typing.Optional[list[str]] = None
32
+
33
+
34
+ # DO NOT MODIFY -- This file is generated by type_spec
35
+ @dataclass(kw_only=True)
36
+ class Arguments:
37
+ option_set_key: identifier_t.IdentifierKey
38
+ field_options: list[FieldOption]
39
+
40
+
41
+ # DO NOT MODIFY -- This file is generated by type_spec
42
+ @dataclass(kw_only=True)
43
+ class Data:
44
+ pass
45
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1,37 @@
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 ... import identifier as identifier_t
12
+ from ... import response as response_t
13
+
14
+ __all__: list[str] = [
15
+ "Arguments",
16
+ "Data",
17
+ "ENDPOINT_METHOD",
18
+ "ENDPOINT_PATH",
19
+ ]
20
+
21
+ ENDPOINT_METHOD = "POST"
22
+ ENDPOINT_PATH = "api/external/inputs/external_set_input_category"
23
+
24
+
25
+ # DO NOT MODIFY -- This file is generated by type_spec
26
+ @dataclass(kw_only=True)
27
+ class Arguments:
28
+ input_key: identifier_t.IdentifierKey
29
+ category_id: int
30
+ material_family_ids: typing.Optional[list[int]] = None
31
+
32
+
33
+ # DO NOT MODIFY -- This file is generated by type_spec
34
+ @dataclass(kw_only=True)
35
+ class Data(response_t.Response):
36
+ pass
37
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1,38 @@
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 ... import identifier as identifier_t
12
+ from ... import post_base as post_base_t
13
+ from ... import response as response_t
14
+
15
+ __all__: list[str] = [
16
+ "Arguments",
17
+ "Data",
18
+ "ENDPOINT_METHOD",
19
+ "ENDPOINT_PATH",
20
+ ]
21
+
22
+ ENDPOINT_METHOD = "POST"
23
+ ENDPOINT_PATH = "api/external/inputs/external_set_input_subcategories"
24
+
25
+
26
+ # DO NOT MODIFY -- This file is generated by type_spec
27
+ @dataclass(kw_only=True)
28
+ class Arguments:
29
+ input_key: identifier_t.IdentifierKey
30
+ subcategory_ids: list[int]
31
+ update_type: post_base_t.UpdateType
32
+
33
+
34
+ # DO NOT MODIFY -- This file is generated by type_spec
35
+ @dataclass(kw_only=True)
36
+ class Data(response_t.Response):
37
+ pass
38
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1 @@
1
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -0,0 +1,41 @@
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 ... import base as base_t
12
+ from ... import entity as entity_t
13
+ from ... import identifier as identifier_t
14
+ from ... import post_base as post_base_t
15
+ from ... import response as response_t
16
+
17
+ __all__: list[str] = [
18
+ "Arguments",
19
+ "Data",
20
+ "ENDPOINT_METHOD",
21
+ "ENDPOINT_PATH",
22
+ ]
23
+
24
+ ENDPOINT_METHOD = "POST"
25
+ ENDPOINT_PATH = "api/external/material_families/external_update_entity_material_families"
26
+
27
+
28
+ # DO NOT MODIFY -- This file is generated by type_spec
29
+ @dataclass(kw_only=True)
30
+ class Arguments:
31
+ entity_key: identifier_t.IdentifierKey
32
+ entity_type: typing.Union[typing.Literal[entity_t.EntityType.RECIPE_METADATA], typing.Literal[entity_t.EntityType.INGREDIENT], typing.Literal[entity_t.EntityType.OUTPUT], typing.Literal[entity_t.EntityType.CONDITION_PARAMETER], typing.Literal[entity_t.EntityType.INGREDIENT_ATTRIBUTE]]
33
+ material_family_ids: list[base_t.ObjectId]
34
+ update_type: post_base_t.UpdateType
35
+
36
+
37
+ # DO NOT MODIFY -- This file is generated by type_spec
38
+ @dataclass(kw_only=True)
39
+ class Data(response_t.Response):
40
+ pass
41
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -30,6 +30,7 @@ class Arguments:
30
30
  material_family_id: base_t.ObjectId
31
31
  workflow_id: base_t.ObjectId
32
32
  name: typing.Optional[str] = None
33
+ project_id: typing.Optional[base_t.ObjectId] = None
33
34
  workflow_variant_id: typing.Optional[typing.Optional[base_t.ObjectId]] = None
34
35
  recipe_metadata: typing.Optional[list[recipe_metadata_t.MetadataValue]] = None
35
36
  identifiers: typing.Optional[recipe_identifiers_t.RecipeIdentifiers] = None
@@ -0,0 +1,34 @@
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 ... import identifier as identifier_t
12
+
13
+ __all__: list[str] = [
14
+ "Arguments",
15
+ "Data",
16
+ "ENDPOINT_METHOD",
17
+ "ENDPOINT_PATH",
18
+ ]
19
+
20
+ ENDPOINT_METHOD = "POST"
21
+ ENDPOINT_PATH = "api/external/recipes/unarchive"
22
+
23
+
24
+ # DO NOT MODIFY -- This file is generated by type_spec
25
+ @dataclass(kw_only=True)
26
+ class Arguments:
27
+ recipes: list[identifier_t.IdentifierKey]
28
+
29
+
30
+ # DO NOT MODIFY -- This file is generated by type_spec
31
+ @dataclass(kw_only=True)
32
+ class Data:
33
+ pass
34
+ # DO NOT MODIFY -- This file is generated by type_spec
@@ -38,6 +38,7 @@ class AsyncBatchProcessorBase(ABC):
38
38
  material_family_id: base_t.ObjectId,
39
39
  workflow_id: base_t.ObjectId,
40
40
  name: typing.Optional[str] = None,
41
+ project_id: typing.Optional[base_t.ObjectId] = None,
41
42
  workflow_variant_id: typing.Optional[typing.Optional[base_t.ObjectId]] = None,
42
43
  recipe_metadata: typing.Optional[list[recipe_metadata_t.MetadataValue]] = None,
43
44
  identifiers: typing.Optional[recipe_identifiers_t.RecipeIdentifiers] = None,
@@ -48,6 +49,7 @@ class AsyncBatchProcessorBase(ABC):
48
49
 
49
50
  :param name: The name for the recipe
50
51
  :param material_family_id: The material family for the recipe
52
+ :param project_id: The identifier of the project to create the recipe in
51
53
  :param workflow_id: The identifier of the workflow to create the recipe with
52
54
  :param workflow_variant_id: The identifier of the workflow variant to create the recipe with
53
55
  :param recipe_metadata: Metadata values to populate the recipe with
@@ -58,6 +60,7 @@ class AsyncBatchProcessorBase(ABC):
58
60
  args = create_recipe_t.Arguments(
59
61
  name=name,
60
62
  material_family_id=material_family_id,
63
+ project_id=project_id,
61
64
  workflow_id=workflow_id,
62
65
  workflow_variant_id=workflow_variant_id,
63
66
  recipe_metadata=recipe_metadata,