Skip to content

Commit 977d3c2

Browse files
authored
Merge pull request #2 from fnmeyer/docstrings
Docstrings
2 parents d1676a3 + 1fe373b commit 977d3c2

File tree

14 files changed

+197
-17
lines changed

14 files changed

+197
-17
lines changed

end-to-end-tests/tests.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Test end-to-end functionality for sysrsync."""
12
import inspect
23
import os
34
import sys
@@ -11,7 +12,10 @@
1112

1213

1314
class TestE2E(unittest.TestCase):
15+
"""Test end-to-end functionality."""
16+
1417
def test_send_file(self):
18+
"""Test sending a file from local to remote."""
1519
sysrsync.run(source="end-to-end-tests/test-cases/test_file",
1620
destination="/tmp/target_test_file",
1721
destination_ssh="test@openssh-server",
@@ -20,6 +24,7 @@ def test_send_file(self):
2024
strict_host_key_checking=False)
2125

2226
def test_send_file_with_spaces(self):
27+
"""Test sending a file with spaces from local to remote."""
2328
sysrsync.run(source="end-to-end-tests/test-cases/file with spaces",
2429
destination="/tmp/target_test_file",
2530
destination_ssh="test@openssh-server",

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Setup script for sysrsync."""
12
import setuptools
23
import toml
34

sysrsync/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
"""sysrsync: A Python wrapper for rsync."""
12
from .command_maker import *
23
from .runner import run

sysrsync/command_maker.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Generates the rsync command."""
12
import os
23
import os.path
34
from typing import Iterable, List, Optional
@@ -17,6 +18,32 @@ def get_rsync_command(source: str,
1718
private_key: Optional[str] = None,
1819
rsh_port: Optional[int] = None,
1920
strict_host_key_checking: Optional[bool] = None) -> List[str]:
21+
"""Generate rsync command with the specified options for synchronizing files and directories.
22+
23+
Args:
24+
source (str): The source directory or file path.
25+
destination (str): The destination directory or file path.
26+
source_ssh (Optional[str], optional): The SSH prefix for the source. Defaults
27+
to None.
28+
destination_ssh (Optional[str], optional): The SSH prefix for the destination.
29+
Defaults to None.
30+
exclusions (Optional[Iterable[str]], optional): The exclusions to be applied
31+
during synchronization. Defaults to None.
32+
sync_source_contents (bool, optional): Whether to sync the contents of the
33+
source directory. Defaults to True.
34+
options (Optional[Iterable[str]], optional): Additional rsync options. Defaults
35+
to None.
36+
private_key (Optional[str], optional): The path to the private key file for SSH
37+
authentication. Defaults to None.
38+
rsh_port (Optional[int], optional): The port number to use for the SSH
39+
connection. Defaults to None.
40+
strict_host_key_checking (Optional[bool], optional): Whether to perform strict
41+
host key checking. Defaults to None.
42+
43+
Returns:
44+
List[str]: A list containing the rsync command and its options for
45+
synchronizing files and directories.
46+
"""
2047
if source_ssh is not None and destination_ssh is not None:
2148
raise RemotesError()
2249

sysrsync/exceptions.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
1+
"""Exceptions for sysrsync."""
12
class RemotesError(Exception):
3+
"""
4+
Exception raised when both the source and destination are remote.
5+
6+
Attributes:
7+
message: The error message indicating that the source and destination cannot
8+
both be remote.
9+
"""
10+
211
def __init__(self):
12+
"""Initialize the RemotesError exception."""
313
message = 'source and destination cannot both be remote'
414
super().__init__(message)
515

616

717
class RsyncError(Exception):
18+
"""Exception raised for errors related to rsync operations."""
19+
820
pass
921

1022

1123
class PrivateKeyError(Exception):
24+
"""
25+
Exception raised when a private key file does not exist.
26+
27+
Args:
28+
key_file: The path to the non-existent private key file.
29+
30+
Attributes:
31+
message: The error message indicating that the private key file does not exist.
32+
"""
33+
1234
def __init__(self, key_file):
35+
"""Initialize the PrivateKeyError exception."""
1336
message = f'Private Key File "{key_file}" does not exist'
1437
super().__init__(message)

sysrsync/helpers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Helpers for sysrsync."""

sysrsync/helpers/directories.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1+
"""Directory helper functions for sysrsync."""
12
from typing import Tuple, Optional
23

34

45
def get_directory_with_ssh(directory: str, ssh: Optional[str]) -> str:
6+
"""
7+
Return the directory path with SSH prefix if SSH is provided.
8+
9+
Args:
10+
directory (str): The directory path.
11+
ssh (Optional[str]): The SSH prefix. Defaults to None.
12+
13+
Returns:
14+
str: The directory path with SSH prefix if SSH is provided, otherwise the
15+
directory path itself.
16+
"""
517
if ssh is None:
618
return directory
719

@@ -10,6 +22,19 @@ def get_directory_with_ssh(directory: str, ssh: Optional[str]) -> str:
1022

1123
def sanitize_trailing_slash(source_dir, target_dir, sync_sourcedir_contents=True):
1224
# type: (str, str, bool) -> Tuple[str, str]
25+
"""
26+
Sanitizes the trailing slashes in the source and target directories.
27+
28+
Args:
29+
source_dir (str): The source directory path.
30+
target_dir (str): The target directory path.
31+
sync_sourcedir_contents (bool, optional): Whether to sync the contents of the
32+
source directory. Defaults to True.
33+
34+
Returns:
35+
Tuple[str, str]: A tuple containing the sanitized source directory path and the
36+
sanitized target directory path.
37+
"""
1338
target_dir = strip_trailing_slash(target_dir)
1439

1540
if sync_sourcedir_contents is True:
@@ -21,12 +46,30 @@ def sanitize_trailing_slash(source_dir, target_dir, sync_sourcedir_contents=True
2146

2247

2348
def strip_trailing_slash(directory: str) -> str:
49+
"""
50+
Strip the trailing slash from the directory path if it exists.
51+
52+
Args:
53+
directory (str): The directory path.
54+
55+
Returns:
56+
str: The directory path without the trailing slash, if present. Otherwise,
57+
returns the directory path as is.
58+
"""
2459
return (directory[:-1]
2560
if directory.endswith('/')
2661
else directory)
2762

28-
2963
def add_trailing_slash(directory: str) -> str:
64+
"""Add a trailing slash to the directory path if it doesn't already have one.
65+
66+
Args:
67+
directory (str): The directory path.
68+
69+
Returns:
70+
str: The directory path with a trailing slash, if it doesn't already have one.
71+
Otherwise, returns the directory path as is.
72+
"""
3073
return (directory
3174
if directory.endswith('/')
3275
else f'{directory}/')

sysrsync/helpers/iterators.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Iterator helper functions for sysrsync."""
12
import collections
23

34
if 'Iterable' in dir(collections):
@@ -11,6 +12,16 @@
1112

1213

1314
def flatten(input_iter: Iterable[Any]) -> List[Any]:
15+
"""
16+
Flattens an iterable by converting nested iterables into a single flat list.
17+
18+
Args:
19+
input_iter (Iterable[Any]): The input iterable.
20+
21+
Returns:
22+
List[Any]: A list containing all the elements from the input iterable, with
23+
nested iterables flattened.
24+
"""
1425
list_of_lists = (element if isinstance(element, Iterable)
1526
else [element]
1627
for element in input_iter)

sysrsync/helpers/rsync.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Generates rsync arguments based on the provided options for sysrsync."""
12
import os
23
from pathlib import Path
34
from typing import Iterable, List, Optional
@@ -7,13 +8,35 @@
78

89

910
def get_exclusions(exclusions: Iterable[str]) -> Iterable[str]:
11+
"""Generate a list of rsync exclusion arguments based on the provided exclusions.
12+
13+
Args:
14+
exclusions (Iterable[str]): The exclusions to be used for generating the rsync
15+
exclusion arguments.
16+
17+
Returns:
18+
Iterable[str]: A list of rsync exclusion arguments, where each exclusion is
19+
prefixed with '--exclude'.
20+
"""
1021
return flatten((('--exclude', exclusion)
1122
for exclusion in exclusions
1223
if exclusion != '--exclude'))
1324

1425

1526
def get_rsh_command(private_key: Optional[str] = None, port: Optional[int] = None, strict_host_key_checking: Optional[bool] = None):
16-
27+
"""Generate rsync remote shell (rsh) command with the specified options.
28+
29+
Args:
30+
private_key (Optional[str], optional): The path to the private key file.
31+
Defaults to None.
32+
port (Optional[int], optional): The port number to use for the SSH connection.
33+
Defaults to None.
34+
strict_host_key_checking (Optional[bool], optional): Whether to perform strict
35+
host key checking. Defaults to None.
36+
37+
Returns:
38+
List[str]: A list containing the rsync rsh command and its options.
39+
"""
1740
args: List[str] = []
1841

1942
if private_key is not None:

sysrsync/runner.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Runs the rsync command with the specified options."""
12
import os
23
import subprocess
34

@@ -6,6 +7,21 @@
67

78

89
def run(cwd=os.getcwd(), strict=True, verbose=False, **kwargs):
10+
"""Run the rsync command with the specified options.
11+
12+
Args:
13+
cwd (str, optional): The current working directory. Defaults to the current
14+
directory.
15+
strict (bool, optional): Whether to raise an exception if the rsync command
16+
returns a non-zero exit code. Defaults to True.
17+
verbose (bool, optional): Whether to print the rsync command before executing
18+
it. Defaults to False.
19+
**kwargs: Additional options to be passed to the `get_rsync_command` function.
20+
21+
Returns:
22+
subprocess.CompletedProcess: The completed process object representing the
23+
execution of the rsync command.
24+
"""
925
rsync_command = get_rsync_command(**kwargs)
1026

1127
rsync_string = ' '.join(rsync_command)
@@ -23,5 +39,15 @@ def run(cwd=os.getcwd(), strict=True, verbose=False, **kwargs):
2339

2440

2541
def _check_return_code(return_code: int, action: str):
42+
"""Check the return code of an action and raises an exception if it is non-zero.
43+
44+
Args:
45+
return_code (int): The return code of the action.
46+
action (str): The description of the action.
47+
48+
Raises:
49+
RsyncError: If the return code is non-zero, an exception is raised with an
50+
error message indicating the action and the return code.
51+
"""
2652
if return_code != 0:
2753
raise RsyncError(f"[sysrsync runner] {action} exited with code {return_code}")

0 commit comments

Comments
 (0)