OperonDBS 0.7.2__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {operondbs-0.7.2 → operondbs-0.8.0}/.github/workflows/publish.yml +2 -1
- operondbs-0.8.0/.github/workflows/test.yml +51 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/.gitignore +6 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/AGENTS.md +46 -14
- {operondbs-0.7.2 → operondbs-0.8.0}/MANIFEST.in +2 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/OperonDBS.egg-info/PKG-INFO +9 -11
- {operondbs-0.7.2 → operondbs-0.8.0}/OperonDBS.egg-info/SOURCES.txt +41 -3
- {operondbs-0.7.2 → operondbs-0.8.0}/OperonDBS.egg-info/requires.txt +7 -4
- {operondbs-0.7.2 → operondbs-0.8.0}/PKG-INFO +9 -11
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/conf.py +1 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/extensibility.md +2 -2
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/external-analysis.md +12 -6
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/files-and-storage.md +4 -4
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/metadata-and-data-model.md +1 -12
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/overview.md +23 -4
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/qc-and-rules.md +2 -0
- operondbs-0.8.0/docs/en/contributor/development-testing.md +100 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/contributor/repository-guide.md +2 -6
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/getting-started/first-project.md +29 -27
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/getting-started/quickstart.md +1 -9
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/backup-migration.md +4 -16
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/curation-lifecycle.md +1 -1
- operondbs-0.8.0/docs/en/guides/external-analysis.md +328 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/file-archiving.md +2 -13
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/index.md +4 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/metadata-import.md +3 -1
- operondbs-0.8.0/docs/en/guides/phylogenetics-workflow.md +202 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/qc-profiles.md +68 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/remote-execution.md +1 -1
- operondbs-0.8.0/docs/en/guides/remote-first.md +138 -0
- operondbs-0.8.0/docs/en/guides/remote-storage.md +70 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/index.md +2 -7
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/operations/database-compatibility.md +5 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/operations/qc-performance.md +6 -3
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/overview.md +1 -11
- operondbs-0.8.0/docs/en/reference/behaviors-and-limitations.md +295 -0
- operondbs-0.8.0/docs/en/reference/cli-analysis.md +213 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/cli-decisions-reports.md +33 -7
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/cli-files-qc.md +37 -3
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/cli-project-metadata.md +45 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/cli-remote.md +3 -2
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/cli-taxonomy-lifecycle-admin.md +2 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/cli-workflow.md +24 -3
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/data-model.md +30 -17
- operondbs-0.8.0/docs/en/reference/recipe-fields.md +449 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/recipe-overview.md +6 -4
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/recipe-parsers-examples.md +164 -8
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/extensibility.md +7 -2
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/external-analysis.md +39 -16
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/files-and-storage.md +9 -11
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/index.md +1 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/metadata-and-data-model.md +4 -31
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/overview.md +23 -4
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/qc-and-rules.md +5 -0
- operondbs-0.8.0/docs/zh/contributor/development-testing.md +107 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/contributor/repository-guide.md +2 -6
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/getting-started/first-project.md +38 -58
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/getting-started/quickstart.md +5 -11
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/backup-migration.md +7 -14
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/curation-lifecycle.md +4 -2
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/external-analysis.md +127 -94
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/file-archiving.md +7 -16
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/index.md +4 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/metadata-import.md +7 -6
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/ncbi-datasets.md +6 -6
- operondbs-0.8.0/docs/zh/guides/phylogenetics-workflow.md +244 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/qc-profiles.md +93 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/remote-execution.md +10 -3
- operondbs-0.8.0/docs/zh/guides/remote-first.md +169 -0
- operondbs-0.8.0/docs/zh/guides/remote-storage.md +82 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/taxonomy-coverage.md +5 -3
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/index.md +2 -7
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/operations/database-compatibility.md +19 -2
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/operations/qc-performance.md +10 -5
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/overview.md +2 -12
- operondbs-0.8.0/docs/zh/reference/behaviors-and-limitations.md +292 -0
- operondbs-0.8.0/docs/zh/reference/cli-analysis.md +326 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/cli-decisions-reports.md +63 -9
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/cli-files-qc.md +50 -8
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/cli-project-metadata.md +45 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/cli-remote.md +8 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/cli-taxonomy-lifecycle-admin.md +4 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/cli-workflow.md +16 -2
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/data-model.md +60 -40
- operondbs-0.8.0/docs/zh/reference/recipe-fields.md +531 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/recipe-overview.md +9 -4
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/recipe-parsers-examples.md +209 -7
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/adapters/ncbi_datasets.py +18 -18
- operondbs-0.8.0/operon/adapters/timetree.py +377 -0
- operondbs-0.8.0/operon/classify.py +519 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/cli.py +641 -31
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/database.py +175 -31
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/demo.py +1 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/entity_view.py +15 -0
- operondbs-0.8.0/operon/environment.py +222 -0
- operondbs-0.8.0/operon/environment_capture.py +261 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/errors.py +9 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/execution.py +30 -10
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/export.py +25 -0
- operondbs-0.8.0/operon/fanout.py +378 -0
- {operondbs-0.7.2/operon/qc_module → operondbs-0.8.0/operon/qc}/__init__.py +92 -86
- operondbs-0.8.0/operon/qc/_alignment.pyx +185 -0
- operondbs-0.8.0/operon/qc/alignment.py +176 -0
- operondbs-0.8.0/operon/qc/measure.py +239 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/remotes.py +90 -36
- operondbs-0.8.0/operon/sequence_tools.py +477 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/taxonomy.py +2 -2
- operondbs-0.8.0/operon/timetree.py +489 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tools.py +881 -54
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/actions.py +1 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/data.py +21 -3
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/common.py +14 -4
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/config.py +11 -5
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/import_wizard.py +3 -3
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/publish.py +2 -2
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/runs.py +1 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/workflow.py +153 -8
- {operondbs-0.7.2 → operondbs-0.8.0}/pyproject.toml +18 -14
- {operondbs-0.7.2 → operondbs-0.8.0}/setup.py +4 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/compatibility/test_python_support.py +24 -3
- operondbs-0.8.0/tests/integration/test_analysis_tools.py +1064 -0
- operondbs-0.8.0/tests/integration/test_classify_sequences.py +206 -0
- operondbs-0.8.0/tests/integration/test_fanout_analyze.py +144 -0
- operondbs-0.8.0/tests/integration/test_python_packaging.py +169 -0
- operondbs-0.8.0/tests/integration/test_qc_remote_measure.py +69 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/integration/test_taxonomy_coverage.py +1 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/regression/test_correctness.py +1 -1
- operondbs-0.8.0/tests/regression/test_cython_alignment_parity.py +151 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/regression/test_cython_parser_parity.py +4 -4
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/regression/test_parser_semantics.py +2 -2
- operondbs-0.8.0/tests/unit/test_alignment_qc.py +285 -0
- operondbs-0.8.0/tests/unit/test_classify.py +584 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_cli_edges.py +14 -10
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_config_workflow_edges.py +50 -9
- operondbs-0.8.0/tests/unit/test_core_coverage_more.py +2030 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_coverage_edges.py +0 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_database_edges_more.py +0 -8
- operondbs-0.8.0/tests/unit/test_environment.py +296 -0
- operondbs-0.8.0/tests/unit/test_environment_capture.py +326 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_execution.py +33 -39
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_execution_edges.py +36 -27
- operondbs-0.8.0/tests/unit/test_fanout.py +296 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_files_edges.py +23 -3
- operondbs-0.8.0/tests/unit/test_follow.py +265 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_import_backup_show.py +0 -22
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_lifecycle.py +3 -17
- operondbs-0.8.0/tests/unit/test_misc_coverage_more.py +1548 -0
- operondbs-0.8.0/tests/unit/test_ncbi_coverage_gaps.py +1517 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_parser_edge_paths.py +1 -1
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_qc_and_rules.py +8 -18
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_qc_edges_more.py +15 -6
- operondbs-0.8.0/tests/unit/test_qc_measure.py +434 -0
- operondbs-0.8.0/tests/unit/test_qc_remote_only.py +141 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_recipe_history.py +0 -12
- operondbs-0.8.0/tests/unit/test_remote_taxonomy_more.py +1504 -0
- operondbs-0.8.0/tests/unit/test_remote_transport_edges.py +254 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_remotes.py +12 -20
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_remotes_edges.py +2 -1
- operondbs-0.8.0/tests/unit/test_schema_2_10.py +79 -0
- operondbs-0.8.0/tests/unit/test_schema_2_11.py +62 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_schema_2_9.py +1 -2
- operondbs-0.8.0/tests/unit/test_sequence_tools.py +350 -0
- operondbs-0.8.0/tests/unit/test_sequences.py +168 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_support_edges.py +13 -2
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_taxonomy_edges.py +18 -30
- operondbs-0.8.0/tests/unit/test_timetree.py +518 -0
- operondbs-0.8.0/tests/unit/test_timetree_snapshots.py +938 -0
- operondbs-0.8.0/tests/unit/test_tools_edges.py +1077 -0
- operondbs-0.8.0/tests/unit/test_tools_execution_more.py +1250 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_tui.py +94 -19
- operondbs-0.8.0/tests/unit/test_tui_config.py +1621 -0
- operondbs-0.8.0/tests/unit/test_tui_flows_more.py +1126 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_tui_publish.py +19 -7
- operondbs-0.8.0/tests/unit/test_tui_screens_more.py +1663 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_tui_writes.py +44 -8
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_views_release_reports_edges.py +4 -27
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_workflow_cli.py +41 -0
- operondbs-0.7.2/.github/workflows/test.yml +0 -27
- operondbs-0.7.2/docs/en/contributor/development-testing.md +0 -48
- operondbs-0.7.2/docs/en/guides/external-analysis.md +0 -262
- operondbs-0.7.2/docs/en/guides/remote-storage.md +0 -113
- operondbs-0.7.2/docs/en/reference/behaviors-and-limitations.md +0 -192
- operondbs-0.7.2/docs/en/reference/cli-analysis.md +0 -111
- operondbs-0.7.2/docs/en/reference/recipe-fields.md +0 -328
- operondbs-0.7.2/docs/zh/contributor/development-testing.md +0 -57
- operondbs-0.7.2/docs/zh/guides/remote-storage.md +0 -130
- operondbs-0.7.2/docs/zh/reference/behaviors-and-limitations.md +0 -190
- operondbs-0.7.2/docs/zh/reference/cli-analysis.md +0 -152
- operondbs-0.7.2/docs/zh/reference/recipe-fields.md +0 -364
- operondbs-0.7.2/operon/environment.py +0 -92
- operondbs-0.7.2/tests/integration/test_analysis_tools.py +0 -492
- operondbs-0.7.2/tests/integration/test_python_packaging.py +0 -131
- operondbs-0.7.2/tests/unit/test_environment.py +0 -121
- operondbs-0.7.2/tests/unit/test_tools_edges.py +0 -361
- operondbs-0.7.2/tests/unit/test_tui_config.py +0 -683
- {operondbs-0.7.2 → operondbs-0.8.0}/.readthedocs.yaml +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/LICENSE +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/OperonDBS.egg-info/dependency_links.txt +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/OperonDBS.egg-info/entry_points.txt +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/OperonDBS.egg-info/top_level.txt +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/README.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/README_ZH.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/benchmarks/qc_representative_entities.tsv +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/_static/language-switcher.js +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/_static/operon.css +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/_templates/layout.html +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/release-lifecycle.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/architecture/taxonomy-coverage.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/contributor/documentation-deployment.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/contributor/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/contributor/pypi-release.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/getting-started/daily-workflow.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/getting-started/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/getting-started/installation.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/ncbi-datasets.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/taxonomy-coverage.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/guides/troubleshooting.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/operations/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/operations/ncbi-recovery-migration.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/cli-tui.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/en/reference/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/requirements.txt +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/release-lifecycle.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/architecture/taxonomy-coverage.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/contributor/documentation-deployment.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/contributor/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/contributor/pypi-release.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/getting-started/daily-workflow.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/getting-started/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/getting-started/installation.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/guides/troubleshooting.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/operations/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/operations/ncbi-recovery-migration.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/cli-tui.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/docs/zh/reference/index.md +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/__main__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/adapters/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/backup.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/config.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/coverage.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/files.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/import_wizard.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/lifecycle.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/lineage.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/metadata_files.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/ncbi_reconcile.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/profiles.py +0 -0
- {operondbs-0.7.2/operon/qc_module → operondbs-0.8.0/operon/qc}/_parsers.pyx +0 -0
- {operondbs-0.7.2/operon/qc_module → operondbs-0.8.0/operon/qc}/parsers.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/release.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/reports.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/rules.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/schema.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/shutdown.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/table_import.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/app.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/app.tcss +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/assets/splash.png +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/assets/splash.rgb.z +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/coverage.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/decisions.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/entities.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/files.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/files_ops.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/screens/home.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/splash.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/tui/splash_terminal.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/operon/utils.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/setup.cfg +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/compatibility/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/helpers.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/integration/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/integration/test_analysis_resume.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/integration/test_analysis_shutdown.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/integration/test_execution_backends.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/integration/test_lineage_cascade.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/integration/test_ncbi_datasets_adapter.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/integration/test_pipeline_and_release.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/regression/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/__init__.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_docs_versions.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_export.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_import_wizard_edges.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_lineage.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_ncbi_edge_cases.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_ncbi_reconcile_edges.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_rules_schema_edges.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_schema_and_metadata.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_shutdown.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_table_import_edges.py +0 -0
- {operondbs-0.7.2 → operondbs-0.8.0}/tests/unit/test_tui_splash_terminal.py +0 -0
|
@@ -74,7 +74,8 @@ jobs:
|
|
|
74
74
|
CIBW_BUILD: "cp310-* cp311-* cp312-* cp313-* cp314-*"
|
|
75
75
|
CIBW_SKIP: "*-musllinux_*"
|
|
76
76
|
CIBW_TEST_COMMAND: >-
|
|
77
|
-
python -c "import operon; import operon.
|
|
77
|
+
python -c "import operon; import operon.qc._parsers;
|
|
78
|
+
import operon.qc._alignment;
|
|
78
79
|
print(operon.__version__)" && operon --help
|
|
79
80
|
- uses: actions/upload-artifact@v7
|
|
80
81
|
with:
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
# A newer push supersedes an in-flight run of the same ref.
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
# Documentation is cheap to build and independent of the test matrix, so it
|
|
16
|
+
# runs as its own job in parallel instead of gating the ten test jobs.
|
|
17
|
+
docs:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
- uses: actions/setup-python@v7
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
cache: pip
|
|
25
|
+
cache-dependency-path: pyproject.toml
|
|
26
|
+
- run: python -m pip install --upgrade pip
|
|
27
|
+
- run: python -m pip install -e '.[docs]'
|
|
28
|
+
- run: sphinx-build -W --keep-going -b html docs docs/_build/html
|
|
29
|
+
|
|
30
|
+
pytest:
|
|
31
|
+
strategy:
|
|
32
|
+
fail-fast: false
|
|
33
|
+
matrix:
|
|
34
|
+
os: [ ubuntu-latest, macos-latest ]
|
|
35
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
36
|
+
runs-on: ${{ matrix.os }}
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v6
|
|
39
|
+
- uses: actions/setup-python@v7
|
|
40
|
+
with:
|
|
41
|
+
python-version: ${{ matrix.python-version }}
|
|
42
|
+
cache: pip
|
|
43
|
+
cache-dependency-path: pyproject.toml
|
|
44
|
+
- run: python -m pip install --upgrade pip
|
|
45
|
+
- run: python -m pip install -e '.[test]'
|
|
46
|
+
- run: python -m pytest -n 2 --dist loadfile
|
|
47
|
+
- if: ${{ !cancelled() }}
|
|
48
|
+
uses: codecov/codecov-action@v7
|
|
49
|
+
with:
|
|
50
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
51
|
+
report_type: test_results
|
|
@@ -5,7 +5,8 @@ dist/
|
|
|
5
5
|
__pycache__/
|
|
6
6
|
*.py[cod]
|
|
7
7
|
*.so
|
|
8
|
-
operon/
|
|
8
|
+
operon/qc/_parsers.c
|
|
9
|
+
operon/qc/_alignment.c
|
|
9
10
|
*.egg-info/
|
|
10
11
|
*.sqlite
|
|
11
12
|
*.sqlite-wal
|
|
@@ -14,6 +15,7 @@ logs/
|
|
|
14
15
|
raw/
|
|
15
16
|
standardized/
|
|
16
17
|
qc/
|
|
18
|
+
!operon/qc/
|
|
17
19
|
analysis/
|
|
18
20
|
reports/
|
|
19
21
|
releases/
|
|
@@ -26,3 +28,6 @@ junit.xml
|
|
|
26
28
|
htmlcov/
|
|
27
29
|
/site/
|
|
28
30
|
/docs/_build/
|
|
31
|
+
/workflows/
|
|
32
|
+
/HPC/
|
|
33
|
+
.matrix/
|
|
@@ -26,8 +26,8 @@ principle-to-implementation mapping.
|
|
|
26
26
|
|
|
27
27
|
Current version markers (must stay consistent across code and docs):
|
|
28
28
|
|
|
29
|
-
- `operon` 0.
|
|
30
|
-
- database schema 2.
|
|
29
|
+
- `operon` 0.8.0 (`pyproject.toml`)
|
|
30
|
+
- database schema 2.11 (`operon/database.py`, `SCHEMA_VERSION`)
|
|
31
31
|
- metadata schema 1.4 (`operon/schema.py`, `METADATA_SCHEMA_VERSION`)
|
|
32
32
|
|
|
33
33
|
The project is licensed AGPL-3.0-or-later (`LICENSE` at the repo root).
|
|
@@ -36,17 +36,27 @@ The project is licensed AGPL-3.0-or-later (`LICENSE` at the repo root).
|
|
|
36
36
|
|
|
37
37
|
- `operon/` — the Python package (CLI entry points: `operon/cli.py`,
|
|
38
38
|
`operon/__main__.py`; console script `operon = operon.cli:main`).
|
|
39
|
-
- `operon/adapters/` — external source adapters
|
|
40
|
-
offline-first: JSON/JSONL, ZIP, or unpacked directories, plus optional
|
|
41
|
-
online download)
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
- `operon/adapters/` — external source adapters: NCBI Datasets
|
|
40
|
+
(offline-first: JSON/JSONL, ZIP, or unpacked directories, plus optional
|
|
41
|
+
online download) and TimeTree (query-cache-only REST client caching the
|
|
42
|
+
verbatim responses of exact queries under `adapters_cache/timetree/`;
|
|
43
|
+
mirroring or redistribution is forbidden by TimeTree's terms).
|
|
44
|
+
- `operon/qc/` — home for all QC functionality: streaming
|
|
45
|
+
FASTA/FASTQ/GFF3/protein parsers and built-in QC stages, plus alignment
|
|
46
|
+
QC (`alignment.py`, the pure-Python multiple-alignment QC reference
|
|
47
|
+
implementation behind `operon alignment-qc`, and `_alignment.pyx`, its
|
|
48
|
+
Cython production backend; parity enforced by
|
|
49
|
+
`tests/regression/test_cython_alignment_parity.py`). `parsers.py` is the
|
|
50
|
+
pure-Python reference
|
|
44
51
|
implementation; `_parsers.pyx` is the Cython-accelerated build of the
|
|
45
|
-
same API (compiled in place as `operon.
|
|
52
|
+
same API (compiled in place as `operon.qc._parsers`). The Cython
|
|
46
53
|
module is the required production backend; the pure-Python module is the
|
|
47
54
|
behavioral reference used by regression tests. Both must produce
|
|
48
55
|
identical metrics and error messages (enforced by
|
|
49
|
-
`tests/regression/test_cython_parser_parity.py`).
|
|
56
|
+
`tests/regression/test_cython_parser_parity.py`). `measure.py` backs
|
|
57
|
+
`operon qc-measure`, a project-independent measurement-only path whose
|
|
58
|
+
JSON payload can be imported back through `operon import-qc` (the remote
|
|
59
|
+
built-in QC workflow).
|
|
50
60
|
- `operon/execution.py` — execution backends for external commands:
|
|
51
61
|
`local` subprocess, `slurm` (sbatch submit + squeue poll), and `ssh`
|
|
52
62
|
(Paramiko; HPC head nodes and cloud VMs, optionally through remote
|
|
@@ -96,9 +106,18 @@ The project is licensed AGPL-3.0-or-later (`LICENSE` at the repo root).
|
|
|
96
106
|
NCBI Taxonomy snapshots and coverage denominators), `release.py` +
|
|
97
107
|
`export.py` (immutable releases and selective exports), `lifecycle.py`
|
|
98
108
|
(audited reversible entity retirement), `lineage.py` (adopting external
|
|
99
|
-
workflow outputs), `
|
|
109
|
+
workflow outputs), `sequence_tools.py` (alignment-driven domain
|
|
110
|
+
extraction and sequence selection), `classify.py` (versioned
|
|
111
|
+
sequence_classification profiles labelling `sequence_labels`),
|
|
112
|
+
`fanout.py` (data-derived fan-out of registered sequence files into
|
|
113
|
+
per-unit FASTAs under `analysis/derived/`, selected downstream by recipe
|
|
114
|
+
`file_role_prefix`), `timetree.py` (TimeTree query/calibration CLI
|
|
115
|
+
group backed by the query-cache adapter), `backup.py`, `reports.py`,
|
|
116
|
+
`table_import.py`,
|
|
100
117
|
`import_wizard.py`, `entity_view.py`, `environment.py`
|
|
101
|
-
(execution-environment capture
|
|
118
|
+
(execution-environment capture with at-capture redaction; recipe
|
|
119
|
+
`environment_policy` governs environment-aware cache reuse),
|
|
120
|
+
`shutdown.py` (graceful SIGINT/SIGTERM
|
|
102
121
|
handling), `ncbi_reconcile.py` (development-era adapter anomaly repair),
|
|
103
122
|
`demo.py` (deterministic synthetic demo project), `errors.py`,
|
|
104
123
|
`utils.py`.
|
|
@@ -112,6 +131,9 @@ The project is licensed AGPL-3.0-or-later (`LICENSE` at the repo root).
|
|
|
112
131
|
(`.readthedocs.yaml`).
|
|
113
132
|
- `benchmarks/` — representative entity sets for QC performance diagnostics
|
|
114
133
|
(see `docs/*/operations/qc-performance.md`).
|
|
134
|
+
- `scripts/` — local developer tooling; `setup-test-matrix.sh` and
|
|
135
|
+
`run-test-matrix.sh` build and drive the uv-managed Python 3.10–3.14
|
|
136
|
+
matrix under .matrix/ (see `docs/*/contributor/development-testing.md`).
|
|
115
137
|
|
|
116
138
|
## Setup, test, and build
|
|
117
139
|
|
|
@@ -123,17 +145,22 @@ python3 -m venv .venv && source .venv/bin/activate
|
|
|
123
145
|
python -m pip install -e '.[dev]' # runtime + pytest + Cython + Sphinx;
|
|
124
146
|
# also compiles the qc parsers extension
|
|
125
147
|
|
|
126
|
-
python -m pytest # full suite (coverage gate:
|
|
148
|
+
python -m pytest # full suite (coverage gate: >=95% combined
|
|
149
|
+
# line+branch, and >=95% branch coverage)
|
|
127
150
|
python -m pytest tests/unit # by category: unit / integration /
|
|
128
151
|
# regression / compatibility
|
|
129
152
|
|
|
153
|
+
python -m pytest --lf -q --no-cov # iterate: last failures, no coverage
|
|
154
|
+
python -m pytest -n 4 --dist loadfile # parallel full suite (xdist, in the dev/test extras)
|
|
155
|
+
scripts/run-test-matrix.sh # whole suite on 3.10-3.14 concurrently
|
|
156
|
+
|
|
130
157
|
python setup.py build_ext --inplace # rebuild only the Cython extension
|
|
131
158
|
|
|
132
159
|
sphinx-build -W --keep-going -b html docs docs/_build/html # strict docs build
|
|
133
160
|
```
|
|
134
161
|
|
|
135
162
|
Run the relevant test category after any change; run the full suite before
|
|
136
|
-
considering work done. CI (`.github/workflows/
|
|
163
|
+
considering work done. CI (`.github/workflows/test.yml`) runs pytest on
|
|
137
164
|
Python 3.10–3.14 and the strict Sphinx build. Releases are published
|
|
138
165
|
exclusively to PyPI; see `docs/*/contributor/pypi-release.md`.
|
|
139
166
|
|
|
@@ -170,6 +197,11 @@ asks.
|
|
|
170
197
|
exists only for pre-1.0 databases and is scheduled for removal at the 1.0
|
|
171
198
|
release; check it before touching `operon/database.py` migrations or the
|
|
172
199
|
NCBI adapter's schema-upgrade path.
|
|
200
|
+
- The `operon.qc` module uses CFFI (specifically, Cython), so static analysis
|
|
201
|
+
tools, such as `flake8`, will report "undefined reference" errors (F821).
|
|
202
|
+
Using `# noqa: F821` behind the line **ONLY** when importing `operon.qc`
|
|
203
|
+
and an F821 error is likely to occur. Globally ignoring F821 is **STRICKLY
|
|
204
|
+
PROHIBITED**.
|
|
173
205
|
|
|
174
206
|
## Documentation sync
|
|
175
207
|
|
|
@@ -186,7 +218,7 @@ change:
|
|
|
186
218
|
- Contributor-facing processes → `docs/*/contributor/`; navigation →
|
|
187
219
|
`docs/*/index.md`
|
|
188
220
|
|
|
189
|
-
Version markers in docs (`operon` 0.
|
|
221
|
+
Version markers in docs (`operon` 0.8.0, database schema 2.11, metadata
|
|
190
222
|
schema 1.4) must match `pyproject.toml` and the code. Do not write the
|
|
191
223
|
current values literally in Markdown sources: use the `myst_substitutions`
|
|
192
224
|
references `{{ operon_version }}`, `{{ db_schema }}`, and
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: OperonDBS
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Operon the Database System: Archive, Quality-Control, Organize, Analyze and Release Your Bio-Data
|
|
5
5
|
Author-email: hyli360 <lihuanyu2003@gmail.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -8,30 +8,26 @@ Project-URL: Repository, https://github.com/HYLi360/Operon
|
|
|
8
8
|
Project-URL: Issues, https://github.com/HYLi360/Operon/issues
|
|
9
9
|
Classifier: Operating System :: MacOS
|
|
10
10
|
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
12
|
Requires-Python: >=3.10
|
|
18
13
|
Description-Content-Type: text/markdown
|
|
19
14
|
License-File: LICENSE
|
|
20
15
|
Requires-Dist: aiohttp>=3.9
|
|
21
16
|
Requires-Dist: biopython>=1.85
|
|
22
|
-
Requires-Dist: PyYAML>=6.0
|
|
23
17
|
Requires-Dist: paramiko>=3.4
|
|
18
|
+
Requires-Dist: PyYAML>=6.0
|
|
24
19
|
Requires-Dist: questionary>=2.1
|
|
25
20
|
Requires-Dist: requests>=2.32
|
|
26
21
|
Requires-Dist: textual>=8.0
|
|
27
22
|
Provides-Extra: test
|
|
28
23
|
Requires-Dist: coverage>=7.0; extra == "test"
|
|
24
|
+
Requires-Dist: cython>=3.0; extra == "test"
|
|
29
25
|
Requires-Dist: paramiko>=3.4; extra == "test"
|
|
30
|
-
Requires-Dist: pytest-cov>=7.0; extra == "test"
|
|
31
26
|
Requires-Dist: pytest>=8.0; extra == "test"
|
|
27
|
+
Requires-Dist: pytest-cov>=7.0; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-xdist>=3.8; extra == "test"
|
|
32
29
|
Requires-Dist: setuptools>=77; extra == "test"
|
|
33
30
|
Requires-Dist: textual>=8.0; extra == "test"
|
|
34
|
-
Requires-Dist: cython>=3.0; extra == "test"
|
|
35
31
|
Provides-Extra: docs
|
|
36
32
|
Requires-Dist: Sphinx<9,>=7.4; extra == "docs"
|
|
37
33
|
Requires-Dist: myst-parser<5,>=4.0; extra == "docs"
|
|
@@ -40,8 +36,10 @@ Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "docs"
|
|
|
40
36
|
Provides-Extra: dev
|
|
41
37
|
Requires-Dist: coverage>=7.0; extra == "dev"
|
|
42
38
|
Requires-Dist: cython>=3.0; extra == "dev"
|
|
43
|
-
Requires-Dist: pytest-cov>=7.0; extra == "dev"
|
|
44
39
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-cov>=7.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-xdist>=3.8; extra == "dev"
|
|
42
|
+
Requires-Dist: setuptools>=77; extra == "dev"
|
|
45
43
|
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "dev"
|
|
46
44
|
Requires-Dist: Sphinx<9,>=7.4; extra == "dev"
|
|
47
45
|
Requires-Dist: myst-parser<5,>=4.0; extra == "dev"
|
|
@@ -50,8 +50,10 @@ docs/en/guides/file-archiving.md
|
|
|
50
50
|
docs/en/guides/index.md
|
|
51
51
|
docs/en/guides/metadata-import.md
|
|
52
52
|
docs/en/guides/ncbi-datasets.md
|
|
53
|
+
docs/en/guides/phylogenetics-workflow.md
|
|
53
54
|
docs/en/guides/qc-profiles.md
|
|
54
55
|
docs/en/guides/remote-execution.md
|
|
56
|
+
docs/en/guides/remote-first.md
|
|
55
57
|
docs/en/guides/remote-storage.md
|
|
56
58
|
docs/en/guides/taxonomy-coverage.md
|
|
57
59
|
docs/en/guides/troubleshooting.md
|
|
@@ -101,8 +103,10 @@ docs/zh/guides/file-archiving.md
|
|
|
101
103
|
docs/zh/guides/index.md
|
|
102
104
|
docs/zh/guides/metadata-import.md
|
|
103
105
|
docs/zh/guides/ncbi-datasets.md
|
|
106
|
+
docs/zh/guides/phylogenetics-workflow.md
|
|
104
107
|
docs/zh/guides/qc-profiles.md
|
|
105
108
|
docs/zh/guides/remote-execution.md
|
|
109
|
+
docs/zh/guides/remote-first.md
|
|
106
110
|
docs/zh/guides/remote-storage.md
|
|
107
111
|
docs/zh/guides/taxonomy-coverage.md
|
|
108
112
|
docs/zh/guides/troubleshooting.md
|
|
@@ -127,6 +131,7 @@ docs/zh/reference/recipe-parsers-examples.md
|
|
|
127
131
|
operon/__init__.py
|
|
128
132
|
operon/__main__.py
|
|
129
133
|
operon/backup.py
|
|
134
|
+
operon/classify.py
|
|
130
135
|
operon/cli.py
|
|
131
136
|
operon/config.py
|
|
132
137
|
operon/coverage.py
|
|
@@ -134,9 +139,11 @@ operon/database.py
|
|
|
134
139
|
operon/demo.py
|
|
135
140
|
operon/entity_view.py
|
|
136
141
|
operon/environment.py
|
|
142
|
+
operon/environment_capture.py
|
|
137
143
|
operon/errors.py
|
|
138
144
|
operon/execution.py
|
|
139
145
|
operon/export.py
|
|
146
|
+
operon/fanout.py
|
|
140
147
|
operon/files.py
|
|
141
148
|
operon/import_wizard.py
|
|
142
149
|
operon/lifecycle.py
|
|
@@ -149,17 +156,23 @@ operon/remotes.py
|
|
|
149
156
|
operon/reports.py
|
|
150
157
|
operon/rules.py
|
|
151
158
|
operon/schema.py
|
|
159
|
+
operon/sequence_tools.py
|
|
152
160
|
operon/shutdown.py
|
|
153
161
|
operon/table_import.py
|
|
154
162
|
operon/taxonomy.py
|
|
163
|
+
operon/timetree.py
|
|
155
164
|
operon/tools.py
|
|
156
165
|
operon/utils.py
|
|
157
166
|
operon/workflow.py
|
|
158
167
|
operon/adapters/__init__.py
|
|
159
168
|
operon/adapters/ncbi_datasets.py
|
|
160
|
-
operon/
|
|
161
|
-
operon/
|
|
162
|
-
operon/
|
|
169
|
+
operon/adapters/timetree.py
|
|
170
|
+
operon/qc/__init__.py
|
|
171
|
+
operon/qc/_alignment.pyx
|
|
172
|
+
operon/qc/_parsers.pyx
|
|
173
|
+
operon/qc/alignment.py
|
|
174
|
+
operon/qc/measure.py
|
|
175
|
+
operon/qc/parsers.py
|
|
163
176
|
operon/tui/__init__.py
|
|
164
177
|
operon/tui/actions.py
|
|
165
178
|
operon/tui/app.py
|
|
@@ -189,50 +202,75 @@ tests/integration/__init__.py
|
|
|
189
202
|
tests/integration/test_analysis_resume.py
|
|
190
203
|
tests/integration/test_analysis_shutdown.py
|
|
191
204
|
tests/integration/test_analysis_tools.py
|
|
205
|
+
tests/integration/test_classify_sequences.py
|
|
192
206
|
tests/integration/test_execution_backends.py
|
|
207
|
+
tests/integration/test_fanout_analyze.py
|
|
193
208
|
tests/integration/test_lineage_cascade.py
|
|
194
209
|
tests/integration/test_ncbi_datasets_adapter.py
|
|
195
210
|
tests/integration/test_pipeline_and_release.py
|
|
196
211
|
tests/integration/test_python_packaging.py
|
|
212
|
+
tests/integration/test_qc_remote_measure.py
|
|
197
213
|
tests/integration/test_taxonomy_coverage.py
|
|
198
214
|
tests/regression/__init__.py
|
|
199
215
|
tests/regression/test_correctness.py
|
|
216
|
+
tests/regression/test_cython_alignment_parity.py
|
|
200
217
|
tests/regression/test_cython_parser_parity.py
|
|
201
218
|
tests/regression/test_parser_semantics.py
|
|
202
219
|
tests/unit/__init__.py
|
|
220
|
+
tests/unit/test_alignment_qc.py
|
|
221
|
+
tests/unit/test_classify.py
|
|
203
222
|
tests/unit/test_cli_edges.py
|
|
204
223
|
tests/unit/test_config_workflow_edges.py
|
|
224
|
+
tests/unit/test_core_coverage_more.py
|
|
205
225
|
tests/unit/test_coverage_edges.py
|
|
206
226
|
tests/unit/test_database_edges_more.py
|
|
207
227
|
tests/unit/test_docs_versions.py
|
|
208
228
|
tests/unit/test_environment.py
|
|
229
|
+
tests/unit/test_environment_capture.py
|
|
209
230
|
tests/unit/test_execution.py
|
|
210
231
|
tests/unit/test_execution_edges.py
|
|
211
232
|
tests/unit/test_export.py
|
|
233
|
+
tests/unit/test_fanout.py
|
|
212
234
|
tests/unit/test_files_edges.py
|
|
235
|
+
tests/unit/test_follow.py
|
|
213
236
|
tests/unit/test_import_backup_show.py
|
|
214
237
|
tests/unit/test_import_wizard_edges.py
|
|
215
238
|
tests/unit/test_lifecycle.py
|
|
216
239
|
tests/unit/test_lineage.py
|
|
240
|
+
tests/unit/test_misc_coverage_more.py
|
|
241
|
+
tests/unit/test_ncbi_coverage_gaps.py
|
|
217
242
|
tests/unit/test_ncbi_edge_cases.py
|
|
218
243
|
tests/unit/test_ncbi_reconcile_edges.py
|
|
219
244
|
tests/unit/test_parser_edge_paths.py
|
|
220
245
|
tests/unit/test_qc_and_rules.py
|
|
221
246
|
tests/unit/test_qc_edges_more.py
|
|
247
|
+
tests/unit/test_qc_measure.py
|
|
248
|
+
tests/unit/test_qc_remote_only.py
|
|
222
249
|
tests/unit/test_recipe_history.py
|
|
250
|
+
tests/unit/test_remote_taxonomy_more.py
|
|
251
|
+
tests/unit/test_remote_transport_edges.py
|
|
223
252
|
tests/unit/test_remotes.py
|
|
224
253
|
tests/unit/test_remotes_edges.py
|
|
225
254
|
tests/unit/test_rules_schema_edges.py
|
|
255
|
+
tests/unit/test_schema_2_10.py
|
|
256
|
+
tests/unit/test_schema_2_11.py
|
|
226
257
|
tests/unit/test_schema_2_9.py
|
|
227
258
|
tests/unit/test_schema_and_metadata.py
|
|
259
|
+
tests/unit/test_sequence_tools.py
|
|
260
|
+
tests/unit/test_sequences.py
|
|
228
261
|
tests/unit/test_shutdown.py
|
|
229
262
|
tests/unit/test_support_edges.py
|
|
230
263
|
tests/unit/test_table_import_edges.py
|
|
231
264
|
tests/unit/test_taxonomy_edges.py
|
|
265
|
+
tests/unit/test_timetree.py
|
|
266
|
+
tests/unit/test_timetree_snapshots.py
|
|
232
267
|
tests/unit/test_tools_edges.py
|
|
268
|
+
tests/unit/test_tools_execution_more.py
|
|
233
269
|
tests/unit/test_tui.py
|
|
234
270
|
tests/unit/test_tui_config.py
|
|
271
|
+
tests/unit/test_tui_flows_more.py
|
|
235
272
|
tests/unit/test_tui_publish.py
|
|
273
|
+
tests/unit/test_tui_screens_more.py
|
|
236
274
|
tests/unit/test_tui_splash_terminal.py
|
|
237
275
|
tests/unit/test_tui_writes.py
|
|
238
276
|
tests/unit/test_views_release_reports_edges.py
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
aiohttp>=3.9
|
|
2
2
|
biopython>=1.85
|
|
3
|
-
PyYAML>=6.0
|
|
4
3
|
paramiko>=3.4
|
|
4
|
+
PyYAML>=6.0
|
|
5
5
|
questionary>=2.1
|
|
6
6
|
requests>=2.32
|
|
7
7
|
textual>=8.0
|
|
@@ -9,8 +9,10 @@ textual>=8.0
|
|
|
9
9
|
[dev]
|
|
10
10
|
coverage>=7.0
|
|
11
11
|
cython>=3.0
|
|
12
|
-
pytest-cov>=7.0
|
|
13
12
|
pytest>=8.0
|
|
13
|
+
pytest-cov>=7.0
|
|
14
|
+
pytest-xdist>=3.8
|
|
15
|
+
setuptools>=77
|
|
14
16
|
Sphinx<9,>=7.4
|
|
15
17
|
myst-parser<5,>=4.0
|
|
16
18
|
sphinx-rtd-theme<4,>=3.0
|
|
@@ -28,9 +30,10 @@ tomli>=2.0
|
|
|
28
30
|
|
|
29
31
|
[test]
|
|
30
32
|
coverage>=7.0
|
|
33
|
+
cython>=3.0
|
|
31
34
|
paramiko>=3.4
|
|
32
|
-
pytest-cov>=7.0
|
|
33
35
|
pytest>=8.0
|
|
36
|
+
pytest-cov>=7.0
|
|
37
|
+
pytest-xdist>=3.8
|
|
34
38
|
setuptools>=77
|
|
35
39
|
textual>=8.0
|
|
36
|
-
cython>=3.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: OperonDBS
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Operon the Database System: Archive, Quality-Control, Organize, Analyze and Release Your Bio-Data
|
|
5
5
|
Author-email: hyli360 <lihuanyu2003@gmail.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -8,30 +8,26 @@ Project-URL: Repository, https://github.com/HYLi360/Operon
|
|
|
8
8
|
Project-URL: Issues, https://github.com/HYLi360/Operon/issues
|
|
9
9
|
Classifier: Operating System :: MacOS
|
|
10
10
|
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
12
|
Requires-Python: >=3.10
|
|
18
13
|
Description-Content-Type: text/markdown
|
|
19
14
|
License-File: LICENSE
|
|
20
15
|
Requires-Dist: aiohttp>=3.9
|
|
21
16
|
Requires-Dist: biopython>=1.85
|
|
22
|
-
Requires-Dist: PyYAML>=6.0
|
|
23
17
|
Requires-Dist: paramiko>=3.4
|
|
18
|
+
Requires-Dist: PyYAML>=6.0
|
|
24
19
|
Requires-Dist: questionary>=2.1
|
|
25
20
|
Requires-Dist: requests>=2.32
|
|
26
21
|
Requires-Dist: textual>=8.0
|
|
27
22
|
Provides-Extra: test
|
|
28
23
|
Requires-Dist: coverage>=7.0; extra == "test"
|
|
24
|
+
Requires-Dist: cython>=3.0; extra == "test"
|
|
29
25
|
Requires-Dist: paramiko>=3.4; extra == "test"
|
|
30
|
-
Requires-Dist: pytest-cov>=7.0; extra == "test"
|
|
31
26
|
Requires-Dist: pytest>=8.0; extra == "test"
|
|
27
|
+
Requires-Dist: pytest-cov>=7.0; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-xdist>=3.8; extra == "test"
|
|
32
29
|
Requires-Dist: setuptools>=77; extra == "test"
|
|
33
30
|
Requires-Dist: textual>=8.0; extra == "test"
|
|
34
|
-
Requires-Dist: cython>=3.0; extra == "test"
|
|
35
31
|
Provides-Extra: docs
|
|
36
32
|
Requires-Dist: Sphinx<9,>=7.4; extra == "docs"
|
|
37
33
|
Requires-Dist: myst-parser<5,>=4.0; extra == "docs"
|
|
@@ -40,8 +36,10 @@ Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "docs"
|
|
|
40
36
|
Provides-Extra: dev
|
|
41
37
|
Requires-Dist: coverage>=7.0; extra == "dev"
|
|
42
38
|
Requires-Dist: cython>=3.0; extra == "dev"
|
|
43
|
-
Requires-Dist: pytest-cov>=7.0; extra == "dev"
|
|
44
39
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-cov>=7.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-xdist>=3.8; extra == "dev"
|
|
42
|
+
Requires-Dist: setuptools>=77; extra == "dev"
|
|
45
43
|
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "dev"
|
|
46
44
|
Requires-Dist: Sphinx<9,>=7.4; extra == "dev"
|
|
47
45
|
Requires-Dist: myst-parser<5,>=4.0; extra == "dev"
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
The built-in source adapter currently covers NCBI Datasets; sources such as ENA remain part of the future extension boundary. Taxonomy coverage currently supports only NCBI Taxonomy; GTDB and the NCBI↔GTDB crosswalk are not yet implemented. Built-in QC covers file level, generic sequence basics for non-genome FASTA (CDS/protein), reads basics, assembly structure, and annotation structure. BUSCO is natively integrated through directory output and a JSON summary parser; tools without a parser yet — QUAST, Merqury, Kraken2, CheckM2, and similar — can still be integrated through `run-external` + `import-qc`. Downstream comparative-genomics analysis is done by external workflows in `analysis/`; `operon` is responsible for data admission, provenance, and publication.
|
|
6
6
|
|
|
7
|
-
The contract between downstream workflows and the database is a closed loop formed by `operon export` and `operon adopt`: export materializes the selected entities by file identity into a `data/<entity_type>/<entity_id>/<filename>` layout, accompanied by `manifest.tsv` (with SHA-256 recomputed over the materialized bytes), a `qc.tsv` QC long-table snapshot, `checksums.sha256`, and `provenance.json` (the input-side manifest); after consuming this artifact set, the external workflow uses adopt to re-register derived artifacts as first-class manifest members — materialized under `analysis/adopted/<entity_id>/`, inheriting the ingest idempotency/conflict invariants, with file-to-file lineage edges recorded in `file_lineage` (the output-side manifest). Adopted products can be QC'd, evaluated, exported, released, and selected by `analyze` as inputs of downstream recipes (cascading analysis). Downstream workflows should read and write through this contract instead of reading the database directly. Orchestration of cascading workflows (dependency graphs, parallelism, retries) belongs to workflow managers such as snakemake/nextflow; `operon` is responsible for data admission, lineage, and publication, while `run-pipeline` only covers simple single-file chaining. The batch adopt manifest format is described in the [external analysis guide](../guides/external-analysis.md). Export is semantically complementary to release: release targets publication (QC-gated, immutable snapshot), while export targets analysis inputs (arbitrary selection criteria, materialized on demand).
|
|
7
|
+
The contract between downstream workflows and the database is a closed loop formed by `operon export` and `operon adopt`: export materializes the selected entities by file identity into a `data/<entity_type>/<entity_id>/<filename>` layout, accompanied by `manifest.tsv` (with SHA-256 recomputed over the materialized bytes), a `qc.tsv` QC long-table snapshot, `checksums.sha256`, and `provenance.json` (the input-side manifest); after consuming this artifact set, the external workflow uses adopt to re-register derived artifacts as first-class manifest members — materialized under `analysis/adopted/<entity_id>/`, inheriting the ingest idempotency/conflict invariants, with file-to-file lineage edges recorded in `file_lineage` (the output-side manifest). Adopted products can be QC'd, evaluated, exported, released, and selected by `analyze` as inputs of downstream recipes (cascading analysis). Downstream workflows should read and write through this contract instead of reading the database directly. Orchestration of cascading workflows (dependency graphs, parallelism, retries) belongs to workflow managers such as snakemake/nextflow; `operon` is responsible for data admission, lineage, and publication, while `run-pipeline` only covers simple single-file chaining. One carve-out on the admission side: when the number of downstream analysis units is data-dependent (for example subfamilies whose count is known only after classification), admitting those units is `operon`'s responsibility — `operon fanout` materializes and registers the per-unit files with lineage under `analysis/derived/`; orchestrating the runs over them still belongs to the executor and the workflow engine. The batch adopt manifest format is described in the [external analysis guide](../guides/external-analysis.md). Export is semantically complementary to release: release targets publication (QC-gated, immutable snapshot), while export targets analysis inputs (arbitrary selection criteria, materialized on demand).
|
|
8
8
|
|
|
9
9
|
Deduplication is implemented by layer: byte-level duplication is already guaranteed by SHA-256 idempotence (same entity and role with identical bytes returns the same `FIL_`; different bytes are explicitly rejected); sequence-level duplication (normalized sequence digests / refget-style summaries) and biological near-duplication (Mash/ANI/k-mer similarity, duplicate clusters, and representative selection) are extension directions — they can be performed with external tools in `analysis/` with results written back to `qc_results`, and the representative-selection rules themselves should also be versioned.
|
|
10
10
|
|
|
11
11
|
For scale, SQLite WAL plus indexes suits metadata on the order of millions of rows, and all sequence parsing is streaming; if inode sharing is explicitly acceptable, hard links can be used for `standardized/` or releases.
|
|
12
12
|
|
|
13
|
-
Execution backends extend along the abstraction in `execution.py`: `local`, `slurm`, and `ssh` are provided today, and a new backend only needs to implement the same executor interface to plug into `run-external`/`analyze`. Cloud-vendor SDKs (AWS Batch, GCP Batch, etc.) and Slurm array jobs are not yet supported; remote storage currently consists of SFTP mirrors only, and object storage (S3 and the like) is likewise an extension direction.
|
|
13
|
+
Execution backends extend along the abstraction in `execution.py`: `local`, `slurm`, and `ssh` are provided today, and a new backend only needs to implement the same executor interface to plug into `run-external`/`analyze`. Cloud-vendor SDKs (AWS Batch, GCP Batch, etc.) and Slurm array jobs are not yet supported; remote storage currently consists of SFTP mirrors only, and object storage (S3 and the like) is likewise an extension direction. Data-dependent fan-out does not require array jobs: `operon fanout` admits each unit as its own manifest file, and `analyze` with a `file_role_prefix` recipe then submits one job per unit through any backend.
|
|
@@ -10,10 +10,12 @@ External programs such as BLAST/HMMER/BUSCO no longer require hand-assembled com
|
|
|
10
10
|
4. Computes the reference database identity (single-file SHA-256 / directory fingerprint / explicit checksum);
|
|
11
11
|
5. Looks up a completed cache by `analysis_name + file_id + input SHA + parameter fingerprint + tool version + database identity`, skipping on a hit; on a miss, enters the second-level continuation: if an old `completed` job for the same `(analysis, file_id)` has a matching input content hash and its recorded output artifact passes byte-level verification, that output is adopted (a new `completed` row is inserted under the current fingerprint, traced in the `changes` audit table, with status `adopted`); only otherwise is the job recomputed;
|
|
12
12
|
6. On a miss, launches the program via `conda run`, a container prefix, or a direct path; both file and directory outputs must exist and be non-empty, with stdout/stderr written to disk;
|
|
13
|
-
7. Computes the file or directory content hash, parses top hits or the BUSCO JSON summary into `analysis_hits`/`analysis_results`, and syncs the same-named metrics into `qc_results`.
|
|
13
|
+
7. Computes the file or directory content hash, parses top hits or the BUSCO JSON summary into `analysis_hits`/`analysis_results`, and syncs the same-named metrics into `qc_results`. Parsers with coordinates (`blast_tabular`, `hmmer_domtblout`, `rpsbproc_tabular`) additionally write every parsed hit to `analysis_alignments` as a structured row (query/subject IDs, hit rank, query/subject intervals, e-value, bitscore, percent identity, unmapped columns in `extra_json`), untruncated by `max_hits_per_query`; `report analysis --hits` reads this table.
|
|
14
14
|
|
|
15
15
|
Directories use a deterministic tree hash composed of relative paths, empty directories, file sizes/contents, and symlink targets. `database_mode: mutable_cache` serves shared caches such as BUSCO's that gradually download lineages, identified by an explicit `database_version` as the logical version; immutable reference databases keep the default `reference` content identity.
|
|
16
16
|
|
|
17
|
+
A recipe may replace the single command with a `commands` chain (mutually exclusive with `arguments`). All rendered steps execute in order through the same executor and parent-tool `run_method` (one recipe, one environment — a deliberate capability limitation), under one run record and one `analysis_jobs` row. The first command is the recipe's logical owner: the job's `tool_version` and the version component of cache identity come from it — from the first block's own `version_args`/`version_pattern` when declared, otherwise from the tool-level probe (recipe loading forces the two to target the same program). A step invoking the parent `executable` inherits its already-probed version; another program may declare its own `version_args` and `version_pattern`, which are run through the same launcher/executor. Unconfigured secondary programs are explicitly recorded as version `unknown`; version flags are never guessed. Each step receives its own `logs/<run_id>.step<N>.stdout.log` / `.stderr.log`, and its `argv`, `executable`, `tool_version`, `tool_version_raw`, `version_source`, `version_command`, and `exit_code` are recorded in `execution_details.steps`. The first non-zero step aborts the chain and fails the job with a `step N/M failed` error. Intermediate artifacts live in a deterministic `${work_dir}` scratch directory (`<output_name>.work` next to the output), which is deleted and rebuilt before execution and removed after success or failure (`--keep-partial` keeps it). Expected-output validation, content hashing, and result parsing run once, after the last step. On SSH backends with a remote root the work directory is mapped to the remote root and created there like any other project path. The canonical example couples `rpsblast -outfmt 11` (ASN.1 archive) with independently versioned `rpsbproc`, whose tabular report is parsed by `rpsbproc_tabular`: domain rows from the `DATA`/`SESSION`/`QUERY`/`DOMAINS` blocks become full `analysis_alignments` rows (the query is the QUERY definition line, the subject is the accession, coordinates come from the `from`/`to` columns, and hit type/PSSM IDs/short name stay in `extra_json`), with EAV hits truncated to `max_hits_per_query` as usual. Every probed step version is mixed into the cache fingerprint: upgrading any step's program invalidates the exact cache even when the recipe text and the primary tool version are unchanged, with verified-output adoption applying as usual.
|
|
18
|
+
|
|
17
19
|
Actual execution of external commands is taken over by the backend abstraction in `execution.py`; `run_external_command` selects a backend through `get_executor(project, backend)`:
|
|
18
20
|
|
|
19
21
|
- `local` (default): the original local subprocess behavior, completely unchanged;
|
|
@@ -22,13 +24,17 @@ Actual execution of external commands is taken over by the backend abstraction i
|
|
|
22
24
|
|
|
23
25
|
All three backends share the same provenance and correctness contract: exit codes, start/end times, and logs are written to `workflow_runs` and `logs/workflow.jsonl` as usual; SQLite additionally stores the executor, scheduler job ID, and resource/script details; success determination and input/output SHA-256 verification are unchanged; tool version probing on non-`local` backends also goes through the same backend. An individual recipe can override same-named fields of `execution.slurm` with a `slurm:` mapping (e.g. adjusting memory/time for BUSCO alone).
|
|
24
26
|
|
|
25
|
-
Execution environment capture (
|
|
27
|
+
Execution environment capture (`environment.py`, `environment_capture.py`) stores normalized JSON in `execution_environments`, addressed by `environment_id`. Runs and analysis jobs reference that document; each command-chain step also records its own environment ID. No database migration is needed for the extended JSON document (`capture_schema: 1`). The document is redacted at capture time, before storage: the hostname is replaced by `sha256:` plus the first 16 hex characters of its SHA-256, and the `$HOME` prefix of path-like values (`PATH`, `CONDA_PREFIX`, `VIRTUAL_ENV`, the conda prefix) is replaced by `~`. Remote probes transfer the raw values (probe files are written with umask 077) and the controlling Python process redacts them before storage; a transient `home` probe key feeds the replacement and is then discarded, never entering the stored document or any fingerprint. The `environment_id` and sub-fingerprints are computed from the redacted document, so identical configurations captured on different hosts deduplicate to one record. Documents recorded before redaction was introduced are content-addressed and immutable and are not migrated; new captures produce new environment IDs.
|
|
28
|
+
|
|
29
|
+
The local, Slurm and SSH backends probe immediately before the payload. Slurm probes after `setup_commands` on the compute node; direct SSH probes in the payload shell's working directory. Recognized `conda`, `mamba` and `micromamba run` launchers run the probe through the same launcher and target name/prefix. Reading `conda-meta/*.json` requires no Python or package-manager CLI inside the target environment. Direct programs inherit the executor environment. Known opaque shell/container launchers and unsupported manager options are labelled `unsupported_launcher`, with `capture_scope: executor_only`; their outer environment is not claimed as the tool's Conda environment. Arbitrary custom wrappers are not introspected.
|
|
30
|
+
|
|
31
|
+
Conda snapshots retain package name, version, build, subdir, dependencies, archive URL and available SHA-256/MD5. Complete inventories include an `@EXPLICIT` reconstruction specification (SHA-256 preferred, MD5 fallback). Package fingerprints exclude installation prefixes and hostnames. Credential-bearing URL components (userinfo, `/t/` tokens and queries) are removed. Private channels may consequently require credentials supplied separately during restoration. Pip-installed distribution names detected through `INSTALLER` metadata are reported separately; neither pip packages, editable installs, manually modified files nor custom activation scripts are restored by the Conda specification. The package inventory describes original archives, not a verification of installed bytes. Empty, malformed, interrupted or unresolvable inventories cannot be exported as complete specifications.
|
|
32
|
+
|
|
33
|
+
Separate `system_fingerprint` and `hardware_fingerprint` cover OS/kernel/architecture, distribution and glibc, and CPU model/features, total memory and available NVIDIA GPU model/driver/compute capability respectively. Hostname, PATH, prefix, CPU affinity and runtime settings do not enter those two fingerprints. Selected locale, timezone and threading/device variables and CPU affinity are retained as context. These are Linux-oriented probes: missing CPU/GPU data is explicitly marked unavailable (GPU absence and probe failure are not distinguished); no dynamic metrics, GPU UUIDs or serial numbers are collected. Hardware fingerprints describe observed fields and do not certify hardware equivalence when fields are unavailable.
|
|
26
34
|
|
|
27
|
-
-
|
|
28
|
-
- `slurm`: embeds the probe in the sbatch script, writes the result to `<run_id>.env` inside the job, and reads it back — the captured environment is the compute node's, not the submission host's;
|
|
29
|
-
- `ssh`: direct mode runs the probe on the remote host through paramiko; remote Slurm mode embeds and retrieves the same job-side probe so it also records the compute node rather than the SSH login node.
|
|
35
|
+
Probes are best-effort, bounded by 30 seconds (NVIDIA query: 5 seconds), and require a POSIX shell, `base64` and common system utilities. GNU `timeout` bounds the probe when the host provides it; elsewhere — macOS ships no `timeout` — a POSIX watcher enforces the same 30-second bound, so a host without it still captures instead of reporting `unavailable`. Linux-only data sources such as `/proc` simply leave their fields unavailable. `capture_status` distinguishes complete, partial, failed, unavailable and unsupported launcher captures. Earlier documents remain readable and may lack these fields. Controller-only legacy probes remain available as fallback; their Python version must not be interpreted as the target interpreter version.
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
Environment fingerprints also drive a recipe-level reuse policy: the optional recipe field `environment_policy` takes `ignore`, `warn` (the default) or `strict`, and any other value is rejected at configuration validation. The field enters the parameter fingerprint only when it is explicitly set — the same mechanism as `hmmer_mode` and the alignment column-mapping keys — so setting or changing it invalidates the completed cache exactly once. On a completed-cache hit with a policy other than `ignore`, `operon` compares an environment-relevance fingerprint: the composite of the document's `system_fingerprint`, `hardware_fingerprint` and `conda.package_fingerprint`. Hostname, paths, CPU affinity and runtime threading variables are deliberately excluded — the thread count already participates in the parameter fingerprint, and affinity is transient scheduler state. If the fingerprints match, the cache is reused as usual; on a mismatch, `warn` reuses the cached result while recording a warning in the run details and printing it, and `strict` treats the hit as a miss and recomputes. Backends without a pre-job probe (`slurm` and remote Slurm) cannot compare before reuse, so `strict` degrades to `warn` and the downgrade is recorded in the run details. When either side's environment document lacks sub-fingerprints (captures recorded before database schema {{ db_schema }}), the comparison is recorded as `unavailable`: `warn` reuses as usual and `strict` likewise degrades to `warn`, so legacy provenance never causes spurious recomputation.
|
|
32
38
|
|
|
33
39
|
Recipe versioning and snapshots (schema 2.9): a recipe gains an optional `version:` field (a positive integer, default 1; invalid values are rejected at configuration validation). As `analyze` processes each candidate file it records the current recipe together with the verbatim spec of its referenced tool into the `recipe_snapshots` table: the snapshot document is `{"recipe": <the recipe's raw mapping>, "tool": <the referenced tool spec's raw mapping>}`, content-addressed by the SHA-256 of its canonicalized JSON and deduplicated by `UNIQUE(recipe_name, recipe_version, recipe_sha256)` — so edits to the tool definition also produce a new snapshot, and cache hits record a snapshot of the current configuration as well. `analysis_jobs.recipe_snapshot_id` points back to the exact configuration that produced the job; jobs adopted during resume inherit the original job's snapshot id (they were produced by that configuration, not today's). Inspect them with `operon recipes list / history / show`; the QC-profile counterparts recorded in `qc_profiles` are inspected with `operon profiles history / show`. Restoration via the CLI is print-only in both cases: a human copies the output back into the configuration YAML, and the CLI never rewrites files in place. The audited alternative is the TUI Config screen, whose structured editors save every change as the next version with a new snapshot and can restore any recorded snapshot into the editor (saving it creates the next version); TUI recipe saves normalize `tools.yaml` formatting and drop hand-written comments. <!-- version-pin -->
|
|
34
40
|
|
|
@@ -18,12 +18,12 @@ Guarantees of `ingest`:
|
|
|
18
18
|
The `remotes:` section of `project.yaml` can configure one or more SFTP remote mirrors (`operon/remotes.py`), synchronizing manifest files to a remote without breaking the invariants of this section:
|
|
19
19
|
|
|
20
20
|
- Plain files and directory artifacts are all verified by `sha256 + size_bytes`; when the server lacks `sha256sum`, SHA-256 is computed by streaming over SFTP, never degrading to size-only comparison; directories use exactly the same deterministic tree hash as locally (including empty directories and symlink targets);
|
|
21
|
-
- The remote maintains an `operon-manifest.json` v2 manifest (project_id + relative_path → file_id/sha256/size/kind/synced_at)
|
|
21
|
+
- The remote maintains an `operon-manifest.json` v2 manifest (project_id + relative_path → file_id/sha256/size/kind/synced_at) whose updates are published atomically and serialized between concurrent control ends;
|
|
22
22
|
- All relative paths are root-constrained on both sides; absolute paths, `..`, and path escapes are rejected. The remote manifest's `project_id` and every entry identity must match the local SQLite;
|
|
23
23
|
- Every transfer reuses `workflow_runs` for provenance (step `push:<name>` / `pull:<name>`); successful locations are also cached in `file_locations`;
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
- After `pull` restores a locally missing file, `files.status` returns to `CHECKSUM_VERIFIED`, and this change is written to `changes` just like the status changes from `verify`/`evict`.
|
|
25
|
+
|
|
26
|
+
Manifest publication and locking, batch semantics and per-item exit codes, and `sftp://`/`remote://` ingest are command-level details; see [Remote storage commands](../reference/cli-remote.md) and [File and QC Commands](../reference/cli-files-qc.md#ingest).
|
|
27
27
|
|
|
28
28
|
Paramiko is a core runtime dependency but remains lazily imported, so local-only commands do not initialize the SSH stack.
|
|
29
29
|
|