DevTools agent and error reports¶
The in-app half of PythonNative Go and DevTools:
the agent that answers DevTools, the inspector it uses, the REPL, live
performance sampling, and the debugger integration. Development builds
only; release bundles omit pythonnative.devtools.
pythonnative.devtools¶
The devtools agent: answer DevTools and publish what the app is doing.
One Agent runs in every dev client
(PythonNative Go, a project's debug build) and in the browser preview's
process. The dev server forwards DevTools requests to it with
Agent.dispatch, and the
agent publishes events back through the publish callback its owner
supplies: the dev client sends them over the dev session, and the preview
hands them to the server directly.
Requests run on the application loop, so they see a consistent tree and may await. See the method table in RFC 0006 for the request names.
The agent also owns the device-side development UI, through the native
DevSupport module: the dev menu, the element inspector, the
highlight outline, and the performance monitor.
Classes:
| Name | Description |
|---|---|
MenuItem |
One dev menu entry. |
Agent |
Serve DevTools requests and publish app events. |
Functions:
| Name | Description |
|---|---|
current |
The process's agent, if one is installed. |
install |
Create, start, and register the process's agent (replacing any previous one). |
uninstall |
Stop and forget the process's agent (and restore |
Agent
¶
Agent(
publish: Publish,
*,
kind: str = "app",
disconnect: Optional[Callable[[], None]] = None,
reload: Optional[Callable[[], None]] = None
)
Serve DevTools requests and publish app events.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
publish
|
Publish
|
|
required |
kind
|
str
|
|
'app'
|
disconnect
|
Optional[Callable[[], None]]
|
Called by the dev menu's Disconnect item (Go only). |
None
|
reload
|
Optional[Callable[[], None]]
|
Remounts the app; defaults to reloading the app's modules and remounting every screen. |
None
|
Methods:
| Name | Description |
|---|---|
start |
Subscribe to warnings, errors, network requests, and native dev events. |
stop |
Undo |
dispatch |
Run request |
request |
Call a request handler directly (tests and the preview). |
rpc_tree |
Every live screen's component tree and the selected node. |
rpc_inspect |
One node's props, hooks, context, frame, and source; it becomes the selection. |
rpc_set_state |
Replace a |
rpc_highlight |
Outline node |
rpc_set_inspecting |
Turn the on-device element inspector on or off. |
rpc_eval |
Evaluate |
rpc_reload |
Remount the app with fresh state. |
rpc_menu |
Show the dev menu. |
rpc_perf |
Turn the DevTools panel's sampling (and optionally the on-device monitor) on or off. |
rpc_trace |
|
rpc_debug |
Start the in-process debug adapter; returns |
rpc_status |
What the agent is doing: inspector, monitor, sampling, debugger. |
set_perf_monitor |
Show or hide the floating on-device performance monitor. |
menu_items |
The dev menu's entries, in order. |
menu_subtitle |
The dev menu's message: what this client runs and where it's connected. |
open_menu |
Show the dev menu (from any thread). |
dispatch
¶
Run request method on the application loop and reply(result, error).
Safe to call from any thread. reply runs on the application
loop.
request
async
¶
Call a request handler directly (tests and the preview).
rpc_inspect
¶
One node's props, hooks, context, frame, and source; it becomes the selection.
rpc_set_state
¶
Replace a use_state slot of node id with a Python literal.
rpc_highlight
¶
Outline node id on screen, or clear the outline when id is None.
rpc_set_inspecting
¶
Turn the on-device element inspector on or off.
rpc_eval
async
¶
Evaluate code in the REPL namespace (see Console.evaluate).
rpc_perf
¶
Turn the DevTools panel's sampling (and optionally the on-device monitor) on or off.
rpc_trace
¶
"start" recording a Chrome trace, or "stop" and return it.
rpc_debug
async
¶
Start the in-process debug adapter; returns {"port"}.
rpc_status
¶
What the agent is doing: inspector, monitor, sampling, debugger.
set_perf_monitor
¶
set_perf_monitor(visible: bool) -> None
Show or hide the floating on-device performance monitor.
reload_app
¶
Re-import the app's modules and remount every screen with fresh state.
install
¶
Create, start, and register the process's agent (replacing any previous one).
Inspector¶
Read and edit the mounted component tree for DevTools.
Every ScreenHost owns a reconciler
whose mounted VNodes form the tree
DevTools shows. Node ids are id(vnode): nodes are reused across
renders, so an id stays valid while the node is mounted, and every lookup
walks the live trees, so a stale id simply isn't found.
Values are summarized with summarize
before they leave the process: DevTools sees short, typed descriptions,
never the objects themselves.
Functions:
| Name | Description |
|---|---|
find_node |
The mounted node whose id is |
find_node_by_tag |
The native node that owns view |
summarize |
A short, JSON-safe description of |
tree |
Every live screen's tree, as nested |
node_label_path |
Component names from the root down to |
inspect_node |
Props, hooks, context, frame, and source of one node. |
set_state |
Replace |
live_reconcilers
¶
(label, reconciler) for every live screen host.
find_node
¶
find_node(
node_id: int,
reconcilers: Optional[Iterable[Tuple[str, Any]]] = None,
) -> Optional[Any]
The mounted node whose id is node_id, or None.
find_node_by_tag
¶
find_node_by_tag(
tag: int,
reconcilers: Optional[Iterable[Tuple[str, Any]]] = None,
) -> Optional[Any]
The native node that owns view tag, or None.
summarize
¶
A short, JSON-safe description of value for DevTools.
Returns a dict with type (the class name), repr (a truncated
one-line description), and, for containers and dataclasses within
the depth limit, items (a list of [key, summary] pairs).
tree
¶
Every live screen's tree, as nested {"id", "name", "kind", ...} dicts.
node_label_path
¶
Component names from the root down to node, skipping framework components.
owner_component
¶
The nearest component at or above node (node itself for components).
native_root_tag
¶
The tag of the first native view node renders, if any.
inspect_node
¶
Props, hooks, context, frame, and source of one node.
set_state
¶
Replace use_state slot index of a component with a Python literal.
Raises:
| Type | Description |
|---|---|
ValueError
|
When |
Console¶
The DevTools REPL: evaluate Python inside the running app.
Code runs on the application loop, so it sees the same state components
do and may await (await pn.fetch(...), await asyncio.sleep(1)).
Each agent keeps one namespace across evaluations. It starts with
pn (pythonnative), asyncio, app (the entry module, once
imported), and node, a NodeHandle
for the component selected in DevTools.
Classes:
| Name | Description |
|---|---|
NodeHandle |
The component selected in DevTools, as seen from the REPL. |
Console |
One persistent REPL namespace. |
NodeHandle
¶
NodeHandle(vnode: Any)
The component selected in DevTools, as seen from the REPL.
Attributes are read live from the mounted node, so node.state
reflects the latest render.
Methods:
| Name | Description |
|---|---|
set_state |
Call the setter of |
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The component or view name. |
props |
Dict[str, Any]
|
The props the node last rendered with. |
state |
List[Any]
|
The values of its |
refs |
List[Any]
|
The |
Performance¶
Live performance numbers and trace capture for DevTools.
While DevTools' Performance panel or the on-device performance monitor is
open, Sampler keeps a
Profiler installed as the process
session and summarizes it once a second:
- Loop lag: how late a timer scheduled on the application loop fired, the Python counterpart of a dropped frame.
- Renders and commits: reconciler passes, components rendered, native commits, operations, and the time each phase took.
- UI frame rate: reported by the native
DevSupportmodule.
Trace capture records the same profiler's events into a Chrome trace document that Perfetto and Chrome's trace viewer open.
Classes:
| Name | Description |
|---|---|
Sampler |
Summarize runtime work once a second while enabled. |
Sampler
¶
Sampler(
publish: Callable[[Dict[str, Any]], None],
frame_stats: Optional[
Callable[[], Optional[Dict[str, Any]]]
] = None,
)
Summarize runtime work once a second while enabled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
publish
|
Callable[[Dict[str, Any]], None]
|
Called with each sample dict on the application loop. |
required |
frame_stats
|
Optional[Callable[[], Optional[Dict[str, Any]]]]
|
Returns the native UI thread's |
None
|
Methods:
| Name | Description |
|---|---|
acquire |
Start sampling (reference counted: the panel and the monitor share it). |
release |
Stop sampling once the last consumer releases it. |
start_trace |
Begin recording a trace (sampling may continue alongside it). |
stop_trace |
Stop recording and return the Chrome trace document. |
monitor_lines |
Text lines for the on-device performance monitor. |
Attributes:
| Name | Type | Description |
|---|---|---|
running |
bool
|
Whether samples are being produced. |
Debugger¶
Breakpoint debugging through debugpy, inside any dev client.
pn start accepts Debug Adapter Protocol connections on
127.0.0.1:5678 and asks the selected dev client to start a debug
adapter. start runs debugpy
with its adapter in this process (in_process_debug_adapter=True):
mobile platforms can't spawn the separate adapter process debugpy
normally uses. The adapter listens on a localhost port, which the dev
server reaches directly (the browser preview runs in its own process) or
through the dev session's tunnel (devices).
On a device debugpy arrives through the dev session's package sync:
the dev server sends its Python sources, without the compiled speedups,
into the overlay's site-packages. The pure-Python tracer is slower
than the compiled one, which only matters while a debugger is attached.
Path mapping makes breakpoints set in the editor bind on the device: the
dev server sends the host paths of the project, the pythonnative
package, and the installed packages, and the device maps its own copies
to them.
Functions:
| Name | Description |
|---|---|
mark_dev_thread |
Keep the debugger from tracing or suspending a development thread. |
attached |
Whether a debugger client is connected to this process. |
start |
Start the in-process debug adapter (once) and return its port. |
install_breakpoint_hook |
Make |
mark_dev_thread
¶
Keep the debugger from tracing or suspending a development thread.
The dev client's network and tunnel threads carry the debugger's own
traffic; pausing them at a breakpoint would freeze the session that
reports the breakpoint. pydevd skips threads marked this way.
start
¶
Start the in-process debug adapter (once) and return its port.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
host_paths
|
Optional[Dict[str, Any]]
|
|
None
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
When |
pythonnative.errors¶
Structured error reports for the development error screen and DevTools.
A traceback says where Python was; it doesn't say which component was
rendering, and it buries the application's frames among the
reconciler's. ErrorReport adds both:
- A component stack. In development mode the reconciler records the
component path while rendering, running effects, and updating, and
attaches it to an exception the first time the exception crosses a
component (see
add_component_frame). PythonNative's own components (navigators, host roots) are left out. The path also appears in the printed traceback as a note (PEP 678):
ZeroDivisionError: division by zero
The above error occurred in <Counter> (app/main.py:14)
in <HomeScreen> (app/main.py:30)
in <App> (app/main.py:52)
- Classified frames with source excerpts. Frames from PythonNative, the standard library, and installed packages are marked as framework frames, which the error screens collapse; application frames carry a few lines of source around the failing line.
The development error screen on iOS, Android, and in the browser preview
renders ErrorReport.to_dict,
and DevTools lists the same reports under Problems. Release builds never
build reports: the error screen is development-only.
Classes:
| Name | Description |
|---|---|
ComponentFrame |
One component in a component stack. |
StackFrame |
One traceback frame, classified and with a source excerpt. |
ErrorReport |
An error or warning, ready for an error screen or DevTools. |
Functions:
| Name | Description |
|---|---|
add_component_frame |
Record that |
component_stack |
The component stack recorded on |
project_path |
|
report |
Build an |
warning_report |
Build a warning report, attributed to the component rendering now, if any. |
ComponentFrame
dataclass
¶
One component in a component stack.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The component's display name. |
file |
str
|
The file that defines it, relative to the project when
possible ( |
line |
int
|
The first line of its definition ( |
Methods:
| Name | Description |
|---|---|
describe |
|
to_dict |
The JSON shape native error screens and DevTools read. |
StackFrame
dataclass
¶
StackFrame(
file: str,
line: int,
function: str,
code: str = "",
excerpt: Tuple[Tuple[int, str], ...] = (),
framework: bool = False,
)
One traceback frame, classified and with a source excerpt.
Attributes:
| Name | Type | Description |
|---|---|---|
file |
str
|
The frame's file, relative to the project for application
code ( |
line |
int
|
The line number. |
function |
str
|
The function name. |
code |
str
|
The failing line's source, stripped. |
excerpt |
Tuple[Tuple[int, str], ...]
|
|
framework |
bool
|
Whether the frame belongs to PythonNative, the standard library, or an installed package. |
Methods:
| Name | Description |
|---|---|
excerpt_text |
The excerpt as text, with |
to_dict |
The JSON shape native error screens and DevTools read. |
ErrorReport
dataclass
¶
ErrorReport(
phase: str,
type: str,
message: str,
component_stack: Tuple[ComponentFrame, ...] = (),
frames: Tuple[StackFrame, ...] = (),
text: str = "",
level: str = "error",
timestamp: float = 0.0,
)
An error or warning, ready for an error screen or DevTools.
Attributes:
| Name | Type | Description |
|---|---|---|
phase |
str
|
Where it happened: |
type |
str
|
The exception's class name ( |
message |
str
|
|
component_stack |
Tuple[ComponentFrame, ...]
|
Innermost component first. |
frames |
Tuple[StackFrame, ...]
|
Innermost frame last, like a traceback. |
text |
str
|
The formatted traceback, notes included. |
level |
str
|
|
Methods:
| Name | Description |
|---|---|
to_dict |
The JSON shape native error screens and DevTools read. |
add_component_frame
¶
add_component_frame(
exc: BaseException, component: Any
) -> None
Record that exc passed through component while unwinding.
The reconciler calls this, innermost component first, as an exception
leaves each component it was rendering. The stack is kept on the
exception and mirrored into one PEP 678 note, which is rewritten as
frames are added so the printed traceback always shows the full path.
Built-in containers (Column, Text) aren't components and don't
appear.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exc
|
BaseException
|
The propagating exception. |
required |
component
|
Any
|
A |
required |
complete_component_stack
¶
complete_component_stack(
exc: BaseException, components: Sequence[Any]
) -> None
Append components (innermost first) and stop collecting.
Used when an update or effect fails in the middle of the tree: the reconciler knows the remaining ancestors from the mounted nodes, so the stack is completed at once and later frames are ignored.
component_stack
¶
component_stack(
exc: BaseException,
) -> Tuple[ComponentFrame, ...]
The component stack recorded on exc (innermost first), or ().
project_path
¶
filename relative to the project (app/main.py) when it's app code.
Device builds load the app from their bundle or the dev client's
overlay; both hold an app/ package, so the project-relative path is
the same everywhere and the dev server can map it back to a file on
the developer's machine. Anything else is returned unchanged.
report
¶
report(
exc: BaseException, phase: str = "runtime"
) -> ErrorReport
Build an ErrorReport for exc.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exc
|
BaseException
|
The exception, with its traceback. |
required |
phase
|
str
|
Where it happened ( |
'runtime'
|