Skip to content

Commit e76df77

Browse files
caseneuvefiliplajszczak
authored andcommitted
#29 updates docs for cli path commands; minor formatting
1 parent 58c2ad3 commit e76df77

File tree

4 files changed

+58
-49
lines changed

4 files changed

+58
-49
lines changed

cli/path.py

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,19 @@ def setup(path: str, quiet: bool) -> Tuple[str, PAPath]:
2222

2323
@app.command()
2424
def get(
25-
path: str = typer.Argument(..., help="Path to PythonAnywhere file or directory"),
26-
only_files: bool = typer.Option(False, "-f", "--files", help="List only files"),
27-
only_dirs: bool = typer.Option(False, "-d", "--dirs", help="List only directories"),
28-
sort_by_type: bool = typer.Option(False, "-t", "--type", help="Sort by type"),
29-
sort_reverse: bool = typer.Option(False, "-r", "--reverse", help="Sort in reverse order"),
25+
path: str = typer.Argument(..., help="Path to PythonAnywhere file or directory."),
26+
only_files: bool = typer.Option(False, "-f", "--files", help="List only files."),
27+
only_dirs: bool = typer.Option(False, "-d", "--dirs", help="List only directories."),
28+
sort_by_type: bool = typer.Option(False, "-t", "--type", help="Sort by type."),
29+
sort_reverse: bool = typer.Option(False, "-r", "--reverse", help="Sort in reverse order."),
3030
raw: bool = typer.Option(
31-
False, "-a", "--raw", help="Print API response (if PATH is file that's the only option)"
31+
False, "-a", "--raw", help="Print API response (has effect only for directories)."
3232
),
33-
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging"),
33+
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging."),
3434
):
3535
"""
3636
Get contents of PATH.
37+
3738
If PATH points to a directory, show list of it's contents.
3839
If PATH points to a file, print it's contents.
3940
"""
@@ -73,7 +74,7 @@ def _format_tree(data, current):
7374

7475
for entry in reversed(data):
7576
entry = re.sub(r"/$", "\0", entry.replace(current, ""))
76-
chunks = [cc for cc in entry.split('/') if cc]
77+
chunks = [cc for cc in entry.split("/") if cc]
7778
item = chunks[-1].replace("\0", "/")
7879
level = len(chunks) - 1
7980
level_tracker = set([lvl for lvl in level_tracker if lvl <= level])
@@ -87,9 +88,10 @@ def _format_tree(data, current):
8788

8889
@app.command()
8990
def tree(
90-
path: str = typer.Argument(..., help="Path to PythonAnywhere file or directory"),
91-
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging")
91+
path: str = typer.Argument(..., help="Path to PythonAnywhere directory."),
92+
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging.")
9293
):
94+
"""Show preview of directory contents at PATH in tree-like format (2 levels deep)."""
9395
pa_path = setup(path, quiet)
9496
tree = pa_path.tree
9597

@@ -103,43 +105,49 @@ def tree(
103105

104106
@app.command()
105107
def upload(
106-
path: str = typer.Argument(
107-
...,
108-
help=(
109-
"Full path of FILE where CONTENTS should be uploaded to -- "
110-
"Warning: if FILE already exists, it's contents will be overwritten"
111-
)
112-
),
108+
path: str = typer.Argument(..., help=("Full path of FILE where CONTENTS should be uploaded to.")),
113109
file: typer.FileBinaryRead = typer.Option(
114110
...,
115111
"-c",
116112
"--contents",
117-
help="Path to exisitng file or stdin stream that should be uploaded to PATH"
113+
help="Path to exisitng file or stdin stream that should be uploaded to PATH."
118114
),
119-
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging")
115+
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging.")
120116
):
117+
"""
118+
Upload CONTENTS to file at PATH.
119+
120+
If PATH points to an existing file, it will be overwritten.
121+
"""
121122
pa_path = setup(path, quiet)
122123
success = pa_path.upload(file)
123124
sys.exit(0 if success else 1)
124125

125126

126127
@app.command()
127128
def delete(
128-
path: str = typer.Argument(..., help="Path to PythonAnywhere file or directory to be deleted"),
129-
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging")
129+
path: str = typer.Argument(..., help="Path to PythonAnywhere file or directory to be deleted."),
130+
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging.")
130131
):
132+
"""
133+
Delete file or directory at PATH.
134+
135+
If PATH points to a user owned directory all its contents will be
136+
deleted recursively.
137+
"""
131138
pa_path = setup(path, quiet)
132139
success = pa_path.delete()
133140
sys.exit(0 if success else 1)
134141

135142

136143
@app.command()
137144
def share(
138-
path: str = typer.Argument(..., help="Path to PythonAnywhere file to be shared"),
139-
check: bool = typer.Option(False, "-c", "--check", help="Check sharing status"),
140-
porcelain: bool = typer.Option(False, "-p", "--porcelain", help="Return sharing url in easy-to-parse format"),
141-
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable logging"),
145+
path: str = typer.Argument(..., help="Path to PythonAnywhere file."),
146+
check: bool = typer.Option(False, "-c", "--check", help="Check sharing status."),
147+
porcelain: bool = typer.Option(False, "-p", "--porcelain", help="Return sharing url in easy-to-parse format."),
148+
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable logging."),
142149
):
150+
"""Create a sharing link to a file at PATH or check its sharing status."""
143151
pa_path = setup(path, quiet or porcelain)
144152
link = pa_path.get_sharing_url() if check else pa_path.share()
145153

@@ -151,9 +159,10 @@ def share(
151159

152160
@app.command()
153161
def unshare(
154-
path: str = typer.Argument(..., help="Path to PythonAnywhere file to be unshared"),
155-
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging")
162+
path: str = typer.Argument(..., help="Path to PythonAnywhere file."),
163+
quiet: bool = typer.Option(False, "-q", "--quiet", help="Disable additional logging.")
156164
):
165+
"""Disable sharing link for a file at PATH."""
157166
pa_path = setup(path, quiet)
158167
success = pa_path.unshare()
159168
sys.exit(0 if success else 1)

pythonanywhere/api/files_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def sharing_post(self, path):
122122

123123
url = self.sharing_endpoint
124124

125-
result = call_api(url, "POST", json={'path': path})
125+
result = call_api(url, "POST", json={"path": path})
126126

127127
if result.ok:
128128
return result.status_code, result.json()["url"]

tests/test_cli_path.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class TestGet:
4545
def test_exits_early_when_no_contents_for_given_path(self, mock_path):
4646
mock_path.return_value.contents = None
4747

48-
result = runner.invoke(app, ["get", '~/nonexistent.file'])
48+
result = runner.invoke(app, ["get", "~/nonexistent.file"])
4949

5050
assert result.exit_code == 1
5151

@@ -67,9 +67,9 @@ def test_lists_only_directories_when_dirs_option_set(self, mock_homedir_path, ho
6767

6868
assert result.stdout.startswith(home_dir)
6969
for item, value in mock_homedir_path.return_value.contents.items():
70-
if value['type'] == 'file':
70+
if value["type"] == "file":
7171
assert item not in result.stdout
72-
elif value['type'] == 'directory':
72+
elif value["type"] == "directory":
7373
assert item in result.stdout
7474

7575
def test_lists_only_files_when_files_option_set(self, mock_homedir_path, home_dir):
@@ -79,9 +79,9 @@ def test_lists_only_files_when_files_option_set(self, mock_homedir_path, home_di
7979

8080
assert result.stdout.startswith(home_dir)
8181
for item, value in mock_homedir_path.return_value.contents.items():
82-
if value['type'] == 'file':
82+
if value["type"] == "file":
8383
assert item in result.stdout
84-
elif value['type'] == 'directory':
84+
elif value["type"] == "directory":
8585
assert item not in result.stdout
8686

8787
def test_reverses_directory_content_list_when_reverse_option_set(self, mock_homedir_path, home_dir):
@@ -132,18 +132,18 @@ class TestTree:
132132
def test_prints_formatted_tree_when_successfull_api_call(self, mock_path, home_dir):
133133
mock_path.return_value.path = home_dir
134134
mock_path.return_value.tree = [
135-
f'{home_dir}/README.txt',
136-
f'{home_dir}/dir_one/',
137-
f'{home_dir}/dir_one/bar.txt',
138-
f'{home_dir}/dir_one/nested_one/',
139-
f'{home_dir}/dir_one/nested_one/foo.txt',
140-
f'{home_dir}/dir_one/nested_two/',
141-
f'{home_dir}/empty/',
142-
f'{home_dir}/dir_two/',
143-
f'{home_dir}/dir_two/quux',
144-
f'{home_dir}/dir_two/baz/',
145-
f'{home_dir}/dir_three/',
146-
f'{home_dir}/dir_three/last.txt',
135+
f"{home_dir}/README.txt",
136+
f"{home_dir}/dir_one/",
137+
f"{home_dir}/dir_one/bar.txt",
138+
f"{home_dir}/dir_one/nested_one/",
139+
f"{home_dir}/dir_one/nested_one/foo.txt",
140+
f"{home_dir}/dir_one/nested_two/",
141+
f"{home_dir}/empty/",
142+
f"{home_dir}/dir_two/",
143+
f"{home_dir}/dir_two/quux",
144+
f"{home_dir}/dir_two/baz/",
145+
f"{home_dir}/dir_three/",
146+
f"{home_dir}/dir_three/last.txt",
147147
]
148148

149149
result = runner.invoke(app, ["tree", "~"])

tests/test_files.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ def test_repr_returns_url_property_value(self, mocker):
3232

3333
def test_make_sharing_url_contains_pa_site_address(self, mocker):
3434
mock_urljoin = mocker.patch("pythonanywhere.files.urljoin")
35-
pa_path = PAPath('path')
35+
pa_path = PAPath("path")
3636

37-
pa_path._make_sharing_url('rest')
37+
pa_path._make_sharing_url("rest")
3838

39-
assert mock_urljoin.call_args == call(pa_path.api.base_url.split("api")[0], 'rest')
39+
assert mock_urljoin.call_args == call(pa_path.api.base_url.split("api")[0], "rest")
4040

4141
def test_sanitizes_path(self):
4242
pa_path = PAPath("~")
@@ -70,7 +70,7 @@ def test_warns_when_path_unavailable(self, mocker):
7070
mock_snake = mocker.patch("pythonanywhere.files.snakesay")
7171
mock_warning = mocker.patch("pythonanywhere.files.logger.warning")
7272

73-
result = PAPath('/home/different_user').contents
73+
result = PAPath("/home/different_user").contents
7474

7575
assert mock_snake.call_args == call("error msg")
7676
assert mock_warning.call_args == call(mock_snake.return_value)

0 commit comments

Comments
 (0)