Executable State Models
AsciiDoctest provides a unified, symmetric state model across interactive REPL blocks and non-interactive script blocks.
Defining Marked Blocks
A block is marked by specifying test, shared, or reset in its block header:
Positional argument:
[source,python,shared],[source,python,reset]Explicit attribute:
[source,python,test="true"],[source,python,shared="context_name"]Role attribute:
[source,python,role="test"]
State Models Overview
Marker / Directive |
State Model |
Description |
(No marker) |
Static Listing |
Skipped by default; runs in eager fallback if unmarked document. |
|
Isolated & Ephemeral ( |
Executed in a fresh, clean namespace ( |
|
Persistent Timeline |
Continuous sequential document-level shared global namespace (like a notebook). Variables persist across subsequent |
|
Ephemeral Snapshot Copy |
Inherits a snapshot copy of shared state up to that point; local mutations are discarded when the block completes. |
|
Parallel Named Scope |
Maintains independent persistent state shared only with blocks having the same context name. |
|
Explicit State Reset |
Explicit reset of default & named shared states from that block forward. |
|
Automatic Boundary Reset |
Section header boundary automatically resets the default shared namespace and named contexts. |
No Marker: Ordinary static code listing (not executed, unless in
eagerfallback mode on unmarked documents).test(Isolated & Ephemeral): Executed in a fresh, clean namespace ({}). Any local variables or mutations are discarded after the block finishes.shared(Read-Write & Persistent): Participates in a continuous document-level shared global namespace (like a notebook). Variables and definitions persist top-to-bottom across subsequentsharedblocks.shared, test(Ephemeral Copy): Inherits a snapshot copy of the shared state up to that point, but any mutations made inside the block are discarded when the block completes.Named Contexts (
[source,python,shared="context_name"]): Maintains separate persistent timelines. Blocks sharing the same context name share state with each other independently of the default shared timeline.Explicit Reset (
[source,python,reset]): Explicitly clears all accumulated shared state and named contexts, starting fresh from that block forward.Section Boundary Scoping: In multi-section documents, crossing top-level section boundaries (
==) automatically resets the default shared namespace and named contexts, isolating independent sections while preserving sequential flow within each section.
Examples
Interactive REPL Block with Shared State
>>> x = "asciidoctest"
>>> x.upper()
'ASCIIDOCTEST'
Subsequent Script Block Accessing Shared State
assert x == "asciidoctest"
y = len(x)
assert y == 12
Isolated Test Block
>>> print(x)
Traceback (most recent call last):
...
NameError: name 'x' is not defined
Ephemeral Copy Block (shared, test)
>>> print(x)
asciidoctest
>>> x = "modified value"
>>> print(x)
modified value
Confirming Shared State Untouched
>>> print(x)
asciidoctest
Named Context Scopes (shared="<name>")
Independent state timelines can run in parallel within the same document using named contexts. Blocks sharing the same context name share state with each other but are fully isolated from the default shared namespace and from other named contexts.
connection = "postgres://localhost/mydb"
records = [{"id": 1, "name": "Alice"}]
cache = {}
cache["session_42"] = {"user": "Alice", "role": "admin"}
Subsequent blocks in the same context see accumulated state; blocks in a different context do not:
assert connection == "postgres://localhost/mydb"
assert len(records) == 1
# 'cache' lives in "cache_context" and is NOT visible here
assert cache["session_42"]["role"] == "admin"
# 'connection' lives in "db_context" and is NOT visible here
Explicit Reset (reset)
Use [source,python,reset] to explicitly clear all accumulated shared state and named
contexts at any point in the document, starting fresh from that block forward.
setup_value = 42
# Executes in a fresh namespace. setup_value has been cleared.
pass
# Shared namespace is now empty — setup_value is gone.
assert "setup_value" not in dir()
new_value = 99
Section Boundary Scoping (== Section)
When a document has multiple top-level sections (==), crossing a section boundary
automatically resets the default shared namespace and all named contexts, preventing
state from leaking between unrelated topics or API groups.
== First Section
[source,python,shared]
\----
section_one_var = "hello"
\----
== Second Section
[source,python,shared]
\----
// section_one_var is NOT accessible here — the boundary reset cleared it.
assert "section_one_var" not in dir()
section_two_var = "world"
\----