Configuration¶
# settings.py: complete development example; does not start services.
from pathlib import Path
from django.http import HttpRequest
BASE_DIR = Path(__file__).resolve().parent.parent
def can_edit_hyperview(request: HttpRequest) -> bool:
return request.user.is_superuser is True
HYPERVIEW = {
"TEMPLATE_DIRS": [BASE_DIR / "hyperview"], # Create this directory in your project.
"SOURCES": [
{"BACKEND": "dj_hyperview.sources.FileSystemSource", "OPTIONS": {}},
],
"CACHE": { # Optional: omit this section or use {} to disable caching.
"ALIAS": "default", # Must exist in CACHES and use a compatible backend.
"NAMESPACE": "my-app-templates-dev",
"TTL": 300,
"NEGATIVE_TTL": 15,
"FAILURE_MODE": "bypass",
},
"VALIDATION": {
"MAX_BYTES": 1_000_000,
"MAX_DEPTH": 64,
"MAX_NODES": 20_000,
},
"ADMIN": {
"EDITOR": False, # Does not require the optional editor extra.
"PERMISSION": can_edit_hyperview,
},
"EXTRA_SCHEMAS": [], # No additional XSD files in this example.
"SCHEMA_EXTENSIONS": {
"BEHAVIORS": {
"show-snackbar": {
"ATTRIBUTES": {
"message": {"TYPE": "string", "REQUIRED": True},
"tone": {"TYPE": "string", "ENUM": ["success", "error"]},
},
},
},
"ELEMENT_ATTRIBUTES": {
"image": {
"variant": {"TYPE": "string", "ENUM": ["face", "fingerprint"]},
},
},
},
"REALTIME": { # Optional: omit this section or use None to disable SSE.
"REDIS_URL": "redis://127.0.0.1:6379/0", # Development Redis, if you use it.
"NAMESPACE": "my-app-dev",
},
}
This example shows every public section, not every possible combination. Adjust paths and names to your project. Before using it:
- Install the package and add
dj_hyperviewtoINSTALLED_APPS, as described in installation. Create your project'shyperview/directory. - Keep a compatible
defaultalias inCACHES. Django defaults to LocMemCache when you do not configure it: suitable for this single-process example, not for coherence across workers. Do not overwrite deployment caches when copying. EXTRA_SCHEMAS=[]needs no additional files. Theshow-snackbarandimage.variantdeclarations only validate XML; implement their mobile behavior before using them. They do not install features into Hyperview.REALTIMEdoes not connect to Redis when settings are read. Using the transport requires[realtime], a reachable Redis service and the ASGI/client integration in the SSE guide. This example starts no services.- Run
python manage.py check. Createhyperview/screens/home.xmlbefore trying the resolver below. Later snippets update one section, keeping the rest ofHYPERVIEWintact unless explicitly stated otherwise.
Resolve a canonical relative POSIX name through the public API:
from dj_hyperview import TemplateResolver
template = TemplateResolver.from_settings().resolve("screens/home.xml")
Sources are queried in order and the first hit wins. Absolute paths, traversal,
backslashes, empty path segments, control characters, invisible format
characters, line and paragraph separators, and surrogates are rejected. Omitting
CACHE keeps caching disabled and avoids cache backend initialization.
DummyCache is not a valid Hyperview cache backend because it cannot preserve
generation state. To disable caching, omit CACHE instead of selecting a dummy
cache alias. The system check only warns (dj_hyperview.W004), but the effect at
runtime is not mild: with CACHE.FAILURE_MODE set to "raise" every lookup
raises SourceUnavailable, and with "bypass" every lookup logs a
template_cache_bypassed warning and reads from the sources.
FileBasedCache and its subclasses are rejected with dj_hyperview.E018, even
when CACHE.FAILURE_MODE is bypass: their non-atomic add() cannot protect
template generations. Select a backend with atomic add and coherent reads, or
omit CACHE. This is a configuration error, not a recoverable backend outage.
Settings reference¶
All keys are optional except the fields inside each configured source. Cache
defaults apply only when CACHE is a non-empty mapping; omitting it or using an
empty mapping disables Hyperview caching. REALTIME omitted or None is disabled;
an empty realtime mapping is an error, not another disabled form.
Every message that python manage.py check can report is listed in the
system check reference.
Unknown keys are rejected, not ignored. A key that HYPERVIEW, a SOURCES entry,
CACHE, VALIDATION or ADMIN does not define, such as MAX_BYTE, PERMISION
or a lowercase cache, produces dj_hyperview.E023 from python manage.py check
and HyperviewConfigurationError when settings are read. A typo therefore cannot
silently fall back to a default and weaken a limit, a cache policy or the Admin
permission. The error names the key and lists the valid ones. The removed keys
SCHEMA_PROFILE, VALIDATION.MODE and VALIDATION.SCHEMA keep their own errors
and are not reported twice.
| Setting | Type | Default | Meaning |
|---|---|---|---|
HYPERVIEW |
Mapping | {} |
Package configuration in Django settings. An absent or empty mapping configures no sources and no cache. |
TEMPLATE_DIRS |
List or tuple of strings or Path objects |
() |
Ordered project-owned roots inherited by FileSystemSource instances that do not override template_dirs. Missing roots emit an operational warning and are skipped at runtime. |
SOURCES |
Sequence of mappings | () |
Ordered source definitions. The first source that resolves a canonical template name wins. An empty sequence resolves no templates. |
SOURCES[].BACKEND |
Dotted import path | Required | Importable source class for one entry. Built-in paths are shown below. |
SOURCES[].OPTIONS |
Mapping | {} |
Keyword arguments passed to that source class constructor. Supported keys are backend-specific; entries the constructor does not accept, or required arguments it does not receive, produce dj_hyperview.E024. |
CACHE |
Mapping | Omitted (disabled) | Enables raw-source and source-miss caching when non-empty, for the sources that opt in (see cache consistency). It does not cache compiled templates; the loader keeps those in process (see template engine behavior). |
CACHE.ALIAS |
String | "default" |
Django cache alias with atomic add and coherent reads. DummyCache and FileBasedCache are unsupported. |
CACHE.NAMESPACE |
Non-empty string | "dj-hyperview" |
Prefix domain that isolates all Hyperview cache keys. Change it to abandon previously published cache state. |
CACHE.TTL |
Integer greater than or equal to 1 | 300 seconds | Lifetime of successful raw-template and resolved-source entries. Generation keys do not expire. |
CACHE.NEGATIVE_TTL |
Integer greater than or equal to 0 | 15 seconds | Lifetime of explicit source misses. Zero disables effective negative-entry retention. |
CACHE.FAILURE_MODE |
bypass or raise |
"bypass" |
bypass falls back to authoritative sources after ordinary cache failures; raise reports SourceUnavailable. Invalidation remains fail-closed in both modes. |
VALIDATION |
Mapping | {} |
Resource limits for mandatory source safety and automatic rendered validation. |
VALIDATION.MAX_BYTES |
Positive integer | 1,000,000 bytes | Maximum UTF-8 size accepted for raw source and the final rendered document. |
VALIDATION.MAX_DEPTH |
Positive integer | 64 levels | Maximum depth of the final parsed XML tree, with an absolute maximum of 256 imposed by the parser safety ceiling. A comment or processing instruction is a node one level below its parent, so it counts too. |
VALIDATION.MAX_NODES |
Positive integer | 20,000 nodes | Maximum number of nodes under and including the root element of the final parsed XML document: elements, comments and processing instructions. Text content is not a node, and a comment or processing instruction outside the root element is not counted, so only MAX_BYTES bounds those. |
ADMIN |
Mapping | {} |
Optional Django Admin enhancements. |
ADMIN.EDITOR |
Boolean | False |
Replace the database template textarea with the optional HXML-aware Ace editor with one conservative Format and Validate action. Requires the editor extra and django_ace in INSTALLED_APPS. |
ADMIN.PERMISSION |
Callable or dotted callable path | Superuser-only callback | Authoritative mutation policy for adding, changing, and deleting stored templates. The callable receives the current HttpRequest and must return the literal boolean True; exceptions and non-boolean results deny access. |
EXTRA_SCHEMAS |
List or tuple of strings or Path objects |
() |
Local XSD roots merged into the bundled Hyperview 0.111.0 registry and completion catalog. URLs are rejected. |
SCHEMA_EXTENSIONS |
Mapping | {} |
Typed app-owned behavior and element-attribute declarations; standard declarations cannot be replaced. |
REALTIME |
Exact mapping or None | None |
Optional SSE transport configuration. Does not create an endpoint, client or connection. |
REALTIME.REDIS_URL |
String | Required when enabled | Validated server-owned Redis URL; not a cache alias. Excluded from the normalized object's repr. |
REALTIME.NAMESPACE |
String | Required when enabled | App/environment domain: [a-z0-9][a-z0-9_-]{0,63}. |
Automatic Hyperview XSD 1.1 validation¶
The package always validates final rendered documents and fragments against one
corrected Hyperview 0.111.0 registry. Raw source remains context-free: safety and
Django compilation do not invent variables or render a scenario. Configuring
VALIDATION changes only MAX_BYTES, MAX_DEPTH, and MAX_NODES; it cannot
skip or replace standard validation. Separate fixed caps allow at most 128
attributes and 8 in-scope namespaces on one element, and 32 namespace
declarations, counting every rebinding, on the path from the root to one element;
exceeding any of them fails with the validation code max_attributes. They do not
replace these three limits as the bounds on the whole document: lower the three
settings for untrusted input, because validation cost grows with the nodes and
attributes of a document (see Security). Template source has one
more fixed limit, on the work that unclosed {{, {% and {# delimiters cost
Django's lexer; exceeding it fails with the code max_unclosed.
SCHEMA_PROFILE, VALIDATION.MODE, and VALIDATION.SCHEMA are removed settings.
Their presence produces a configuration error, including their former default
values. Delete them rather than replacing them with a new selector. Register
only application extensions when needed:
# First create this local schema using the custom-schemas guide.
HYPERVIEW["EXTRA_SCHEMAS"] = [
*HYPERVIEW["EXTRA_SCHEMAS"],
BASE_DIR / "schema" / "hypertodo.xsd",
]
Project schemas declare namespaced custom elements. To accept Hyperview elements
inside one, use xs:any with namespace="https://hyperview.org/hyperview", as the
custom schema guide does. An xs:import of that namespace
cannot supply its components: each extra schema is also compiled on its own,
without the Hyperview schema, so a ref or type that names one fails with
dj_hyperview.E012 (reason: schema_invalid). Includes, imports, and redefines
may reference only plain local files below their root schema's directory. Remote
references, traversal (any .. segment), percent-encoded locations, control or
other non-printable characters, the characters ?, # and :, backslash/URI
ambiguity, DTD/entities, and arbitrary xs:override are rejected.
Each extra schema may reference at most 256 distinct file paths, including its
root; cycles are visited once. Symlink escapes remain forbidden, also through the
dependencies of a schema file that is itself a symlink.
After every extra schema passes on its own, the system check compiles them all
together with the bundled Hyperview schema. Two schemas that declare the same
global name differently, or a schema that declares a Hyperview or alert name
differently from the bundled schemas, fail the check with dj_hyperview.E012
(reason: duplicate_schema_declaration) instead of failing the first request. A
registry that compiles cleanly is cached, so the first request does not compile it
again.
Validation, static Admin checks, and completion use one immutable registry
identity: the internal correction revision, normalized registrations, and complete
transitive dependency fingerprints (resolved paths, sizes and nanosecond mtimes).
References are rechecked before cache hits. Changed dependencies or HYPERVIEW
settings refresh all consumers without restarting Django.
The fixed trusted package overlay leaves upstream XSD artifacts unchanged.
get_hyperview_catalog() returns active catalog_format: 2 without public
profile metadata. The config-free get_hyperview_schema_path() and
build_hyperview_catalog() helpers still inspect the archived upstream 0.110.0
resources, not the
active corrected runtime registry.
Follow Add custom HXML elements for namespace registration and the custom component example. Standard validation does not require an additional install or callback.
Admin editor¶
The enhanced editor is deliberately separate from database storage:
# Add django_ace to your existing INSTALLED_APPS; retain other applications.
# Keep dj_hyperview.contrib.database if using database templates.
HYPERVIEW["ADMIN"] = {**HYPERVIEW["ADMIN"], "EDITOR": True}
Enabling the setting without the extra, or without django_ace in
INSTALLED_APPS, produces an actionable Django system-check error. When the
setting is false, the standard Django textarea remains unchanged.
Stored templates are executable Django template source, so mutations default to superusers even when a staff user holds the model's ordinary add, change, or delete permissions. A project can replace that policy with an inline callable:
HYPERVIEW["ADMIN"] = {
**HYPERVIEW["ADMIN"],
"PERMISSION": lambda request: request.user.is_superuser,
}
For reusable and testable production configuration, create this module first, then reference its dotted path:
# sample_app/permissions.py
from django.http import HttpRequest
def can_edit_hyperview(request: HttpRequest) -> bool:
"""Return whether the current user may mutate stored HXML templates."""
return request.user.has_perm("dj_hyperview_database.change_hyperviewtemplate")
HYPERVIEW["ADMIN"] = {
**HYPERVIEW["ADMIN"],
"PERMISSION": "sample_app.permissions.can_edit_hyperview",
}
The callback is authoritative for all three mutation operations rather than an additional Django model-permission check. Admin-site access still requires an active staff user. Standard model view permission continues to govern read-only access. Missing paths, non-callables, and callbacks that cannot accept one request fail Django system checks; runtime exceptions and non-boolean return values fail closed.
Source backend options¶
OPTIONS is an optional mapping. The resolver passes its entries to the
configured backend constructor as keyword arguments. The bundled backends
support the following options:
| Backend | Option | Default | Meaning |
|---|---|---|---|
FileSystemSource |
template_dirs |
HYPERVIEW["TEMPLATE_DIRS"] |
Ordered template roots for this source instance, supplied as a list or tuple of strings or Path objects. Earlier roots win. |
DatabaseSource |
using |
None |
A configured Django database alias. A fixed alias permits source caching; omitting it delegates to Django database routing and disables source caching because the selected database can vary. |
template_dirs must be a list or tuple of roots. Do not pass a single string,
Path, generator, set, or other iterable: only reusable ordered collections are
accepted. A root that is temporarily unavailable emits a system-check warning;
resolution continues through later roots.
For example, one filesystem source can override the global roots:
# Create tenant-hyperview/ first. This changes SOURCES, not other sections.
HYPERVIEW["SOURCES"] = [
{
"BACKEND": "dj_hyperview.sources.FileSystemSource",
"OPTIONS": {"template_dirs": [BASE_DIR / "tenant-hyperview"]},
},
]
A custom backend defines its own supported OPTIONS through its constructor.
There is no package-wide list for third-party options. System checks bind
OPTIONS to the constructor signature of an importable backend: a misspelled
option, an unexpected one, or a missing required argument produces
dj_hyperview.E024 ("OPTIONS do not match the backend constructor") instead of
a TypeError on every request. Reading settings fails the same way. A custom
backend is also never cached unless it declares cacheable = True; see
cache consistency. See
Filesystem and Database and admin for
backend-specific behavior.
Template engine behavior¶
Named templates use dj-hyperview's dedicated resolver-backed template engine
by default. That engine copies only context_processors, string_if_invalid,
builtins, and libraries from the first configured DjangoTemplates backend
or subclass. It deliberately isolates security-sensitive options such as
autoescape and replaces the backend's loaders, so template lookup still
follows HYPERVIEW["SOURCES"] and never falls through to unrelated Django
template directories.
The engine's loader keeps the templates it compiled, so a template that resolves
to the same content is validated and compiled once instead of on every render.
The resolver still runs on every lookup, so invalidation, cache generations and
the per-render revision snapshot behave as before. A stored template is reused
only when the new resolution matches it in every field, content included, so a
custom source whose revision does not follow its content never serves stale
code. Validation and compile errors are never stored. A template keeps one entry
per source, name and origin, so a template that is published again replaces its
previous version instead of adding to it. The memory is bounded for each engine
to 256 templates and 524,288 characters (512 Ki) of source, and the least
recently used template leaves first. A compiled template takes about 5 to 25
bytes of memory per character of its source, and up to about 100 for dense
markup, so that is about 12 MiB for typical templates and 50 MiB at worst. A
source over 524,288 characters is compiled on every render. The settings a
compile depends on are read when the engine is built: HYPERVIEW, TEMPLATES
and DEBUG rebuild the default engine, which starts empty, and a loader that
Django builds from TEMPLATES keeps the sources and limits it read when it was
built, as it did before. ResolverLoader.reset() empties the loader. A subclass
that overrides get_contents() or get_template_sources() compiles on every
render, because an override may read state that the cache cannot see. Compiled
templates are shared between threads, as in Django's cached loader, so a custom
tag must keep no per-render state on its nodes; the tags and filters of this
package keep none.
The response path does not switch engines when SOURCES is empty. An empty
source list therefore produces a normal missing-template result. To opt out and
select a consumer Django engine explicitly, pass its alias, for example
using="django", to HyperviewTemplateResponse. The dj_hyperview.W005
system check calls out an absent configuration or an explicitly empty source
list. Temporarily unavailable filesystem roots emit dj_hyperview.W006 and do
not prevent later roots from resolving templates.
Continue with Filesystem, Database and admin, Cache consistency, Security, Testing, Release and rollback, or the public Python API. Return to the documentation home.
Corrected schema boundaries¶
The internal correction revision is package-owned, not a user-selectable profile.
It accepts signed decimal percentages on the nine margin attributes while keeping
integer and auto values, and adds only these verified declarations:
| Element | Added attributes | Boundary |
|---|---|---|
text |
ellipsizeMode |
clip, head, middle, tail; clip is iOS-specific |
text, text-field |
accessibilityLabel |
String, including empty text |
text |
accessibilityRole |
button, none |
image |
accessibilityRole, alt |
Role button; alternative text is a string |
text |
importantForAccessibility |
auto, yes, no, no-hide-descendants; Android-specific |
date-field |
cancel-label, done-label |
Strings consumed by the iOS modal, not Android's native picker |
The correction restricts only style@width, not the shared upstream sizing types. It accepts
nonnegative decimal points with a leading digit (0, 84, 12.5, 0.5) and
decimal percentages (0%, 12.5%, .5%, 150%); a leading + is accepted.
It rejects negative values, auto, .5 without %, trailing decimal points,
units, exponent notation, arbitrary suffixes, NaN, and Infinity.
These are deliberate lexical boundaries. Hyperview 0.110.0 truncates point
values with parseInt: 12.5 becomes 12. Validation never rewrites the input.
React Native itself supports fractional dimensions and auto, but this pinned
Hyperview converter passes auto as NaN, not as the native auto value.
The corrected schema does not permit accessibilityElementsHidden as a boolean
string, move styles outside its owning screen, accept arbitrary native
properties, or establish native visual/accessibility parity. The evidence is
pinned client source plus package tests, not device E2E testing.
Register typed schema extensions¶
SCHEMA_EXTENSIONS defaults to {}. Invalid registrations produce
dj_hyperview.E021. Registration describes server validation
and editor metadata, not executable mobile implementations.
The complete example at the top declares a required message, a tone enum,
and an image.variant enum. Merge new declarations into your existing registry;
do not replace unrelated behaviors or attributes. This valid fragment uses them:
<view xmlns="https://hyperview.org/hyperview">
<behavior trigger="load" action="show-snackbar" message="Saved" tone="success" />
</view>
A descriptor requires TYPE: string, boolean, integer, or decimal.
REQUIRED defaults to False; True requires the attribute's presence, not
nonempty string content. Optional ENUM is a nonempty sequence of unique XML
strings and is valid only with TYPE: "string". There are no implicit defaults,
coercions or output mutations. XML boolean lexical forms are true, false,
1, and 0; declaring a type does not convert a mobile client's raw attribute.
All sections and descriptor keys are closed. Names must be unqualified ASCII
XML names; names starting with xml are reserved. Standard actions and standard
attributes cannot be redefined. Qualified and unqualified names are distinct:
custom message can coexist with standard alert:message. ELEMENT_ATTRIBUTES
can add attributes only to existing Hyperview elements other than behavior.
Use BEHAVIORS for action-specific attributes; custom actions are supported on
behavior, not inline on view, text, or other built-in elements.
Strings can be empty, including an opaque revocation token. Register DOM target
identifiers as strings when they may reference a host outside the current
fragment; registration does not impose document-wide xs:IDREF existence.
See custom schema contracts
for validation, catalog and trust boundaries.
Optional realtime broker¶
HYPERVIEW["REALTIME"] centralizes the Redis URL and namespace. Omitted or None
means disabled. An enabled mapping must contain exactly REDIS_URL and
NAMESPACE; empty mappings, extra keys, ALIAS or invalid values produce
dj_hyperview.E022 and HyperviewConfigurationError when reading settings.
Configuration errors never silently fall back to disabled. Diagnostics do not
include the secret URL.
from dj_hyperview.conf import get_settings
from dj_hyperview.realtime import RedisBroker
realtime = get_settings().realtime
broker = (
RedisBroker(realtime.redis_url, realtime.namespace)
if realtime is not None
else None
)
get_settings().realtime returns immutable RealtimeSettings or None; its repr
excludes redis_url. Reading settings, running checks and constructing the broker
do not import redis-py or connect. Subscription/publication requires the
[realtime] extra. When REALTIME is enabled but redis-py cannot be found,
python manage.py check reports the warning dj_hyperview.W007 with the hint
pip install "dj-hyperview[realtime]"; the check only looks for the package and
never imports it. Configuration alone creates no endpoint, producer or mobile
listener. To disable this section without losing template sources or schemas:
There is no REALTIME.ALIAS adapter. CACHE.ALIAS selects a Django cache, not a
Pub/Sub transport. Use a distinct app/environment namespace: Redis database
numbers do not isolate Pub/Sub. A namespace prevents collisions, not unauthorized
access. Use rediss:// for remote services; TLS certificate verification and
hostname checks remain required. See the complete SSE guide for
application integration and the cache comparison.
URLs support redis://, rediss:// and unix:///absolute/socket. The only query
option is one canonical db=0 (or another nonnegative database number), without
a conflicting TCP URL database path. Retry, timeout, SSL and unknown query
options are rejected: redis-py URL options can otherwise override safe kwargs.
Namespace syntax is [a-z0-9][a-z0-9_-]{0,63}; topics are at most 32 supplied
items matching [A-Za-z0-9][A-Za-z0-9._:-]{0,127}. Duplicates are coalesced, but
still count toward that input bound. Topics are server-selected, never query
parameters. The broker prefixes them with namespace:.
Redis permissions and TLS¶
The package issues PUBLISH and SUBSCRIBE on channels named
<namespace>:<topic>. Redis also receives AUTH when the URL carries
credentials and SELECT when it selects a database other than 0. redis-py also
sends CLIENT SETINFO with its library name and version whenever it opens a
connection. The rule below denies that command, and redis-py ignores the error (its
Connection.on_connect in 7.4.1 and 8.1.0 catches ResponseError around both
commands), so the connection works; the denied attempts may appear in ACL LOG.
No scripting permission is required. Since Redis 7.0 the default for new ACL users is
resetchannels (the acl-pubsub-default setting), so +publish +subscribe alone
is refused with NOPERM until the user is also granted the namespace's channels:
Replace my-app-dev with your REALTIME.NAMESPACE, drop +select when the URL
uses database 0, and try the rule with a throwaway user on your Redis version. A
rejected command shows up in the publisher log as
realtime_publish_failed error_type=NoPermissionError; a subscription that cannot
start raises RealtimeUnavailable without further detail, so check the ACL first
when a stream never starts.
TLS is deliberately narrow. A rediss:// URL always verifies the certificate and
the host name, and the URL accepts no query option except db, so there is no
setting for a CA bundle, a client certificate or a key. A private CA must be
trusted through the process's default trust store, for example with the
SSL_CERT_FILE or SSL_CERT_DIR environment variables that OpenSSL reads. A
unix:///absolute/socket URL carries no credentials; authenticate such a
connection with the socket's file permissions.
Call broker.publish_after_commit(event, topics, *, using) with an explicit
Django database alias: using is keyword-only and has no default, so omitting it
raises TypeError. It snapshots the closed envelope and topics before
scheduling. Rollback publishes nothing; invalid inputs fail before scheduling.
Publication failure never fails the committed business operation. It logs only
a fixed code and the exception type name, as
realtime_publish_failed error_type=<TypeName>, never the exception message,
which can contain the Redis URL. A per-process daemon worker has a queue of 32
jobs; each commit caller waits at most two seconds including queue time. Expired queued jobs do
not start I/O. Forked children create their own worker, not an inherited client.
The worker keeps one Redis connection per configuration and reuses it for later
hints, sending all channels of a hint in one pipeline round trip. It replaces the
connection after a failure, after 30 seconds without use, or after five minutes of
age, so that the host name is resolved again even under steady traffic. It checks
the connection that a hint uses against those limits, and sweeps every connection
at most every 30 seconds, whether hints arrive or not, so a configuration that is
never used again does not keep its connection open until the process ends. The
sweep also forgets a configuration, with the failures counted for it, once nothing
was attempted on it for 30 seconds and its breaker is not open: a configuration
that only ever failed does not stay in memory, and a failure that old stops
counting toward the breaker. After three consecutive failures of one configuration,
including a client that cannot be built, publications for it fail fast for five
seconds instead of each paying the connection timeout. The breaker logs the fixed
code realtime_publish_circuit_open once when it opens, not for each dropped hint.
The first publication after that pause is the probe: success closes the breaker,
failure reopens it for another five seconds. A worker ended by a BaseException,
such as a gevent Timeout, is replaced by the next commit.
Hints dropped this way follow the same at-most-once rule as every other failure.
The caller deadline is not a total I/O deadline. DNS resolution cannot be preempted; socket timeouts apply per operation, including multiple pipeline responses. One slow worker can block later hints until they expire. An in-flight hint may finish late or partially. There is no retry, rollback, delivery receipt, EVAL requirement or durability claim. No thread is created per hint.
await broker.subscribe(topics) waits for each actual SUBSCRIBE acknowledgement
within a two-second setup budget. Only then does it return an owned async
iterator, beginning with one resync; pre-ACK data is conservatively covered by
that resync. Cleanup has a separate two-second cooperative budget, so failed
setup plus cleanup can take longer than the setup deadline. Cancellation does
not forcibly stop an OS resolver already running in asyncio's executor.
Repeated cancellation during failed setup waits for the same owned cleanup
budget before propagating cancellation; it does not restart that budget.
Each subscription owns its client/one-connection pool and queue of at most 32
closed JSON payloads (each at most 4096 bytes). Overflow discards pending hints
and retains one resync until consumed. This is a logical retained-payload bound,
not a peak allocation guarantee inside redis-py. No transparent reconnection is
allowed: a lost connection closes the iterator; the application may subscribe
again and must reauthorize before its new resync. A cancelled __anext__ wait
(for example a heartbeat deadline) does not close ownership; call aclose().
Idle connections have no two-second socket read timeout. The application owns
heartbeat cadence, stream lifetime, authorization, connection admission caps,
and realtime_asgi/sse_response composition.
System check reference¶
python manage.py check reports these IDs. Each message names the failing setting
and carries a hint; messages never include file paths, exception text or secret
values. Errors fail the check, and warnings describe configuration that works but
probably is not what you meant. E020 is not used.
| ID | Raised when | Fix |
|---|---|---|
dj_hyperview.E001 |
HYPERVIEW is not a mapping. |
Make it a dictionary. |
dj_hyperview.E002 |
TEMPLATE_DIRS is not a sequence, or an entry is not a path. |
Use a list or tuple of strings or Path objects. |
dj_hyperview.E003 |
SOURCES is not a sequence, an entry is not a mapping, its BACKEND cannot be imported (the message names the exception class), or its OPTIONS is not a mapping. |
Correct the entry; use a dotted path to an importable source class. |
dj_hyperview.E004 |
CACHE is not a mapping, CACHE.ALIAS names no configured cache, or CACHE.NAMESPACE is not a non-empty string. |
Define the alias in CACHES and supply a namespace. |
dj_hyperview.E005 |
CACHE.TTL is not an integer of at least 1, or CACHE.NEGATIVE_TTL is not an integer of at least 0. |
Use a plain integer; bool is rejected. |
dj_hyperview.E006 |
CACHE.FAILURE_MODE is neither bypass nor raise. |
Choose one of the two values. |
dj_hyperview.E007 |
VALIDATION is not a mapping, or the removed key VALIDATION.MODE is present. |
Use a mapping with limits only; delete MODE. |
dj_hyperview.E008 |
The removed key VALIDATION.SCHEMA is present. |
Delete it; validation cannot be replaced. |
dj_hyperview.E009 |
A VALIDATION.MAX_* limit is not a positive integer (a bool or other int subclass counts as invalid), or MAX_DEPTH is above 256. |
Use a plain positive integer; keep MAX_DEPTH at 256 or less. |
dj_hyperview.E010 |
DatabaseSource is configured but dj_hyperview.contrib.database is not in INSTALLED_APPS. |
Install the contrib app and migrate, or remove the source. |
dj_hyperview.E011 |
DatabaseSource OPTIONS["using"] is neither None nor a configured database alias. |
Name an alias that exists in DATABASES. |
dj_hyperview.E012 |
EXTRA_SCHEMAS is not a sequence of files, one file is not a valid local XSD 1.1 schema, or the schemas do not compile together with the Hyperview schema. The message ends with (reason: <code>), such as unreadable, forbidden_schema_reference, schema_invalid or duplicate_schema_declaration. |
Fix the file named by the index, or declare each global name once; see Automatic Hyperview XSD 1.1 validation. |
dj_hyperview.E013 |
xmlschema, a required dependency, is not installed. |
Repair the package installation. |
dj_hyperview.E014 |
ADMIN is not a mapping, or ADMIN.EDITOR is not a boolean. |
Use a mapping and True or False. |
dj_hyperview.E015 |
ADMIN.EDITOR is on but django-ace is not installed. |
Install dj-hyperview[editor]. |
dj_hyperview.E016 |
ADMIN.EDITOR is on but django_ace is not in INSTALLED_APPS. |
Add django_ace before dj_hyperview. |
dj_hyperview.E017 |
ADMIN.PERMISSION is not a callable that accepts one request, or its dotted path cannot be imported. |
Pass a callable, or a dotted path to an importable callable; see Admin editor. |
dj_hyperview.E018 |
CACHE.ALIAS uses FileBasedCache or a subclass, whose add() is not atomic. |
Select another backend or omit CACHE; bypass does not override this. |
dj_hyperview.E019 |
The removed key SCHEMA_PROFILE is present. |
Delete it; the corrected schema is automatic. |
dj_hyperview.E021 |
A SCHEMA_EXTENSIONS registration is invalid; the message names the path. |
Follow Register typed schema extensions. |
dj_hyperview.E022 |
REALTIME is neither None nor a mapping with exactly a valid REDIS_URL and NAMESPACE. |
See Optional realtime broker. |
dj_hyperview.E023 |
A key that HYPERVIEW, a SOURCES entry, CACHE, VALIDATION or ADMIN does not define. |
Remove it or fix its spelling; the hint lists the valid keys. |
dj_hyperview.E024 |
SOURCES[].OPTIONS do not match the source constructor: an unknown keyword or a missing required argument. |
Pass only keyword arguments the constructor accepts. |
dj_hyperview.W001 |
CACHE.ALIAS names a backend that cannot be initialized now. |
Correct the CACHES entry; runtime behavior follows CACHE.FAILURE_MODE. |
dj_hyperview.W002 |
TEMPLATE_DIRS is set but no FileSystemSource is configured to use it. |
Add FileSystemSource or remove TEMPLATE_DIRS. |
dj_hyperview.W003 |
A FileSystemSource has no template roots. |
Set TEMPLATE_DIRS or OPTIONS["template_dirs"]. |
dj_hyperview.W004 |
CACHE.ALIAS is a DummyCache. |
Omit CACHE; with FAILURE_MODE="raise" every lookup would fail. |
dj_hyperview.W005 |
No SOURCES are configured, so nothing resolves. |
Add a source, or pass using="django" to the response. |
dj_hyperview.W006 |
A template root is not an available directory right now; it is skipped at runtime. | Create or mount the directory. |
dj_hyperview.W007 |
REALTIME is configured but redis-py is not installed. |
Install dj-hyperview[realtime]. |