fivetran-connector-sdk 1.2.0__py3-none-any.whl → 1.3.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 +65 -26
- {fivetran_connector_sdk-1.2.0.dist-info → fivetran_connector_sdk-1.3.0.dist-info}/METADATA +2 -2
- {fivetran_connector_sdk-1.2.0.dist-info → fivetran_connector_sdk-1.3.0.dist-info}/RECORD +6 -6
- {fivetran_connector_sdk-1.2.0.dist-info → fivetran_connector_sdk-1.3.0.dist-info}/WHEEL +1 -1
- {fivetran_connector_sdk-1.2.0.dist-info → fivetran_connector_sdk-1.3.0.dist-info}/entry_points.txt +0 -0
- {fivetran_connector_sdk-1.2.0.dist-info → fivetran_connector_sdk-1.3.0.dist-info}/top_level.txt +0 -0
@@ -31,13 +31,13 @@ from fivetran_connector_sdk.protos import connector_sdk_pb2_grpc
|
|
31
31
|
|
32
32
|
# Version format: <major_version>.<minor_version>.<patch_version>
|
33
33
|
# (where Major Version = 1 for GA, Minor Version is incremental MM from Jan 25 onwards, Patch Version is incremental within a month)
|
34
|
-
__version__ = "1.
|
34
|
+
__version__ = "1.3.0"
|
35
35
|
|
36
36
|
MAC_OS = "mac"
|
37
37
|
WIN_OS = "windows"
|
38
38
|
LINUX_OS = "linux"
|
39
39
|
|
40
|
-
TESTER_VERSION = "0.25.
|
40
|
+
TESTER_VERSION = "0.25.0403.001"
|
41
41
|
TESTER_FILENAME = "run_sdk_tester.jar"
|
42
42
|
VERSION_FILENAME = "version.txt"
|
43
43
|
UPLOAD_FILENAME = "code.zip"
|
@@ -49,6 +49,8 @@ REQUIREMENTS_TXT = "requirements.txt"
|
|
49
49
|
PYPI_PACKAGE_DETAILS_URL = "https://pypi.org/pypi/fivetran_connector_sdk/json"
|
50
50
|
ONE_DAY_IN_SEC = 24 * 60 * 60
|
51
51
|
MAX_RETRIES = 3
|
52
|
+
LOGGING_PREFIX = "Fivetran-Connector-SDK"
|
53
|
+
LOGGING_DELIMITER = ": "
|
52
54
|
VIRTUAL_ENV_CONFIG = "pyvenv.cfg"
|
53
55
|
|
54
56
|
# Compile patterns used in the implementation
|
@@ -162,7 +164,8 @@ class Operations:
|
|
162
164
|
Returns:
|
163
165
|
list[connector_sdk_pb2.UpdateResponse]: A list of update responses.
|
164
166
|
"""
|
165
|
-
|
167
|
+
if DEBUGGING:
|
168
|
+
_yield_check(inspect.stack())
|
166
169
|
|
167
170
|
responses = []
|
168
171
|
|
@@ -200,7 +203,8 @@ class Operations:
|
|
200
203
|
Returns:
|
201
204
|
connector_sdk_pb2.UpdateResponse: The update response.
|
202
205
|
"""
|
203
|
-
|
206
|
+
if DEBUGGING:
|
207
|
+
_yield_check(inspect.stack())
|
204
208
|
|
205
209
|
table = get_renamed_table_name(table)
|
206
210
|
columns = _get_columns(table)
|
@@ -226,7 +230,8 @@ class Operations:
|
|
226
230
|
Returns:
|
227
231
|
connector_sdk_pb2.UpdateResponse: The delete response.
|
228
232
|
"""
|
229
|
-
|
233
|
+
if DEBUGGING:
|
234
|
+
_yield_check(inspect.stack())
|
230
235
|
|
231
236
|
table = get_renamed_table_name(table)
|
232
237
|
columns = _get_columns(table)
|
@@ -262,7 +267,9 @@ class Operations:
|
|
262
267
|
Returns:
|
263
268
|
connector_sdk_pb2.UpdateResponse: The checkpoint response.
|
264
269
|
"""
|
265
|
-
|
270
|
+
if DEBUGGING:
|
271
|
+
_yield_check(inspect.stack())
|
272
|
+
|
266
273
|
return connector_sdk_pb2.UpdateResponse(
|
267
274
|
operation=connector_sdk_pb2.Operation(checkpoint=connector_sdk_pb2.Checkpoint(
|
268
275
|
state_json=json.dumps(state))))
|
@@ -401,10 +408,7 @@ def map_defined_data_type(columns, k, mapped_data, v):
|
|
401
408
|
mapped_data[k] = common_pb2.ValueType(naive_datetime=timestamp)
|
402
409
|
elif columns[k].type == common_pb2.DataType.UTC_DATETIME:
|
403
410
|
timestamp = timestamp_pb2.Timestamp()
|
404
|
-
if
|
405
|
-
dt = datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%f%z")
|
406
|
-
else:
|
407
|
-
dt = datetime.strptime(v, "%Y-%m-%dT%H:%M:%S%z")
|
411
|
+
dt = v if isinstance(v, datetime) else _parse_datetime_str(v)
|
408
412
|
timestamp.FromDatetime(dt)
|
409
413
|
mapped_data[k] = common_pb2.ValueType(utc_datetime=timestamp)
|
410
414
|
elif columns[k].type == common_pb2.DataType.BINARY:
|
@@ -420,6 +424,10 @@ def map_defined_data_type(columns, k, mapped_data, v):
|
|
420
424
|
raise ValueError(f"Unsupported data type encountered: {columns[k].type}. Please use valid data types.")
|
421
425
|
|
422
426
|
|
427
|
+
def _parse_datetime_str(dt):
|
428
|
+
return datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S.%f%z" if '.' in dt else "%Y-%m-%dT%H:%M:%S%z")
|
429
|
+
|
430
|
+
|
423
431
|
def _yield_check(stack):
|
424
432
|
"""Checks for the presence of 'yield' in the calling code.
|
425
433
|
Args:
|
@@ -432,8 +440,6 @@ def _yield_check(stack):
|
|
432
440
|
# the file paths. This can lead to unexpected behavior, such as yield returning None or
|
433
441
|
# the failure to retrieve the module inside a frozen app
|
434
442
|
# (Reference: https://github.com/pyinstaller/pyinstaller/issues/5963)
|
435
|
-
if not DEBUGGING:
|
436
|
-
return
|
437
443
|
|
438
444
|
called_method = stack[0].function
|
439
445
|
calling_code = stack[1].code_context[0]
|
@@ -524,9 +530,9 @@ def print_library_log(message: str, level: Logging.Level = Logging.Level.INFO):
|
|
524
530
|
if DEBUGGING or EXECUTED_VIA_CLI:
|
525
531
|
current_time = datetime.now().strftime("%b %d, %Y %I:%M:%S %p")
|
526
532
|
escaped_message = json.dumps(message).strip('"')
|
527
|
-
print(f"{current_time} {level.name}: {escaped_message}")
|
533
|
+
print(f"{current_time} {level.name} {LOGGING_PREFIX}: {escaped_message}")
|
528
534
|
else:
|
529
|
-
escaped_message = json.dumps(message)
|
535
|
+
escaped_message = json.dumps(LOGGING_PREFIX + LOGGING_DELIMITER + message)
|
530
536
|
log_message = f'{{"level":"{level.name}", "message": {escaped_message}, "message_origin": "library"}}'
|
531
537
|
print(log_message)
|
532
538
|
|
@@ -925,7 +931,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
925
931
|
self.__update_connection(
|
926
932
|
args, connection_id, connection, group_name, connection_config, deploy_key, hd_agent_id)
|
927
933
|
print("✓")
|
928
|
-
print_library_log(f"
|
934
|
+
print_library_log(f"Connection ID: {connection_id}")
|
929
935
|
print_library_log(
|
930
936
|
f"Visit the Fivetran dashboard to manage the connection: https://fivetran.com/dashboard/connectors/{connection_id}/status")
|
931
937
|
else:
|
@@ -945,7 +951,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
945
951
|
connection_id = response.json()['data']['id']
|
946
952
|
# Python Version is not passed into connection_config as default value will be picked up from ConnectorSdkCredentials.java class.
|
947
953
|
print_library_log(f"Python Version: {args.python_version if args.python_version else DEFAULT_PYTHON_VERSION}", Logging.Level.INFO)
|
948
|
-
print_library_log(f"
|
954
|
+
print_library_log(f"Connection ID: {connection_id}")
|
949
955
|
print_library_log(
|
950
956
|
f"Visit the Fivetran dashboard to start the initial sync: https://fivetran.com/dashboard/connectors/{connection_id}/status")
|
951
957
|
else:
|
@@ -986,13 +992,19 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
986
992
|
if not args.configuration:
|
987
993
|
del config["secrets_list"]
|
988
994
|
|
995
|
+
json_payload = {
|
996
|
+
"config": config,
|
997
|
+
"run_setup_tests": True
|
998
|
+
}
|
999
|
+
|
1000
|
+
# hybrid_deployment_agent_id is optional when redeploying your connection.
|
1001
|
+
# Customer can use it to change existing hybrid_deployment_agent_id.
|
1002
|
+
if hd_agent_id:
|
1003
|
+
json_payload["hybrid_deployment_agent_id"] = hd_agent_id
|
1004
|
+
|
989
1005
|
response = rq.patch(f"{PRODUCTION_BASE_URL}/v1/connectors/{id}",
|
990
1006
|
headers={"Authorization": f"Basic {deploy_key}"},
|
991
|
-
json=
|
992
|
-
"config": config,
|
993
|
-
"hybrid_deployment_agent_id": hd_agent_id,
|
994
|
-
"run_setup_tests": True
|
995
|
-
})
|
1007
|
+
json=json_payload)
|
996
1008
|
|
997
1009
|
if response.ok and response.status_code == HTTPStatus.OK:
|
998
1010
|
if Connector.__are_setup_tests_failing(response):
|
@@ -1010,7 +1022,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
|
|
1010
1022
|
print_library_log(log_message, Logging.Level.SEVERE)
|
1011
1023
|
Connector.__print_failing_setup_tests(resp)
|
1012
1024
|
connection_id = resp.json().get('data', {}).get('id')
|
1013
|
-
print_library_log(f"
|
1025
|
+
print_library_log(f"Connection ID: {connection_id}")
|
1014
1026
|
print_library_log("Please try again with the deploy command after resolving the issue!")
|
1015
1027
|
os._exit(1)
|
1016
1028
|
|
@@ -1755,6 +1767,20 @@ def edit_distance(first_string: str, second_string: str) -> int:
|
|
1755
1767
|
return previous_row[second_string_length]
|
1756
1768
|
|
1757
1769
|
|
1770
|
+
def get_input_from_cli(prompt : str, default_value: str) -> str:
|
1771
|
+
"""
|
1772
|
+
Prompts the user for input.
|
1773
|
+
"""
|
1774
|
+
if default_value:
|
1775
|
+
value = input(f"{prompt} [Default : {default_value}]: ").strip() or default_value
|
1776
|
+
else:
|
1777
|
+
value = input(f"{prompt}: ").strip()
|
1778
|
+
|
1779
|
+
if not value:
|
1780
|
+
raise ValueError("Missing required input: Expected a value but received None")
|
1781
|
+
return value or None
|
1782
|
+
|
1783
|
+
|
1758
1784
|
def main():
|
1759
1785
|
"""The main entry point for the script.
|
1760
1786
|
Parses command line arguments and passes them to connector object methods
|
@@ -1794,9 +1820,9 @@ def main():
|
|
1794
1820
|
sys.exit(1)
|
1795
1821
|
|
1796
1822
|
# Process optional args
|
1797
|
-
ft_group = args.destination if args.destination else
|
1798
|
-
ft_connection = args.connection if args.connection else
|
1799
|
-
ft_deploy_key = args.api_key if args.api_key else
|
1823
|
+
ft_group = args.destination if args.destination else None
|
1824
|
+
ft_connection = args.connection if args.connection else None
|
1825
|
+
ft_deploy_key = args.api_key if args.api_key else None
|
1800
1826
|
hd_agent_id = args.hybrid_deployment_agent_id if args.hybrid_deployment_agent_id else os.getenv(FIVETRAN_HD_AGENT_ID, None)
|
1801
1827
|
configuration = args.configuration if args.configuration else None
|
1802
1828
|
state = args.state if args.state else os.getenv('FIVETRAN_STATE', None)
|
@@ -1804,14 +1830,27 @@ def main():
|
|
1804
1830
|
configuration = validate_and_load_configuration(args, configuration)
|
1805
1831
|
state = validate_and_load_state(args, state)
|
1806
1832
|
|
1833
|
+
FIVETRAN_API_KEY = os.getenv('FIVETRAN_API_KEY', None)
|
1834
|
+
FIVETRAN_DESTINATION_NAME = os.getenv('FIVETRAN_DESTINATION_NAME', None)
|
1835
|
+
FIVETRAN_CONNECTION_NAME = os.getenv('FIVETRAN_CONNECTION_NAME', None)
|
1836
|
+
|
1807
1837
|
if args.command.lower() == "deploy":
|
1808
1838
|
if args.state:
|
1809
1839
|
print_library_log("'state' parameter is not used for 'deploy' command", Logging.Level.WARNING)
|
1840
|
+
|
1841
|
+
if not ft_deploy_key:
|
1842
|
+
ft_deploy_key = get_input_from_cli("Please provide the API Key", FIVETRAN_API_KEY)
|
1843
|
+
|
1844
|
+
if not ft_group:
|
1845
|
+
ft_group = get_input_from_cli("Please provide the destination", FIVETRAN_DESTINATION_NAME)
|
1846
|
+
|
1847
|
+
if not ft_connection:
|
1848
|
+
ft_connection = get_input_from_cli("Please provide the connection name",FIVETRAN_CONNECTION_NAME)
|
1849
|
+
|
1810
1850
|
connector_object.deploy(args, ft_deploy_key, ft_group, ft_connection, hd_agent_id, configuration)
|
1811
1851
|
|
1812
1852
|
elif args.command.lower() == "debug":
|
1813
1853
|
connector_object.debug(args.project_path, configuration, state)
|
1814
|
-
|
1815
1854
|
else:
|
1816
1855
|
if not suggest_correct_command(args.command):
|
1817
1856
|
raise NotImplementedError(f"Invalid command: {args.command}, see `fivetran --help`")
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: fivetran_connector_sdk
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.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
|
@@ -1,4 +1,4 @@
|
|
1
|
-
fivetran_connector_sdk/__init__.py,sha256=
|
1
|
+
fivetran_connector_sdk/__init__.py,sha256=ubzp6kUWV4j8A3hgC-GRqtcX4WIQV5vMk5gdVkOZw4s,80578
|
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-1.
|
10
|
-
fivetran_connector_sdk-1.
|
11
|
-
fivetran_connector_sdk-1.
|
12
|
-
fivetran_connector_sdk-1.
|
13
|
-
fivetran_connector_sdk-1.
|
9
|
+
fivetran_connector_sdk-1.3.0.dist-info/METADATA,sha256=ilFpUA6zFnHz4_tEpKpG7IZxORmHqdcMdW0wb0z2sME,2967
|
10
|
+
fivetran_connector_sdk-1.3.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
11
|
+
fivetran_connector_sdk-1.3.0.dist-info/entry_points.txt,sha256=uQn0KPnFlQmXJfxlk0tifdNsSXWfVlnAFzNqjXZM_xM,57
|
12
|
+
fivetran_connector_sdk-1.3.0.dist-info/top_level.txt,sha256=-_xk2MFY4psIh7jw1lJePMzFb5-vask8_ZtX-UzYWUI,23
|
13
|
+
fivetran_connector_sdk-1.3.0.dist-info/RECORD,,
|
{fivetran_connector_sdk-1.2.0.dist-info → fivetran_connector_sdk-1.3.0.dist-info}/entry_points.txt
RENAMED
File without changes
|
{fivetran_connector_sdk-1.2.0.dist-info → fivetran_connector_sdk-1.3.0.dist-info}/top_level.txt
RENAMED
File without changes
|