asyncz 0.8.2__tar.gz → 0.8.3__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 (55) hide show
  1. {asyncz-0.8.2 → asyncz-0.8.3}/PKG-INFO +1 -1
  2. asyncz-0.8.3/asyncz/__init__.py +1 -0
  3. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/executors/base.py +1 -3
  4. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/schedulers/base.py +0 -2
  5. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/stores/memory.py +1 -1
  6. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/utils.py +5 -1
  7. asyncz-0.8.2/asyncz/__init__.py +0 -1
  8. asyncz-0.8.2/asyncz/contrib/esmerald/__init__.py +0 -0
  9. asyncz-0.8.2/asyncz/contrib/esmerald/decorator.py +0 -40
  10. asyncz-0.8.2/asyncz/contrib/esmerald/scheduler.py +0 -217
  11. asyncz-0.8.2/asyncz/stores/__init__.py +0 -0
  12. {asyncz-0.8.2 → asyncz-0.8.3}/.gitignore +0 -0
  13. {asyncz-0.8.2 → asyncz-0.8.3}/LICENSE +0 -0
  14. {asyncz-0.8.2 → asyncz-0.8.3}/README.md +0 -0
  15. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/_mapping.py +0 -0
  16. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/datastructures.py +0 -0
  17. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/enums.py +0 -0
  18. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/events/__init__.py +0 -0
  19. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/events/base.py +0 -0
  20. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/events/constants.py +0 -0
  21. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/exceptions.py +0 -0
  22. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/executors/__init__.py +0 -0
  23. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/executors/asyncio.py +0 -0
  24. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/executors/debug.py +0 -0
  25. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/executors/pool.py +0 -0
  26. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/executors/types.py +0 -0
  27. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/py.typed +0 -0
  28. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/schedulers/__init__.py +0 -0
  29. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/schedulers/asyncio.py +0 -0
  30. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/schedulers/datastructures.py +0 -0
  31. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/schedulers/types.py +0 -0
  32. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/schedulers/utils.py +0 -0
  33. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/state.py +0 -0
  34. {asyncz-0.8.2/asyncz/contrib → asyncz-0.8.3/asyncz/stores}/__init__.py +0 -0
  35. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/stores/base.py +0 -0
  36. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/stores/mongo.py +0 -0
  37. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/stores/redis.py +0 -0
  38. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/stores/types.py +0 -0
  39. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/tasks/__init__.py +0 -0
  40. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/tasks/base.py +0 -0
  41. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/tasks/types.py +0 -0
  42. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/__init__.py +0 -0
  43. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/base.py +0 -0
  44. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/combination.py +0 -0
  45. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/cron/__init__.py +0 -0
  46. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/cron/constants.py +0 -0
  47. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/cron/expressions.py +0 -0
  48. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/cron/fields.py +0 -0
  49. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/cron/trigger.py +0 -0
  50. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/cron/types.py +0 -0
  51. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/date.py +0 -0
  52. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/interval.py +0 -0
  53. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/triggers/types.py +0 -0
  54. {asyncz-0.8.2 → asyncz-0.8.3}/asyncz/typing.py +0 -0
  55. {asyncz-0.8.2 → asyncz-0.8.3}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: asyncz
3
- Version: 0.8.2
3
+ Version: 0.8.3
4
4
  Summary: The scheduler that nobody wants but every application needs.
5
5
  Project-URL: Homepage, https://github.com/dymmond/asyncz
6
6
  Project-URL: Documentation, https://asyncz.dymmond.com/
@@ -0,0 +1 @@
1
+ __version__ = "0.8.3"
@@ -97,9 +97,7 @@ class BaseExecutor(BaseStateExtra, ABC):
97
97
  if self.instances[task_id] == 0:
98
98
  del self.instances[task_id]
99
99
 
100
- self.logger.opt(exception=True).error(
101
- f"Error running task {task_id}", exc_info=True
102
- )
100
+ self.logger.opt(exception=True).error(f"Error running task {task_id}", exc_info=True)
103
101
 
104
102
 
105
103
  def run_task(
@@ -155,7 +155,6 @@ class BaseScheduler(BaseStateExtra, ABC):
155
155
  raise SchedulerAlreadyRunningError()
156
156
 
157
157
  self.check_uwsgi()
158
-
159
158
  with self.executor_lock:
160
159
  if "default" not in self.executors:
161
160
  self.add_executor(self.create_default_executor(), "default")
@@ -824,7 +823,6 @@ class BaseScheduler(BaseStateExtra, ABC):
824
823
 
825
824
  # Apply replacements
826
825
  task._update(**replacements)
827
-
828
826
  # Add the task to the given store
829
827
  store = self.lookup_store(store_alias)
830
828
  try:
@@ -11,7 +11,7 @@ if TYPE_CHECKING:
11
11
 
12
12
  class MemoryStore(BaseStore):
13
13
  """
14
- Stores tasks in an arrat in RAM. Provides no persistance support.
14
+ Stores tasks in an array in RAM. Provides no persistance support.
15
15
  """
16
16
 
17
17
  def __init__(self, **kwargs):
@@ -234,10 +234,14 @@ def ref_to_obj(ref: str) -> Any:
234
234
  raise AsynczLookupError(
235
235
  "Error resolving reference %s: could not import module" % ref
236
236
  ) from None
237
-
238
237
  try:
239
238
  for name in rest.split("."):
240
239
  obj = getattr(obj, name)
240
+
241
+ # It might come from a class containing the fn attribute
242
+ # implementation of the __call__ method
243
+ if hasattr(obj, "fn"):
244
+ obj = obj.fn
241
245
  return obj
242
246
  except Exception:
243
247
  raise AsynczLookupError(
@@ -1 +0,0 @@
1
- __version__ = "0.8.2"
File without changes
@@ -1,40 +0,0 @@
1
- from datetime import datetime
2
- from typing import Any, Dict, Optional
3
-
4
- from asyncz.contrib.esmerald.scheduler import Task
5
- from asyncz.triggers.types import TriggerType
6
-
7
-
8
- class scheduler(Task):
9
- def __init__(
10
- self,
11
- *,
12
- name: Optional[str] = None,
13
- trigger: Optional[TriggerType] = None,
14
- id: Optional[str] = None,
15
- mistrigger_grace_time: Optional[int] = None,
16
- coalesce: Optional[bool] = None,
17
- max_instances: Optional[int] = None,
18
- next_run_time: Optional[datetime] = None,
19
- store: Optional[str] = "default",
20
- executor: Optional[str] = "default",
21
- replace_existing: bool = True,
22
- extra_args: Optional[Any] = None,
23
- extra_kwargs: Optional[Dict[str, Any]] = None,
24
- is_enabled: bool = True,
25
- ) -> None:
26
- super().__init__(
27
- name=name,
28
- trigger=trigger,
29
- id=id,
30
- mistrigger_grace_time=mistrigger_grace_time,
31
- coalesce=coalesce,
32
- max_instances=max_instances,
33
- next_run_time=next_run_time,
34
- store=store,
35
- executor=executor,
36
- replace_existing=replace_existing,
37
- args=extra_args,
38
- kwargs=extra_kwargs,
39
- is_enabled=is_enabled,
40
- )
@@ -1,217 +0,0 @@
1
- import warnings
2
- from datetime import datetime
3
- from datetime import timezone as dtimezone
4
- from typing import TYPE_CHECKING, Any, Dict, Optional, Union
5
-
6
- from asyncz.schedulers.types import SchedulerType
7
- from asyncz.triggers.types import TriggerType
8
- from asyncz.typing import undefined
9
-
10
- try:
11
- from esmerald.conf import settings
12
- from esmerald.exceptions import ImproperlyConfigured
13
- from esmerald.utils.module_loading import import_string
14
- except ImportError:
15
- raise ImportError(
16
- "Esmerald cannot be found. Please install it by running `pip install esmerald`."
17
- ) from None
18
-
19
- if TYPE_CHECKING:
20
- from esmerald.applications import Esmerald
21
-
22
-
23
- class EsmeraldScheduler:
24
- """
25
- Scheduler instance to be used by the Esmerald application instance.
26
-
27
- Args:
28
- app: Esmerald application
29
- scheduler_class: An instance of a SchedulerType
30
- tasks: A dictinary str, str mapping the tasks to be executed.
31
- timezone: The timezone instance.
32
- configurations: A dictionary with extra configurations to be passed to the scheduler.
33
- """
34
-
35
- def __init__(
36
- self,
37
- app: Optional["Esmerald"] = None,
38
- scheduler_class: Optional["SchedulerType"] = None,
39
- tasks: Optional[Dict[str, str]] = None,
40
- timezone: Optional[Union[dtimezone, str]] = None,
41
- configurations: Optional[Dict[str, Dict[str, str]]] = None,
42
- ) -> None:
43
- self.app = app
44
- self.tasks = tasks
45
- self.timezone = timezone
46
- self.scheduler_class = scheduler_class
47
- self.configurations = configurations
48
-
49
- if not self.scheduler_class and self.app.enable_scheduler:
50
- raise ImproperlyConfigured(
51
- "It cannot start the scheduler if there is no scheduler_class declared."
52
- )
53
-
54
- for task, module in self.tasks.items():
55
- if not isinstance(task, str) or not isinstance(module, str):
56
- raise ImproperlyConfigured("The dict of tasks must be Dict[str, str].")
57
-
58
- if not self.tasks:
59
- warnings.warn(
60
- "Esmerald is starting the scheduler, yet there are no tasks declared.",
61
- UserWarning,
62
- stacklevel=2,
63
- )
64
-
65
- # Load the scheduler object
66
- self.handler = self.get_scheduler(
67
- scheduler=self.scheduler_class,
68
- timezone=self.timezone,
69
- configurations=self.configurations,
70
- )
71
-
72
- self.register_events(app=self.app)
73
- self.register_tasks(tasks=self.tasks)
74
-
75
- def register_tasks(self, tasks: Dict[str, str]) -> None:
76
- """
77
- Registers the tasks in the Scheduler
78
- """
79
- for task, _module in tasks.items():
80
- imported_task = f"{_module}.{task}"
81
- scheduled_task: "Task" = import_string(imported_task)
82
-
83
- if not scheduled_task.is_enabled:
84
- continue
85
-
86
- try:
87
- scheduled_task.add_task(self.handler)
88
- except Exception as e:
89
- raise ImproperlyConfigured(str(e)) from e
90
-
91
- def register_events(self, app: "Esmerald") -> None:
92
- """
93
- Registers the scheduler events in the Esmerald application.
94
- """
95
- if app.on_startup is not None:
96
- app.on_startup.append(self.handler.start)
97
- else:
98
- app.on_startup = [self.handler.start]
99
-
100
- if app.on_shutdown is not None:
101
- app.on_shutdown.append(self.handler.shutdown)
102
- else:
103
- app.on_shutdown = [self.handler.shutdown]
104
-
105
- def get_scheduler(
106
- self,
107
- scheduler: "SchedulerType",
108
- timezone: Optional[dtimezone] = None,
109
- configurations: Optional[Dict[str, str]] = None,
110
- ) -> SchedulerType:
111
- """
112
- Initiates the scheduler from the given time.
113
- If no value is provided, it will default to AsyncIOScheduler.
114
-
115
- The value of `scheduler_class` can be overwritten by any esmerald custom settings.
116
-
117
- Args:
118
- scheduler: AsyncIOScheduler.
119
- timezone: The timezone instance.
120
- configurations: A dictionary with extra configurations to be passed to the scheduler.
121
-
122
- Return:
123
- SchedulerType: An instance of a Scheduler.
124
- """
125
- if not timezone:
126
- timezone = settings.timezone
127
-
128
- if not configurations:
129
- return scheduler(timezone=timezone)
130
-
131
- return scheduler(global_config=configurations, timezone=timezone)
132
-
133
-
134
- class Task:
135
- """
136
- Base for the scheduler decorator that will auto discover the
137
- tasks in the application and add them to the internal scheduler.
138
- """
139
-
140
- def __init__(
141
- self,
142
- *,
143
- name: Optional[str] = None,
144
- trigger: Optional[TriggerType] = None,
145
- id: Optional[str] = None,
146
- mistrigger_grace_time: Optional[int] = None,
147
- coalesce: Optional[bool] = None,
148
- max_instances: Optional[int] = None,
149
- next_run_time: Optional[datetime] = None,
150
- store: Optional[str] = "default",
151
- executor: Optional[str] = "default",
152
- replace_existing: bool = False,
153
- args: Optional[Any] = None,
154
- kwargs: Optional[Dict[str, Any]] = None,
155
- is_enabled: bool = True,
156
- ) -> None:
157
- """_summary_
158
-
159
- Args:
160
- name: Textual description of the task.
161
- trigger: An instance of a trigger class.
162
- identifier: Explicit identifier for the task.
163
- mistrigger_grace_time: Seconds after the designated runtime that the task is still allowed to be run (or None to allow the task to run no
164
- matter how late it is).
165
- coalesce: Run once instead of many times if the scheduler determines that the task should be run more than once in succession.
166
- max_instances: Maximum number of concurrently running instances allowed for this task.
167
- next_run_time: When to first run the task, regardless of the trigger (pass None to add the task as paused).
168
- store: Alias of the task store to store the task in.
169
- executor: Alias of the executor to run the task with.
170
- replace_existing: True to replace an existing task with the same id
171
- (but retain the number of runs from the existing one).
172
- args: List of positional arguments to call func with.
173
- kwargs: Dict of keyword arguments to call func with.
174
- is_enabled: True if the the task to be added to the scheduler.
175
- """
176
- self.name = name
177
- self.trigger = trigger
178
- self.id = id
179
- self.mistrigger_grace_time = mistrigger_grace_time or undefined
180
- self.coalesce = coalesce or undefined
181
- self.max_instances = max_instances or undefined
182
- self.next_run_time = next_run_time or undefined
183
- self.store = store
184
- self.executor = executor
185
- self.replace_existing = replace_existing
186
- self.args = args
187
- self.kwargs = kwargs
188
- self.is_enabled = is_enabled
189
- self.fn = None
190
-
191
- def add_task(self, scheduler: "SchedulerType"):
192
- try:
193
- scheduler.add_task(
194
- fn=self.fn,
195
- trigger=self.trigger,
196
- args=self.args,
197
- kwargs=self.kwargs,
198
- id=self.id,
199
- name=self.name,
200
- mistrigger_grace_time=self.mistrigger_grace_time,
201
- coalesce=self.coalesce,
202
- max_instances=self.max_instances,
203
- next_run_time=self.next_run_time,
204
- store=self.store,
205
- executor=self.executor,
206
- replace_existing=self.replace_existing,
207
- )
208
- except Exception as e:
209
- raise ImproperlyConfigured(str(e)) from e
210
-
211
- def __call__(self, fn: Any) -> None:
212
- """
213
- Tricking the object into think it's being instantiated by in reality
214
- is just returning itself.
215
- """
216
- self.fn = fn
217
- return self
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes