csu 2.0.7__tar.gz → 2.1.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.
- {csu-2.0.7 → csu-2.1.0}/.bumpversion.cfg +1 -1
- {csu-2.0.7 → csu-2.1.0}/.cookiecutterrc +1 -1
- {csu-2.0.7 → csu-2.1.0}/PKG-INFO +3 -3
- {csu-2.0.7 → csu-2.1.0}/README.rst +2 -2
- {csu-2.0.7 → csu-2.1.0}/pyproject.toml +1 -1
- {csu-2.0.7 → csu-2.1.0}/src/csu/__init__.py +1 -1
- {csu-2.0.7 → csu-2.1.0}/src/csu/worker/engine.py +83 -60
- {csu-2.0.7 → csu-2.1.0}/src/csu/worker/enums.py +4 -2
- {csu-2.0.7 → csu-2.1.0}/src/csu.egg-info/PKG-INFO +3 -3
- {csu-2.0.7 → csu-2.1.0}/tests/exampleworker.py +8 -4
- {csu-2.0.7 → csu-2.1.0}/tests/test_worker.py +4 -3
- {csu-2.0.7 → csu-2.1.0}/.coveragerc +0 -0
- {csu-2.0.7 → csu-2.1.0}/.editorconfig +0 -0
- {csu-2.0.7 → csu-2.1.0}/.github/workflows/github-actions.yml +0 -0
- {csu-2.0.7 → csu-2.1.0}/.pre-commit-config.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/.taplo.toml +0 -0
- {csu-2.0.7 → csu-2.1.0}/AUTHORS.rst +0 -0
- {csu-2.0.7 → csu-2.1.0}/CHANGELOG.rst +0 -0
- {csu-2.0.7 → csu-2.1.0}/CONTRIBUTING.rst +0 -0
- {csu-2.0.7 → csu-2.1.0}/LICENSE +0 -0
- {csu-2.0.7 → csu-2.1.0}/MANIFEST.in +0 -0
- {csu-2.0.7 → csu-2.1.0}/ci/bootstrap.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/ci/requirements.txt +0 -0
- {csu-2.0.7 → csu-2.1.0}/ci/templates/.github/workflows/github-actions.yml +0 -0
- {csu-2.0.7 → csu-2.1.0}/pytest.ini +0 -0
- {csu-2.0.7 → csu-2.1.0}/setup.cfg +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/admin.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/conf.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/consts.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/__init__.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/auth.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/fields.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/forms.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/perms.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/phonenumber.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/serializers.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/test_auth.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/test_fields.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/test_forms.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/test_phonenumber.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/test_serializers.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/drf/views.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/enums.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/env.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/exceptions.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/export.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/fixups.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/forms/__init__.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/forms/crispy.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/forms/fields.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/gettext.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/gettext_lazy.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/locale/ro/LC_MESSAGES/django.mo +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/locale/ro/LC_MESSAGES/django.po +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/logging.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/management.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/models.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/query.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/routers.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/service.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/templates/api_exception.html +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/templates/forms/widgets/opaquewidget.html +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_consts.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_env.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_exceptions.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_logging.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_management.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_service.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_timezones.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_utils.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/test_xml.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/timezones.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/utils.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/views.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/worker/__init__.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/worker/admin.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/worker/asgi.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/worker/job.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/worker/models.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/worker/registry.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/wsgi.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu/xml.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu.egg-info/SOURCES.txt +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu.egg-info/dependency_links.txt +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu.egg-info/requires.txt +0 -0
- {csu-2.0.7 → csu-2.1.0}/src/csu.egg-info/top_level.txt +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/cassettes/test_service/test_custom_context.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/cassettes/test_service/test_custom_context_0_retries.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/cassettes/test_service/test_decoding.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/cassettes/test_service/test_error.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/cassettes/test_service/test_logging.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/cassettes/test_service/test_redirects.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/cassettes/test_service_auth/test_async.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/cassettes/test_service_auth/test_sync.yaml +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/conftest.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/test_models.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/test_service.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/test_service_auth.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/test_views.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/testproject/__init__.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/testproject/fixtures/testuser.json +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/testproject/models.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/testproject/settings.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tests/testproject/urls.py +0 -0
- {csu-2.0.7 → csu-2.1.0}/tox.ini +0 -0
{csu-2.0.7 → csu-2.1.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csu
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Clean Slate Utils - bunch of utility code, mostly Django/DRF specific.
|
|
5
5
|
Author-email: Ionel Cristian Mărieș <contact@ionelmc.ro>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -77,9 +77,9 @@ Overview
|
|
|
77
77
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
78
78
|
:alt: Supported implementations
|
|
79
79
|
:target: https://pypi.org/project/csu
|
|
80
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.0.
|
|
80
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.1.0.svg
|
|
81
81
|
:alt: Commits since latest release
|
|
82
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.0
|
|
82
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.1.0...main
|
|
83
83
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
84
84
|
:alt: Scrutinizer Status
|
|
85
85
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -34,9 +34,9 @@ Overview
|
|
|
34
34
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
35
35
|
:alt: Supported implementations
|
|
36
36
|
:target: https://pypi.org/project/csu
|
|
37
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.0.
|
|
37
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.1.0.svg
|
|
38
38
|
:alt: Commits since latest release
|
|
39
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.0
|
|
39
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.1.0...main
|
|
40
40
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
41
41
|
:alt: Scrutinizer Status
|
|
42
42
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -4,11 +4,12 @@ import traceback
|
|
|
4
4
|
from abc import ABC
|
|
5
5
|
from abc import abstractmethod
|
|
6
6
|
from asyncio import CancelledError
|
|
7
|
+
from asyncio import Event
|
|
7
8
|
from asyncio import Future
|
|
8
9
|
from asyncio import Queue
|
|
9
|
-
from asyncio import Semaphore
|
|
10
10
|
from collections import defaultdict
|
|
11
|
-
from
|
|
11
|
+
from collections.abc import AsyncIterator
|
|
12
|
+
from contextlib import asynccontextmanager
|
|
12
13
|
from datetime import datetime
|
|
13
14
|
from datetime import time
|
|
14
15
|
from datetime import timedelta
|
|
@@ -112,6 +113,18 @@ class SleepingTimeRangeMixin:
|
|
|
112
113
|
await asyncio.sleep(delta)
|
|
113
114
|
|
|
114
115
|
|
|
116
|
+
class NoPrefetchingProducerMixin:
|
|
117
|
+
state: WorkerState
|
|
118
|
+
engine: AbstractEngine
|
|
119
|
+
sleeping_timerange: tuple[time, time]
|
|
120
|
+
|
|
121
|
+
async def before(self):
|
|
122
|
+
# noinspection PyUnresolvedReferences
|
|
123
|
+
await super().before()
|
|
124
|
+
self.state = WorkerState.WAITING
|
|
125
|
+
await self.engine.wait_worker_ready()
|
|
126
|
+
|
|
127
|
+
|
|
115
128
|
class SleepingCooldown(Flag):
|
|
116
129
|
IDLE = auto()
|
|
117
130
|
BUSY = auto()
|
|
@@ -141,7 +154,6 @@ class SleepingCooldownMixin:
|
|
|
141
154
|
await asyncio.sleep(sleep_seconds)
|
|
142
155
|
|
|
143
156
|
|
|
144
|
-
@dataclass(repr=False)
|
|
145
157
|
class AbstractProducer(AbstractWorker):
|
|
146
158
|
state = WorkerState.UNKNOWN
|
|
147
159
|
engine: AbstractEngine
|
|
@@ -157,6 +169,9 @@ class AbstractProducer(AbstractWorker):
|
|
|
157
169
|
Should raise error if there would be a spin-loop condition.
|
|
158
170
|
"""
|
|
159
171
|
|
|
172
|
+
def __init__(self, engine: AbstractEngine):
|
|
173
|
+
self.engine = engine
|
|
174
|
+
|
|
160
175
|
def __str__(self):
|
|
161
176
|
return f"{type(self).__name__}()"
|
|
162
177
|
|
|
@@ -186,7 +201,6 @@ class AbstractProducer(AbstractWorker):
|
|
|
186
201
|
await self.after(idle=not task)
|
|
187
202
|
|
|
188
203
|
|
|
189
|
-
@dataclass(repr=False)
|
|
190
204
|
class AbstractConsumer(AbstractWorker):
|
|
191
205
|
engine: AbstractEngine
|
|
192
206
|
|
|
@@ -199,6 +213,9 @@ class AbstractConsumer(AbstractWorker):
|
|
|
199
213
|
async def save_result(self, job: Job, /, **kwargs):
|
|
200
214
|
pass
|
|
201
215
|
|
|
216
|
+
def __init__(self, engine: AbstractEngine):
|
|
217
|
+
self.engine = engine
|
|
218
|
+
|
|
202
219
|
def __str__(self):
|
|
203
220
|
return f"{type(self).__name__}({id(self)})"
|
|
204
221
|
|
|
@@ -208,38 +225,39 @@ class AbstractConsumer(AbstractWorker):
|
|
|
208
225
|
self.state = WorkerState.BEFORE
|
|
209
226
|
await self.before()
|
|
210
227
|
self.state = WorkerState.READY
|
|
211
|
-
job: Job
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
228
|
+
job: Job | None
|
|
229
|
+
async with self.engine.consume() as job:
|
|
230
|
+
if job is None:
|
|
231
|
+
break
|
|
232
|
+
job.started.set_result(True)
|
|
233
|
+
logger.info("%s.run() working on: %s", self, job)
|
|
234
|
+
self.state = WorkerState.WORKING
|
|
235
|
+
logger.info("%s.run() - performing...", self)
|
|
236
|
+
try:
|
|
237
|
+
fields = await self.perform_work(job)
|
|
238
|
+
except Exception as exc:
|
|
239
|
+
self.state = WorkerState.SAVING
|
|
240
|
+
logger.error("%s.perform_work(%s) failed: %r", self, job, exc)
|
|
241
|
+
result = await self.save_result(
|
|
242
|
+
job,
|
|
243
|
+
result_type=self.result_type_enum.ERROR,
|
|
244
|
+
result_details=f"{exc!r}\n{traceback.format_exc()}",
|
|
245
|
+
)
|
|
246
|
+
idle = True
|
|
247
|
+
else:
|
|
248
|
+
self.state = WorkerState.SAVING
|
|
249
|
+
result = await self.save_result(
|
|
250
|
+
job,
|
|
251
|
+
result_type=self.result_type_enum.SUCCESS if fields else self.result_type_enum.ABSENT,
|
|
252
|
+
result_details=None if fields else repr(fields),
|
|
253
|
+
**fields or {},
|
|
254
|
+
)
|
|
255
|
+
idle = False
|
|
256
|
+
if job.done.cancelled():
|
|
257
|
+
logger.warning("%s.run() - %s is cancelled.", self, job)
|
|
258
|
+
else:
|
|
259
|
+
job.done.set_result(result)
|
|
260
|
+
|
|
243
261
|
if self.shutdown_requested:
|
|
244
262
|
continue
|
|
245
263
|
self.state = WorkerState.AFTER
|
|
@@ -250,21 +268,21 @@ class AbstractConsumer(AbstractWorker):
|
|
|
250
268
|
pass
|
|
251
269
|
|
|
252
270
|
|
|
253
|
-
@dataclass
|
|
254
271
|
class AbstractEngine(ABC):
|
|
255
272
|
workers: list[AbstractWorker]
|
|
256
|
-
queue: Queue
|
|
273
|
+
queue: Queue = None
|
|
274
|
+
queue_maxsize: int
|
|
257
275
|
shutdown_signal = signal.SIGINT
|
|
258
276
|
shutdown_requested = False
|
|
259
277
|
shutdown_task = None
|
|
260
278
|
|
|
261
279
|
def __init__(self):
|
|
262
280
|
self.workers = []
|
|
263
|
-
self.
|
|
264
|
-
self.
|
|
281
|
+
self.queue_awaited = Event()
|
|
282
|
+
self.queue_maxsize = 0
|
|
265
283
|
|
|
266
284
|
def __str__(self):
|
|
267
|
-
return f"{type(self).__name__}({len(self.workers)}w/{self.queue.qsize()}q)"
|
|
285
|
+
return f"{type(self).__name__}({len(self.workers)}w/{self.queue.qsize() if self.queue else '-'}q)"
|
|
268
286
|
|
|
269
287
|
def is_work_pending(self):
|
|
270
288
|
if any(worker for worker in self.workers if worker.state == WorkerState.WORKING):
|
|
@@ -273,26 +291,31 @@ class AbstractEngine(ABC):
|
|
|
273
291
|
return True
|
|
274
292
|
return not self.shutdown_requested
|
|
275
293
|
|
|
276
|
-
async def push(self, job: Job) -> None:
|
|
294
|
+
async def push(self, job: Job | None) -> None:
|
|
277
295
|
logger.info("%s.push(%s)", self, job)
|
|
278
|
-
await self.semaphore.acquire()
|
|
279
296
|
await self.queue.put(job)
|
|
280
297
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
298
|
+
@asynccontextmanager
|
|
299
|
+
async def consume(self) -> AsyncIterator[Job | None]:
|
|
300
|
+
try:
|
|
301
|
+
self.queue_awaited.set()
|
|
302
|
+
yield await self.queue.get()
|
|
303
|
+
finally:
|
|
304
|
+
self.queue.task_done()
|
|
305
|
+
|
|
306
|
+
async def wait_worker_ready(self):
|
|
307
|
+
await self.queue_awaited.wait()
|
|
308
|
+
self.queue_awaited.clear()
|
|
309
|
+
|
|
310
|
+
def add_worker(self, worker: AbstractWorker):
|
|
311
|
+
if self.queue is not None:
|
|
312
|
+
raise RuntimeError(f"Engine {self} is already started!")
|
|
313
|
+
if isinstance(worker, AbstractConsumer):
|
|
314
|
+
self.queue_maxsize += 1
|
|
315
|
+
self.workers.append(worker)
|
|
294
316
|
|
|
295
317
|
async def start(self):
|
|
318
|
+
self.queue = Queue(maxsize=self.queue_maxsize)
|
|
296
319
|
signal.signal(self.shutdown_signal, self.shutdown_handler)
|
|
297
320
|
|
|
298
321
|
def shutdown_handler(self, sig, frame):
|
|
@@ -314,20 +337,20 @@ class AbstractEngine(ABC):
|
|
|
314
337
|
for worker in self.workers:
|
|
315
338
|
worker.shutdown_requested = True
|
|
316
339
|
if isinstance(worker, AbstractConsumer):
|
|
317
|
-
self.
|
|
340
|
+
await self.push(None)
|
|
318
341
|
else:
|
|
319
342
|
while self.queue.qsize() > 0:
|
|
320
343
|
item = self.queue.get_nowait()
|
|
321
344
|
if item is not None:
|
|
322
|
-
logger.critical("%s unprocessed queue item: %r", item)
|
|
345
|
+
logger.critical("%s unprocessed queue item: %r", self, item)
|
|
323
346
|
for worker in self.workers:
|
|
324
347
|
worker.runner.cancel()
|
|
325
348
|
await asyncio.gather(*[worker.runner for worker in self.workers], return_exceptions=True)
|
|
326
349
|
self.workers.clear()
|
|
327
350
|
logger.info("%s shutdown complete.", self)
|
|
328
351
|
|
|
329
|
-
def report(self, inspect: defaultdict[str,
|
|
330
|
-
inspect["QSIZE"] = self.queue.qsize()
|
|
352
|
+
def report(self, inspect: defaultdict[str, object]):
|
|
353
|
+
inspect["QSIZE"] = "UNSTARTED" if self.queue is None else self.queue.qsize()
|
|
331
354
|
|
|
332
355
|
def inspect(self) -> dict[str, dict[str, int]]:
|
|
333
356
|
result = defaultdict(partial(defaultdict, int))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csu
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Clean Slate Utils - bunch of utility code, mostly Django/DRF specific.
|
|
5
5
|
Author-email: Ionel Cristian Mărieș <contact@ionelmc.ro>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -77,9 +77,9 @@ Overview
|
|
|
77
77
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
78
78
|
:alt: Supported implementations
|
|
79
79
|
:target: https://pypi.org/project/csu
|
|
80
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.0.
|
|
80
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.1.0.svg
|
|
81
81
|
:alt: Commits since latest release
|
|
82
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.0
|
|
82
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.1.0...main
|
|
83
83
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
84
84
|
:alt: Scrutinizer Status
|
|
85
85
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -44,7 +44,10 @@ class ExampleResultType(StrEnum):
|
|
|
44
44
|
ABSENT = "ABSENT"
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
class ExampleProducer(
|
|
47
|
+
class ExampleProducer(
|
|
48
|
+
# NoPrefetchingProducerMixin,
|
|
49
|
+
AbstractProducer,
|
|
50
|
+
):
|
|
48
51
|
engine: ExampleEngine
|
|
49
52
|
job_class = ExampleJob
|
|
50
53
|
counter = 0
|
|
@@ -75,17 +78,18 @@ class ExampleEngine(AbstractEngine):
|
|
|
75
78
|
queue_maxsize = WORKERS
|
|
76
79
|
|
|
77
80
|
async def start(self):
|
|
78
|
-
await super().start()
|
|
79
81
|
logger.info("Starting workers...")
|
|
80
82
|
|
|
81
83
|
for _ in range(WORKERS):
|
|
82
84
|
consumer = ExampleConsumer(engine=self)
|
|
83
85
|
consumer.start()
|
|
84
|
-
self.
|
|
86
|
+
self.add_worker(consumer)
|
|
85
87
|
|
|
86
88
|
producer = ExampleProducer(engine=self)
|
|
87
89
|
producer.start()
|
|
88
|
-
self.
|
|
90
|
+
self.add_worker(producer)
|
|
91
|
+
|
|
92
|
+
await super().start()
|
|
89
93
|
|
|
90
94
|
while self.is_work_pending():
|
|
91
95
|
await asyncio.sleep(1)
|
|
@@ -43,7 +43,8 @@ class Engine(AbstractEngine):
|
|
|
43
43
|
async def start(self):
|
|
44
44
|
worker = Consumer(engine=self)
|
|
45
45
|
worker.start()
|
|
46
|
-
self.
|
|
46
|
+
self.add_worker(worker)
|
|
47
|
+
await super().start()
|
|
47
48
|
logging.info("engine started")
|
|
48
49
|
|
|
49
50
|
|
|
@@ -52,9 +53,9 @@ async def test_cancel():
|
|
|
52
53
|
engine = Engine()
|
|
53
54
|
await engine.start()
|
|
54
55
|
job1 = SleepyJob(0.2)
|
|
55
|
-
engine.
|
|
56
|
+
await engine.push(job1)
|
|
56
57
|
job2 = SleepyJob(0)
|
|
57
|
-
engine.
|
|
58
|
+
await engine.push(job2)
|
|
58
59
|
await asyncio.sleep(0.1)
|
|
59
60
|
with pytest.raises(TimeoutError):
|
|
60
61
|
await asyncio.wait_for(job1.done, 0.1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csu-2.0.7 → csu-2.1.0}/LICENSE
RENAMED
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{csu-2.0.7 → csu-2.1.0}/tox.ini
RENAMED
|
File without changes
|