saviialib 1.6.1__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.
Files changed (91) hide show
  1. saviialib/__init__.py +79 -0
  2. saviialib/general_types/__init__.py +0 -0
  3. saviialib/general_types/api/__init__.py +0 -0
  4. saviialib/general_types/api/saviia_api_types.py +48 -0
  5. saviialib/general_types/api/saviia_backup_api_types.py +24 -0
  6. saviialib/general_types/api/saviia_netcamera_api_types.py +11 -0
  7. saviialib/general_types/api/saviia_shakes_api_types.py +21 -0
  8. saviialib/general_types/api/saviia_thies_api_types.py +31 -0
  9. saviialib/general_types/error_types/__init__.py +0 -0
  10. saviialib/general_types/error_types/api/__init__.py +0 -0
  11. saviialib/general_types/error_types/api/saviia_api_error_types.py +113 -0
  12. saviialib/general_types/error_types/api/saviia_netcamera_error_types.py +7 -0
  13. saviialib/general_types/error_types/common/__init__.py +7 -0
  14. saviialib/general_types/error_types/common/common_types.py +26 -0
  15. saviialib/libs/directory_client/__init__.py +4 -0
  16. saviialib/libs/directory_client/client/os_client.py +55 -0
  17. saviialib/libs/directory_client/directory_client.py +44 -0
  18. saviialib/libs/directory_client/directory_client_contract.py +40 -0
  19. saviialib/libs/directory_client/types/directory_client_types.py +6 -0
  20. saviialib/libs/files_client/__init__.py +4 -0
  21. saviialib/libs/files_client/clients/aiofiles_client.py +44 -0
  22. saviialib/libs/files_client/clients/csv_client.py +42 -0
  23. saviialib/libs/files_client/files_client.py +26 -0
  24. saviialib/libs/files_client/files_client_contract.py +13 -0
  25. saviialib/libs/files_client/types/files_client_types.py +32 -0
  26. saviialib/libs/ftp_client/__init__.py +4 -0
  27. saviialib/libs/ftp_client/clients/__init__.py +0 -0
  28. saviialib/libs/ftp_client/clients/aioftp_client.py +52 -0
  29. saviialib/libs/ftp_client/clients/ftplib_client.py +58 -0
  30. saviialib/libs/ftp_client/ftp_client.py +25 -0
  31. saviialib/libs/ftp_client/ftp_client_contract.py +13 -0
  32. saviialib/libs/ftp_client/types/__init__.py +3 -0
  33. saviialib/libs/ftp_client/types/ftp_client_types.py +18 -0
  34. saviialib/libs/log_client/__init__.py +19 -0
  35. saviialib/libs/log_client/log_client.py +46 -0
  36. saviialib/libs/log_client/log_client_contract.py +28 -0
  37. saviialib/libs/log_client/logging_client/logging_client.py +58 -0
  38. saviialib/libs/log_client/types/__init__.py +0 -0
  39. saviialib/libs/log_client/types/log_client_types.py +47 -0
  40. saviialib/libs/log_client/utils/log_client_utils.py +6 -0
  41. saviialib/libs/sftp_client/__init__.py +8 -0
  42. saviialib/libs/sftp_client/clients/asyncssh_sftp_client.py +83 -0
  43. saviialib/libs/sftp_client/sftp_client.py +26 -0
  44. saviialib/libs/sftp_client/sftp_client_contract.py +13 -0
  45. saviialib/libs/sftp_client/types/sftp_client_types.py +24 -0
  46. saviialib/libs/sharepoint_client/__init__.py +17 -0
  47. saviialib/libs/sharepoint_client/clients/sharepoint_rest_api.py +160 -0
  48. saviialib/libs/sharepoint_client/sharepoint_client.py +58 -0
  49. saviialib/libs/sharepoint_client/sharepoint_client_contract.py +26 -0
  50. saviialib/libs/sharepoint_client/types/sharepoint_client_types.py +30 -0
  51. saviialib/libs/zero_dependency/utils/booleans_utils.py +2 -0
  52. saviialib/libs/zero_dependency/utils/datetime_utils.py +25 -0
  53. saviialib/libs/zero_dependency/utils/strings_utils.py +5 -0
  54. saviialib/services/backup/__init__.py +0 -0
  55. saviialib/services/backup/api.py +36 -0
  56. saviialib/services/backup/controllers/__init__.py +0 -0
  57. saviialib/services/backup/controllers/types/__init__.py +6 -0
  58. saviialib/services/backup/controllers/types/upload_backup_to_sharepoint_types.py +18 -0
  59. saviialib/services/backup/controllers/upload_backup_to_sharepoint.py +87 -0
  60. saviialib/services/backup/use_cases/constants/upload_backup_to_sharepoint_constants.py +5 -0
  61. saviialib/services/backup/use_cases/types/__init__.py +7 -0
  62. saviialib/services/backup/use_cases/types/upload_backup_to_sharepoint_types.py +11 -0
  63. saviialib/services/backup/use_cases/upload_backup_to_sharepoint.py +474 -0
  64. saviialib/services/backup/utils/__init__.py +3 -0
  65. saviialib/services/backup/utils/upload_backup_to_sharepoint_utils.py +100 -0
  66. saviialib/services/netcamera/api.py +30 -0
  67. saviialib/services/netcamera/controllers/get_media_files.py +40 -0
  68. saviialib/services/netcamera/controllers/types/get_media_files_types.py +16 -0
  69. saviialib/services/netcamera/use_cases/get_media_files.py +76 -0
  70. saviialib/services/netcamera/use_cases/types/get_media_files_types.py +18 -0
  71. saviialib/services/shakes/__init__.py +0 -0
  72. saviialib/services/shakes/api.py +31 -0
  73. saviialib/services/shakes/controllers/get_miniseed_files.py +48 -0
  74. saviialib/services/shakes/controllers/types/get_miniseed_files_types.py +16 -0
  75. saviialib/services/shakes/use_cases/get_miniseed_files.py +79 -0
  76. saviialib/services/shakes/use_cases/types/get_miniseed_files_types.py +18 -0
  77. saviialib/services/shakes/use_cases/utils/get_miniseed_files_utils.py +11 -0
  78. saviialib/services/thies/__init__.py +0 -0
  79. saviialib/services/thies/api.py +42 -0
  80. saviialib/services/thies/constants/update_thies_data_constants.py +67 -0
  81. saviialib/services/thies/controllers/types/update_thies_data_types.py +18 -0
  82. saviialib/services/thies/controllers/update_thies_data.py +119 -0
  83. saviialib/services/thies/use_cases/components/create_thies_statistics_file.py +115 -0
  84. saviialib/services/thies/use_cases/components/thies_bp.py +442 -0
  85. saviialib/services/thies/use_cases/types/update_thies_data_types.py +24 -0
  86. saviialib/services/thies/use_cases/update_thies_data.py +391 -0
  87. saviialib/services/thies/utils/update_thies_data_utils.py +21 -0
  88. saviialib-1.6.1.dist-info/METADATA +126 -0
  89. saviialib-1.6.1.dist-info/RECORD +91 -0
  90. saviialib-1.6.1.dist-info/WHEEL +4 -0
  91. saviialib-1.6.1.dist-info/licenses/LICENSE +22 -0
@@ -0,0 +1,32 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal, Union, List, Dict
3
+
4
+
5
+ @dataclass
6
+ class FilesClientInitArgs:
7
+ client_name: str = "aiofiles_client"
8
+
9
+
10
+ @dataclass
11
+ class ReadArgs:
12
+ """
13
+ Represents the arguments required to read a file.
14
+
15
+ Attributes:
16
+ file_path (str): The path to the file to be read.
17
+ mode (Literal['r', 'rb']): The mode in which the file should be opened.
18
+ - 'r': Open for reading (text mode).
19
+ - 'rb': Open for reading (binary mode).
20
+ """
21
+
22
+ file_path: str
23
+ mode: Literal["r", "rb", "json"]
24
+ encoding: str = "utf-8"
25
+
26
+
27
+ @dataclass
28
+ class WriteArgs:
29
+ file_name: str
30
+ file_content: Union[str, bytes, List[Dict]]
31
+ mode: Literal["w", "wb", "a", "json"]
32
+ destination_path: str = ""
@@ -0,0 +1,4 @@
1
+ from .ftp_client import FTPClient
2
+ from .types import FtpClientInitArgs, FtpListFilesArgs, FtpReadFileArgs
3
+
4
+ __all__ = ["FTPClient", "FtpClientInitArgs", "FtpListFilesArgs", "FtpReadFileArgs"]
File without changes
@@ -0,0 +1,52 @@
1
+ from aioftp import Client
2
+ from aioftp.errors import StatusCodeError
3
+ from saviialib.libs.ftp_client.ftp_client_contract import (
4
+ FTPClientContract,
5
+ )
6
+ from saviialib.libs.ftp_client.types.ftp_client_types import (
7
+ FtpClientInitArgs,
8
+ FtpListFilesArgs,
9
+ FtpReadFileArgs,
10
+ )
11
+
12
+
13
+ class AioFTPClient(FTPClientContract):
14
+ def __init__(self, args: FtpClientInitArgs) -> None:
15
+ self.host = args.config.ftp_host
16
+ self.port = args.config.ftp_port
17
+ self.password = args.config.ftp_password
18
+ self.user = args.config.ftp_user
19
+ self.client = Client()
20
+
21
+ async def _async_start(self) -> None:
22
+ try:
23
+ await self.client.connect(host=self.host, port=self.port)
24
+ except OSError:
25
+ raise ConnectionRefusedError(
26
+ f"{self.host}:{self.port} isn't active. "
27
+ "Please ensure the server is running and accessible."
28
+ )
29
+ try:
30
+ await self.client.login(user=self.user, password=self.password)
31
+ except StatusCodeError:
32
+ raise ConnectionAbortedError(
33
+ "Authentication failed. Please verify your credentials and try again."
34
+ )
35
+
36
+ async def list_files(self, args: FtpListFilesArgs) -> list[str]:
37
+ try:
38
+ await self._async_start()
39
+ files = []
40
+ async for path, info in self.client.list(args.path, recursive=False):
41
+ files.append((path.name, int((info.get("size", 0)))))
42
+ return files
43
+ except StatusCodeError as error:
44
+ raise ConnectionAbortedError(error)
45
+
46
+ async def read_file(self, args: FtpReadFileArgs) -> bytes:
47
+ await self._async_start()
48
+ try:
49
+ async with self.client.download_stream(args.file_path) as stream: # type: ignore
50
+ return await stream.read()
51
+ except StatusCodeError as error:
52
+ raise FileNotFoundError(f"File not found: {args.file_path}") from error
@@ -0,0 +1,58 @@
1
+ import ftplib
2
+ import asyncio
3
+ from io import BytesIO
4
+ from saviialib.libs.ftp_client.ftp_client_contract import (
5
+ FTPClientContract,
6
+ )
7
+ from saviialib.libs.ftp_client.types.ftp_client_types import (
8
+ FtpClientInitArgs,
9
+ FtpListFilesArgs,
10
+ FtpReadFileArgs,
11
+ )
12
+
13
+
14
+ class FtplibClient(FTPClientContract):
15
+ def __init__(self, args: FtpClientInitArgs) -> None:
16
+ self.host = args.config.ftp_host
17
+ self.port = args.config.ftp_port
18
+ self.password = args.config.ftp_password
19
+ self.user = args.config.ftp_user
20
+ self.client = ftplib.FTP(host=self.host, user=self.user, passwd=self.password)
21
+
22
+ async def _async_start(self) -> None:
23
+ try:
24
+ await asyncio.to_thread(self.client.login, self.user, self.password)
25
+ except OSError:
26
+ raise ConnectionRefusedError(
27
+ f"{self.host}:{self.port} isn't active. "
28
+ "Please ensure the server is running and accessible."
29
+ )
30
+ except Exception as error:
31
+ raise ConnectionError(
32
+ f"General connection for {self.host}:{self.port}.", error.__str__()
33
+ )
34
+
35
+ async def list_files(self, args: FtpListFilesArgs) -> list[str]:
36
+ try:
37
+ EXCLUDED_NAMES = [".", ".."]
38
+ await self._async_start()
39
+ await asyncio.to_thread(self.client.cwd, args.path)
40
+ filenames = await asyncio.to_thread(self.client.nlst, args.path)
41
+ return [
42
+ filename for filename in filenames if filename not in EXCLUDED_NAMES
43
+ ]
44
+ except Exception as error:
45
+ raise ConnectionAbortedError(error)
46
+
47
+ async def read_file(self, args: FtpReadFileArgs) -> bytes:
48
+ await self._async_start()
49
+ try:
50
+ file_content = BytesIO()
51
+ await asyncio.to_thread(
52
+ self.client.retrbinary, "RETR " + args.file_path, file_content.write
53
+ )
54
+ await asyncio.to_thread(file_content.seek, 0)
55
+ file_bytes = await asyncio.to_thread(file_content.read)
56
+ return file_bytes
57
+ except Exception as error:
58
+ raise FileNotFoundError(f"File not found: {args.file_path}") from error
@@ -0,0 +1,25 @@
1
+ from .clients.aioftp_client import AioFTPClient
2
+ from .clients.ftplib_client import FtplibClient
3
+ from .ftp_client_contract import FTPClientContract
4
+ from .types.ftp_client_types import FtpClientInitArgs, FtpListFilesArgs, FtpReadFileArgs
5
+
6
+
7
+ class FTPClient(FTPClientContract):
8
+ CLIENTS = {"aioftp_client", "ftplib_client"}
9
+
10
+ def __init__(self, args: FtpClientInitArgs) -> None:
11
+ if args.client_name not in FTPClient.CLIENTS:
12
+ msg = f"Unsupported client {args.client_name}"
13
+ raise KeyError(msg)
14
+
15
+ if args.client_name == "aioftp_client":
16
+ self.client_obj = AioFTPClient(args)
17
+ elif args.client_name == "ftplib_client":
18
+ self.client_obj = FtplibClient(args)
19
+ self.client_name = args.client_name
20
+
21
+ async def list_files(self, args: FtpListFilesArgs) -> list[str]:
22
+ return await self.client_obj.list_files(args)
23
+
24
+ async def read_file(self, args: FtpReadFileArgs) -> bytes:
25
+ return await self.client_obj.read_file(args)
@@ -0,0 +1,13 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from .types.ftp_client_types import FtpListFilesArgs, FtpReadFileArgs
4
+
5
+
6
+ class FTPClientContract(ABC):
7
+ @abstractmethod
8
+ async def list_files(self, args: FtpListFilesArgs) -> list[str]:
9
+ pass
10
+
11
+ @abstractmethod
12
+ async def read_file(self, args: FtpReadFileArgs) -> bytes:
13
+ pass
@@ -0,0 +1,3 @@
1
+ from .ftp_client_types import FtpClientInitArgs, FtpListFilesArgs, FtpReadFileArgs
2
+
3
+ __all__ = ["FtpClientInitArgs", "FtpListFilesArgs", "FtpReadFileArgs"]
@@ -0,0 +1,18 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+
4
+
5
+ @dataclass
6
+ class FtpClientInitArgs:
7
+ config: Any
8
+ client_name: str = "aioftp_client"
9
+
10
+
11
+ @dataclass
12
+ class FtpListFilesArgs:
13
+ path: str
14
+
15
+
16
+ @dataclass
17
+ class FtpReadFileArgs:
18
+ file_path: str
@@ -0,0 +1,19 @@
1
+ from saviialib.libs.log_client.log_client import LogClient
2
+ from .types.log_client_types import (
3
+ InfoArgs,
4
+ DebugArgs,
5
+ ErrorArgs,
6
+ WarningArgs,
7
+ LogClientArgs,
8
+ LogStatus,
9
+ )
10
+
11
+ __all__ = [
12
+ "LogClient",
13
+ "InfoArgs",
14
+ "DebugArgs",
15
+ "ErrorArgs",
16
+ "WarningArgs",
17
+ "LogClientArgs",
18
+ "LogStatus",
19
+ ]
@@ -0,0 +1,46 @@
1
+ # Internal modules
2
+ from saviialib.libs.log_client.log_client_contract import LogClientContract
3
+ from saviialib.libs.log_client.logging_client.logging_client import LoggingClient
4
+ from saviialib.libs.log_client.types.log_client_types import (
5
+ ErrorArgs,
6
+ InfoArgs,
7
+ LogClientArgs,
8
+ DebugArgs,
9
+ WarningArgs,
10
+ )
11
+
12
+
13
+ class LogClient(LogClientContract):
14
+ def __init__(self, args: LogClientArgs):
15
+ clients = {
16
+ "logging": LoggingClient(args),
17
+ }
18
+ if clients.get(args.client_name):
19
+ self.client_name = args.client_name
20
+ self.client_obj = clients[args.client_name]
21
+ else:
22
+ raise KeyError(f"Unsupported client '{args.client_name}'.")
23
+
24
+ @property
25
+ def method_name(self):
26
+ return self.client_obj.method_name
27
+
28
+ @method_name.setter
29
+ def method_name(self, method_name: str):
30
+ self.client_obj.method_name = method_name
31
+
32
+ @property
33
+ def log_history(self):
34
+ return self.client_obj.log_history
35
+
36
+ def info(self, args: InfoArgs):
37
+ return self.client_obj.info(args)
38
+
39
+ def error(self, args: ErrorArgs):
40
+ return self.client_obj.error(args)
41
+
42
+ def debug(self, args: DebugArgs):
43
+ return self.client_obj.debug(args)
44
+
45
+ def warning(self, args: WarningArgs):
46
+ return self.client_obj.warning(args)
@@ -0,0 +1,28 @@
1
+ # External libraries
2
+ from abc import ABC, abstractmethod
3
+
4
+ # Internal modules
5
+ from saviialib.libs.log_client.types.log_client_types import (
6
+ ErrorArgs,
7
+ InfoArgs,
8
+ DebugArgs,
9
+ WarningArgs,
10
+ )
11
+
12
+
13
+ class LogClientContract(ABC):
14
+ @abstractmethod
15
+ def info(self, args: InfoArgs):
16
+ pass
17
+
18
+ @abstractmethod
19
+ def error(self, args: ErrorArgs):
20
+ pass
21
+
22
+ @abstractmethod
23
+ def debug(self, args: DebugArgs):
24
+ pass
25
+
26
+ @abstractmethod
27
+ def warning(self, args: WarningArgs):
28
+ pass
@@ -0,0 +1,58 @@
1
+ # External libraries
2
+ import logging
3
+
4
+ # Internal modules
5
+ from saviialib.libs.log_client.utils.log_client_utils import format_message
6
+ from saviialib.libs.log_client.log_client_contract import LogClientContract
7
+ from saviialib.libs.log_client.types.log_client_types import (
8
+ ErrorArgs,
9
+ InfoArgs,
10
+ LogClientArgs,
11
+ DebugArgs,
12
+ WarningArgs,
13
+ )
14
+
15
+ from saviialib.libs.zero_dependency.utils.datetime_utils import today, datetime_to_str
16
+
17
+
18
+ class LoggingClient(LogClientContract):
19
+ def __init__(self, args: LogClientArgs):
20
+ log_format = "{message}"
21
+ logging.basicConfig(format=log_format, level=logging.INFO, style="{")
22
+ self.class_name = args.class_name
23
+ self.method_name = args.method_name
24
+ self.active_record = args.active_record
25
+ self.log_history = []
26
+
27
+ def _save_to_history(self, meta: dict):
28
+ self.log_history.append(
29
+ f"[{datetime_to_str(today(), date_format='%m-%d-%Y %H:%M:%S')}][{self.class_name}] {meta.get('msg', '')}"
30
+ )
31
+
32
+ def info(self, args: InfoArgs) -> None:
33
+ if self.active_record:
34
+ self._save_to_history(args.metadata)
35
+ return logging.info(
36
+ format_message(self.class_name, self.method_name, args.status)
37
+ )
38
+
39
+ def error(self, args: ErrorArgs) -> None:
40
+ if self.active_record:
41
+ self._save_to_history(args.metadata)
42
+ return logging.error(
43
+ format_message(self.class_name, self.method_name, args.status)
44
+ )
45
+
46
+ def debug(self, args: DebugArgs) -> None:
47
+ if self.active_record:
48
+ self._save_to_history(args.metadata)
49
+ return logging.debug(
50
+ format_message(self.class_name, self.method_name, args.status)
51
+ )
52
+
53
+ def warning(self, args: WarningArgs) -> None:
54
+ if self.active_record:
55
+ self._save_to_history(args.metadata)
56
+ return logging.warning(
57
+ format_message(self.class_name, self.method_name, args.status)
58
+ )
File without changes
@@ -0,0 +1,47 @@
1
+ from typing import Literal, Dict
2
+ from enum import Enum
3
+ from dataclasses import dataclass, field
4
+
5
+
6
+ class LogStatus(Enum):
7
+ STARTED = "started"
8
+ SUCCESSFUL = "successful"
9
+ FAILED = "failed"
10
+ ERROR = "error"
11
+ EARLY_RETURN = "early_return"
12
+ ALERT = "alert"
13
+
14
+
15
+ @dataclass
16
+ class LogClientArgs:
17
+ client_name: str = field(default="logging")
18
+ service_name: str = field(default="")
19
+ class_name: str = field(default="")
20
+ method_name: str = field(default="")
21
+ active_record: bool = False
22
+
23
+
24
+ @dataclass
25
+ class InfoArgs:
26
+ status: Literal[LogStatus.STARTED, LogStatus.SUCCESSFUL, LogStatus.EARLY_RETURN]
27
+ metadata: Dict = field(default_factory=dict)
28
+
29
+
30
+ @dataclass
31
+ class DebugArgs:
32
+ status: Literal[
33
+ LogStatus.STARTED, LogStatus.SUCCESSFUL, LogStatus.EARLY_RETURN, LogStatus.ALERT
34
+ ]
35
+ metadata: Dict = field(default_factory=dict)
36
+
37
+
38
+ @dataclass
39
+ class ErrorArgs:
40
+ status: Literal[LogStatus.ERROR]
41
+ metadata: Dict = field(default_factory=dict)
42
+
43
+
44
+ @dataclass
45
+ class WarningArgs:
46
+ status: Literal[LogStatus.FAILED, LogStatus.ALERT]
47
+ metadata: Dict = field(default_factory=dict)
@@ -0,0 +1,6 @@
1
+ # Internal libraries
2
+ from saviialib.libs.log_client.types.log_client_types import LogStatus
3
+
4
+
5
+ def format_message(class_name: str, method_name: str, status: LogStatus) -> str:
6
+ return f"{class_name}: {method_name}_{status.value}"
@@ -0,0 +1,8 @@
1
+ from .sftp_client import SFTPClient
2
+ from .types.sftp_client_types import (
3
+ ListfilesArgs,
4
+ DownloadfilesArgs,
5
+ SFTPClientInitArgs,
6
+ )
7
+
8
+ __all__ = ["SFTPClient", "ListfilesArgs", "DownloadfilesArgs", "SFTPClientInitArgs"]
@@ -0,0 +1,83 @@
1
+ from saviialib.libs.sftp_client.sftp_client_contract import SFTPClientContract
2
+ from saviialib.libs.sftp_client.types.sftp_client_types import (
3
+ SFTPClientInitArgs,
4
+ ListfilesArgs,
5
+ DownloadfilesArgs,
6
+ )
7
+ from typing import Optional, List, Tuple
8
+ from saviialib.general_types.error_types.common.common_types import EmptyDataError
9
+ import asyncssh # type: ignore
10
+ from saviialib.libs.directory_client import DirectoryClient, DirectoryClientArgs
11
+
12
+
13
+ class AsyncsshSFTPClient(SFTPClientContract):
14
+ def __init__(self, args: SFTPClientInitArgs) -> None:
15
+ self.host: str = args.host
16
+ self.port: int = args.port
17
+ self.username: str = args.username
18
+ self.password: Optional[str] = args.password
19
+ self.ssh_key_path: Optional[str] = args.ssh_key_path
20
+ self.dir_client = DirectoryClient(DirectoryClientArgs("os_client"))
21
+ self._validate_credentials()
22
+
23
+ def _validate_credentials(self):
24
+ if not self.password and not self.ssh_key_path:
25
+ raise EmptyDataError(
26
+ reason="At least one attribute (ssh key or password) must be provided"
27
+ )
28
+
29
+ async def _start_connection(
30
+ self,
31
+ ) -> Tuple[asyncssh.SSHClientConnection, asyncssh.SFTPClient]:
32
+ try:
33
+ ssh_connection = await asyncssh.connect(
34
+ self.host,
35
+ username=self.username,
36
+ port=self.port,
37
+ client_keys=[self.ssh_key_path],
38
+ password=self.password,
39
+ )
40
+ sftp_client = await ssh_connection.start_sftp_client()
41
+ return ssh_connection, sftp_client
42
+ except (OSError, asyncssh.Error) as exc:
43
+ raise ConnectionError("SFTP Operation failed: " + str(exc))
44
+
45
+ async def list_files(self, args: ListfilesArgs) -> List[str]:
46
+ ssh_conn, sftp_client = await self._start_connection()
47
+ async with ssh_conn:
48
+ async with sftp_client:
49
+ files = await sftp_client.listdir(args.path)
50
+ files = [f for f in files if f not in (".", "..")]
51
+ return files
52
+ await self._end_connection(ssh_conn)
53
+
54
+ async def download_files(self, args: DownloadfilesArgs) -> None:
55
+ ssh_conn, sftp_client = await self._start_connection()
56
+ if not args.destination_path or not args.source_path:
57
+ conflict_path = (
58
+ "destination path" if not args.destination_path else "source path"
59
+ )
60
+ raise ConnectionError(f"The {conflict_path} must be provided.")
61
+
62
+ download_all = len(args.files_to_download) == 0
63
+ async with ssh_conn:
64
+ async with sftp_client:
65
+ if download_all:
66
+ await sftp_client.get(
67
+ args.source_path,
68
+ args.destination_path,
69
+ recurse=True,
70
+ preserve=True,
71
+ )
72
+ else:
73
+ for filename in args.files_to_download:
74
+ source_path = self.dir_client.join_paths(
75
+ args.source_path, filename
76
+ )
77
+ dest_path = self.dir_client.join_paths(
78
+ args.destination_path, filename
79
+ )
80
+ await sftp_client.get(source_path, dest_path)
81
+
82
+ async def _end_connection(self, connection) -> None:
83
+ await connection.wait_closed()
@@ -0,0 +1,26 @@
1
+ from .sftp_client_contract import SFTPClientContract
2
+ from .types.sftp_client_types import (
3
+ SFTPClientInitArgs,
4
+ ListfilesArgs,
5
+ DownloadfilesArgs,
6
+ )
7
+ from .clients.asyncssh_sftp_client import AsyncsshSFTPClient
8
+ from typing import List
9
+
10
+
11
+ class SFTPClient(SFTPClientContract):
12
+ CLIENTS = {"asyncssh_sftp"}
13
+
14
+ def __init__(self, args: SFTPClientInitArgs) -> None:
15
+ if args.client_name not in SFTPClient.CLIENTS:
16
+ msg = f"Unsupported client {args.client_name}"
17
+ raise KeyError(msg)
18
+ if args.client_name == "asyncssh_sftp":
19
+ self.client_obj = AsyncsshSFTPClient(args)
20
+ self.client_name = args.client_name
21
+
22
+ async def list_files(self, args: ListfilesArgs) -> List[str]:
23
+ return await self.client_obj.list_files(args)
24
+
25
+ async def download_files(self, args: DownloadfilesArgs) -> None:
26
+ return await self.client_obj.download_files(args)
@@ -0,0 +1,13 @@
1
+ from .types.sftp_client_types import ListfilesArgs, DownloadfilesArgs
2
+ from abc import ABC, abstractmethod
3
+ from typing import List
4
+
5
+
6
+ class SFTPClientContract(ABC):
7
+ @abstractmethod
8
+ async def list_files(self, args: ListfilesArgs) -> List[str]:
9
+ pass
10
+
11
+ @abstractmethod
12
+ async def download_files(self, args: DownloadfilesArgs) -> None:
13
+ pass
@@ -0,0 +1,24 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional, List
3
+
4
+
5
+ @dataclass
6
+ class SFTPClientInitArgs:
7
+ client_name: str
8
+ password: Optional[str]
9
+ username: str
10
+ ssh_key_path: str
11
+ host: str = "localhost"
12
+ port: int = 22
13
+
14
+
15
+ @dataclass
16
+ class ListfilesArgs:
17
+ path: str
18
+
19
+
20
+ @dataclass
21
+ class DownloadfilesArgs:
22
+ source_path: str
23
+ destination_path: str
24
+ files_to_download: List[str] = field(default_factory=list)
@@ -0,0 +1,17 @@
1
+ from .sharepoint_client import SharepointClient
2
+ from .types.sharepoint_client_types import (
3
+ SharepointClientInitArgs,
4
+ SpListFilesArgs,
5
+ SpListFoldersArgs,
6
+ SpUploadFileArgs,
7
+ SpCreateFolderArgs,
8
+ )
9
+
10
+ __all__ = [
11
+ "SharepointClientInitArgs",
12
+ "SharepointClient",
13
+ "SpListFilesArgs",
14
+ "SpListFoldersArgs",
15
+ "SpUploadFileArgs",
16
+ "SpCreateFolderArgs",
17
+ ]