Compare commits
3 Commits
37e7470f26
...
0a3c48fc57
| Author | SHA1 | Date |
|---|---|---|
|
|
0a3c48fc57 | |
|
|
3a5cfde023 | |
|
|
8661336cf6 |
1
NEWS.rst
1
NEWS.rst
|
|
@ -78,6 +78,7 @@ Bug Fixes
|
||||||
for ``asyncio``-side errors to not propagate due to a race condition.
|
for ``asyncio``-side errors to not propagate due to a race condition.
|
||||||
|
|
||||||
The implementation fix summary is:
|
The implementation fix summary is:
|
||||||
|
|
||||||
- add state to signal the end of the ``trio`` side task to be
|
- add state to signal the end of the ``trio`` side task to be
|
||||||
read by the ``asyncio`` side and always cancel any ongoing
|
read by the ``asyncio`` side and always cancel any ongoing
|
||||||
task in such cases.
|
task in such cases.
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,14 @@ Rendering policy,
|
||||||
emitted as a literal block so no content is ever
|
emitted as a literal block so no content is ever
|
||||||
silently dropped.
|
silently dropped.
|
||||||
|
|
||||||
|
A render that is *attempted and fails* (a ``d2`` bin is
|
||||||
|
present but errors on the source) is NOT silently
|
||||||
|
degraded to the stale committed SVG: it raises a
|
||||||
|
docutils error (so ``sphinx-build -W`` fails the
|
||||||
|
build). The render is also atomic — a failed/torn
|
||||||
|
render can never clobber a good committed SVG — so the
|
||||||
|
last-good diagram survives a bad edit.
|
||||||
|
|
||||||
Binary discovery order,
|
Binary discovery order,
|
||||||
|
|
||||||
- the ``D2_BIN`` env var; may contain args which are
|
- the ``D2_BIN`` env var; may contain args which are
|
||||||
|
|
@ -37,11 +45,13 @@ Usage,
|
||||||
'''
|
'''
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import enum
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shlex
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.parsers.rst import directives
|
from docutils.parsers.rst import directives
|
||||||
|
|
@ -55,6 +65,22 @@ log = logging.getLogger(__name__)
|
||||||
# git-committed, fallback SVG outputs.
|
# git-committed, fallback SVG outputs.
|
||||||
_outdir: str = '_diagrams'
|
_outdir: str = '_diagrams'
|
||||||
|
|
||||||
|
# per-build map of {output-svg-name: source-relpath} used
|
||||||
|
# to detect 2 distinct `.d2` sources colliding on a single
|
||||||
|
# output stem; reset on each `builder-inited` (see `setup`).
|
||||||
|
_seen_outputs: dict[str, str] = {}
|
||||||
|
|
||||||
|
|
||||||
|
class RenderResult(enum.Enum):
|
||||||
|
'''
|
||||||
|
Outcome of a `render_svg()` call.
|
||||||
|
|
||||||
|
'''
|
||||||
|
OK = 'ok' # fresh SVG exists on disk
|
||||||
|
FELL_BACK = 'fell_back' # no bin; serving committed SVG
|
||||||
|
NO_OUTPUT = 'no_output' # no bin AND no committed SVG
|
||||||
|
FAILED = 'failed' # bin present, render errored
|
||||||
|
|
||||||
|
|
||||||
def find_d2(
|
def find_d2(
|
||||||
app: Sphinx,
|
app: Sphinx,
|
||||||
|
|
@ -77,37 +103,54 @@ def render_svg(
|
||||||
app: Sphinx,
|
app: Sphinx,
|
||||||
src: Path,
|
src: Path,
|
||||||
out: Path,
|
out: Path,
|
||||||
) -> bool:
|
) -> RenderResult:
|
||||||
'''
|
'''
|
||||||
Maybe (re)render `src` -> `out`, returning
|
Maybe (re)render `src` -> `out` and report the
|
||||||
`True` when an up-to-date SVG exists after the
|
outcome as a `RenderResult`.
|
||||||
call.
|
|
||||||
|
A render is performed only when `out` is missing or
|
||||||
|
older than `src` AND a `d2` binary is available. The
|
||||||
|
write is atomic (temp-file + `os.replace`) so a
|
||||||
|
failed or torn render never clobbers an existing
|
||||||
|
(committed) SVG.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
stale: bool = (
|
fresh: bool = (
|
||||||
not out.exists()
|
out.exists()
|
||||||
or
|
and
|
||||||
src.stat().st_mtime > out.stat().st_mtime
|
src.stat().st_mtime <= out.stat().st_mtime
|
||||||
)
|
)
|
||||||
if not stale:
|
if fresh:
|
||||||
return True
|
return RenderResult.OK
|
||||||
d2cmd: list[str]|None = find_d2(app)
|
d2cmd: list[str]|None = find_d2(app)
|
||||||
if d2cmd is None:
|
if d2cmd is None:
|
||||||
|
# no binary: fall back to whatever is committed,
|
||||||
|
# else signal the caller to emit the raw source.
|
||||||
if out.exists():
|
if out.exists():
|
||||||
log.info(
|
log.info(
|
||||||
f'no d2 binary; using committed svg '
|
f'no d2 binary; using committed svg '
|
||||||
f'for {src.name}'
|
f'for {src.name}'
|
||||||
)
|
)
|
||||||
return True
|
return RenderResult.FELL_BACK
|
||||||
return False
|
return RenderResult.NO_OUTPUT
|
||||||
out.parent.mkdir(
|
out.parent.mkdir(
|
||||||
parents=True,
|
parents=True,
|
||||||
exist_ok=True,
|
exist_ok=True,
|
||||||
)
|
)
|
||||||
|
# render into a sibling temp-file first so a bad
|
||||||
|
# `d2` exit (or a crash mid-write) leaves any prior
|
||||||
|
# committed SVG fully intact.
|
||||||
|
fd, tmpname = tempfile.mkstemp(
|
||||||
|
dir=str(out.parent),
|
||||||
|
prefix=f'.{out.stem}.',
|
||||||
|
suffix='.svg.tmp',
|
||||||
|
)
|
||||||
|
os.close(fd)
|
||||||
|
tmp = Path(tmpname)
|
||||||
argv: list[str] = (
|
argv: list[str] = (
|
||||||
d2cmd
|
d2cmd
|
||||||
+ list(app.config.d2_args)
|
+ list(app.config.d2_args)
|
||||||
+ [str(src), str(out)]
|
+ [str(src), str(tmp)]
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
proc = sp.run(
|
proc = sp.run(
|
||||||
|
|
@ -120,18 +163,22 @@ def render_svg(
|
||||||
OSError,
|
OSError,
|
||||||
sp.TimeoutExpired,
|
sp.TimeoutExpired,
|
||||||
) as err:
|
) as err:
|
||||||
|
tmp.unlink(missing_ok=True)
|
||||||
log.warning(
|
log.warning(
|
||||||
f'd2 invocation failed for {src.name}: '
|
f'd2 invocation failed for {src.name}: '
|
||||||
f'{err}'
|
f'{err}'
|
||||||
)
|
)
|
||||||
return out.exists()
|
return RenderResult.FAILED
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
|
tmp.unlink(missing_ok=True)
|
||||||
log.warning(
|
log.warning(
|
||||||
f'd2 render error for {src.name}:\n'
|
f'd2 render error for {src.name}:\n'
|
||||||
f'{proc.stderr}'
|
f'{proc.stderr}'
|
||||||
)
|
)
|
||||||
return out.exists()
|
return RenderResult.FAILED
|
||||||
return True
|
# atomic swap-in of the freshly rendered SVG.
|
||||||
|
os.replace(tmp, out)
|
||||||
|
return RenderResult.OK
|
||||||
|
|
||||||
|
|
||||||
class D2Diagram(SphinxDirective):
|
class D2Diagram(SphinxDirective):
|
||||||
|
|
@ -169,18 +216,54 @@ class D2Diagram(SphinxDirective):
|
||||||
/ _outdir
|
/ _outdir
|
||||||
/ f'{src.stem}.svg'
|
/ f'{src.stem}.svg'
|
||||||
)
|
)
|
||||||
if not render_svg(self.env.app, src, out):
|
# collision guard: two distinct sources must not
|
||||||
# last resort: emit the raw d2 source.
|
# map onto the same output stem within a build.
|
||||||
|
prior: str|None = _seen_outputs.get(out.name)
|
||||||
|
if (
|
||||||
|
prior is not None
|
||||||
|
and
|
||||||
|
prior != relsrc
|
||||||
|
):
|
||||||
|
err = self.state_machine.reporter.error(
|
||||||
|
f'd2 output collision: {relsrc!r} and '
|
||||||
|
f'{prior!r} both render to '
|
||||||
|
f'{_outdir}/{out.name}; rename one '
|
||||||
|
f'`.d2` stem',
|
||||||
|
line=self.lineno,
|
||||||
|
)
|
||||||
|
return [err]
|
||||||
|
_seen_outputs[out.name] = relsrc
|
||||||
|
|
||||||
|
result: RenderResult = render_svg(
|
||||||
|
self.env.app,
|
||||||
|
src,
|
||||||
|
out,
|
||||||
|
)
|
||||||
|
if result is RenderResult.FAILED:
|
||||||
|
# loud, build-failing (under `-W`) signal; the
|
||||||
|
# prior committed SVG, if any, is untouched.
|
||||||
|
err = self.state_machine.reporter.error(
|
||||||
|
f'd2 render failed for {relsrc} (see '
|
||||||
|
f'build log); the committed svg, if any, '
|
||||||
|
f'was left untouched',
|
||||||
|
line=self.lineno,
|
||||||
|
)
|
||||||
|
return [err]
|
||||||
|
if result is RenderResult.NO_OUTPUT:
|
||||||
|
# last resort: emit the raw d2 source so no
|
||||||
|
# content is ever silently dropped.
|
||||||
log.warning(
|
log.warning(
|
||||||
f'no svg available for {relsrc}; '
|
f'no svg available for {relsrc}; '
|
||||||
f'emitting d2 source as literal block'
|
f'emitting d2 source as literal block'
|
||||||
)
|
)
|
||||||
|
src_text: str = src.read_text()
|
||||||
literal = nodes.literal_block(
|
literal = nodes.literal_block(
|
||||||
src.read_text(),
|
src_text,
|
||||||
src.read_text(),
|
src_text,
|
||||||
)
|
)
|
||||||
literal['language'] = 'text'
|
literal['language'] = 'text'
|
||||||
return [literal]
|
return [literal]
|
||||||
|
# OK | FELL_BACK -> embed the SVG figure.
|
||||||
img = nodes.image(
|
img = nodes.image(
|
||||||
uri=f'/{_outdir}/{out.name}',
|
uri=f'/{_outdir}/{out.name}',
|
||||||
alt=self.options.get(
|
alt=self.options.get(
|
||||||
|
|
@ -224,12 +307,29 @@ class D2Diagram(SphinxDirective):
|
||||||
return [fig]
|
return [fig]
|
||||||
|
|
||||||
|
|
||||||
|
def _reset_seen(
|
||||||
|
app: Sphinx,
|
||||||
|
) -> None:
|
||||||
|
'''
|
||||||
|
Clear the per-build output-collision map at the
|
||||||
|
start of each build.
|
||||||
|
|
||||||
|
'''
|
||||||
|
_seen_outputs.clear()
|
||||||
|
|
||||||
|
|
||||||
def setup(app: Sphinx) -> dict:
|
def setup(app: Sphinx) -> dict:
|
||||||
app.add_config_value('d2_bin', None, 'env')
|
app.add_config_value('d2_bin', None, 'env')
|
||||||
app.add_config_value('d2_args', [], 'env')
|
app.add_config_value('d2_args', [], 'env')
|
||||||
app.add_directive('d2', D2Diagram)
|
app.add_directive('d2', D2Diagram)
|
||||||
|
app.connect('builder-inited', _reset_seen)
|
||||||
return {
|
return {
|
||||||
'version': '0.1.0',
|
'version': '0.1.0',
|
||||||
|
# NB: run() writes the rendered SVG during the
|
||||||
|
# READ phase; the temp-file + `os.replace` swap
|
||||||
|
# keeps that atomic so concurrent renders of the
|
||||||
|
# same diagram (under `sphinx-build -j`) can't
|
||||||
|
# tear the output file.
|
||||||
'parallel_read_safe': True,
|
'parallel_read_safe': True,
|
||||||
'parallel_write_safe': True,
|
'parallel_write_safe': True,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
86
flake.nix
86
flake.nix
|
|
@ -25,43 +25,63 @@
|
||||||
cpython = "python313";
|
cpython = "python313";
|
||||||
venv_dir = "py313";
|
venv_dir = "py313";
|
||||||
pypkgs = pkgs."${cpython}Packages";
|
pypkgs = pkgs."${cpython}Packages";
|
||||||
|
|
||||||
|
# shared base toolchain for every dev-shell variant;
|
||||||
|
# extra-tooling shells (eg. `docs`, below) extend it
|
||||||
|
# so heavy/niche deps stay OUT of the `default` shell.
|
||||||
|
basePkgs = [
|
||||||
|
# XXX, ensure sh completions activate!
|
||||||
|
pkgs.bashInteractive
|
||||||
|
pkgs.bash-completion
|
||||||
|
|
||||||
|
# XXX, on nix(os), use pkgs version to avoid
|
||||||
|
# build/sys-sh-integration issues
|
||||||
|
pkgs.ruff
|
||||||
|
|
||||||
|
pkgs.uv
|
||||||
|
pkgs.${cpython}# ?TODO^ how to set from `cpython` above?
|
||||||
|
];
|
||||||
|
|
||||||
|
baseHook = ''
|
||||||
|
# unmask to debug **this** dev-shell-hook
|
||||||
|
# set -e
|
||||||
|
|
||||||
|
# link-in c++ stdlib for various AOT-ext-pkgs (numpy, etc.)
|
||||||
|
LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib:$LD_LIBRARY_PATH"
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
# RUNTIME-SETTINGS
|
||||||
|
# ------ uv ------
|
||||||
|
# - always use the ./py313/ venv-subdir
|
||||||
|
# - sync env with all extras
|
||||||
|
export UV_PROJECT_ENVIRONMENT=${venv_dir}
|
||||||
|
uv sync --dev --all-extras
|
||||||
|
|
||||||
|
# ------ TIPS ------
|
||||||
|
# NOTE, to launch the py-venv installed `xonsh` (like @goodboy)
|
||||||
|
# run the `nix develop` cmd with,
|
||||||
|
# >> nix develop -c uv run xonsh
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
|
packages = basePkgs;
|
||||||
|
shellHook = baseHook;
|
||||||
|
};
|
||||||
|
|
||||||
packages = [
|
# OPT-IN docs shell: `default` + the `d2` diagram
|
||||||
# XXX, ensure sh completions activate!
|
# renderer, kept OUT of `default` so casual dev shells
|
||||||
pkgs.bashInteractive
|
# don't pull it in. Enter with,
|
||||||
pkgs.bash-completion
|
# >> nix develop .#docs
|
||||||
|
# then build (the `.. d2::` directive auto-detects the
|
||||||
# XXX, on nix(os), use pkgs version to avoid
|
# `d2` bin now on PATH; see `docs/_ext/d2diagrams.py`),
|
||||||
# build/sys-sh-integration issues
|
# >> uv run --group docs make -C docs html
|
||||||
pkgs.ruff
|
docs = pkgs.mkShell {
|
||||||
|
packages = basePkgs ++ [ pkgs.d2 ];
|
||||||
pkgs.uv
|
shellHook = baseHook + ''
|
||||||
pkgs.${cpython}# ?TODO^ how to set from `cpython` above?
|
echo "[docs] d2 $(d2 --version) on PATH \
|
||||||
];
|
— build via: uv run --group docs make -C docs html"
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
# unmask to debug **this** dev-shell-hook
|
|
||||||
# set -e
|
|
||||||
|
|
||||||
# link-in c++ stdlib for various AOT-ext-pkgs (numpy, etc.)
|
|
||||||
LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib:$LD_LIBRARY_PATH"
|
|
||||||
|
|
||||||
export LD_LIBRARY_PATH
|
|
||||||
|
|
||||||
# RUNTIME-SETTINGS
|
|
||||||
# ------ uv ------
|
|
||||||
# - always use the ./py313/ venv-subdir
|
|
||||||
# - sync env with all extras
|
|
||||||
export UV_PROJECT_ENVIRONMENT=${venv_dir}
|
|
||||||
uv sync --dev --all-extras
|
|
||||||
|
|
||||||
# ------ TIPS ------
|
|
||||||
# NOTE, to launch the py-venv installed `xonsh` (like @goodboy)
|
|
||||||
# run the `nix develop` cmd with,
|
|
||||||
# >> nix develop -c uv run xonsh
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -135,19 +135,21 @@ class Context:
|
||||||
communication context.
|
communication context.
|
||||||
|
|
||||||
(We've also considered other names and ideas:
|
(We've also considered other names and ideas:
|
||||||
- "communicating tasks scope": cts
|
|
||||||
- "distributed task scope": dts
|
|
||||||
- "communicating tasks context": ctc
|
|
||||||
|
|
||||||
**Got a better idea for naming? Make an issue dawg!**
|
- "communicating tasks scope": cts
|
||||||
|
- "distributed task scope": dts
|
||||||
|
- "communicating tasks context": ctc
|
||||||
|
|
||||||
|
**Got a better idea for naming? Make an issue dawg!**
|
||||||
)
|
)
|
||||||
|
|
||||||
NB: This class should **never be instatiated directly**, it is
|
NB: This class should **never be instatiated directly**, it is
|
||||||
allocated by the runtime in 2 ways:
|
allocated by the runtime in 2 ways:
|
||||||
- by entering `Portal.open_context()` which is the primary
|
|
||||||
public API for any "parent" task or,
|
- by entering `Portal.open_context()` which is the primary
|
||||||
- by the RPC machinery's `._rpc._invoke()` as a `ctx` arg
|
public API for any "parent" task or,
|
||||||
to a remotely scheduled "child" function.
|
- by the RPC machinery's `._rpc._invoke()` as a `ctx` arg
|
||||||
|
to a remotely scheduled "child" function.
|
||||||
|
|
||||||
AND is always constructed using the below `mk_context()`.
|
AND is always constructed using the below `mk_context()`.
|
||||||
|
|
||||||
|
|
@ -443,6 +445,7 @@ class Context:
|
||||||
'''
|
'''
|
||||||
Records whether cancellation has been requested for this context
|
Records whether cancellation has been requested for this context
|
||||||
by a call to `.cancel()` either due to,
|
by a call to `.cancel()` either due to,
|
||||||
|
|
||||||
- an explicit call by some local task,
|
- an explicit call by some local task,
|
||||||
- or an implicit call due to an error caught inside
|
- or an implicit call due to an error caught inside
|
||||||
the `Portal.open_context()` block.
|
the `Portal.open_context()` block.
|
||||||
|
|
@ -554,6 +557,7 @@ class Context:
|
||||||
Only as an FYI, in the "child" side case it can also be
|
Only as an FYI, in the "child" side case it can also be
|
||||||
set but never is readable by any task outside the RPC
|
set but never is readable by any task outside the RPC
|
||||||
machinery in `._invoke()` since,:
|
machinery in `._invoke()` since,:
|
||||||
|
|
||||||
- when a child side calls `.cancel()`, `._scope.cancel()`
|
- when a child side calls `.cancel()`, `._scope.cancel()`
|
||||||
is called immediately and handled specially inside
|
is called immediately and handled specially inside
|
||||||
`._invoke()` to raise a `ContextCancelled` which is then
|
`._invoke()` to raise a `ContextCancelled` which is then
|
||||||
|
|
@ -1033,8 +1037,8 @@ class Context:
|
||||||
`._scope.cancel()` and delivering an `ContextCancelled`
|
`._scope.cancel()` and delivering an `ContextCancelled`
|
||||||
ack msg in reponse.
|
ack msg in reponse.
|
||||||
|
|
||||||
Behaviour:
|
**Behaviour:**
|
||||||
---------
|
|
||||||
- after the far end cancels, the `.cancel()` calling side
|
- after the far end cancels, the `.cancel()` calling side
|
||||||
should receive a `ContextCancelled` with the
|
should receive a `ContextCancelled` with the
|
||||||
`.canceller: tuple` uid set to the current `Actor.aid.uid`.
|
`.canceller: tuple` uid set to the current `Actor.aid.uid`.
|
||||||
|
|
@ -1505,6 +1509,7 @@ class Context:
|
||||||
TODO->( this is doc-driven-dev content not yet actual ;P )
|
TODO->( this is doc-driven-dev content not yet actual ;P )
|
||||||
|
|
||||||
The final "outcome" from an IPC context which can be any of:
|
The final "outcome" from an IPC context which can be any of:
|
||||||
|
|
||||||
- some `outcome.Value` which boxes the returned output from the peer task's
|
- some `outcome.Value` which boxes the returned output from the peer task's
|
||||||
`@context`-decorated remote task-as-func, or
|
`@context`-decorated remote task-as-func, or
|
||||||
- an `outcome.Error` wrapping an exception raised that same RPC task
|
- an `outcome.Error` wrapping an exception raised that same RPC task
|
||||||
|
|
@ -2066,7 +2071,7 @@ async def open_context_from_portal(
|
||||||
allows for deterministic setup and teardown of a remotely
|
allows for deterministic setup and teardown of a remotely
|
||||||
scheduled task in another remote actor. Once opened, the 2 now
|
scheduled task in another remote actor. Once opened, the 2 now
|
||||||
"linked" tasks run completely in parallel in each actor's
|
"linked" tasks run completely in parallel in each actor's
|
||||||
runtime with their enclosing `trio.CancelScope`s kept in
|
runtime with their enclosing `trio.CancelScope`\\ s kept in
|
||||||
a synced state wherein if either side errors or cancels an
|
a synced state wherein if either side errors or cancels an
|
||||||
equivalent error is relayed to the other side via an SC-compat
|
equivalent error is relayed to the other side via an SC-compat
|
||||||
IPC protocol.
|
IPC protocol.
|
||||||
|
|
|
||||||
|
|
@ -824,11 +824,12 @@ class ContextCancelled(RemoteActorError):
|
||||||
- (simulating) an IPC transport network outage
|
- (simulating) an IPC transport network outage
|
||||||
- a (malicious) pkt sent specifically to cancel an actor's
|
- a (malicious) pkt sent specifically to cancel an actor's
|
||||||
runtime non-gracefully without ensuring ongoing RPC tasks are
|
runtime non-gracefully without ensuring ongoing RPC tasks are
|
||||||
incrementally cancelled as is done with:
|
incrementally cancelled as is done with::
|
||||||
`Actor`
|
|
||||||
|_`.cancel()`
|
`Actor`
|
||||||
|_`.cancel_soon()`
|
|_`.cancel()`
|
||||||
|_`._cancel_task()`
|
|_`.cancel_soon()`
|
||||||
|
|_`._cancel_task()`
|
||||||
|
|
||||||
'''
|
'''
|
||||||
value: tuple[str, str]|None = self._ipc_msg.canceller
|
value: tuple[str, str]|None = self._ipc_msg.canceller
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,7 @@ def open_crash_handler(
|
||||||
`typer` users so they can quickly wrap cmd endpoints which get
|
`typer` users so they can quickly wrap cmd endpoints which get
|
||||||
automatically wrapped to use the runtime's `debug_mode: bool`
|
automatically wrapped to use the runtime's `debug_mode: bool`
|
||||||
AND `pdbp.pm()` around any code that is PRE-runtime entry
|
AND `pdbp.pm()` around any code that is PRE-runtime entry
|
||||||
|
|
||||||
- any sync code which runs BEFORE the main call to
|
- any sync code which runs BEFORE the main call to
|
||||||
`trio.run()`.
|
`trio.run()`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ def mk_pdb() -> PdbREPL:
|
||||||
|
|
||||||
FURTHER, the `pdbp.Pdb` instance is configured to be `trio`
|
FURTHER, the `pdbp.Pdb` instance is configured to be `trio`
|
||||||
"compatible" from a SIGINT handling perspective; we mask out
|
"compatible" from a SIGINT handling perspective; we mask out
|
||||||
the default `pdb` handler and instead apply `trio`s default
|
the default `pdb` handler and instead apply `trio`\\ s default
|
||||||
which mostly addresses all issues described in:
|
which mostly addresses all issues described in:
|
||||||
|
|
||||||
- https://github.com/python-trio/trio/issues/1155
|
- https://github.com/python-trio/trio/issues/1155
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,7 @@ async def query_actor(
|
||||||
listening @ `regaddr`.
|
listening @ `regaddr`.
|
||||||
|
|
||||||
Yields a `tuple` of `(addr, reg_portal)` where,
|
Yields a `tuple` of `(addr, reg_portal)` where,
|
||||||
|
|
||||||
- `addr` is the transport protocol (socket) address or `None` if
|
- `addr` is the transport protocol (socket) address or `None` if
|
||||||
no entry under that name exists,
|
no entry under that name exists,
|
||||||
- `reg_portal` is the `Portal` (or `LocalPortal` when the
|
- `reg_portal` is the `Portal` (or `LocalPortal` when the
|
||||||
|
|
@ -439,7 +440,7 @@ async def wait_for_actor(
|
||||||
) -> AsyncGenerator[Portal, None]:
|
) -> AsyncGenerator[Portal, None]:
|
||||||
'''
|
'''
|
||||||
Wait on at least one peer actor to register `name` with the
|
Wait on at least one peer actor to register `name` with the
|
||||||
registrar, yield a `Portal to the first registree.
|
registrar, yield a `Portal` to the first registree.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
actor: Actor = current_actor()
|
actor: Actor = current_actor()
|
||||||
|
|
|
||||||
|
|
@ -371,7 +371,7 @@ class MsgCodec(Struct):
|
||||||
A IPC msg interchange format lib's encoder + decoder pair.
|
A IPC msg interchange format lib's encoder + decoder pair.
|
||||||
|
|
||||||
Pretty much nothing more then delegation to underlying
|
Pretty much nothing more then delegation to underlying
|
||||||
`msgspec.<interchange-protocol>.Encoder/Decoder`s for now.
|
`msgspec.<interchange-protocol>.Encoder/Decoder`\\ s for now.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
_enc: msgpack.Encoder
|
_enc: msgpack.Encoder
|
||||||
|
|
|
||||||
|
|
@ -453,7 +453,7 @@ class Error(
|
||||||
# omit_defaults=True,
|
# omit_defaults=True,
|
||||||
):
|
):
|
||||||
'''
|
'''
|
||||||
A pkt that wraps `RemoteActorError`s for relay and raising.
|
A pkt that wraps `RemoteActorError`\\ s for relay and raising.
|
||||||
|
|
||||||
Fields are 1-to-1 meta-data as needed originally by
|
Fields are 1-to-1 meta-data as needed originally by
|
||||||
`RemoteActorError.msgdata: dict` but now are defined here.
|
`RemoteActorError.msgdata: dict` but now are defined here.
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,7 @@ class ActorNursery:
|
||||||
'''
|
'''
|
||||||
Records whether cancellation has been requested for this
|
Records whether cancellation has been requested for this
|
||||||
actor-nursery by a call to `.cancel()` either due to,
|
actor-nursery by a call to `.cancel()` either due to,
|
||||||
|
|
||||||
- an explicit call by some actor-local-task,
|
- an explicit call by some actor-local-task,
|
||||||
- an implicit call due to an error/cancel emited inside
|
- an implicit call due to an error/cancel emited inside
|
||||||
the `tractor.open_nursery()` block.
|
the `tractor.open_nursery()` block.
|
||||||
|
|
|
||||||
|
|
@ -120,12 +120,12 @@ async def gather_contexts(
|
||||||
None,
|
None,
|
||||||
]:
|
]:
|
||||||
'''
|
'''
|
||||||
Concurrently enter a sequence of async context managers (`acm`s),
|
Concurrently enter a sequence of async context managers (`acm`\\ s),
|
||||||
each scheduled in a separate `trio.Task` and deliver their
|
each scheduled in a separate `trio.Task` and deliver their
|
||||||
unwrapped `yield`-ed values in the same order once all `@acm`s
|
unwrapped `yield`-ed values in the same order once all `@acm`\\ s
|
||||||
in every task have entered.
|
in every task have entered.
|
||||||
|
|
||||||
On exit, all `acm`s are subsequently and concurrently exited with
|
On exit, all `acm`\\ s are subsequently and concurrently exited with
|
||||||
**no order guarantees**.
|
**no order guarantees**.
|
||||||
|
|
||||||
This function is somewhat similar to a batch of non-blocking
|
This function is somewhat similar to a batch of non-blocking
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue