Skip to content

Commit

Permalink
added check_file method to Client
Browse files Browse the repository at this point in the history
  • Loading branch information
charlottekostelic committed Aug 1, 2024
1 parent dae802c commit 7a39ef2
Show file tree
Hide file tree
Showing 6 changed files with 399 additions and 150 deletions.
28 changes: 19 additions & 9 deletions file_retriever/_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ftplib
import os
import paramiko
import sys
from typing import List, Union, Optional

from file_retriever.file import File
Expand Down Expand Up @@ -35,7 +36,7 @@ def __init__(
port: port number for server
"""
self.connection = self.__create_ftp_connection(
self.connection = self._create_ftp_connection(
username=username, password=password, host=host, port=int(port)
)

Expand All @@ -55,7 +56,7 @@ def __exit__(self, *args):
"""
self.connection.close()

def __create_ftp_connection(
def _create_ftp_connection(
self, username: str, password: str, host: str, port: int
) -> ftplib.FTP:
"""
Expand Down Expand Up @@ -102,18 +103,21 @@ def get_remote_file_data(self, file: str, remote_dir: Optional[str] = None) -> F
"""
if remote_dir is not None:
remote_file = f"{remote_dir}/{file}"
file_name = file
else:
remote_file = file
file_name = os.path.basename(remote_file)
file_name = os.path.basename(remote_file)
try:

permissions = None

def get_file_permissions(data):
nonlocal permissions
permissions = File.parse_permissions(data)
permissions = File.parse_permissions(permissions_str=data)

self.connection.retrlines(f"LIST {remote_file}", get_file_permissions),
if permissions is None:
raise ftplib.error_perm("File not found on server.")

return File(
file_name=file_name,
file_size=self.connection.size(remote_file),
Expand All @@ -123,7 +127,13 @@ def get_file_permissions(data):
file_mode=permissions,
)
except ftplib.error_reply:
raise
raise ftplib.error_reply(
f"Received unexpected response from server: {sys.exc_info()[1]}"
)
except ftplib.error_perm:
raise ftplib.error_perm(
f"Unable to retrieve file data: {sys.exc_info()[1]}"
)

def list_file_data(self, remote_dir: str) -> List[File]:
"""
Expand Down Expand Up @@ -173,7 +183,7 @@ def download_file(self, file: str, remote_dir: str, local_dir: str) -> None:
try:
with open(local_file, "wb") as f:
self.connection.retrbinary(f"RETR {remote_file}", f.write)
except OSError:
except (OSError, ftplib.error_reply):
raise

def upload_file(self, file: str, remote_dir: str, local_dir: str) -> File:
Expand Down Expand Up @@ -229,7 +239,7 @@ def __init__(
port: port number for server
"""
self.connection = self.__create_sftp_connection(
self.connection = self._create_sftp_connection(
username=username, password=password, host=host, port=int(port)
)

Expand All @@ -249,7 +259,7 @@ def __exit__(self, *args):
"""
self.connection.close()

def __create_sftp_connection(
def _create_sftp_connection(
self, username: str, password: str, host: str, port: int
) -> paramiko.SFTPClient:
"""
Expand Down
39 changes: 37 additions & 2 deletions file_retriever/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ def _create_client(
case _:
raise ValueError(f"Invalid port number: {self.port}")

def check_file(self, file: str, check_dir: str, remote: bool) -> bool:
"""
Check if `file` exists in `check_dir`. If `remote` is True then check will
be performed on server, otherwise check will be performed locally.
Args:
file: name of file to check
check_dir: directory to check for file
remote: whether to check file on server (True) or locally (False)
Returns:
bool indicating if file exists in `check_dir`
"""
with self.session as session:
if remote:
remote_file = session.get_remote_file_data(file, check_dir)
return remote_file.file_name == file
else:
return os.path.exists(os.path.join(check_dir, file))

def get_file_data(self, file: str, remote_dir: Optional[str] = None) -> List[File]:
"""
Retrieve metadata for file in `remote_dir` on server. If `remote_dir` is not
Expand Down Expand Up @@ -120,23 +140,31 @@ def get_file(
file: str,
remote_dir: Optional[str] = None,
local_dir: str = ".",
check: bool = True,
) -> File:
"""
Downloads `file` from `remote_dir` on server to `local_dir`. If `remote_dir`
is not provided then file will be downloaded from `self.remote_dir`. If
`local_dir` is not provided then file will be downloaded to cwd.
`local_dir` is not provided then file will be downloaded to cwd. If `check` is
True, then `local_dir` will be checked for file before downloading.
Args:
file: name of file to download
remote_dir: directory on server to download file from
local_dir: local directory to download file to
check: check if file exists in `local_dir` before downloading
Returns:
file downloaded to `local_dir` as `File` object
"""
if not remote_dir or remote_dir is None:
remote_dir = self.remote_dir
with self.session as session:
if check and self.check_file(file, check_dir=local_dir, remote=False):
raise FileExistsError(
f"File {file} already exists in {local_dir}. File not downloaded."
)

session.download_file(file=file, remote_dir=remote_dir, local_dir=local_dir)

local_file = os.path.normpath(os.path.join(local_dir, file))
Expand All @@ -147,23 +175,30 @@ def put_file(
file: str,
local_dir: str = ".",
remote_dir: Optional[str] = None,
check: bool = True,
) -> File:
"""
Uploads file from local directory to server. If `remote_dir` is not
provided then file will be uploaded to `self.remote_dir`. If `local_dir`
is not provided then file will be uploaded from cwd.
is not provided then file will be uploaded from cwd. If `check` is
True, then `remote_dir` will be checked for file before downloading.
Args:
file: name of file to upload
local_dir: local directory to upload file from
remote_dir: remote directory to upload file to
check: check if file exists in `remote_dir` before uploading
Returns:
file uploaded to `remote_dir` as `File` object
"""
if remote_dir is None:
remote_dir = self.remote_dir
with self.session as session:
if check and self.check_file(file, check_dir=remote_dir, remote=True):
raise FileExistsError(
f"File {file} already exists in {remote_dir}. File not uploaded."
)
uploaded_file = session.upload_file(
file=file, remote_dir=remote_dir, local_dir=local_dir
)
Expand Down
6 changes: 3 additions & 3 deletions file_retriever/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def parse_mdtm_time(mdtm_time: str) -> int:
)

@staticmethod
def parse_permissions(permissions: str) -> int:
def parse_permissions(permissions_str: str) -> int:
"""
parse permissions string to decimal value.
Expand All @@ -91,9 +91,9 @@ def parse_permissions(permissions: str) -> int:
(filetype * 8^5) + (0 * 8^4) + (0 * 8^3) + (owner * 8^2) +
(group * 8^1) + (others * 8^0) = decimal value
"""
file_type = permissions[0].replace("d", "4").replace("-", "1")
file_type = permissions_str[0].replace("d", "4").replace("-", "1")
file_perm = (
permissions[1:10]
permissions_str[1:10]
.replace("-", "0")
.replace("r", "4")
.replace("w", "2")
Expand Down
Loading

0 comments on commit 7a39ef2

Please sign in to comment.