plain 0.39.0__tar.gz → 0.39.1__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.
- {plain-0.39.0 → plain-0.39.1}/PKG-INFO +1 -1
- plain-0.39.1/plain/chores/README.md +64 -0
- {plain-0.39.0 → plain-0.39.1}/pyproject.toml +1 -1
- {plain-0.39.0 → plain-0.39.1}/.gitignore +0 -0
- {plain-0.39.0 → plain-0.39.1}/LICENSE +0 -0
- {plain-0.39.0 → plain-0.39.1}/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/__main__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/assets/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/assets/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/assets/compile.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/assets/finders.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/assets/fingerprints.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/assets/urls.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/assets/views.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/chores/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/chores/registry.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/build.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/chores.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/core.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/docs.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/formatting.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/preflight.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/print.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/registry.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/scaffold.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/settings.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/shell.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/startup.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/urls.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/cli/utils.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/csrf/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/csrf/middleware.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/csrf/views.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/debug.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/exceptions.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/forms/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/forms/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/forms/boundfield.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/forms/exceptions.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/forms/fields.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/forms/forms.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/http/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/http/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/http/cookie.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/http/multipartparser.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/http/request.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/http/response.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/files/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/files/base.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/files/locks.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/files/move.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/files/temp.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/files/uploadedfile.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/files/uploadhandler.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/files/utils.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/handlers/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/handlers/base.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/handlers/exception.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/handlers/wsgi.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/middleware/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/middleware/headers.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/middleware/https.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/internal/middleware/slash.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/json.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/logs/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/logs/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/logs/configure.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/logs/loggers.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/logs/utils.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/packages/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/packages/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/packages/config.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/packages/registry.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/paginator.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/preflight/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/preflight/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/preflight/files.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/preflight/messages.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/preflight/registry.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/preflight/security.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/preflight/urls.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/runtime/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/runtime/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/runtime/global_settings.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/runtime/user_settings.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/signals/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/signals/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/signals/dispatch/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/signals/dispatch/dispatcher.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/signals/dispatch/license.txt +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/signing.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/templates/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/templates/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/templates/core.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/templates/jinja/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/templates/jinja/environments.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/templates/jinja/extensions.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/templates/jinja/filters.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/templates/jinja/globals.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/test/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/test/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/test/client.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/test/encoding.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/test/exceptions.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/urls/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/urls/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/urls/converters.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/urls/exceptions.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/urls/patterns.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/urls/resolvers.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/urls/routers.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/urls/utils.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/cache.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/connection.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/crypto.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/datastructures.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/dateparse.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/deconstruct.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/decorators.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/duration.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/encoding.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/functional.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/hashable.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/html.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/http.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/inspect.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/ipv6.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/itercompat.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/module_loading.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/regex_helper.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/safestring.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/text.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/timesince.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/timezone.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/utils/tree.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/validators.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/README.md +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/base.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/csrf.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/errors.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/exceptions.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/forms.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/objects.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/redirect.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/views/templates.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/plain/wsgi.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/.bolt/assets_collected/assets.json +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/.gitignore +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/app/.gitignore +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/app/settings.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/app/test/__init__.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/app/test/default_settings.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/app/urls.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/conftest.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/test_cli.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/test_runtime.py +0 -0
- {plain-0.39.0 → plain-0.39.1}/tests/test_wsgi.py +0 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
# Chores
|
2
|
+
|
3
|
+
**Routine maintenance tasks.**
|
4
|
+
|
5
|
+
Chores are registered functions that can be run at any time to keep an app in a desirable state.
|
6
|
+
|
7
|
+

|
8
|
+
|
9
|
+
A good example is the clearing of expired sessions in [`plain.sessions`](/plain-sessions/plain/sessions/chores.py) — since the sessions are stored in the database, occasionally you will want to delete any sessions that are expired and no longer in use.
|
10
|
+
|
11
|
+
```python
|
12
|
+
# plain/sessions/chores.py
|
13
|
+
from plain.chores import register_chore
|
14
|
+
from plain.utils import timezone
|
15
|
+
|
16
|
+
from .models import Session
|
17
|
+
|
18
|
+
|
19
|
+
@register_chore("sessions")
|
20
|
+
def clear_expired():
|
21
|
+
"""
|
22
|
+
Delete sessions that have expired.
|
23
|
+
"""
|
24
|
+
result = Session.objects.filter(expires_at__lt=timezone.now()).delete()
|
25
|
+
return f"{result[0]} expired sessions deleted"
|
26
|
+
```
|
27
|
+
|
28
|
+
## Running chores
|
29
|
+
|
30
|
+
The `plain chores run` command will execute all registered chores. When and how to run this is up to the user, but running them hourly is a safe assumption in most cases (assuming you have any chores — `plain chores list`).
|
31
|
+
|
32
|
+
There are several ways you can run chores depending on your needs:
|
33
|
+
|
34
|
+
- on deploy
|
35
|
+
- as a [`plain.worker` scheduled job](/plain-worker/plain/worker/README.md#scheduled-jobs)
|
36
|
+
- as a cron job (using any cron-like system where your app is hosted)
|
37
|
+
- manually as needed
|
38
|
+
|
39
|
+
## Writing chores
|
40
|
+
|
41
|
+
A chore is a function decorated with `@register_chore(chore_group_name)`. It can write a description as a docstring, and it can return a value that will be printed when the chore is run.
|
42
|
+
|
43
|
+
```python
|
44
|
+
# app/chores.py
|
45
|
+
from plain.chores import register_chore
|
46
|
+
|
47
|
+
|
48
|
+
@register_chore("app")
|
49
|
+
def chore_name():
|
50
|
+
"""
|
51
|
+
A chore description can go here
|
52
|
+
"""
|
53
|
+
# Do a thing!
|
54
|
+
return "We did it!"
|
55
|
+
```
|
56
|
+
|
57
|
+
A good chore is:
|
58
|
+
|
59
|
+
- Fast
|
60
|
+
- Idempotent
|
61
|
+
- Recurring
|
62
|
+
- Stateless
|
63
|
+
|
64
|
+
If chores are written in `app/chores.py` or `{pkg}/chores.py`, then they will be imported automatically and registered.
|
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
|
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
|