fivetran-connector-sdk 0.12.17.1__tar.gz → 0.13.10.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.12.17.1 → fivetran_connector_sdk-0.13.10.1}/PKG-INFO +2 -2
  2. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk/__init__.py +62 -20
  3. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk.egg-info/PKG-INFO +2 -2
  4. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/README.md +0 -0
  5. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/pyproject.toml +0 -0
  6. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/setup.cfg +0 -0
  7. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk/protos/__init__.py +0 -0
  8. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk/protos/common_pb2.py +0 -0
  9. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk/protos/common_pb2.pyi +0 -0
  10. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk/protos/common_pb2_grpc.py +0 -0
  11. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk/protos/connector_sdk_pb2.py +0 -0
  12. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk/protos/connector_sdk_pb2.pyi +0 -0
  13. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk/protos/connector_sdk_pb2_grpc.py +0 -0
  14. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk.egg-info/SOURCES.txt +0 -0
  15. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk.egg-info/dependency_links.txt +0 -0
  16. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk.egg-info/entry_points.txt +0 -0
  17. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk.egg-info/requires.txt +0 -0
  18. {fivetran_connector_sdk-0.12.17.1 → fivetran_connector_sdk-0.13.10.1}/src/fivetran_connector_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: fivetran_connector_sdk
3
- Version: 0.12.17.1
3
+ Version: 0.13.10.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
@@ -26,7 +26,8 @@ from fivetran_connector_sdk.protos import common_pb2
26
26
  from fivetran_connector_sdk.protos import connector_sdk_pb2
27
27
  from fivetran_connector_sdk.protos import connector_sdk_pb2_grpc
28
28
 
29
- __version__ = "0.12.17.1"
29
+ # Version format: <major_version>.<MM>.<DD>.<iteration> (where MM is incremental value from Jan 2024)
30
+ __version__ = "0.13.10.1"
30
31
 
31
32
  MAC_OS = "mac"
32
33
  WIN_OS = "windows"
@@ -465,7 +466,6 @@ def log_unused_deps_error(package_name: str, version: str):
465
466
  print_library_log(f"Please remove `{package_name}` from requirements.txt."
466
467
  f" The latest version of `{package_name}` is always available when executing your code."
467
468
  f" Current version: {version}", Logging.Level.SEVERE)
468
- os._exit(1)
469
469
 
470
470
 
471
471
  def validate_deploy_parameters(connection, deploy_key):
@@ -574,7 +574,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
574
574
  print_library_log(f"Invalid requirement format: '{requirement}'", Logging.Level.SEVERE)
575
575
  return requirements_dict
576
576
 
577
- def validate_requirements_file(self, project_path: str, is_deploy: bool):
577
+ def validate_requirements_file(self, project_path: str, is_deploy: bool, force: bool = False):
578
578
  """Validates the `requirements.txt` file against the project's actual dependencies.
579
579
 
580
580
  This method generates a temporary requirements file using `pipreqs`, compares
@@ -585,10 +585,22 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
585
585
  Args:
586
586
  project_path (str): The path to the project directory containing the `requirements.txt`.
587
587
  is_deploy (bool): If `True`, the method will exit the process on critical errors.
588
+ force (bool): Force update an existing connection.
588
589
 
589
590
  """
590
- subprocess.check_call(["pipreqs", "--savepath", "tmp_requirements.txt", "--ignore"] + EXCLUDED_PIPREQS_DIRS,
591
- stderr=subprocess.PIPE)
591
+ # Run the pipreqs command and capture stderr
592
+ result = subprocess.run(
593
+ ["pipreqs", "--savepath", "tmp_requirements.txt", "--ignore"] + EXCLUDED_PIPREQS_DIRS,
594
+ stderr=subprocess.PIPE,
595
+ text=True # Ensures output is in string format
596
+ )
597
+
598
+ if result.returncode != 0:
599
+ print_library_log("pipreqs failed with:", Logging.Level.SEVERE)
600
+ print(result.stderr)
601
+ sys.exit(1)
602
+
603
+ # tmp_requirements is only generated when pipreqs command is successful
592
604
  tmp_requirements_file_path = os.path.join(project_path, 'tmp_requirements.txt')
593
605
 
594
606
  tmp_requirements = self.fetch_requirements_as_dict(self, tmp_requirements_file_path)
@@ -597,6 +609,11 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
597
609
  tmp_requirements.pop("requests")
598
610
  os.remove(tmp_requirements_file_path)
599
611
 
612
+ # remove corrupt requirements listed by pipreqs
613
+ corrupt_requirements = [key for key in tmp_requirements if key.startswith("~")]
614
+ for requirement in corrupt_requirements:
615
+ del tmp_requirements[requirement]
616
+
600
617
  if len(tmp_requirements) > 0:
601
618
  requirements = self.load_or_add_requirements_file(project_path)
602
619
 
@@ -609,11 +626,26 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
609
626
 
610
627
  missing_deps = {key: tmp_requirements[key] for key in (tmp_requirements.keys() - requirements.keys())}
611
628
  if missing_deps:
612
- self.handle_missing_deps(is_deploy, missing_deps)
629
+ self.handle_missing_deps(missing_deps)
613
630
 
614
631
  unused_deps = list(requirements.keys() - tmp_requirements.keys())
615
632
  if unused_deps:
616
633
  self.handle_unused_deps(unused_deps)
634
+
635
+ if is_deploy and (version_mismatch_deps or missing_deps or unused_deps):
636
+ if force:
637
+ confirm = "y"
638
+ else:
639
+ confirm = input("We detected issues in your requirements.txt. "
640
+ "Would you like us to update it to reflect the necessary changes? (Y/N):")
641
+ if confirm.lower() == "y":
642
+ with open(REQUIREMENTS_TXT, "w") as file:
643
+ file.write("\n".join(tmp_requirements.values()))
644
+ print_library_log(f"`{REQUIREMENTS_TXT}` has been updated successfully")
645
+ else:
646
+ if missing_deps or 'fivetran_connector_sdk' in unused_deps or 'requests' in unused_deps:
647
+ print_library_log(f"Please fix your {REQUIREMENTS_TXT} file to proceed with deployment.")
648
+ os._exit(1)
617
649
  else:
618
650
  if os.path.exists(REQUIREMENTS_TXT):
619
651
  print_library_log("`requirements.txt` is not required as no additional "
@@ -632,15 +664,13 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
632
664
  "they are not used or already installed. Please remove them from requirements.txt:")
633
665
  print(*unused_deps)
634
666
 
635
- def handle_missing_deps(self, is_deploy, missing_deps):
667
+ def handle_missing_deps(self, missing_deps):
636
668
  print_library_log("Please include the following dependency libraries in requirements.txt, to be used by "
637
669
  "Fivetran production. "
638
670
  "For more information, please visit: "
639
671
  "https://fivetran.com/docs/connectors/connector-sdk/detailed-guide"
640
672
  "#workingwithrequirementstxtfile", Logging.Level.SEVERE)
641
673
  print(*list(missing_deps.values()))
642
- if is_deploy:
643
- os._exit(1)
644
674
 
645
675
  def load_or_add_requirements_file(self, project_path):
646
676
  if os.path.exists(REQUIREMENTS_TXT):
@@ -685,7 +715,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
685
715
  "custom_payloads": [],
686
716
  }
687
717
 
688
- self.validate_requirements_file(project_path, True)
718
+ self.validate_requirements_file(project_path, True, force)
689
719
 
690
720
  group_id, group_name = self.__get_group_info(group, deploy_key)
691
721
  connection_id, service = self.__get_connection_id(connection, group, group_id, deploy_key) or (None, None)
@@ -1253,6 +1283,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1253
1283
  else:
1254
1284
  try:
1255
1285
  configuration = self.configuration if self.configuration else request.configuration
1286
+ print_library_log("Initiating the 'schema' method call...", Logging.Level.WARNING)
1256
1287
  response = self.schema_method(configuration)
1257
1288
  self.process_tables(response)
1258
1289
  return connector_sdk_pb2.SchemaResponse(without_schema=common_pb2.TableList(tables=TABLES.values()))
@@ -1260,6 +1291,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1260
1291
  except Exception as e:
1261
1292
  tb = traceback.format_exc()
1262
1293
  error_message = f"Error: {str(e)}\n{tb}"
1294
+ print_library_log(error_message, Logging.Level.SEVERE)
1263
1295
  raise RuntimeError(error_message) from e
1264
1296
 
1265
1297
  def process_tables(self, response):
@@ -1358,6 +1390,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1358
1390
  state = self.state if self.state else json.loads(request.state_json)
1359
1391
 
1360
1392
  try:
1393
+ print_library_log("Initiating the 'update' method call...", Logging.Level.WARNING)
1361
1394
  for resp in self.update_method(configuration=configuration, state=state):
1362
1395
  if isinstance(resp, list):
1363
1396
  for r in resp:
@@ -1372,6 +1405,7 @@ class Connector(connector_sdk_pb2_grpc.ConnectorServicer):
1372
1405
  except Exception as e:
1373
1406
  tb = traceback.format_exc()
1374
1407
  error_message = f"Error: {str(e)}\n{tb}"
1408
+ print_library_log(error_message, Logging.Level.SEVERE)
1375
1409
  raise RuntimeError(error_message) from e
1376
1410
 
1377
1411
 
@@ -1387,19 +1421,24 @@ def find_connector_object(project_path) -> Connector:
1387
1421
  sys.path.append(project_path) # Allows python interpreter to search for modules in this path
1388
1422
  module_name = "connector_connector_code"
1389
1423
  connector_py = os.path.join(project_path, "connector.py")
1390
- spec = importlib.util.spec_from_file_location(module_name, connector_py)
1391
- module = importlib.util.module_from_spec(spec)
1392
- sys.modules[module_name] = module
1393
- spec.loader.exec_module(module)
1394
- for obj in dir(module):
1395
- if not obj.startswith('__'): # Exclude built-in attributes
1396
- obj_attr = getattr(module, obj)
1397
- if '<fivetran_connector_sdk.Connector object at' in str(obj_attr):
1398
- return obj_attr
1424
+ try:
1425
+ spec = importlib.util.spec_from_file_location(module_name, connector_py)
1426
+ module = importlib.util.module_from_spec(spec)
1427
+ sys.modules[module_name] = module
1428
+ spec.loader.exec_module(module)
1429
+ for obj in dir(module):
1430
+ if not obj.startswith('__'): # Exclude built-in attributes
1431
+ obj_attr = getattr(module, obj)
1432
+ if '<fivetran_connector_sdk.Connector object at' in str(obj_attr):
1433
+ return obj_attr
1434
+ except FileNotFoundError:
1435
+ print_library_log(
1436
+ "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)
1437
+ return
1399
1438
 
1400
1439
  print_library_log(
1401
1440
  "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
- sys.exit(1)
1441
+ return
1403
1442
 
1404
1443
 
1405
1444
  def suggest_correct_command(input_command: str) -> bool:
@@ -1490,6 +1529,9 @@ def main():
1490
1529
 
1491
1530
  connector_object = find_connector_object(args.project_path)
1492
1531
 
1532
+ if not connector_object:
1533
+ sys.exit(1)
1534
+
1493
1535
  # Process optional args
1494
1536
  ft_group = args.destination if args.destination else os.getenv('FIVETRAN_DESTINATION_NAME', None)
1495
1537
  ft_connection = args.connection if args.connection else os.getenv('FIVETRAN_CONNECTION_NAME', None)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: fivetran_connector_sdk
3
- Version: 0.12.17.1
3
+ Version: 0.13.10.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