Host API¶
The four functions a host project's main.py and modules/__init__.py
typically reach for. setup() and register_modules() are wrappers
that hide the low-level details and are sufficient for most projects;
activate() and protect() are the primitives behind them and are
useful when you need finer control.
setup¶
setup
¶
setup(*, env_var: str = 'VIUR_TESTING', namespace: str | None = _UNSET, database: str = DEFAULT_DATABASE, api_dir: str | None = 'testing') -> None
One-call host-side wiring for main.py.
Must be the first line of code in main.py — before any
from viur.core ... import. Internally:
- Resolves enabled + namespace. Without an explicit
namespace(the usual case) it parsesos.environ[env_var](defaultVIUR_TESTING) via :func:viur.testing.mode.parse_spec. An explicitnamespacekwarg forces test mode on and skips the env var. - When enabled, calls :func:
activate(datastore client swap todatabase+namespace, probe, validator) and loads the project test API. - Calls :func:
protectunconditionally to install the production cookie guard.
The single env var carries on/off + an optional namespace::
$ VIUR_TESTING=1 # on, default namespace
$ VIUR_TESTING=ak # on, namespace "ak"
# unset / 0 / off / false → off
There is no separator and no reserved names — VIUR_TESTING=ak means
"on, namespace ak". See :func:viur.testing.mode.parse_spec.
Use the env var, not conf.instance.is_dev_server, as the
gate — reading conf.instance triggers the full viur.core
import chain (including viur.core.db.transport), which would
leave :func:activate with no chance to patch the singleton.
Typical host wiring::
# main.py
import viur.testing
viur.testing.setup()
from viur.core import setup as core_setup
import modules, render
app = core_setup(modules, render)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
env_var
|
str
|
Name of the single variable to read. Default
|
'VIUR_TESTING'
|
namespace
|
str | None
|
Explicit Datastore namespace override. When given,
test mode is forced on and the env var is ignored; |
_UNSET
|
database
|
str
|
Name of the test database to swap to. Default
|
DEFAULT_DATABASE
|
api_dir
|
str | None
|
Name of the wrapper directory (relative to the
caller's parent dir) that contains an Default: If the resolved |
'testing'
|
Source code in src/viur/testing/__init__.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 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 243 | |
register_modules¶
register_modules
¶
Inject :class:~viur.testing._test.TestModule into the host's
modules/ namespace if test mode is active.
Call from modules/__init__.py after the auto-discovery loop —
typically::
# modules/__init__.py
from viur.testing import register_modules
register_modules(globals())
Idempotent: if :func:activate has not run (test mode not armed)
this is a no-op, so the same line stays in place for both dev and
production deployments.
TestModule is registered as a class, not an instance, so
viur-core's __build_app (which scans vars(modules) for
Module subclasses) picks it up and routes /_test/config/*
through it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
dict
|
The |
required |
Source code in src/viur/testing/__init__.py
activate¶
activate
¶
Switch the running process into test mode.
Must be called before any viur.core import. Performs:
viur.core.db.transportnot-yet-imported precondition check.conf.instance.is_dev_serverprecondition check.- Construction of a datastore client targeting
database(andnamespace, if given). - Synchronous probe roundtrip in that database/namespace.
- Patching of
viur.core.db.transport.__client__. - Patching of
viur.core.db.types.Key.__init__to defaultdatabase=andnamespace=to the client's values — without this every Key viur-core constructs goes to the wrong database/ namespace and Datastore rejects the request (or, worse, silently returns empty results). - Patching of
google.cloud.datastore.Key.to_legacy_urlsafeso it tolerates named databases — the original raises on them and viur-core'sstr(key)cascade goes through it on hot paths (session save, JSON render of login_success). See :func:_patch_legacy_urlsafe. - Activation of the in-process state on
:class:
~viur.testing._test.config.ConfigModule. - Installation of the request validator.
- Wrap of
viur.core.setupso the dev-server boot banner gains adatabase = <name>(and, when set,namespace = <name>) line — see :mod:viur.testing.banner.
No token is created here — the session token is created and stored
by /_test/config/status directly in the test database, and
released by /_test/config/finish.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
str
|
Name of the target test database. Default |
DEFAULT_DATABASE
|
namespace
|
str | None
|
Optional Datastore namespace to scope every read
and write to. When several testers share one |
None
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
if any of the precondition checks or the probe fail. The process must abort rather than continue with a half-applied swap. |
Source code in src/viur/testing/activation.py
protect¶
protect
¶
Install :class:ProductionGuardValidator into the viur-core router.
Idempotent — calling twice is a no-op. Safe to call in any environment.