fivetran-connector-sdk 0.8.12.1__py3-none-any.whl → 0.8.19.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.
@@ -23,7 +23,7 @@ from fivetran_connector_sdk.protos import common_pb2
23
23
  from fivetran_connector_sdk.protos import connector_sdk_pb2
24
24
  from fivetran_connector_sdk.protos import connector_sdk_pb2_grpc
25
25
 
26
- __version__ = "0.8.12.1"
26
+ __version__ = "0.8.19.1"
27
27
 
28
28
  MAC_OS = "mac"
29
29
  WIN_OS = "windows"
@@ -39,6 +39,7 @@ OUTPUT_FILES_DIR = "files"
39
39
  ONE_DAY_IN_SEC = 24 * 60 * 60
40
40
 
41
41
  EXCLUDED_DIRS = ["__pycache__", "lib", "include", OUTPUT_FILES_DIR]
42
+ EXCLUDED_PIPREQS_DIRS = ["bin,etc,include,lib,Lib,lib64,Scripts"]
42
43
 
43
44
  DEBUGGING = False
44
45
  TABLES = {}
@@ -236,7 +237,7 @@ def check_newer_version():
236
237
  obtainer = GetPyPiLatestVersion()
237
238
  latest_version = obtainer('fivetran_connector_sdk')
238
239
  if __version__ < latest_version:
239
- print(f"[notice] A new release of 'fivetran-connector-sdk' available: {latest_version}\n" +
240
+ print(f"[notice] A new release of 'fivetran-connector-sdk' is available: {latest_version}\n" +
240
241
  f"[notice] To update, run: pip install --upgrade fivetran-connector-sdk\n")
241
242
 
242
243
  with open(last_check_file_path, 'w') as f_out:
@@ -279,8 +280,6 @@ def _map_data_to_columns(data: dict, columns: dict) -> dict:
279
280
  for k, v in data.items():
280
281
  if v is None:
281
282
  mapped_data[k] = common_pb2.ValueType(null=True)
282
- elif isinstance(v, list):
283
- raise ValueError("Value type cannot be list")
284
283
  elif (k in columns) and columns[k].type != common_pb2.DataType.UNSPECIFIED:
285
284
  if columns[k].type == common_pb2.DataType.BOOLEAN:
286
285
  mapped_data[k] = common_pb2.ValueType(bool=v)
@@ -325,7 +324,7 @@ def _map_data_to_columns(data: dict, columns: dict) -> dict:
325
324
  elif columns[k].type == common_pb2.DataType.JSON:
326
325
  mapped_data[k] = common_pb2.ValueType(json=json.dumps(v))
327
326
  else:
328
- raise ValueError(f"Unknown data type: {columns[k].type}")
327
+ raise ValueError(f"Unsupported data type encountered: {columns[k].type}. Please use valid data types.")
329
328
  else:
330
329
  # We can infer type from the value
331
330
  if isinstance(v, int):
@@ -340,7 +339,7 @@ def _map_data_to_columns(data: dict, columns: dict) -> dict:
340
339
  elif isinstance(v, bytes):
341
340
  mapped_data[k] = common_pb2.ValueType(binary=v)
342
341
  elif isinstance(v, list):
343
- raise ValueError("Value type cannot be list")
342
+ raise ValueError("Values for the columns cannot be of type 'list'. Please ensure that all values are of a supported type. Reference: https://fivetran.com/docs/connectors/connector-sdk/technical-reference#supporteddatatypes")
344
343
  elif isinstance(v, dict):
345
344
  mapped_data[k] = common_pb2.ValueType(json=json.dumps(v))
346
345
  elif isinstance(v, str):
@@ -371,11 +370,11 @@ def _yield_check(stack):
371
370
  calling_code = stack[1].code_context[0]
372
371
  if f"{called_method}(" in calling_code:
373
372
  if 'yield' not in calling_code:
374
- print(f"ERROR: Please add 'yield' to '{called_method}' operation on line {stack[1].lineno} in file '{stack[1].filename}'")
373
+ print(f"SEVERE: Please add 'yield' to '{called_method}' operation on line {stack[1].lineno} in file '{stack[1].filename}'")
375
374
  os._exit(1)
376
375
  else:
377
376
  # This should never happen
378
- raise RuntimeError(f"Unable to find '{called_method}' function in stack")
377
+ raise RuntimeError(f"The '{called_method}' function is missing in the connector. Please ensure that the '{called_method}' function is properly defined in your code to proceed. Reference: https://fivetran.com/docs/connectors/connector-sdk/technical-reference#technicaldetailsmethods")
379
378
 
380
379
 
381
380
  def _check_dict(incoming: dict, string_only: bool = False) -> dict:
@@ -392,12 +391,12 @@ def _check_dict(incoming: dict, string_only: bool = False) -> dict:
392
391
  return {}
393
392
 
394
393
  if not isinstance(incoming, dict):
395
- raise ValueError("Configuration should be a dictionary")
394
+ raise ValueError("Configuration must be provided as a JSON dictionary. Please check your input. Reference: https://fivetran.com/docs/connectors/connector-sdk/detailed-guide#workingwithconfigurationjsonfile")
396
395
 
397
396
  if string_only:
398
397
  for k, v in incoming.items():
399
398
  if not isinstance(v, str):
400
- print("ERROR: Use only string values in configuration")
399
+ print("SEVERE: All values in the configuration must be STRING. Please check your configuration and ensure that every value is a STRING.")
401
400
  os._exit(1)
402
401
 
403
402
  return incoming
@@ -417,28 +416,6 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
417
416
  self.configuration = None
418
417
  self.state = None
419
418
 
420
- # Call this method to unpause and start a connector
421
- def start(self, deploy_key: str, group: str, connection: str):
422
- """Starts the connector with the given deployment key, group name, and connection schema name.
423
-
424
- Args:
425
- deploy_key (str): The deployment key.
426
- group (str): The group name.
427
- connection (str): The connection schema name.
428
- """
429
- if not deploy_key: print("ERROR: Missing deploy key"); os._exit(1)
430
- if not connection: print("ERROR: Missing connection name"); os._exit(1)
431
-
432
- group_id, group_name = self.__get_group_info(group, deploy_key)
433
- connection_id = self.__get_connection_id(connection, group, group_id, deploy_key)
434
- if not self.__unpause_connection():
435
- print(f"WARNING: Unable to unpause connection '{connection}'")
436
- os._exit(1)
437
-
438
- if not self.__force_sync(connection_id, connection, deploy_key):
439
- print(f"WARNING: Unable to start sync on connection '{connection}'")
440
- os._exit(1)
441
-
442
419
  @staticmethod
443
420
  def __unpause_connection(id: str, deploy_key: str) -> bool:
444
421
  """Unpauses the connection with the given ID and deployment key.
@@ -495,7 +472,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
495
472
  is_deploy (bool): If `True`, the method will exit the process on critical errors.
496
473
 
497
474
  """
498
- subprocess.run(["pipreqs", "--savepath", "tmp_requirements.txt"], text=True, check=True)
475
+ subprocess.run(["pipreqs", "--savepath", "tmp_requirements.txt", "--ignore"] + EXCLUDED_PIPREQS_DIRS, text=True, check=True)
499
476
  tmp_requirements_file_path = os.path.join(project_path, 'tmp_requirements.txt')
500
477
 
501
478
  tmp_requirements = self.fetch_requirements_as_dict(self, tmp_requirements_file_path)
@@ -553,8 +530,8 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
553
530
  connection (str): The connection name.
554
531
  configuration (dict): The configuration dictionary.
555
532
  """
556
- if not deploy_key: print("ERROR: Missing deploy key"); os._exit(1)
557
- if not connection: print("ERROR: Missing connection name"); os._exit(1)
533
+ if not deploy_key: print("SEVERE: The Fivetran API key is missing. Please provide a valid Fivetran API key to create the connector."); os._exit(1)
534
+ if not connection: print("SEVERE: The connection name is missing. Please provide a valid connection name to create the connector."); os._exit(1)
558
535
  _check_dict(configuration)
559
536
 
560
537
  secrets_list = []
@@ -572,7 +549,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
572
549
  self.validate_requirements_file(project_path, True)
573
550
 
574
551
  group_id, group_name = self.__get_group_info(group, deploy_key)
575
- print(f"Deploying '{project_path}' to '{group_name}/{connection}'")
552
+ print(f"INFO: Deploying '{project_path}' to connector '{connection}' in destination '{group_name}'.\n")
576
553
  upload_file_path = self.__create_upload_file(project_path)
577
554
  upload_result = self.__upload(upload_file_path, deploy_key, group_id, connection)
578
555
  os.remove(upload_file_path)
@@ -580,15 +557,15 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
580
557
  os._exit(1)
581
558
  connection_id = self.__get_connection_id(connection, group, group_id, deploy_key)
582
559
  if connection_id:
583
- print(f"Connection '{connection}' already exists in destination '{group}', updating .. ", end="", flush=True)
560
+ print(f"INFO: The connection '{connection}' already exists in destination '{group}', updating the existing connector... ", end="", flush=True)
584
561
  self.__update_connection(connection_id, connection, group_name, connection_config, deploy_key)
585
562
  print("✓")
586
563
  else:
587
564
  response = self.__create_connection(deploy_key, group_id, connection_config)
588
565
  if response.ok:
589
- print(f"New connection with name '{connection}' created")
566
+ print(f"INFO: Connection named '{connection}' has been created successfully.\n")
590
567
  else:
591
- print(f"ERROR: Failed to create new connection: {response.json()['message']}")
568
+ print(f"SEVERE: Unable to create a new Connection, failed with error: {response.json()['message']}")
592
569
  os._exit(1)
593
570
 
594
571
  @staticmethod
@@ -629,7 +606,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
629
606
  })
630
607
 
631
608
  if not resp.ok:
632
- print(f"ERROR: Unable to update connection '{name}' in group '{group}'")
609
+ print(f"SEVERE: Unable to update Connection '{name}' in destination '{group}', failed with error: '{response.json()['message']}'.")
633
610
  os._exit(1)
634
611
 
635
612
  @staticmethod
@@ -649,7 +626,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
649
626
  headers={"Authorization": f"Basic {deploy_key}"},
650
627
  params={"schema": name})
651
628
  if not resp.ok:
652
- print(f"ERROR: Unable to fetch connection list in group '{group}'")
629
+ print(f"SEVERE: Unable to fetch connection list in destination '{group}'")
653
630
  os._exit(1)
654
631
 
655
632
  if resp.json()['data']['items']:
@@ -690,7 +667,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
690
667
  Returns:
691
668
  str: The path to the upload file.
692
669
  """
693
- print("Packaging project for upload ..")
670
+ print("INFO: Packaging your project for upload...")
694
671
  zip_file_path = self.__zip_folder(project_path)
695
672
  print("✓")
696
673
  return zip_file_path
@@ -717,7 +694,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
717
694
  zipf.write(file_path, arcname)
718
695
 
719
696
  if not connector_file_exists:
720
- print("ERROR: Missing connector.py file")
697
+ print("SEVERE: The 'connector.py' file is missing. Please ensure that 'connector.py' is present in your project directory, and that the file name is in lowercase letters. All custom connectors require this file because Fivetran calls it to start a sync.")
721
698
  os._exit(1)
722
699
  return upload_filepath
723
700
 
@@ -759,7 +736,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
759
736
  Returns:
760
737
  bool: True if the upload was successful, False otherwise.
761
738
  """
762
- print("Uploading project .. ", end="", flush=True)
739
+ print("INFO: Uploading your project...", end="", flush=True)
763
740
  response = rq.post(f"https://api.fivetran.com/v2/deploy/{group_id}/{connection}",
764
741
  files={'file': open(local_path, 'rb')},
765
742
  headers={"Authorization": f"Basic {deploy_key}"})
@@ -767,7 +744,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
767
744
  print("✓")
768
745
  return True
769
746
 
770
- print("fail\nERROR: ", response.reason)
747
+ print("SEVERE: Unable to upload the project, failed with error: ", response.reason)
771
748
  return False
772
749
 
773
750
  @staticmethod
@@ -801,27 +778,27 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
801
778
  headers={"Authorization": f"Basic {deploy_key}"})
802
779
 
803
780
  if not resp.ok:
804
- print(f"ERROR: Unable to fetch list of destination names, status code = {resp.status_code}")
781
+ print(f"SEVERE: Unable to fetch list of destination names, status code = {resp.status_code}")
805
782
  os._exit(1)
806
783
 
807
784
  # TODO: Do we need to implement pagination?
808
785
  groups = resp.json()['data']['items']
809
786
  if not groups:
810
- print("ERROR: No destinations defined in the account")
787
+ print("SEVERE: No destinations defined in the account")
811
788
  os._exit(1)
812
789
 
813
790
  if len(groups) == 1:
814
791
  return groups[0]['id'], groups[0]['name']
815
792
  else:
816
793
  if not group:
817
- print("ERROR: Destination name is required when there are multiple destinations in the account")
794
+ print("SEVERE: Destination name is required when there are multiple destinations in the account")
818
795
  os._exit(1)
819
796
 
820
797
  for grp in groups:
821
798
  if grp['name'] == group:
822
799
  return grp['id'], grp['name']
823
800
 
824
- print(f"ERROR: Specified destination was not found in the account: {group}")
801
+ print(f"SEVERE: Specified destination was not found in the account: {group}")
825
802
  os._exit(1)
826
803
 
827
804
  # Call this method to run the connector in production
@@ -899,17 +876,17 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
899
876
  download_filename = f"sdk-connector-tester-{os_name}-{TESTER_VERSION}.zip"
900
877
  download_filepath = os.path.join(tester_root_dir, download_filename)
901
878
  try:
902
- print(f"Downloading connector tester version {TESTER_VERSION} .. ", end="", flush=True)
879
+ print(f"INFO: Downloading connector tester version: {TESTER_VERSION} ", end="", flush=True)
903
880
  download_url = f"https://github.com/fivetran/fivetran_sdk_tools/releases/download/{TESTER_VERSION}/{download_filename}"
904
881
  r = rq.get(download_url)
905
882
  if r.ok:
906
883
  with open(download_filepath, 'wb') as fo:
907
884
  fo.write(r.content)
908
885
  else:
909
- print(f"\nDownload failed, status code: {r.status_code}, url: {download_url}")
886
+ print(f"\nSEVERE: Failed to download the connector tester. Please check your access permissions or try again later ( status code: {r.status_code}), url: {download_url}")
910
887
  os._exit(1)
911
888
  except:
912
- print(f"\nSomething went wrong during download: {traceback.format_exc()}")
889
+ print(f"\nSEVERE: Failed to download the connector tester. Error details: {traceback.format_exc()}")
913
890
  os._exit(1)
914
891
 
915
892
  try:
@@ -924,13 +901,13 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
924
901
  os.chmod(java_exe, st.st_mode | stat.S_IEXEC)
925
902
  print("✓")
926
903
  except:
927
- print(f"\nSomething went wrong during install: ", traceback.format_exc())
904
+ print(f"\nSEVERE: Failed to install the connector tester. Error details: ", traceback.format_exc())
928
905
  shutil.rmtree(tester_root_dir)
929
906
  os._exit(1)
930
907
 
931
908
  project_path = os.getcwd() if project_path is None else project_path
932
909
  self.validate_requirements_file(project_path, False)
933
- print(f"Debugging connector at: {project_path}")
910
+ print(f"INFO: Debugging connector at: {project_path}")
934
911
  server = self.run(port, configuration, state, log_level=log_level)
935
912
 
936
913
  # Uncomment this to run the tester manually
@@ -938,7 +915,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
938
915
 
939
916
  error = False
940
917
  try:
941
- print(f"Starting connector tester..")
918
+ print(f"INFO: Running connector tester...")
942
919
  for log_msg in self.__run_tester(java_exe, tester_root_dir, project_path, port):
943
920
  print(log_msg, end="")
944
921
  except:
@@ -1121,7 +1098,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1121
1098
  elif type.upper() == "JSON":
1122
1099
  column.type = common_pb2.DataType.JSON
1123
1100
  else:
1124
- raise ValueError("Unrecognized column type: ", str(type))
1101
+ raise ValueError("Unrecognized column type encountered:: ", str(type))
1125
1102
 
1126
1103
  elif isinstance(type, dict):
1127
1104
  if type['type'].upper() != "DECIMAL":
@@ -1190,7 +1167,7 @@ def find_connector_object(project_path) -> Connector:
1190
1167
  if '<fivetran_connector_sdk.Connector object at' in str(obj_attr):
1191
1168
  return obj_attr
1192
1169
 
1193
- print("Unable to find connector object")
1170
+ print("SEVERE: The connector object is missing. Please ensure that you have defined a connector object using the correct syntax in your `connector.py` file. Reference: https://fivetran.com/docs/connectors/connector-sdk/technical-reference#technicaldetailsrequiredobjectconnector")
1194
1171
  sys.exit(1)
1195
1172
 
1196
1173
 
@@ -1202,7 +1179,7 @@ def main():
1202
1179
  parser = argparse.ArgumentParser(allow_abbrev=False)
1203
1180
 
1204
1181
  # Positional
1205
- parser.add_argument("command", help="debug|run|deploy|start")
1182
+ parser.add_argument("command", help="debug|deploy")
1206
1183
  parser.add_argument("project_path", nargs='?', default=os.getcwd(), help="Path to connector project directory")
1207
1184
 
1208
1185
  # Optional (Not all of these are valid with every mutually exclusive option below)
@@ -1230,7 +1207,7 @@ def main():
1230
1207
  with open(json_filepath, 'r') as fi:
1231
1208
  configuration = json.load(fi)
1232
1209
  else:
1233
- raise ValueError("Configuration needs to be a JSON file")
1210
+ raise ValueError("Configuration must be provided as a JSON file. Please check your input. Reference: https://fivetran.com/docs/connectors/connector-sdk/detailed-guide#workingwithconfigurationjsonfile")
1234
1211
  else:
1235
1212
  configuration = {}
1236
1213
 
@@ -1251,25 +1228,10 @@ def main():
1251
1228
  print("WARNING: 'state' parameter is not used for 'deploy' command")
1252
1229
  connector_object.deploy(args.project_path, ft_deploy_key, ft_group, ft_connection, configuration)
1253
1230
 
1254
- elif args.command.lower() == "start":
1255
- if args.port:
1256
- print("WARNING: 'port' parameter is not used for 'deploy' command")
1257
- if args.state:
1258
- print("WARNING: 'state' parameter is not used for 'deploy' command")
1259
- connector_object.start(ft_deploy_key, ft_group, ft_connection)
1260
-
1261
1231
  elif args.command.lower() == "debug":
1262
1232
  port = 50051 if not args.port else args.port
1263
1233
  connector_object.debug(args.project_path, port, configuration, state)
1264
1234
 
1265
- elif args.command.lower() == "run":
1266
- try:
1267
- port = 50051 if not args.port else args.port
1268
- connector_object.run(port, configuration, state)
1269
- except:
1270
- Logging.severe(traceback.format_exc())
1271
- os._exit(1)
1272
-
1273
1235
  else:
1274
1236
  raise NotImplementedError("Invalid command: ", args.command)
1275
1237
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fivetran_connector_sdk
3
- Version: 0.8.12.1
3
+ Version: 0.8.19.1
4
4
  Summary: Build custom connectors on Fivetran platform
5
5
  Author-email: Fivetran <developers@fivetran.com>
6
6
  Project-URL: Homepage, https://fivetran.com/docs/connectors/connector-sdk
@@ -1,4 +1,4 @@
1
- fivetran_connector_sdk/__init__.py,sha256=OaXaLM_1xxs7sF6sBAB3aBW4b9DTpc_mR6q23pGgQnw,49697
1
+ fivetran_connector_sdk/__init__.py,sha256=DRdHyxqKeBGsvwYcqe2aCmM3AlVCiqVjbLQvRkfFVs0,49915
2
2
  fivetran_connector_sdk/protos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  fivetran_connector_sdk/protos/common_pb2.py,sha256=kUwVcyZHgLigNR-KnHZn7dHrlxaMnUXqzprsRx6T72M,6831
4
4
  fivetran_connector_sdk/protos/common_pb2.pyi,sha256=S0hdIzoXyyOKD5cjiGeDDLYpQ9J3LjAvu4rCj1JvJWE,9038
@@ -6,8 +6,8 @@ fivetran_connector_sdk/protos/common_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXH
6
6
  fivetran_connector_sdk/protos/connector_sdk_pb2.py,sha256=9Ke_Ti1s0vAeXapfXT-EryrT2-TSGQb8mhs4gxTpUMk,7732
7
7
  fivetran_connector_sdk/protos/connector_sdk_pb2.pyi,sha256=FWYxRgshEF3QDYAE0TM_mv4N2gGvkxCH_uPpxnMc4oA,8406
8
8
  fivetran_connector_sdk/protos/connector_sdk_pb2_grpc.py,sha256=ZfJLp4DW7uP4pFOZ74s_wQ6tD3eIPi-08UfnLwe4tzo,7163
9
- fivetran_connector_sdk-0.8.12.1.dist-info/METADATA,sha256=nZR69biAGw0z-EXCSUTcXXWcIpx1BkkNLQW3RukPAOY,708
10
- fivetran_connector_sdk-0.8.12.1.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
11
- fivetran_connector_sdk-0.8.12.1.dist-info/entry_points.txt,sha256=uQn0KPnFlQmXJfxlk0tifdNsSXWfVlnAFzNqjXZM_xM,57
12
- fivetran_connector_sdk-0.8.12.1.dist-info/top_level.txt,sha256=-_xk2MFY4psIh7jw1lJePMzFb5-vask8_ZtX-UzYWUI,23
13
- fivetran_connector_sdk-0.8.12.1.dist-info/RECORD,,
9
+ fivetran_connector_sdk-0.8.19.1.dist-info/METADATA,sha256=fgkWljNC3yuszXoF9mo6HGx2mw8KvKLAhf6G5uMuxHs,708
10
+ fivetran_connector_sdk-0.8.19.1.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
11
+ fivetran_connector_sdk-0.8.19.1.dist-info/entry_points.txt,sha256=uQn0KPnFlQmXJfxlk0tifdNsSXWfVlnAFzNqjXZM_xM,57
12
+ fivetran_connector_sdk-0.8.19.1.dist-info/top_level.txt,sha256=-_xk2MFY4psIh7jw1lJePMzFb5-vask8_ZtX-UzYWUI,23
13
+ fivetran_connector_sdk-0.8.19.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (72.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5