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.
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/PKG-INFO +2 -2
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/pyproject.toml +1 -1
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk/__init__.py +66 -34
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk.egg-info/PKG-INFO +2 -2
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk.egg-info/requires.txt +1 -1
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/README.md +0 -0
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/setup.cfg +0 -0
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk/protos/__init__.py +0 -0
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk/protos/common_pb2.py +0 -0
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk/protos/common_pb2.pyi +0 -0
- {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
- {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
- {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
- {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
- {fivetran_connector_sdk-0.13.17.1 → fivetran_connector_sdk-0.13.22.1}/src/fivetran_connector_sdk.egg-info/SOURCES.txt +0 -0
- {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
- {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
- {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.
|
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:
|
18
|
+
Requires-Dist: unidecode==1.3.8
|
19
19
|
|
20
20
|
# **fivetran-connector-sdk**
|
21
21
|
[](https://pepy.tech/project/fivetran-connector-sdk)
|
@@ -6,7 +6,8 @@ import importlib.util
|
|
6
6
|
import inspect
|
7
7
|
import json
|
8
8
|
import os
|
9
|
-
|
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.
|
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)
|
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
|
-
|
518
|
+
escaped_message = json.dumps(message).strip('"')
|
519
|
+
print(f"{current_time} {level.name}: {escaped_message}")
|
518
520
|
else:
|
519
|
-
|
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
|
-
|
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
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
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,
|
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
|
-
|
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
|
-
|
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
|
849
|
-
|
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
|
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.
|
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:
|
18
|
+
Requires-Dist: unidecode==1.3.8
|
19
19
|
|
20
20
|
# **fivetran-connector-sdk**
|
21
21
|
[](https://pepy.tech/project/fivetran-connector-sdk)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|