fivetran-connector-sdk 0.13.22.1__py3-none-any.whl → 1.0.0__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 +51 -36
- {fivetran_connector_sdk-0.13.22.1.dist-info → fivetran_connector_sdk-1.0.0.dist-info}/METADATA +1 -1
- {fivetran_connector_sdk-0.13.22.1.dist-info → fivetran_connector_sdk-1.0.0.dist-info}/RECORD +6 -6
- {fivetran_connector_sdk-0.13.22.1.dist-info → fivetran_connector_sdk-1.0.0.dist-info}/WHEEL +0 -0
- {fivetran_connector_sdk-0.13.22.1.dist-info → fivetran_connector_sdk-1.0.0.dist-info}/entry_points.txt +0 -0
- {fivetran_connector_sdk-0.13.22.1.dist-info → fivetran_connector_sdk-1.0.0.dist-info}/top_level.txt +0 -0
@@ -28,14 +28,15 @@ from fivetran_connector_sdk.protos import common_pb2
|
|
28
28
|
from fivetran_connector_sdk.protos import connector_sdk_pb2
|
29
29
|
from fivetran_connector_sdk.protos import connector_sdk_pb2_grpc
|
30
30
|
|
31
|
-
# Version format: <major_version>.<
|
32
|
-
|
31
|
+
# Version format: <major_version>.<minor_version>.<patch_version>
|
32
|
+
# (where Major Version = 1 for GA, Minor Version is incremental MM from Jan 25 onwards, Patch Version is incremental within a month)
|
33
|
+
__version__ = "1.0.0"
|
33
34
|
|
34
35
|
MAC_OS = "mac"
|
35
36
|
WIN_OS = "windows"
|
36
37
|
LINUX_OS = "linux"
|
37
38
|
|
38
|
-
TESTER_VERSION = "0.25.
|
39
|
+
TESTER_VERSION = "0.25.0130.001"
|
39
40
|
TESTER_FILENAME = "run_sdk_tester.jar"
|
40
41
|
VERSION_FILENAME = "version.txt"
|
41
42
|
UPLOAD_FILENAME = "code.zip"
|
@@ -76,6 +77,7 @@ DRIVERS = "drivers"
|
|
76
77
|
JAVA_LONG_MAX_VALUE = 9223372036854775807
|
77
78
|
MAX_CONFIG_FIELDS = 100
|
78
79
|
SUPPORTED_PYTHON_VERSIONS = {"3.12.8", "3.11.11", "3.10.16", "3.9.21"}
|
80
|
+
DEFAULT_PYTHON_VERSION = "3.12.8"
|
79
81
|
|
80
82
|
|
81
83
|
class Logging:
|
@@ -161,13 +163,14 @@ class Operations:
|
|
161
163
|
|
162
164
|
responses = []
|
163
165
|
|
164
|
-
table =
|
166
|
+
table = get_renamed_table_name(table)
|
165
167
|
columns = _get_columns(table)
|
166
168
|
if not columns:
|
167
169
|
global TABLES
|
168
170
|
for field in data.keys():
|
169
|
-
|
170
|
-
|
171
|
+
field_name = get_renamed_column_name(field)
|
172
|
+
columns[field_name] = common_pb2.Column(
|
173
|
+
name=field_name, type=common_pb2.DataType.UNSPECIFIED, primary_key=False)
|
171
174
|
|
172
175
|
mapped_data = _map_data_to_columns(data, columns)
|
173
176
|
record = connector_sdk_pb2.Record(
|
@@ -196,7 +199,7 @@ class Operations:
|
|
196
199
|
"""
|
197
200
|
_yield_check(inspect.stack())
|
198
201
|
|
199
|
-
table =
|
202
|
+
table = get_renamed_table_name(table)
|
200
203
|
columns = _get_columns(table)
|
201
204
|
mapped_data = _map_data_to_columns(modified, columns)
|
202
205
|
record = connector_sdk_pb2.Record(
|
@@ -222,7 +225,7 @@ class Operations:
|
|
222
225
|
"""
|
223
226
|
_yield_check(inspect.stack())
|
224
227
|
|
225
|
-
table =
|
228
|
+
table = get_renamed_table_name(table)
|
226
229
|
columns = _get_columns(table)
|
227
230
|
mapped_data = _map_data_to_columns(keys, columns)
|
228
231
|
record = connector_sdk_pb2.Record(
|
@@ -313,6 +316,7 @@ def _get_columns(table: str) -> dict:
|
|
313
316
|
columns = {}
|
314
317
|
if table in TABLES:
|
315
318
|
for column in TABLES[table].columns:
|
319
|
+
column.name = get_renamed_column_name(column.name)
|
316
320
|
columns[column.name] = column
|
317
321
|
|
318
322
|
return columns
|
@@ -330,12 +334,13 @@ def _map_data_to_columns(data: dict, columns: dict) -> dict:
|
|
330
334
|
"""
|
331
335
|
mapped_data = {}
|
332
336
|
for k, v in data.items():
|
337
|
+
key = get_renamed_column_name(k)
|
333
338
|
if v is None:
|
334
|
-
mapped_data[
|
335
|
-
elif (
|
336
|
-
map_defined_data_type(columns,
|
339
|
+
mapped_data[key] = common_pb2.ValueType(null=True)
|
340
|
+
elif (key in columns) and columns[key].type != common_pb2.DataType.UNSPECIFIED:
|
341
|
+
map_defined_data_type(columns, key, mapped_data, v)
|
337
342
|
else:
|
338
|
-
map_inferred_data_type(
|
343
|
+
map_inferred_data_type(key, mapped_data, v)
|
339
344
|
|
340
345
|
return mapped_data
|
341
346
|
|
@@ -643,13 +648,19 @@ def safe_drop_underscores(name):
|
|
643
648
|
return safe_name
|
644
649
|
|
645
650
|
|
646
|
-
def
|
651
|
+
def get_renamed_table_name(source_table):
|
647
652
|
"""
|
648
653
|
Process a source table name to ensure it conforms to naming rules.
|
649
654
|
"""
|
650
655
|
return safe_drop_underscores(source_table)
|
651
656
|
|
652
657
|
|
658
|
+
def get_renamed_column_name(source_column):
|
659
|
+
"""
|
660
|
+
Process a source column name to ensure it conforms to naming rules.
|
661
|
+
"""
|
662
|
+
return redshift_safe(source_column)
|
663
|
+
|
653
664
|
class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
654
665
|
def __init__(self, update, schema=None):
|
655
666
|
"""Initializes the Connector instance.
|
@@ -716,14 +727,16 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
716
727
|
force (bool): Force update an existing connection.
|
717
728
|
|
718
729
|
"""
|
730
|
+
# tmp_requirements is only generated when pipreqs command is successful
|
731
|
+
tmp_requirements_file_path = os.path.join(project_path, 'tmp_requirements.txt')
|
719
732
|
# Run the pipreqs command and capture stderr
|
720
733
|
attempt = 0
|
721
734
|
while attempt < MAX_RETRIES:
|
722
735
|
attempt += 1
|
723
736
|
result = subprocess.run(
|
724
|
-
["pipreqs", "--savepath",
|
737
|
+
["pipreqs", project_path, "--savepath", tmp_requirements_file_path, "--ignore"] + EXCLUDED_PIPREQS_DIRS,
|
725
738
|
stderr=subprocess.PIPE,
|
726
|
-
text=True
|
739
|
+
text=True # Ensures output is in string format
|
727
740
|
)
|
728
741
|
|
729
742
|
if result.returncode == 0:
|
@@ -740,9 +753,6 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
740
753
|
print(result.stderr)
|
741
754
|
sys.exit(1)
|
742
755
|
|
743
|
-
# tmp_requirements is only generated when pipreqs command is successful
|
744
|
-
tmp_requirements_file_path = os.path.join(project_path, 'tmp_requirements.txt')
|
745
|
-
|
746
756
|
tmp_requirements = self.fetch_requirements_as_dict(self, tmp_requirements_file_path)
|
747
757
|
tmp_requirements.pop("fivetran_connector_sdk")
|
748
758
|
if tmp_requirements.get('requests') is not None:
|
@@ -872,17 +882,19 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
872
882
|
else:
|
873
883
|
if args.force:
|
874
884
|
confirm = "y"
|
885
|
+
if args.configuration:
|
886
|
+
confirm_config = "y"
|
875
887
|
else:
|
876
888
|
confirm = input(
|
877
889
|
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
|
890
|
+
if confirm.lower() == "y" and args.configuration:
|
879
891
|
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
892
|
if confirm.lower() == "y" and (not connection_config["secrets_list"] or (confirm_config.lower() == "y")):
|
881
893
|
print_library_log("Updating the connection...\n")
|
882
894
|
self.__upload_project(
|
883
895
|
args.project_path, deploy_key, group_id, group_name, connection)
|
884
896
|
self.__update_connection(
|
885
|
-
connection_id, connection, group_name, connection_config, deploy_key)
|
897
|
+
args, connection_id, connection, group_name, connection_config, deploy_key)
|
886
898
|
print("✓")
|
887
899
|
print_library_log(f"Connector ID: {connection_id}")
|
888
900
|
print_library_log(
|
@@ -899,6 +911,8 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
899
911
|
print_library_log(
|
900
912
|
f"The connection '{connection}' has been created successfully.\n")
|
901
913
|
connection_id = response.json()['data']['id']
|
914
|
+
# Python Version is not passed into connection_config as default value will be picked up from ConnectorSdkCredentials.java class.
|
915
|
+
print_library_log(f"Python Version: {args.python_version if args.python_version else DEFAULT_PYTHON_VERSION}", Logging.Level.INFO)
|
902
916
|
print_library_log(f"Connector ID: {connection_id}")
|
903
917
|
print_library_log(
|
904
918
|
f"Visit the Fivetran dashboard to start the initial sync: https://fivetran.com/dashboard/connectors/{connection_id}/status")
|
@@ -925,17 +939,18 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
925
939
|
os._exit(1)
|
926
940
|
|
927
941
|
@staticmethod
|
928
|
-
def __update_connection(id: str, name: str, group: str, config: dict, deploy_key: str):
|
942
|
+
def __update_connection(args: dict, id: str, name: str, group: str, config: dict, deploy_key: str):
|
929
943
|
"""Updates the connection with the given ID, name, group, configuration, and deployment key.
|
930
944
|
|
931
945
|
Args:
|
946
|
+
args (dict): The command arguments.
|
932
947
|
id (str): The connection ID.
|
933
948
|
name (str): The connection name.
|
934
949
|
group (str): The group name.
|
935
950
|
config (dict): The configuration dictionary.
|
936
951
|
deploy_key (str): The deployment key.
|
937
952
|
"""
|
938
|
-
if not
|
953
|
+
if not args.configuration:
|
939
954
|
del config["secrets_list"]
|
940
955
|
|
941
956
|
resp = rq.patch(f"{PRODUCTION_BASE_URL}/v1/connectors/{id}",
|
@@ -1161,7 +1176,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1161
1176
|
|
1162
1177
|
if not resp.ok:
|
1163
1178
|
print_library_log(
|
1164
|
-
f"
|
1179
|
+
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)
|
1165
1180
|
os._exit(1)
|
1166
1181
|
|
1167
1182
|
data = resp.json().get("data", {})
|
@@ -1234,7 +1249,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1234
1249
|
project_path: str = None,
|
1235
1250
|
configuration: dict = None,
|
1236
1251
|
state: dict = None,
|
1237
|
-
log_level: Logging.Level = Logging.Level.FINE)
|
1252
|
+
log_level: Logging.Level = Logging.Level.FINE):
|
1238
1253
|
"""Tests the connector code by running it with the connector tester.\n
|
1239
1254
|
state.json docs: https://fivetran.com/docs/connectors/connector-sdk/detailed-guide#workingwithstatejsonfile\n
|
1240
1255
|
configuration.json docs: https://fivetran.com/docs/connectors/connector-sdk/detailed-guide#workingwithconfigurationjsonfile
|
@@ -1244,9 +1259,6 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1244
1259
|
configuration (dict): The configuration dictionary, same as configuration.json if present.
|
1245
1260
|
state (dict): The state dictionary, same as state.json if present.
|
1246
1261
|
log_level (Logging.Level): The logging level.
|
1247
|
-
|
1248
|
-
Returns:
|
1249
|
-
bool: True if there was an error, False otherwise.
|
1250
1262
|
"""
|
1251
1263
|
global DEBUGGING
|
1252
1264
|
DEBUGGING = True
|
@@ -1443,7 +1455,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1443
1455
|
else:
|
1444
1456
|
try:
|
1445
1457
|
configuration = self.configuration if self.configuration else request.configuration
|
1446
|
-
print_library_log("Initiating the 'schema' method call...", Logging.Level.
|
1458
|
+
print_library_log("Initiating the 'schema' method call...", Logging.Level.INFO)
|
1447
1459
|
response = self.schema_method(configuration)
|
1448
1460
|
self.process_tables(response)
|
1449
1461
|
return connector_sdk_pb2.SchemaResponse(without_schema=common_pb2.TableList(tables=TABLES.values()))
|
@@ -1459,7 +1471,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1459
1471
|
if 'table' not in entry:
|
1460
1472
|
raise ValueError("Entry missing table name: " + entry)
|
1461
1473
|
|
1462
|
-
table_name =
|
1474
|
+
table_name = get_renamed_table_name(entry['table'])
|
1463
1475
|
|
1464
1476
|
if table_name in TABLES:
|
1465
1477
|
raise ValueError("Table already defined: " + table_name)
|
@@ -1478,13 +1490,15 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1478
1490
|
|
1479
1491
|
def process_primary_keys(self, columns, entry):
|
1480
1492
|
for pkey_name in entry["primary_key"]:
|
1481
|
-
|
1493
|
+
column_name = get_renamed_column_name(pkey_name)
|
1494
|
+
column = columns[column_name] if column_name in columns else common_pb2.Column(name=column_name)
|
1482
1495
|
column.primary_key = True
|
1483
|
-
columns[
|
1496
|
+
columns[column_name] = column
|
1484
1497
|
|
1485
1498
|
def process_columns(self, columns, entry):
|
1486
1499
|
for name, type in entry["columns"].items():
|
1487
|
-
|
1500
|
+
column_name = get_renamed_column_name(name)
|
1501
|
+
column = columns[column_name] if column_name in columns else common_pb2.Column(name=column_name)
|
1488
1502
|
|
1489
1503
|
if isinstance(type, str):
|
1490
1504
|
self.process_data_type(column, type)
|
@@ -1502,7 +1516,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1502
1516
|
if "primary_key" in entry and name in entry["primary_key"]:
|
1503
1517
|
column.primary_key = True
|
1504
1518
|
|
1505
|
-
columns[
|
1519
|
+
columns[column_name] = column
|
1506
1520
|
|
1507
1521
|
def process_data_type(self, column, type):
|
1508
1522
|
if type.upper() == "BOOLEAN":
|
@@ -1550,7 +1564,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1550
1564
|
state = self.state if self.state else json.loads(request.state_json)
|
1551
1565
|
|
1552
1566
|
try:
|
1553
|
-
print_library_log("Initiating the 'update' method call...", Logging.Level.
|
1567
|
+
print_library_log("Initiating the 'update' method call...", Logging.Level.INFO)
|
1554
1568
|
for resp in self.update_method(configuration=configuration, state=state):
|
1555
1569
|
if isinstance(resp, list):
|
1556
1570
|
for r in resp:
|
@@ -1667,7 +1681,8 @@ def main():
|
|
1667
1681
|
global EXECUTED_VIA_CLI
|
1668
1682
|
EXECUTED_VIA_CLI = True
|
1669
1683
|
|
1670
|
-
parser = argparse.ArgumentParser(allow_abbrev=False)
|
1684
|
+
parser = argparse.ArgumentParser(allow_abbrev=False, add_help=True)
|
1685
|
+
parser._option_string_actions["-h"].help = "Show this help message and exit"
|
1671
1686
|
|
1672
1687
|
# Positional
|
1673
1688
|
parser.add_argument("command", help="|".join(VALID_COMMANDS))
|
@@ -1676,7 +1691,7 @@ def main():
|
|
1676
1691
|
# Optional (Not all of these are valid with every mutually exclusive option below)
|
1677
1692
|
parser.add_argument("--state", type=str, default=None, help="Provide state as JSON string or file")
|
1678
1693
|
parser.add_argument("--configuration", type=str, default=None, help="Provide secrets as JSON file")
|
1679
|
-
parser.add_argument("--api-key", type=str, default=None, help="Provide
|
1694
|
+
parser.add_argument("--api-key", type=str, default=None, help="Provide your base64-encoded API key for deployment")
|
1680
1695
|
parser.add_argument("--destination", type=str, default=None, help="Destination name (aka 'group name')")
|
1681
1696
|
parser.add_argument("--connection", type=str, default=None, help="Connection name (aka 'destination schema')")
|
1682
1697
|
parser.add_argument("-f", "--force", action="store_true", help="Force update an existing connection")
|
{fivetran_connector_sdk-0.13.22.1.dist-info → fivetran_connector_sdk-1.0.0.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: fivetran_connector_sdk
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0
|
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
|
{fivetran_connector_sdk-0.13.22.1.dist-info → fivetran_connector_sdk-1.0.0.dist-info}/RECORD
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
fivetran_connector_sdk/__init__.py,sha256=
|
1
|
+
fivetran_connector_sdk/__init__.py,sha256=Nx4fuu2Q901W2ecDr7f9-UgkRjsM4Oz0sYX0XVrChkA,74181
|
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-1.0.0.dist-info/METADATA,sha256=vcXCf52OxYYGX-uqK0gG52I382Iu_UNASzRAruUtshw,2967
|
10
|
+
fivetran_connector_sdk-1.0.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
11
|
+
fivetran_connector_sdk-1.0.0.dist-info/entry_points.txt,sha256=uQn0KPnFlQmXJfxlk0tifdNsSXWfVlnAFzNqjXZM_xM,57
|
12
|
+
fivetran_connector_sdk-1.0.0.dist-info/top_level.txt,sha256=-_xk2MFY4psIh7jw1lJePMzFb5-vask8_ZtX-UzYWUI,23
|
13
|
+
fivetran_connector_sdk-1.0.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{fivetran_connector_sdk-0.13.22.1.dist-info → fivetran_connector_sdk-1.0.0.dist-info}/top_level.txt
RENAMED
File without changes
|