stempeluhr 1.6.0__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.
Files changed (42) hide show
  1. stempeluhr-1.6.0/LICENSE +21 -0
  2. stempeluhr-1.6.0/PKG-INFO +158 -0
  3. stempeluhr-1.6.0/README.md +129 -0
  4. stempeluhr-1.6.0/pyproject.toml +121 -0
  5. stempeluhr-1.6.0/pyproject.toml.orig +109 -0
  6. stempeluhr-1.6.0/stempeluhr/__init__.py +1 -0
  7. stempeluhr-1.6.0/stempeluhr/config_handler.py +95 -0
  8. stempeluhr-1.6.0/stempeluhr/data_exporter.py +122 -0
  9. stempeluhr-1.6.0/stempeluhr/database_controller.py +327 -0
  10. stempeluhr-1.6.0/stempeluhr/datastore.py +370 -0
  11. stempeluhr-1.6.0/stempeluhr/filepath.py +55 -0
  12. stempeluhr-1.6.0/stempeluhr/icons.py +82 -0
  13. stempeluhr-1.6.0/stempeluhr/main.py +59 -0
  14. stempeluhr-1.6.0/stempeluhr/migrations/env.py +74 -0
  15. stempeluhr-1.6.0/stempeluhr/migrations/script.py.mako +28 -0
  16. stempeluhr-1.6.0/stempeluhr/migrations/versions/348acf3ce3c3_add_reason_column.py +36 -0
  17. stempeluhr-1.6.0/stempeluhr/migrations/versions/74beea3304bb_add_overtime_adjustment_table.py +38 -0
  18. stempeluhr-1.6.0/stempeluhr/migrations/versions/813a2379f36d_add_project_column_to_time.py +28 -0
  19. stempeluhr-1.6.0/stempeluhr/migrations/versions/c5e8a1b2d3f4_add_work_schedule_table.py +42 -0
  20. stempeluhr-1.6.0/stempeluhr/models.py +162 -0
  21. stempeluhr-1.6.0/stempeluhr/ui/__init__.py +13 -0
  22. stempeluhr-1.6.0/stempeluhr/ui/clock.png +0 -0
  23. stempeluhr-1.6.0/stempeluhr/ui/config_window.py +375 -0
  24. stempeluhr-1.6.0/stempeluhr/ui/config_window.ui +834 -0
  25. stempeluhr-1.6.0/stempeluhr/ui/data_window.py +172 -0
  26. stempeluhr-1.6.0/stempeluhr/ui/data_window.ui +374 -0
  27. stempeluhr-1.6.0/stempeluhr/ui/mainwindow.py +183 -0
  28. stempeluhr-1.6.0/stempeluhr/ui/mainwindow.ui +337 -0
  29. stempeluhr-1.6.0/stempeluhr/ui/overtime_window.py +101 -0
  30. stempeluhr-1.6.0/stempeluhr/ui/overtime_window.ui +161 -0
  31. stempeluhr-1.6.0/stempeluhr/ui/stempeluhr.svg +14 -0
  32. stempeluhr-1.6.0/stempeluhr/ui/vacation_window.py +116 -0
  33. stempeluhr-1.6.0/stempeluhr/ui/vacation_window.ui +208 -0
  34. stempeluhr-1.6.0/stempeluhr/ui_config_window.py +199 -0
  35. stempeluhr-1.6.0/stempeluhr/ui_controller.py +128 -0
  36. stempeluhr-1.6.0/stempeluhr/ui_data_window.py +512 -0
  37. stempeluhr-1.6.0/stempeluhr/ui_mainwindow.py +262 -0
  38. stempeluhr-1.6.0/stempeluhr/ui_overtime_window.py +87 -0
  39. stempeluhr-1.6.0/stempeluhr/ui_schedule_window.py +218 -0
  40. stempeluhr-1.6.0/stempeluhr/ui_vacation_window.py +114 -0
  41. stempeluhr-1.6.0/stempeluhr/updater.py +18 -0
  42. stempeluhr-1.6.0/stempeluhr/utils.py +139 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andre Wohnsland
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: stempeluhr
3
+ Version: 1.6.0
4
+ Summary: Stempeluhr: track your working time with a Qt tray app
5
+ Keywords: time-tracking,work-hours,overtime,qt,tray,stempeluhr
6
+ Author: Andre Wohnsland
7
+ Author-email: Andre Wohnsland <50302161+AndreWohnsland@users.noreply.github.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Requires-Dist: alembic>=1.19.1
14
+ Requires-Dist: gitpython>=3.1.59
15
+ Requires-Dist: matplotlib>=3.11.1
16
+ Requires-Dist: pandas>=3.0.5
17
+ Requires-Dist: xlsxwriter>=3.2.9
18
+ Requires-Dist: qtawesome>=1.4.2
19
+ Requires-Dist: holidays>=0.103
20
+ Requires-Dist: pyqt6>=6.11.0
21
+ Requires-Dist: numpy>=2.5.2
22
+ Requires-Dist: seaborn>=0.13.2
23
+ Requires-Dist: sqlalchemy>=2.0.52
24
+ Requires-Dist: pyqtdarktheme-fork>=2.3.6
25
+ Requires-Dist: typer>=0.27.1
26
+ Requires-Python: >=3.13
27
+ Project-URL: Repository, https://github.com/AndreWohnsland/TimeTracker
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Stempeluhr
31
+
32
+ > *Stempeluhr* (pronounced SHTEM-pel-oor, [ˈʃtɛmpl̩ˌʔuːɐ̯]) is German for *punch clock* — the clock at the factory gate that workers used to stamp their arrival and leaving times onto a time card. This app is that clock, minus the cardboard.
33
+
34
+ A Qt-Application to start and stop time tracking, enter additional breaks, view your daily and monthly data, and generate a report out of it.
35
+
36
+ ![mainwindow](./doc/mainwindow.PNG 'mainwindow')
37
+ ![report](./doc/report.PNG 'report')
38
+
39
+ ## Installation
40
+
41
+ The easiest way is installing from PyPI, otherwise you can use the standalone version.
42
+
43
+ ### A: Install from PyPI (recommended)
44
+
45
+ The app is published on PyPI as [`stempeluhr`](https://pypi.org/project/stempeluhr/).
46
+ Install it as a tool with [uv](https://docs.astral.sh/uv/getting-started/installation/) (or use `pipx` if you prefer):
47
+
48
+ ```bash
49
+ uv tool install stempeluhr
50
+ stempeluhr
51
+ ```
52
+
53
+ This is especially recommended on macOS, where the standalone binary is not signed and gets blocked by Gatekeeper.
54
+ Update any time with:
55
+
56
+ ```bash
57
+ uv tool upgrade stempeluhr
58
+ ```
59
+
60
+ ### B: Standalone Installation
61
+
62
+ With a new release, there is also a standalone version available.
63
+ You can download the latest release from the [release page](https://github.com/AndreWohnsland/TimeTracker/releases).
64
+ Choose the right version for your operating system and download the file.
65
+ Execute the file according to your usual system start option.
66
+ The application will start and you can use it as described below.
67
+
68
+ #### Windows
69
+
70
+ Just use the installer, put it on the desktop, and start the application via the icon.
71
+
72
+ #### Linux
73
+
74
+ You probably know your ways how to get started with the binary file.
75
+ But if you are lazy like me, you can install the application with the [following script](https://github.com/AndreWohnsland/TimeTracker/blob/master/scripts/installer.sh):
76
+
77
+ ```bash
78
+ curl -s https://raw.githubusercontent.com/AndreWohnsland/TimeTracker/master/scripts/installer.sh | bash
79
+ ```
80
+
81
+ This will download the latest release, put it into your binary folder, and create an application entry.
82
+
83
+ #### macOS
84
+
85
+ This is currently still experimental, but you can try either the manual installation or the standalone version.
86
+
87
+ ### B: Manual Installation
88
+
89
+ We use [uv](https://docs.astral.sh/uv/getting-started/installation/) for managing Python versions and packages.
90
+ First clone the repository and cd into it.
91
+ To start the app, you run the `runme.py` file, you can create a shortcut on your desktop:
92
+
93
+ ```bash
94
+ git clone https://github.com/AndreWohnsland/TimeTracker.git
95
+ cd TimeTracker
96
+ uv sync
97
+ uv run runme.py
98
+ ```
99
+
100
+ If you want to contribute, also install the [pre-commit](https://pre-commit.com/) hooks, they run linting and formatting before each commit:
101
+
102
+ ```bash
103
+ uv run pre-commit install
104
+ ```
105
+
106
+ ### Manual build of the standalone version
107
+
108
+ If you want to build the standalone version by yourself, you can also do it with [uv](https://docs.astral.sh/uv/getting-started/installation/).
109
+ Especially on windows and macOS, because on these systems, they will probably complain that the downloaded binary is not trusted.
110
+ First, make sure you have uv installed and clone the repository.
111
+ Then run the following commands to create the standalone version:
112
+
113
+ ```bash
114
+ uv run pyinstaller installer.spec
115
+ ```
116
+
117
+ The created binary will be in the `dist` folder.
118
+
119
+ ## Options
120
+
121
+ On first startup, the application will create the needed configuration and the database.
122
+ You can adjust your settings via `Options > Configure Settings` and the folder to save the reports to with `Options > Set Save folder`.
123
+ With `Start` the tracking is started and with `Stop` the tracking is stopped.
124
+ You can repeat this start-stop procedure any time you want.
125
+ Over the spin box you can select the pause time and submit them with the `Pause` button.
126
+ It is also possible to enter negative Pause to correct previous mistakes.
127
+ You can also start and stop over the tray icon in the taskbar.
128
+
129
+ ![settings](./doc/options.PNG 'settings')
130
+
131
+ ## Reports
132
+
133
+ An overview can be seen when clicking `Options > Summary`.
134
+ With a datepicker, a day can be chosen to display a summary of the data in either the according month or all events of this day.
135
+ The day / month view can be changed over the view toggle button.
136
+ To generate the report of your overtime or work time, click the `Export` button.
137
+ By default settings, the report will be saved into the reports folder of this application.
138
+ As soon as the save folder was changed over the option setting, the app will use this location instead.
139
+ The default work time for overtime is eight hours, time worked less than eight will displayed as zero overtime.
140
+ The overtime/work time is rounded to the closest quarter hour.
141
+ Breaks are already subtracted in the calculation, adherence to the regular break times is not observed.
142
+
143
+ ## Adjust Past Values
144
+
145
+ To enter values you have missed, you can switch to past entry mode.
146
+ This can be done over the `Options > Switch to Past Entry` setting.
147
+ A date and time can be selected with the according action to insert past values.
148
+ To go back to the default option, click the shown back button.
149
+
150
+ ## Updating to latest Version
151
+
152
+ Just download the latest executable from the [release page](https://github.com/AndreWohnsland/TimeTracker/releases).
153
+ If you have installed the application manually, you can update it with git:
154
+
155
+ ```bash
156
+ git pull
157
+ uv sync
158
+ ```
@@ -0,0 +1,129 @@
1
+ # Stempeluhr
2
+
3
+ > *Stempeluhr* (pronounced SHTEM-pel-oor, [ˈʃtɛmpl̩ˌʔuːɐ̯]) is German for *punch clock* — the clock at the factory gate that workers used to stamp their arrival and leaving times onto a time card. This app is that clock, minus the cardboard.
4
+
5
+ A Qt-Application to start and stop time tracking, enter additional breaks, view your daily and monthly data, and generate a report out of it.
6
+
7
+ ![mainwindow](./doc/mainwindow.PNG 'mainwindow')
8
+ ![report](./doc/report.PNG 'report')
9
+
10
+ ## Installation
11
+
12
+ The easiest way is installing from PyPI, otherwise you can use the standalone version.
13
+
14
+ ### A: Install from PyPI (recommended)
15
+
16
+ The app is published on PyPI as [`stempeluhr`](https://pypi.org/project/stempeluhr/).
17
+ Install it as a tool with [uv](https://docs.astral.sh/uv/getting-started/installation/) (or use `pipx` if you prefer):
18
+
19
+ ```bash
20
+ uv tool install stempeluhr
21
+ stempeluhr
22
+ ```
23
+
24
+ This is especially recommended on macOS, where the standalone binary is not signed and gets blocked by Gatekeeper.
25
+ Update any time with:
26
+
27
+ ```bash
28
+ uv tool upgrade stempeluhr
29
+ ```
30
+
31
+ ### B: Standalone Installation
32
+
33
+ With a new release, there is also a standalone version available.
34
+ You can download the latest release from the [release page](https://github.com/AndreWohnsland/TimeTracker/releases).
35
+ Choose the right version for your operating system and download the file.
36
+ Execute the file according to your usual system start option.
37
+ The application will start and you can use it as described below.
38
+
39
+ #### Windows
40
+
41
+ Just use the installer, put it on the desktop, and start the application via the icon.
42
+
43
+ #### Linux
44
+
45
+ You probably know your ways how to get started with the binary file.
46
+ But if you are lazy like me, you can install the application with the [following script](https://github.com/AndreWohnsland/TimeTracker/blob/master/scripts/installer.sh):
47
+
48
+ ```bash
49
+ curl -s https://raw.githubusercontent.com/AndreWohnsland/TimeTracker/master/scripts/installer.sh | bash
50
+ ```
51
+
52
+ This will download the latest release, put it into your binary folder, and create an application entry.
53
+
54
+ #### macOS
55
+
56
+ This is currently still experimental, but you can try either the manual installation or the standalone version.
57
+
58
+ ### B: Manual Installation
59
+
60
+ We use [uv](https://docs.astral.sh/uv/getting-started/installation/) for managing Python versions and packages.
61
+ First clone the repository and cd into it.
62
+ To start the app, you run the `runme.py` file, you can create a shortcut on your desktop:
63
+
64
+ ```bash
65
+ git clone https://github.com/AndreWohnsland/TimeTracker.git
66
+ cd TimeTracker
67
+ uv sync
68
+ uv run runme.py
69
+ ```
70
+
71
+ If you want to contribute, also install the [pre-commit](https://pre-commit.com/) hooks, they run linting and formatting before each commit:
72
+
73
+ ```bash
74
+ uv run pre-commit install
75
+ ```
76
+
77
+ ### Manual build of the standalone version
78
+
79
+ If you want to build the standalone version by yourself, you can also do it with [uv](https://docs.astral.sh/uv/getting-started/installation/).
80
+ Especially on windows and macOS, because on these systems, they will probably complain that the downloaded binary is not trusted.
81
+ First, make sure you have uv installed and clone the repository.
82
+ Then run the following commands to create the standalone version:
83
+
84
+ ```bash
85
+ uv run pyinstaller installer.spec
86
+ ```
87
+
88
+ The created binary will be in the `dist` folder.
89
+
90
+ ## Options
91
+
92
+ On first startup, the application will create the needed configuration and the database.
93
+ You can adjust your settings via `Options > Configure Settings` and the folder to save the reports to with `Options > Set Save folder`.
94
+ With `Start` the tracking is started and with `Stop` the tracking is stopped.
95
+ You can repeat this start-stop procedure any time you want.
96
+ Over the spin box you can select the pause time and submit them with the `Pause` button.
97
+ It is also possible to enter negative Pause to correct previous mistakes.
98
+ You can also start and stop over the tray icon in the taskbar.
99
+
100
+ ![settings](./doc/options.PNG 'settings')
101
+
102
+ ## Reports
103
+
104
+ An overview can be seen when clicking `Options > Summary`.
105
+ With a datepicker, a day can be chosen to display a summary of the data in either the according month or all events of this day.
106
+ The day / month view can be changed over the view toggle button.
107
+ To generate the report of your overtime or work time, click the `Export` button.
108
+ By default settings, the report will be saved into the reports folder of this application.
109
+ As soon as the save folder was changed over the option setting, the app will use this location instead.
110
+ The default work time for overtime is eight hours, time worked less than eight will displayed as zero overtime.
111
+ The overtime/work time is rounded to the closest quarter hour.
112
+ Breaks are already subtracted in the calculation, adherence to the regular break times is not observed.
113
+
114
+ ## Adjust Past Values
115
+
116
+ To enter values you have missed, you can switch to past entry mode.
117
+ This can be done over the `Options > Switch to Past Entry` setting.
118
+ A date and time can be selected with the according action to insert past values.
119
+ To go back to the default option, click the shown back button.
120
+
121
+ ## Updating to latest Version
122
+
123
+ Just download the latest executable from the [release page](https://github.com/AndreWohnsland/TimeTracker/releases).
124
+ If you have installed the application manually, you can update it with git:
125
+
126
+ ```bash
127
+ git pull
128
+ uv sync
129
+ ```
@@ -0,0 +1,121 @@
1
+ [project]
2
+ name = "stempeluhr"
3
+ version = "1.6.0"
4
+ description = "Stempeluhr: track your working time with a Qt tray app"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.13"
9
+ keywords = [
10
+ "time-tracking",
11
+ "work-hours",
12
+ "overtime",
13
+ "qt",
14
+ "tray",
15
+ "stempeluhr",
16
+ ]
17
+ classifiers = [
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Programming Language :: Python :: 3.14",
21
+ ]
22
+ dependencies = [
23
+ "alembic>=1.19.1",
24
+ "gitpython>=3.1.59",
25
+ "matplotlib>=3.11.1",
26
+ "pandas>=3.0.5",
27
+ "xlsxwriter>=3.2.9",
28
+ "qtawesome>=1.4.2",
29
+ "holidays>=0.103",
30
+ "pyqt6>=6.11.0",
31
+ "numpy>=2.5.2",
32
+ "seaborn>=0.13.2",
33
+ "sqlalchemy>=2.0.52",
34
+ "pyqtdarktheme-fork>=2.3.6",
35
+ "typer>=0.27.1",
36
+ ]
37
+
38
+ [[project.authors]]
39
+ name = "Andre Wohnsland"
40
+ email = "50302161+AndreWohnsland@users.noreply.github.com"
41
+
42
+ [project.urls]
43
+ Repository = "https://github.com/AndreWohnsland/TimeTracker"
44
+
45
+ [project.scripts]
46
+ stempeluhr = "stempeluhr.main:app"
47
+
48
+ [build-system]
49
+ requires = ["uv_build>=0.9.5,<0.13.0"]
50
+ build-backend = "uv_build"
51
+
52
+ [tool.uv.build-backend]
53
+ module-name = ["stempeluhr"]
54
+ module-root = ""
55
+
56
+ [tool.ty.src]
57
+ exclude = ["stempeluhr/ui"]
58
+
59
+ [tool.ruff]
60
+ target-version = "py313"
61
+ line-length = 120
62
+ exclude = [
63
+ "stempeluhr/ui",
64
+ "*.ipynb",
65
+ ]
66
+
67
+ [tool.ruff.lint]
68
+ extend-safe-fixes = [
69
+ "UP",
70
+ "D107",
71
+ "D205",
72
+ "W291",
73
+ ]
74
+ select = [
75
+ "A",
76
+ "ANN",
77
+ "C",
78
+ "C4",
79
+ "D",
80
+ "E",
81
+ "F",
82
+ "I",
83
+ "ICN001",
84
+ "PIE",
85
+ "PL",
86
+ "PTH",
87
+ "PYI",
88
+ "Q",
89
+ "R",
90
+ "RET",
91
+ "RUF",
92
+ "SIM",
93
+ "UP",
94
+ "W",
95
+ ]
96
+ ignore = [
97
+ "D100",
98
+ "D101",
99
+ "D102",
100
+ "D103",
101
+ "D104",
102
+ "D105",
103
+ "D203",
104
+ "D213",
105
+ "ANN401",
106
+ ]
107
+
108
+ [tool.ruff.lint.per-file-ignores]
109
+ "stempeluhr/main.py" = ["PLC0415"]
110
+ "tests/*" = ["PLR2004"]
111
+
112
+ [dependency-groups]
113
+ dev = [
114
+ "pyinstaller>=6.22.2",
115
+ "jupyterlab>=4.6.3",
116
+ "ty==0.0.73",
117
+ "ruff>=0.16.4",
118
+ "pytest>=9.1.1",
119
+ "pytest-cov>=7.1.0",
120
+ "pre-commit>=4.6.2",
121
+ ]
@@ -0,0 +1,109 @@
1
+ [project]
2
+ name = "stempeluhr"
3
+ version = "1.6.0"
4
+ description = "Stempeluhr: track your working time with a Qt tray app"
5
+ authors = [{ name = "Andre Wohnsland", email = "50302161+AndreWohnsland@users.noreply.github.com" }]
6
+ readme = "README.md"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ requires-python = ">=3.13"
10
+ keywords = ["time-tracking", "work-hours", "overtime", "qt", "tray", "stempeluhr"]
11
+ classifiers = [
12
+ "Programming Language :: Python :: 3",
13
+ "Programming Language :: Python :: 3.13",
14
+ "Programming Language :: Python :: 3.14",
15
+ ]
16
+
17
+ dependencies = [
18
+ "alembic>=1.19.1",
19
+ "gitpython>=3.1.59",
20
+ "matplotlib>=3.11.1",
21
+ "pandas>=3.0.5",
22
+ "xlsxwriter>=3.2.9",
23
+ "qtawesome>=1.4.2",
24
+ "holidays>=0.103",
25
+ "pyqt6>=6.11.0",
26
+ "numpy>=2.5.2",
27
+ "seaborn>=0.13.2",
28
+ "sqlalchemy>=2.0.52",
29
+ "pyqtdarktheme-fork>=2.3.6",
30
+ "typer>=0.27.1",
31
+ ]
32
+
33
+ [project.urls]
34
+ Repository = "https://github.com/AndreWohnsland/TimeTracker"
35
+
36
+ [project.scripts]
37
+ stempeluhr = "stempeluhr.main:app"
38
+
39
+ [build-system]
40
+ requires = ["uv_build>=0.9.5,<0.13.0"]
41
+ build-backend = "uv_build"
42
+
43
+ [tool.uv.build-backend]
44
+ module-name = ["stempeluhr"]
45
+ module-root = ""
46
+
47
+ [dependency-groups]
48
+ dev = [
49
+ "pyinstaller>=6.22.2",
50
+ "jupyterlab>=4.6.3",
51
+ "ty==0.0.73",
52
+ "ruff>=0.16.4",
53
+ "pytest>=9.1.1",
54
+ "pytest-cov>=7.1.0",
55
+ "pre-commit>=4.6.2",
56
+ ]
57
+
58
+ [tool.ty.src]
59
+ # stempeluhr/ui/ holds pyuic6-generated code, same exclusion as ruff
60
+ exclude = ["stempeluhr/ui"]
61
+
62
+ [tool.ruff]
63
+ target-version = "py313"
64
+ line-length = 120
65
+ # stempeluhr/ui/ holds pyuic6-generated code
66
+ exclude = ["stempeluhr/ui", "*.ipynb"]
67
+
68
+ [tool.ruff.lint]
69
+ extend-safe-fixes = [
70
+ "UP", # pyupgrade
71
+ "D107", # Missing docstring in __init__
72
+ "D205", # 1 blank line required between summary line and description
73
+ "W291", # Trailing whitespace
74
+ ]
75
+ # main.py imports lazily: data prep must run before the GUI modules' import-time singletons
76
+ per-file-ignores = { "stempeluhr/main.py" = ["PLC0415"], "tests/*" = ["PLR2004"] }
77
+ select = [
78
+ "A", # flake8-builtins
79
+ "ANN", # Type annotations
80
+ "C", # Convention
81
+ "C4", # flake-comprehensions
82
+ "D", # pydocstyle
83
+ "E", # pycodestyle
84
+ "F", # Pyflakes
85
+ "I", # isort
86
+ "ICN001", # {name} should be imported as {asname},
87
+ "PIE", # flake8-pie
88
+ "PL", # pylint
89
+ "PTH", # flake8-use-pathlib
90
+ "PYI", # flake8-pyi
91
+ "Q", # flake8-quotes
92
+ "R", # Refactor
93
+ "RET", # flake8-return
94
+ "RUF", # Ruff
95
+ "SIM", # flake8-simplify
96
+ "UP", # pyupgrade
97
+ "W", # Pylint (Warning)
98
+ ]
99
+ ignore = [
100
+ "D100", # Missing docstring in public module
101
+ "D101", # Missing docstring in public class
102
+ "D102", # Missing docstring in public method
103
+ "D103", # Missing docstring in public function
104
+ "D104", # Missing docstring in public package
105
+ "D105", # Missing docstring in magic method
106
+ "D203", # 1 blank line required before class docstring
107
+ "D213", # Multi-line docstring summary should start at the second line
108
+ "ANN401", # Dynamically typed expressions (typing.Any) are disallowed
109
+ ]
@@ -0,0 +1 @@
1
+ __version__ = "1.5.1"
@@ -0,0 +1,95 @@
1
+ import datetime
2
+ import json
3
+ from dataclasses import asdict, dataclass
4
+ from inspect import signature
5
+ from typing import Any, Literal
6
+
7
+ import holidays
8
+
9
+ from stempeluhr.filepath import CONFIG_PATH
10
+
11
+ # Fill data currently not in the config file,
12
+ # need at least all that config has
13
+ NEEDED_DATA = {
14
+ "name": "",
15
+ "project_names": ["Default"],
16
+ "save_path": "",
17
+ "country": "US",
18
+ "subdiv": None,
19
+ }
20
+ CONFIG_NAMES = Literal[
21
+ "name",
22
+ "project_names",
23
+ "save_path",
24
+ "country",
25
+ "subdiv",
26
+ ]
27
+
28
+
29
+ @dataclass
30
+ class Config:
31
+ name: str
32
+ project_names: list[str]
33
+ save_path: str
34
+ country: str
35
+ subdiv: str | None
36
+
37
+ @classmethod
38
+ def from_kwargs(cls, **kwargs: Any) -> "Config":
39
+ cls_fields = set(signature(cls).parameters)
40
+
41
+ class_args, other_args = {}, {}
42
+ for name, val in kwargs.items():
43
+ if name in cls_fields:
44
+ class_args[name] = val
45
+ continue
46
+ other_args[name] = val
47
+
48
+ c = cls(**class_args)
49
+ for new_name, new_val in other_args.items():
50
+ setattr(c, new_name, new_val)
51
+ return c
52
+
53
+ def __getitem__(self, item: CONFIG_NAMES) -> Any:
54
+ return getattr(self, item)
55
+
56
+ def get_holidays(self, year: int) -> list[datetime.date]:
57
+ available_holidays = holidays.country_holidays(self.country, subdiv=self.subdiv or None, years=year)
58
+ return list(available_holidays.keys())
59
+
60
+
61
+ class ConfigHandler:
62
+ def __init__(self) -> None:
63
+ """Class for managing configuration file and settings ."""
64
+ self.config = self._get_config()
65
+
66
+ def _get_config(self) -> Config:
67
+ config_file = self.read_config_file()
68
+ return Config.from_kwargs(**config_file)
69
+
70
+ def read_config_file(self) -> dict:
71
+ if not CONFIG_PATH.exists():
72
+ return NEEDED_DATA
73
+ with CONFIG_PATH.open(encoding="utf-8") as f:
74
+ config = json.load(f)
75
+ for d in NEEDED_DATA.items():
76
+ if d[0] not in config:
77
+ config[d[0]] = d[1]
78
+ return config
79
+
80
+ def write_config_file(self) -> None:
81
+ with CONFIG_PATH.open("w", encoding="utf-8") as write_file:
82
+ json.dump(asdict(self.config), write_file)
83
+
84
+ def set_config_value(self, key: CONFIG_NAMES, value: Any, write: bool = True) -> None:
85
+ setattr(self.config, key, value)
86
+ if not write:
87
+ return
88
+ self.write_config_file()
89
+
90
+ def config_hash(self) -> int:
91
+ """Get a hash of the current config."""
92
+ return hash(json.dumps(asdict(self.config)))
93
+
94
+
95
+ CONFIG_HANDLER = ConfigHandler()