omnata-plugin-devkit 0.13.0a158__tar.gz → 0.13.1__tar.gz
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.
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/PKG-INFO +1 -1
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/pyproject.toml +1 -1
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/development_session.py +188 -120
- omnata_plugin_devkit-0.13.1/src/omnata_plugin_devkit/jinja_templates/CHECK_CONNECTION_PROGRESS.sql.jinja +112 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CONFIGURE_APIS.sql.jinja +5 -0
- omnata_plugin_devkit-0.13.1/src/omnata_plugin_devkit/jinja_templates/GET_MISSING_APP_PRIVILEGES.sql.jinja +35 -0
- omnata_plugin_devkit-0.13.1/src/omnata_plugin_devkit/jinja_templates/LIST_APP_SPECIFICATIONS.sql.jinja +40 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/NETWORK_ADDRESSES.sql.jinja +2 -1
- omnata_plugin_devkit-0.13.1/src/omnata_plugin_devkit/jinja_templates/SET_CONNECTION_OBJECTS.sql.jinja +357 -0
- omnata_plugin_devkit-0.13.1/src/omnata_plugin_devkit/jinja_templates/SET_EAI_ENABLED.sql.jinja +43 -0
- omnata_plugin_devkit-0.13.1/src/omnata_plugin_devkit/jinja_templates/SET_EAI_SPECIFICATION.sql.jinja +61 -0
- omnata_plugin_devkit-0.13.1/src/omnata_plugin_devkit/jinja_templates/SET_SI_SPECIFICATION.sql.jinja +69 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/manifest.yml.jinja +5 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/native_app_packaging.py +0 -2
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/plugin_uploader.py +10 -1
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/test_step_definitions.py +416 -186
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/LICENSE +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/README.md +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/airbyte_wrapper.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/cli/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/development.ipynb +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/initialiser.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/API_LIMITS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/ASSIGN_OUTBOUND_TARGET_TYPE.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CONFIGURATION_FORM.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CONNECTION_FORM.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CONNECTION_TEST.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CONSTRUCT_FORM_OPTION.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CREATE_BILLING_EVENTS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CREATE_GENERIC_SECRET_OBJECT.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CREATE_NETWORK_RULE_OBJECT.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CREATE_NETWORK_RULE_OBJECT_FROM_EXISTING.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/CREATE_OAUTH_SECRET_OBJECT.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/DROP_NETWORK_RULES.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/DROP_SECRETS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/FETCH_CONNECTIONS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/FETCH_SYNCS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/FETCH_SYNC_BRANCHES.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/INBOUND_LIST_STREAMS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/LIST_STAGES.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/NGROK_POST_TUNNEL_FIELDS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/OUTBOUND_RECORD_VALIDATOR.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/PENDING_API_CONFIGURATION.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/POST_INSTALL_ACTIONS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/RENAME_CONNECTION_METHODS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/RETRIEVE_NETWORK_RULE_OBJECT.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/RETRIEVE_SECRETS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/RETRIEVE_SECRETS_UDF.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/SYNC.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/TEST_CALLBACK.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/TEST_OAUTH_TOKEN_EXISTS.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/TUNNEL_TEST.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/UPDATE_API_CONFIGURATION.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/UPDATE_GENERIC_SECRET_OBJECT.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/UPDATE_GENERIC_SECRET_OBJECT_OLD.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/jinja_templates/UPDATE_NETWORK_RULE_OBJECT.sql.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/plugin_registration.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/plugin_template/icon.svg +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/plugin_template/plugin.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/plugin_template/plugin_development.ipynb +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/plugin_template/requirements.txt +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/api/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/api/config.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/api/constants.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/api/exceptions.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/api/secure_path.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/api/secure_utils.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/api/utils/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/api/utils/types.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/app/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/app/snow_connector.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/plugins/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/models.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/package/__init__.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/package_utils.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/snowpark_shared.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/venv.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/zipper.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/snowcli/cli/templates/environment.yml.jinja +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/streamlit/plugin_configuration.py +0 -0
- {omnata_plugin_devkit-0.13.0a158 → omnata_plugin_devkit-0.13.1}/src/omnata_plugin_devkit/utils.py +0 -0
|
@@ -28,6 +28,7 @@ from omnata_plugin_runtime.omnata_plugin import (
|
|
|
28
28
|
InboundSyncRequest,
|
|
29
29
|
OmnataPlugin,
|
|
30
30
|
OutboundSyncRequest,
|
|
31
|
+
RecordsToUploadResult,
|
|
31
32
|
SyncRequest,
|
|
32
33
|
)
|
|
33
34
|
from omnata_plugin_runtime.logging import OmnataPluginLogHandler
|
|
@@ -103,7 +104,7 @@ class SyncScenario:
|
|
|
103
104
|
)
|
|
104
105
|
os.makedirs(os.path.dirname(self.inbound_results_file), exist_ok=True)
|
|
105
106
|
self.scenario_records = scenario_records
|
|
106
|
-
self.results:Optional[pandas.DataFrame] = None
|
|
107
|
+
self.results: Optional[pandas.DataFrame] = None
|
|
107
108
|
self.initial_stream_state = initial_stream_state
|
|
108
109
|
|
|
109
110
|
|
|
@@ -136,9 +137,9 @@ class DevelopmentSession:
|
|
|
136
137
|
self.vcr = None
|
|
137
138
|
self.recorded_http = recorded_http
|
|
138
139
|
self.inject_snowpark_session = inject_snowpark_session
|
|
139
|
-
self.stream_index_fields:Dict[str,str] = {}
|
|
140
|
-
self.stream_excluded_fields:Dict[str,List[str]] = {}
|
|
141
|
-
self.exclude_records_by_field_value:Dict[str,str] = {}
|
|
140
|
+
self.stream_index_fields: Dict[str, str] = {}
|
|
141
|
+
self.stream_excluded_fields: Dict[str, List[str]] = {}
|
|
142
|
+
self.exclude_records_by_field_value: Dict[str, str] = {}
|
|
142
143
|
self.plugin_id = plugin_instance.get_manifest().plugin_id
|
|
143
144
|
self.feature_filename = os.path.join("features", f"{self.plugin_id}.feature")
|
|
144
145
|
self.current_scenario = None
|
|
@@ -153,8 +154,8 @@ class DevelopmentSession:
|
|
|
153
154
|
Collects the full set of records which were previously staged
|
|
154
155
|
"""
|
|
155
156
|
return self.current_scenario.scenario_records
|
|
156
|
-
|
|
157
|
-
def set_inbound_stream_index_field(self,stream_name:str,index_field:str):
|
|
157
|
+
|
|
158
|
+
def set_inbound_stream_index_field(self, stream_name: str, index_field: str):
|
|
158
159
|
"""
|
|
159
160
|
Sets the field to be used as the index field for a given stream.
|
|
160
161
|
By default, it is set to the primary key field of the stream, but this may
|
|
@@ -163,18 +164,22 @@ class DevelopmentSession:
|
|
|
163
164
|
"""
|
|
164
165
|
self.stream_index_fields[stream_name] = index_field
|
|
165
166
|
|
|
166
|
-
def exclude_inbound_result_fields(
|
|
167
|
+
def exclude_inbound_result_fields(
|
|
168
|
+
self, stream_name: str, field_names: Union[str, List[str]]
|
|
169
|
+
):
|
|
167
170
|
"""
|
|
168
171
|
Excludes a field from the comparison of inbound results.
|
|
169
172
|
"""
|
|
170
173
|
if stream_name not in self.stream_excluded_fields:
|
|
171
174
|
self.stream_excluded_fields[stream_name] = []
|
|
172
|
-
if isinstance(field_names,str):
|
|
175
|
+
if isinstance(field_names, str):
|
|
173
176
|
self.stream_excluded_fields[stream_name].append(field_names)
|
|
174
177
|
else:
|
|
175
178
|
self.stream_excluded_fields[stream_name].extend(field_names)
|
|
176
|
-
|
|
177
|
-
def exclude_inbound_result_records_by_field_value(
|
|
179
|
+
|
|
180
|
+
def exclude_inbound_result_records_by_field_value(
|
|
181
|
+
self, field_name: str, field_value: str
|
|
182
|
+
):
|
|
178
183
|
"""
|
|
179
184
|
Excludes records from the comparison of inbound results where the field matches the value.
|
|
180
185
|
"""
|
|
@@ -235,13 +240,13 @@ class DevelopmentSession:
|
|
|
235
240
|
if not click.globals.get_current_context(silent=True):
|
|
236
241
|
# set an empty one so snowcli's app config doesn't error
|
|
237
242
|
click.globals.push_context(click.core.Context(click.core.Group()))
|
|
238
|
-
self.session: Session = get_snowpark_session(
|
|
243
|
+
self.session: Session = get_snowpark_session(
|
|
244
|
+
connection_name=snowcli_environment
|
|
245
|
+
)
|
|
239
246
|
self.sync_slug = sync_slug
|
|
240
|
-
session_run_response = self.session.sql(
|
|
241
|
-
f"""
|
|
247
|
+
session_run_response = self.session.sql(f"""
|
|
242
248
|
call {self.omnata_app_name}.API.CREATE_DEVELOPMENT_SESSION_RUN('{sync_slug}')
|
|
243
|
-
"""
|
|
244
|
-
).collect()
|
|
249
|
+
""").collect()
|
|
245
250
|
response_parsed = json.loads(session_run_response[0][0])
|
|
246
251
|
if response_parsed["success"] is False:
|
|
247
252
|
raise ValueError(f"Failed: {response_parsed['error']}")
|
|
@@ -276,16 +281,15 @@ class DevelopmentSession:
|
|
|
276
281
|
else "null"
|
|
277
282
|
)
|
|
278
283
|
|
|
279
|
-
secrets_fetch_response = self.session.sql(
|
|
280
|
-
f"""
|
|
284
|
+
secrets_fetch_response = self.session.sql(f"""
|
|
281
285
|
call {plugin_app_name}.PLUGIN.RETRIEVE_SECRETS({oauth_secret_param},{other_secrets_param})
|
|
282
|
-
"""
|
|
283
|
-
).collect()
|
|
286
|
+
""").collect()
|
|
284
287
|
secrets_response_parsed = json.loads(secrets_fetch_response[0][0])
|
|
285
288
|
if secrets_response_parsed["success"] is False:
|
|
286
289
|
raise ValueError(f"Failed: {secrets_response_parsed['error']}")
|
|
287
|
-
secrets_data = TypeAdapter(
|
|
288
|
-
|
|
290
|
+
secrets_data = TypeAdapter(Dict[str, StoredConfigurationValue]).validate_python(
|
|
291
|
+
secrets_response_parsed["data"]
|
|
292
|
+
)
|
|
289
293
|
|
|
290
294
|
source_database = self.omnata_app_name
|
|
291
295
|
source_schema = outbound_payload.records_schema_name
|
|
@@ -298,17 +302,20 @@ class DevelopmentSession:
|
|
|
298
302
|
configuration_parameters = OutboundSyncConfigurationParameters(
|
|
299
303
|
connection_method=outbound_payload.connection_method,
|
|
300
304
|
connection_parameters=TypeAdapter(
|
|
301
|
-
Dict[str, StoredConfigurationValue]
|
|
305
|
+
Dict[str, StoredConfigurationValue]
|
|
306
|
+
).validate_python(
|
|
302
307
|
outbound_payload.connection_parameters,
|
|
303
308
|
),
|
|
304
309
|
connection_secrets=TypeAdapter(
|
|
305
|
-
Dict[str, StoredConfigurationValue]
|
|
306
|
-
),
|
|
310
|
+
Dict[str, StoredConfigurationValue]
|
|
311
|
+
).validate_python(secrets_data),
|
|
307
312
|
sync_parameters=TypeAdapter(
|
|
308
|
-
Dict[str, StoredConfigurationValue]
|
|
309
|
-
),
|
|
313
|
+
Dict[str, StoredConfigurationValue]
|
|
314
|
+
).validate_python(outbound_payload.sync_parameters),
|
|
310
315
|
sync_strategy=outbound_payload.sync_strategy,
|
|
311
|
-
field_mappings=TypeAdapter(StoredMappingValue).validate_python(
|
|
316
|
+
field_mappings=TypeAdapter(StoredMappingValue).validate_python(
|
|
317
|
+
outbound_payload.field_mappings
|
|
318
|
+
),
|
|
312
319
|
current_form_parameters={},
|
|
313
320
|
)
|
|
314
321
|
outbound_sync_request = OutboundSyncRequest(
|
|
@@ -323,7 +330,8 @@ class DevelopmentSession:
|
|
|
323
330
|
api_limits=self.api_limits,
|
|
324
331
|
rate_limit_state_all={},
|
|
325
332
|
rate_limit_state_this_sync_and_branch={},
|
|
326
|
-
run_deadline=datetime.datetime.now(datetime.timezone.utc)
|
|
333
|
+
run_deadline=datetime.datetime.now(datetime.timezone.utc)
|
|
334
|
+
+ datetime.timedelta(hours=4),
|
|
327
335
|
development_mode=True,
|
|
328
336
|
)
|
|
329
337
|
|
|
@@ -359,20 +367,20 @@ class DevelopmentSession:
|
|
|
359
367
|
if not click.globals.get_current_context(silent=True):
|
|
360
368
|
# set an empty one so snowcli's app config doesn't error
|
|
361
369
|
click.globals.push_context(click.core.Context(click.core.Group()))
|
|
362
|
-
|
|
363
|
-
self.session: Session = get_snowpark_session(
|
|
370
|
+
|
|
371
|
+
self.session: Session = get_snowpark_session(
|
|
372
|
+
connection_name=snowcli_environment
|
|
373
|
+
)
|
|
364
374
|
# we set the current database to the plugin app name, if it's set in the environment
|
|
365
375
|
# this means any plugins which call their own UDFs will work
|
|
366
|
-
if
|
|
367
|
-
plugin_app_name = os.environ[
|
|
376
|
+
if "PLUGIN_APP_NAME" in os.environ:
|
|
377
|
+
plugin_app_name = os.environ["PLUGIN_APP_NAME"]
|
|
368
378
|
self.session.sql(f"USE DATABASE {plugin_app_name}").collect()
|
|
369
379
|
|
|
370
380
|
self.sync_slug = sync_slug
|
|
371
|
-
session_run_response = self.session.sql(
|
|
372
|
-
f"""
|
|
381
|
+
session_run_response = self.session.sql(f"""
|
|
373
382
|
call {self.omnata_app_name}.API.CREATE_DEVELOPMENT_SESSION_RUN('{sync_slug}')
|
|
374
|
-
"""
|
|
375
|
-
).collect()
|
|
383
|
+
""").collect()
|
|
376
384
|
response_parsed = json.loads(session_run_response[0][0])
|
|
377
385
|
if response_parsed["success"] is False:
|
|
378
386
|
raise ValueError(f"Failed: {response_parsed['error']}")
|
|
@@ -408,31 +416,31 @@ class DevelopmentSession:
|
|
|
408
416
|
else "null"
|
|
409
417
|
)
|
|
410
418
|
|
|
411
|
-
secrets_fetch_response = self.session.sql(
|
|
412
|
-
f"""
|
|
419
|
+
secrets_fetch_response = self.session.sql(f"""
|
|
413
420
|
call {plugin_app_name}.PLUGIN.RETRIEVE_SECRETS({oauth_secret_param},{other_secrets_param})
|
|
414
|
-
"""
|
|
415
|
-
).collect()
|
|
421
|
+
""").collect()
|
|
416
422
|
secrets_response_parsed = json.loads(secrets_fetch_response[0][0])
|
|
417
423
|
if secrets_response_parsed["success"] is False:
|
|
418
424
|
raise ValueError(f"Failed: {secrets_response_parsed['error']}")
|
|
419
|
-
secrets_data = TypeAdapter(
|
|
420
|
-
|
|
425
|
+
secrets_data = TypeAdapter(Dict[str, StoredConfigurationValue]).validate_python(
|
|
426
|
+
secrets_response_parsed["data"]
|
|
427
|
+
)
|
|
421
428
|
|
|
422
429
|
# full_source_table_name = f"{source_database}.{source_schema}.{source_table}"
|
|
423
430
|
# self.api_limits.concurrency = 1 # we have to set this because pyvcr isn't thread safe
|
|
424
431
|
configuration_parameters = InboundSyncConfigurationParameters(
|
|
425
432
|
connection_method=inbound_payload.connection_method,
|
|
426
433
|
connection_parameters=TypeAdapter(
|
|
427
|
-
Dict[str, StoredConfigurationValue]
|
|
434
|
+
Dict[str, StoredConfigurationValue]
|
|
435
|
+
).validate_python(
|
|
428
436
|
inbound_payload.connection_parameters,
|
|
429
437
|
),
|
|
430
438
|
connection_secrets=TypeAdapter(
|
|
431
|
-
Dict[str, StoredConfigurationValue]
|
|
432
|
-
),
|
|
439
|
+
Dict[str, StoredConfigurationValue]
|
|
440
|
+
).validate_python(secrets_data),
|
|
433
441
|
sync_parameters=TypeAdapter(
|
|
434
|
-
Dict[str, StoredConfigurationValue]
|
|
435
|
-
),
|
|
442
|
+
Dict[str, StoredConfigurationValue]
|
|
443
|
+
).validate_python(inbound_payload.sync_parameters),
|
|
436
444
|
current_form_parameters={},
|
|
437
445
|
)
|
|
438
446
|
|
|
@@ -446,7 +454,9 @@ class DevelopmentSession:
|
|
|
446
454
|
)
|
|
447
455
|
for stream in streams_list:
|
|
448
456
|
if stream.stream.source_defined_primary_key is not None:
|
|
449
|
-
self.stream_index_fields[stream.stream_name] =
|
|
457
|
+
self.stream_index_fields[stream.stream_name] = (
|
|
458
|
+
stream.stream.source_defined_primary_key
|
|
459
|
+
)
|
|
450
460
|
omnata_log_handler = OmnataPluginLogHandler(
|
|
451
461
|
session=self.session,
|
|
452
462
|
sync_id=None,
|
|
@@ -464,12 +474,13 @@ class DevelopmentSession:
|
|
|
464
474
|
api_limits=self.api_limits,
|
|
465
475
|
rate_limit_state_all={},
|
|
466
476
|
rate_limit_state_this_sync_and_branch={},
|
|
467
|
-
run_deadline=datetime.datetime.now(datetime.timezone.utc)
|
|
477
|
+
run_deadline=datetime.datetime.now(datetime.timezone.utc)
|
|
478
|
+
+ datetime.timedelta(hours=4),
|
|
468
479
|
development_mode=True,
|
|
469
480
|
# this skips over the part where we check for new streams etc,
|
|
470
481
|
# so development sessions will only get requests for explicitly configured streams
|
|
471
482
|
streams=streams_list,
|
|
472
|
-
omnata_log_handler=omnata_log_handler
|
|
483
|
+
omnata_log_handler=omnata_log_handler,
|
|
473
484
|
)
|
|
474
485
|
|
|
475
486
|
self.current_scenario = SyncScenario(
|
|
@@ -479,14 +490,14 @@ class DevelopmentSession:
|
|
|
479
490
|
configuration_parameters=configuration_parameters,
|
|
480
491
|
sync_request=inbound_sync_request,
|
|
481
492
|
scenario_records=None,
|
|
482
|
-
initial_stream_state=initial_stream_state
|
|
493
|
+
initial_stream_state=initial_stream_state,
|
|
483
494
|
)
|
|
484
495
|
self.run_id = inbound_payload.run_id
|
|
485
496
|
self.plugin_instance._sync_request = inbound_sync_request
|
|
486
497
|
if self.recorded_http:
|
|
487
498
|
self._start_recording()
|
|
488
499
|
return configuration_parameters, inbound_sync_request
|
|
489
|
-
|
|
500
|
+
|
|
490
501
|
def cancel_scenario(self):
|
|
491
502
|
"""
|
|
492
503
|
Cancels the current scenario, and stops recording traffic.
|
|
@@ -498,7 +509,7 @@ class DevelopmentSession:
|
|
|
498
509
|
self._stop_recording()
|
|
499
510
|
print("Success: cancelled scenario")
|
|
500
511
|
|
|
501
|
-
def complete_scenario(self,apply_results:bool=True):
|
|
512
|
+
def complete_scenario(self, apply_results: bool = True):
|
|
502
513
|
"""
|
|
503
514
|
Marks the scenario as complete, and stops recording traffic.
|
|
504
515
|
"""
|
|
@@ -511,14 +522,18 @@ class DevelopmentSession:
|
|
|
511
522
|
self._stop_recording()
|
|
512
523
|
if apply_results:
|
|
513
524
|
self.current_scenario.sync_request.apply_results_queue()
|
|
514
|
-
if
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
525
|
+
if (
|
|
526
|
+
self.current_scenario.sync_request.__class__.__name__
|
|
527
|
+
== "InboundSyncRequest"
|
|
528
|
+
):
|
|
529
|
+
# Checkpointing have removed this field
|
|
530
|
+
# print(f"States at completion: {self.current_scenario.sync_request._latest_states}")
|
|
531
|
+
self.current_scenario.sync_request.apply_progress_updates(
|
|
532
|
+
ignore_errors=False
|
|
533
|
+
)
|
|
534
|
+
session_run_response = self.session.sql(f"""
|
|
519
535
|
call {self.omnata_app_name}.API.COMPLETE_DEVELOPMENT_SESSION_RUN({self.run_id},{apply_results})
|
|
520
|
-
"""
|
|
521
|
-
).collect()
|
|
536
|
+
""").collect()
|
|
522
537
|
response_parsed = json.loads(session_run_response[0][0])
|
|
523
538
|
if response_parsed["success"] is False:
|
|
524
539
|
raise ValueError(f"Failed: {response_parsed['error']}")
|
|
@@ -576,7 +591,9 @@ class DevelopmentSession:
|
|
|
576
591
|
if self.current_scenario is None:
|
|
577
592
|
print("Failed: no active scenario")
|
|
578
593
|
return
|
|
579
|
-
results_dataframe = pandas.concat(
|
|
594
|
+
results_dataframe = pandas.concat(
|
|
595
|
+
outbound_sync_request._apply_results
|
|
596
|
+
).copy()
|
|
580
597
|
|
|
581
598
|
originally_provided_records = self.current_scenario.scenario_records
|
|
582
599
|
|
|
@@ -625,7 +642,10 @@ class DevelopmentSession:
|
|
|
625
642
|
print("Success: results are valid")
|
|
626
643
|
elif sync_request.__class__.__name__ == "InboundSyncRequest":
|
|
627
644
|
inbound_sync_request: InboundSyncRequest = sync_request
|
|
628
|
-
if
|
|
645
|
+
if (
|
|
646
|
+
inbound_sync_request._apply_results is None
|
|
647
|
+
or len(inbound_sync_request._apply_results) == 0
|
|
648
|
+
):
|
|
629
649
|
# if there are no results, we check the real results table
|
|
630
650
|
full_table_name = inbound_sync_request._full_results_table_name
|
|
631
651
|
# usually if results are provided in a table, RECORD_OBJECT (object) is used instead of RECORD_DATA (varchar)
|
|
@@ -637,27 +657,37 @@ class DevelopmentSession:
|
|
|
637
657
|
COALESCE(PARSE_JSON(RECORD_DATA), RECORD_OBJECT) as RECORD_OBJECT,
|
|
638
658
|
IS_DELETED
|
|
639
659
|
from {full_table_name}""").collect()
|
|
640
|
-
|
|
660
|
+
|
|
641
661
|
if len(results_from_table) == 0:
|
|
642
|
-
print(
|
|
662
|
+
print(
|
|
663
|
+
f"Failed: No results were enqueued to the sync request, and no results found in {full_table_name}"
|
|
664
|
+
)
|
|
643
665
|
else:
|
|
644
666
|
results_dataframe = pandas.DataFrame(results_from_table)
|
|
645
|
-
results_dataframe["RECORD_OBJECT"] = results_dataframe[
|
|
646
|
-
|
|
647
|
-
)
|
|
667
|
+
results_dataframe["RECORD_OBJECT"] = results_dataframe[
|
|
668
|
+
"RECORD_OBJECT"
|
|
669
|
+
].apply(lambda x: json.loads(x) if x is not None else None)
|
|
648
670
|
self.current_scenario.results = results_dataframe
|
|
649
671
|
print("Success: results are valid (retrieved from table)")
|
|
650
672
|
else:
|
|
651
673
|
# inbound_sync_request._apply_results is a dictionary of stream_name -> list of dataframes
|
|
652
674
|
# we want to flatten this into a single dataframe
|
|
675
|
+
|
|
676
|
+
# In Checkpointing, we need to loop each dataframe again as each dataframe holds a RecordsToUploadResult object
|
|
653
677
|
results_dataframe = pandas.concat(
|
|
654
|
-
[
|
|
678
|
+
[
|
|
679
|
+
item.records
|
|
680
|
+
for df_list in inbound_sync_request._apply_results.values()
|
|
681
|
+
for item in df_list
|
|
682
|
+
if isinstance(item, RecordsToUploadResult)
|
|
683
|
+
]
|
|
655
684
|
).copy()
|
|
685
|
+
|
|
656
686
|
# typically, the results table will have a RECORD_DATA column, which is a varchar
|
|
657
687
|
# we need to parse this as JSON into an object column named RECORD_OBJECT, allowing for nulls
|
|
658
|
-
results_dataframe["RECORD_OBJECT"] = results_dataframe[
|
|
659
|
-
|
|
660
|
-
)
|
|
688
|
+
results_dataframe["RECORD_OBJECT"] = results_dataframe[
|
|
689
|
+
"RECORD_DATA"
|
|
690
|
+
].apply(lambda x: json.loads(x) if x is not None else None)
|
|
661
691
|
# we can drop the RECORD_DATA column now
|
|
662
692
|
results_dataframe = results_dataframe.drop(columns=["RECORD_DATA"])
|
|
663
693
|
self.current_scenario.results = results_dataframe
|
|
@@ -766,20 +796,18 @@ class DevelopmentSession:
|
|
|
766
796
|
{
|
|
767
797
|
"Property": "connection_parameters",
|
|
768
798
|
"Value": json.dumps(
|
|
769
|
-
to_jsonable_python(
|
|
799
|
+
to_jsonable_python(
|
|
800
|
+
outbound_params.connection_parameters
|
|
801
|
+
)
|
|
770
802
|
),
|
|
771
803
|
},
|
|
772
804
|
{
|
|
773
805
|
"Property": "connection_secrets",
|
|
774
|
-
"Value": json.dumps(
|
|
775
|
-
to_jsonable_python(secrets_redacted)
|
|
776
|
-
),
|
|
806
|
+
"Value": json.dumps(to_jsonable_python(secrets_redacted)),
|
|
777
807
|
},
|
|
778
808
|
{
|
|
779
809
|
"Property": "api_limits",
|
|
780
|
-
"Value": json.dumps(
|
|
781
|
-
to_jsonable_python(self.api_limits)
|
|
782
|
-
),
|
|
810
|
+
"Value": json.dumps(to_jsonable_python(self.api_limits)),
|
|
783
811
|
},
|
|
784
812
|
{
|
|
785
813
|
"Property": "sync_parameters",
|
|
@@ -816,15 +844,11 @@ class DevelopmentSession:
|
|
|
816
844
|
},
|
|
817
845
|
{
|
|
818
846
|
"Property": "connection_secrets",
|
|
819
|
-
"Value": json.dumps(
|
|
820
|
-
to_jsonable_python(secrets_redacted)
|
|
821
|
-
),
|
|
847
|
+
"Value": json.dumps(to_jsonable_python(secrets_redacted)),
|
|
822
848
|
},
|
|
823
849
|
{
|
|
824
850
|
"Property": "api_limits",
|
|
825
|
-
"Value": json.dumps(
|
|
826
|
-
to_jsonable_python(self.api_limits)
|
|
827
|
-
),
|
|
851
|
+
"Value": json.dumps(to_jsonable_python(self.api_limits)),
|
|
828
852
|
},
|
|
829
853
|
{
|
|
830
854
|
"Property": "sync_parameters",
|
|
@@ -846,7 +870,11 @@ class DevelopmentSession:
|
|
|
846
870
|
f.write(f"\tScenario: {recorded_scenario.scenario_name}\n")
|
|
847
871
|
if recorded_scenario.sync_direction == SyncDirection.OUTBOUND:
|
|
848
872
|
f.write("\t\tGiven the following records:\n")
|
|
849
|
-
for col in [
|
|
873
|
+
for col in [
|
|
874
|
+
"RESULT",
|
|
875
|
+
"TRANSFORMED_RECORD",
|
|
876
|
+
"TRANSFORMED_RECORD_PREVIOUS",
|
|
877
|
+
]:
|
|
850
878
|
recorded_scenario.scenario_records[col] = (
|
|
851
879
|
recorded_scenario.scenario_records[col]
|
|
852
880
|
.apply(lambda x: json.loads(x) if x is not None else None)
|
|
@@ -859,7 +887,14 @@ class DevelopmentSession:
|
|
|
859
887
|
)
|
|
860
888
|
table_indented = self.dataframe_to_behave_table(
|
|
861
889
|
recorded_scenario.scenario_records[
|
|
862
|
-
[
|
|
890
|
+
[
|
|
891
|
+
"IDENTIFIER",
|
|
892
|
+
"APP_IDENTIFIER",
|
|
893
|
+
"RESULT",
|
|
894
|
+
"SYNC_ACTION",
|
|
895
|
+
"TRANSFORMED_RECORD",
|
|
896
|
+
"TRANSFORMED_RECORD_PREVIOUS",
|
|
897
|
+
]
|
|
863
898
|
],
|
|
864
899
|
3,
|
|
865
900
|
)
|
|
@@ -871,7 +906,10 @@ class DevelopmentSession:
|
|
|
871
906
|
recorded_scenario.sync_request
|
|
872
907
|
)
|
|
873
908
|
for stream in inbound_sync_request.streams:
|
|
874
|
-
if
|
|
909
|
+
if (
|
|
910
|
+
recorded_scenario.initial_stream_state is not None
|
|
911
|
+
and stream.stream_name in recorded_scenario.initial_stream_state
|
|
912
|
+
):
|
|
875
913
|
f.write(
|
|
876
914
|
f"\t\t\t| {stream.stream_name} | {json.dumps(recorded_scenario.initial_stream_state[stream.stream_name],separators=(',', ':'),default=str)} | \n"
|
|
877
915
|
)
|
|
@@ -892,9 +930,7 @@ class DevelopmentSession:
|
|
|
892
930
|
f"\t\tAnd we use the {self.plugin_instance.__class__.__name__} class from the {self.plugin_module} module\n"
|
|
893
931
|
)
|
|
894
932
|
if self.inject_snowpark_session:
|
|
895
|
-
f.write(
|
|
896
|
-
f"\t\tAnd we attach a Snowpark session to the sync request\n"
|
|
897
|
-
)
|
|
933
|
+
f.write(f"\t\tAnd we attach a Snowpark session to the sync request\n")
|
|
898
934
|
f.write(
|
|
899
935
|
f"\t\tAnd the plugin returns inbound sync results directly to a real table\n"
|
|
900
936
|
)
|
|
@@ -907,7 +943,9 @@ class DevelopmentSession:
|
|
|
907
943
|
"\t\tWhen we perform an inbound sync with configuration parameters:\n"
|
|
908
944
|
)
|
|
909
945
|
f.write(f"{table_indented}\n")
|
|
910
|
-
f.write(
|
|
946
|
+
f.write(
|
|
947
|
+
f"\t\tAnd we use the recorded results from {recorded_scenario.inbound_results_file_name}\n"
|
|
948
|
+
)
|
|
911
949
|
if recorded_scenario.sync_direction == SyncDirection.OUTBOUND:
|
|
912
950
|
f.write("\t\tAnd the response will be:\n")
|
|
913
951
|
# self.create_results['TRANSFORMED_RECORD']=self.create_results['TRANSFORMED_RECORD'].apply(json.dumps)
|
|
@@ -942,9 +980,7 @@ class DevelopmentSession:
|
|
|
942
980
|
"RECORD_OBJECT",
|
|
943
981
|
].apply(
|
|
944
982
|
lambda x: {
|
|
945
|
-
k: v
|
|
946
|
-
for k, v in x.items()
|
|
947
|
-
if k not in excluded_fields
|
|
983
|
+
k: v for k, v in x.items() if k not in excluded_fields
|
|
948
984
|
}
|
|
949
985
|
)
|
|
950
986
|
f.write(
|
|
@@ -952,56 +988,88 @@ class DevelopmentSession:
|
|
|
952
988
|
)
|
|
953
989
|
# any records excluded by field value are removed both in the recording and the test
|
|
954
990
|
if len(self.exclude_records_by_field_value) > 0:
|
|
955
|
-
for
|
|
956
|
-
|
|
991
|
+
for (
|
|
992
|
+
field_name,
|
|
993
|
+
field_value,
|
|
994
|
+
) in self.exclude_records_by_field_value.items():
|
|
995
|
+
if field_value == "true":
|
|
957
996
|
field_value = True
|
|
958
|
-
elif field_value ==
|
|
997
|
+
elif field_value == "false":
|
|
959
998
|
field_value = False
|
|
960
|
-
recorded_scenario.results[
|
|
961
|
-
|
|
999
|
+
recorded_scenario.results[
|
|
1000
|
+
"value_test"
|
|
1001
|
+
] = recorded_scenario.results["RECORD_OBJECT"].apply(
|
|
1002
|
+
lambda x: (
|
|
1003
|
+
x[field_name]
|
|
1004
|
+
if x is not None and field_name in x
|
|
1005
|
+
else None
|
|
1006
|
+
)
|
|
962
1007
|
)
|
|
963
|
-
matching_records = recorded_scenario.results[
|
|
964
|
-
|
|
965
|
-
|
|
1008
|
+
matching_records = recorded_scenario.results[
|
|
1009
|
+
recorded_scenario.results["value_test"] == field_value
|
|
1010
|
+
]
|
|
1011
|
+
print(
|
|
1012
|
+
f"Excluded {len(matching_records)} records where {field_name} is {field_value}"
|
|
1013
|
+
)
|
|
1014
|
+
recorded_scenario.results = recorded_scenario.results[
|
|
1015
|
+
recorded_scenario.results["value_test"] != field_value
|
|
1016
|
+
]
|
|
966
1017
|
# remove the temporary column
|
|
967
|
-
recorded_scenario.results.drop(
|
|
968
|
-
|
|
1018
|
+
recorded_scenario.results.drop(
|
|
1019
|
+
columns=["value_test"], inplace=True
|
|
1020
|
+
)
|
|
969
1021
|
|
|
970
1022
|
# convert the RECORD_OBJECT to a json string without newlines
|
|
971
1023
|
recorded_scenario.results["RECORD_OBJECT"] = recorded_scenario.results[
|
|
972
1024
|
"RECORD_OBJECT"
|
|
973
1025
|
].apply(json.dumps)
|
|
974
1026
|
# also, drop the RETRIEVE_DATE column
|
|
975
|
-
recorded_scenario.results.drop(columns=["RETRIEVE_DATE"],inplace=True)
|
|
1027
|
+
recorded_scenario.results.drop(columns=["RETRIEVE_DATE"], inplace=True)
|
|
976
1028
|
# create the results file if it doesn't exist
|
|
977
|
-
os.makedirs(
|
|
978
|
-
|
|
1029
|
+
os.makedirs(
|
|
1030
|
+
os.path.dirname(recorded_scenario.inbound_results_file),
|
|
1031
|
+
exist_ok=True,
|
|
1032
|
+
)
|
|
1033
|
+
recorded_scenario.results.to_csv(
|
|
1034
|
+
recorded_scenario.inbound_results_file, sep="|", index=False
|
|
1035
|
+
)
|
|
979
1036
|
|
|
980
1037
|
if len(self.exclude_records_by_field_value) > 0:
|
|
981
|
-
for
|
|
982
|
-
|
|
1038
|
+
for (
|
|
1039
|
+
field_name,
|
|
1040
|
+
field_value,
|
|
1041
|
+
) in self.exclude_records_by_field_value.items():
|
|
1042
|
+
f.write(
|
|
1043
|
+
f"\t\tAnd we exclude all inbound results where the field {field_name} has the value {field_value}\n"
|
|
1044
|
+
)
|
|
983
1045
|
# group the results by stream name
|
|
984
1046
|
stream_names = recorded_scenario.results["STREAM_NAME"].unique()
|
|
985
1047
|
|
|
986
1048
|
for stream_name in stream_names:
|
|
987
1049
|
if stream_name not in self.stream_index_fields:
|
|
988
|
-
print(
|
|
1050
|
+
print(
|
|
1051
|
+
f"Failed: no index field set for stream {stream_name}. Use the set_inbound_stream_index_field function to set one"
|
|
1052
|
+
)
|
|
989
1053
|
return
|
|
990
1054
|
f.write(
|
|
991
1055
|
f"\t\tAnd when indexed on the {self.stream_index_fields[stream_name]} RECORD_OBJECT field, we assert that the recorded results for the {stream_name} stream are correct\n"
|
|
992
1056
|
)
|
|
993
1057
|
# count the number of records in the results that have a STREAM_NAME of stream_name
|
|
994
|
-
stream_results = recorded_scenario.results[
|
|
1058
|
+
stream_results = recorded_scenario.results[
|
|
1059
|
+
recorded_scenario.results["STREAM_NAME"] == stream_name
|
|
1060
|
+
]
|
|
995
1061
|
if len(stream_results) == 0:
|
|
996
|
-
raise ValueError(
|
|
997
|
-
|
|
1062
|
+
raise ValueError(
|
|
1063
|
+
f"Recorded results for scenario {recorded_scenario.scenario_name} did not contain any results for stream {stream_name}"
|
|
1064
|
+
)
|
|
1065
|
+
# results = pandas.concat(recorded_scenario.results[stream_name])
|
|
998
1066
|
## no need to do this anymore, as the results are already json
|
|
999
1067
|
##results["RECORD_DATA"] = results["RECORD_DATA"].apply(json.dumps)
|
|
1000
|
-
#results["RECORD_DATA"] = results["RECORD_DATA"].replace("|", "\\|")
|
|
1001
|
-
#results.loc[
|
|
1068
|
+
# results["RECORD_DATA"] = results["RECORD_DATA"].replace("|", "\\|")
|
|
1069
|
+
# results.loc[
|
|
1002
1070
|
# results["RECORD_DATA"] == '"null"', "RECORD_DATA"
|
|
1003
|
-
#] = "null"
|
|
1004
|
-
#results = results[
|
|
1071
|
+
# ] = "null"
|
|
1072
|
+
# results = results[
|
|
1005
1073
|
# results.columns.intersection(
|
|
1006
1074
|
# [
|
|
1007
1075
|
# "APP_IDENTIFIER",
|
|
@@ -1010,9 +1078,9 @@ class DevelopmentSession:
|
|
|
1010
1078
|
# "STREAM_NAME",
|
|
1011
1079
|
# ]
|
|
1012
1080
|
# )
|
|
1013
|
-
#]
|
|
1014
|
-
#table_indented = self.dataframe_to_behave_table(results, 3)
|
|
1015
|
-
#f.write(f"{table_indented}\n")
|
|
1081
|
+
# ]
|
|
1082
|
+
# table_indented = self.dataframe_to_behave_table(results, 3)
|
|
1083
|
+
# f.write(f"{table_indented}\n")
|
|
1016
1084
|
|
|
1017
1085
|
f.close()
|
|
1018
1086
|
print("Finished writing feature file")
|