systemlink-cli 1.3.1__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.
- slcli/__init__.py +1 -0
- slcli/__main__.py +23 -0
- slcli/_version.py +4 -0
- slcli/asset_click.py +1289 -0
- slcli/cli_formatters.py +218 -0
- slcli/cli_utils.py +504 -0
- slcli/comment_click.py +602 -0
- slcli/completion_click.py +418 -0
- slcli/config.py +81 -0
- slcli/config_click.py +498 -0
- slcli/dff_click.py +979 -0
- slcli/dff_decorators.py +24 -0
- slcli/example_click.py +404 -0
- slcli/example_loader.py +274 -0
- slcli/example_provisioner.py +2777 -0
- slcli/examples/README.md +134 -0
- slcli/examples/_schema/schema-v1.0.json +169 -0
- slcli/examples/demo-complete-workflow/README.md +323 -0
- slcli/examples/demo-complete-workflow/config.yaml +638 -0
- slcli/examples/demo-test-plans/README.md +132 -0
- slcli/examples/demo-test-plans/config.yaml +154 -0
- slcli/examples/exercise-5-1-parametric-insights/README.md +101 -0
- slcli/examples/exercise-5-1-parametric-insights/config.yaml +1589 -0
- slcli/examples/exercise-7-1-test-plans/README.md +93 -0
- slcli/examples/exercise-7-1-test-plans/config.yaml +323 -0
- slcli/examples/spec-compliance-notebooks/README.md +140 -0
- slcli/examples/spec-compliance-notebooks/config.yaml +112 -0
- slcli/examples/spec-compliance-notebooks/notebooks/SpecAnalysis_ComplianceCalculation.ipynb +1553 -0
- slcli/examples/spec-compliance-notebooks/notebooks/SpecComplianceCalculation.ipynb +1577 -0
- slcli/examples/spec-compliance-notebooks/notebooks/SpecfileExtractionAndIngestion.ipynb +912 -0
- slcli/examples/spec-compliance-notebooks/spec_template.xlsx +0 -0
- slcli/feed_click.py +892 -0
- slcli/file_click.py +932 -0
- slcli/function_click.py +1400 -0
- slcli/function_templates.py +85 -0
- slcli/main.py +406 -0
- slcli/mcp_click.py +269 -0
- slcli/mcp_server.py +748 -0
- slcli/notebook_click.py +1770 -0
- slcli/platform.py +345 -0
- slcli/policy_click.py +679 -0
- slcli/policy_utils.py +411 -0
- slcli/profiles.py +411 -0
- slcli/response_handlers.py +359 -0
- slcli/routine_click.py +763 -0
- slcli/skill_click.py +253 -0
- slcli/skills/slcli/SKILL.md +713 -0
- slcli/skills/slcli/references/analysis-recipes.md +474 -0
- slcli/skills/slcli/references/filtering.md +236 -0
- slcli/skills/systemlink-webapp/SKILL.md +744 -0
- slcli/skills/systemlink-webapp/references/deployment.md +123 -0
- slcli/skills/systemlink-webapp/references/nimble-angular.md +380 -0
- slcli/skills/systemlink-webapp/references/systemlink-services.md +192 -0
- slcli/ssl_trust.py +93 -0
- slcli/system_click.py +2216 -0
- slcli/table_utils.py +124 -0
- slcli/tag_click.py +794 -0
- slcli/templates_click.py +599 -0
- slcli/testmonitor_click.py +1667 -0
- slcli/universal_handlers.py +305 -0
- slcli/user_click.py +1218 -0
- slcli/utils.py +832 -0
- slcli/web_editor.py +295 -0
- slcli/webapp_click.py +981 -0
- slcli/workflow_preview.py +287 -0
- slcli/workflows_click.py +988 -0
- slcli/workitem_click.py +2258 -0
- slcli/workspace_click.py +576 -0
- slcli/workspace_utils.py +206 -0
- systemlink_cli-1.3.1.dist-info/METADATA +20 -0
- systemlink_cli-1.3.1.dist-info/RECORD +74 -0
- systemlink_cli-1.3.1.dist-info/WHEEL +4 -0
- systemlink_cli-1.3.1.dist-info/entry_points.txt +7 -0
- systemlink_cli-1.3.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,912 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "code",
|
|
5
|
+
"execution_count": null,
|
|
6
|
+
"metadata": {},
|
|
7
|
+
"outputs": [],
|
|
8
|
+
"source": [
|
|
9
|
+
"import json\n",
|
|
10
|
+
"import math\n",
|
|
11
|
+
"import os\n",
|
|
12
|
+
"from enum import Enum\n",
|
|
13
|
+
"from http import HTTPStatus\n",
|
|
14
|
+
"from typing import Callable\n",
|
|
15
|
+
"\n",
|
|
16
|
+
"import backoff\n",
|
|
17
|
+
"import pandas as pd\n",
|
|
18
|
+
"import requests\n",
|
|
19
|
+
"import scrapbook as sb\n",
|
|
20
|
+
"from pandas import DataFrame, ExcelFile\n",
|
|
21
|
+
"from requests import Response\n",
|
|
22
|
+
"from requests.exceptions import HTTPError\n",
|
|
23
|
+
"from requests.packages.urllib3.exceptions import InsecureRequestWarning\n",
|
|
24
|
+
"\n",
|
|
25
|
+
"requests.packages.urllib3.disable_warnings(InsecureRequestWarning)"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"cell_type": "code",
|
|
30
|
+
"execution_count": null,
|
|
31
|
+
"metadata": {},
|
|
32
|
+
"outputs": [],
|
|
33
|
+
"source": [
|
|
34
|
+
"api_key = os.getenv(\"SYSTEMLINK_API_KEY\")\n",
|
|
35
|
+
"systemlink_uri = os.getenv(\"SYSTEMLINK_HTTP_URI\")"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"cell_type": "markdown",
|
|
40
|
+
"metadata": {},
|
|
41
|
+
"source": [
|
|
42
|
+
"### HTTP Status codes and constants\n"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"cell_type": "code",
|
|
47
|
+
"execution_count": null,
|
|
48
|
+
"metadata": {},
|
|
49
|
+
"outputs": [],
|
|
50
|
+
"source": [
|
|
51
|
+
"MAX_HTTP_RETRIES = 6\n",
|
|
52
|
+
"TIMEOUT_IN_SECONDS = 60\n",
|
|
53
|
+
"CREATE_SPECS_BATCH_SIZE = 1000\n",
|
|
54
|
+
"MAXIMUM_SPEC_LIMIT = 10000\n",
|
|
55
|
+
"VERIFY_SSL_CERTIFICATE = False\n",
|
|
56
|
+
"HTTP_RETRY_CODES = [\n",
|
|
57
|
+
" HTTPStatus.TOO_MANY_REQUESTS,\n",
|
|
58
|
+
" HTTPStatus.INTERNAL_SERVER_ERROR,\n",
|
|
59
|
+
" HTTPStatus.BAD_GATEWAY,\n",
|
|
60
|
+
" HTTPStatus.SERVICE_UNAVAILABLE,\n",
|
|
61
|
+
" HTTPStatus.GATEWAY_TIMEOUT\n",
|
|
62
|
+
"]"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"cell_type": "markdown",
|
|
67
|
+
"metadata": {},
|
|
68
|
+
"source": [
|
|
69
|
+
"### HTTP Routes\n"
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"cell_type": "code",
|
|
74
|
+
"execution_count": null,
|
|
75
|
+
"metadata": {},
|
|
76
|
+
"outputs": [],
|
|
77
|
+
"source": [
|
|
78
|
+
"class HttpRouteConstants:\n",
|
|
79
|
+
" TM_BASE_ROUTE = \"/nitestmonitor\"\n",
|
|
80
|
+
" POST_QUERY_PRODUCTS = \"/v2/query-products\"\n",
|
|
81
|
+
" FILE_BASE_ROUTE = \"/nifile\"\n",
|
|
82
|
+
" AVAILABLE_FILES_ROUTE = \"/v1/service-groups/Default/files\"\n",
|
|
83
|
+
" SPECS_BASE_ROUTE = \"/nispec/v1\"\n",
|
|
84
|
+
" CREATE_SPECS_ROUTE = \"/specs\"\n",
|
|
85
|
+
" DELETE_SPECS_ROUTE = \"/delete-specs\"\n",
|
|
86
|
+
" QUERY_SPECS_ROUTE = \"/query-specs\""
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"cell_type": "markdown",
|
|
91
|
+
"metadata": {},
|
|
92
|
+
"source": [
|
|
93
|
+
"### Error Messages\n"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"cell_type": "code",
|
|
98
|
+
"execution_count": null,
|
|
99
|
+
"metadata": {},
|
|
100
|
+
"outputs": [],
|
|
101
|
+
"source": [
|
|
102
|
+
"class ErrorMessages:\n",
|
|
103
|
+
" EMPTY_SPEC_ID = \"Spec ID cannot be empty\"\n",
|
|
104
|
+
" EMPTY_TYPE = \"Spec Type cannot be empty\"\n",
|
|
105
|
+
" EMPTY_PRODUCT_ID = \"Product ID cannot be empty\"\n",
|
|
106
|
+
" MULTIPLE_NOTEBOOKS_SELECTED = \"This notebook is designed to operate on one file at a time\"\n",
|
|
107
|
+
" WRONG_FILE_EXTENSION = \"File extension is not xlsx\"\n",
|
|
108
|
+
" MAXIMUM_SPEC_INGESTION_LIMIT = (f\"Notebook only supports extraction and ingestion of {MAXIMUM_SPEC_LIMIT} specs\")\n",
|
|
109
|
+
" CONDITION_EXTRACTION_ERROR = \"Error when extracting condition\""
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"cell_type": "markdown",
|
|
114
|
+
"metadata": {},
|
|
115
|
+
"source": [
|
|
116
|
+
"### Input Parameters\n"
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"cell_type": "code",
|
|
121
|
+
"execution_count": null,
|
|
122
|
+
"metadata": {
|
|
123
|
+
"papermill": {
|
|
124
|
+
"parameters": {
|
|
125
|
+
"file_ids": [],
|
|
126
|
+
"product_ids": []
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"systemlink": {
|
|
130
|
+
"namespaces": [],
|
|
131
|
+
"parameters": [
|
|
132
|
+
{
|
|
133
|
+
"display_name": "file_ids",
|
|
134
|
+
"id": "file_ids",
|
|
135
|
+
"type": "string[]"
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
"version": 2
|
|
139
|
+
},
|
|
140
|
+
"tags": [
|
|
141
|
+
"parameters"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
"outputs": [],
|
|
145
|
+
"source": [
|
|
146
|
+
"file_ids = [\"\"]"
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"cell_type": "markdown",
|
|
151
|
+
"metadata": {},
|
|
152
|
+
"source": [
|
|
153
|
+
"### API URL's\n"
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"cell_type": "code",
|
|
158
|
+
"execution_count": null,
|
|
159
|
+
"metadata": {},
|
|
160
|
+
"outputs": [],
|
|
161
|
+
"source": [
|
|
162
|
+
"delete_spec_url = f\"{systemlink_uri}{HttpRouteConstants.SPECS_BASE_ROUTE}{HttpRouteConstants.DELETE_SPECS_ROUTE}\"\n",
|
|
163
|
+
"create_spec_url = f\"{systemlink_uri}{HttpRouteConstants.SPECS_BASE_ROUTE}{HttpRouteConstants.CREATE_SPECS_ROUTE}\"\n",
|
|
164
|
+
"query_spec_url = f\"{systemlink_uri}{HttpRouteConstants.SPECS_BASE_ROUTE}{HttpRouteConstants.QUERY_SPECS_ROUTE}\"\n",
|
|
165
|
+
"query_products_url = f\"{systemlink_uri}{HttpRouteConstants.TM_BASE_ROUTE}{HttpRouteConstants.POST_QUERY_PRODUCTS}\""
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"cell_type": "markdown",
|
|
170
|
+
"metadata": {},
|
|
171
|
+
"source": [
|
|
172
|
+
"### API Utility functions\n"
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"cell_type": "code",
|
|
177
|
+
"execution_count": null,
|
|
178
|
+
"metadata": {},
|
|
179
|
+
"outputs": [],
|
|
180
|
+
"source": [
|
|
181
|
+
"@backoff.on_exception(backoff.expo, HTTPError, max_tries=MAX_HTTP_RETRIES, giveup=lambda e: e.response.status_code not in HTTP_RETRY_CODES)\n",
|
|
182
|
+
"def retry_request(callable_function: Callable) -> Response:\n",
|
|
183
|
+
" response = callable_function()\n",
|
|
184
|
+
" response.raise_for_status()\n",
|
|
185
|
+
"\n",
|
|
186
|
+
" return response\n",
|
|
187
|
+
"\n",
|
|
188
|
+
"\n",
|
|
189
|
+
"def create_get_request(url: str, headers: object = {}) -> Response:\n",
|
|
190
|
+
" default_headers = {'x-ni-api-key': api_key}\n",
|
|
191
|
+
" headers = {**default_headers, **headers}\n",
|
|
192
|
+
"\n",
|
|
193
|
+
" return retry_request(lambda: requests.get(url, headers=headers, verify=VERIFY_SSL_CERTIFICATE, timeout=TIMEOUT_IN_SECONDS))\n",
|
|
194
|
+
"\n",
|
|
195
|
+
"\n",
|
|
196
|
+
"def create_post_request(url: str, body, headers: object = {}) -> Response:\n",
|
|
197
|
+
" default_headers = {\n",
|
|
198
|
+
" \"accept\": \"application/json\",\n",
|
|
199
|
+
" \"Content-Type\": \"application/json\",\n",
|
|
200
|
+
" \"x-ni-api-key\": api_key,\n",
|
|
201
|
+
" }\n",
|
|
202
|
+
" headers = {**default_headers, **headers}\n",
|
|
203
|
+
"\n",
|
|
204
|
+
" return retry_request(lambda: requests.post(url, data=body, headers=headers, verify=VERIFY_SSL_CERTIFICATE, timeout=TIMEOUT_IN_SECONDS))"
|
|
205
|
+
]
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"cell_type": "markdown",
|
|
209
|
+
"metadata": {},
|
|
210
|
+
"source": [
|
|
211
|
+
"### Constants"
|
|
212
|
+
]
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"cell_type": "code",
|
|
216
|
+
"execution_count": null,
|
|
217
|
+
"metadata": {},
|
|
218
|
+
"outputs": [],
|
|
219
|
+
"source": [
|
|
220
|
+
"TEMPLATE_SHEET = \"SpecTemplate\"\n",
|
|
221
|
+
"SPEC_FILE_MAPPING = {\n",
|
|
222
|
+
" \"Spec ID\": \"specId\",\n",
|
|
223
|
+
" \"Category\": \"category\",\n",
|
|
224
|
+
" \"Block\": \"block\",\n",
|
|
225
|
+
" \"Spec Symbol\": \"symbol\",\n",
|
|
226
|
+
" \"Spec Name\": \"name\",\n",
|
|
227
|
+
" \"Min\": \"min\",\n",
|
|
228
|
+
" \"Typical\": \"typical\",\n",
|
|
229
|
+
" \"Max\": \"max\",\n",
|
|
230
|
+
" \"Unit\": \"unit\",\n",
|
|
231
|
+
"}\n",
|
|
232
|
+
"\n",
|
|
233
|
+
"\n",
|
|
234
|
+
"class ColumnTypes(Enum):\n",
|
|
235
|
+
" STD = \"STD\"\n",
|
|
236
|
+
" COND = \"COND\"\n",
|
|
237
|
+
" INF = \"INF\"\n",
|
|
238
|
+
"\n",
|
|
239
|
+
"\n",
|
|
240
|
+
"class SpecDataKeys:\n",
|
|
241
|
+
" SPEC_ID = \"specId\"\n",
|
|
242
|
+
" PRODUCT_ID = \"productId\"\n",
|
|
243
|
+
" NAME = \"name\"\n",
|
|
244
|
+
" CATEGORY = \"category\"\n",
|
|
245
|
+
" TYPE = \"type\"\n",
|
|
246
|
+
" SYMBOL = \"symbol\"\n",
|
|
247
|
+
" BLOCK = \"block\"\n",
|
|
248
|
+
" UNIT = \"unit\"\n",
|
|
249
|
+
" LIMIT = \"limit\"\n",
|
|
250
|
+
" CONDITIONS = \"conditions\"\n",
|
|
251
|
+
" WORKSPACE = \"workspace\"\n",
|
|
252
|
+
" PROPERTIES = \"properties\"\n",
|
|
253
|
+
"\n",
|
|
254
|
+
"\n",
|
|
255
|
+
"class SpecLimitKeys:\n",
|
|
256
|
+
" MIN = \"min\"\n",
|
|
257
|
+
" MAX = \"max\"\n",
|
|
258
|
+
" TYPICAL = \"typical\"\n",
|
|
259
|
+
"\n",
|
|
260
|
+
"\n",
|
|
261
|
+
"class SpecConditionKeys:\n",
|
|
262
|
+
" CONDITION_TYPE = \"conditionType\"\n",
|
|
263
|
+
" NAME = \"name\"\n",
|
|
264
|
+
" VALUE = \"value\"\n",
|
|
265
|
+
" DISCRETE = \"discrete\"\n",
|
|
266
|
+
" RANGE = \"range\"\n",
|
|
267
|
+
" MIN = \"min\"\n",
|
|
268
|
+
" MAX = \"max\"\n",
|
|
269
|
+
" UNIT = \"unit\"\n",
|
|
270
|
+
"\n",
|
|
271
|
+
"\n",
|
|
272
|
+
"class SpecConditionTypeValues:\n",
|
|
273
|
+
" STRING = \"STRING\"\n",
|
|
274
|
+
" NUMERIC = \"NUMERIC\"\n",
|
|
275
|
+
"\n",
|
|
276
|
+
"\n",
|
|
277
|
+
"class SpecType:\n",
|
|
278
|
+
" PARAMETRIC = \"parametric\"\n",
|
|
279
|
+
" FUNCTIONAL = \"functional\"\n",
|
|
280
|
+
"\n",
|
|
281
|
+
"\n",
|
|
282
|
+
"class ApiBodyKeys:\n",
|
|
283
|
+
" PRODUCT_IDS = \"productIds\"\n",
|
|
284
|
+
" TAKE = \"take\"\n",
|
|
285
|
+
" IDS = \"ids\"\n",
|
|
286
|
+
" SPECS = \"specs\"\n",
|
|
287
|
+
" FILTER = \"filter\"\n",
|
|
288
|
+
" FILE_IDS = \"fileIds\"\n",
|
|
289
|
+
" CONTAINS = \"Contains\"\n",
|
|
290
|
+
"\n",
|
|
291
|
+
"\n",
|
|
292
|
+
"class ApiResponseKeys:\n",
|
|
293
|
+
" ID = \"id\"\n",
|
|
294
|
+
" ERROR = \"error\"\n",
|
|
295
|
+
" SPEC_ID = \"specId\"\n",
|
|
296
|
+
" SPECS = \"specs\"\n",
|
|
297
|
+
" CREATED_SPECS = \"createdSpecs\"\n",
|
|
298
|
+
" AVAILABLE_FILES = \"availableFiles\"\n",
|
|
299
|
+
" WORKSPACE = \"workspace\"\n",
|
|
300
|
+
" PRODUCTS = \"products\""
|
|
301
|
+
]
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"cell_type": "markdown",
|
|
305
|
+
"metadata": {},
|
|
306
|
+
"source": [
|
|
307
|
+
"### Get File content and write into a file\n"
|
|
308
|
+
]
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"cell_type": "code",
|
|
312
|
+
"execution_count": null,
|
|
313
|
+
"metadata": {},
|
|
314
|
+
"outputs": [],
|
|
315
|
+
"source": [
|
|
316
|
+
"def get_file_content(file_id: str):\n",
|
|
317
|
+
" download_file_url = f\"{systemlink_uri}{HttpRouteConstants.FILE_BASE_ROUTE}{HttpRouteConstants.AVAILABLE_FILES_ROUTE}/{file_id}/data\"\n",
|
|
318
|
+
"\n",
|
|
319
|
+
" headers = {'X-NI-API-KEY': api_key}\n",
|
|
320
|
+
" download_resp = create_get_request(\n",
|
|
321
|
+
" download_file_url,\n",
|
|
322
|
+
" headers\n",
|
|
323
|
+
" )\n",
|
|
324
|
+
"\n",
|
|
325
|
+
" download_resp.raise_for_status()\n",
|
|
326
|
+
"\n",
|
|
327
|
+
" return download_resp"
|
|
328
|
+
]
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"cell_type": "code",
|
|
332
|
+
"execution_count": null,
|
|
333
|
+
"metadata": {},
|
|
334
|
+
"outputs": [],
|
|
335
|
+
"source": [
|
|
336
|
+
"def write_file_content_into_file(response: Response | None):\n",
|
|
337
|
+
" filename = response.headers['content-disposition'].split('\"')[1::-1][0]\n",
|
|
338
|
+
" file_extension = response.headers['content-disposition'].split('\"')[1::-1][0].split(\".\")[-1]\n",
|
|
339
|
+
"\n",
|
|
340
|
+
" if (file_extension != 'xlsx'):\n",
|
|
341
|
+
" raise Exception(ErrorMessages.WRONG_FILE_EXTENSION)\n",
|
|
342
|
+
"\n",
|
|
343
|
+
" with open(filename, 'wb') as file:\n",
|
|
344
|
+
" file.write(response.content)\n",
|
|
345
|
+
"\n",
|
|
346
|
+
" return filename"
|
|
347
|
+
]
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"cell_type": "code",
|
|
351
|
+
"execution_count": null,
|
|
352
|
+
"metadata": {},
|
|
353
|
+
"outputs": [],
|
|
354
|
+
"source": [
|
|
355
|
+
"if len(file_ids) != 1:\n",
|
|
356
|
+
" raise Exception(ErrorMessages.MULTIPLE_NOTEBOOKS_SELECTED)\n",
|
|
357
|
+
"\n",
|
|
358
|
+
"file_id = file_ids[0]\n",
|
|
359
|
+
"\n",
|
|
360
|
+
"file_content_response = get_file_content(file_id)\n",
|
|
361
|
+
"\n",
|
|
362
|
+
"filename = write_file_content_into_file(file_content_response)"
|
|
363
|
+
]
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"cell_type": "markdown",
|
|
367
|
+
"metadata": {},
|
|
368
|
+
"source": [
|
|
369
|
+
"### Get Workspace ID for the file\n"
|
|
370
|
+
]
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"cell_type": "code",
|
|
374
|
+
"execution_count": null,
|
|
375
|
+
"metadata": {},
|
|
376
|
+
"outputs": [],
|
|
377
|
+
"source": [
|
|
378
|
+
"def get_workspace_id(file_id: str):\n",
|
|
379
|
+
" get_file_properties_url = f\"{systemlink_uri}{HttpRouteConstants.FILE_BASE_ROUTE}{HttpRouteConstants.AVAILABLE_FILES_ROUTE}?id={file_id}\"\n",
|
|
380
|
+
" resp_json = create_get_request(get_file_properties_url)\n",
|
|
381
|
+
" resp = resp_json.json()\n",
|
|
382
|
+
" workspace_id = resp[ApiResponseKeys.AVAILABLE_FILES][0][ApiResponseKeys.WORKSPACE]\n",
|
|
383
|
+
" return str(workspace_id)"
|
|
384
|
+
]
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"cell_type": "markdown",
|
|
388
|
+
"metadata": {},
|
|
389
|
+
"source": [
|
|
390
|
+
"### Get Product ID from File ID\n"
|
|
391
|
+
]
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
"cell_type": "code",
|
|
395
|
+
"execution_count": null,
|
|
396
|
+
"metadata": {},
|
|
397
|
+
"outputs": [],
|
|
398
|
+
"source": [
|
|
399
|
+
"def get_product_id_for_file(file_id: str):\n",
|
|
400
|
+
" body = {ApiBodyKeys.FILTER: f'{ApiBodyKeys.FILE_IDS}.{ApiBodyKeys.CONTAINS}(\"{file_id}\")'}\n",
|
|
401
|
+
" payload = json.dumps(body)\n",
|
|
402
|
+
" resp_json = create_post_request(query_products_url, payload)\n",
|
|
403
|
+
" resp = resp_json.json()\n",
|
|
404
|
+
" product_id = resp[ApiResponseKeys.PRODUCTS][0][ApiResponseKeys.ID]\n",
|
|
405
|
+
" return str(product_id)"
|
|
406
|
+
]
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
"cell_type": "code",
|
|
410
|
+
"execution_count": null,
|
|
411
|
+
"metadata": {},
|
|
412
|
+
"outputs": [],
|
|
413
|
+
"source": [
|
|
414
|
+
"product_id = get_product_id_for_file(file_id)\n",
|
|
415
|
+
"workspace_id = get_workspace_id(file_id)"
|
|
416
|
+
]
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"cell_type": "markdown",
|
|
420
|
+
"metadata": {},
|
|
421
|
+
"source": [
|
|
422
|
+
"### Spec extraction utility functions\n"
|
|
423
|
+
]
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"cell_type": "code",
|
|
427
|
+
"execution_count": null,
|
|
428
|
+
"metadata": {},
|
|
429
|
+
"outputs": [],
|
|
430
|
+
"source": [
|
|
431
|
+
"def process_condition_values(input_string: str, unit: str | None, sheet_name: str, column, row):\n",
|
|
432
|
+
" try:\n",
|
|
433
|
+
" if input_string is not None:\n",
|
|
434
|
+
" input_string = input_string.strip()\n",
|
|
435
|
+
"\n",
|
|
436
|
+
" if not input_string:\n",
|
|
437
|
+
" return None\n",
|
|
438
|
+
"\n",
|
|
439
|
+
" if input_string.startswith('[') and input_string.endswith(']'):\n",
|
|
440
|
+
" input_string = input_string[1:-1]\n",
|
|
441
|
+
" discrete = []\n",
|
|
442
|
+
" range_min = None\n",
|
|
443
|
+
" range_max = None\n",
|
|
444
|
+
"\n",
|
|
445
|
+
" if '..' in input_string:\n",
|
|
446
|
+
" values = input_string.split('..')\n",
|
|
447
|
+
"\n",
|
|
448
|
+
" if (values[0] == '' or values[-1] == ''):\n",
|
|
449
|
+
" if (values[0] == ''):\n",
|
|
450
|
+
" range_max = float(values[-1])\n",
|
|
451
|
+
" elif (values[-1] == ''):\n",
|
|
452
|
+
" range_min = float(values[0])\n",
|
|
453
|
+
" if (len(values) >= 3):\n",
|
|
454
|
+
" for index, value in enumerate(values):\n",
|
|
455
|
+
" if index != 0 and index != len(values)-1:\n",
|
|
456
|
+
" discrete.append(float(value))\n",
|
|
457
|
+
" else:\n",
|
|
458
|
+
" range_min = float(values[0])\n",
|
|
459
|
+
" range_max = float(values[-1])\n",
|
|
460
|
+
"\n",
|
|
461
|
+
" if (len(values) >= 3):\n",
|
|
462
|
+
" for index, value in enumerate(values):\n",
|
|
463
|
+
" if index != 0 and index != len(values)-1:\n",
|
|
464
|
+
" discrete.append(float(value))\n",
|
|
465
|
+
" return {\n",
|
|
466
|
+
" SpecConditionKeys.CONDITION_TYPE: SpecConditionTypeValues.NUMERIC,\n",
|
|
467
|
+
" SpecConditionKeys.DISCRETE: discrete,\n",
|
|
468
|
+
" SpecConditionKeys.RANGE: [\n",
|
|
469
|
+
" {\n",
|
|
470
|
+
" SpecConditionKeys.MIN: range_min,\n",
|
|
471
|
+
" SpecConditionKeys.MAX: range_max\n",
|
|
472
|
+
" }\n",
|
|
473
|
+
" ],\n",
|
|
474
|
+
" SpecConditionKeys.UNIT: unit\n",
|
|
475
|
+
" }\n",
|
|
476
|
+
"\n",
|
|
477
|
+
" else:\n",
|
|
478
|
+
" if ',' in input_string:\n",
|
|
479
|
+
" discrete = [float(value)\n",
|
|
480
|
+
" for value in input_string.split(',')]\n",
|
|
481
|
+
" else:\n",
|
|
482
|
+
" discrete = [float(input_string)]\n",
|
|
483
|
+
" return {\n",
|
|
484
|
+
" SpecConditionKeys.CONDITION_TYPE: SpecConditionTypeValues.NUMERIC,\n",
|
|
485
|
+
" SpecConditionKeys.DISCRETE: discrete,\n",
|
|
486
|
+
" SpecConditionKeys.UNIT: unit\n",
|
|
487
|
+
" }\n",
|
|
488
|
+
" elif (not (input_string.startswith('[') and input_string.endswith(']'))):\n",
|
|
489
|
+
" discrete = [str(value).strip() for value in input_string.split(',')]\n",
|
|
490
|
+
" return {\n",
|
|
491
|
+
" SpecConditionKeys.CONDITION_TYPE: SpecConditionTypeValues.STRING,\n",
|
|
492
|
+
" SpecConditionKeys.DISCRETE: discrete\n",
|
|
493
|
+
" }\n",
|
|
494
|
+
" else:\n",
|
|
495
|
+
" return None\n",
|
|
496
|
+
" except Exception:\n",
|
|
497
|
+
" raise SystemExit(\n",
|
|
498
|
+
" f\"{ErrorMessages.CONDITION_EXTRACTION_ERROR} in {sheet_name}, {column}, row {row}\")\n",
|
|
499
|
+
"\n",
|
|
500
|
+
"\n",
|
|
501
|
+
"def extract_condition_unit(input_string: str):\n",
|
|
502
|
+
" start = input_string.find('(')\n",
|
|
503
|
+
" end = input_string.find(')')\n",
|
|
504
|
+
" if start != -1 and end != -1 and start < end:\n",
|
|
505
|
+
" return input_string[start+1:end]\n",
|
|
506
|
+
" else:\n",
|
|
507
|
+
" return None\n",
|
|
508
|
+
"\n",
|
|
509
|
+
"\n",
|
|
510
|
+
"def validate_column_types(df_type: pd.DataFrame, sheet_name: str):\n",
|
|
511
|
+
" for idx, col in enumerate(df_type.columns):\n",
|
|
512
|
+
" if (idx == 0):\n",
|
|
513
|
+
" continue\n",
|
|
514
|
+
" if isinstance(df_type.at[0, col], str):\n",
|
|
515
|
+
" col_value = df_type.at[0, col].upper()\n",
|
|
516
|
+
" else:\n",
|
|
517
|
+
" raise Exception(\n",
|
|
518
|
+
" f\"Column '{col}' Name cannot be empty in {sheet_name}\")\n",
|
|
519
|
+
" if col_value not in [column_types.value for column_types in ColumnTypes]:\n",
|
|
520
|
+
" raise Exception(f\"Column '{col}' has an invalid value: '{col_value}'. \"\n",
|
|
521
|
+
" f\"Allowed values are: {', '.join(column_type.value for column_type in ColumnTypes)}\")\n",
|
|
522
|
+
"\n",
|
|
523
|
+
" for idx, col in enumerate(df_type.columns):\n",
|
|
524
|
+
" col_value = df_type.at[1, col]\n",
|
|
525
|
+
" if (idx == 0):\n",
|
|
526
|
+
" continue\n",
|
|
527
|
+
" if isinstance(df_type.at[1, col], str):\n",
|
|
528
|
+
" if (col_value in dict.fromkeys(SPEC_FILE_MAPPING) and df_type.at[0, col].upper() != ColumnTypes.STD.value):\n",
|
|
529
|
+
" raise Exception(f\"Column '{col_value}' should be {ColumnTypes.STD.value} type, \"\n",
|
|
530
|
+
" f\"instead it is {df_type.at[0, col].upper()} type in {sheet_name}\")\n",
|
|
531
|
+
" if (col_value not in dict.fromkeys(SPEC_FILE_MAPPING) and df_type.at[0, col].upper() == ColumnTypes.STD.value):\n",
|
|
532
|
+
" raise Exception(f\"Column '{col}' has an invalid value: '{col_value}' in {sheet_name}. \"\n",
|
|
533
|
+
" f\"Allowed values for STD columns are: {', '.join(SPEC_FILE_MAPPING.keys())}\")\n",
|
|
534
|
+
" else:\n",
|
|
535
|
+
" raise Exception(\n",
|
|
536
|
+
" f\"Column '{col}' Name cannot be empty in {sheet_name}\")\n",
|
|
537
|
+
"\n",
|
|
538
|
+
"\n",
|
|
539
|
+
"def seperate_column_types(df_type: DataFrame):\n",
|
|
540
|
+
" \"\"\"Separate columns by type and return their header names for use with pandas usecols.\"\"\"\n",
|
|
541
|
+
" standard_columns = [\n",
|
|
542
|
+
" df_type.iloc[1, idx] for idx, col in enumerate(df_type.columns) if df_type.at[0, col].upper() == ColumnTypes.STD.value]\n",
|
|
543
|
+
" condition_columns = [\n",
|
|
544
|
+
" df_type.iloc[1, idx] for idx, col in enumerate(df_type.columns) if df_type.at[0, col].upper() == ColumnTypes.COND.value]\n",
|
|
545
|
+
" property_columns = [\n",
|
|
546
|
+
" df_type.iloc[1, idx] for idx, col in enumerate(df_type.columns) if df_type.at[0, col].upper() == ColumnTypes.INF.value]\n",
|
|
547
|
+
"\n",
|
|
548
|
+
" return standard_columns, condition_columns, property_columns\n",
|
|
549
|
+
"\n",
|
|
550
|
+
"\n",
|
|
551
|
+
"def extract_column_names(df_type: DataFrame, column_names: list[str]):\n",
|
|
552
|
+
" \"\"\"Extract unique column names from the list.\"\"\"\n",
|
|
553
|
+
" column_names = list(dict.fromkeys(column_names))\n",
|
|
554
|
+
" return column_names\n",
|
|
555
|
+
"\n",
|
|
556
|
+
"\n",
|
|
557
|
+
"def construct_dataframe_for_column_type(excel_file: ExcelFile, sheet_name: str, column_info, column_type: str):\n",
|
|
558
|
+
" \"\"\"Construct dataframe for a specific column type using actual column header names.\"\"\"\n",
|
|
559
|
+
" column_names = column_info[sheet_name][f\"{column_type}\"]\n",
|
|
560
|
+
" if not column_names:\n",
|
|
561
|
+
" # Return empty dataframe if no columns of this type\n",
|
|
562
|
+
" return pd.DataFrame()\n",
|
|
563
|
+
" \n",
|
|
564
|
+
" # Use actual column names (which become the headers when header=3)\n",
|
|
565
|
+
" data_frame = excel_file.parse(\n",
|
|
566
|
+
" sheet_name,\n",
|
|
567
|
+
" header=3,\n",
|
|
568
|
+
" usecols=column_names,\n",
|
|
569
|
+
" dtype=str,\n",
|
|
570
|
+
" keep_default_na=False\n",
|
|
571
|
+
" ).rename(columns=SPEC_FILE_MAPPING).replace('', None)\n",
|
|
572
|
+
"\n",
|
|
573
|
+
" return data_frame\n",
|
|
574
|
+
"\n",
|
|
575
|
+
"\n",
|
|
576
|
+
"def seperate_columns(excel_file: ExcelFile, sheet_names: list):\n",
|
|
577
|
+
" column_info = {}\n",
|
|
578
|
+
" for sheet_name in sheet_names:\n",
|
|
579
|
+
" data_frame = excel_file.parse(sheet_name, skiprows=2, nrows=2, header=None, dtype=object)\n",
|
|
580
|
+
" standard_columns, condition_columns, property_columns = seperate_column_types(data_frame)\n",
|
|
581
|
+
"\n",
|
|
582
|
+
" column_info.update({\n",
|
|
583
|
+
" sheet_name: {\n",
|
|
584
|
+
" ColumnTypes.STD.value: standard_columns,\n",
|
|
585
|
+
" ColumnTypes.COND.value: condition_columns,\n",
|
|
586
|
+
" ColumnTypes.INF.value: property_columns\n",
|
|
587
|
+
" }\n",
|
|
588
|
+
" })\n",
|
|
589
|
+
"\n",
|
|
590
|
+
" return column_info, standard_columns, condition_columns, property_columns\n",
|
|
591
|
+
"\n",
|
|
592
|
+
"\n",
|
|
593
|
+
"def validate_spec_count(excel_file: ExcelFile, sheet_names: list):\n",
|
|
594
|
+
" total_specs = 0\n",
|
|
595
|
+
"\n",
|
|
596
|
+
" for sheet_name in sheet_names:\n",
|
|
597
|
+
" data_frame = excel_file.parse(sheet_name, header=3)\n",
|
|
598
|
+
" total_specs += len(data_frame)\n",
|
|
599
|
+
"\n",
|
|
600
|
+
" if (total_specs > 10000):\n",
|
|
601
|
+
" raise Exception(f\"{ErrorMessages.MAXIMUM_SPEC_INGESTION_LIMIT}, total specs in the excel file is {total_specs}\")"
|
|
602
|
+
]
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
"cell_type": "code",
|
|
606
|
+
"execution_count": null,
|
|
607
|
+
"metadata": {},
|
|
608
|
+
"outputs": [],
|
|
609
|
+
"source": [
|
|
610
|
+
"def generate_base_spec_data(df_type: DataFrame, sheet_name: str, category: str, type: str):\n",
|
|
611
|
+
" specs = []\n",
|
|
612
|
+
" for idx, spec_row in enumerate(df_type.to_dict(\"records\")):\n",
|
|
613
|
+
" if not product_id:\n",
|
|
614
|
+
" raise Exception(ErrorMessages.EMPTY_PRODUCT_ID)\n",
|
|
615
|
+
" if not spec_row.get(SpecDataKeys.SPEC_ID):\n",
|
|
616
|
+
" raise Exception(\n",
|
|
617
|
+
" f\"{ErrorMessages.EMPTY_SPEC_ID} in {sheet_name} in row {idx}\")\n",
|
|
618
|
+
" if isinstance(type, str):\n",
|
|
619
|
+
" pass\n",
|
|
620
|
+
" elif (math.isnan(type)):\n",
|
|
621
|
+
" raise Exception(f\"{ErrorMessages.EMPTY_TYPE} in {sheet_name}\")\n",
|
|
622
|
+
" spec_data = {\n",
|
|
623
|
+
" SpecDataKeys.PRODUCT_ID: product_id,\n",
|
|
624
|
+
" SpecDataKeys.SPEC_ID: spec_row.get(SpecDataKeys.SPEC_ID),\n",
|
|
625
|
+
" SpecDataKeys.NAME: spec_row.get(SpecDataKeys.NAME) if isinstance(spec_row.get(SpecDataKeys.NAME), str) else None,\n",
|
|
626
|
+
" SpecDataKeys.CATEGORY: category if isinstance(category, str) else None,\n",
|
|
627
|
+
" SpecDataKeys.TYPE: type,\n",
|
|
628
|
+
" SpecDataKeys.SYMBOL: spec_row.get(SpecDataKeys.SYMBOL) if isinstance(spec_row.get(SpecDataKeys.SYMBOL), str) else None,\n",
|
|
629
|
+
" SpecDataKeys.BLOCK: spec_row.get(SpecDataKeys.BLOCK) if isinstance(spec_row.get(SpecDataKeys.BLOCK), str) else None,\n",
|
|
630
|
+
" SpecDataKeys.UNIT: spec_row.get(SpecDataKeys.UNIT) if isinstance(spec_row.get(SpecDataKeys.UNIT), str) else None,\n",
|
|
631
|
+
" SpecDataKeys.CONDITIONS: [],\n",
|
|
632
|
+
" SpecDataKeys.WORKSPACE: workspace_id if workspace_id else None\n",
|
|
633
|
+
" }\n",
|
|
634
|
+
" if type.lower() == SpecType.PARAMETRIC:\n",
|
|
635
|
+
" try:\n",
|
|
636
|
+
" spec_data[SpecDataKeys.LIMIT] = {\n",
|
|
637
|
+
" SpecLimitKeys.MIN: float(spec_row.get(SpecLimitKeys.MIN)) if spec_row.get(SpecLimitKeys.MIN) else None,\n",
|
|
638
|
+
" SpecLimitKeys.MAX: float(spec_row.get(SpecLimitKeys.MAX)) if spec_row.get(SpecLimitKeys.MAX) else None,\n",
|
|
639
|
+
" SpecLimitKeys.TYPICAL: float(spec_row.get(SpecLimitKeys.TYPICAL)) if spec_row.get(SpecLimitKeys.TYPICAL) else None\n",
|
|
640
|
+
" }\n",
|
|
641
|
+
" except ValueError as e:\n",
|
|
642
|
+
" raise Exception(\n",
|
|
643
|
+
" f\"Invalid numeric value in {sheet_name} row {idx + 1}. \"\n",
|
|
644
|
+
" f\"Min, Max, and Typical columns must contain valid numbers. \"\n",
|
|
645
|
+
" f\"Error: {str(e)}\")\n",
|
|
646
|
+
" specs.append(spec_data)\n",
|
|
647
|
+
" return specs"
|
|
648
|
+
]
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"cell_type": "code",
|
|
652
|
+
"execution_count": null,
|
|
653
|
+
"metadata": {},
|
|
654
|
+
"outputs": [],
|
|
655
|
+
"source": [
|
|
656
|
+
"def generate_spec_conditions(df_type: DataFrame, column_names: list, sheet_name: str, specs: list, index: int):\n",
|
|
657
|
+
" for idx, row in enumerate(df_type.to_dict(\"records\")):\n",
|
|
658
|
+
" for column in column_names:\n",
|
|
659
|
+
" if (row.get(column)):\n",
|
|
660
|
+
" condition = {}\n",
|
|
661
|
+
" condition[SpecConditionKeys.NAME] = column.split('(')[0].strip()\n",
|
|
662
|
+
" unit = extract_condition_unit(column)\n",
|
|
663
|
+
" condition[SpecConditionKeys.VALUE] = process_condition_values(\n",
|
|
664
|
+
" row[str(column)], unit, sheet_name, column, idx)\n",
|
|
665
|
+
" specs[index][SpecDataKeys.CONDITIONS].append(condition)\n",
|
|
666
|
+
" index = index + 1"
|
|
667
|
+
]
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
"cell_type": "code",
|
|
671
|
+
"execution_count": null,
|
|
672
|
+
"metadata": {},
|
|
673
|
+
"outputs": [],
|
|
674
|
+
"source": [
|
|
675
|
+
"def generate_spec_properties(df_type: DataFrame, column_names: list, specs: list, index: int):\n",
|
|
676
|
+
" for row in df_type.to_dict(\"records\"):\n",
|
|
677
|
+
" property = {column: row.get(str(column)) for column in column_names if row.get(str(column)) is not None}\n",
|
|
678
|
+
" if property:\n",
|
|
679
|
+
" specs[index][SpecDataKeys.PROPERTIES] = property\n",
|
|
680
|
+
" index = index + 1"
|
|
681
|
+
]
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
"cell_type": "markdown",
|
|
685
|
+
"metadata": {},
|
|
686
|
+
"source": [
|
|
687
|
+
"### SCM Template to SLE Format extraction logic\n"
|
|
688
|
+
]
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
"cell_type": "code",
|
|
692
|
+
"execution_count": null,
|
|
693
|
+
"metadata": {},
|
|
694
|
+
"outputs": [],
|
|
695
|
+
"source": [
|
|
696
|
+
"def generate_spec_data():\n",
|
|
697
|
+
"\n",
|
|
698
|
+
" xl = pd.ExcelFile(filename)\n",
|
|
699
|
+
" sheet_names = [\n",
|
|
700
|
+
" sheet_name for sheet_name in xl.sheet_names if sheet_name != TEMPLATE_SHEET\n",
|
|
701
|
+
" ]\n",
|
|
702
|
+
" column_info = {}\n",
|
|
703
|
+
" specs = []\n",
|
|
704
|
+
" index = 0\n",
|
|
705
|
+
"\n",
|
|
706
|
+
" validate_spec_count(xl, sheet_names)\n",
|
|
707
|
+
"\n",
|
|
708
|
+
" # Construct dataframe and generate specs\n",
|
|
709
|
+
" for sheet_name in sheet_names:\n",
|
|
710
|
+
"\n",
|
|
711
|
+
" df_type = xl.parse(sheet_name, skiprows=2, nrows=2, header=None, dtype=object)\n",
|
|
712
|
+
"\n",
|
|
713
|
+
" if (df_type.empty):\n",
|
|
714
|
+
" continue\n",
|
|
715
|
+
"\n",
|
|
716
|
+
" validate_column_types(df_type, sheet_name)\n",
|
|
717
|
+
"\n",
|
|
718
|
+
" standard_columns, condition_columns, property_columns = seperate_column_types(df_type)\n",
|
|
719
|
+
"\n",
|
|
720
|
+
" column_info.update({\n",
|
|
721
|
+
" sheet_name: {\n",
|
|
722
|
+
" ColumnTypes.STD.value: standard_columns,\n",
|
|
723
|
+
" ColumnTypes.COND.value: condition_columns,\n",
|
|
724
|
+
" ColumnTypes.INF.value: property_columns\n",
|
|
725
|
+
" }\n",
|
|
726
|
+
" }\n",
|
|
727
|
+
" )\n",
|
|
728
|
+
" all_condition_column_names = extract_column_names(df_type, condition_columns)\n",
|
|
729
|
+
" all_properties_column_names = extract_column_names(df_type, property_columns)\n",
|
|
730
|
+
"\n",
|
|
731
|
+
" df_meta = xl.parse(sheet_name, nrows=2, usecols=\"B\", header=None)\n",
|
|
732
|
+
" category = df_meta.values[0][0]\n",
|
|
733
|
+
" type = df_meta.values[1][0]\n",
|
|
734
|
+
"\n",
|
|
735
|
+
" df_standard = construct_dataframe_for_column_type(xl, sheet_name, column_info, ColumnTypes.STD.value)\n",
|
|
736
|
+
" df_condition = construct_dataframe_for_column_type(xl, sheet_name, column_info, ColumnTypes.COND.value)\n",
|
|
737
|
+
" df_properties = construct_dataframe_for_column_type(xl, sheet_name, column_info, ColumnTypes.INF.value)\n",
|
|
738
|
+
"\n",
|
|
739
|
+
" specs.extend(generate_base_spec_data(df_standard, sheet_name, category, type))\n",
|
|
740
|
+
"\n",
|
|
741
|
+
" generate_spec_conditions(df_condition, all_condition_column_names, sheet_name, specs, index)\n",
|
|
742
|
+
"\n",
|
|
743
|
+
" generate_spec_properties(df_properties, all_properties_column_names, specs, index)\n",
|
|
744
|
+
"\n",
|
|
745
|
+
" index += len(df_standard)\n",
|
|
746
|
+
"\n",
|
|
747
|
+
" return specs"
|
|
748
|
+
]
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
"cell_type": "markdown",
|
|
752
|
+
"metadata": {},
|
|
753
|
+
"source": [
|
|
754
|
+
"### Query Specs\n"
|
|
755
|
+
]
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
"cell_type": "code",
|
|
759
|
+
"execution_count": null,
|
|
760
|
+
"metadata": {},
|
|
761
|
+
"outputs": [],
|
|
762
|
+
"source": [
|
|
763
|
+
"def query_specs(product_ids: str):\n",
|
|
764
|
+
" body = json.dumps({\n",
|
|
765
|
+
" ApiBodyKeys.PRODUCT_IDS: [\n",
|
|
766
|
+
" product_ids\n",
|
|
767
|
+
" ],\n",
|
|
768
|
+
" ApiBodyKeys.TAKE: MAXIMUM_SPEC_LIMIT\n",
|
|
769
|
+
" }, indent=4)\n",
|
|
770
|
+
" response = create_post_request(query_spec_url, body)\n",
|
|
771
|
+
" response = response.json()\n",
|
|
772
|
+
" return response"
|
|
773
|
+
]
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
"cell_type": "markdown",
|
|
777
|
+
"metadata": {},
|
|
778
|
+
"source": [
|
|
779
|
+
"### Delete Specs\n"
|
|
780
|
+
]
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
"cell_type": "code",
|
|
784
|
+
"execution_count": null,
|
|
785
|
+
"metadata": {},
|
|
786
|
+
"outputs": [],
|
|
787
|
+
"source": [
|
|
788
|
+
"def delete_specs(query_spec_ids: list):\n",
|
|
789
|
+
" body = json.dumps({\n",
|
|
790
|
+
" ApiBodyKeys.IDS: query_spec_ids\n",
|
|
791
|
+
" }, indent=4)\n",
|
|
792
|
+
" response = create_post_request(delete_spec_url, body)\n",
|
|
793
|
+
" return response"
|
|
794
|
+
]
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
"cell_type": "markdown",
|
|
798
|
+
"metadata": {},
|
|
799
|
+
"source": [
|
|
800
|
+
"### Create Specs\n"
|
|
801
|
+
]
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
"cell_type": "code",
|
|
805
|
+
"execution_count": null,
|
|
806
|
+
"metadata": {},
|
|
807
|
+
"outputs": [],
|
|
808
|
+
"source": [
|
|
809
|
+
"def create_specs(spec_data: list):\n",
|
|
810
|
+
" complete_response = []\n",
|
|
811
|
+
" for i in range(0, len(spec_data), CREATE_SPECS_BATCH_SIZE):\n",
|
|
812
|
+
" specs_batch = spec_data[i:i+CREATE_SPECS_BATCH_SIZE]\n",
|
|
813
|
+
" payload = json.dumps({\n",
|
|
814
|
+
" ApiBodyKeys.SPECS: specs_batch\n",
|
|
815
|
+
" }, indent=4)\n",
|
|
816
|
+
" response = create_post_request(create_spec_url, payload)\n",
|
|
817
|
+
" complete_response.append(response.json())\n",
|
|
818
|
+
" return complete_response"
|
|
819
|
+
]
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
"cell_type": "code",
|
|
823
|
+
"execution_count": null,
|
|
824
|
+
"metadata": {},
|
|
825
|
+
"outputs": [],
|
|
826
|
+
"source": [
|
|
827
|
+
"spec_data = generate_spec_data()"
|
|
828
|
+
]
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
"cell_type": "markdown",
|
|
832
|
+
"metadata": {},
|
|
833
|
+
"source": [
|
|
834
|
+
"### Call API's and process responses\n"
|
|
835
|
+
]
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
"cell_type": "code",
|
|
839
|
+
"execution_count": null,
|
|
840
|
+
"metadata": {},
|
|
841
|
+
"outputs": [],
|
|
842
|
+
"source": [
|
|
843
|
+
"error_messages = []\n",
|
|
844
|
+
"query_spec_ids = []\n",
|
|
845
|
+
"created_spec_ids = []\n",
|
|
846
|
+
"\n",
|
|
847
|
+
"query_spec_response = query_specs(product_id)\n",
|
|
848
|
+
"\n",
|
|
849
|
+
"query_spec_ids = [spec[ApiResponseKeys.ID]\n",
|
|
850
|
+
" for spec in query_spec_response.get(ApiResponseKeys.SPECS, [])]\n",
|
|
851
|
+
"\n",
|
|
852
|
+
"delete_spec_response = delete_specs(query_spec_ids) if len(query_spec_ids) > 0 else None\n",
|
|
853
|
+
"create_spec_response = create_specs(spec_data)\n",
|
|
854
|
+
"\n",
|
|
855
|
+
"error_messages = [response[ApiResponseKeys.ERROR] for response in create_spec_response\n",
|
|
856
|
+
" if ApiResponseKeys.ERROR in response]\n",
|
|
857
|
+
"\n",
|
|
858
|
+
"if error_messages:\n",
|
|
859
|
+
" error = True\n",
|
|
860
|
+
"\n",
|
|
861
|
+
"created_spec_ids = [spec[ApiResponseKeys.SPEC_ID] for response in create_spec_response\n",
|
|
862
|
+
" for spec in response.get(ApiResponseKeys.CREATED_SPECS, [])]\n",
|
|
863
|
+
"\n",
|
|
864
|
+
"created_spec_ids_df = pd.DataFrame(\n",
|
|
865
|
+
" {'Created Spec Id': created_spec_ids}).to_dict(orient='records')"
|
|
866
|
+
]
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
"cell_type": "markdown",
|
|
870
|
+
"metadata": {},
|
|
871
|
+
"source": [
|
|
872
|
+
"### Print the execution result\n"
|
|
873
|
+
]
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
"cell_type": "code",
|
|
877
|
+
"execution_count": null,
|
|
878
|
+
"metadata": {},
|
|
879
|
+
"outputs": [],
|
|
880
|
+
"source": [
|
|
881
|
+
"if not error_messages:\n",
|
|
882
|
+
" sb.glue(\"Result\", \"All specs uploaded successfully\")\n",
|
|
883
|
+
" sb.glue(\"Created Specs\", created_spec_ids_df)\n",
|
|
884
|
+
"else:\n",
|
|
885
|
+
" sb.glue(\"Error\", error_messages)\n",
|
|
886
|
+
" if created_spec_ids:\n",
|
|
887
|
+
" sb.glue(\"Created Specs\", created_spec_ids_df)"
|
|
888
|
+
]
|
|
889
|
+
}
|
|
890
|
+
],
|
|
891
|
+
"metadata": {
|
|
892
|
+
"kernelspec": {
|
|
893
|
+
"display_name": "Python 3 (ipykernel)",
|
|
894
|
+
"language": "python",
|
|
895
|
+
"name": "python3"
|
|
896
|
+
},
|
|
897
|
+
"language_info": {
|
|
898
|
+
"codemirror_mode": {
|
|
899
|
+
"name": "ipython",
|
|
900
|
+
"version": 3
|
|
901
|
+
},
|
|
902
|
+
"file_extension": ".py",
|
|
903
|
+
"mimetype": "text/x-python",
|
|
904
|
+
"name": "python",
|
|
905
|
+
"nbconvert_exporter": "python",
|
|
906
|
+
"pygments_lexer": "ipython3",
|
|
907
|
+
"version": "3.11.4"
|
|
908
|
+
}
|
|
909
|
+
},
|
|
910
|
+
"nbformat": 4,
|
|
911
|
+
"nbformat_minor": 4
|
|
912
|
+
}
|