Skip to content

Commit f3d54ed

Browse files
committed
add/update docstrings
1 parent d1676a3 commit f3d54ed

9 files changed

Lines changed: 188 additions & 15 deletions

File tree

sysrsync/command_maker.py

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

sysrsync/exceptions.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
11
class RemotesError(Exception):
2+
"""
3+
Exception raised when both the source and destination are remote.
4+
5+
Attributes:
6+
message: The error message indicating that the source and destination cannot
7+
both be remote.
8+
"""
9+
210
def __init__(self):
311
message = 'source and destination cannot both be remote'
412
super().__init__(message)
513

614

715
class RsyncError(Exception):
16+
"""
17+
Exception raised for errors related to rsync operations.
18+
"""
819
pass
920

1021

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

sysrsync/helpers/directories.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33

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

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

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

1539
if sync_sourcedir_contents is True:
@@ -24,9 +48,29 @@ def strip_trailing_slash(directory: str) -> str:
2448
return (directory[:-1]
2549
if directory.endswith('/')
2650
else directory)
51+
"""
52+
Strips the trailing slash from the directory path if it exists.
53+
54+
Args:
55+
directory (str): The directory path.
56+
57+
Returns:
58+
str: The directory path without the trailing slash, if present. Otherwise,
59+
returns the directory path as is.
60+
"""
2761

2862

2963
def add_trailing_slash(directory: str) -> str:
3064
return (directory
3165
if directory.endswith('/')
3266
else f'{directory}/')
67+
"""
68+
Adds a trailing slash to the directory path if it doesn't already have one.
69+
70+
Args:
71+
directory (str): The directory path.
72+
73+
Returns:
74+
str: The directory path with a trailing slash, if it doesn't already have one.
75+
Otherwise, returns the directory path as is.
76+
"""

sysrsync/helpers/iterators.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,15 @@ def flatten(input_iter: Iterable[Any]) -> List[Any]:
1414
list_of_lists = (element if isinstance(element, Iterable)
1515
else [element]
1616
for element in input_iter)
17+
"""
18+
Flattens an iterable by converting nested iterables into a single flat list.
19+
20+
Args:
21+
input_iter (Iterable[Any]): The input iterable.
22+
23+
Returns:
24+
List[Any]: A list containing all the elements from the input iterable, with
25+
nested iterables flattened.
26+
"""
1727

1828
return reduce(iconcat, list_of_lists, [])

sysrsync/helpers/rsync.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,38 @@
77

88

99
def get_exclusions(exclusions: Iterable[str]) -> Iterable[str]:
10+
"""
11+
Generates 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):
1627

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

1944
if private_key is not None:

sysrsync/runner.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@
66

77

88
def run(cwd=os.getcwd(), strict=True, verbose=False, **kwargs):
9+
"""
10+
Runs 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,16 @@ def run(cwd=os.getcwd(), strict=True, verbose=False, **kwargs):
2339

2440

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

test/test_directories_helper.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,41 @@
44

55

66
class TestDirectoriesHelper(unittest.TestCase):
7+
"""
8+
Unit tests for the directories helper module.
9+
"""
710
def test_strip_trailing_slash(self):
8-
"""test strip trailing slash"""
11+
"""Test the strip_trailing_slash function."""
912
test_dir = '/a/'
1013
expect = '/a'
1114
result = directories.strip_trailing_slash(test_dir)
1215

1316
self.assertEqual(expect, result)
1417

1518
def test_skip_strip_trailing_slash(self):
16-
"""test skip strip trailing slash when not necessary"""
19+
"""Test skipping strip_trailing_slash when not necessary."""
1720
test_dir = '/a'
1821
result = directories.strip_trailing_slash(test_dir)
1922

2023
self.assertEqual(result, test_dir)
2124

2225
def test_add_trailing_slash(self):
23-
"""test add trailing slash"""
26+
"""Test the add_trailing_slash function."""
2427
test_dir = '/a'
2528
expect = '/a/'
2629
result = directories.add_trailing_slash(test_dir)
2730

2831
self.assertEqual(expect, result)
2932

3033
def test_skip_add_trailing_slash(self):
31-
"""test skip add trailing slash when not necessary"""
34+
"""Test skipping add_trailing_slash when not necessary."""
3235
test_dir = '/a/'
3336
result = directories.add_trailing_slash(test_dir)
3437

3538
self.assertEqual(result, test_dir)
3639

3740
def test_sanitize_trailing_slash(self):
38-
"""test sanitize trailing slash when syncing source contents"""
41+
"""Test sanitizing trailing slash when syncing source contents."""
3942
source, target = '/a', '/b/'
4043
expect_source, expect_target = '/a/', '/b'
4144
result_source, result_target = directories.sanitize_trailing_slash(
@@ -45,7 +48,7 @@ def test_sanitize_trailing_slash(self):
4548
self.assertEqual(expect_target, result_target)
4649

4750
def test_sanitize_trailing_slash_no_action_needed(self):
48-
"""test sanitize trailing slash when syncing source contents when already sanitized"""
51+
"""Test sanitizing trailing slash when syncing source contents when already sanitized."""
4952
source, target = '/a/', '/b'
5053
expect_source, expect_target = '/a/', '/b'
5154
result_source, result_target = directories.sanitize_trailing_slash(
@@ -55,7 +58,7 @@ def test_sanitize_trailing_slash_no_action_needed(self):
5558
self.assertEqual(expect_target, result_target)
5659

5760
def test_sanitize_trailing_slash_whole_source(self):
58-
"""test sanitize trailing slash when syncing whole source"""
61+
"""Test sanitizing trailing slash when syncing whole source."""
5962
source, target = '/a/', '/b/'
6063
expect_source, expect_target = '/a', '/b'
6164
result_source, result_target = directories.sanitize_trailing_slash(
@@ -65,7 +68,7 @@ def test_sanitize_trailing_slash_whole_source(self):
6568
self.assertEqual(expect_target, result_target)
6669

6770
def test_sanitize_trailing_slash_whole_source_no_action_needed(self):
68-
"""test sanitize trailing slash when syncing whole source when already sanitized"""
71+
"""Test sanitizing trailing slash when syncing whole source when already sanitized."""
6972
source, target = '/a', '/b/'
7073
expect_source, expect_target = '/a', '/b'
7174
result_source, result_target = directories.sanitize_trailing_slash(
@@ -75,7 +78,7 @@ def test_sanitize_trailing_slash_whole_source_no_action_needed(self):
7578
self.assertEqual(expect_target, result_target)
7679

7780
def test_dir_with_ssh(self):
78-
"""should compose string with ssh for rsync connection"""
81+
"""Test composing string with ssh for rsync connection."""
7982
directory = '/a'
8083
ssh = 'host'
8184
expect = 'host:/a'
@@ -84,7 +87,7 @@ def test_dir_with_ssh(self):
8487
self.assertEqual(result, expect)
8588

8689
def test_dir_without_ssh(self):
87-
"""should return directory when ssh is None"""
90+
"""Test returning directory when ssh is None."""
8891
directory = '/a'
8992
ssh = None
9093
result = directories.get_directory_with_ssh(directory, ssh)

test/test_iterators_helper.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@
44

55

66
class TestIteratorsHelper(unittest.TestCase):
7+
"""
8+
Unit tests for the iterators helper module.
9+
"""
710
def test_list_flatten(self):
11+
"""Test the flatten function with a list input."""
812
list_input = [1, [2, 3], [4]]
913
expect = [1, 2, 3, 4]
1014
result = iterators.flatten(list_input)
1115

1216
self.assertEqual(expect, result)
1317

1418
def test_tuple_flatten(self):
19+
"""Test the flatten function with a tuple input."""
1520
tuple_input = (1, [2, 3], [4])
1621
expect = [1, 2, 3, 4]
1722
result = iterators.flatten(tuple_input)
1823

1924
self.assertEqual(expect, result)
2025

2126
def test_tuples_and_lists_list_flatten(self):
27+
"""Test the flatten function with a tuple input containing tuples and lists."""
2228
tuple_input = (1, (2, 3), [4])
2329
expect = [1, 2, 3, 4]
2430
result = iterators.flatten(tuple_input)

0 commit comments

Comments
 (0)