orthonym.validation.opsin_server#

Note

Internal API. Names and behaviour may change between releases.

Persistent OPSIN process — amortize the ~1.7s JVM startup across every call.

The validity gate (namer.py -> OpsinOracle) shells out java -jar opsin -r -osmi once per distinct name; on a full gate that is ~2000 fresh JVM boots (~1.7s each ≈ 50+ min of pure startup). OPSIN’s CLI reads names line-by-line from stdin and emits exactly ONE line per input (the SMILES, or a BLANK line when it rejects the name) and flushes each line interactively — so a single long-lived JVM fed over a pipe gives one startup for the whole run.

Contract preserved verbatim for the caller (OpsinOracle._invoke_opsin): invoke(name) -> (raw_smiles_or_None, ran)

  • (smiles, True) — OPSIN parsed the name;

  • (None, True) — OPSIN ran and DEFINITIVELY rejected it (blank line);

  • (None, False) — the parse could not be performed (server absent / dead / read timeout / protocol anomaly). The caller treats this as transient and MUST fall back (to a one-shot subprocess.run), so correctness NEVER depends on this optimization — it only removes latency.

Safety: a per-read timeout + auto-restart means a hung/crashed JVM degrades to (None, False) (caller falls back) rather than blocking the gate. A single lock serializes access (the pipe is one ordered stream; the gate is single-threaded per the historical [99Tc] ThreadPoolExecutor-hang lesson).

class orthonym.validation.opsin_server.PersistentOpsin(jar, args=('-r', '-osmi'), read_timeout=15.0)#

Bases: object

One long-lived java -jar opsin... process fed names over stdin.

close()#
invoke(name)#

Feed one name; return (raw_smiles_or_None, ran). Never raises.

orthonym.validation.opsin_server.get_persistent_opsin(jar, args=('-r', '-osmi'))#

Shared PersistentOpsin for jar/args; None if no jar.