Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #959 from procrastinate-org/django-app-proxy
- Loading branch information
Showing
4 changed files
with
83 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
from __future__ import annotations | ||
|
||
import functools | ||
from typing import NoReturn, cast | ||
|
||
from procrastinate import app as app_module | ||
from procrastinate import blueprints | ||
|
||
from . import exceptions | ||
|
||
|
||
def _not_ready(_method: str, *args, **kwargs) -> NoReturn: | ||
base_text = ( | ||
f"Cannot call procrastinate.contrib.app.{_method}() before " | ||
"the 'procrastinate.contrib.django' django app is ready." | ||
) | ||
details = ( | ||
"If this message appears at import time, the app is not ready yet: " | ||
"move the corresponding code in an app's `AppConfig.ready()` method. " | ||
"If this message appears in an app's `AppConfig.ready()` method, " | ||
'make sure `"procrastinate.contrib.django"` appears before ' | ||
"that app when ordering apps in the Django setting `INSTALLED_APPS`. " | ||
"Alternatively, use the Django setting " | ||
"PROCRASTINATE_ON_APP_READY (see the doc)." | ||
) | ||
raise exceptions.DjangoNotReady(base_text + "\n\n" + details) | ||
|
||
|
||
class FutureApp(blueprints.Blueprint): | ||
_shadowed_methods = frozenset( | ||
[ | ||
"__enter__", | ||
"__exit__", | ||
"_register_builtin_tasks", | ||
"_worker", | ||
"check_connection_async", | ||
"check_connection", | ||
"close_async", | ||
"close", | ||
"configure_task", | ||
"open_async", | ||
"open", | ||
"perform_import_paths", | ||
"run_worker_async", | ||
"run_worker", | ||
"schema_manager", | ||
"with_connector", | ||
"will_configure_task", | ||
] | ||
) | ||
for method in _shadowed_methods: | ||
locals()[method] = functools.partial(_not_ready, method) | ||
|
||
|
||
class ProxyApp: | ||
def __repr__(self) -> str: | ||
return repr(_current_app) | ||
|
||
def __getattr__(self, name): | ||
return getattr(_current_app, name) | ||
|
||
|
||
# Users may import the app before it's ready, so we're defining a proxy | ||
# that references either the pre-app or the real app. | ||
app: app_module.App = cast(app_module.App, ProxyApp()) | ||
|
||
# Before the Django app is ready, we're defining the app as a blueprint so | ||
# that tasks can be registered. The real app will be initialized in the | ||
# ProcrastinateConfig.ready() method. | ||
# This blueprint has special implementations for App methods so that if | ||
# users try to use the app before it's ready, they get a helpful error message. | ||
_current_app: app_module.App = cast(app_module.App, FutureApp()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters