From 20eb3bad808968d0dab29cb2e7712dc931caee0d Mon Sep 17 00:00:00 2001 From: Tabish Mustufa Date: Sat, 5 Sep 2026 22:57:22 -0700 Subject: [PATCH 1/3] Fix stale output.py reference in test_readme docstring output.py was removed in PR #40; the columns it checks now live in parser.py. Co-Authored-By: Claude Sonnet 5 --- tests/test_readme.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_readme.py b/tests/test_readme.py index f4743d0..de6eea7 100644 --- a/tests/test_readme.py +++ b/tests/test_readme.py @@ -1,4 +1,4 @@ -"""Keeps README.md's tables in sync with output.py.""" +"""Keeps README.md's tables in sync with parser.py.""" import re from dataclasses import fields From 40518d903500f1ffa2aa846b6cb6ef881d4bc0aa Mon Sep 17 00:00:00 2001 From: Tabish Mustufa Date: Sat, 5 Sep 2026 22:57:46 -0700 Subject: [PATCH 2/3] Stop index_by_time mutating the caller's DataFrame The empty-and-column-absent branch wrote NaT into the input in place. Co-Authored-By: Claude Sonnet 5 --- src/activity_parser/postprocess.py | 1 + tests/test_postprocess.py | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/activity_parser/postprocess.py b/src/activity_parser/postprocess.py index da6bc07..fc84353 100644 --- a/src/activity_parser/postprocess.py +++ b/src/activity_parser/postprocess.py @@ -43,6 +43,7 @@ def index_by_time(records: pd.DataFrame, column: str) -> pd.DataFrame: if column not in records.columns: if not records.empty: return records.rename_axis(column) + records = records.copy() records[column] = pd.NaT records = records.set_index(column) diff --git a/tests/test_postprocess.py b/tests/test_postprocess.py index 55191df..1fc790d 100644 --- a/tests/test_postprocess.py +++ b/tests/test_postprocess.py @@ -43,6 +43,12 @@ def test_index_by_time_missing_column_yields_empty_datetime_index(): assert isinstance(out.index, pd.DatetimeIndex) +def test_index_by_time_missing_column_and_empty_does_not_mutate_input(): + df = pd.DataFrame({"value": []}) + index_by_time(df, "time") + assert "time" not in df.columns + + def test_index_by_time_missing_column_with_rows_keeps_them(): df = pd.DataFrame({"value": [1, 2, 3]}) out = index_by_time(df, "time") From b6896c970f2b18e081d52055ce61e78c9eb2f78a Mon Sep 17 00:00:00 2001 From: Tabish Mustufa Date: Sat, 5 Sep 2026 22:58:21 -0700 Subject: [PATCH 3/3] Raise Ambiguous extension for a bare file.gz infer_extension silently returned "" instead of reusing normalize_extension's guard. Co-Authored-By: Claude Sonnet 5 --- src/activity_parser/parser.py | 2 ++ tests/test_parser.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/activity_parser/parser.py b/src/activity_parser/parser.py index 8651451..1165140 100644 --- a/src/activity_parser/parser.py +++ b/src/activity_parser/parser.py @@ -104,6 +104,8 @@ def infer_extension(file: str | PathLike[str]) -> str: ext = p.suffix if ext.lower() == ".gz": ext = Path(p.stem).suffix + if not ext: + ext = ".gz" return normalize_extension(ext) diff --git a/tests/test_parser.py b/tests/test_parser.py index ae1e115..1835dad 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -34,6 +34,11 @@ def test_infer_extension(): assert infer_extension("dir/sub/ride.GPX.GZ") == "gpx" +def test_infer_extension_bare_gz_rejected(): + with pytest.raises(ValueError, match="Ambiguous"): + infer_extension("ride.gz") + + def test_select_and_reorder_cols_selects_and_orders(): df = pd.DataFrame({"b": [1], "a": [2], "ignored": [3]}) out = select_and_reorder_cols(df, ["a", "b", "missing"], include_all_columns=False)