dc-python-sdk 1.5.45__py3-none-any.whl → 1.5.47__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dc-python-sdk
3
- Version: 1.5.45
3
+ Version: 1.5.47
4
4
  Summary: Data Connector Python SDK
5
5
  Home-page: https://github.com/data-connector/dc-python-sdk
6
6
  Author: DataConnector
@@ -1,4 +1,4 @@
1
- dc_python_sdk-1.5.45.dist-info/licenses/LICENSE,sha256=ACwmltkrXIz5VsEQcrqljq-fat6ZXAMepjXGoe40KtE,1069
1
+ dc_python_sdk-1.5.47.dist-info/licenses/LICENSE,sha256=ACwmltkrXIz5VsEQcrqljq-fat6ZXAMepjXGoe40KtE,1069
2
2
  dc_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  dc_sdk/app.py,sha256=VeGe1q2F71XtZp9VWBUlNowGcF6J-gYsqOu7k2CaeuU,8320
4
4
  dc_sdk/cli.py,sha256=fu4ePzpurYO_URvxyaaUuiptOLqiWiwLoieSbKeni3c,891
@@ -9,22 +9,22 @@ dc_sdk/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  dc_sdk/src/ai.py,sha256=aIKN6TiBKF8ZJYNpcphwWNqtI34Ni36UipxT-AEyQ1I,23321
10
10
  dc_sdk/src/ai_http.py,sha256=9c1X4Sr-2uutTrovHSZVmAacLLwcmFaQ8vA-tOKC0L0,24696
11
11
  dc_sdk/src/mapping.py,sha256=NuXrdE1MuRVRT7ILpc86RrVJq60t6Dl_lnlG1A7Ulks,3653
12
- dc_sdk/src/pipeline.py,sha256=nc7sXc-qNHisUQYdONNB7uosrN69ezNzv8fSiQRRNck,27262
12
+ dc_sdk/src/pipeline.py,sha256=gjStYsUYbI_WOwfn9QpAbnoBL2yEwBsrfaDB61ix0MQ,27032
13
13
  dc_sdk/src/server.py,sha256=2ZhITJhVcj-jd4a-768lAmmmDjTWATGmgwKD-1OVOVI,3028
14
14
  dc_sdk/src/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  dc_sdk/src/models/enums.py,sha256=UwUH7Bnu9SMyl_sgkfhrgFsuA7rM-eQV-b0PEjhTs_U,981
16
16
  dc_sdk/src/models/errors.py,sha256=uD7EDiQUFUZWjYfowJC4cx6Z0X53UoD1ckh7LD2hcWk,11413
17
17
  dc_sdk/src/models/log_templates.py,sha256=gNmU8c9V-fjiraCMSKi3GfojZ6KjJ4EHQst3-G_9OCE,3111
18
- dc_sdk/src/models/pipeline_details.py,sha256=mZPtPw0X-_dctARCV_i8PJRpHgjl4OMk_bplSNGOltg,2859
18
+ dc_sdk/src/models/pipeline_details.py,sha256=025uh8jKWlfgdwYyrS6vXgl8SACXtD3UeoBzEWiaUSw,2938
19
19
  dc_sdk/src/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- dc_sdk/src/services/api.py,sha256=mXX_ELmHWEUgWpYoEzR010LnXXCyB-RrbTmkMnw9o58,7302
20
+ dc_sdk/src/services/api.py,sha256=lI6O4JmlCtNPnSVSwuUJqjIuWe1jRQCZNHCw8pXk3K8,7665
21
21
  dc_sdk/src/services/aws.py,sha256=zYAbTAjQ4bAO_YLfPYCVhdNz9SC_nCy4vAm8HdteHwY,9411
22
22
  dc_sdk/src/services/environment.py,sha256=lKOuDyzFbjdriPVeVy1GGeuZjutzhwUsZCQcF84XyHM,6447
23
23
  dc_sdk/src/services/loader.py,sha256=0zlQm4HOPKffN9Q6YlMv73fCMBsrwkEBnka5rEJTvqU,1175
24
24
  dc_sdk/src/services/logger.py,sha256=GrQGfgYfrzmPYFRHkctDSg54jvN7ObveETTPezYldXs,2055
25
25
  dc_sdk/src/services/session.py,sha256=SpaZ_qnxMbEZO5fxsbjw6WZXVP5JpncnWalgLqB3MYo,423
26
- dc_python_sdk-1.5.45.dist-info/METADATA,sha256=syZWEl2LAbT7SEs1eMhok9MhIGvle5FL8pWslPDAVA0,15980
27
- dc_python_sdk-1.5.45.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
28
- dc_python_sdk-1.5.45.dist-info/entry_points.txt,sha256=HSIKPlg7qer7Atu8oOKVpptahi_ZxqfJE-Bh2bmVSss,43
29
- dc_python_sdk-1.5.45.dist-info/top_level.txt,sha256=gD_FZnF6mZfFU5EmdB2knYHDHKfH5kXJMtSgEZga3BI,7
30
- dc_python_sdk-1.5.45.dist-info/RECORD,,
26
+ dc_python_sdk-1.5.47.dist-info/METADATA,sha256=jjnO75U_GV1ovT2iCGUde9PVZaOGAWzj3UpQhjRh1ZQ,15980
27
+ dc_python_sdk-1.5.47.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
28
+ dc_python_sdk-1.5.47.dist-info/entry_points.txt,sha256=HSIKPlg7qer7Atu8oOKVpptahi_ZxqfJE-Bh2bmVSss,43
29
+ dc_python_sdk-1.5.47.dist-info/top_level.txt,sha256=gD_FZnF6mZfFU5EmdB2knYHDHKfH5kXJMtSgEZga3BI,7
30
+ dc_python_sdk-1.5.47.dist-info/RECORD,,
@@ -37,6 +37,7 @@ class PipelineDetails:
37
37
  self.primary_key_column_nm = row_data.get('primary_key_column_nm')
38
38
  self.updated_date_column_nm = row_data.get('updated_date_column_nm')
39
39
  self.sync_cursor_dsc = row_data.get('sync_cursor_dsc')
40
+ self.pending_sync_cursor_dsc = row_data.get('pending_sync_cursor_dsc')
40
41
 
41
42
  def increment_stage(self):
42
43
  self.stage += 1
dc_sdk/src/pipeline.py CHANGED
@@ -155,7 +155,7 @@ class PipelineConductor:
155
155
  self._update_extracted_sync_cursor(results.get("metadata"))
156
156
 
157
157
  if self._should_track_sync_cursor():
158
- self._upload_extracted_sync_cursor()
158
+ self._save_pending_sync_cursor()
159
159
 
160
160
  self.log(self.log_templates.GET_DATA_FINISH.format(self.row_count, self.pipeline_details.source_object_id))
161
161
 
@@ -256,60 +256,58 @@ class PipelineConductor:
256
256
  if self.extracted_sync_cursor is None or sync_cursor > self.extracted_sync_cursor:
257
257
  self.extracted_sync_cursor = sync_cursor
258
258
 
259
- def _get_sync_cursor_key_name(self):
260
- return f"transfers/e{self.pipeline_run_history_id}-sync_cursor.json"
259
+ def _save_pending_sync_cursor(self):
260
+ if not self._should_track_sync_cursor():
261
+ return
261
262
 
262
- def _upload_extracted_sync_cursor(self):
263
263
  if self.extracted_sync_cursor is None:
264
+ self.internal_log(
265
+ "Stay in Sync: no sync cursor value was extracted from source data."
266
+ )
264
267
  return
265
268
 
266
- payload = json.dumps({"sync_cursor": self.extracted_sync_cursor})
267
- json_buffer = io.StringIO(payload)
268
- key_name = self._get_sync_cursor_key_name()
269
-
270
- if PipelineEnvironment.platform == "aws":
271
- self.aws.upload_object(key_name, json_buffer=json_buffer)
272
- elif PipelineEnvironment.platform == "azure":
273
- key_name = f"{PipelineEnvironment.app_env}/{key_name}"
274
- self.azure.upload_object(key_name, json_buffer=json_buffer)
275
-
276
- self.internal_log(f"Uploaded sync cursor sidecar to {key_name}")
277
-
278
- def _load_extracted_sync_cursor(self):
279
- key_name = self._get_sync_cursor_key_name()
269
+ if self.mode != "prod":
270
+ self.internal_log(
271
+ f"Stay in Sync: extracted sync cursor {self.extracted_sync_cursor} (dev mode; not saved)."
272
+ )
273
+ return
280
274
 
281
275
  try:
282
- if PipelineEnvironment.platform == "aws":
283
- file_object = self.aws.download_object(key_name)
284
- elif PipelineEnvironment.platform == "azure":
285
- file_object = self.azure.download_object(
286
- f"{PipelineEnvironment.app_env}/{key_name}"
287
- )
288
- else:
289
- return None
290
-
291
- payload = json.load(file_object)
292
- return payload.get("sync_cursor")
276
+ self.api.save_pending_sync_cursor(
277
+ self.pipeline_id, self.extracted_sync_cursor
278
+ )
279
+ self.log(
280
+ f"Stay in Sync: saved pending sync cursor {self.extracted_sync_cursor}."
281
+ )
293
282
  except Exception as e:
294
- self.internal_log(f"No sync cursor sidecar found: {e}")
295
- return None
283
+ self.log(
284
+ f"Stay in Sync: failed to save pending sync cursor {self.extracted_sync_cursor}. {e}"
285
+ )
296
286
 
297
287
  def _persist_sync_cursor_after_load(self):
298
288
  if self.task != "DESTINATION":
299
289
  return
300
290
 
301
- sync_cursor = self._load_extracted_sync_cursor()
302
- if sync_cursor is None:
291
+ if self.mode != "prod":
303
292
  return
304
293
 
305
- if self.mode == "prod":
306
- self.api.save_sync_cursor(self.pipeline_id, sync_cursor)
307
-
308
- if PipelineEnvironment.platform == "aws":
309
- self.aws.delete_object(self._get_sync_cursor_key_name())
310
- elif PipelineEnvironment.platform == "azure":
311
- self.azure.delete_object(
312
- f"{PipelineEnvironment.app_env}/{self._get_sync_cursor_key_name()}"
294
+ try:
295
+ result = self.api.commit_sync_cursor(self.pipeline_id)
296
+ if result.get("committed"):
297
+ sync_cursor_dsc = result.get("sync_cursor_dsc", "")
298
+ self.log(
299
+ f"Stay in Sync: committed sync cursor {sync_cursor_dsc}."
300
+ )
301
+ else:
302
+ self.log(
303
+ "Stay in Sync: destination load finished but no pending sync cursor was committed."
304
+ )
305
+ except Exception as e:
306
+ self.log(
307
+ f"Stay in Sync: failed to commit sync cursor during destination load. {e}"
308
+ )
309
+ self.internal_log(
310
+ "Stay in Sync: commit will be retried when the pipeline run history is finalized."
313
311
  )
314
312
 
315
313
  def _call_connector_load_data(
@@ -113,6 +113,18 @@ class DataConnectorAPI:
113
113
 
114
114
  self.post(f"{pipeline_id}/mapping", body)
115
115
 
116
+ def save_pending_sync_cursor(self, pipeline_id, pending_sync_cursor):
117
+ self.put(
118
+ f"{pipeline_id}/pending-sync-cursor",
119
+ {"pending_sync_cursor_dsc": pending_sync_cursor},
120
+ )
121
+
122
+ def commit_sync_cursor(self, pipeline_id):
123
+ self.put(
124
+ f"{pipeline_id}/sync-cursor",
125
+ {"commit": True},
126
+ )
127
+
116
128
  def save_sync_cursor(self, pipeline_id, sync_cursor):
117
129
  self.put(
118
130
  f"{pipeline_id}/sync-cursor",