opensees-cli 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/PKG-INFO +1 -1
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/pyproject.toml +1 -1
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/__init__.py +1 -1
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/files.py +31 -5
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/run.py +15 -8
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli.egg-info/PKG-INFO +1 -1
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/tests/test_files_commands.py +14 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/README.md +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/setup.cfg +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/__main__.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/admin.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/api.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/auth.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/config.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/main.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/path_setup.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli/version.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli.egg-info/SOURCES.txt +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli.egg-info/dependency_links.txt +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli.egg-info/entry_points.txt +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli.egg-info/requires.txt +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/src/opensees_cli.egg-info/top_level.txt +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/tests/test_admin_commands.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/tests/test_api.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/tests/test_auth_commands.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/tests/test_config.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/tests/test_main_commands.py +0 -0
- {opensees_cli-0.2.0 → opensees_cli-0.2.1}/tests/test_run_commands.py +0 -0
|
@@ -28,14 +28,35 @@ def _files_callback(ctx: typer.Context) -> None:
|
|
|
28
28
|
raise typer.Exit(0)
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def _files_list_items() -> list[dict]:
|
|
32
|
-
"""
|
|
33
|
-
|
|
31
|
+
def _files_list_items(folder: Optional[str] = None) -> list[dict]:
|
|
32
|
+
"""List files in the user file system, optionally under ``folder``."""
|
|
33
|
+
params = {}
|
|
34
|
+
if folder:
|
|
35
|
+
params["folder"] = folder.strip().strip("/")
|
|
36
|
+
r = api.get("/files/list", params=params or None)
|
|
34
37
|
return list(r.get("files", []))
|
|
35
38
|
|
|
36
39
|
|
|
40
|
+
def _filter_under_folder(items: list[dict], folder: str) -> list[dict]:
|
|
41
|
+
"""Keep files at or under ``folder`` (client-side fallback)."""
|
|
42
|
+
root = folder.strip().strip("/")
|
|
43
|
+
if not root:
|
|
44
|
+
return items
|
|
45
|
+
prefix = root + "/"
|
|
46
|
+
out = []
|
|
47
|
+
for f in items:
|
|
48
|
+
path = str(f.get("path", ""))
|
|
49
|
+
if path == root or path.startswith(prefix):
|
|
50
|
+
out.append(f)
|
|
51
|
+
return out
|
|
52
|
+
|
|
53
|
+
|
|
37
54
|
@app.command("list")
|
|
38
55
|
def list_files(
|
|
56
|
+
folder: Optional[str] = typer.Argument(
|
|
57
|
+
None,
|
|
58
|
+
help="Only list files in this folder (and its subfolders), e.g. truss or examples/dambreak",
|
|
59
|
+
),
|
|
39
60
|
as_json: bool = typer.Option(
|
|
40
61
|
False,
|
|
41
62
|
"--json",
|
|
@@ -44,9 +65,12 @@ def list_files(
|
|
|
44
65
|
is_flag=True,
|
|
45
66
|
),
|
|
46
67
|
):
|
|
47
|
-
"""List files.
|
|
68
|
+
"""List files. With FOLDER, only show files under that path. Prints nothing when empty (non-JSON)."""
|
|
48
69
|
try:
|
|
49
|
-
items = _files_list_items()
|
|
70
|
+
items = _files_list_items(folder)
|
|
71
|
+
# Older APIs ignore ?folder= — filter locally so the CLI still works.
|
|
72
|
+
if folder:
|
|
73
|
+
items = _filter_under_folder(items, folder)
|
|
50
74
|
except api.ApiError as e:
|
|
51
75
|
console.print(f"[red]{e.message}[/red]")
|
|
52
76
|
raise typer.Exit(1)
|
|
@@ -66,6 +90,8 @@ def list_files(
|
|
|
66
90
|
"file_count": len(rows),
|
|
67
91
|
"total_size": total,
|
|
68
92
|
}
|
|
93
|
+
if folder:
|
|
94
|
+
obj["folder"] = folder.strip().strip("/")
|
|
69
95
|
typer.echo(json.dumps(obj, indent=2).rstrip("\n"))
|
|
70
96
|
return
|
|
71
97
|
|
|
@@ -1093,32 +1093,39 @@ def _week_range(week: int) -> tuple[datetime, datetime]:
|
|
|
1093
1093
|
return start.astimezone(timezone.utc), end.astimezone(timezone.utc)
|
|
1094
1094
|
|
|
1095
1095
|
|
|
1096
|
-
def _fmt_date_span(after_dt: datetime, before_dt: datetime
|
|
1096
|
+
def _fmt_date_span(after_dt: datetime, before_dt: Optional[datetime]) -> str:
|
|
1097
1097
|
"""Return a compact human-readable date span string in local time.
|
|
1098
1098
|
|
|
1099
1099
|
``before_dt`` is exclusive (the day after the last day), so we display
|
|
1100
1100
|
``before_dt - 1 day`` as the end date. If ``before_dt`` is ``None`` the
|
|
1101
1101
|
end is displayed as "today".
|
|
1102
1102
|
Example: "Jan 5 – Mar 8, 2026" or "May 4–10, 2026" (same year/month).
|
|
1103
|
+
|
|
1104
|
+
Avoids ``%-d`` / ``%#d`` strftime flags (Unix vs Windows) by formatting
|
|
1105
|
+
the day with ``dt.day`` instead.
|
|
1103
1106
|
"""
|
|
1107
|
+
def _md(dt: datetime, *, year: bool = False) -> str:
|
|
1108
|
+
s = f"{dt.strftime('%b')} {dt.day}"
|
|
1109
|
+
return f"{s}, {dt.year}" if year else s
|
|
1110
|
+
|
|
1104
1111
|
local = datetime.now().astimezone().tzinfo
|
|
1105
1112
|
start = after_dt.astimezone(local)
|
|
1106
1113
|
|
|
1107
1114
|
if before_dt is None:
|
|
1108
1115
|
end = datetime.now().astimezone(local)
|
|
1109
|
-
end_str =
|
|
1116
|
+
end_str = _md(end, year=True)
|
|
1110
1117
|
if start.year == end.year:
|
|
1111
1118
|
if start.month == end.month:
|
|
1112
|
-
return f"{start
|
|
1113
|
-
return f"{start
|
|
1114
|
-
return f"{start
|
|
1119
|
+
return f"{_md(start)}–{end.day}, {end.year}"
|
|
1120
|
+
return f"{_md(start)} – {end_str}"
|
|
1121
|
+
return f"{_md(start, year=True)} – {end_str}"
|
|
1115
1122
|
|
|
1116
1123
|
end = (before_dt - timedelta(seconds=1)).astimezone(local)
|
|
1117
1124
|
if start.year == end.year:
|
|
1118
1125
|
if start.month == end.month:
|
|
1119
|
-
return f"{start
|
|
1120
|
-
return f"{start
|
|
1121
|
-
return f"{start
|
|
1126
|
+
return f"{_md(start)}–{end.day}, {end.year}"
|
|
1127
|
+
return f"{_md(start)} – {_md(end, year=True)}"
|
|
1128
|
+
return f"{_md(start, year=True)} – {_md(end, year=True)}"
|
|
1122
1129
|
|
|
1123
1130
|
|
|
1124
1131
|
def _week_span_range(w1: int, w2: int) -> tuple[datetime, datetime]:
|
|
@@ -27,6 +27,20 @@ class TestFilesList:
|
|
|
27
27
|
assert "model.py" in result.output
|
|
28
28
|
assert "data.csv" in result.output
|
|
29
29
|
|
|
30
|
+
def test_list_folder_filters(self, cli_runner, logged_in_creds, patch_httpx, mock_router):
|
|
31
|
+
mock_router.add("GET", "/prod/files/list", json={
|
|
32
|
+
"files": [
|
|
33
|
+
{"path": "truss/Truss.py", "size": 100, "last_modified": "2025-01-01T00:00:00Z"},
|
|
34
|
+
{"path": "truss/data.csv", "size": 200, "last_modified": "2025-01-01T00:00:00Z"},
|
|
35
|
+
{"path": "other/model.py", "size": 300, "last_modified": "2025-01-01T00:00:00Z"},
|
|
36
|
+
]
|
|
37
|
+
})
|
|
38
|
+
result = cli_runner.invoke(app, ["files", "list", "truss"])
|
|
39
|
+
assert result.exit_code == 0
|
|
40
|
+
assert "truss/Truss.py" in result.output
|
|
41
|
+
assert "truss/data.csv" in result.output
|
|
42
|
+
assert "other/model.py" not in result.output
|
|
43
|
+
|
|
30
44
|
|
|
31
45
|
class TestFilesUpload:
|
|
32
46
|
def test_upload_single_file(self, cli_runner, logged_in_creds, patch_httpx, mock_router, tmp_file):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|