wish.session

The one live connection, and the state machine around it.

VICE serves exactly one binary-monitor connection at a time. It accepts a second TCP connection and then silently ignores it, so a window whose tabs each opened their own would hang the second one with no error to show for it. This class owns a single Target for the window’s lifetime and hands it to whichever tab is visible.

Three ordinary states, none of them an error: nothing to attach to, attached, and attached-then-gone. The session moves between them on its own – quitting the emulator and starting it again needs no intervention – and says which one it is in through note, which is what the status bar shows.

Only the visible tab polls. set_reader is how a tab says “read this for me”; switching tabs changes what is read, not how often, and a tab that is not showing costs nothing. The cost of a poll is per round trip, so this matters more than it looks: under VICE each resume hands the emulation ~14.3 ms of extra emulated time, and on a network device each trip is a network trip.

Classes

Session

One Target, shared, with attach and reattach handled for you.

class wish.session.Session[source]

Bases: PyQt6.QtCore.QObject

One Target, shared, with attach and reattach handled for you.

__init__(preferred=None, interval_ms=None, parent=None, find=None)[source]
Parameters:
attach()[source]

Attach if something is answering. Idempotent: one target, always.

Returns True while connected, including when it already was – a tab asking twice must not open a second connection.

Return type:

bool

changed

alias of str

close()[source]
Return type:

None

detach(note='disconnected')[source]

Drop the connection and go back to waiting. Never raises.

Parameters:

note (str)

Return type:

None

property interval_ms: int

The poll interval this backend wants, unless told otherwise.

A device on the end of a network cable cannot be asked as often as a loopback socket, so the number belongs to the backend and not to the window. While there is nothing attached this is the retry interval instead – there is nothing to poll, only something to look for.

poll()[source]

One tick: attach if needed, then read what the visible tab asked for.

An error that is not NotConnected is reported and swallowed. The map has run for hours beside a game; a transient bad read is not a reason to take the window down, and the next tick usually fixes it.

Return type:

None

prefer(name)[source]

Choose which backend to attach to, or None for whichever answers.

A different backend already attached is dropped, so the next poll reattaches to the chosen one: the whole point of choosing is to be on the other one, and waiting for the emulator to go away first would look like the menu had done nothing.

Parameters:

name (str | None)

Return type:

None

set_interval(interval_ms)[source]

Poll this often instead of the backend’s own. 0 gives it back.

The preference and --interval land here; the backend’s own number is the default because it is a fact about the transport – 200 ms for a loopback monitor, 500 for a device on a network cable.

Parameters:

interval_ms (int | None)

Return type:

None

set_reader(reader)[source]

What the visible tab wants read. None means nothing is watching.

Parameters:

reader (Callable[[automap.target.Target], None] | None)

Return type:

None

start()[source]
Return type:

None

property state: str
stop()[source]
Return type:

None