deeporigin.drug_discovery.secondary_pharma¶
SecondaryPharmacology drives platform tool deeporigin.secondary-pharma. It
scores ligands against a baked off-target 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 off-target panel.
Backed by the platform tool deeporigin.secondary-pharma, which offers two
mutually exclusive scoring methods, chosen at construction:
"ligand-ml"-- served, synchronous XGBoost booster scoring. Use :meth:run."docking"-- asynchronous Argo workflow. Use :meth:start(and :meth:watchin Jupyter).
The tool schema has no inputs.sync field (unlike deeporigin.docking), so
method alone decides the execution mode. :meth:get_results returns a
:class:pandas.DataFrame either way, but reads from different places: ligand-ml
results come back in the run's jobOutputs, while docking results are only in
result-explorer (jobOutputs is empty for an async run). For the docked poses
themselves, use :meth:get_poses; each pose carries the path of its verified
panel receptor in pose.props["receptor_local_path"] when the run recorded
one. :meth:show_panel_pose shows one in its pocket.
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 panel.
Attributes:
| Name | Type | Description |
|---|---|---|
ligands |
list[Ligand]
|
Ligands to score. Empty only when :attr: |
method |
str
|
Scoring path for this instance -- |
uniprots |
list[str] | tuple[str, ...] | None
|
Panel accessions to restrict scoring to, or |
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 |
Attributes¶
USER_LOG_COLUMNS
class-attribute
¶
USER_LOG_COLUMNS: list[str] = [
"log_level",
"tool_key",
"timestamp",
"message",
]
batch_size
property
¶
batch_size: int
Panel cells packed per docking leaf (default 30). Read-only.
Ignored on the ligand-ml path.
cost
property
¶
cost: float | None
Actual cost in dollars, set after execution completes.
This property cannot be set manually.
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.
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,
)
)
panel_version
property
¶
panel_version: str | None
The panel version this run's results were produced against (docking only).
Read from the run's own results, so it is set once they're loaded
(:meth:get_results, :meth:get_poses or a gap check) and None before
that, for ligand-ml runs, and for runs from before results named their panel.
What you asked for (:attr:uniprots) is left as requested.
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.
tool_key
class-attribute
instance-attribute
¶
tool_key: str = TOOL_KEYS_AND_VERSIONS["secondary_pharma"][
"tool_key"
]
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
|
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 |
required |
client
|
DeepOriginClient | None
|
Optional API client. Uses the default if not provided. |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
A |
Self
|
domain inputs set. |
from_id
classmethod
¶
from_id(
id: str, *, client: DeepOriginClient | None = None
) -> Self
Construct an instance from an existing platform execution ID.
Fetches the execution DTO via client.executions.get and delegates to
:meth:from_dto. Concrete subclasses override :meth:from_dto to attach
domain state from userInputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
id
|
str
|
Platform execution ID. |
required |
client
|
DeepOriginClient | None
|
Optional API client. Uses the default if not provided. |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
A partially-hydrated instance with common fields populated. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If |
from_last_run
classmethod
¶
from_last_run(
*, client: DeepOriginClient | None = None
) -> Self
Construct an instance from the most recently created execution of this tool.
Scoped to the client's project, like :meth:list. Calls
client.executions.list with tool_key, order set to
:data:~deeporigin.utils.constants.EXECUTION_LIST_ORDER_CREATED_DESC,
the client's project_id, and page_size=1, then delegates to
:meth:from_dto. Concrete subclasses inherit this method; domain
state is restored via their from_dto overrides.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
DeepOriginClient | None
|
Optional API client. Uses the default if not provided. |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
A partially-hydrated instance for the newest execution by |
Self
|
|
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If |
ValueError
|
If no executions exist for this tool type. |
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,
panel_version: str | None = None,
tool_version: str = TOOL_KEYS_AND_VERSIONS[
"secondary_pharma"
]["tool_version"],
client: DeepOriginClient | None = None
) -> DataFrame
Return the current scoring panel, or an earlier version of it.
No ligand or instance needed. Pass panel_version (e.g. a run's
:attr:panel_version) to get exactly the panel that run used, even if the panel
has changed since. Both methods validate uniprots against this same panel
today; they may grow separate catalogs later.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
full
|
bool
|
Return every member instead of a preview. |
False
|
panel_version
|
str | None
|
An immutable panel version to look up instead of the current panel. |
None
|
tool_version
|
str
|
Platform tool version to look up (ignored when
|
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: |
DataFrame
|
|
Raises:
| Type | Description |
|---|---|
DeepOriginException
|
If |
get_poses
¶
get_poses(
*,
verify_receptor_digest: bool = True,
dto: dict[str, Any] | None = None
) -> PoseSet
Download this docking run's poses, each with its panel receptor.
Docking only. Loads the run's panel_poses rows (as :meth:get_results
does), builds a :class:PoseSet and downloads the pose files, like
:meth:Docking.get_poses <deeporigin.drug_discovery.docking.Docking.get_poses>.
Each pose whose row names a receptor_file_path also gets the receptor it was
docked into, downloaded once per distinct receptor (cached) and checked against
the row's structure_sha256; its local path is in
pose.props["receptor_local_path"]. Rows without a receptor path (runs from
before receptors were recorded) still yield a pose, just without that key.
These are panel poses, not registered poses, so they have no pose result id and
can't be passed to tools that take a registered Pose (e.g. ABFE, RBFE). Not
available for self_test runs, which publish no panel poses. To view one pose
in its pocket, use :meth:show_panel_pose.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
verify_receptor_digest
|
bool
|
Reject a receptor whose bytes don't match the row's
|
True
|
dto
|
dict[str, Any] | None
|
Optional execution payload, forwarded to :func: |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
PoseSet
|
class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If :attr: |
DeepOriginException
|
If a row's |
get_results
¶
get_results(dto: dict[str, Any] | None = None) -> DataFrame
Return this execution's results as a :class:pandas.DataFrame.
Ligand-ml results are read from the run's jobOutputs (like
:meth:Admet.get_results <deeporigin.drug_discovery.admet.Admet.get_results>).
Docking is an async workflow, so its rows are read from result-explorer, falling
back to jobOutputs (see :func:_load_panel_pose_rows). Docking rows include
pose_score, binding_energy and file_path; every row has a method
column.
The ligand-ml path drops the platform's unused p_affinity column. Each row
sets exactly one of p_active / p_affinity, so a NaN p_active is
that omission, not missing data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dto
|
dict[str, Any] | None
|
Optional execution payload. Ligand-ml reads it instead of making an extra GET; docking consults it only if result-explorer has no rows yet. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
A DataFrame of |
Raises:
| Type | Description |
|---|---|
ValueError
|
If :attr: |
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 |
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 |
DataFrame | None
|
and |
DataFrame | None
|
|
DataFrame | None
|
if this instance has no execution id yet or the client has no |
DataFrame | None
|
|
list
classmethod
¶
list(
*,
client: DeepOriginClient | None = None,
status: list[str] | None = None
) -> list[Self]
List executions of this tool, newest first, scoped to the client's project.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
DeepOriginClient | None
|
Optional API client. Uses the default if not provided. |
None
|
status
|
list[str] | None
|
Optional list of statuses to keep. |
None
|
Returns:
| Type | Description |
|---|---|
list[Self]
|
Instances of this class, newest first. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If |
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: |
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 |
False
|
approve_amount
|
int | None
|
Spend cap forwarded as |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
DataFrame | SecondaryPharmacology
|
class: |
DataFrame | SecondaryPharmacology
|
when quoting. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If :attr: |
DeepOriginException
|
If |
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).
show_panel_pose
¶
show_panel_pose(
*,
ligand_id: str | None = None,
ligand: Ligand | None = None,
uniprot_id: str | None = None,
gene_name: str | None = None,
verify_receptor_digest: bool = True,
height: int = 620,
dto: dict[str, Any] | None = None
)
Show one docked pose in its target's pocket, in a Jupyter notebook.
Downloads the pose's panel receptor (checked against its recorded checksum) and
overlays the docked ligand on it in an interactive Mol* viewer. Choose the pose
by ligand and by target. Needs a completed docking run whose results record
their receptor; use :meth:get_poses to work with poses in code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ligand_id
|
str | None
|
Platform ligand id (from |
None
|
ligand
|
Ligand | None
|
A ligand, instead of |
None
|
uniprot_id
|
str | None
|
Panel target accession. |
None
|
gene_name
|
str | None
|
Panel target gene symbol, matched against this run's results
(instead of |
None
|
verify_receptor_digest
|
bool
|
Verify the downloaded receptor against the row's
|
True
|
height
|
int
|
Iframe height in pixels. |
620
|
dto
|
dict[str, Any] | None
|
Optional execution payload for loading pose rows. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
The |
func: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If :attr: |
DeepOriginException
|
If the row has no |
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 |
False
|
approve_amount
|
int | None
|
Spend cap passed to the platform as |
None
|
**kwargs
|
Forwarded verbatim to |
{}
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the current status is not |
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.
Rejected executions are refreshed without raising for their status, so history inspection and notebook displays remain available. HTTP failures while fetching the execution still raise.
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 |
ValueError
|
If the returned DTO |
update_from_dto
¶
update_from_dto(dto: dict[str, Any]) -> None
Apply execution fields from dto, freeze uniprots, drop a stale panel version.
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
|
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The latest execution DTO, or |
Raises:
| Type | Description |
|---|---|
ValueError
|
If this instance has no execution id yet. |
TimeoutError
|
If |
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: |