fivetran-connector-sdk 0.13.17.1__tar.gz → 0.13.30.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.
Files changed (18) hide show
  1. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/PKG-INFO +2 -2
  2. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/pyproject.toml +1 -1
  3. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk/__init__.py +105 -64
  4. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk.egg-info/PKG-INFO +2 -2
  5. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk.egg-info/requires.txt +1 -1
  6. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/README.md +0 -0
  7. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/setup.cfg +0 -0
  8. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk/protos/__init__.py +0 -0
  9. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk/protos/common_pb2.py +0 -0
  10. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk/protos/common_pb2.pyi +0 -0
  11. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk/protos/common_pb2_grpc.py +0 -0
  12. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk/protos/connector_sdk_pb2.py +0 -0
  13. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk/protos/connector_sdk_pb2.pyi +0 -0
  14. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk/protos/connector_sdk_pb2_grpc.py +0 -0
  15. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk.egg-info/SOURCES.txt +0 -0
  16. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk.egg-info/dependency_links.txt +0 -0
  17. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk.egg-info/entry_points.txt +0 -0
  18. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.30.1}/src/fivetran_connector_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fivetran_connector_sdk
3
- Version: 0.13.17.1
3
+ Version: 0.13.30.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
@@ -15,7 +15,7 @@ Requires-Dist: grpcio==1.60.1
15
15
  Requires-Dist: grpcio-tools==1.60.1
16
16
  Requires-Dist: requests==2.32.3
17
17
  Requires-Dist: pipreqs==0.5.0
18
- Requires-Dist: transliterate==1.10.2
18
+ Requires-Dist: unidecode==1.3.8
19
19
 
20
20
  # **fivetran-connector-sdk**
21
21
  [![Downloads](https://static.pepy.tech/badge/fivetran-connector-sdk)](https://pepy.tech/project/fivetran-connector-sdk)
@@ -17,7 +17,7 @@ dependencies = [
17
17
  "grpcio-tools==1.60.1",
18
18
  "requests==2.32.3",
19
19
  "pipreqs==0.5.0",
20
- "transliterate==1.10.2"
20
+ "unidecode==1.3.8"
21
21
  ]
22
22
 
23
23
  [project.scripts]
@@ -6,7 +6,8 @@ import importlib.util
6
6
  import inspect
7
7
  import json
8
8
  import os
9
- from transliterate import translit
9
+ import unicodedata
10
+ from unidecode import unidecode
10
11
  import platform
11
12
  import requests as rq
12
13
  import shutil
@@ -28,13 +29,13 @@ from fivetran_connector_sdk.protos import connector_sdk_pb2
28
29
  from fivetran_connector_sdk.protos import connector_sdk_pb2_grpc
29
30
 
30
31
  # Version format: <major_version>.<MM>.<DD>.<iteration> (where MM is incremental value from Jan 2024)
31
- __version__ = "0.13.17.1"
32
+ __version__ = "0.13.30.1"
32
33
 
33
34
  MAC_OS = "mac"
34
35
  WIN_OS = "windows"
35
36
  LINUX_OS = "linux"
36
37
 
37
- TESTER_VERSION = "0.25.0117.001"
38
+ TESTER_VERSION = "0.25.0130.001"
38
39
  TESTER_FILENAME = "run_sdk_tester.jar"
39
40
  VERSION_FILENAME = "version.txt"
40
41
  UPLOAD_FILENAME = "code.zip"
@@ -54,11 +55,6 @@ WORD_OR_DOLLAR_PATTERN = re.compile(r'[\w$]')
54
55
  DROP_LEADING_UNDERSCORE = re.compile(r'_+([a-zA-Z]\w*)')
55
56
  WORD_PATTERN = re.compile(r'\w')
56
57
 
57
- # Transliteration rules
58
- TO_ASCII_RULES = (
59
- "Han-Latin; Katakana-Latin; Arabic-Latin; NFD; [:Nonspacing Mark:] Remove; NFC"
60
- )
61
-
62
58
  EXCLUDED_DIRS = ["__pycache__", "lib", "include", OUTPUT_FILES_DIR]
63
59
  EXCLUDED_PIPREQS_DIRS = ["bin,etc,include,lib,Lib,lib64,Scripts,share"]
64
60
  VALID_COMMANDS = ["debug", "deploy", "reset", "version"]
@@ -79,6 +75,7 @@ INSTALLATION_SCRIPT = "installation.sh"
79
75
  DRIVERS = "drivers"
80
76
  JAVA_LONG_MAX_VALUE = 9223372036854775807
81
77
  MAX_CONFIG_FIELDS = 100
78
+ SUPPORTED_PYTHON_VERSIONS = {"3.12.8", "3.11.11", "3.10.16", "3.9.21"}
82
79
 
83
80
 
84
81
  class Logging:
@@ -100,7 +97,7 @@ class Logging:
100
97
  """
101
98
  if DEBUGGING:
102
99
  current_time = datetime.now().strftime("%b %d, %Y %I:%M:%S %p")
103
- escaped_message = json.dumps(message) [1:-1]
100
+ escaped_message = json.dumps(message).strip('"')
104
101
  print(f"{current_time} {level.name}: {escaped_message}")
105
102
  else:
106
103
  escaped_message = json.dumps(message)
@@ -164,13 +161,14 @@ class Operations:
164
161
 
165
162
  responses = []
166
163
 
167
- table = for_table(table)
164
+ table = get_renamed_table_name(table)
168
165
  columns = _get_columns(table)
169
166
  if not columns:
170
167
  global TABLES
171
168
  for field in data.keys():
172
- columns[field] = common_pb2.Column(
173
- name=field, type=common_pb2.DataType.UNSPECIFIED, primary_key=False)
169
+ field_name = get_renamed_column_name(field)
170
+ columns[field_name] = common_pb2.Column(
171
+ name=field_name, type=common_pb2.DataType.UNSPECIFIED, primary_key=False)
174
172
 
175
173
  mapped_data = _map_data_to_columns(data, columns)
176
174
  record = connector_sdk_pb2.Record(
@@ -199,7 +197,7 @@ class Operations:
199
197
  """
200
198
  _yield_check(inspect.stack())
201
199
 
202
- table = for_table(table)
200
+ table = get_renamed_table_name(table)
203
201
  columns = _get_columns(table)
204
202
  mapped_data = _map_data_to_columns(modified, columns)
205
203
  record = connector_sdk_pb2.Record(
@@ -225,7 +223,7 @@ class Operations:
225
223
  """
226
224
  _yield_check(inspect.stack())
227
225
 
228
- table = for_table(table)
226
+ table = get_renamed_table_name(table)
229
227
  columns = _get_columns(table)
230
228
  mapped_data = _map_data_to_columns(keys, columns)
231
229
  record = connector_sdk_pb2.Record(
@@ -316,6 +314,7 @@ def _get_columns(table: str) -> dict:
316
314
  columns = {}
317
315
  if table in TABLES:
318
316
  for column in TABLES[table].columns:
317
+ column.name = get_renamed_column_name(column.name)
319
318
  columns[column.name] = column
320
319
 
321
320
  return columns
@@ -333,12 +332,13 @@ def _map_data_to_columns(data: dict, columns: dict) -> dict:
333
332
  """
334
333
  mapped_data = {}
335
334
  for k, v in data.items():
335
+ key = get_renamed_column_name(k)
336
336
  if v is None:
337
- mapped_data[k] = common_pb2.ValueType(null=True)
338
- elif (k in columns) and columns[k].type != common_pb2.DataType.UNSPECIFIED:
339
- map_defined_data_type(columns, k, mapped_data, v)
337
+ mapped_data[key] = common_pb2.ValueType(null=True)
338
+ elif (key in columns) and columns[key].type != common_pb2.DataType.UNSPECIFIED:
339
+ map_defined_data_type(columns, key, mapped_data, v)
340
340
  else:
341
- map_inferred_data_type(k, mapped_data, v)
341
+ map_inferred_data_type(key, mapped_data, v)
342
342
 
343
343
  return mapped_data
344
344
 
@@ -489,7 +489,7 @@ def log_unused_deps_error(package_name: str, version: str):
489
489
  f" Current version: {version}", Logging.Level.SEVERE)
490
490
 
491
491
 
492
- def validate_deploy_parameters(connection, deploy_key):
492
+ def validate_deploy_parameters(connection, deploy_key, python_version):
493
493
  if not deploy_key or not connection:
494
494
  print_library_log("The deploy command needs the following parameters:"
495
495
  "\n\tRequired:\n"
@@ -504,6 +504,10 @@ def validate_deploy_parameters(connection, deploy_key):
504
504
  f"underscore or a lowercase letter (a-z), followed by any combination of underscores, lowercase "
505
505
  f"letters, or digits (0-9). Uppercase characters are not allowed.", Logging.Level.SEVERE)
506
506
  os._exit(1)
507
+ if python_version and python_version not in SUPPORTED_PYTHON_VERSIONS:
508
+ print_library_log(f"This Python version is not supported: {python_version}. "
509
+ f"We only support the following python versions: {SUPPORTED_PYTHON_VERSIONS} ", Logging.Level.SEVERE)
510
+ os._exit(1)
507
511
 
508
512
  def print_library_log(message: str, level: Logging.Level = Logging.Level.INFO):
509
513
  """Logs a library message with the specified logging level.
@@ -514,9 +518,12 @@ def print_library_log(message: str, level: Logging.Level = Logging.Level.INFO):
514
518
  """
515
519
  if DEBUGGING or EXECUTED_VIA_CLI:
516
520
  current_time = datetime.now().strftime("%b %d, %Y %I:%M:%S %p")
517
- print(f'{current_time} {level.name}: {message}')
521
+ escaped_message = json.dumps(message).strip('"')
522
+ print(f"{current_time} {level.name}: {escaped_message}")
518
523
  else:
519
- print(f'{{"level":"{level.name}", "message": "{message}", "message_origin": "library"}}')
524
+ escaped_message = json.dumps(message)
525
+ log_message = f'{{"level":"{level.name}", "message": {escaped_message}, "message_origin": "library"}}'
526
+ print(log_message)
520
527
 
521
528
 
522
529
  def is_port_in_use(port: int):
@@ -605,7 +612,16 @@ def transliterate(name):
605
612
  """
606
613
  if contains_only_word_dash_dot(name):
607
614
  return name
608
- return translit(name, 'en', reversed=True)
615
+ # Step 1: Normalize the name to NFD form (decomposed form)
616
+ normalized_name = unicodedata.normalize('NFD', name)
617
+ # Step 2: Remove combining characters (diacritics, accents, etc.)
618
+ normalized_name = ''.join(char for char in normalized_name if not unicodedata.combining(char))
619
+ # Step 3: Normalize back to NFC form (composed form)
620
+ normalized_name = unicodedata.normalize('NFC', normalized_name)
621
+ # Step 4: Convert the string to ASCII using `unidecode` (removes any remaining non-ASCII characters)
622
+ normalized_name = unidecode(normalized_name)
623
+ # Step 5: Return the normalized name
624
+ return normalized_name
609
625
 
610
626
 
611
627
  def redshift_safe(name):
@@ -630,13 +646,19 @@ def safe_drop_underscores(name):
630
646
  return safe_name
631
647
 
632
648
 
633
- def for_table(source_table):
649
+ def get_renamed_table_name(source_table):
634
650
  """
635
651
  Process a source table name to ensure it conforms to naming rules.
636
652
  """
637
653
  return safe_drop_underscores(source_table)
638
654
 
639
655
 
656
+ def get_renamed_column_name(source_column):
657
+ """
658
+ Process a source column name to ensure it conforms to naming rules.
659
+ """
660
+ return redshift_safe(source_column)
661
+
640
662
  class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
641
663
  def __init__(self, update, schema=None):
642
664
  """Initializes the Connector instance.
@@ -703,20 +725,31 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
703
725
  force (bool): Force update an existing connection.
704
726
 
705
727
  """
706
- # Run the pipreqs command and capture stderr
707
- result = subprocess.run(
708
- ["pipreqs", "--savepath", "tmp_requirements.txt", "--ignore"] + EXCLUDED_PIPREQS_DIRS,
709
- stderr=subprocess.PIPE,
710
- text=True # Ensures output is in string format
711
- )
712
-
713
- if result.returncode != 0:
714
- print_library_log("pipreqs failed with:", Logging.Level.SEVERE)
715
- print(result.stderr)
716
- sys.exit(1)
717
-
718
728
  # tmp_requirements is only generated when pipreqs command is successful
719
729
  tmp_requirements_file_path = os.path.join(project_path, 'tmp_requirements.txt')
730
+ # Run the pipreqs command and capture stderr
731
+ attempt = 0
732
+ while attempt < MAX_RETRIES:
733
+ attempt += 1
734
+ result = subprocess.run(
735
+ ["pipreqs", project_path, "--savepath", tmp_requirements_file_path, "--ignore"] + EXCLUDED_PIPREQS_DIRS,
736
+ stderr=subprocess.PIPE,
737
+ text=True # Ensures output is in string format
738
+ )
739
+
740
+ if result.returncode == 0:
741
+ break
742
+
743
+ print_library_log(f"Attempt {attempt}: pipreqs check failed.", Logging.Level.WARNING)
744
+
745
+ if attempt < MAX_RETRIES:
746
+ retry_after = 3 ** attempt
747
+ print_library_log(f"Retrying in {retry_after} seconds...", Logging.Level.SEVERE)
748
+ time.sleep(retry_after)
749
+ else:
750
+ print_library_log(f"pipreqs failed after {MAX_RETRIES} attempts with:", Logging.Level.SEVERE)
751
+ print(result.stderr)
752
+ sys.exit(1)
720
753
 
721
754
  tmp_requirements = self.fetch_requirements_as_dict(self, tmp_requirements_file_path)
722
755
  tmp_requirements.pop("fivetran_connector_sdk")
@@ -798,12 +831,11 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
798
831
  return requirements
799
832
 
800
833
  # Call this method to deploy the connector to Fivetran platform
801
- def deploy(self, project_path: str, force: bool, deploy_key: str, group: str, connection: str, configuration: dict = None):
834
+ def deploy(self, args: dict, deploy_key: str, group: str, connection: str, configuration: dict = None):
802
835
  """Deploys the connector to the Fivetran platform.
803
836
 
804
837
  Args:
805
- project_path (str): The path to the connector project.
806
- force (bool): Force update an existing connection.
838
+ args (dict): The command arguments.
807
839
  deploy_key (str): The deployment key.
808
840
  group (str): The group name.
809
841
  connection (str): The connection name.
@@ -814,7 +846,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
814
846
 
815
847
  print_library_log("We support only `.py` files and a `requirements.txt` file as part of the code upload. *No other code files* are supported or uploaded during the deployment process. Ensure that your code is structured accordingly and all dependencies are listed in `requirements.txt`")
816
848
 
817
- validate_deploy_parameters(connection, deploy_key)
849
+ validate_deploy_parameters(connection, deploy_key, args.python_version)
818
850
 
819
851
  _check_dict(configuration, True)
820
852
 
@@ -827,10 +859,15 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
827
859
  "schema": connection,
828
860
  "secrets_list": secrets_list,
829
861
  "sync_method": "DIRECT",
830
- "custom_payloads": [],
862
+ "custom_payloads": []
831
863
  }
832
864
 
833
- self.validate_requirements_file(project_path, True, force)
865
+ # args.python_version is already validated in validate_deploy_parameters - so its safe to add in connection_config
866
+ if args.python_version:
867
+ connection_config["python_version"] = args.python_version
868
+ print_library_log(f"Python version {args.python_version} to be used at runtime.", Logging.Level.INFO)
869
+
870
+ self.validate_requirements_file(args.project_path, True, args.force)
834
871
 
835
872
  group_id, group_name = self.__get_group_info(group, deploy_key)
836
873
  connection_id, service = self.__get_connection_id(connection, group, group_id, deploy_key) or (None, None)
@@ -841,17 +878,19 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
841
878
  f"The connection '{connection}' already exists and does not use the 'Connector SDK' service. You cannot update this connection.", Logging.Level.SEVERE)
842
879
  os._exit(1)
843
880
  else:
844
- if force:
881
+ if args.force:
845
882
  confirm = "y"
846
883
  else:
847
884
  confirm = input(
848
- f"The connection '{connection}' already exists in the destination '{group}'. Updating it will overwrite the existing code and configuration. Do you want to proceed with the update? (Y/N): ")
849
- if confirm.lower() == "y":
885
+ f"The connection '{connection}' already exists in the destination '{group}'. Updating it will overwrite the existing code. Do you want to proceed with the update? (Y/N): ")
886
+ if confirm.lower() == "y" and args.configuration:
887
+ confirm_config = input(f"Your deploy will overwrite the configuration using the values provided in '{args.configuration}': key-value pairs not present in the new configuration will be removed; existing keys' values set in the cofiguration file or in the dashboard will be overwritten with new (empty or non-empty) values; new key-value pairs will be added. Do you want to proceed with the update? (Y/N): ")
888
+ if confirm.lower() == "y" and (not connection_config["secrets_list"] or (confirm_config.lower() == "y")):
850
889
  print_library_log("Updating the connection...\n")
851
890
  self.__upload_project(
852
- project_path, deploy_key, group_id, group_name, connection)
891
+ args.project_path, deploy_key, group_id, group_name, connection)
853
892
  self.__update_connection(
854
- connection_id, connection, group_name, connection_config, deploy_key)
893
+ args, connection_id, connection, group_name, connection_config, deploy_key)
855
894
  print("✓")
856
895
  print_library_log(f"Connector ID: {connection_id}")
857
896
  print_library_log(
@@ -860,7 +899,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
860
899
  print_library_log("Update canceled. The process is now terminating.")
861
900
  os._exit(1)
862
901
  else:
863
- self.__upload_project(project_path, deploy_key,
902
+ self.__upload_project(args.project_path, deploy_key,
864
903
  group_id, group_name, connection)
865
904
  response = self.__create_connection(
866
905
  deploy_key, group_id, connection_config)
@@ -894,17 +933,18 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
894
933
  os._exit(1)
895
934
 
896
935
  @staticmethod
897
- def __update_connection(id: str, name: str, group: str, config: dict, deploy_key: str):
936
+ def __update_connection(args: dict, id: str, name: str, group: str, config: dict, deploy_key: str):
898
937
  """Updates the connection with the given ID, name, group, configuration, and deployment key.
899
938
 
900
939
  Args:
940
+ args (dict): The command arguments.
901
941
  id (str): The connection ID.
902
942
  name (str): The connection name.
903
943
  group (str): The group name.
904
944
  config (dict): The configuration dictionary.
905
945
  deploy_key (str): The deployment key.
906
946
  """
907
- if not config["secrets_list"]:
947
+ if not args.configuration:
908
948
  del config["secrets_list"]
909
949
 
910
950
  resp = rq.patch(f"{PRODUCTION_BASE_URL}/v1/connectors/{id}",
@@ -1130,7 +1170,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1130
1170
 
1131
1171
  if not resp.ok:
1132
1172
  print_library_log(
1133
- f"Unable to retrieve destination details. The request failed with status code: {resp.status_code}. Please ensure you're using a valid base64-encoded API key and try again.", Logging.Level.SEVERE)
1173
+ f"The request failed with status code: {resp.status_code}. Please ensure you're using a valid base64-encoded API key and try again.", Logging.Level.SEVERE)
1134
1174
  os._exit(1)
1135
1175
 
1136
1176
  data = resp.json().get("data", {})
@@ -1203,7 +1243,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1203
1243
  project_path: str = None,
1204
1244
  configuration: dict = None,
1205
1245
  state: dict = None,
1206
- log_level: Logging.Level = Logging.Level.FINE) -> bool:
1246
+ log_level: Logging.Level = Logging.Level.FINE):
1207
1247
  """Tests the connector code by running it with the connector tester.\n
1208
1248
  state.json docs: https://fivetran.com/docs/connectors/connector-sdk/detailed-guide#workingwithstatejsonfile\n
1209
1249
  configuration.json docs: https://fivetran.com/docs/connectors/connector-sdk/detailed-guide#workingwithconfigurationjsonfile
@@ -1213,9 +1253,6 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1213
1253
  configuration (dict): The configuration dictionary, same as configuration.json if present.
1214
1254
  state (dict): The state dictionary, same as state.json if present.
1215
1255
  log_level (Logging.Level): The logging level.
1216
-
1217
- Returns:
1218
- bool: True if there was an error, False otherwise.
1219
1256
  """
1220
1257
  global DEBUGGING
1221
1258
  DEBUGGING = True
@@ -1412,7 +1449,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1412
1449
  else:
1413
1450
  try:
1414
1451
  configuration = self.configuration if self.configuration else request.configuration
1415
- print_library_log("Initiating the 'schema' method call...", Logging.Level.WARNING)
1452
+ print_library_log("Initiating the 'schema' method call...", Logging.Level.INFO)
1416
1453
  response = self.schema_method(configuration)
1417
1454
  self.process_tables(response)
1418
1455
  return connector_sdk_pb2.SchemaResponse(without_schema=common_pb2.TableList(tables=TABLES.values()))
@@ -1428,7 +1465,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1428
1465
  if 'table' not in entry:
1429
1466
  raise ValueError("Entry missing table name: " + entry)
1430
1467
 
1431
- table_name = for_table(entry['table'])
1468
+ table_name = get_renamed_table_name(entry['table'])
1432
1469
 
1433
1470
  if table_name in TABLES:
1434
1471
  raise ValueError("Table already defined: " + table_name)
@@ -1447,13 +1484,15 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1447
1484
 
1448
1485
  def process_primary_keys(self, columns, entry):
1449
1486
  for pkey_name in entry["primary_key"]:
1450
- column = columns[pkey_name] if pkey_name in columns else common_pb2.Column(name=pkey_name)
1487
+ column_name = get_renamed_column_name(pkey_name)
1488
+ column = columns[column_name] if column_name in columns else common_pb2.Column(name=column_name)
1451
1489
  column.primary_key = True
1452
- columns[pkey_name] = column
1490
+ columns[column_name] = column
1453
1491
 
1454
1492
  def process_columns(self, columns, entry):
1455
1493
  for name, type in entry["columns"].items():
1456
- column = columns[name] if name in columns else common_pb2.Column(name=name)
1494
+ column_name = get_renamed_column_name(name)
1495
+ column = columns[column_name] if column_name in columns else common_pb2.Column(name=column_name)
1457
1496
 
1458
1497
  if isinstance(type, str):
1459
1498
  self.process_data_type(column, type)
@@ -1471,7 +1510,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1471
1510
  if "primary_key" in entry and name in entry["primary_key"]:
1472
1511
  column.primary_key = True
1473
1512
 
1474
- columns[name] = column
1513
+ columns[column_name] = column
1475
1514
 
1476
1515
  def process_data_type(self, column, type):
1477
1516
  if type.upper() == "BOOLEAN":
@@ -1519,7 +1558,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1519
1558
  state = self.state if self.state else json.loads(request.state_json)
1520
1559
 
1521
1560
  try:
1522
- print_library_log("Initiating the 'update' method call...", Logging.Level.WARNING)
1561
+ print_library_log("Initiating the 'update' method call...", Logging.Level.INFO)
1523
1562
  for resp in self.update_method(configuration=configuration, state=state):
1524
1563
  if isinstance(resp, list):
1525
1564
  for r in resp:
@@ -1636,7 +1675,8 @@ def main():
1636
1675
  global EXECUTED_VIA_CLI
1637
1676
  EXECUTED_VIA_CLI = True
1638
1677
 
1639
- parser = argparse.ArgumentParser(allow_abbrev=False)
1678
+ parser = argparse.ArgumentParser(allow_abbrev=False, add_help=True)
1679
+ parser._option_string_actions["-h"].help = "Show this help message and exit"
1640
1680
 
1641
1681
  # Positional
1642
1682
  parser.add_argument("command", help="|".join(VALID_COMMANDS))
@@ -1645,10 +1685,11 @@ def main():
1645
1685
  # Optional (Not all of these are valid with every mutually exclusive option below)
1646
1686
  parser.add_argument("--state", type=str, default=None, help="Provide state as JSON string or file")
1647
1687
  parser.add_argument("--configuration", type=str, default=None, help="Provide secrets as JSON file")
1648
- parser.add_argument("--api-key", type=str, default=None, help="Provide api key for deployment to production")
1688
+ parser.add_argument("--api-key", type=str, default=None, help="Provide your base64-encoded API key for deployment")
1649
1689
  parser.add_argument("--destination", type=str, default=None, help="Destination name (aka 'group name')")
1650
1690
  parser.add_argument("--connection", type=str, default=None, help="Connection name (aka 'destination schema')")
1651
1691
  parser.add_argument("-f", "--force", action="store_true", help="Force update an existing connection")
1692
+ parser.add_argument("--python-version", "--python", type=str, help=f"Supported Python versions you can use: {SUPPORTED_PYTHON_VERSIONS}. Defaults to 3.12.8")
1652
1693
 
1653
1694
  args = parser.parse_args()
1654
1695
 
@@ -1677,7 +1718,7 @@ def main():
1677
1718
  if args.command.lower() == "deploy":
1678
1719
  if args.state:
1679
1720
  print_library_log("'state' parameter is not used for 'deploy' command", Logging.Level.WARNING)
1680
- connector_object.deploy(args.project_path, args.force, ft_deploy_key, ft_group, ft_connection, configuration)
1721
+ connector_object.deploy(args, ft_deploy_key, ft_group, ft_connection, configuration)
1681
1722
 
1682
1723
  elif args.command.lower() == "debug":
1683
1724
  connector_object.debug(args.project_path, configuration, state)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fivetran_connector_sdk
3
- Version: 0.13.17.1
3
+ Version: 0.13.30.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
@@ -15,7 +15,7 @@ Requires-Dist: grpcio==1.60.1
15
15
  Requires-Dist: grpcio-tools==1.60.1
16
16
  Requires-Dist: requests==2.32.3
17
17
  Requires-Dist: pipreqs==0.5.0
18
- Requires-Dist: transliterate==1.10.2
18
+ Requires-Dist: unidecode==1.3.8
19
19
 
20
20
  # **fivetran-connector-sdk**
21
21
  [![Downloads](https://static.pepy.tech/badge/fivetran-connector-sdk)](https://pepy.tech/project/fivetran-connector-sdk)
@@ -2,4 +2,4 @@ grpcio==1.60.1
2
2
  grpcio-tools==1.60.1
3
3
  requests==2.32.3
4
4
  pipreqs==0.5.0
5
- transliterate==1.10.2
5
+ unidecode==1.3.8