Add --weekly flag to csv command
- Add `write_csv_weekly()` to output.py: writes entries from multiple days as a single CSV with one header row, correct date per row - Add `-w`/`--weekly` flag to csv subparser - _cmd_csv branches on args.weekly: fetches week sections, formats per-day date strings, calls write_csv_weekly; --raw is honoured - Add TestWriteCsvWeekly with 6 tests - Update README with weekly csv usage examples
This commit is contained in:
parent
985ee28113
commit
cd8ca789aa
4 changed files with 134 additions and 10 deletions
|
|
@ -21,6 +21,7 @@ from .output import (
|
|||
print_summary_weekly_totals,
|
||||
to_csv_entries,
|
||||
write_csv,
|
||||
write_csv_weekly,
|
||||
)
|
||||
from .parser import (
|
||||
aggregate_rows,
|
||||
|
|
@ -140,6 +141,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|||
"combining entries that share the same project and story."
|
||||
),
|
||||
)
|
||||
csv_parser.add_argument(
|
||||
"--weekly",
|
||||
"-w",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Export the full week containing the given day instead of a single day.",
|
||||
)
|
||||
|
||||
status_parser = subparsers.add_parser(
|
||||
"status",
|
||||
|
|
@ -396,18 +404,37 @@ def _cmd_stories(args: argparse.Namespace, config: dict) -> None:
|
|||
|
||||
def _cmd_csv(args: argparse.Namespace, config: dict) -> None:
|
||||
target_date, date_str = _resolve_date(args)
|
||||
rows = _resolve_rows(args, config, target_date)
|
||||
if not rows:
|
||||
print("Warning: no timesheet rows found in input.", file=sys.stderr)
|
||||
entries = to_csv_entries(rows) if args.raw else aggregate_rows(rows)
|
||||
project_map = _resolve_project_map(args, config)
|
||||
|
||||
if args.output:
|
||||
with open(args.output, "w", newline="", encoding="utf-8") as f:
|
||||
write_csv(entries, f, date_str, project_map)
|
||||
print(f"Written to {args.output}", file=sys.stderr)
|
||||
if args.weekly:
|
||||
day_sections_raw = _resolve_week_sections(args, config, target_date)
|
||||
if not day_sections_raw:
|
||||
print("Warning: no timesheet rows found for this week.", file=sys.stderr)
|
||||
return
|
||||
day_sections = [
|
||||
(
|
||||
format_date(day),
|
||||
to_csv_entries(rows) if args.raw else aggregate_rows(rows),
|
||||
)
|
||||
for day, rows in day_sections_raw
|
||||
]
|
||||
if args.output:
|
||||
with open(args.output, "w", newline="", encoding="utf-8") as f:
|
||||
write_csv_weekly(day_sections, f, project_map)
|
||||
print(f"Written to {args.output}", file=sys.stderr)
|
||||
else:
|
||||
write_csv_weekly(day_sections, sys.stdout, project_map)
|
||||
else:
|
||||
write_csv(entries, sys.stdout, date_str, project_map)
|
||||
rows = _resolve_rows(args, config, target_date)
|
||||
if not rows:
|
||||
print("Warning: no timesheet rows found in input.", file=sys.stderr)
|
||||
entries = to_csv_entries(rows) if args.raw else aggregate_rows(rows)
|
||||
if args.output:
|
||||
with open(args.output, "w", newline="", encoding="utf-8") as f:
|
||||
write_csv(entries, f, date_str, project_map)
|
||||
print(f"Written to {args.output}", file=sys.stderr)
|
||||
else:
|
||||
write_csv(entries, sys.stdout, date_str, project_map)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -31,6 +31,32 @@ def to_csv_entries(rows: list[dict]) -> list[dict]:
|
|||
]
|
||||
|
||||
|
||||
def write_csv_weekly(
|
||||
day_sections: list[tuple[str, list[dict]]],
|
||||
output: IO[str],
|
||||
project_map: dict,
|
||||
) -> None:
|
||||
"""Write entries from multiple days as a single CSV with one header row.
|
||||
|
||||
day_sections is a list of (date_str, entries) pairs where entries are
|
||||
already write_csv-compatible (project, description, quantity).
|
||||
"""
|
||||
writer = csv.writer(output)
|
||||
writer.writerow(["Date*", "Project*", "Task", "Description", "Quantity"])
|
||||
for date_str, entries in day_sections:
|
||||
for entry in entries:
|
||||
project, task = resolve_project_task(entry["project"], project_map)
|
||||
writer.writerow(
|
||||
[
|
||||
date_str,
|
||||
project,
|
||||
task,
|
||||
entry["description"],
|
||||
f"{entry['quantity']:.2f}",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def write_csv(
|
||||
aggregated: list[dict],
|
||||
output: IO[str],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue