wiederverwendbar 0.9.0__py3-none-any.whl → 0.9.2__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  __title__ = "wiederverwendbar"
2
2
  __description__ = "A collection of scripts, classes and tools they are \\\"wiederverwendbar\\\"."
3
- __version__ = "0.9.0"
3
+ __version__ = "0.9.2"
4
4
  __author__ = "Julius Koenig"
5
5
  __author_email__ = "info@bastelquartier.de"
6
6
  __license__ = "GPL-3.0"
@@ -22,13 +22,15 @@ class BrandingSettings(BaseModel):
22
22
  main_module = sys.modules["__main__"]
23
23
  module_data = self.get_attributes(main_module.__dict__)
24
24
  if module_data is None:
25
- init_file = Path(main_module.__file__).parent / "__init__.py"
26
- if init_file.is_file():
27
- init_file_module_spec = importlib.util.spec_from_file_location("__main__.__init__", init_file)
28
- init_file_module = importlib.util.module_from_spec(init_file_module_spec)
29
- sys.modules["__main__.__init__"] = init_file_module
30
- init_file_module_spec.loader.exec_module(init_file_module)
31
- module_data = self.get_attributes(init_file_module.__dict__)
25
+ # ToDO: this code is not working for pyprojects.toml [project.scripts]
26
+ if hasattr(main_module, "__file__"):
27
+ init_file = Path(main_module.__file__).parent / "__init__.py"
28
+ if init_file.is_file():
29
+ init_file_module_spec = importlib.util.spec_from_file_location("__main__.__init__", init_file)
30
+ init_file_module = importlib.util.module_from_spec(init_file_module_spec)
31
+ sys.modules["__main__.__init__"] = init_file_module
32
+ init_file_module_spec.loader.exec_module(init_file_module)
33
+ module_data = self.get_attributes(init_file_module.__dict__)
32
34
  if module_data is None:
33
35
  module_data = {}
34
36
 
@@ -367,7 +367,10 @@ class FastAPI(_FastAPI):
367
367
  "terms_of_service": self.terms_of_service}
368
368
 
369
369
  async def get_version(self, request: Request) -> dict[str, Any]:
370
- return {"version": self.version}
370
+ version = self.version
371
+ if version.startswith("v"):
372
+ version = version[1:]
373
+ return {"version": version}
371
374
 
372
375
  async def get_root_redirect(self, request: Request) -> RedirectResponse:
373
376
  root_path = request.scope.get("root_path", "").rstrip("/")
@@ -172,13 +172,13 @@ class SqlalchemyDb:
172
172
  else:
173
173
  connection_string += self.password
174
174
  if self.host is None:
175
- raise RuntimeError(f"No host specified for {self}")
175
+ raise RuntimeError(f"No host specified for {self.__class__.__name__}")
176
176
  connection_string += f"@{self.host}"
177
177
  if self.port is None:
178
- raise RuntimeError(f"No port specified for {self}")
178
+ raise RuntimeError(f"No port specified for {self.__class__.__name__}")
179
179
  connection_string += f":{self.port}"
180
180
  if self.name is None:
181
- raise RuntimeError(f"No name specified for {self}")
181
+ raise RuntimeError(f"No name specified for {self.__class__.__name__}")
182
182
  connection_string += f"/{self.name}"
183
183
  return connection_string
184
184
 
@@ -1,4 +1,17 @@
1
- from wiederverwendbar.task_manger.task_manager import TaskManager
2
- from wiederverwendbar.task_manger.singleton import ManagerSingleton
3
- from wiederverwendbar.task_manger.task import Task
4
- from wiederverwendbar.task_manger.trigger import Interval, EverySeconds, EveryMinutes, EveryHours, EveryDays, EveryWeeks, EveryMonths, EveryYears, At, AtNow, AtCreation
1
+ from wiederverwendbar.task_manger.task_manager import (TaskManager)
2
+ from wiederverwendbar.task_manger.singleton import (ManagerSingleton)
3
+ from wiederverwendbar.task_manger.task import (Task)
4
+ from wiederverwendbar.task_manger.trigger import (Trigger,
5
+ Interval,
6
+ EverySeconds,
7
+ EveryMinutes,
8
+ EveryHours,
9
+ EveryDays,
10
+ EveryWeeks,
11
+ EveryMonths,
12
+ EveryYears,
13
+ At,
14
+ AtDatetime,
15
+ AtNow,
16
+ AtManagerCreation,
17
+ AtManagerStart)
@@ -1,104 +1,147 @@
1
- from datetime import datetime
2
- from typing import Optional
1
+ from datetime import datetime as _datetime
2
+ from enum import Enum
3
+ from typing import Any, Optional, Callable, Union, TYPE_CHECKING
3
4
 
4
- from wiederverwendbar.task_manger.trigger import Trigger, Interval, At
5
+ from wiederverwendbar.functions.is_coroutine_function import is_coroutine_function
6
+ from wiederverwendbar.task_manger.trigger import Trigger
7
+
8
+ if TYPE_CHECKING:
9
+ from wiederverwendbar.task_manger.task_manager import TaskManager
5
10
 
6
11
 
7
12
  class Task:
13
+ class TimeMeasurement(str, Enum):
14
+ START = "START"
15
+ END = "END"
16
+
8
17
  def __init__(self,
9
- payload,
10
- manager=None,
18
+ payload: Callable[..., None],
19
+ *triggers: Trigger,
11
20
  name: Optional[str] = None,
12
- trigger: Optional[Trigger] = None,
13
- time_measurement_before_run: bool = True,
14
- auto_add: Optional[bool] = None,
15
- *args,
16
- **kwargs):
17
- # set task name
21
+ time_measurement: Optional[TimeMeasurement] = None,
22
+ task_args: Optional[Union[list, tuple]] = None,
23
+ task_kwargs: Optional[dict] = None):
24
+ self._manager = None
25
+
26
+ # set the task name
18
27
  if name is None:
19
28
  name = payload.__name__
20
- self.name = name
21
-
22
- self.manager = None
23
-
24
- # set task trigger
25
- if not isinstance(trigger, (Interval, At)):
26
- raise ValueError("Invalid trigger object.")
27
- self.trigger = trigger
29
+ self._name = name
30
+
31
+ # set task triggers
32
+ self._triggers = []
33
+ for trigger in triggers:
34
+ if not isinstance(trigger, Trigger):
35
+ raise ValueError("Trigger must be an instance of Trigger.")
36
+ if trigger.task is not None:
37
+ raise ValueError("Trigger already assigned to a task.")
38
+ trigger._task = self
39
+ self._triggers.append(trigger)
40
+ self._triggers = tuple(self._triggers)
28
41
 
29
42
  # set task payload
30
43
  if not callable(payload):
31
44
  raise ValueError("Payload must be callable.")
45
+ if is_coroutine_function(payload):
46
+ raise ValueError("Coroutine functions are not supported.")
32
47
  self._payload = payload
33
48
 
49
+ # indicates when the last run time should be measured
50
+ if time_measurement is None:
51
+ time_measurement = self.TimeMeasurement.START
52
+ if not isinstance(time_measurement, self.TimeMeasurement):
53
+ raise ValueError("Time measurement must be an instance of TaskTimeMeasurement.")
54
+ self._time_measurement = time_measurement
55
+
34
56
  # set payload args and kwargs
35
- self.args = []
36
- self.kwargs = {}
37
- if not iter(args):
38
- raise ValueError("Args must be iterable.")
39
- for arg in args:
40
- self.args.append(arg)
41
- if not isinstance(kwargs, dict):
42
- raise ValueError("Kwargs must be dict.")
43
- self.kwargs = kwargs
44
-
45
- self.time_measurement_before_run = time_measurement_before_run
46
-
47
- self._last_run: Optional[datetime] = None
48
- self._next_run: Optional[datetime] = None
49
-
50
- # indicate if task is done
57
+ if task_args is None:
58
+ task_args = []
59
+ if not iter(task_args):
60
+ raise ValueError("Task args must be iterable.")
61
+ self._task_args = tuple(task_args)
62
+ if task_kwargs is None:
63
+ task_kwargs = {}
64
+ if not isinstance(task_kwargs, dict):
65
+ raise ValueError("Task kwargs must be dict.")
66
+ self._task_kwargs = task_kwargs
67
+
68
+ # indicate last run
69
+ self._last_run = None
70
+
71
+ # indicate if the task is done
51
72
  self._done = False
52
73
 
53
- # auto add task to manager
54
- if auto_add is None:
55
- auto_add = True if manager else False
74
+ def __str__(self):
75
+ return (f"{self.__class__.__name__}("
76
+ f"name={self.name}, "
77
+ f"trigger=[{', '.join([str(trigger) for trigger in self._triggers])}], "
78
+ f"last_run={self.last_run})")
56
79
 
57
- if auto_add:
58
- if not manager:
59
- raise ValueError("Manager object is required.")
60
- manager.add_task(self)
80
+ def __call__(self, *args, **kwargs) -> bool:
81
+ if self.manager is None:
82
+ raise ValueError(f"Task {self} is not assigned to a manager.")
83
+ for trigger in self.triggers:
84
+ if trigger():
85
+ return True
86
+ return False
61
87
 
62
- def init(self, manager):
63
- self.manager = manager
64
- self.trigger.init(manager)
65
- self.set_next_run()
88
+ @property
89
+ def manager(self) -> Optional["TaskManager"]:
90
+ return self._manager
91
+
92
+ @manager.setter
93
+ def manager(self, manager: "TaskManager") -> None:
94
+ if manager is None:
95
+ if self._manager is None:
96
+ return
97
+ manager = self._manager
98
+ with manager.lock:
99
+ # noinspection PyProtectedMember
100
+ manager._tasks.remove(self)
101
+ self.manager_removed()
102
+ else:
103
+ if self._manager is not None:
104
+ raise ValueError(f"Task {self} is already assigned to manager {self._manager}.")
105
+ self._manager = manager
66
106
 
67
- # log task creation
68
- self.manager.logger.debug(f"Task created.")
107
+ with manager.lock:
108
+ # noinspection PyProtectedMember
109
+ manager._tasks.append(self)
110
+ self.manager_added()
69
111
 
70
112
  @property
71
- def last_run(self) -> Optional[datetime]:
72
- if self._last_run is None:
73
- return datetime.fromtimestamp(0)
74
- return self._last_run
113
+ def name(self) -> str:
114
+ return self._name
75
115
 
76
116
  @property
77
- def next_run(self) -> Optional[datetime]:
78
- if self.is_done:
79
- return None
80
- return self._next_run
117
+ def triggers(self) -> tuple[Trigger, ...]:
118
+ return self._triggers
81
119
 
82
120
  @property
83
- def is_done(self) -> bool:
84
- return self._done
85
-
86
- def set_next_run(self):
87
- if isinstance(self.trigger, Interval):
88
- next_run = self.trigger.next(self.last_run)
89
- elif isinstance(self.trigger, At):
90
- next_run = self.trigger.next()
91
- if next_run == self._next_run:
92
- self.done()
93
- else:
94
- raise ValueError("Invalid trigger object.")
95
- self._next_run = next_run
121
+ def time_measurement(self) -> TimeMeasurement:
122
+ return self._time_measurement
123
+
124
+ @property
125
+ def task_args(self) -> tuple[Any]:
126
+ return self._task_args
127
+
128
+ @property
129
+ def task_kwargs(self) -> dict[str, Any]:
130
+ return self._task_kwargs
131
+
132
+ @property
133
+ def last_run(self) -> Optional[_datetime]:
134
+ return self._last_run
96
135
 
97
- def set_last_run(self):
98
- self._last_run = datetime.now()
136
+ def manager_added(self) -> None:
137
+ for trigger in self.triggers:
138
+ trigger.manager_added()
139
+ self.manager.logger.debug(f"{self.manager} -> Task {self} added.")
99
140
 
100
- def done(self):
101
- self._done = True
141
+ def manager_removed(self) -> None:
142
+ for trigger in self.triggers:
143
+ trigger.manager_removed()
144
+ self.manager.logger.debug(f"{self.manager} -> Task {self} removed.")
102
145
 
103
- def payload(self):
104
- self._payload(*self.args, **self.kwargs)
146
+ def payload(self) -> None:
147
+ self._payload(*self.task_args, **self.task_kwargs)