django-queuebie 0.2.0__tar.gz → 0.3.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.
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/CHANGES.md +3 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/PKG-INFO +1 -1
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/__init__.py +1 -1
- django_queuebie-0.3.0/queuebie/runner.py +63 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/handlers/commands/testapp.py +13 -5
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/messages/commands/my_commands.py +10 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_registry.py +1 -1
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_runner.py +11 -11
- django_queuebie-0.2.0/queuebie/runner.py +0 -64
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/.ambient-package-update/metadata.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/.ambient-package-update/templates/snippets/content.tpl +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/.ambient-package-update/templates/snippets/tagline.tpl +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/.editorconfig +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/.github/workflows/ci.yml +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/.gitignore +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/.pre-commit-config.yaml +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/.readthedocs.yaml +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/LICENSE +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/LICENSE.md +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/MANIFEST.in +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/README.md +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/SECURITY.md +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/Makefile +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/conf.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/features/changelog.rst +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/features/getting-started.md +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/features/introduction.md +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/features/motivation.md +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/features/settings.md +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/features/setup.md +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/index.rst +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/docs/make.bat +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/manage.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/pyproject.toml +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/apps.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/database_blocker.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/exceptions.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/logger.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/management/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/management/commands/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/management/commands/clear_queuebie_registry.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/messages.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/registry.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/settings.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/queuebie/utils.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/scripts/unix/install_requirements.sh +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/scripts/unix/publish_to_pypi.sh +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/scripts/windows/install_requirements.ps1 +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/scripts/windows/publish_to_pypi.ps1 +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/settings.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/handlers/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/handlers/commands/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/handlers/events/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/handlers/events/testapp.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/messages/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/messages/commands/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/messages/commands/other_commands.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/messages/events/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/messages/events/my_events.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/testapp/urls.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/helpers/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/helpers/commands.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/helpers/events.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/management_commands/__init__.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/management_commands/test_clear_queuebie_registry.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_apps.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_database_blocker.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_exceptions.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_logger.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_messages.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_settings.py +0 -0
- {django_queuebie-0.2.0 → django_queuebie-0.3.0}/tests/test_utils.py +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from contextlib import nullcontext
|
|
3
|
+
|
|
4
|
+
from django.db import transaction
|
|
5
|
+
|
|
6
|
+
from queuebie import message_registry
|
|
7
|
+
from queuebie.database_blocker import BlockDatabaseAccess
|
|
8
|
+
from queuebie.exceptions import InvalidMessageTypeError
|
|
9
|
+
from queuebie.logger import get_logger
|
|
10
|
+
from queuebie.messages import Command, Event, Message
|
|
11
|
+
from queuebie.settings import get_queuebie_strict_mode
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def handle_message(messages: Message | list[Message]) -> None:
|
|
15
|
+
queue: list[Message] = messages if isinstance(messages, list) else [messages]
|
|
16
|
+
|
|
17
|
+
for message in queue:
|
|
18
|
+
if not isinstance(message, (Command, Event)):
|
|
19
|
+
raise InvalidMessageTypeError(class_name=message.__class__.__name__)
|
|
20
|
+
|
|
21
|
+
# Run auto-registry
|
|
22
|
+
message_registry.autodiscover()
|
|
23
|
+
|
|
24
|
+
with transaction.atomic():
|
|
25
|
+
while queue:
|
|
26
|
+
message = queue.pop(0)
|
|
27
|
+
if isinstance(message, Command):
|
|
28
|
+
handler_list = message_registry.command_dict.get(message.module_path(), [])
|
|
29
|
+
block_db_access = False
|
|
30
|
+
else:
|
|
31
|
+
handler_list = message_registry.event_dict.get(message.module_path(), [])
|
|
32
|
+
block_db_access = True if get_queuebie_strict_mode() else False
|
|
33
|
+
|
|
34
|
+
new_messages = _process_message(handler_list=handler_list, message=message, block_db_access=block_db_access)
|
|
35
|
+
queue.extend(new_messages)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _process_message(*, handler_list: list, message: [Command, Event], block_db_access: bool) -> list[Message]:
|
|
39
|
+
"""
|
|
40
|
+
Handler to process messages of type "Command"
|
|
41
|
+
"""
|
|
42
|
+
logger = get_logger()
|
|
43
|
+
messages = []
|
|
44
|
+
|
|
45
|
+
for handler in handler_list:
|
|
46
|
+
try:
|
|
47
|
+
logger.debug(
|
|
48
|
+
f"Handling command '{message.module_path()}' ({message.uuid}) with handler '{handler['name']}'."
|
|
49
|
+
)
|
|
50
|
+
module = importlib.import_module(handler["module"])
|
|
51
|
+
handler_function = getattr(module, handler["name"])
|
|
52
|
+
with BlockDatabaseAccess() if block_db_access else nullcontext():
|
|
53
|
+
handler_messages = handler_function(context=message) or []
|
|
54
|
+
handler_messages = handler_messages if isinstance(handler_messages, list) else [handler_messages]
|
|
55
|
+
if len(handler_messages) > 0:
|
|
56
|
+
messages.extend(handler_messages)
|
|
57
|
+
uuid_list = [f"{m!s}" for m in handler_messages]
|
|
58
|
+
logger.debug(f"New messages: {uuid_list!s}")
|
|
59
|
+
except Exception as e:
|
|
60
|
+
logger.debug(f"Exception handling command {message.module_path()}: {e!s}")
|
|
61
|
+
raise e from e
|
|
62
|
+
|
|
63
|
+
return messages
|
|
@@ -5,7 +5,13 @@ from django.contrib.auth.models import User
|
|
|
5
5
|
from queuebie import message_registry
|
|
6
6
|
from queuebie.logger import get_logger
|
|
7
7
|
from queuebie.messages import Event
|
|
8
|
-
from testapp.messages.commands.my_commands import
|
|
8
|
+
from testapp.messages.commands.my_commands import (
|
|
9
|
+
CreateUser,
|
|
10
|
+
CriticalCommand,
|
|
11
|
+
DoSomething,
|
|
12
|
+
PersistSomething,
|
|
13
|
+
RaiseRuntimeError,
|
|
14
|
+
)
|
|
9
15
|
from testapp.messages.events.my_events import SomethingHappened, SomethingHappenedThatWantsToBePersisted
|
|
10
16
|
|
|
11
17
|
|
|
@@ -29,9 +35,11 @@ def handle_critical_command(*, context: CriticalCommand) -> None:
|
|
|
29
35
|
raise RuntimeError("Handler is broken.") # noqa: TRY003
|
|
30
36
|
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
@message_registry.register_command(command=CreateUser)
|
|
39
|
+
def create_user(context: CreateUser):
|
|
40
|
+
User.objects.create_user(username=context.username)
|
|
34
41
|
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
@message_registry.register_command(command=RaiseRuntimeError)
|
|
44
|
+
def raise_exception(context: RaiseRuntimeError):
|
|
45
|
+
raise RuntimeError(context.error_msg)
|
|
@@ -21,3 +21,13 @@ class SameNameCommand(Command):
|
|
|
21
21
|
@dataclass(kw_only=True)
|
|
22
22
|
class PersistSomething(Command):
|
|
23
23
|
any_var: str
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(kw_only=True)
|
|
27
|
+
class CreateUser(Command):
|
|
28
|
+
username: str
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(kw_only=True)
|
|
32
|
+
class RaiseRuntimeError(Command):
|
|
33
|
+
error_msg: str
|
|
@@ -124,7 +124,7 @@ def test_message_autodiscover_regular():
|
|
|
124
124
|
message_registry.autodiscover()
|
|
125
125
|
|
|
126
126
|
# Assert one command registered
|
|
127
|
-
assert len(message_registry.command_dict) ==
|
|
127
|
+
assert len(message_registry.command_dict) == 5 # noqa: PLR2004
|
|
128
128
|
assert DoSomething.module_path() in message_registry.command_dict.keys()
|
|
129
129
|
assert CriticalCommand.module_path() in message_registry.command_dict.keys()
|
|
130
130
|
|
|
@@ -8,8 +8,15 @@ from django.test import override_settings
|
|
|
8
8
|
from queuebie import MessageRegistry
|
|
9
9
|
from queuebie.database_blocker import DatabaseAccessDeniedError
|
|
10
10
|
from queuebie.exceptions import InvalidMessageTypeError
|
|
11
|
-
from queuebie.runner import
|
|
12
|
-
from testapp.messages.commands.my_commands import
|
|
11
|
+
from queuebie.runner import handle_message
|
|
12
|
+
from testapp.messages.commands.my_commands import (
|
|
13
|
+
CreateUser,
|
|
14
|
+
CriticalCommand,
|
|
15
|
+
DoSomething,
|
|
16
|
+
PersistSomething,
|
|
17
|
+
RaiseRuntimeError,
|
|
18
|
+
SameNameCommand,
|
|
19
|
+
)
|
|
13
20
|
from testapp.messages.events.my_events import (
|
|
14
21
|
SomethingHappened,
|
|
15
22
|
SomethingHappenedThatWantsToBePersistedViaEvent,
|
|
@@ -125,15 +132,8 @@ def test_handle_message_other_command_with_same_name(mocked_handle_command, *arg
|
|
|
125
132
|
|
|
126
133
|
@pytest.mark.django_db
|
|
127
134
|
@mock.patch("queuebie.registry.get_queuebie_strict_mode", return_value=False)
|
|
128
|
-
def
|
|
129
|
-
handler_list = [
|
|
130
|
-
{"module": "testapp.handlers.commands.testapp", "name": "create_user"},
|
|
131
|
-
{"module": "testapp.handlers.commands.testapp", "name": "raise_exception"},
|
|
132
|
-
]
|
|
133
|
-
|
|
134
|
-
message = DoSomething(my_var=1)
|
|
135
|
-
|
|
135
|
+
def test_handle_message_atomic_works(*args):
|
|
136
136
|
with pytest.raises(RuntimeError, match="Something is broken."):
|
|
137
|
-
|
|
137
|
+
handle_message([CreateUser(username="username"), RaiseRuntimeError(error_msg="Something is broken.")])
|
|
138
138
|
|
|
139
139
|
assert User.objects.filter(username="username").exists() is False
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import importlib
|
|
2
|
-
from contextlib import nullcontext
|
|
3
|
-
|
|
4
|
-
from django.db import transaction
|
|
5
|
-
|
|
6
|
-
from queuebie import message_registry
|
|
7
|
-
from queuebie.database_blocker import BlockDatabaseAccess
|
|
8
|
-
from queuebie.exceptions import InvalidMessageTypeError
|
|
9
|
-
from queuebie.logger import get_logger
|
|
10
|
-
from queuebie.messages import Command, Event, Message
|
|
11
|
-
from queuebie.settings import get_queuebie_strict_mode
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def handle_message(messages: Message | list[Message]) -> None:
|
|
15
|
-
queue: list[Message] = messages if isinstance(messages, list) else [messages]
|
|
16
|
-
|
|
17
|
-
for message in queue:
|
|
18
|
-
if not isinstance(message, (Command, Event)):
|
|
19
|
-
raise InvalidMessageTypeError(class_name=message.__class__.__name__)
|
|
20
|
-
|
|
21
|
-
# Run auto-registry
|
|
22
|
-
message_registry.autodiscover()
|
|
23
|
-
|
|
24
|
-
while queue:
|
|
25
|
-
message = queue.pop(0)
|
|
26
|
-
if isinstance(message, Command):
|
|
27
|
-
handler_list = message_registry.command_dict.get(message.module_path(), [])
|
|
28
|
-
block_db_access = False
|
|
29
|
-
else:
|
|
30
|
-
handler_list = message_registry.event_dict.get(message.module_path(), [])
|
|
31
|
-
block_db_access = True if get_queuebie_strict_mode() else False
|
|
32
|
-
|
|
33
|
-
new_messages = _process_message(handler_list=handler_list, message=message, block_db_access=block_db_access)
|
|
34
|
-
queue.extend(new_messages)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def _process_message(*, handler_list: list, message: [Command, Event], block_db_access: bool) -> list[Message]:
|
|
38
|
-
"""
|
|
39
|
-
Handler to process messages of type "Command"
|
|
40
|
-
"""
|
|
41
|
-
logger = get_logger()
|
|
42
|
-
messages = []
|
|
43
|
-
|
|
44
|
-
# TODO: should the whole chain be atomic and not just the handler?
|
|
45
|
-
with transaction.atomic():
|
|
46
|
-
for handler in handler_list:
|
|
47
|
-
try:
|
|
48
|
-
logger.debug(
|
|
49
|
-
f"Handling command '{message.module_path()}' ({message.uuid}) with handler '{handler['name']}'."
|
|
50
|
-
)
|
|
51
|
-
module = importlib.import_module(handler["module"])
|
|
52
|
-
handler_function = getattr(module, handler["name"])
|
|
53
|
-
with BlockDatabaseAccess() if block_db_access else nullcontext():
|
|
54
|
-
handler_messages = handler_function(context=message) or []
|
|
55
|
-
handler_messages = handler_messages if isinstance(handler_messages, list) else [handler_messages]
|
|
56
|
-
if len(handler_messages) > 0:
|
|
57
|
-
messages.extend(handler_messages)
|
|
58
|
-
uuid_list = [f"{m!s}" for m in handler_messages]
|
|
59
|
-
logger.debug(f"New messages: {uuid_list!s}")
|
|
60
|
-
except Exception as e:
|
|
61
|
-
logger.debug(f"Exception handling command {message.module_path()}: {e!s}")
|
|
62
|
-
raise e from e
|
|
63
|
-
|
|
64
|
-
return messages
|
|
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
|