Skip to content

deeporigin.drug_discovery.secondary_pharma

SecondaryPharmacology drives platform tool deeporigin.secondary-pharma. It scores ligands against a baked kinase panel, using either a served ligand-ML path (method="ligand-ml", use run()) or an async docking workflow (method="docking", use start()). See the tool guide for the full explanation of why these are separate execution modes on one class.

SecondaryPharmacology -- score ligands against a baked kinase panel.

Backed by the platform tool deeporigin.secondary-pharma, which supports two mutually exclusive scoring methods selected at construction:

  • "ligand-ml" -- served, synchronous XGBoost booster scoring. Use :meth:run.
  • "docking" -- Argo workflow, asynchronous only. Use :meth:start (and :meth:watch in Jupyter).

The tool schema has no inputs.sync field (unlike deeporigin.docking), so method alone determines execution modality -- there is no unified blocking/ non-blocking call across both paths. :meth:get_results always returns a :class:pandas.DataFrame regardless of method (method-aware columns), but the two paths load from different places: ligand-ml is served/sync, so results come back in the same response's jobOutputs; docking is an async Argo workflow, so results are only ever persisted to result-explorer (jobOutputs on a polled execution is empty) -- same reason Docking.get_results() tries result-explorer before jobOutputs. Use get_results()'s pose_score/ binding_energy columns for docking results -- pose visualization isn't available yet (DDOS-7481).

Usage::

from deeporigin.drug_discovery import SecondaryPharmacology, Ligand

ligand = Ligand.from_smiles("CCO")

ml = SecondaryPharmacology(ligands=[ligand], method="ligand-ml")
df = ml.run()

dock = SecondaryPharmacology(ligands=[ligand], method="docking", effort=2)
dock.start()
dock.wait()
df = dock.get_results()  # pose_score, binding_energy, etc.

Attributes

Classes

SecondaryPharmacology

Bases: Execution, SyncExecutableMixin, AsyncExecutableMixin, NotebookWatchMixin

Score ligands against a baked secondary-pharmacology kinase panel.

Attributes:

Name Type Description
ligands list[Ligand]

Ligands to score. Empty only when :attr:self_test is True.

method str

Scoring path for this instance -- "docking" (async workflow, use :meth:start) or "ligand-ml" (served, use :meth:run).

uniprots list[str] | tuple[str, ...] | None

Panel accessions to restrict scoring to, or None for the whole panel. Validated against the live tool definition's enum.

effort int

Docking effort level (1 = fastest, 5 = most thorough). Ignored on the ligand-ml path.

batch_size int

Panel cells (ligand x target) packed per docking leaf -- a soft cap; a single target's cells are never split across leaves. Ignored on the ligand-ml path.

self_test bool

When True, runs a served ligand-ml health-check against the full panel with a baked test ligand and ignores :attr:ligands. Not supported with method="docking".

Attributes

USER_LOG_COLUMNS class-attribute
USER_LOG_COLUMNS: list[str] = [
    "log_level",
    "tool_key",
    "timestamp",
    "message",
]
app instance-attribute
app: str | None = None
approve_amount instance-attribute
approve_amount: int | None = None
batch_size property
batch_size: int

Panel cells packed per docking leaf (default 30). Read-only.

Ignored on the ligand-ml path.

client instance-attribute
client: DeepOriginClient = client
completed_at instance-attribute
completed_at: str | None = None
cost property
cost: float | None

Actual cost in dollars, set after execution completes.

This property cannot be set manually.

created_at instance-attribute
created_at: str | None = None
created_by instance-attribute
created_by: str | None = None
dto property
dto: dict[str, Any] | None

Last tools execution DTO from the platform, if any.

effort class-attribute instance-attribute
effort: int = effort
estimate property
estimate: float | None

Cost estimate in dollars, populated when the platform returns a quotation.

Set after run(quote=True), start(quote=True), or any call with approve_amount=-1. None until a quotation result is received. This property cannot be set manually.

id property
id: str | None

Platform execution ID when set (read-only).

ligands property
ligands: list[Ligand]

Ligands targeted by this run (read-only).

method property
method: str

Scoring path for this instance ("docking" or "ligand-ml").

name instance-attribute
name = (
    name
    if name is not None
    else _secondary_pharma_default_name(
        method=self._method,
        ligands=self._ligands,
        uniprots=self._uniprots,
        self_test=self._self_test,
    )
)
progress instance-attribute
progress: dict | None = None
runtime property
runtime: float | None

Seconds from DTO startedAt to completedAt or current UTC time.

Uses :attr:dto (same shape as client.executions.get). When completedAt is present, it is the end time; otherwise the end time is datetime.now(timezone.utc). Returns None if there is no DTO or startedAt is missing or empty.

self_test property
self_test: bool

Whether this run scores the baked test ligand against the full panel.

session instance-attribute
session: str | None = None
started_at instance-attribute
started_at: str | None = None
status instance-attribute
status: PlatformStatus | None = None
tool_key class-attribute instance-attribute
tool_key: str = TOOL_KEYS_AND_VERSIONS["secondary_pharma"][
    "tool_key"
]
tool_version instance-attribute
tool_version = tool_version
uniprots property writable
uniprots: list[str] | tuple[str, ...] | None

Panel accessions this run is restricted to, or None for the whole panel.

A mutable list on a draft instance. After an execution id is set, a tuple. None when unset or a rehydrated execution omitted the field.

Methods:

cancel
cancel() -> None

Cancel a running or queued execution.

Raises:

Type Description
ValueError

If the job has no execution ID.

ValueError

If the job is not in a cancellable state.

confirm
confirm() -> None

Confirm a quoted tools execution on the platform.

Requires :attr:id and status equal to "Quoted". Uses :meth:~deeporigin.platform.executions.Executions.confirm with :data:~deeporigin.utils.constants.TOOL_EXECUTION_POST_TIMEOUT_SECONDS (10 minutes) and retry=False, then applies the returned DTO via :meth:update_from_dto so status, :attr:cost, and :attr:dto reflect the platform response. For direct (blocking) tools the response is typically terminal (Completed); for async tools it may be Created or Running — call :meth:sync until the job finishes.

Raises:

Type Description
ValueError

If there is no platform execution id or status is not "Quoted".

duplicate
duplicate(
    *, client: DeepOriginClient | None = None
) -> Self

Copy configuration into a new draft with a writable uniprots.

from_dto does not fetch the tool definition, so a rehydrated instance has no allowlist. Fetch it here so the draft can assign uniprots like a constructor-built instance.

from_dto classmethod
from_dto(
    dto: dict[str, Any],
    *,
    client: DeepOriginClient | None = None
) -> Self

Construct a SecondaryPharmacology from a tools execution DTO.

Restores ligands, method, uniprots, effort, and self_test from userInputs, and batch_size from the execution's top-level batchSize field (or its metadata, for an older execution record) -- like batch_size, batchSize is not a schema input, so it doesn't live in userInputs. Does not fetch the live tool definition, so a rehydrated instance's uniprots is read-only until :meth:duplicate is called.

Parameters:

Name Type Description Default
dto dict[str, Any]

Execution payload (same shape as client.executions.get).

required
client DeepOriginClient | None

Optional API client. Uses the default if not provided.

None

Returns:

Type Description
Self

A SecondaryPharmacology with id, lifecycle fields, and

Self

domain inputs set.

from_id classmethod
from_id(
    id: str,
    *,
    client: DeepOriginClient | None = None,
    quiet: bool = True
) -> Self

Same as :meth:Execution.from_id, but quiet defaults to True.

Rebuilding ligands from stored inputs can emit chemistry normalization warnings (naming the raw SMILES) -- not useful noise when you're just reloading a run you already know about. Pass quiet=False to see them.

from_last_run classmethod
from_last_run(
    *,
    client: DeepOriginClient | None = None,
    quiet: bool = True
) -> Self

Same as :meth:Execution.from_last_run, but quiet defaults to True.

get_missing_pairs
get_missing_pairs() -> list[tuple[Ligand, str]] | None

(ligand, uniprot) pairs with no docked pose, or None if complete.

Valid only when :attr:method is "docking".

get_panel classmethod
get_panel(
    *,
    full: bool = False,
    tool_version: str = TOOL_KEYS_AND_VERSIONS[
        "secondary_pharma"
    ]["tool_version"],
    client: DeepOriginClient | None = None
) -> DataFrame

Return the current scoring panel, no ligand or instance required.

Both methods validate uniprots against this same panel today -- docking and ligand-ml are expected to grow independent, differently sized catalogs later, which this method will need to account for then.

Parameters:

Name Type Description Default
full bool

Return every member instead of just a preview.

False
tool_version str

Platform tool version to look up. Defaults to the pinned major version in :data:TOOL_KEYS_AND_VERSIONS.

TOOL_KEYS_AND_VERSIONS['secondary_pharma']['tool_version']
client DeepOriginClient | None

Optional API client. Uses the default if not provided.

None

Returns:

Name Type Description
A DataFrame

class:pandas.DataFrame with one row per panel member

DataFrame

(uniprot_id, gene_name).

get_results
get_results(dto: dict[str, Any] | None = None) -> DataFrame

Return this execution's results as a :class:pandas.DataFrame.

Method-aware, and the two paths load from different places:

  • ligand-ml is served/sync, so jobOutputs is populated in the same response that completed the run -- read directly, like :meth:Admet.get_results <deeporigin.drug_discovery.admet.Admet.get_results>.
  • docking is an async Argo workflow with no synchronous response to embed results into, so it only ever persists rows to result-explorer; jobOutputs on a polled execution is empty. Loaded via :func:_load_panel_pose_rows, mirroring :func:~deeporigin.drug_discovery.docking_common.load_docking_poses_from_execution's result-explorer-first, jobOutputs-fallback shape.

The docking-path DataFrame includes pose_score, binding_energy, and file_path per pose. Every row also carries a method column ("ligand-ml" or "docking").

Parameters:

Name Type Description Default
dto dict[str, Any] | None

Optional execution payload (executions.create / executions.get). On the ligand-ml path, used directly instead of an extra GET. On the docking path, only consulted as a fallback if result-explorer has no rows yet.

None

Returns:

Type Description
DataFrame

A DataFrame of ligand_ml_predictions or panel_poses rows.

Raises:

Type Description
ValueError

If :attr:id is unset and dto is omitted.

DeepOriginException

If no rows could be loaded.

get_undocked_ligands
get_undocked_ligands() -> LigandSet | None

Ligands with zero docked poses, or None if none. Docking only.

A ligand with at least one docked pose won't appear here, even if it's missing poses for other targets -- use :meth:get_missing_pairs for that.

get_user_logs
get_user_logs(
    *,
    limit: int | None = None,
    offset: int | None = None,
    select: list[str] | None = None,
    with_total_count: bool = False
) -> DataFrame | None

Search data-platform user_logs rows for this execution.

Uses :meth:deeporigin.platform.user_logs.UserLogs.search with this execution's id (tools executionId), stored as execution_id on user_logs rows — the same string passed to :meth:get_results as compute_job_id.

When no execution id is assigned yet, returns None without calling the API.

Parameters:

Name Type Description Default
limit int | None

Max rows to return (forwarded to UserLogs.search).

None
offset int | None

Skip offset (forwarded).

None
select list[str] | None

Columns to select (forwarded).

None
with_total_count bool

Request total count from the server (forwarded).

False

Returns:

Type Description
DataFrame | None

A DataFrame with columns log_level, tool_key, timestamp,

DataFrame | None

and message. tool_key omits the deeporigin. prefix;

DataFrame | None

timestamp is a compact humanized relative time. Returns None

DataFrame | None

if this instance has no execution id yet or the client has no

DataFrame | None

user_logs API.

list classmethod
list(
    *,
    client: DeepOriginClient | None = None,
    status: list[str] | None = None,
    quiet: bool = True
) -> list[Self]

Same as :meth:Execution.list, but quiet defaults to True.

plot
plot(
    *,
    dto: dict[str, Any] | None = None,
    metric: Literal[
        "binding_energy", "pose_score"
    ] = "binding_energy",
    clim: tuple[float, float] | None = None
) -> None

Visualize this run's results -- method-aware.

ligand-ml: heatmap colored by p_active. docking: heatmap colored by metric.

Parameters:

Name Type Description Default
dto dict[str, Any] | None

Optional execution payload, forwarded to :meth:get_results.

None
metric Literal['binding_energy', 'pose_score']

Docking only. Which column to color the heatmap by.

'binding_energy'
clim tuple[float, float] | None

Override the default color range. A value outside the chosen range still renders, clipped to the nearest edge color.

None
run
run(
    *,
    quote: bool = False,
    approve_amount: int | None = None
) -> DataFrame | SecondaryPharmacology

Execute the ligand-ml path synchronously and return predictions.

Valid only when :attr:method is "ligand-ml"; use :meth:start for the docking path.

With quote=True (or approve_amount=0), requests a cost estimate only, updates execution fields from the platform DTO, and returns self without running inference.

Parameters:

Name Type Description Default
quote bool

Shorthand for approve_amount=0.

False
approve_amount int | None

Spend cap forwarded as approveAmount.

None

Returns:

Name Type Description
A DataFrame | SecondaryPharmacology

class:pandas.DataFrame of ligand-ml predictions, or self

DataFrame | SecondaryPharmacology

when quoting.

Raises:

Type Description
ValueError

If :attr:method is not "ligand-ml", or if uniprots was mutated in place into an invalid selection.

DeepOriginException

If effort is outside 1-5, or the execution did not complete successfully.

show
show() -> None

Display the current execution in Jupyter using the execution card HTML view.

If no platform execution ID exists yet, shows the same card with a short notice instead of raising (see :meth:~deeporigin.platform.execution_display.ExecutionDisplay.from_pending).

start
start(
    *,
    quote: bool = False,
    approve_amount: int | None = None,
    **kwargs
) -> None

Submit a persisted async execution to the platform.

Only valid when status is None (no execution exists yet). All other statuses raise immediately to prevent re-submission.

Pass quote=True or approve_amount=-1 to request a cost estimate without running. If the platform returns a Quoted DTO the instance is left in that state — call :meth:~deeporigin.drug_discovery.execution.Execution.confirm explicitly to proceed.

Parameters:

Name Type Description Default
quote bool

Shorthand for approve_amount=-1. Takes precedence when both quote and approve_amount are provided.

False
approve_amount int | None

Spend cap passed to the platform as approveAmount. -1 (or any negative value) forces a quote-only create. None omits the field (platform may auto-confirm).

None
**kwargs

Forwarded verbatim to _start_impl.

{}

Raises:

Type Description
ValueError

If the current status is not None.

stop_watching
stop_watching() -> None

Cancel an in-flight watch loop if one is running.

Safe to call when no watch is active. Does not cancel the caller's current task when invoked from inside the watch loop.

sync
sync() -> None

Fetch the latest tools execution from the platform and refresh fields.

Calls client.executions.get for :attr:id and applies the response with :meth:update_from_dto. Use when the job may have changed outside this process (for example after submission from the web UI), to poll lifecycle state, or to refresh an instance built from an older DTO. Available on sync-only and async execution types alike.

If executions.get returns a falsy value, this instance is left unchanged.

Raises:

Type Description
ValueError

If this instance has no execution id yet.

NotImplementedError

If type(self).tool_key is empty (bare :class:Execution).

ValueError

If the returned DTO tool.key does not match this class (see :meth:update_from_dto).

update_from_dto
update_from_dto(dto: dict[str, Any]) -> None

Apply execution fields from dto and freeze uniprots.

wait
wait(
    *,
    poll_interval: float = 5.0,
    timeout: float | None = None
) -> dict[str, Any] | None

Block until this execution reaches a terminal state.

Parameters:

Name Type Description Default
poll_interval float

Seconds to sleep between polling cycles.

5.0
timeout float | None

Maximum total seconds to wait. If None, waits indefinitely.

None

Returns:

Type Description
dict[str, Any] | None

The latest execution DTO, or None if the platform returned no DTO.

Raises:

Type Description
ValueError

If this instance has no execution id yet.

TimeoutError

If timeout elapses before the execution terminates.

watch async
watch(
    *, interval: float = 5.0, blocking: bool = False
) -> Task | None

Live notebook updates for the docking path only.

Valid only when :attr:method is "docking" -- the ligand-ml path is synchronous (:meth:run blocks until done), so there is never an in-flight async job to poll.

See :meth:~deeporigin.drug_discovery.notebook_watch_mixin.NotebookWatchMixin.watch for the full parameter/return contract.

Raises:

Type Description
ValueError

If :attr:method is not "docking".

Functions: