summaryrefslogtreecommitdiff
path: root/overlays/worktime
diff options
context:
space:
mode:
Diffstat (limited to 'overlays/worktime')
-rw-r--r--overlays/worktime/poetry.lock30
-rw-r--r--overlays/worktime/pyproject.toml2
-rwxr-xr-xoverlays/worktime/worktime/__main__.py44
3 files changed, 38 insertions, 38 deletions
diff --git a/overlays/worktime/poetry.lock b/overlays/worktime/poetry.lock
index 7a9a9b86..eab1d070 100644
--- a/overlays/worktime/poetry.lock
+++ b/overlays/worktime/poetry.lock
@@ -110,22 +110,6 @@ files = [
110] 110]
111 111
112[[package]] 112[[package]]
113name = "configparser"
114version = "5.3.0"
115description = "Updated configparser from stdlib for earlier Pythons."
116category = "main"
117optional = false
118python-versions = ">=3.7"
119files = [
120 {file = "configparser-5.3.0-py3-none-any.whl", hash = "sha256:b065779fd93c6bf4cee42202fa4351b4bb842e96a3fb469440e484517a49b9fa"},
121 {file = "configparser-5.3.0.tar.gz", hash = "sha256:8be267824b541c09b08db124917f48ab525a6c3e837011f3130781a224c57090"},
122]
123
124[package.extras]
125docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"]
126testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "types-backports"]
127
128[[package]]
129name = "idna" 113name = "idna"
130version = "3.4" 114version = "3.4"
131description = "Internationalized Domain Names in Applications (IDNA)" 115description = "Internationalized Domain Names in Applications (IDNA)"
@@ -214,6 +198,18 @@ files = [
214widechars = ["wcwidth"] 198widechars = ["wcwidth"]
215 199
216[[package]] 200[[package]]
201name = "toml"
202version = "0.10.2"
203description = "Python Library for Tom's Obvious, Minimal Language"
204category = "main"
205optional = false
206python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
207files = [
208 {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
209 {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
210]
211
212[[package]]
217name = "uritools" 213name = "uritools"
218version = "4.0.1" 214version = "4.0.1"
219description = "URI parsing, classification and composition" 215description = "URI parsing, classification and composition"
@@ -245,4 +241,4 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
245[metadata] 241[metadata]
246lock-version = "2.0" 242lock-version = "2.0"
247python-versions = "^3.10" 243python-versions = "^3.10"
248content-hash = "30e7918385e12f686b92da70a0be69cd22879892239b65e399828c24d13ca262" 244content-hash = "0d556c1b7f4ca6764a006e10ef9949359911925a9dae09d25a3c3d26d8966790"
diff --git a/overlays/worktime/pyproject.toml b/overlays/worktime/pyproject.toml
index f3fd3dfa..61257422 100644
--- a/overlays/worktime/pyproject.toml
+++ b/overlays/worktime/pyproject.toml
@@ -10,9 +10,9 @@ pyxdg = "^0.28"
10python-dateutil = "^2.8.2" 10python-dateutil = "^2.8.2"
11uritools = "^4.0.1" 11uritools = "^4.0.1"
12requests = "^2.28.2" 12requests = "^2.28.2"
13configparser = "^5.3.0"
14tabulate = "^0.9.0" 13tabulate = "^0.9.0"
15backoff = "^2.2.1" 14backoff = "^2.2.1"
15toml = "^0.10.2"
16 16
17[tool.poetry.scripts] 17[tool.poetry.scripts]
18worktime = "worktime.__main__:main" 18worktime = "worktime.__main__:main"
diff --git a/overlays/worktime/worktime/__main__.py b/overlays/worktime/worktime/__main__.py
index ed7880db..2dc9ed72 100755
--- a/overlays/worktime/worktime/__main__.py
+++ b/overlays/worktime/worktime/__main__.py
@@ -3,7 +3,7 @@ from requests.exceptions import HTTPError
3from requests.auth import HTTPBasicAuth 3from requests.auth import HTTPBasicAuth
4from datetime import * 4from datetime import *
5from xdg import (BaseDirectory) 5from xdg import (BaseDirectory)
6import configparser 6import toml
7from uritools import uricompose 7from uritools import uricompose
8 8
9from dateutil.easter import * 9from dateutil.easter import *
@@ -30,6 +30,8 @@ from functools import cache
30 30
31import backoff 31import backoff
32 32
33from pathlib import Path
34
33 35
34class TogglAPISection(Enum): 36class TogglAPISection(Enum):
35 TOGGL = '/api/v8' 37 TOGGL = '/api/v8'
@@ -201,10 +203,8 @@ class Worktime(object):
201 203
202 @staticmethod 204 @staticmethod
203 def config(): 205 def config():
204 config = configparser.ConfigParser()
205 config_dir = BaseDirectory.load_first_config('worktime') 206 config_dir = BaseDirectory.load_first_config('worktime')
206 config.read(f"{config_dir}/worktime.ini") 207 return toml.load(Path(config_dir) / 'worktime.toml')
207 return config
208 208
209 def ordinal_workday(self, date): 209 def ordinal_workday(self, date):
210 start_date = datetime(date.year, 1, 1, tzinfo=tzlocal()).date() 210 start_date = datetime(date.year, 1, 1, tzinfo=tzlocal()).date()
@@ -222,14 +222,18 @@ class Worktime(object):
222 222
223 config = Worktime.config() 223 config = Worktime.config()
224 config_dir = BaseDirectory.load_first_config('worktime') 224 config_dir = BaseDirectory.load_first_config('worktime')
225 api = TogglAPI(api_token=config['TOGGL']['ApiToken'], workspace_id=config['TOGGL']['Workspace'], client_ids=config.get('TOGGL', 'ClientIds', fallback=None)) 225 api = TogglAPI(
226 date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') 226 api_token=config.get("TOGGL", {}).get("ApiToken", None),
227 227 workspace_id=config.get("TOGGL", {}).get("Workspace", None),
228 start_date = start_datetime or datetime.strptime(config['WORKTIME']['StartDate'], date_format).replace(tzinfo=tzlocal()) 228 client_ids=config.get("TOGGL", {}).get("ClientIds", None)
229 )
230 date_format = config.get("WORKTIME", {}).get("DateFormat", '%Y-%m-%d')
231
232 start_date = start_datetime or datetime.strptime(config.get("WORKTIME", {}).get("StartDate"), date_format).replace(tzinfo=tzlocal())
229 end_date = end_datetime or self.now 233 end_date = end_datetime or self.now
230 234
231 try: 235 try:
232 with open(f"{config_dir}/reset", 'r') as reset: 236 with open(Path(config_dir) / "reset", 'r') as reset:
233 for line in reset: 237 for line in reset:
234 stripped_line = line.strip() 238 stripped_line = line.strip()
235 reset_date = datetime.strptime(stripped_line, date_format).replace(tzinfo=tzlocal()) 239 reset_date = datetime.strptime(stripped_line, date_format).replace(tzinfo=tzlocal())
@@ -241,13 +245,13 @@ class Worktime(object):
241 raise e 245 raise e
242 246
243 247
244 hours_per_week = float(config.get('WORKTIME', 'HoursPerWeek', fallback=40)) 248 hours_per_week = float(config.get("WORKTIME", {}).get("HoursPerWeek", 40))
245 self.workdays = set([int(d.strip()) for d in config.get('WORKTIME', 'Workdays', fallback='1,2,3,4,5').split(',')]) 249 self.workdays = set([int(d.strip()) for d in config.get("WORKTIME", {}).get("Workdays", '1,2,3,4,5').split(',')])
246 self.time_per_day = timedelta(hours = hours_per_week) / len(self.workdays) 250 self.time_per_day = timedelta(hours = hours_per_week) / len(self.workdays)
247 251
248 holidays = dict() 252 holidays = dict()
249 253
250 leave_per_year = int(config.get('WORKTIME', 'LeavePerYear', fallback=30)) 254 leave_per_year = int(config.get("WORKTIME", {}).get("LeavePerYear", 30))
251 for year in range(start_date.year, end_date.year + 1): 255 for year in range(start_date.year, end_date.year + 1):
252 holidays |= {k: v * self.time_per_day for k, v in Worktime.holidays(year).items()} 256 holidays |= {k: v * self.time_per_day for k, v in Worktime.holidays(year).items()}
253 leave_frac = 1 257 leave_frac = 1
@@ -256,7 +260,7 @@ class Worktime(object):
256 self.leave_budget |= {year: floor(leave_per_year * leave_frac)} 260 self.leave_budget |= {year: floor(leave_per_year * leave_frac)}
257 261
258 try: 262 try:
259 with open(f"{config_dir}/reset-leave", 'r') as excused: 263 with open(Path(config_dir) / "reset-leave", 'r') as excused:
260 for line in excused: 264 for line in excused:
261 stripped_line = line.strip() 265 stripped_line = line.strip()
262 if stripped_line: 266 if stripped_line:
@@ -273,7 +277,7 @@ class Worktime(object):
273 277
274 for excused_kind in {'excused', 'leave'}: 278 for excused_kind in {'excused', 'leave'}:
275 try: 279 try:
276 with open(f"{config_dir}/{excused_kind}", 'r') as excused: 280 with open(Path(config_dir) / excused_kind, 'r') as excused:
277 for line in excused: 281 for line in excused:
278 stripped_line = line.strip() 282 stripped_line = line.strip()
279 if stripped_line: 283 if stripped_line:
@@ -314,7 +318,7 @@ class Worktime(object):
314 end_day = end_date.date() 318 end_day = end_date.date()
315 319
316 try: 320 try:
317 with open(f"{config_dir}/pull-forward", 'r') as excused: 321 with open(Path(config_dir) / "pull-forward", 'r') as excused:
318 for line in excused: 322 for line in excused:
319 stripped_line = line.strip() 323 stripped_line = line.strip()
320 if stripped_line: 324 if stripped_line:
@@ -357,7 +361,7 @@ class Worktime(object):
357 extra_days_to_work = dict() 361 extra_days_to_work = dict()
358 362
359 try: 363 try:
360 with open(f"{config_dir}/days-to-work", 'r') as extra_days_to_work_file: 364 with open(Path(config_dir) / "days-to-work", 'r') as extra_days_to_work_file:
361 for line in extra_days_to_work_file: 365 for line in extra_days_to_work_file:
362 stripped_line = line.strip() 366 stripped_line = line.strip()
363 if stripped_line: 367 if stripped_line:
@@ -413,7 +417,7 @@ class Worktime(object):
413 417
414 self.time_to_work += self.time_pulled_forward 418 self.time_to_work += self.time_pulled_forward
415 419
416 self.time_worked += api.get_billable_hours(start_date, self.now, rounding = config.getboolean('WORKTIME', 'rounding', fallback=True)) 420 self.time_worked += api.get_billable_hours(start_date, self.now, rounding = config.get("WORKTIME", {}).get("rounding", True))
417 421
418def worktime(**args): 422def worktime(**args):
419 worktime = Worktime(**args) 423 worktime = Worktime(**args)
@@ -520,7 +524,7 @@ def diff(now, **args):
520 524
521def holidays(year, **args): 525def holidays(year, **args):
522 config = Worktime.config() 526 config = Worktime.config()
523 date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') 527 date_format = config.get("WORKTIME", {}).get("DateFormat", '%Y-%m-%d')
524 528
525 table_data = [] 529 table_data = []
526 530
@@ -534,8 +538,8 @@ def leave(year, table, **args):
534 def_year = datetime.now(tzlocal()).year 538 def_year = datetime.now(tzlocal()).year
535 worktime = Worktime(**dict(**args, end_datetime = datetime(year = (year if year else def_year) + 1, month = 1, day = 1, tzinfo=tzlocal()) - timedelta(microseconds=1))) 539 worktime = Worktime(**dict(**args, end_datetime = datetime(year = (year if year else def_year) + 1, month = 1, day = 1, tzinfo=tzlocal()) - timedelta(microseconds=1)))
536 config = Worktime.config() 540 config = Worktime.config()
537 date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') 541 date_format = config.get("WORKTIME", {}).get("DateFormat", '%Y-%m-%d')
538 leave_expires = config.get('WORKTIME', 'LeaveExpires', fallback=None) 542 leave_expires = config.get("WORKTIME", {}).get("LeaveExpires", None)
539 if leave_expires: 543 if leave_expires:
540 leave_expires = datetime.strptime(leave_expires, '%m-%d').date() 544 leave_expires = datetime.strptime(leave_expires, '%m-%d').date()
541 545