fivetran-connector-sdk 0.12.17.1__py3-none-any.whl → 0.13.16.2__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.
- fivetran_connector_sdk/__init__.py +199 -27
- {fivetran_connector_sdk-0.12.17.1.dist-info → fivetran_connector_sdk-0.13.16.2.dist-info}/METADATA +3 -2
- {fivetran_connector_sdk-0.12.17.1.dist-info → fivetran_connector_sdk-0.13.16.2.dist-info}/RECORD +6 -6
- {fivetran_connector_sdk-0.12.17.1.dist-info → fivetran_connector_sdk-0.13.16.2.dist-info}/WHEEL +1 -1
- {fivetran_connector_sdk-0.12.17.1.dist-info → fivetran_connector_sdk-0.13.16.2.dist-info}/entry_points.txt +0 -0
- {fivetran_connector_sdk-0.12.17.1.dist-info → fivetran_connector_sdk-0.13.16.2.dist-info}/top_level.txt +0 -0
@@ -6,6 +6,7 @@ import importlib.util
|
|
6
6
|
import inspect
|
7
7
|
import json
|
8
8
|
import os
|
9
|
+
from transliterate import translit
|
9
10
|
import platform
|
10
11
|
import requests as rq
|
11
12
|
import shutil
|
@@ -26,13 +27,14 @@ from fivetran_connector_sdk.protos import common_pb2
|
|
26
27
|
from fivetran_connector_sdk.protos import connector_sdk_pb2
|
27
28
|
from fivetran_connector_sdk.protos import connector_sdk_pb2_grpc
|
28
29
|
|
29
|
-
|
30
|
+
# Version format: <major_version>.<MM>.<DD>.<iteration> (where MM is incremental value from Jan 2024)
|
31
|
+
__version__ = "0.13.16.2"
|
30
32
|
|
31
33
|
MAC_OS = "mac"
|
32
34
|
WIN_OS = "windows"
|
33
35
|
LINUX_OS = "linux"
|
34
36
|
|
35
|
-
TESTER_VERSION = "0.
|
37
|
+
TESTER_VERSION = "0.25.0116.001"
|
36
38
|
TESTER_FILENAME = "run_sdk_tester.jar"
|
37
39
|
VERSION_FILENAME = "version.txt"
|
38
40
|
UPLOAD_FILENAME = "code.zip"
|
@@ -45,6 +47,18 @@ PYPI_PACKAGE_DETAILS_URL = "https://pypi.org/pypi/fivetran_connector_sdk/json"
|
|
45
47
|
ONE_DAY_IN_SEC = 24 * 60 * 60
|
46
48
|
MAX_RETRIES = 3
|
47
49
|
|
50
|
+
# Compile patterns used in the implementation
|
51
|
+
WORD_DASH_DOT_PATTERN = re.compile(r'^[\w.-]*$')
|
52
|
+
NON_WORD_PATTERN = re.compile(r'\W')
|
53
|
+
WORD_OR_DOLLAR_PATTERN = re.compile(r'[\w$]')
|
54
|
+
DROP_LEADING_UNDERSCORE = re.compile(r'_+([a-zA-Z]\w*)')
|
55
|
+
WORD_PATTERN = re.compile(r'\w')
|
56
|
+
|
57
|
+
# Transliteration rules
|
58
|
+
TO_ASCII_RULES = (
|
59
|
+
"Han-Latin; Katakana-Latin; Arabic-Latin; NFD; [:Nonspacing Mark:] Remove; NFC"
|
60
|
+
)
|
61
|
+
|
48
62
|
EXCLUDED_DIRS = ["__pycache__", "lib", "include", OUTPUT_FILES_DIR]
|
49
63
|
EXCLUDED_PIPREQS_DIRS = ["bin,etc,include,lib,Lib,lib64,Scripts,share"]
|
50
64
|
VALID_COMMANDS = ["debug", "deploy", "reset", "version"]
|
@@ -60,7 +74,9 @@ DEBUGGING = False
|
|
60
74
|
EXECUTED_VIA_CLI = False
|
61
75
|
PRODUCTION_BASE_URL = "https://api.fivetran.com"
|
62
76
|
TABLES = {}
|
63
|
-
|
77
|
+
INSTALLATION_SCRIPT_MISSING_MESSAGE = "The 'installation.sh' file is missing in the 'drivers' directory. Please ensure that 'installation.sh' is present to properly configure drivers."
|
78
|
+
INSTALLATION_SCRIPT = "installation.sh"
|
79
|
+
DRIVERS = "drivers"
|
64
80
|
JAVA_LONG_MAX_VALUE = 9223372036854775807
|
65
81
|
MAX_CONFIG_FIELDS = 100
|
66
82
|
|
@@ -84,9 +100,12 @@ class Logging:
|
|
84
100
|
"""
|
85
101
|
if DEBUGGING:
|
86
102
|
current_time = datetime.now().strftime("%b %d, %Y %I:%M:%S %p")
|
87
|
-
|
103
|
+
escaped_message = json.dumps(message) [1:-1]
|
104
|
+
print(f"{current_time} {level.name}: {escaped_message}")
|
88
105
|
else:
|
89
|
-
|
106
|
+
escaped_message = json.dumps(message)
|
107
|
+
log_message = f'{{"level":"{level.name}", "message": {escaped_message}, "message_origin": "connector_sdk"}}'
|
108
|
+
print(log_message)
|
90
109
|
|
91
110
|
@staticmethod
|
92
111
|
def fine(message: str):
|
@@ -145,6 +164,7 @@ class Operations:
|
|
145
164
|
|
146
165
|
responses = []
|
147
166
|
|
167
|
+
table = for_table(table)
|
148
168
|
columns = _get_columns(table)
|
149
169
|
if not columns:
|
150
170
|
global TABLES
|
@@ -179,6 +199,7 @@ class Operations:
|
|
179
199
|
"""
|
180
200
|
_yield_check(inspect.stack())
|
181
201
|
|
202
|
+
table = for_table(table)
|
182
203
|
columns = _get_columns(table)
|
183
204
|
mapped_data = _map_data_to_columns(modified, columns)
|
184
205
|
record = connector_sdk_pb2.Record(
|
@@ -204,6 +225,7 @@ class Operations:
|
|
204
225
|
"""
|
205
226
|
_yield_check(inspect.stack())
|
206
227
|
|
228
|
+
table = for_table(table)
|
207
229
|
columns = _get_columns(table)
|
208
230
|
mapped_data = _map_data_to_columns(keys, columns)
|
209
231
|
record = connector_sdk_pb2.Record(
|
@@ -465,7 +487,6 @@ def log_unused_deps_error(package_name: str, version: str):
|
|
465
487
|
print_library_log(f"Please remove `{package_name}` from requirements.txt."
|
466
488
|
f" The latest version of `{package_name}` is always available when executing your code."
|
467
489
|
f" Current version: {version}", Logging.Level.SEVERE)
|
468
|
-
os._exit(1)
|
469
490
|
|
470
491
|
|
471
492
|
def validate_deploy_parameters(connection, deploy_key):
|
@@ -522,6 +543,100 @@ def update_base_url_if_required():
|
|
522
543
|
print_library_log(f"Updating PRODUCTION_BASE_URL to: {base_url}")
|
523
544
|
|
524
545
|
|
546
|
+
def is_special(c):
|
547
|
+
"""Check if the character is a special character."""
|
548
|
+
return not WORD_OR_DOLLAR_PATTERN.fullmatch(c)
|
549
|
+
|
550
|
+
|
551
|
+
def starts_word(previous, current):
|
552
|
+
"""
|
553
|
+
Check if the current character starts a new word based on the previous character.
|
554
|
+
"""
|
555
|
+
return (previous and previous.islower() and current.isupper()) or (
|
556
|
+
previous and previous.isdigit() != current.isdigit()
|
557
|
+
)
|
558
|
+
|
559
|
+
|
560
|
+
def underscore_invalid_leading_character(name, valid_leading_regex):
|
561
|
+
"""
|
562
|
+
Ensure the name starts with a valid leading character.
|
563
|
+
"""
|
564
|
+
if name and not valid_leading_regex.match(name[0]):
|
565
|
+
name = f'_{name}'
|
566
|
+
return name
|
567
|
+
|
568
|
+
|
569
|
+
def single_underscore_case(name):
|
570
|
+
"""
|
571
|
+
Convert the input name to single underscore case, replacing special characters and spaces.
|
572
|
+
"""
|
573
|
+
acc = []
|
574
|
+
previous = None
|
575
|
+
|
576
|
+
for char_index, c in enumerate(name):
|
577
|
+
if char_index == 0 and c == '$':
|
578
|
+
acc.append('_')
|
579
|
+
elif is_special(c):
|
580
|
+
acc.append('_')
|
581
|
+
elif c == ' ':
|
582
|
+
acc.append('_')
|
583
|
+
elif starts_word(previous, c):
|
584
|
+
acc.append('_')
|
585
|
+
acc.append(c.lower())
|
586
|
+
else:
|
587
|
+
acc.append(c.lower())
|
588
|
+
|
589
|
+
previous = c
|
590
|
+
|
591
|
+
name = ''.join(acc)
|
592
|
+
return re.sub(r'_+', '_', name)
|
593
|
+
|
594
|
+
|
595
|
+
def contains_only_word_dash_dot(name):
|
596
|
+
"""
|
597
|
+
Check if the name contains only word characters, dashes, and dots.
|
598
|
+
"""
|
599
|
+
return bool(WORD_DASH_DOT_PATTERN.fullmatch(name))
|
600
|
+
|
601
|
+
|
602
|
+
def transliterate(name):
|
603
|
+
"""
|
604
|
+
Transliterate the input name if it contains non-word, dash, or dot characters.
|
605
|
+
"""
|
606
|
+
if contains_only_word_dash_dot(name):
|
607
|
+
return name
|
608
|
+
return translit(name, 'en', reversed=True)
|
609
|
+
|
610
|
+
|
611
|
+
def redshift_safe(name):
|
612
|
+
"""
|
613
|
+
Make the name safe for use in Redshift.
|
614
|
+
"""
|
615
|
+
name = transliterate(name)
|
616
|
+
name = NON_WORD_PATTERN.sub('_', name)
|
617
|
+
name = single_underscore_case(name)
|
618
|
+
name = underscore_invalid_leading_character(name, WORD_PATTERN)
|
619
|
+
return name
|
620
|
+
|
621
|
+
|
622
|
+
def safe_drop_underscores(name):
|
623
|
+
"""
|
624
|
+
Drop leading underscores if the name starts with valid characters after sanitization.
|
625
|
+
"""
|
626
|
+
safe_name = redshift_safe(name)
|
627
|
+
match = DROP_LEADING_UNDERSCORE.match(safe_name)
|
628
|
+
if match:
|
629
|
+
return match.group(1)
|
630
|
+
return safe_name
|
631
|
+
|
632
|
+
|
633
|
+
def for_table(source_table):
|
634
|
+
"""
|
635
|
+
Process a source table name to ensure it conforms to naming rules.
|
636
|
+
"""
|
637
|
+
return safe_drop_underscores(source_table)
|
638
|
+
|
639
|
+
|
525
640
|
class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
526
641
|
def __init__(self, update, schema=None):
|
527
642
|
"""Initializes the Connector instance.
|
@@ -574,7 +689,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
574
689
|
print_library_log(f"Invalid requirement format: '{requirement}'", Logging.Level.SEVERE)
|
575
690
|
return requirements_dict
|
576
691
|
|
577
|
-
def validate_requirements_file(self, project_path: str, is_deploy: bool):
|
692
|
+
def validate_requirements_file(self, project_path: str, is_deploy: bool, force: bool = False):
|
578
693
|
"""Validates the `requirements.txt` file against the project's actual dependencies.
|
579
694
|
|
580
695
|
This method generates a temporary requirements file using `pipreqs`, compares
|
@@ -585,10 +700,22 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
585
700
|
Args:
|
586
701
|
project_path (str): The path to the project directory containing the `requirements.txt`.
|
587
702
|
is_deploy (bool): If `True`, the method will exit the process on critical errors.
|
703
|
+
force (bool): Force update an existing connection.
|
588
704
|
|
589
705
|
"""
|
590
|
-
|
591
|
-
|
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
|
+
# tmp_requirements is only generated when pipreqs command is successful
|
592
719
|
tmp_requirements_file_path = os.path.join(project_path, 'tmp_requirements.txt')
|
593
720
|
|
594
721
|
tmp_requirements = self.fetch_requirements_as_dict(self, tmp_requirements_file_path)
|
@@ -597,6 +724,11 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
597
724
|
tmp_requirements.pop("requests")
|
598
725
|
os.remove(tmp_requirements_file_path)
|
599
726
|
|
727
|
+
# remove corrupt requirements listed by pipreqs
|
728
|
+
corrupt_requirements = [key for key in tmp_requirements if key.startswith("~")]
|
729
|
+
for requirement in corrupt_requirements:
|
730
|
+
del tmp_requirements[requirement]
|
731
|
+
|
600
732
|
if len(tmp_requirements) > 0:
|
601
733
|
requirements = self.load_or_add_requirements_file(project_path)
|
602
734
|
|
@@ -609,11 +741,26 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
609
741
|
|
610
742
|
missing_deps = {key: tmp_requirements[key] for key in (tmp_requirements.keys() - requirements.keys())}
|
611
743
|
if missing_deps:
|
612
|
-
self.handle_missing_deps(
|
744
|
+
self.handle_missing_deps(missing_deps)
|
613
745
|
|
614
746
|
unused_deps = list(requirements.keys() - tmp_requirements.keys())
|
615
747
|
if unused_deps:
|
616
748
|
self.handle_unused_deps(unused_deps)
|
749
|
+
|
750
|
+
if is_deploy and (version_mismatch_deps or missing_deps or unused_deps):
|
751
|
+
if force:
|
752
|
+
confirm = "y"
|
753
|
+
else:
|
754
|
+
confirm = input("We detected issues in your requirements.txt. "
|
755
|
+
"Would you like us to update it to reflect the necessary changes? (Y/N):")
|
756
|
+
if confirm.lower() == "y":
|
757
|
+
with open(REQUIREMENTS_TXT, "w") as file:
|
758
|
+
file.write("\n".join(tmp_requirements.values()))
|
759
|
+
print_library_log(f"`{REQUIREMENTS_TXT}` has been updated successfully")
|
760
|
+
else:
|
761
|
+
if missing_deps or 'fivetran_connector_sdk' in unused_deps or 'requests' in unused_deps:
|
762
|
+
print_library_log(f"Please fix your {REQUIREMENTS_TXT} file to proceed with deployment.")
|
763
|
+
os._exit(1)
|
617
764
|
else:
|
618
765
|
if os.path.exists(REQUIREMENTS_TXT):
|
619
766
|
print_library_log("`requirements.txt` is not required as no additional "
|
@@ -632,15 +779,13 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
632
779
|
"they are not used or already installed. Please remove them from requirements.txt:")
|
633
780
|
print(*unused_deps)
|
634
781
|
|
635
|
-
def handle_missing_deps(self,
|
782
|
+
def handle_missing_deps(self, missing_deps):
|
636
783
|
print_library_log("Please include the following dependency libraries in requirements.txt, to be used by "
|
637
784
|
"Fivetran production. "
|
638
785
|
"For more information, please visit: "
|
639
786
|
"https://fivetran.com/docs/connectors/connector-sdk/detailed-guide"
|
640
787
|
"#workingwithrequirementstxtfile", Logging.Level.SEVERE)
|
641
788
|
print(*list(missing_deps.values()))
|
642
|
-
if is_deploy:
|
643
|
-
os._exit(1)
|
644
789
|
|
645
790
|
def load_or_add_requirements_file(self, project_path):
|
646
791
|
if os.path.exists(REQUIREMENTS_TXT):
|
@@ -685,7 +830,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
685
830
|
"custom_payloads": [],
|
686
831
|
}
|
687
832
|
|
688
|
-
self.validate_requirements_file(project_path, True)
|
833
|
+
self.validate_requirements_file(project_path, True, force)
|
689
834
|
|
690
835
|
group_id, group_name = self.__get_group_info(group, deploy_key)
|
691
836
|
connection_id, service = self.__get_connection_id(connection, group, group_id, deploy_key) or (None, None)
|
@@ -849,9 +994,15 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
849
994
|
"""
|
850
995
|
upload_filepath = os.path.join(project_path, UPLOAD_FILENAME)
|
851
996
|
connector_file_exists = False
|
997
|
+
custom_drivers_exists = False
|
998
|
+
custom_driver_installation_script_exists = False
|
852
999
|
|
853
1000
|
with ZipFile(upload_filepath, 'w', ZIP_DEFLATED) as zipf:
|
854
1001
|
for root, files in self.__dir_walker(project_path):
|
1002
|
+
if os.path.basename(root) == DRIVERS:
|
1003
|
+
custom_drivers_exists = True
|
1004
|
+
if INSTALLATION_SCRIPT in files:
|
1005
|
+
custom_driver_installation_script_exists = True
|
855
1006
|
for file in files:
|
856
1007
|
if file == "connector.py":
|
857
1008
|
connector_file_exists = True
|
@@ -863,6 +1014,11 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
863
1014
|
print_library_log(
|
864
1015
|
"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.", Logging.Level.SEVERE)
|
865
1016
|
os._exit(1)
|
1017
|
+
|
1018
|
+
if custom_drivers_exists and not custom_driver_installation_script_exists:
|
1019
|
+
print_library_log(INSTALLATION_SCRIPT_MISSING_MESSAGE, Logging.Level.SEVERE)
|
1020
|
+
os._exit(1)
|
1021
|
+
|
866
1022
|
return upload_filepath
|
867
1023
|
|
868
1024
|
def __dir_walker(self, top):
|
@@ -881,6 +1037,9 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
881
1037
|
if (name not in EXCLUDED_DIRS) and (not name.startswith(".")):
|
882
1038
|
dirs.append(name)
|
883
1039
|
else:
|
1040
|
+
# Include all files if in `drivers` folder
|
1041
|
+
if os.path.basename(top) == DRIVERS:
|
1042
|
+
files.append(name)
|
884
1043
|
if name.endswith(".py") or name == "requirements.txt":
|
885
1044
|
files.append(name)
|
886
1045
|
|
@@ -1253,6 +1412,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1253
1412
|
else:
|
1254
1413
|
try:
|
1255
1414
|
configuration = self.configuration if self.configuration else request.configuration
|
1415
|
+
print_library_log("Initiating the 'schema' method call...", Logging.Level.WARNING)
|
1256
1416
|
response = self.schema_method(configuration)
|
1257
1417
|
self.process_tables(response)
|
1258
1418
|
return connector_sdk_pb2.SchemaResponse(without_schema=common_pb2.TableList(tables=TABLES.values()))
|
@@ -1260,6 +1420,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1260
1420
|
except Exception as e:
|
1261
1421
|
tb = traceback.format_exc()
|
1262
1422
|
error_message = f"Error: {str(e)}\n{tb}"
|
1423
|
+
print_library_log(error_message, Logging.Level.SEVERE)
|
1263
1424
|
raise RuntimeError(error_message) from e
|
1264
1425
|
|
1265
1426
|
def process_tables(self, response):
|
@@ -1267,7 +1428,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1267
1428
|
if 'table' not in entry:
|
1268
1429
|
raise ValueError("Entry missing table name: " + entry)
|
1269
1430
|
|
1270
|
-
table_name = entry['table']
|
1431
|
+
table_name = for_table(entry['table'])
|
1271
1432
|
|
1272
1433
|
if table_name in TABLES:
|
1273
1434
|
raise ValueError("Table already defined: " + table_name)
|
@@ -1358,6 +1519,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1358
1519
|
state = self.state if self.state else json.loads(request.state_json)
|
1359
1520
|
|
1360
1521
|
try:
|
1522
|
+
print_library_log("Initiating the 'update' method call...", Logging.Level.WARNING)
|
1361
1523
|
for resp in self.update_method(configuration=configuration, state=state):
|
1362
1524
|
if isinstance(resp, list):
|
1363
1525
|
for r in resp:
|
@@ -1372,6 +1534,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1372
1534
|
except Exception as e:
|
1373
1535
|
tb = traceback.format_exc()
|
1374
1536
|
error_message = f"Error: {str(e)}\n{tb}"
|
1537
|
+
print_library_log(error_message, Logging.Level.SEVERE)
|
1375
1538
|
raise RuntimeError(error_message) from e
|
1376
1539
|
|
1377
1540
|
|
@@ -1387,19 +1550,24 @@ def find_connector_object(project_path) -> Connector:
|
|
1387
1550
|
sys.path.append(project_path) # Allows python interpreter to search for modules in this path
|
1388
1551
|
module_name = "connector_connector_code"
|
1389
1552
|
connector_py = os.path.join(project_path, "connector.py")
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1553
|
+
try:
|
1554
|
+
spec = importlib.util.spec_from_file_location(module_name, connector_py)
|
1555
|
+
module = importlib.util.module_from_spec(spec)
|
1556
|
+
sys.modules[module_name] = module
|
1557
|
+
spec.loader.exec_module(module)
|
1558
|
+
for obj in dir(module):
|
1559
|
+
if not obj.startswith('__'): # Exclude built-in attributes
|
1560
|
+
obj_attr = getattr(module, obj)
|
1561
|
+
if '<fivetran_connector_sdk.Connector object at' in str(obj_attr):
|
1562
|
+
return obj_attr
|
1563
|
+
except FileNotFoundError:
|
1564
|
+
print_library_log(
|
1565
|
+
"The connector object is missing in the current directory. Please ensure that you are running the command from correct directory or 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", Logging.Level.SEVERE)
|
1566
|
+
return
|
1399
1567
|
|
1400
1568
|
print_library_log(
|
1401
1569
|
"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", Logging.Level.SEVERE)
|
1402
|
-
|
1570
|
+
return
|
1403
1571
|
|
1404
1572
|
|
1405
1573
|
def suggest_correct_command(input_command: str) -> bool:
|
@@ -1487,9 +1655,15 @@ def main():
|
|
1487
1655
|
if args.command.lower() == "version":
|
1488
1656
|
print_library_log("fivetran_connector_sdk " + __version__)
|
1489
1657
|
return
|
1658
|
+
elif args.command.lower() == "reset":
|
1659
|
+
reset_local_file_directory(args)
|
1660
|
+
return
|
1490
1661
|
|
1491
1662
|
connector_object = find_connector_object(args.project_path)
|
1492
1663
|
|
1664
|
+
if not connector_object:
|
1665
|
+
sys.exit(1)
|
1666
|
+
|
1493
1667
|
# Process optional args
|
1494
1668
|
ft_group = args.destination if args.destination else os.getenv('FIVETRAN_DESTINATION_NAME', None)
|
1495
1669
|
ft_connection = args.connection if args.connection else os.getenv('FIVETRAN_CONNECTION_NAME', None)
|
@@ -1508,8 +1682,6 @@ def main():
|
|
1508
1682
|
elif args.command.lower() == "debug":
|
1509
1683
|
connector_object.debug(args.project_path, configuration, state)
|
1510
1684
|
|
1511
|
-
elif args.command.lower() == "reset":
|
1512
|
-
reset_local_file_directory(args)
|
1513
1685
|
else:
|
1514
1686
|
if not suggest_correct_command(args.command):
|
1515
1687
|
raise NotImplementedError(f"Invalid command: {args.command}, see `fivetran --help`")
|
{fivetran_connector_sdk-0.12.17.1.dist-info → fivetran_connector_sdk-0.13.16.2.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: fivetran_connector_sdk
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.13.16.2
|
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,6 +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
19
|
|
19
20
|
# **fivetran-connector-sdk**
|
20
21
|
[](https://pepy.tech/project/fivetran-connector-sdk)
|
{fivetran_connector_sdk-0.12.17.1.dist-info → fivetran_connector_sdk-0.13.16.2.dist-info}/RECORD
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
fivetran_connector_sdk/__init__.py,sha256=
|
1
|
+
fivetran_connector_sdk/__init__.py,sha256=t6bJFY6EMwS7HqbumKVCJq7bpkVBExpjmTGRp-gBafA,70538
|
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.
|
10
|
-
fivetran_connector_sdk-0.
|
11
|
-
fivetran_connector_sdk-0.
|
12
|
-
fivetran_connector_sdk-0.
|
13
|
-
fivetran_connector_sdk-0.
|
9
|
+
fivetran_connector_sdk-0.13.16.2.dist-info/METADATA,sha256=PKR_2EXCjVTfC2LusmArJqVEq8aVpzum4J0eXfm4lhs,2976
|
10
|
+
fivetran_connector_sdk-0.13.16.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
11
|
+
fivetran_connector_sdk-0.13.16.2.dist-info/entry_points.txt,sha256=uQn0KPnFlQmXJfxlk0tifdNsSXWfVlnAFzNqjXZM_xM,57
|
12
|
+
fivetran_connector_sdk-0.13.16.2.dist-info/top_level.txt,sha256=-_xk2MFY4psIh7jw1lJePMzFb5-vask8_ZtX-UzYWUI,23
|
13
|
+
fivetran_connector_sdk-0.13.16.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|