fivetran-connector-sdk 0.13.17.1__tar.gz → 0.13.22.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.22.1}/PKG-INFO +2 -2
  2. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/pyproject.toml +1 -1
  3. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk/__init__.py +66 -34
  4. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk.egg-info/PKG-INFO +2 -2
  5. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk.egg-info/requires.txt +1 -1
  6. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/README.md +0 -0
  7. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/setup.cfg +0 -0
  8. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk/protos/__init__.py +0 -0
  9. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk/protos/common_pb2.py +0 -0
  10. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk/protos/common_pb2.pyi +0 -0
  11. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.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.22.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.22.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.22.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.22.1}/src/fivetran_connector_sdk.egg-info/SOURCES.txt +0 -0
  16. {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.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.22.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.22.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.22.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,7 +29,7 @@ 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.22.1"
32
33
 
33
34
  MAC_OS = "mac"
34
35
  WIN_OS = "windows"
@@ -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)
@@ -489,7 +486,7 @@ def log_unused_deps_error(package_name: str, version: str):
489
486
  f" Current version: {version}", Logging.Level.SEVERE)
490
487
 
491
488
 
492
- def validate_deploy_parameters(connection, deploy_key):
489
+ def validate_deploy_parameters(connection, deploy_key, python_version):
493
490
  if not deploy_key or not connection:
494
491
  print_library_log("The deploy command needs the following parameters:"
495
492
  "\n\tRequired:\n"
@@ -504,6 +501,10 @@ def validate_deploy_parameters(connection, deploy_key):
504
501
  f"underscore or a lowercase letter (a-z), followed by any combination of underscores, lowercase "
505
502
  f"letters, or digits (0-9). Uppercase characters are not allowed.", Logging.Level.SEVERE)
506
503
  os._exit(1)
504
+ if python_version and python_version not in SUPPORTED_PYTHON_VERSIONS:
505
+ print_library_log(f"This Python version is not supported: {python_version}. "
506
+ f"We only support the following python versions: {SUPPORTED_PYTHON_VERSIONS} ", Logging.Level.SEVERE)
507
+ os._exit(1)
507
508
 
508
509
  def print_library_log(message: str, level: Logging.Level = Logging.Level.INFO):
509
510
  """Logs a library message with the specified logging level.
@@ -514,9 +515,12 @@ def print_library_log(message: str, level: Logging.Level = Logging.Level.INFO):
514
515
  """
515
516
  if DEBUGGING or EXECUTED_VIA_CLI:
516
517
  current_time = datetime.now().strftime("%b %d, %Y %I:%M:%S %p")
517
- print(f'{current_time} {level.name}: {message}')
518
+ escaped_message = json.dumps(message).strip('"')
519
+ print(f"{current_time} {level.name}: {escaped_message}")
518
520
  else:
519
- print(f'{{"level":"{level.name}", "message": "{message}", "message_origin": "library"}}')
521
+ escaped_message = json.dumps(message)
522
+ log_message = f'{{"level":"{level.name}", "message": {escaped_message}, "message_origin": "library"}}'
523
+ print(log_message)
520
524
 
521
525
 
522
526
  def is_port_in_use(port: int):
@@ -605,7 +609,16 @@ def transliterate(name):
605
609
  """
606
610
  if contains_only_word_dash_dot(name):
607
611
  return name
608
- return translit(name, 'en', reversed=True)
612
+ # Step 1: Normalize the name to NFD form (decomposed form)
613
+ normalized_name = unicodedata.normalize('NFD', name)
614
+ # Step 2: Remove combining characters (diacritics, accents, etc.)
615
+ normalized_name = ''.join(char for char in normalized_name if not unicodedata.combining(char))
616
+ # Step 3: Normalize back to NFC form (composed form)
617
+ normalized_name = unicodedata.normalize('NFC', normalized_name)
618
+ # Step 4: Convert the string to ASCII using `unidecode` (removes any remaining non-ASCII characters)
619
+ normalized_name = unidecode(normalized_name)
620
+ # Step 5: Return the normalized name
621
+ return normalized_name
609
622
 
610
623
 
611
624
  def redshift_safe(name):
@@ -704,16 +717,28 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
704
717
 
705
718
  """
706
719
  # 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)
720
+ attempt = 0
721
+ while attempt < MAX_RETRIES:
722
+ attempt += 1
723
+ result = subprocess.run(
724
+ ["pipreqs", "--savepath", "tmp_requirements.txt", "--ignore"] + EXCLUDED_PIPREQS_DIRS,
725
+ stderr=subprocess.PIPE,
726
+ text=True # Ensures output is in string format
727
+ )
728
+
729
+ if result.returncode == 0:
730
+ break
731
+
732
+ print_library_log(f"Attempt {attempt}: pipreqs check failed.", Logging.Level.WARNING)
733
+
734
+ if attempt < MAX_RETRIES:
735
+ retry_after = 3 ** attempt
736
+ print_library_log(f"Retrying in {retry_after} seconds...", Logging.Level.SEVERE)
737
+ time.sleep(retry_after)
738
+ else:
739
+ print_library_log(f"pipreqs failed after {MAX_RETRIES} attempts with:", Logging.Level.SEVERE)
740
+ print(result.stderr)
741
+ sys.exit(1)
717
742
 
718
743
  # tmp_requirements is only generated when pipreqs command is successful
719
744
  tmp_requirements_file_path = os.path.join(project_path, 'tmp_requirements.txt')
@@ -798,12 +823,11 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
798
823
  return requirements
799
824
 
800
825
  # 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):
826
+ def deploy(self, args: dict, deploy_key: str, group: str, connection: str, configuration: dict = None):
802
827
  """Deploys the connector to the Fivetran platform.
803
828
 
804
829
  Args:
805
- project_path (str): The path to the connector project.
806
- force (bool): Force update an existing connection.
830
+ args (dict): The command arguments.
807
831
  deploy_key (str): The deployment key.
808
832
  group (str): The group name.
809
833
  connection (str): The connection name.
@@ -814,7 +838,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
814
838
 
815
839
  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
840
 
817
- validate_deploy_parameters(connection, deploy_key)
841
+ validate_deploy_parameters(connection, deploy_key, args.python_version)
818
842
 
819
843
  _check_dict(configuration, True)
820
844
 
@@ -827,10 +851,15 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
827
851
  "schema": connection,
828
852
  "secrets_list": secrets_list,
829
853
  "sync_method": "DIRECT",
830
- "custom_payloads": [],
854
+ "custom_payloads": []
831
855
  }
832
856
 
833
- self.validate_requirements_file(project_path, True, force)
857
+ # args.python_version is already validated in validate_deploy_parameters - so its safe to add in connection_config
858
+ if args.python_version:
859
+ connection_config["python_version"] = args.python_version
860
+ print_library_log(f"Python version {args.python_version} to be used at runtime.", Logging.Level.INFO)
861
+
862
+ self.validate_requirements_file(args.project_path, True, args.force)
834
863
 
835
864
  group_id, group_name = self.__get_group_info(group, deploy_key)
836
865
  connection_id, service = self.__get_connection_id(connection, group, group_id, deploy_key) or (None, None)
@@ -841,15 +870,17 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
841
870
  f"The connection '{connection}' already exists and does not use the 'Connector SDK' service. You cannot update this connection.", Logging.Level.SEVERE)
842
871
  os._exit(1)
843
872
  else:
844
- if force:
873
+ if args.force:
845
874
  confirm = "y"
846
875
  else:
847
876
  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":
877
+ 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): ")
878
+ if confirm.lower() == "y" and connection_config["secrets_list"]:
879
+ 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): ")
880
+ if confirm.lower() == "y" and (not connection_config["secrets_list"] or (confirm_config.lower() == "y")):
850
881
  print_library_log("Updating the connection...\n")
851
882
  self.__upload_project(
852
- project_path, deploy_key, group_id, group_name, connection)
883
+ args.project_path, deploy_key, group_id, group_name, connection)
853
884
  self.__update_connection(
854
885
  connection_id, connection, group_name, connection_config, deploy_key)
855
886
  print("✓")
@@ -860,7 +891,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
860
891
  print_library_log("Update canceled. The process is now terminating.")
861
892
  os._exit(1)
862
893
  else:
863
- self.__upload_project(project_path, deploy_key,
894
+ self.__upload_project(args.project_path, deploy_key,
864
895
  group_id, group_name, connection)
865
896
  response = self.__create_connection(
866
897
  deploy_key, group_id, connection_config)
@@ -1649,6 +1680,7 @@ def main():
1649
1680
  parser.add_argument("--destination", type=str, default=None, help="Destination name (aka 'group name')")
1650
1681
  parser.add_argument("--connection", type=str, default=None, help="Connection name (aka 'destination schema')")
1651
1682
  parser.add_argument("-f", "--force", action="store_true", help="Force update an existing connection")
1683
+ 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
1684
 
1653
1685
  args = parser.parse_args()
1654
1686
 
@@ -1677,7 +1709,7 @@ def main():
1677
1709
  if args.command.lower() == "deploy":
1678
1710
  if args.state:
1679
1711
  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)
1712
+ connector_object.deploy(args, ft_deploy_key, ft_group, ft_connection, configuration)
1681
1713
 
1682
1714
  elif args.command.lower() == "debug":
1683
1715
  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.22.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