feat(secondary-pharma): public get_poses with verified receptor, project-scoped from_last_run (DDOS-8005) - #646
Merged
ASinanSaglam merged 8 commits intoSep 30, 2026
Conversation
sg-s
approved these changes
Sep 30, 2026
sg-s
left a comment
Collaborator
There was a problem hiding this comment.
@ASinanSaglam approving, but please resolve conflicts and merge
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
URL path validation misses query and fragment delimiters, and documentation overpromises receptor availability for legacy rows.
Review effort: Balanced
Findings: 1
Open (3)
What changed in this PR
Adds project-scoped execution discovery and public, receptor-aware Secondary Pharmacology pose APIs.
Changes:
- Scopes execution listing and latest-run lookup by project.
- Adds verified receptor downloads, panel-version tracking, and pose visualization.
- Updates tests, mock-server fixtures, plots, and documentation.
| File | Description |
|---|---|
src/drug_discovery/execution.py |
Adds project scoping and removes quiet. |
src/drug_discovery/protein_prep.py |
Removes redundant execution lookup overrides. |
src/drug_discovery/secondary_pharma.py |
Adds public pose APIs and panel-version handling. |
src/plots.py |
Makes heatmap value labels configurable. |
tests/test_executions.py |
Tests project-scoped execution discovery. |
tests/test_secondary_pharma.py |
Tests poses, receptors, panels, and scoping. |
tests/test_plots.py |
Tests configurable hover labels. |
tests/conftest.py |
Isolates download caches during tests. |
tests/mock_server/server.py |
Seeds panel catalogs and structure files. |
tests/mock_server/routers/tools.py |
Updates mock panel metadata. |
docs/notebooks/clean/secondary-pharma.ipynb |
Demonstrates pose download and visualization. |
docs/dd/tools/secondary-pharma.md |
Documents new Secondary Pharmacology APIs. |
docs/dd/ref/secondary_pharma.md |
Updates API terminology. |
docs/dd/tools/proteinprep.md |
Updates execution-reconnection guidance. |
docs/dd/tools/overview.md |
Documents project-scoped history methods. |
docs/dd/tools/docking.md |
Clarifies latest-run project scope. |
CONTEXT.md |
Defines project, panel, and panel-pose terminology. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
plot_heatmap hardcoded 'RMSD' in the hover text; add value_label (default 'RMSD') so binding-energy and pose-score heatmaps label themselves. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…_panel_pose, project-scoped from_last_run (DDOS-8005) - get_poses() is public: downloads each pose's panel receptor once, verifies structure_sha256, sets props['receptor_local_path']; rows without a receptor_file_path yield poses without one; paths outside protected/ or containing '..', '%' or NUL are rejected before any download - panel_version (immutable volume_key) is stamped from result rows; gap checks and get_panel(panel_version=...) read that panel's members.json - show_panel_pose() is public; matches a ligand without an id by SMILES - Execution.from_last_run() passes project_id=client.project_id like list() - remove the quiet= flag and _from_dto_maybe_quiet - delete ProteinPrep list/from_last_run overrides (vestigial after #639) - de-duplicate SecondaryPharmacology.plot(); condense docstrings - tests: discovery-based scoping checks over every Execution subclass, project_id=None cases, mock panel catalog/receptor, isolated HOME fixture Addresses the post-merge review of #630. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ct scoping (DDOS-8005) - user guide, API ref and notebook samples for get_poses / show_panel_pose - 'in your current project' scoping wording in tools overview and docking - drop stale ProteinPrep 'either routed tool' wording - CONTEXT.md: Project scope, Panel, Panel pose; 'off-target panel' wording Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…se (DDOS-8005) - ligand= works for a ligand synced in a live run; a reloaded run needs a ligand from job.ligands or a ligand_id from get_results() - drop language_info.version from the notebook so nb-clean (check) passes Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ow_panel_pose lookup (DDOS-8005) - compare structure_sha256 case-insensitively; inline the digest check into _fetch_verified_receptor and delete _verify_panel_receptor_digest - fold ligand-id/SMILES resolution into _panel_pose_row; errors now point to ligand_id when a SMILES matches nothing or several ligands - inline the receptor-path check into show_panel_pose - write cached panel files with write_bytes (receptor and catalog reads already re-fetch on a bad digest or unreadable JSON) - clear panel_version when update_from_dto assigns a new execution id Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…on, clearer from_last_run error (DDOS-8005) - restore temp-file + os.replace for cached panel files so an interrupted or concurrent download never leaves or exposes a partial file - panel_version must be a single name ([A-Za-z0-9_-][A-Za-z0-9._-]*) - from_last_run 'No executions found' error names the project_id; docs note that runs started with no project are not listed once a project is selected - remove the deeporigin.__file__ debug cell from the secondary-pharma notebook - fix stale mock comment about who seeds the pose SDF Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…hint, receptor docs (DDOS-8005) - _validate_panel_file_path refuses '?' and '#' like '%': the path builds both a request URL and a local cache path. Two cases added to test_secondary_pharma_get_poses_rejects_unsafe_receptor_path. - _panel_pose_row: nested conditional and hint branching moved to _panel_pose_lookup_hint (same strings; Sonar S3358, S3776). - docs/notebook: receptor_local_path is set only for rows with receptor_file_path; older rows return the pose without it (Copilot review). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… gone (DDOS-8005) ABFE.from_id (added in #647) called Execution._from_dto_maybe_quiet(..., quiet=False), which this PR removes with quiet=. quiet=False ran from_dto() unchanged, so the call becomes cls.from_dto(dto, client=client). test_abfe_from_id_hydrates_from_fetched_dto fails with AttributeError on the old call (no test reached it before). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ASinanSaglam
force-pushed
the
feat/DDOS-8005-get-poses-receptor-and-630-followups
branch
from
September 30, 2026 18:19
a04e5b9 to
e4e980d
Compare
ASinanSaglam
deleted the
feat/DDOS-8005-get-poses-receptor-and-630-followups
branch
September 30, 2026 18:43
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Execution.from_last_run()now passesproject_id=client.project_id, likelist(). Unset client project stays org-wide. Lookups by id orcompute_job_idstay unscoped. (project_idonExecutions.list/searchdates from DDOS-5704: feat: ability to list executions by project id #540.)quiet=removed fromExecution.from_id/from_last_run/listand_from_dto_maybe_quiet(review of feat(drug-discovery): add SecondaryPharmacology SDK class (DDOS-7332) #630, Remove "CLI" #3/I think we should generalize the description further -- "Command line tool and Python client for working ..." #5).list/from_last_runoverrides (vestigial since Migrate ProteinPrep to deeporigin.protein-prep v10 #639 removed the dual-tool-key logic).from_iduntouched. Expect conflicts inprotein_prep.pywith in-flight ProteinPrep work.SecondaryPharmacology.get_poses()is public. It downloads each distinct panel receptor once, verifiesstructure_sha256(one re-download on mismatch), and setspose.props["receptor_local_path"]. Rows with noreceptor_file_pathreturn poses without a receptor. Paths outsideprotected/or containing..,%or NUL are rejected before any download.show_panel_pose()is public. Pick the pose by ligand (ligand_id, or aLigand, matched on SMILES when it has no id) and byuniprot_idorgene_name.panel_version(the immutable manifestvolume_key) is stamped from result rows. Gap checks andget_panel(panel_version=...)read that panel'smembers.json, so a later panel change can't cause false gaps. Rows naming several versions raise.plot()de-duplicated (output identical to main across six cases);plot_heatmap(value_label=...)replaces the hardcoded "RMSD" hover label; docstrings condensed; "kinase panel" wording → "off-target panel" / "secondary-pharmacology panel";self_testguard on dockingget_results();_backfill_ligand_idsno longer overwrites API ids.get_poses,show_panel_pose) andCONTEXT.mdglossary entries (Project scope, Panel, Panel pose).Jira: https://deeporigin.atlassian.net/browse/DDOS-8005
Test plan
uv run pytest --env local -q -p no:cacheprovider→ 1503 passed, 34 skipped, 4 xpasseduv run pytest --env local -q -p no:cacheprovider tests/test_notebooks.py -k secondary→ 1 passedinterrogate -c pyproject.toml -f 100 --omit-covered-files .→ 100%uvx ruff@0.14.7 format --check .→ cleanExecutionsubclass, forproject_idset andNone; each new guard was mutation-checkedshow_panel_posevisually confirmed in a notebook on dev🤖 Generated with Claude Code