From 7bea08ddac2ddd78dfd9e9305329c39b11d27897 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Fri, 22 May 2026 10:09:59 +0200 Subject: [PATCH] feat: set up modularized version of project with testing --- .coverage | Bin 0 -> 53248 bytes .gitignore | 10 +++ .python-version | 1 + AGENTS.md | 112 +++++++++++++++++++++++++ README.md | 0 project_map.json | 57 +++++++++++++ pyproject.toml | 32 +++++++ src/timesheets/__init__.py | 3 + src/timesheets/cli.py | 85 +++++++++++++++++++ src/timesheets/output.py | 54 ++++++++++++ src/timesheets/parser.py | 115 +++++++++++++++++++++++++ src/timesheets/projects.py | 29 +++++++ src/timesheets/utils.py | 44 ++++++++++ tests/__init__.py | 0 tests/test_output.py | 113 +++++++++++++++++++++++++ tests/test_parser.py | 150 +++++++++++++++++++++++++++++++++ tests/test_projects.py | 67 +++++++++++++++ tests/test_utils.py | 100 ++++++++++++++++++++++ uv.lock | 166 +++++++++++++++++++++++++++++++++++++ 19 files changed, 1138 insertions(+) create mode 100644 .coverage create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 AGENTS.md create mode 100644 README.md create mode 100644 project_map.json create mode 100644 pyproject.toml create mode 100644 src/timesheets/__init__.py create mode 100644 src/timesheets/cli.py create mode 100644 src/timesheets/output.py create mode 100644 src/timesheets/parser.py create mode 100644 src/timesheets/projects.py create mode 100644 src/timesheets/utils.py create mode 100644 tests/__init__.py create mode 100644 tests/test_output.py create mode 100644 tests/test_parser.py create mode 100644 tests/test_projects.py create mode 100644 tests/test_utils.py create mode 100644 uv.lock diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..addd3c52561f65f5f222abf75ab137ed6f313f69 GIT binary patch literal 53248 zcmeI)%WoS+90%}Suf47vCli!bCXK4h1*M^RGy)0wfHpv&6_rAvAWpdJ^(5Y4?>f8d zG(n0gm!cwi=ft^O`2&D*EEmqb5ICV83IYj)s#cWW?8A>VuHs5nl<2#P?S0J5{^m1} z^~Q?p zmW4OLjb;r^hvHoI!`iw|b=r4$#j=BH+MeZGj?KlYFzdc3ZCSwyi54$}*IpYc>!PgC z#V}`dt~Q-k<}GqY$)n5*6rAnEtgVdl)RZ}h*{)ZMM7~t7)@0*Qj_}03(=BJWyuK4v zcH3>UMO(J&+tHjcxopueSKYRj>!R8C6TFpkBB+M#OmJBV>H*L7>G@+rszSX|ta{58 zdh1j$>b?_f7pU;i?E=4!Svtf%uMBkGk* z(2b(jieAzkT_|qJEvC`Q zHPXp+{=fmX5snBsFUd!$qY`pYYY1$*5NtpEn&FrEqp{1~6!=(5&!0HZEpQn^VMadd zR|gY8$e(M0ew8MD`OrE-mU~(uzb)1#SBwhHCN;xyX~@zX99{vqOjt4~u~BsDe$apA zX3#z5wWk$tSU_t#wx?9%L2?@2?>L@k(PdR$w!GuOwpOJ(s$apBeI4Z|0{RTW$& z34#ea)+NK^rYq=RbS(`6BeC-4sKR2-(2;l!4Qn$#rai9j$R;k#$Y*(%yidNBYmBPt z{E;JSqaKamaB?bm^iH5^#C44}6CFKk)4^6Jo2OZt-XgVkE(zXdC^y41$Qdzg_F_mE zr;6SnWyj?WzRK<^^n(Qg5P$##AOHafKmY;|fB*y_0D-+Hps5KpE${ym>{o^TK~Gp9 z009U<00Izz00bZa0SG_<0ub1h0=a~Ch{b;va&%DDMuwxm0eER@=EbR_S*lfn-BH*b z_Rp@YAcBSf1Rwwb2tWV=5P$##AOHafK%gm*(+;WeuK^NSZ6p)@7C?UfuMd2ou$$~E zdy}OGZqWu72tWV=5P$##AOHafKmY;|fWT7|IH_yO<>|6h71K*g?sQ44Onatl)qHPS z{x`o@7J^ni*KFUc8LlT>`m%r%DNR}LHFw>&DjsD%l}suPt=HT&*I5!KeOF3t?WFbu zvD5cJ)apLvK9etc?8 zjDjHm0SG_<0uX=z1Rwwb2tWV=it>tfS?%>MxOxAtpVZcS&K=+Xr%opuTF<%L?*Efd z5_|LhUpua?^?dg5{y%YwBG2@y)^`7o@BhQlg8&2|009U<00Izz00bZa0SN4A0ZrAE ze);*o${r~6g9QQ*fB*y_009U<00Izz00bZafjuaoY5ket|Nq%H3cJVdvJG~NeMcKu zAOHafKmY;|fB*y_009U<00I!$QGq@^sb-!{-I)J={_Fjj6m9HJ-gr3l>i#6HKCgfI z=lsQ+_rCpU6DtxWCpUq|Npbw3cJt# zX1}vv*lqUPj#dyShX4d1009U<00Izz00bZa0SG`~+XC{}1ZqkTUXrQcMNbAVnijky z5=r_6K=Ap$GPvzxkq`n9fB*y_009U<00Izz00bZafn6vdKmW)5|1NAegbV=)KmY;| wfB*y_009U<00I!`K|uchKkol~07Fs;KmY;|fB*y_009U<00Izzz%CT{AFkABkpKVy literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..505a3b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..eb8b696 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,112 @@ +# Timesheets — Agent Guide + +## Project overview + +A Python CLI tool that parses markdown pipe-delimited timesheet tables and +exports them to CSV for import into Odoo (or similar tools). It also supports +a human-readable summary view. + +### Package layout + +``` +timesheets/ +├── pyproject.toml # package metadata, entry point, dev dependencies +├── AGENTS.md +└── src/timesheets/ + ├── cli.py # argument parsing, main() entry point + ├── parser.py # markdown table parsing and row aggregation + ├── projects.py # project_map.json loading and key resolution + ├── output.py # CSV writing and summary printing + └── utils.py # shared low-level helpers (duration parsing, formatting, etc.) +``` + +Tests live in `tests/`, one file per source module: + +``` +tests/ +├── test_utils.py +├── test_parser.py +├── test_projects.py +└── test_output.py +``` + +--- + +## Package manager — uv + +All dependency management and script execution is done via [`uv`](https://docs.astral.sh/uv/). +Do **not** use `pip` or `python` directly. + +| Task | Command | +|---|---| +| Install / sync dependencies | `uv sync` | +| Add a runtime dependency | `uv add ` | +| Add a dev-only dependency | `uv add --dev ` | +| Run the CLI | `uv run timesheets ` | +| Run any Python script | `uv run python