UncountablePythonSDK 0.0.7__py3-none-any.whl → 0.0.9__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.
- {UncountablePythonSDK-0.0.7.dist-info → UncountablePythonSDK-0.0.9.dist-info}/METADATA +4 -2
- UncountablePythonSDK-0.0.9.dist-info/RECORD +145 -0
- pkgs/argument_parser/argument_parser.py +2 -2
- pkgs/serialization/missing_sentry.py +1 -1
- pkgs/serialization_util/serialization_helpers.py +3 -0
- pkgs/type_spec/emit_open_api.py +34 -17
- pkgs/type_spec/emit_open_api_util.py +4 -9
- pkgs/type_spec/emit_python.py +8 -5
- pkgs/type_spec/open_api_util.py +13 -12
- type_spec/external/api/entity/create_entities.yaml +1 -1
- type_spec/external/api/entity/create_entity.yaml +1 -1
- type_spec/external/api/entity/get_entities_data.yaml +4 -30
- type_spec/external/api/entity/list_entities.yaml +4 -14
- type_spec/external/api/entity/resolve_entity_ids.yaml +2 -2
- type_spec/external/api/entity/set_values.yaml +3 -30
- type_spec/external/api/input_groups/get_input_group_names.yaml +2 -2
- type_spec/external/api/inputs/create_inputs.yaml +6 -19
- type_spec/external/api/inputs/get_input_data.yaml +11 -24
- type_spec/external/api/inputs/get_input_names.yaml +4 -4
- type_spec/external/api/inputs/get_inputs_data.yaml +7 -20
- type_spec/external/api/inputs/set_input_attribute_values.yaml +3 -7
- type_spec/external/api/outputs/get_output_data.yaml +9 -20
- type_spec/external/api/outputs/get_output_names.yaml +2 -2
- type_spec/external/api/project/get_projects.yaml +6 -16
- type_spec/external/api/project/get_projects_data.yaml +10 -46
- type_spec/external/api/recipe_metadata/get_recipe_metadata_data.yaml +5 -5
- type_spec/external/api/recipes/create_recipes.yaml +5 -18
- type_spec/external/api/recipes/get_curve.yaml +2 -34
- type_spec/external/api/recipes/get_recipe_calculations.yaml +7 -17
- type_spec/external/api/recipes/get_recipe_links.yaml +1 -1
- type_spec/external/api/recipes/get_recipe_names.yaml +2 -2
- type_spec/external/api/recipes/get_recipe_output_metadata.yaml +4 -17
- type_spec/external/api/recipes/get_recipes_data.yaml +31 -165
- type_spec/external/api/recipes/set_recipe_inputs.yaml +3 -3
- type_spec/external/api/recipes/set_recipe_outputs.yaml +4 -8
- uncountable/integration/__init__.py +0 -0
- uncountable/integration/construct_client.py +30 -0
- uncountable/integration/cron.py +29 -0
- uncountable/integration/db/__init__.py +0 -0
- uncountable/integration/db/connect.py +8 -0
- uncountable/integration/entrypoint.py +41 -0
- uncountable/integration/executors/__init__.py +0 -0
- uncountable/integration/executors/script_executor.py +18 -0
- uncountable/integration/job.py +39 -0
- uncountable/integration/server.py +86 -0
- uncountable/integration/types.py +89 -0
- uncountable/types/__init__.py +30 -0
- uncountable/types/api/entity/create_entities.py +2 -1
- uncountable/types/api/entity/create_entity.py +1 -1
- uncountable/types/api/entity/get_entities_data.py +6 -26
- uncountable/types/api/entity/list_entities.py +5 -12
- uncountable/types/api/entity/resolve_entity_ids.py +4 -2
- uncountable/types/api/entity/set_values.py +7 -29
- uncountable/types/api/input_groups/get_input_group_names.py +3 -2
- uncountable/types/api/inputs/create_inputs.py +8 -20
- uncountable/types/api/inputs/get_input_data.py +12 -25
- uncountable/types/api/inputs/get_input_names.py +5 -4
- uncountable/types/api/inputs/get_inputs_data.py +8 -21
- uncountable/types/api/inputs/set_input_attribute_values.py +5 -7
- uncountable/types/api/outputs/get_output_data.py +10 -17
- uncountable/types/api/outputs/get_output_names.py +3 -2
- uncountable/types/api/project/get_projects.py +8 -14
- uncountable/types/api/project/get_projects_data.py +13 -40
- uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +6 -5
- uncountable/types/api/recipes/create_recipes.py +6 -18
- uncountable/types/api/recipes/get_curve.py +4 -26
- uncountable/types/api/recipes/get_recipe_calculations.py +8 -15
- uncountable/types/api/recipes/get_recipe_links.py +2 -1
- uncountable/types/api/recipes/get_recipe_names.py +3 -2
- uncountable/types/api/recipes/get_recipe_output_metadata.py +5 -13
- uncountable/types/api/recipes/get_recipes_data.py +36 -122
- uncountable/types/api/recipes/set_recipe_inputs.py +4 -3
- uncountable/types/api/recipes/set_recipe_outputs.py +7 -8
- uncountable/types/calculations.py +23 -0
- uncountable/types/client_base.py +43 -43
- uncountable/types/curves.py +47 -0
- uncountable/types/entity.py +4 -1
- uncountable/types/experiment_groups.py +23 -0
- uncountable/types/field_values.py +37 -0
- uncountable/types/fields.py +24 -0
- uncountable/types/input_attributes.py +29 -0
- uncountable/types/inputs.py +61 -0
- uncountable/types/outputs.py +26 -0
- uncountable/types/phases.py +23 -0
- uncountable/types/recipe_links.py +3 -2
- uncountable/types/recipe_metadata.py +50 -0
- uncountable/types/recipe_output_metadata.py +24 -0
- uncountable/types/recipe_tags.py +23 -0
- uncountable/types/response.py +25 -0
- uncountable/types/units.py +23 -0
- uncountable/types/users.py +24 -0
- uncountable/types/workflows.py +32 -0
- UncountablePythonSDK-0.0.7.dist-info/RECORD +0 -119
- {UncountablePythonSDK-0.0.7.dist-info → UncountablePythonSDK-0.0.9.dist-info}/WHEEL +0 -0
- {UncountablePythonSDK-0.0.7.dist-info → UncountablePythonSDK-0.0.9.dist-info}/top_level.txt +0 -0
|
@@ -8,17 +8,17 @@ Arguments:
|
|
|
8
8
|
type: Object
|
|
9
9
|
properties:
|
|
10
10
|
recipe_output_ids:
|
|
11
|
-
type: List<
|
|
11
|
+
type: List<ObjectId>
|
|
12
12
|
desc: "Ids of the Recipe Outputs to retrieve metadata for"
|
|
13
13
|
|
|
14
14
|
RecipeOutputMetadata:
|
|
15
15
|
type: Object
|
|
16
16
|
properties:
|
|
17
17
|
recipe_output_id:
|
|
18
|
-
type:
|
|
18
|
+
type: ObjectId
|
|
19
19
|
desc: "Identifier for the recipe output"
|
|
20
20
|
recipe_output_metadata_field_id:
|
|
21
|
-
type:
|
|
21
|
+
type: ObjectId
|
|
22
22
|
desc: "Identifier for the metadata field id"
|
|
23
23
|
quantity_dec:
|
|
24
24
|
type: Decimal
|
|
@@ -27,23 +27,10 @@ RecipeOutputMetadata:
|
|
|
27
27
|
type: JsonValue
|
|
28
28
|
desc: "The value for the metadata, if it is not of numeric type"
|
|
29
29
|
|
|
30
|
-
RecipeOutputMetadataField:
|
|
31
|
-
type: Object
|
|
32
|
-
properties:
|
|
33
|
-
id:
|
|
34
|
-
type: Integer
|
|
35
|
-
desc: "Identifier for the recipe output metadata field"
|
|
36
|
-
name:
|
|
37
|
-
type: String
|
|
38
|
-
desc: "Name of the recipe output metadata field"
|
|
39
|
-
quantity_type:
|
|
40
|
-
type: String
|
|
41
|
-
desc: "The quantity type of the metadata, such as numeric or text"
|
|
42
|
-
|
|
43
30
|
Data:
|
|
44
31
|
type: Object
|
|
45
32
|
properties:
|
|
46
33
|
recipe_output_metadata:
|
|
47
34
|
type: List<RecipeOutputMetadata>
|
|
48
35
|
recipe_output_metadata_fields:
|
|
49
|
-
type: List<RecipeOutputMetadataField>
|
|
36
|
+
type: List<recipe_output_metadata.RecipeOutputMetadataField>
|
|
@@ -7,89 +7,28 @@ $endpoint:
|
|
|
7
7
|
Arguments:
|
|
8
8
|
type: Object
|
|
9
9
|
properties:
|
|
10
|
-
recipe_ids
|
|
11
|
-
type: Optional<List<
|
|
10
|
+
recipe_ids?:
|
|
11
|
+
type: Optional<List<ObjectId>>
|
|
12
12
|
desc: "The recipes to get the data from. Either these or project_id must be filled in"
|
|
13
|
-
project_id
|
|
14
|
-
type: Optional<
|
|
13
|
+
project_id?:
|
|
14
|
+
type: Optional<ObjectId>
|
|
15
15
|
desc: "The projects to get the data from. Either these or recipe_ids must be filled in"
|
|
16
|
-
offset
|
|
16
|
+
offset?:
|
|
17
17
|
type: Optional<Integer>
|
|
18
18
|
desc: "Used for pagination. All pagination is done in order of Recipe ID"
|
|
19
|
-
limit
|
|
19
|
+
limit?:
|
|
20
20
|
type: Optional<Integer>
|
|
21
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"
|
|
22
22
|
|
|
23
|
-
SimpleRecipeMetadataField:
|
|
24
|
-
type: Object
|
|
25
|
-
desc: "A descriptor of metadata. Metadata includes values that are neither ingredients nor process parameters, such as a location of an experiment"
|
|
26
|
-
properties:
|
|
27
|
-
metadata_id:
|
|
28
|
-
type: Integer
|
|
29
|
-
desc: "A unique ID for the metadata, referenceable elsewhere"
|
|
30
|
-
name:
|
|
31
|
-
type: String
|
|
32
|
-
desc: "The name of the metadata"
|
|
33
|
-
quantity_type:
|
|
34
|
-
type: String
|
|
35
|
-
desc: "The quantity type of the metadata, such as numeric or text"
|
|
36
|
-
|
|
37
|
-
RecipeMetadata:
|
|
38
|
-
type: Object
|
|
39
|
-
desc: "The specific value of a metadata for a recipe. Recipe may only have 1 instance of each metadata"
|
|
40
|
-
properties:
|
|
41
|
-
metadata_id:
|
|
42
|
-
type: Integer
|
|
43
|
-
desc: "The unique ID for the metadata"
|
|
44
|
-
quantity_dec:
|
|
45
|
-
type: Decimal
|
|
46
|
-
desc: "The value for the metadata, if it is of numeric type"
|
|
47
|
-
quantity_json:
|
|
48
|
-
type: JsonValue
|
|
49
|
-
desc: "The value for the metadata, if it is not of numeric type"
|
|
50
|
-
|
|
51
|
-
SimpleRecipeTag:
|
|
52
|
-
type: Object
|
|
53
|
-
desc: "A representation of recipe tags within Uncountable system"
|
|
54
|
-
properties:
|
|
55
|
-
recipe_tag_id:
|
|
56
|
-
type: Integer
|
|
57
|
-
desc: "A unique ID for the tag, referenceable elsewhere"
|
|
58
|
-
name:
|
|
59
|
-
type: String
|
|
60
|
-
desc: "The name of the tag"
|
|
61
|
-
|
|
62
|
-
SimpleExperimentGroup:
|
|
63
|
-
type: Object
|
|
64
|
-
desc: "A representation of experiment groups within Uncountable system"
|
|
65
|
-
properties:
|
|
66
|
-
experiment_group_id:
|
|
67
|
-
type: Integer
|
|
68
|
-
desc: "A unique ID for the group, referenceable elsewhere"
|
|
69
|
-
name:
|
|
70
|
-
type: String
|
|
71
|
-
desc: "The name of the group"
|
|
72
|
-
|
|
73
|
-
SimpleUnit:
|
|
74
|
-
type: Object
|
|
75
|
-
desc: "A representation of units within Uncountable system"
|
|
76
|
-
properties:
|
|
77
|
-
unit_id:
|
|
78
|
-
type: Integer
|
|
79
|
-
desc: "A unique ID for the unit, referenceable elsewhere"
|
|
80
|
-
name:
|
|
81
|
-
type: String
|
|
82
|
-
desc: "The name of the unit"
|
|
83
|
-
|
|
84
23
|
RecipeOutput:
|
|
85
24
|
type: Object
|
|
86
25
|
desc: "A representation of a single measurement associated with a recipe / experiment within Uncountable system"
|
|
87
26
|
properties:
|
|
88
27
|
id:
|
|
89
|
-
type:
|
|
28
|
+
type: ObjectId
|
|
90
29
|
desc: "The global unique identifier for the recipe output. For cross-reference elsewhere."
|
|
91
30
|
output_id:
|
|
92
|
-
type:
|
|
31
|
+
type: ObjectId
|
|
93
32
|
desc: "The output specifically measured in this case"
|
|
94
33
|
replicate_num:
|
|
95
34
|
type: Integer
|
|
@@ -101,35 +40,18 @@ RecipeOutput:
|
|
|
101
40
|
type: JsonValue
|
|
102
41
|
desc: "The quantity of the output, if not numeric"
|
|
103
42
|
curve_id:
|
|
104
|
-
type:
|
|
43
|
+
type: ObjectId
|
|
105
44
|
desc: "The id of the curve associated with the output if the output is of curve type."
|
|
106
45
|
output_condition_id:
|
|
107
|
-
type:
|
|
46
|
+
type: ObjectId
|
|
108
47
|
desc: "A reference to the condition ID for the output (null if there are no conditions). Used to encode complicated test settings such as test standard, aging time, etc."
|
|
109
48
|
|
|
110
|
-
SimpleOutput:
|
|
111
|
-
type: Object
|
|
112
|
-
desc: "A condensed object representing an output / measurement within Uncountables system"
|
|
113
|
-
properties:
|
|
114
|
-
output_id:
|
|
115
|
-
type: Integer
|
|
116
|
-
desc: "The globally unique identifier for the output"
|
|
117
|
-
name:
|
|
118
|
-
type: String
|
|
119
|
-
desc: "The name of the output"
|
|
120
|
-
unit:
|
|
121
|
-
type: Optional<SimpleUnit>
|
|
122
|
-
desc: "The units for the output, if filled in"
|
|
123
|
-
quantity_type:
|
|
124
|
-
type: String
|
|
125
|
-
desc: "The quantity type of the output, with common types including numeric, text, categorical, curve"
|
|
126
|
-
|
|
127
49
|
ConditionParameterValue:
|
|
128
50
|
type: Object
|
|
129
51
|
desc: "A condition parameter value represents a single association of value with a parameter. For instance, Test Method: ISO 23"
|
|
130
52
|
properties:
|
|
131
53
|
condition_parameter_id:
|
|
132
|
-
type:
|
|
54
|
+
type: ObjectId
|
|
133
55
|
desc: "The globally unique identifier for the condition parameter, i.e. Test Method or Aging Time"
|
|
134
56
|
condition_parameter_name:
|
|
135
57
|
type: String
|
|
@@ -146,47 +68,23 @@ SimpleOutputCondition:
|
|
|
146
68
|
desc: "Within Uncountable, Output conditions represent how an output is measured. Common use cases include the test temperature, test standard, aging time, etc. An outputcondition is the full description of these parameters"
|
|
147
69
|
properties:
|
|
148
70
|
output_condition_id:
|
|
149
|
-
type:
|
|
71
|
+
type: ObjectId
|
|
150
72
|
desc: "The globally unique ID for the Output Condition, used for cross reference elsewhere"
|
|
151
73
|
condition_parameter_values:
|
|
152
74
|
type: List<ConditionParameterValue>
|
|
153
75
|
desc: "The list of parameters and values that comprise this condition"
|
|
154
|
-
SimpleWorkflowStep:
|
|
155
|
-
type: Object
|
|
156
|
-
desc: "A step associated with a workflow, representing where inputs are placed in the context of a recipe / experiment."
|
|
157
|
-
properties:
|
|
158
|
-
workflow_step_id:
|
|
159
|
-
type: Integer
|
|
160
|
-
desc: "The globally unique ID for the workflow step, used for cross reference elsewhere"
|
|
161
|
-
name:
|
|
162
|
-
type: String
|
|
163
|
-
desc: "The name of the workflow step"
|
|
164
|
-
|
|
165
|
-
SimpleWorkflow:
|
|
166
|
-
type: Object
|
|
167
|
-
desc: "A workflow object. Workflows represent broad flowcharts for how experimental creation is done, including a graph of steps that lead into each other."
|
|
168
|
-
properties:
|
|
169
|
-
workflow_id:
|
|
170
|
-
type: Integer
|
|
171
|
-
desc: "The globally unique ID for the workflow, used for cross reference elsewhere"
|
|
172
|
-
name:
|
|
173
|
-
type: String
|
|
174
|
-
desc: "The name of the workflow"
|
|
175
|
-
workflow_steps:
|
|
176
|
-
type: List<SimpleWorkflowStep>
|
|
177
|
-
desc: "The steps associated with the workflow, representing where inputs are placed in the context of a recipe / experiment."
|
|
178
76
|
|
|
179
77
|
RecipeInput:
|
|
180
78
|
type: Object
|
|
181
79
|
properties:
|
|
182
80
|
input_id:
|
|
183
|
-
type:
|
|
81
|
+
type: ObjectId
|
|
184
82
|
desc: "The globally unique ID for the input, allowing for cross reference elsewhere"
|
|
185
83
|
input_lot_recipe_id:
|
|
186
|
-
type: Optional<
|
|
84
|
+
type: Optional<ObjectId>
|
|
187
85
|
desc: "The recipe id of the lot associated with the input"
|
|
188
86
|
recipe_step_id:
|
|
189
|
-
type:
|
|
87
|
+
type: ObjectId
|
|
190
88
|
desc: "The unique Recipe Step ID for the input, allowing for placement within the workflow"
|
|
191
89
|
quantity_dec:
|
|
192
90
|
type: Decimal
|
|
@@ -207,25 +105,6 @@ RecipeInput:
|
|
|
207
105
|
type: String
|
|
208
106
|
desc: "The behavior of the input relative to the experiment. For example 'inclusion' or 'use quantity'."
|
|
209
107
|
|
|
210
|
-
SimpleInput:
|
|
211
|
-
type: Object
|
|
212
|
-
properties:
|
|
213
|
-
input_id:
|
|
214
|
-
type: Integer
|
|
215
|
-
desc: "The globally unique ID for the input, allowing for cross reference elsewhere"
|
|
216
|
-
quantity_type:
|
|
217
|
-
type: String
|
|
218
|
-
desc: "The quantity type of the input in string form. Common types are numeric, recipe (representing a nested input), text, categorical"
|
|
219
|
-
name:
|
|
220
|
-
type: String
|
|
221
|
-
desc: "The name of the input"
|
|
222
|
-
is_parameter:
|
|
223
|
-
type: Boolean
|
|
224
|
-
desc: "Whether the input is a process parameter (true) or an ingredient (false)"
|
|
225
|
-
intermediate_recipe_id:
|
|
226
|
-
type: Optional<Integer>
|
|
227
|
-
desc: "The recipe ID of the input if the input is a a recipe (intermediate)."
|
|
228
|
-
|
|
229
108
|
RecipeStep:
|
|
230
109
|
type: Object
|
|
231
110
|
properties:
|
|
@@ -233,7 +112,7 @@ RecipeStep:
|
|
|
233
112
|
type: Optional<String>
|
|
234
113
|
desc: "An optional name for the recipe step"
|
|
235
114
|
recipe_step_id:
|
|
236
|
-
type:
|
|
115
|
+
type: ObjectId
|
|
237
116
|
desc: "An ID value for the recipe step, used elsewhere to reference the part of the recipe / experiment that the input was placed in"
|
|
238
117
|
recipe_step_number:
|
|
239
118
|
type: Integer
|
|
@@ -257,28 +136,15 @@ RecipeWorkflowStep:
|
|
|
257
136
|
desc: "A workflow step associated with a recipe / experiment. Workflow steps are comprised of recipe step groups, in turn comprised of recipe steps, where inputs are located. These groupings exists to give customers the ability to flexibly place inputs into the correct process ordering"
|
|
258
137
|
properties:
|
|
259
138
|
recipe_workflow_step_id:
|
|
260
|
-
type:
|
|
139
|
+
type: ObjectId
|
|
261
140
|
desc: "A unique reference for the workflow step within the recipe."
|
|
262
141
|
workflow_step_id:
|
|
263
|
-
type:
|
|
142
|
+
type: ObjectId
|
|
264
143
|
desc: "A reference to the workflow_step_id for the workflow. This will be shared across recipes / experiments, and can be used to do analysis about what part of a generic process inputs are located in."
|
|
265
144
|
recipe_step_groups:
|
|
266
145
|
type: List<RecipeStepGroup>
|
|
267
146
|
desc: "A listing of recipe step groups within the recipe / experiment"
|
|
268
147
|
|
|
269
|
-
SimpleUser:
|
|
270
|
-
type: Object
|
|
271
|
-
properties:
|
|
272
|
-
user_id:
|
|
273
|
-
type: Integer
|
|
274
|
-
desc: "The globally unique ID for the user, allowing for cross reference elsewhere"
|
|
275
|
-
display_name:
|
|
276
|
-
type: String
|
|
277
|
-
desc: "The display name of the user within Uncountable."
|
|
278
|
-
email:
|
|
279
|
-
type: String
|
|
280
|
-
desc: "The email address of the user in Uncountable's system."
|
|
281
|
-
|
|
282
148
|
RecipeStepRelationship:
|
|
283
149
|
type: Object
|
|
284
150
|
properties:
|
|
@@ -305,10 +171,10 @@ Recipe:
|
|
|
305
171
|
type: Object
|
|
306
172
|
properties:
|
|
307
173
|
recipe_id:
|
|
308
|
-
type:
|
|
174
|
+
type: ObjectId
|
|
309
175
|
desc: "A unique identifier for the recipe / experiment. Used for joining elsewhere"
|
|
310
176
|
creating_user_id?:
|
|
311
|
-
type:
|
|
177
|
+
type: ObjectId
|
|
312
178
|
desc: "The user ID who originally created the recipe / experiment. Null when created from automated scripts, such as data transfers, or from the Uncountable implementation team."
|
|
313
179
|
create_datetime:
|
|
314
180
|
type: String
|
|
@@ -326,10 +192,10 @@ Recipe:
|
|
|
326
192
|
type: String
|
|
327
193
|
desc: "The value used in the barcoding system to lookup this experiment."
|
|
328
194
|
workflow_id:
|
|
329
|
-
type:
|
|
195
|
+
type: ObjectId
|
|
330
196
|
desc: "The workflow ID associated with the recipe / experiment. Workflows correspond to a set of experimental steps performed, and are referenced in the workflows return object"
|
|
331
197
|
metadata:
|
|
332
|
-
type: List<RecipeMetadata>
|
|
198
|
+
type: List<recipe_metadata.RecipeMetadata>
|
|
333
199
|
desc: "Metadata associated with a recipe / experimen. Metadata includes values that are neither ingredients nor process parameters, such as a location of an experiment"
|
|
334
200
|
inputs:
|
|
335
201
|
type: List<RecipeInput>
|
|
@@ -341,10 +207,10 @@ Recipe:
|
|
|
341
207
|
type: List<RecipeWorkflowStep>
|
|
342
208
|
desc: "A reference of workflow steps in the recipe / experimen. This is used to reference input values to where they occurred in the experimental process."
|
|
343
209
|
tag_ids:
|
|
344
|
-
type: List<
|
|
210
|
+
type: List<ObjectId>
|
|
345
211
|
desc: A list of Tag IDs associated with the recipe / experiment
|
|
346
212
|
experiment_group_ids:
|
|
347
|
-
type: List<
|
|
213
|
+
type: List<ObjectId>
|
|
348
214
|
desc: A list of experiment group IDs associated with the recipe / experiment
|
|
349
215
|
step_relationships:
|
|
350
216
|
type: List<RecipeStepRelationship>
|
|
@@ -355,18 +221,18 @@ Data:
|
|
|
355
221
|
recipes:
|
|
356
222
|
type: List<Recipe>
|
|
357
223
|
workflows:
|
|
358
|
-
type: List<SimpleWorkflow>
|
|
224
|
+
type: List<workflows.SimpleWorkflow>
|
|
359
225
|
metadata:
|
|
360
|
-
type: List<SimpleRecipeMetadataField>
|
|
226
|
+
type: List<recipe_metadata.SimpleRecipeMetadataField>
|
|
361
227
|
inputs:
|
|
362
|
-
type: List<SimpleInput>
|
|
228
|
+
type: List<inputs.SimpleInput>
|
|
363
229
|
outputs:
|
|
364
|
-
type: List<SimpleOutput>
|
|
230
|
+
type: List<outputs.SimpleOutput>
|
|
365
231
|
output_conditions:
|
|
366
232
|
type: List<SimpleOutputCondition>
|
|
367
233
|
users:
|
|
368
|
-
type: List<SimpleUser>
|
|
234
|
+
type: List<users.SimpleUser>
|
|
369
235
|
recipe_tags:
|
|
370
|
-
type: List<SimpleRecipeTag>
|
|
236
|
+
type: List<recipe_tags.SimpleRecipeTag>
|
|
371
237
|
experiment_groups:
|
|
372
|
-
type: List<SimpleExperimentGroup>
|
|
238
|
+
type: List<experiment_groups.SimpleExperimentGroup>
|
|
@@ -9,13 +9,13 @@ RecipeInputValue:
|
|
|
9
9
|
type: Object
|
|
10
10
|
properties:
|
|
11
11
|
recipe_id:
|
|
12
|
-
type:
|
|
12
|
+
type: ObjectId
|
|
13
13
|
desc: "A unique identifier for the recipe / experiment. Used for joining elsewhere"
|
|
14
14
|
recipe_step_id?:
|
|
15
|
-
type: Optional<
|
|
15
|
+
type: Optional<ObjectId>
|
|
16
16
|
desc: "Optionally the step id for the step of the recipe to be written to. If none is passed, the input will be written to first recipe workflow step"
|
|
17
17
|
input_id:
|
|
18
|
-
type:
|
|
18
|
+
type: ObjectId
|
|
19
19
|
desc: "A unique identifier for the input. Used for joining and identification"
|
|
20
20
|
value_numeric?:
|
|
21
21
|
type: Decimal
|
|
@@ -19,13 +19,13 @@ RecipeOutputValue:
|
|
|
19
19
|
type: Object
|
|
20
20
|
properties:
|
|
21
21
|
recipe_id:
|
|
22
|
-
type:
|
|
22
|
+
type: ObjectId
|
|
23
23
|
desc: "A unique identifier for the recipe / experiment. Used for joining elsewhere"
|
|
24
24
|
output_id:
|
|
25
|
-
type:
|
|
25
|
+
type: ObjectId
|
|
26
26
|
desc: "A unique identifier for the output. Used for joining and identification"
|
|
27
27
|
condition_id?:
|
|
28
|
-
type:
|
|
28
|
+
type: ObjectId
|
|
29
29
|
desc: "A unique identifier the set of condition parameters associated with the output."
|
|
30
30
|
experiment_num:
|
|
31
31
|
type: Integer
|
|
@@ -48,9 +48,5 @@ Arguments:
|
|
|
48
48
|
desc: "The outputs to set. Must be at most 100 entries long"
|
|
49
49
|
|
|
50
50
|
Data:
|
|
51
|
-
type:
|
|
51
|
+
type: response.Response
|
|
52
52
|
properties:
|
|
53
|
-
status:
|
|
54
|
-
type: Literal<'ok'>
|
|
55
|
-
default: "ok"
|
|
56
|
-
desc: "'ok' indicates the post request was successful"
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import assert_never
|
|
3
|
+
|
|
4
|
+
from uncountable.core.client import AuthDetailsApiKey, Client
|
|
5
|
+
from uncountable.integration.types import (
|
|
6
|
+
AuthRetrievalEnv,
|
|
7
|
+
ProfileMetadata,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def construct_uncountable_client(
|
|
12
|
+
profile_meta: ProfileMetadata
|
|
13
|
+
) -> Client:
|
|
14
|
+
match profile_meta.auth_retrieval:
|
|
15
|
+
case AuthRetrievalEnv():
|
|
16
|
+
api_id = os.getenv(f"UNC_PROFILE_{profile_meta.name}_API_ID")
|
|
17
|
+
api_secret_key = os.getenv(
|
|
18
|
+
f"UNC_PROFILE_{profile_meta.name}_API_SECRET_KEY"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
assert api_id is not None
|
|
22
|
+
assert api_secret_key is not None
|
|
23
|
+
|
|
24
|
+
return Client(
|
|
25
|
+
base_url=profile_meta.base_url,
|
|
26
|
+
auth_details=AuthDetailsApiKey(
|
|
27
|
+
api_id=api_id, api_secret_key=api_secret_key
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
assert_never(profile_meta.auth_retrieval)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from pkgs.argument_parser import CachedParser
|
|
4
|
+
from uncountable.integration.construct_client import construct_uncountable_client
|
|
5
|
+
from uncountable.integration.executors.script_executor import resolve_script_executor
|
|
6
|
+
from uncountable.integration.job import CronJobArguments
|
|
7
|
+
from uncountable.integration.types import JobDefinition, ProfileMetadata
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class CronJobArgs:
|
|
12
|
+
definition: JobDefinition
|
|
13
|
+
profile_metadata: ProfileMetadata
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
cron_args_parser = CachedParser(CronJobArgs)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def cron_job_executor(**kwargs: dict) -> None:
|
|
20
|
+
args_passed = cron_args_parser.parse_storage(kwargs)
|
|
21
|
+
args = CronJobArguments(
|
|
22
|
+
job_definition=args_passed.definition,
|
|
23
|
+
client=construct_uncountable_client(profile_meta=args_passed.profile_metadata),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
job_class = resolve_script_executor(args_passed.definition.executor)
|
|
27
|
+
|
|
28
|
+
job = job_class()
|
|
29
|
+
job.run(args)
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from importlib import resources
|
|
3
|
+
|
|
4
|
+
from uncountable.integration.server import IntegrationServer
|
|
5
|
+
from uncountable.integration.types import ProfileDefinition
|
|
6
|
+
from pkgs.argument_parser import CachedParser
|
|
7
|
+
from uncountable.integration.db.connect import create_db_engine
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
profile_parser = CachedParser(ProfileDefinition)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
profiles_module = os.environ["UNC_PROFILES_MODULE"]
|
|
15
|
+
with IntegrationServer(create_db_engine()) as server:
|
|
16
|
+
# TODO: Loop through all job spec yaml files and call server.add_job
|
|
17
|
+
profiles = [
|
|
18
|
+
entry
|
|
19
|
+
for entry in resources.files(profiles_module).iterdir()
|
|
20
|
+
if entry.is_dir()
|
|
21
|
+
]
|
|
22
|
+
for profile in profiles:
|
|
23
|
+
profile_name = profile.name
|
|
24
|
+
try:
|
|
25
|
+
profile = profile_parser.parse_yaml_resource(
|
|
26
|
+
package=".".join([profiles_module, profile_name]),
|
|
27
|
+
resource="profile.yaml",
|
|
28
|
+
)
|
|
29
|
+
except FileNotFoundError as e:
|
|
30
|
+
print("WARN: profile.yaml not found", e)
|
|
31
|
+
continue
|
|
32
|
+
server.register_profile(
|
|
33
|
+
profile_name=profile_name,
|
|
34
|
+
base_url=profile.base_url,
|
|
35
|
+
auth_retrieval=profile.auth_retrieval,
|
|
36
|
+
jobs=profile.jobs,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import inspect
|
|
5
|
+
from uncountable.integration.job import Job
|
|
6
|
+
from uncountable.integration.types import JobExecutorScript
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def resolve_script_executor(executor: JobExecutorScript) -> type[Job]:
|
|
10
|
+
job_module = importlib.import_module(executor.import_path)
|
|
11
|
+
found_jobs: list[type[Job]] = []
|
|
12
|
+
for _, job_class in inspect.getmembers(job_module, inspect.isclass):
|
|
13
|
+
if Job in job_class.__bases__:
|
|
14
|
+
found_jobs.append(job_class())
|
|
15
|
+
assert (
|
|
16
|
+
len(found_jobs) == 1
|
|
17
|
+
), f"expected exactly one job class in {executor.import_path}"
|
|
18
|
+
return found_jobs[0]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from uncountable.core.client import Client
|
|
3
|
+
from uncountable.integration.types import JobDefinition
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class JobArgumentsBase:
|
|
10
|
+
job_definition: JobDefinition
|
|
11
|
+
client: Client
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class CronJobArguments(JobArgumentsBase):
|
|
16
|
+
# can imagine passing additional data such as in the sftp or webhook cases
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
JobArguments = CronJobArguments
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class JobResult:
|
|
25
|
+
success: bool
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Job(ABC):
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def run(self, args: JobArguments) -> JobResult:
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CronJob(Job):
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def run(self, args: CronJobArguments) -> JobResult:
|
|
39
|
+
...
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from dataclasses import asdict
|
|
2
|
+
from typing import assert_never
|
|
3
|
+
from apscheduler.schedulers.background import BackgroundScheduler
|
|
4
|
+
from apscheduler.schedulers.base import BaseScheduler
|
|
5
|
+
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
|
|
6
|
+
from apscheduler.executors.pool import ThreadPoolExecutor
|
|
7
|
+
from uncountable.integration.cron import CronJobArgs, cron_job_executor
|
|
8
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
9
|
+
from sqlalchemy.engine.base import Engine
|
|
10
|
+
|
|
11
|
+
from uncountable.integration.types import (
|
|
12
|
+
AuthRetrieval,
|
|
13
|
+
CronJobDefinition,
|
|
14
|
+
JobDefinition,
|
|
15
|
+
ProfileMetadata,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_MAX_APSCHEDULER_CONCURRENT_JOBS = 1
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class IntegrationServer:
|
|
23
|
+
_scheduler: BaseScheduler
|
|
24
|
+
_engine: Engine
|
|
25
|
+
|
|
26
|
+
def __init__(self, engine: Engine) -> None:
|
|
27
|
+
self._engine = engine
|
|
28
|
+
self._scheduler = BackgroundScheduler(
|
|
29
|
+
timezone="UTC",
|
|
30
|
+
jobstores={"default": SQLAlchemyJobStore(engine=engine)},
|
|
31
|
+
executors={"default": ThreadPoolExecutor(_MAX_APSCHEDULER_CONCURRENT_JOBS)},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def register_profile(
|
|
35
|
+
self,
|
|
36
|
+
*,
|
|
37
|
+
profile_name: str,
|
|
38
|
+
base_url: str,
|
|
39
|
+
auth_retrieval: AuthRetrieval,
|
|
40
|
+
jobs: list[JobDefinition],
|
|
41
|
+
) -> None:
|
|
42
|
+
for job_defn in jobs:
|
|
43
|
+
profile_metadata = ProfileMetadata(
|
|
44
|
+
name=profile_name, auth_retrieval=auth_retrieval, base_url=base_url
|
|
45
|
+
)
|
|
46
|
+
match job_defn:
|
|
47
|
+
case CronJobDefinition():
|
|
48
|
+
# Add to ap scheduler
|
|
49
|
+
job_kwargs = asdict(
|
|
50
|
+
CronJobArgs(
|
|
51
|
+
definition=job_defn, profile_metadata=profile_metadata
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
existing_job = self._scheduler.get_job(job_defn.id)
|
|
55
|
+
if existing_job is not None:
|
|
56
|
+
existing_job.modify(
|
|
57
|
+
name=job_defn.name,
|
|
58
|
+
kwargs=job_kwargs,
|
|
59
|
+
)
|
|
60
|
+
existing_job.reschedule(job_defn.cron_spec)
|
|
61
|
+
else:
|
|
62
|
+
self._scheduler.add_job(
|
|
63
|
+
cron_job_executor,
|
|
64
|
+
# IMPROVE: reconsider these defaults
|
|
65
|
+
max_instances=1,
|
|
66
|
+
coalesce=True,
|
|
67
|
+
trigger=CronTrigger.from_crontab(job_defn.cron_spec),
|
|
68
|
+
name=job_defn.name,
|
|
69
|
+
id=job_defn.id,
|
|
70
|
+
kwargs=job_kwargs,
|
|
71
|
+
)
|
|
72
|
+
case _:
|
|
73
|
+
assert_never(job_defn.trigger)
|
|
74
|
+
|
|
75
|
+
def _start_apscheduler(self) -> None:
|
|
76
|
+
self._scheduler.start()
|
|
77
|
+
|
|
78
|
+
def _stop_apscheduler(self) -> None:
|
|
79
|
+
self._scheduler.shutdown()
|
|
80
|
+
|
|
81
|
+
def __enter__(self) -> "IntegrationServer":
|
|
82
|
+
self._start_apscheduler()
|
|
83
|
+
return self
|
|
84
|
+
|
|
85
|
+
def __exit__(self) -> None:
|
|
86
|
+
self._stop_apscheduler()
|