ftp_download.ensure
1from .prefs import Conf 2 3import re 4import sys 5import ftplib 6from io import StringIO 7from typing import Dict, List 8from pathlib import PureWindowsPath 9 10# IMPORTANT: https://kb.globalscape.com/KnowledgebaseArticle10142.aspx 11 12 13def posix_path(path: str) -> str: 14 15 """ 16 Normalizes a path and make compatible usual FTP file systems (unix-like). 17 18 ### Args: 19 20 - **path** (`str`): The path to be normalized; 21 22 ### Returns: 23 24 A `str` with path normalized and in posix format. 25 """ # noqa 26 27 posix_path = PureWindowsPath(path).as_posix() 28 swap_drive_letter_for_root = re.compile("[A-Z]:/", re.IGNORECASE) 29 return swap_drive_letter_for_root.sub("/", posix_path) 30 31 32def describe_dir( 33 ftp: ftplib.FTP, 34 path: str = '' 35 ) -> Dict[str, List[str]]: 36 37 """ 38 Describes the remote path showing names of files and folders in the specified directory. 39 40 ### Args: 41 42 - **ftp** (`ftplib.FTP`): A `ftplib.FTP` connected and logged in to the server 43 - **path** (`str`): Path to be described 44 45 ### Returns: 46 47 A `dict` with two keys `"dirs"` and `"files"`. The first stores a `list` of dirnames in the specified directory, and the latter stores a `list` of filenames. 48 """ # noqa 49 50 # Capturing stdout adapted from: 51 # https://stackoverflow.com/questions/5136611/capture-stdout-from-a-script 52 53 curr_stdout = sys.stdout 54 capturer = StringIO() 55 sys.stdout = capturer 56 57 ftp.dir(posix_path(path)) 58 59 sys.stdout = curr_stdout 60 # Capture stdout as a list 61 # Last item is always an empty line 62 lines_list = capturer.getvalue().split("\n")[:-1] 63 64 # Will get wrong result if filename or dirname has space " " 65 paths = {} 66 paths["dirs"] = [i.rpartition(" ")[-1] for i in lines_list if i[0] == "d"] 67 paths["files"] = [i.rpartition(" ")[-1] for i in lines_list if i[0] != "d"] 68 69 if len(paths["dirs"]) + len(paths["files"]) == 0: 70 error_msg = "Invalid path provided." 71 if Conf.raise_if_invalid: 72 raise ftplib.error_perm(error_msg) 73 else: 74 print(error_msg) 75 76 return paths 77 78 79def login(ftp: ftplib.FTP) -> None: 80 81 """ 82 Logs in to the specified `ftplib.FTP` object's server and skips any login error. 83 84 ### Args: 85 86 - **ftp** (`ftplib.FTP`): A connected `ftplib.FTP` object 87 """ # noqa 88 89 try: 90 ftp.login() 91 except ftplib.error_perm as perm_err: 92 resp = perm_err.__str__() 93 94 if resp[:3] != "530": 95 raise ftplib.error_perm(resp)
def
posix_path(path: str) -> str:
14def posix_path(path: str) -> str: 15 16 """ 17 Normalizes a path and make compatible usual FTP file systems (unix-like). 18 19 ### Args: 20 21 - **path** (`str`): The path to be normalized; 22 23 ### Returns: 24 25 A `str` with path normalized and in posix format. 26 """ # noqa 27 28 posix_path = PureWindowsPath(path).as_posix() 29 swap_drive_letter_for_root = re.compile("[A-Z]:/", re.IGNORECASE) 30 return swap_drive_letter_for_root.sub("/", posix_path)
Normalizes a path and make compatible usual FTP file systems (unix-like).
Args:
- path (
str
): The path to be normalized;
Returns:
A str
with path normalized and in posix format.
def
describe_dir(ftp: ftplib.FTP, path: str = '') -> Dict[str, List[str]]:
33def describe_dir( 34 ftp: ftplib.FTP, 35 path: str = '' 36 ) -> Dict[str, List[str]]: 37 38 """ 39 Describes the remote path showing names of files and folders in the specified directory. 40 41 ### Args: 42 43 - **ftp** (`ftplib.FTP`): A `ftplib.FTP` connected and logged in to the server 44 - **path** (`str`): Path to be described 45 46 ### Returns: 47 48 A `dict` with two keys `"dirs"` and `"files"`. The first stores a `list` of dirnames in the specified directory, and the latter stores a `list` of filenames. 49 """ # noqa 50 51 # Capturing stdout adapted from: 52 # https://stackoverflow.com/questions/5136611/capture-stdout-from-a-script 53 54 curr_stdout = sys.stdout 55 capturer = StringIO() 56 sys.stdout = capturer 57 58 ftp.dir(posix_path(path)) 59 60 sys.stdout = curr_stdout 61 # Capture stdout as a list 62 # Last item is always an empty line 63 lines_list = capturer.getvalue().split("\n")[:-1] 64 65 # Will get wrong result if filename or dirname has space " " 66 paths = {} 67 paths["dirs"] = [i.rpartition(" ")[-1] for i in lines_list if i[0] == "d"] 68 paths["files"] = [i.rpartition(" ")[-1] for i in lines_list if i[0] != "d"] 69 70 if len(paths["dirs"]) + len(paths["files"]) == 0: 71 error_msg = "Invalid path provided." 72 if Conf.raise_if_invalid: 73 raise ftplib.error_perm(error_msg) 74 else: 75 print(error_msg) 76 77 return paths
Describes the remote path showing names of files and folders in the specified directory.
Args:
- ftp (
ftplib.FTP
): Aftplib.FTP
connected and logged in to the server - path (
str
): Path to be described
Returns:
A dict
with two keys "dirs"
and "files"
. The first stores a list
of dirnames in the specified directory, and the latter stores a list
of filenames.
def
login(ftp: ftplib.FTP) -> None:
80def login(ftp: ftplib.FTP) -> None: 81 82 """ 83 Logs in to the specified `ftplib.FTP` object's server and skips any login error. 84 85 ### Args: 86 87 - **ftp** (`ftplib.FTP`): A connected `ftplib.FTP` object 88 """ # noqa 89 90 try: 91 ftp.login() 92 except ftplib.error_perm as perm_err: 93 resp = perm_err.__str__() 94 95 if resp[:3] != "530": 96 raise ftplib.error_perm(resp)
Logs in to the specified ftplib.FTP
object's server and skips any login error.
Args:
- ftp (
ftplib.FTP
): A connectedftplib.FTP
object