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.
- stempeluhr-1.6.0/LICENSE +21 -0
- stempeluhr-1.6.0/PKG-INFO +158 -0
- stempeluhr-1.6.0/README.md +129 -0
- stempeluhr-1.6.0/pyproject.toml +121 -0
- stempeluhr-1.6.0/pyproject.toml.orig +109 -0
- stempeluhr-1.6.0/stempeluhr/__init__.py +1 -0
- stempeluhr-1.6.0/stempeluhr/config_handler.py +95 -0
- stempeluhr-1.6.0/stempeluhr/data_exporter.py +122 -0
- stempeluhr-1.6.0/stempeluhr/database_controller.py +327 -0
- stempeluhr-1.6.0/stempeluhr/datastore.py +370 -0
- stempeluhr-1.6.0/stempeluhr/filepath.py +55 -0
- stempeluhr-1.6.0/stempeluhr/icons.py +82 -0
- stempeluhr-1.6.0/stempeluhr/main.py +59 -0
- stempeluhr-1.6.0/stempeluhr/migrations/env.py +74 -0
- stempeluhr-1.6.0/stempeluhr/migrations/script.py.mako +28 -0
- stempeluhr-1.6.0/stempeluhr/migrations/versions/348acf3ce3c3_add_reason_column.py +36 -0
- stempeluhr-1.6.0/stempeluhr/migrations/versions/74beea3304bb_add_overtime_adjustment_table.py +38 -0
- stempeluhr-1.6.0/stempeluhr/migrations/versions/813a2379f36d_add_project_column_to_time.py +28 -0
- stempeluhr-1.6.0/stempeluhr/migrations/versions/c5e8a1b2d3f4_add_work_schedule_table.py +42 -0
- stempeluhr-1.6.0/stempeluhr/models.py +162 -0
- stempeluhr-1.6.0/stempeluhr/ui/__init__.py +13 -0
- stempeluhr-1.6.0/stempeluhr/ui/clock.png +0 -0
- stempeluhr-1.6.0/stempeluhr/ui/config_window.py +375 -0
- stempeluhr-1.6.0/stempeluhr/ui/config_window.ui +834 -0
- stempeluhr-1.6.0/stempeluhr/ui/data_window.py +172 -0
- stempeluhr-1.6.0/stempeluhr/ui/data_window.ui +374 -0
- stempeluhr-1.6.0/stempeluhr/ui/mainwindow.py +183 -0
- stempeluhr-1.6.0/stempeluhr/ui/mainwindow.ui +337 -0
- stempeluhr-1.6.0/stempeluhr/ui/overtime_window.py +101 -0
- stempeluhr-1.6.0/stempeluhr/ui/overtime_window.ui +161 -0
- stempeluhr-1.6.0/stempeluhr/ui/stempeluhr.svg +14 -0
- stempeluhr-1.6.0/stempeluhr/ui/vacation_window.py +116 -0
- stempeluhr-1.6.0/stempeluhr/ui/vacation_window.ui +208 -0
- stempeluhr-1.6.0/stempeluhr/ui_config_window.py +199 -0
- stempeluhr-1.6.0/stempeluhr/ui_controller.py +128 -0
- stempeluhr-1.6.0/stempeluhr/ui_data_window.py +512 -0
- stempeluhr-1.6.0/stempeluhr/ui_mainwindow.py +262 -0
- stempeluhr-1.6.0/stempeluhr/ui_overtime_window.py +87 -0
- stempeluhr-1.6.0/stempeluhr/ui_schedule_window.py +218 -0
- stempeluhr-1.6.0/stempeluhr/ui_vacation_window.py +114 -0
- stempeluhr-1.6.0/stempeluhr/updater.py +18 -0
- stempeluhr-1.6.0/stempeluhr/utils.py +139 -0
stempeluhr-1.6.0/LICENSE
ADDED
|
@@ -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
|
+

|
|
37
|
+

|
|
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
|
+

|
|
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
|
+

|
|
8
|
+

|
|
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
|
+

|
|
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()
|