silkroute 0.1.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.
- silkroute-0.1.0/.github/workflows/pre-commit.yml +17 -0
- silkroute-0.1.0/.github/workflows/publish-pypi.yml +68 -0
- silkroute-0.1.0/.github/workflows/refresh-fixtures.yml +167 -0
- silkroute-0.1.0/.github/workflows/tests.yml +34 -0
- silkroute-0.1.0/.gitignore +67 -0
- silkroute-0.1.0/AGENTS.md +69 -0
- silkroute-0.1.0/CLAUDE.md +1 -0
- silkroute-0.1.0/DEVELOPMENT.md +196 -0
- silkroute-0.1.0/LICENSE +21 -0
- silkroute-0.1.0/PKG-INFO +510 -0
- silkroute-0.1.0/README.md +467 -0
- silkroute-0.1.0/TODO.md +63 -0
- silkroute-0.1.0/docs/workflow_yaml.md +811 -0
- silkroute-0.1.0/examples/API_usage_demo.ipynb +30953 -0
- silkroute-0.1.0/examples/activity_search_demo.ipynb +892 -0
- silkroute-0.1.0/examples/data/unknown_ids.csv +4 -0
- silkroute-0.1.0/examples/data/unknown_sequences.csv +3 -0
- silkroute-0.1.0/examples/new_interface_template.py +71 -0
- silkroute-0.1.0/examples/notebooks/01_workflow_yaml_validation.ipynb +137 -0
- silkroute-0.1.0/examples/notebooks/02_protein_query_first_workflow.ipynb +119 -0
- silkroute-0.1.0/examples/notebooks/03_query_composition_and_gui_metadata.ipynb +100 -0
- silkroute-0.1.0/examples/notebooks/04_compound_ic50_workflow.ipynb +112 -0
- silkroute-0.1.0/examples/notebooks/05_metadata_and_summary_walkthrough.ipynb +113 -0
- silkroute-0.1.0/examples/uniprot_usage_demo.ipynb +1373 -0
- silkroute-0.1.0/examples/workflows/compound_chembl_ic50_ranges.yml +40 -0
- silkroute-0.1.0/examples/workflows/full_options_reference.yml +82 -0
- silkroute-0.1.0/examples/workflows/interaction_pli_chembl.yml +36 -0
- silkroute-0.1.0/examples/workflows/interaction_ppi_uniprot.yml +35 -0
- silkroute-0.1.0/examples/workflows/invalid/forbidden_version_key.yml +18 -0
- silkroute-0.1.0/examples/workflows/invalid/invalid_query_composition.yml +20 -0
- silkroute-0.1.0/examples/workflows/invalid/missing_schema_version.yml +15 -0
- silkroute-0.1.0/examples/workflows/invalid/unknown_top_level_section.yml +21 -0
- silkroute-0.1.0/examples/workflows/invalid/unsupported_schema_version.yml +17 -0
- silkroute-0.1.0/examples/workflows/protein_query_composition_labels.yml +40 -0
- silkroute-0.1.0/examples/workflows/protein_query_first_minimal.yml +31 -0
- silkroute-0.1.0/examples/workflows/protein_query_first_with_fields.yml +39 -0
- silkroute-0.1.0/examples/workflows/protein_query_first_with_gui_metadata.yml +47 -0
- silkroute-0.1.0/examples/workflows_demo.ipynb +2339 -0
- silkroute-0.1.0/prek.toml +37 -0
- silkroute-0.1.0/pyproject.toml +164 -0
- silkroute-0.1.0/silkroute/__init__.py +116 -0
- silkroute-0.1.0/silkroute/cli/__init__.py +8 -0
- silkroute-0.1.0/silkroute/cli/_shared.py +396 -0
- silkroute-0.1.0/silkroute/cli/collect_data.py +67 -0
- silkroute-0.1.0/silkroute/cli/helper_commands.py +99 -0
- silkroute-0.1.0/silkroute/cli/interfaces/__init__.py +1 -0
- silkroute-0.1.0/silkroute/cli/interfaces/alphafold.py +35 -0
- silkroute-0.1.0/silkroute/cli/interfaces/biodbnet.py +71 -0
- silkroute-0.1.0/silkroute/cli/interfaces/biogrid.py +39 -0
- silkroute-0.1.0/silkroute/cli/interfaces/brenda.py +345 -0
- silkroute-0.1.0/silkroute/cli/interfaces/chebi.py +106 -0
- silkroute-0.1.0/silkroute/cli/interfaces/chembl.py +51 -0
- silkroute-0.1.0/silkroute/cli/interfaces/chemical_search_query.py +254 -0
- silkroute-0.1.0/silkroute/cli/interfaces/genontology.py +27 -0
- silkroute-0.1.0/silkroute/cli/interfaces/interpro.py +48 -0
- silkroute-0.1.0/silkroute/cli/interfaces/kegg.py +41 -0
- silkroute-0.1.0/silkroute/cli/interfaces/panther.py +74 -0
- silkroute-0.1.0/silkroute/cli/interfaces/pathwaycommons.py +116 -0
- silkroute-0.1.0/silkroute/cli/interfaces/pride.py +70 -0
- silkroute-0.1.0/silkroute/cli/interfaces/proteindatabank.py +30 -0
- silkroute-0.1.0/silkroute/cli/interfaces/pubchem.py +201 -0
- silkroute-0.1.0/silkroute/cli/interfaces/reactome.py +36 -0
- silkroute-0.1.0/silkroute/cli/interfaces/refseq.py +56 -0
- silkroute-0.1.0/silkroute/cli/interfaces/rhea.py +27 -0
- silkroute-0.1.0/silkroute/cli/interfaces/stringdb.py +50 -0
- silkroute-0.1.0/silkroute/cli/interfaces/uniprot.py +18 -0
- silkroute-0.1.0/silkroute/cli/interfaces/uniprot_crossref.py +130 -0
- silkroute-0.1.0/silkroute/cli/interfaces/uniprot_search_ids.py +70 -0
- silkroute-0.1.0/silkroute/cli/interfaces/uniprot_search_query.py +74 -0
- silkroute-0.1.0/silkroute/cli/interfaces/uniprot_search_sequences.py +155 -0
- silkroute-0.1.0/silkroute/cli/main.py +42 -0
- silkroute-0.1.0/silkroute/cli/workflows.py +2138 -0
- silkroute-0.1.0/silkroute/config/.env.example +7 -0
- silkroute-0.1.0/silkroute/config/alphafold/fields.yml +7 -0
- silkroute-0.1.0/silkroute/config/alphafold/init.yml +1 -0
- silkroute-0.1.0/silkroute/config/biodbnet/fields.yml +157 -0
- silkroute-0.1.0/silkroute/config/biogrid/fields.yml +6 -0
- silkroute-0.1.0/silkroute/config/brenda/fields.yml +58 -0
- silkroute-0.1.0/silkroute/config/chebi/fields.yml +58 -0
- silkroute-0.1.0/silkroute/config/chembl/fields.yml +206 -0
- silkroute-0.1.0/silkroute/config/go/fields.yml +24 -0
- silkroute-0.1.0/silkroute/config/interpro/fields.yml +22 -0
- silkroute-0.1.0/silkroute/config/kegg/fields.yml +36 -0
- silkroute-0.1.0/silkroute/config/panther/fields.yml +5 -0
- silkroute-0.1.0/silkroute/config/pathwaycommons/fields.yml +91 -0
- silkroute-0.1.0/silkroute/config/pdb/fields.yml +7 -0
- silkroute-0.1.0/silkroute/config/pdb/init.yml +1 -0
- silkroute-0.1.0/silkroute/config/pride/fields.yml +90 -0
- silkroute-0.1.0/silkroute/config/pubchem/fields.yml +147 -0
- silkroute-0.1.0/silkroute/config/reactome/fields.yml +7 -0
- silkroute-0.1.0/silkroute/config/refseq/fields.yml +6 -0
- silkroute-0.1.0/silkroute/config/rhea/fields.yml +0 -0
- silkroute-0.1.0/silkroute/config/sabiork/fields.yml +0 -0
- silkroute-0.1.0/silkroute/config/string/fields.yml +18 -0
- silkroute-0.1.0/silkroute/config/uniprot_crossref/config_endpoints.yml +148 -0
- silkroute-0.1.0/silkroute/constants/__init__.py +1 -0
- silkroute-0.1.0/silkroute/constants/biodbnet.py +40 -0
- silkroute-0.1.0/silkroute/constants/brenda.py +166 -0
- silkroute-0.1.0/silkroute/constants/databases.py +69 -0
- silkroute-0.1.0/silkroute/constants/interpro.py +19 -0
- silkroute-0.1.0/silkroute/constants/kegg.py +26 -0
- silkroute-0.1.0/silkroute/constants/pathwaycommons.py +47 -0
- silkroute-0.1.0/silkroute/constants/pubchem.py +53 -0
- silkroute-0.1.0/silkroute/constants/reactome.py +14 -0
- silkroute-0.1.0/silkroute/constants/refseq.py +3 -0
- silkroute-0.1.0/silkroute/constants/stringdb.py +59 -0
- silkroute-0.1.0/silkroute/constants/uniprot.py +189 -0
- silkroute-0.1.0/silkroute/core/__init__.py +1 -0
- silkroute-0.1.0/silkroute/core/cache.py +241 -0
- silkroute-0.1.0/silkroute/core/credentials.py +127 -0
- silkroute-0.1.0/silkroute/core/crossref_enricher.py +962 -0
- silkroute-0.1.0/silkroute/core/dbconfig.py +21 -0
- silkroute-0.1.0/silkroute/core/exceptions.py +42 -0
- silkroute-0.1.0/silkroute/core/export.py +210 -0
- silkroute-0.1.0/silkroute/core/interfaces/__init__.py +1 -0
- silkroute-0.1.0/silkroute/core/interfaces/alphafold.py +323 -0
- silkroute-0.1.0/silkroute/core/interfaces/base.py +1496 -0
- silkroute-0.1.0/silkroute/core/interfaces/biodbnet.py +62 -0
- silkroute-0.1.0/silkroute/core/interfaces/biogrid.py +122 -0
- silkroute-0.1.0/silkroute/core/interfaces/brenda.py +148 -0
- silkroute-0.1.0/silkroute/core/interfaces/chebi.py +162 -0
- silkroute-0.1.0/silkroute/core/interfaces/chembl.py +669 -0
- silkroute-0.1.0/silkroute/core/interfaces/genontology.py +133 -0
- silkroute-0.1.0/silkroute/core/interfaces/interpro.py +185 -0
- silkroute-0.1.0/silkroute/core/interfaces/kegg.py +322 -0
- silkroute-0.1.0/silkroute/core/interfaces/panther.py +58 -0
- silkroute-0.1.0/silkroute/core/interfaces/pathwaycommons.py +92 -0
- silkroute-0.1.0/silkroute/core/interfaces/pride.py +74 -0
- silkroute-0.1.0/silkroute/core/interfaces/proteindatabank.py +314 -0
- silkroute-0.1.0/silkroute/core/interfaces/pubchem.py +679 -0
- silkroute-0.1.0/silkroute/core/interfaces/reactome.py +131 -0
- silkroute-0.1.0/silkroute/core/interfaces/refseq.py +128 -0
- silkroute-0.1.0/silkroute/core/interfaces/rhea.py +35 -0
- silkroute-0.1.0/silkroute/core/interfaces/sabiork.py +447 -0
- silkroute-0.1.0/silkroute/core/interfaces/stringdb.py +99 -0
- silkroute-0.1.0/silkroute/core/interfaces/uniprot.py +911 -0
- silkroute-0.1.0/silkroute/core/interfacesconfig.py +40 -0
- silkroute-0.1.0/silkroute/core/metadata.py +299 -0
- silkroute-0.1.0/silkroute/core/utils/__init__.py +1 -0
- silkroute-0.1.0/silkroute/core/utils/base_auxiliary_methods.py +111 -0
- silkroute-0.1.0/silkroute/core/utils/blast_search.py +215 -0
- silkroute-0.1.0/silkroute/core/utils/crossref_enrichment.py +410 -0
- silkroute-0.1.0/silkroute/core/utils/frames.py +59 -0
- silkroute-0.1.0/silkroute/core/utils/query_builders.py +415 -0
- silkroute-0.1.0/silkroute/core/utils/structure_files.py +64 -0
- silkroute-0.1.0/silkroute/core/utils/uniprot_auxiliary_methods.py +341 -0
- silkroute-0.1.0/silkroute/core/utils/xmlhandler.py +143 -0
- silkroute-0.1.0/silkroute/core/workflow/__init__.py +1 -0
- silkroute-0.1.0/silkroute/core/workflow/chebi_execution.py +165 -0
- silkroute-0.1.0/silkroute/core/workflow/chebi_query_catalog.py +119 -0
- silkroute-0.1.0/silkroute/core/workflow/chebi_query_parser.py +78 -0
- silkroute-0.1.0/silkroute/core/workflow/chembl_query_catalog.py +416 -0
- silkroute-0.1.0/silkroute/core/workflow/chembl_query_parser.py +97 -0
- silkroute-0.1.0/silkroute/core/workflow/main_workflow.py +1696 -0
- silkroute-0.1.0/silkroute/core/workflow/pubchem_execution.py +204 -0
- silkroute-0.1.0/silkroute/core/workflow/pubchem_query_catalog.py +176 -0
- silkroute-0.1.0/silkroute/core/workflow/pubchem_query_parser.py +145 -0
- silkroute-0.1.0/silkroute/core/workflow/query_field_catalog.py +244 -0
- silkroute-0.1.0/silkroute/core/workflow/query_interpreter.py +716 -0
- silkroute-0.1.0/silkroute/core/workflow/query_prefixes.py +53 -0
- silkroute-0.1.0/silkroute/core/workflow/schema.py +1078 -0
- silkroute-0.1.0/silkroute/gui/__init__.py +24 -0
- silkroute-0.1.0/silkroute/gui/form_helpers.py +828 -0
- silkroute-0.1.0/silkroute/gui/nicegui_app.py +2053 -0
- silkroute-0.1.0/silkroute/gui/query_builders/__init__.py +5 -0
- silkroute-0.1.0/silkroute/gui/query_builders/chebi.py +71 -0
- silkroute-0.1.0/silkroute/gui/query_builders/chembl.py +356 -0
- silkroute-0.1.0/silkroute/gui/query_builders/common.py +17 -0
- silkroute-0.1.0/silkroute/gui/query_builders/metadata.py +550 -0
- silkroute-0.1.0/silkroute/gui/query_builders/pubchem.py +107 -0
- silkroute-0.1.0/silkroute/gui/query_builders/registry.py +230 -0
- silkroute-0.1.0/silkroute/gui/query_builders/uniprot.py +140 -0
- silkroute-0.1.0/silkroute/gui/uniprot_return_fields.py +99 -0
- silkroute-0.1.0/silkroute/gui/yaml_builder.py +1795 -0
- silkroute-0.1.0/silkroute/logging/__init__.py +16 -0
- silkroute-0.1.0/silkroute/logging/logger.py +266 -0
- silkroute-0.1.0/tests/__init__.py +0 -0
- silkroute-0.1.0/tests/_capture/__init__.py +4 -0
- silkroute-0.1.0/tests/_capture/capture.py +379 -0
- silkroute-0.1.0/tests/_helpers.py +143 -0
- silkroute-0.1.0/tests/cli/__init__.py +0 -0
- silkroute-0.1.0/tests/cli/test_app_structure.py +36 -0
- silkroute-0.1.0/tests/cli/test_fetch_metadata_flag.py +49 -0
- silkroute-0.1.0/tests/cli/test_graph_externalization.py +168 -0
- silkroute-0.1.0/tests/cli/test_logging_apply.py +20 -0
- silkroute-0.1.0/tests/cli/test_shared.py +180 -0
- silkroute-0.1.0/tests/cli/test_workflow_example_configs.py +127 -0
- silkroute-0.1.0/tests/cli/test_workflow_invalid_examples.py +31 -0
- silkroute-0.1.0/tests/cli/test_workflow_notebooks.py +29 -0
- silkroute-0.1.0/tests/cli/test_workflow_schema.py +405 -0
- silkroute-0.1.0/tests/cli/test_workflow_validate.py +174 -0
- silkroute-0.1.0/tests/cli/test_workflows_validation.py +405 -0
- silkroute-0.1.0/tests/conftest.py +10 -0
- silkroute-0.1.0/tests/core/__init__.py +0 -0
- silkroute-0.1.0/tests/core/interfaces/__init__.py +0 -0
- silkroute-0.1.0/tests/core/interfaces/_contract.py +70 -0
- silkroute-0.1.0/tests/core/interfaces/test_alphafold.py +53 -0
- silkroute-0.1.0/tests/core/interfaces/test_base_transforms.py +338 -0
- silkroute-0.1.0/tests/core/interfaces/test_biodbnet.py +65 -0
- silkroute-0.1.0/tests/core/interfaces/test_biogrid.py +55 -0
- silkroute-0.1.0/tests/core/interfaces/test_brenda.py +72 -0
- silkroute-0.1.0/tests/core/interfaces/test_characterization_base.py +166 -0
- silkroute-0.1.0/tests/core/interfaces/test_chebi.py +45 -0
- silkroute-0.1.0/tests/core/interfaces/test_chembl.py +151 -0
- silkroute-0.1.0/tests/core/interfaces/test_chembl_filters.py +120 -0
- silkroute-0.1.0/tests/core/interfaces/test_fetch_batch_cache.py +63 -0
- silkroute-0.1.0/tests/core/interfaces/test_genontology.py +44 -0
- silkroute-0.1.0/tests/core/interfaces/test_interpro_fetch.py +49 -0
- silkroute-0.1.0/tests/core/interfaces/test_kegg.py +53 -0
- silkroute-0.1.0/tests/core/interfaces/test_metadata_provenance.py +50 -0
- silkroute-0.1.0/tests/core/interfaces/test_panther.py +47 -0
- silkroute-0.1.0/tests/core/interfaces/test_pathwaycommons.py +61 -0
- silkroute-0.1.0/tests/core/interfaces/test_pride.py +44 -0
- silkroute-0.1.0/tests/core/interfaces/test_proteindatabank.py +83 -0
- silkroute-0.1.0/tests/core/interfaces/test_pubchem.py +86 -0
- silkroute-0.1.0/tests/core/interfaces/test_pubchem_parsing.py +153 -0
- silkroute-0.1.0/tests/core/interfaces/test_reactome.py +34 -0
- silkroute-0.1.0/tests/core/interfaces/test_reactome_fetch.py +48 -0
- silkroute-0.1.0/tests/core/interfaces/test_refseq.py +68 -0
- silkroute-0.1.0/tests/core/interfaces/test_response_field_coverage.py +388 -0
- silkroute-0.1.0/tests/core/interfaces/test_rhea.py +64 -0
- silkroute-0.1.0/tests/core/interfaces/test_sabiork.py +144 -0
- silkroute-0.1.0/tests/core/interfaces/test_stringdb.py +48 -0
- silkroute-0.1.0/tests/core/interfaces/test_uniprot.py +143 -0
- silkroute-0.1.0/tests/core/test_application_identity.py +22 -0
- silkroute-0.1.0/tests/core/test_cache.py +81 -0
- silkroute-0.1.0/tests/core/test_characterization_crossref.py +100 -0
- silkroute-0.1.0/tests/core/test_characterization_export.py +74 -0
- silkroute-0.1.0/tests/core/test_credentials.py +69 -0
- silkroute-0.1.0/tests/core/test_crossref_graph_xml.py +51 -0
- silkroute-0.1.0/tests/core/test_crossref_per_row.py +41 -0
- silkroute-0.1.0/tests/core/test_exceptions.py +28 -0
- silkroute-0.1.0/tests/core/test_export.py +106 -0
- silkroute-0.1.0/tests/core/test_metadata.py +111 -0
- silkroute-0.1.0/tests/core/utils/__init__.py +0 -0
- silkroute-0.1.0/tests/core/utils/test_base_auxiliary_methods.py +56 -0
- silkroute-0.1.0/tests/core/utils/test_blast_search.py +98 -0
- silkroute-0.1.0/tests/core/utils/test_characterization_query_builders.py +74 -0
- silkroute-0.1.0/tests/core/utils/test_characterization_xmlhandler.py +71 -0
- silkroute-0.1.0/tests/core/utils/test_crossref_enrichment.py +111 -0
- silkroute-0.1.0/tests/core/utils/test_query_builders.py +69 -0
- silkroute-0.1.0/tests/core/utils/test_uniprot_auxiliary_methods.py +208 -0
- silkroute-0.1.0/tests/core/utils/test_validate_parameters.py +54 -0
- silkroute-0.1.0/tests/core/utils/test_xmlhandler.py +64 -0
- silkroute-0.1.0/tests/core/workflow/__init__.py +0 -0
- silkroute-0.1.0/tests/core/workflow/test_compound_query_parsers.py +47 -0
- silkroute-0.1.0/tests/core/workflow/test_compound_routing.py +65 -0
- silkroute-0.1.0/tests/core/workflow/test_labeling.py +63 -0
- silkroute-0.1.0/tests/core/workflow/test_query_interpreter.py +123 -0
- silkroute-0.1.0/tests/core/workflow/test_schema.py +176 -0
- silkroute-0.1.0/tests/core/workflow/test_structure_download_validation.py +38 -0
- silkroute-0.1.0/tests/core/workflow/test_workflow_helpers.py +223 -0
- silkroute-0.1.0/tests/core/workflow/test_workflow_run.py +450 -0
- silkroute-0.1.0/tests/fixtures/_field_coverage_baseline.json +175 -0
- silkroute-0.1.0/tests/fixtures/alphafold/prediction.json +51 -0
- silkroute-0.1.0/tests/fixtures/biodbnet/getpathways.json +626 -0
- silkroute-0.1.0/tests/fixtures/biogrid/interactions.json +28 -0
- silkroute-0.1.0/tests/fixtures/brenda/getKmValue.json +2174 -0
- silkroute-0.1.0/tests/fixtures/chebi/compound.json +600 -0
- silkroute-0.1.0/tests/fixtures/chembl/activity.json +65 -0
- silkroute-0.1.0/tests/fixtures/genontology/term.json +31 -0
- silkroute-0.1.0/tests/fixtures/interpro/entry.json +213 -0
- silkroute-0.1.0/tests/fixtures/kegg/get.json +1 -0
- silkroute-0.1.0/tests/fixtures/panther/geneinfo.json +1131 -0
- silkroute-0.1.0/tests/fixtures/pathwaycommons/fetch.json +31 -0
- silkroute-0.1.0/tests/fixtures/pdb/entry.json +1258 -0
- silkroute-0.1.0/tests/fixtures/pride/project.json +128 -0
- silkroute-0.1.0/tests/fixtures/pubchem/pug_view_compound.json +575 -0
- silkroute-0.1.0/tests/fixtures/reactome/discover.json +125 -0
- silkroute-0.1.0/tests/fixtures/refseq/protein.json +1880 -0
- silkroute-0.1.0/tests/fixtures/rhea/reaction.json +14 -0
- silkroute-0.1.0/tests/fixtures/sabiork/kineticlaws.json +2414 -0
- silkroute-0.1.0/tests/fixtures/stringdb/get_string_ids.json +11 -0
- silkroute-0.1.0/tests/fixtures/uniprot/idmapping_results.json +1978 -0
- silkroute-0.1.0/tests/gui/__init__.py +1 -0
- silkroute-0.1.0/tests/gui/test_chembl_query_builder.py +109 -0
- silkroute-0.1.0/tests/gui/test_form_helpers.py +156 -0
- silkroute-0.1.0/tests/gui/test_query_builder_metadata.py +44 -0
- silkroute-0.1.0/tests/gui/test_query_builder_registry.py +94 -0
- silkroute-0.1.0/tests/gui/test_uniprot_query_builder.py +114 -0
- silkroute-0.1.0/tests/gui/test_yaml_builder.py +1758 -0
- silkroute-0.1.0/tests/test_chembl_query_field_catalog.py +20 -0
- silkroute-0.1.0/tests/test_chembl_query_parser.py +35 -0
- silkroute-0.1.0/tests/test_package.py +42 -0
- silkroute-0.1.0/tests/test_uniprot_query_field_catalog.py +36 -0
- silkroute-0.1.0/tests/test_uniprot_query_interpreter.py +79 -0
- silkroute-0.1.0/tests/test_uniprot_return_fields.py +34 -0
- silkroute-0.1.0/tests/test_workflow_routing.py +183 -0
- silkroute-0.1.0/uv.lock +2649 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
name: pre-commit
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
prek:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v7
|
|
12
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
13
|
+
with:
|
|
14
|
+
python-version: "3.12"
|
|
15
|
+
- name: Install dependencies
|
|
16
|
+
run: uv sync --extra dev --extra tests
|
|
17
|
+
- uses: j178/prek-action@v2
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: publish-pypi
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: publish-pypi-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
|
|
25
|
+
# The version is dynamic (hatch reads silkroute/__init__.py), so a tag can
|
|
26
|
+
# disagree with the package. Catch that before anything reaches PyPI, where
|
|
27
|
+
# a filename is permanent.
|
|
28
|
+
- name: Check the tag matches __version__
|
|
29
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
30
|
+
env:
|
|
31
|
+
TAG: ${{ github.ref_name }}
|
|
32
|
+
run: |
|
|
33
|
+
version="$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' silkroute/__init__.py)"
|
|
34
|
+
if [ -z "$version" ]; then
|
|
35
|
+
echo "::error::could not read __version__ from silkroute/__init__.py"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
if [ "$TAG" != "v$version" ]; then
|
|
39
|
+
echo "::error::tag $TAG does not match silkroute.__version__ ($version)"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
- name: Build distributions
|
|
44
|
+
run: uv build
|
|
45
|
+
|
|
46
|
+
- name: Upload distributions
|
|
47
|
+
uses: actions/upload-artifact@v7
|
|
48
|
+
with:
|
|
49
|
+
name: python-package-distributions
|
|
50
|
+
path: dist/
|
|
51
|
+
|
|
52
|
+
publish:
|
|
53
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
54
|
+
needs: build
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
environment:
|
|
57
|
+
name: pypi
|
|
58
|
+
url: https://pypi.org/p/silkroute
|
|
59
|
+
permissions:
|
|
60
|
+
id-token: write
|
|
61
|
+
steps:
|
|
62
|
+
- name: Download distributions
|
|
63
|
+
uses: actions/download-artifact@v8
|
|
64
|
+
with:
|
|
65
|
+
name: python-package-distributions
|
|
66
|
+
path: dist/
|
|
67
|
+
- name: Publish package distributions to PyPI
|
|
68
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
name: refresh-fixtures
|
|
2
|
+
|
|
3
|
+
# Re-captures the frozen API fixtures in tests/fixtures/ from the live APIs twice
|
|
4
|
+
# a month. Clean drift (offline suite still green) is committed straight to `dev`;
|
|
5
|
+
# breaking drift goes to a PR against `dev` for a human to reconcile. Never runs
|
|
6
|
+
# on push/PR: the offline test suite must stay offline.
|
|
7
|
+
#
|
|
8
|
+
# This file must live on the default branch for `schedule` to fire at all, but the
|
|
9
|
+
# capture itself always runs against `dev` (see the checkout `ref` below).
|
|
10
|
+
on:
|
|
11
|
+
schedule:
|
|
12
|
+
# 06:00 UTC on the 1st and the 15th.
|
|
13
|
+
- cron: "0 6 1,15 * *"
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
inputs:
|
|
16
|
+
apis:
|
|
17
|
+
description: "Space-separated API names to capture (empty = all)"
|
|
18
|
+
required: false
|
|
19
|
+
default: ""
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: write
|
|
23
|
+
pull-requests: write
|
|
24
|
+
|
|
25
|
+
concurrency:
|
|
26
|
+
group: refresh-fixtures
|
|
27
|
+
cancel-in-progress: false
|
|
28
|
+
|
|
29
|
+
env:
|
|
30
|
+
TARGET: dev
|
|
31
|
+
PR_BRANCH: chore/refresh-fixtures
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
capture:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v7
|
|
38
|
+
with:
|
|
39
|
+
ref: dev
|
|
40
|
+
|
|
41
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.12"
|
|
44
|
+
|
|
45
|
+
- name: Install dependencies
|
|
46
|
+
run: uv sync --extra dev --extra tests
|
|
47
|
+
|
|
48
|
+
- name: Validate api selection
|
|
49
|
+
env:
|
|
50
|
+
APIS: ${{ inputs.apis }}
|
|
51
|
+
run: |
|
|
52
|
+
if [ -n "$APIS" ] && ! printf '%s' "$APIS" | grep -qE '^[a-z0-9 ]+$'; then
|
|
53
|
+
echo "::error::invalid apis input: $APIS"
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Credentialed captures (biogrid, refseq, brenda) skip themselves with a log
|
|
58
|
+
# line when their secret is absent, so unset secrets are not an error.
|
|
59
|
+
- name: Capture fixtures
|
|
60
|
+
id: capture
|
|
61
|
+
continue-on-error: true
|
|
62
|
+
env:
|
|
63
|
+
SILKROUTE_CAPTURE: "1"
|
|
64
|
+
APIS: ${{ inputs.apis }}
|
|
65
|
+
SILKROUTE_BIOGRID_API_KEY: ${{ secrets.SILKROUTE_BIOGRID_API_KEY }}
|
|
66
|
+
SILKROUTE_REFSEQ_EMAIL: ${{ secrets.SILKROUTE_REFSEQ_EMAIL }}
|
|
67
|
+
SILKROUTE_BRENDA_EMAIL: ${{ secrets.SILKROUTE_BRENDA_EMAIL }}
|
|
68
|
+
SILKROUTE_BRENDA_PASSWORD: ${{ secrets.SILKROUTE_BRENDA_PASSWORD }}
|
|
69
|
+
run: |
|
|
70
|
+
# shellcheck disable=SC2086 # intentional word splitting: APIS is a list
|
|
71
|
+
uv run python -m tests._capture.capture $APIS 2>&1 | tee capture.log
|
|
72
|
+
|
|
73
|
+
- name: Detect drift
|
|
74
|
+
id: drift
|
|
75
|
+
run: |
|
|
76
|
+
if [ -n "$(git status --porcelain tests/fixtures)" ]; then
|
|
77
|
+
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
78
|
+
git --no-pager diff --stat tests/fixtures
|
|
79
|
+
else
|
|
80
|
+
echo "changed=false" >> "$GITHUB_OUTPUT"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
- name: Run offline test suite against the new fixtures
|
|
84
|
+
id: tests
|
|
85
|
+
if: steps.drift.outputs.changed == 'true'
|
|
86
|
+
continue-on-error: true
|
|
87
|
+
run: uv run pytest -q 2>&1 | tail -n 60 | tee pytest.log
|
|
88
|
+
|
|
89
|
+
- name: Configure git
|
|
90
|
+
if: steps.drift.outputs.changed == 'true'
|
|
91
|
+
run: |
|
|
92
|
+
git config user.name "github-actions[bot]"
|
|
93
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
94
|
+
|
|
95
|
+
# Suite still green on the fresh fixtures -> nothing for a human to decide.
|
|
96
|
+
- name: Commit to dev
|
|
97
|
+
if: steps.drift.outputs.changed == 'true' && steps.tests.outcome == 'success'
|
|
98
|
+
run: |
|
|
99
|
+
set -euo pipefail
|
|
100
|
+
git add tests/fixtures
|
|
101
|
+
git commit -m "test: refresh API fixtures from live APIs"
|
|
102
|
+
# Rebase onto whatever landed on dev while the capture was running; the
|
|
103
|
+
# commit only touches tests/fixtures so a conflict here is a real one.
|
|
104
|
+
git pull --rebase origin "$TARGET"
|
|
105
|
+
git push origin "HEAD:$TARGET"
|
|
106
|
+
|
|
107
|
+
# Suite broke -> an API changed shape. Park it on a branch and let a human
|
|
108
|
+
# reconcile the assertions.
|
|
109
|
+
- name: Open pull request
|
|
110
|
+
if: steps.drift.outputs.changed == 'true' && steps.tests.outcome != 'success'
|
|
111
|
+
env:
|
|
112
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
113
|
+
CAPTURE_OUTCOME: ${{ steps.capture.outcome }}
|
|
114
|
+
TESTS_OUTCOME: ${{ steps.tests.outcome }}
|
|
115
|
+
run: |
|
|
116
|
+
set -euo pipefail
|
|
117
|
+
git switch -c "$PR_BRANCH"
|
|
118
|
+
git add tests/fixtures
|
|
119
|
+
git commit -m "test: refresh API fixtures from live APIs"
|
|
120
|
+
git push --force origin "$PR_BRANCH"
|
|
121
|
+
|
|
122
|
+
{
|
|
123
|
+
echo "Automated re-capture of \`tests/fixtures/\` from the live APIs."
|
|
124
|
+
echo
|
|
125
|
+
echo "- capture step: **$CAPTURE_OUTCOME**"
|
|
126
|
+
echo "- offline suite on the new fixtures: **$TESTS_OUTCOME**"
|
|
127
|
+
echo
|
|
128
|
+
echo "The suite no longer passes on the fresh fixtures, so this drift was"
|
|
129
|
+
echo "**not** committed to \`$TARGET\` directly. An API changed shape: update"
|
|
130
|
+
echo "the affected assertions on this branch (and re-run"
|
|
131
|
+
echo "\`REGEN_FIELD_BASELINE=1 uv run pytest\` if the field-coverage baseline"
|
|
132
|
+
echo "moved) before merging."
|
|
133
|
+
echo
|
|
134
|
+
echo "<details><summary>capture log</summary>"
|
|
135
|
+
echo
|
|
136
|
+
echo '```'
|
|
137
|
+
tail -n 60 capture.log
|
|
138
|
+
echo '```'
|
|
139
|
+
echo
|
|
140
|
+
echo "</details>"
|
|
141
|
+
if [ -f pytest.log ]; then
|
|
142
|
+
echo
|
|
143
|
+
echo "<details><summary>pytest tail</summary>"
|
|
144
|
+
echo
|
|
145
|
+
echo '```'
|
|
146
|
+
cat pytest.log
|
|
147
|
+
echo '```'
|
|
148
|
+
echo
|
|
149
|
+
echo "</details>"
|
|
150
|
+
fi
|
|
151
|
+
} > pr-body.md
|
|
152
|
+
|
|
153
|
+
if [ -n "$(gh pr list --head "$PR_BRANCH" --state open --json number --jq '.[].number')" ]; then
|
|
154
|
+
gh pr edit "$PR_BRANCH" --body-file pr-body.md
|
|
155
|
+
else
|
|
156
|
+
gh pr create \
|
|
157
|
+
--head "$PR_BRANCH" \
|
|
158
|
+
--base "$TARGET" \
|
|
159
|
+
--title "test: refresh API fixtures (suite needs reconciling)" \
|
|
160
|
+
--body-file pr-body.md
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
- name: Report capture failures
|
|
164
|
+
if: steps.capture.outcome == 'failure'
|
|
165
|
+
run: |
|
|
166
|
+
echo "::error::capture exited non-zero; see the capture log for the failing APIs"
|
|
167
|
+
exit 1
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
paths:
|
|
6
|
+
- "silkroute/**"
|
|
7
|
+
- "tests/**"
|
|
8
|
+
- "pyproject.toml"
|
|
9
|
+
- "uv.lock"
|
|
10
|
+
- ".github/workflows/tests.yml"
|
|
11
|
+
pull_request:
|
|
12
|
+
paths:
|
|
13
|
+
- "silkroute/**"
|
|
14
|
+
- "tests/**"
|
|
15
|
+
- "pyproject.toml"
|
|
16
|
+
- "uv.lock"
|
|
17
|
+
- ".github/workflows/tests.yml"
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
tests:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
strategy:
|
|
23
|
+
fail-fast: false
|
|
24
|
+
matrix:
|
|
25
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v7
|
|
28
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python-version }}
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: uv sync --extra dev --extra tests --extra gui
|
|
33
|
+
- name: Run tests
|
|
34
|
+
run: uv run pytest -q
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
.ipynb_checkpoints/
|
|
6
|
+
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
.Python
|
|
9
|
+
build/
|
|
10
|
+
develop-eggs/
|
|
11
|
+
dist/
|
|
12
|
+
downloads/
|
|
13
|
+
eggs/
|
|
14
|
+
.eggs/
|
|
15
|
+
lib/
|
|
16
|
+
lib64/
|
|
17
|
+
parts/
|
|
18
|
+
sdist/
|
|
19
|
+
var/
|
|
20
|
+
wheels/
|
|
21
|
+
share/python-wheels/
|
|
22
|
+
*.egg-info/
|
|
23
|
+
.installed.cfg
|
|
24
|
+
*.egg
|
|
25
|
+
MANIFEST
|
|
26
|
+
|
|
27
|
+
# Environments
|
|
28
|
+
.env
|
|
29
|
+
.venv
|
|
30
|
+
env/
|
|
31
|
+
venv/
|
|
32
|
+
ENV/
|
|
33
|
+
env.bak/
|
|
34
|
+
venv.bak/
|
|
35
|
+
|
|
36
|
+
# IDEs / Editors
|
|
37
|
+
.vscode/
|
|
38
|
+
.idea/
|
|
39
|
+
*.sublime-project
|
|
40
|
+
*.sublime-workspace
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# Custom directories and files
|
|
44
|
+
input/
|
|
45
|
+
src/db
|
|
46
|
+
output/
|
|
47
|
+
tmp/
|
|
48
|
+
results/
|
|
49
|
+
src/.alphafold_cache/
|
|
50
|
+
src/.pdb_cache/
|
|
51
|
+
|
|
52
|
+
*.json
|
|
53
|
+
*.csv
|
|
54
|
+
*.cif
|
|
55
|
+
*.pdb
|
|
56
|
+
*.html
|
|
57
|
+
*.log
|
|
58
|
+
*.backup
|
|
59
|
+
*.parquet
|
|
60
|
+
.env
|
|
61
|
+
|
|
62
|
+
!examples/data/*.csv
|
|
63
|
+
|
|
64
|
+
# Test fixtures must be tracked despite the global *.json / *.csv rules above
|
|
65
|
+
!tests/**/*.json
|
|
66
|
+
!tests/**/*.csv
|
|
67
|
+
!tests/**/
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to AI agents when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**SilkRoute** is a Python library and CLI to download and integrate biological
|
|
8
|
+
data from many web APIs (UniProt, AlphaFold, BioGRID, KEGG, ChEMBL, Reactome, etc.).
|
|
9
|
+
It is part of the Kren AI Lab ecosystem alongside **Sylphy** (sequence encoders /
|
|
10
|
+
embeddings) and **Roxy** (classical descriptors).
|
|
11
|
+
|
|
12
|
+
Input: identifiers / queries per database. Output: parsed records as
|
|
13
|
+
`polars.DataFrame` / JSON / XML, with on-disk caching.
|
|
14
|
+
|
|
15
|
+
## Package Layout
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
silkroute/
|
|
19
|
+
__init__.py # public API (lazy via __getattr__) + __version__
|
|
20
|
+
cli/
|
|
21
|
+
main.py # Typer root app
|
|
22
|
+
interfaces/ # per-database CLI sub-apps
|
|
23
|
+
constants/ # per-database constants + DBConfig instances (databases.py)
|
|
24
|
+
core/
|
|
25
|
+
interfaces/
|
|
26
|
+
base.py # BaseAPIInterface (fetch_single/fetch_batch/cache/parse)
|
|
27
|
+
<db>.py # one client per database, subclass of BaseAPIInterface
|
|
28
|
+
utils/ # query builders, parsing helpers, BLAST
|
|
29
|
+
workflow/ # multi-step download workflows
|
|
30
|
+
cache.py, export.py, dbconfig.py, interfacesconfig.py
|
|
31
|
+
logging/ # get_logger, unified setup
|
|
32
|
+
tests/ # mirrors source tree, offline
|
|
33
|
+
examples/ # standalone demo scripts
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Development Commands
|
|
37
|
+
|
|
38
|
+
This project uses `uv` and `taskipy`.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
uv sync --extra dev --extra tests
|
|
42
|
+
uv run task test # pytest -q
|
|
43
|
+
uv run task lint # ruff check
|
|
44
|
+
uv run task lint-fix
|
|
45
|
+
uv run task format
|
|
46
|
+
uv run task ty # ty check
|
|
47
|
+
uv run task pyrefly
|
|
48
|
+
uv run silkroute --help
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Architecture Notes
|
|
52
|
+
|
|
53
|
+
- New API clients inherit from `BaseAPIInterface` and declare their `DBConfig`
|
|
54
|
+
(URL + cache/config dirs) from `constants/databases.py`.
|
|
55
|
+
- `fetch_single` / `fetch_batch` handle caching, optional parsing, and output
|
|
56
|
+
format conversion (json / dataframe / xml). `parse` + `fetch` are abstract.
|
|
57
|
+
- Per-database field extraction is config-driven (YAML in the config dir).
|
|
58
|
+
|
|
59
|
+
## Key Invariants
|
|
60
|
+
|
|
61
|
+
- No import side effects: the top-level public API is lazy (`__getattr__`); importing
|
|
62
|
+
`silkroute` must not pull heavy deps (e.g. `zeep` for BRENDA).
|
|
63
|
+
- Use `logging` (`get_logger`), never `print`.
|
|
64
|
+
- A `fetch` override returns the empty of its own success type (a list endpoint
|
|
65
|
+
returns `[]`, an object endpoint `{}`); never `None`. The error-vs-empty reason
|
|
66
|
+
is recorded in `metadata.failed` (`request_error` / `empty_result`), not the
|
|
67
|
+
return value. (`chebi`/`pubchem` are genuinely method-polymorphic and return `{}`.)
|
|
68
|
+
- Tests run offline: HTTP is mocked (`niquests_mock`) behind `conftest` fixtures.
|
|
69
|
+
- Tests mirror the source layout.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AGENTS.md
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
This guide covers local setup, day-to-day commands, and the code structure behind
|
|
4
|
+
SilkRoute.
|
|
5
|
+
|
|
6
|
+
## Local Setup
|
|
7
|
+
|
|
8
|
+
SilkRoute uses `uv` for environment management and `taskipy` for common developer
|
|
9
|
+
commands.
|
|
10
|
+
|
|
11
|
+
Install development dependencies:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv sync --extra dev --extra tests
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Editable install with `pip` also works:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install -e ".[dev,tests]"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Common Commands
|
|
24
|
+
|
|
25
|
+
Run tests:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv run task test
|
|
29
|
+
uv run task test-v
|
|
30
|
+
uv run task test-cov
|
|
31
|
+
uv run pytest tests/core/interfaces/test_reactome.py -v
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Lint, format, and type-check:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
uv run task lint
|
|
38
|
+
uv run task lint-fix
|
|
39
|
+
uv run task format
|
|
40
|
+
uv run task sort-imports
|
|
41
|
+
uv run task ty
|
|
42
|
+
uv run task pyrefly
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Build the package:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv build
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Smoke-test the CLI:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uv run silkroute --help
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Project Layout
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
silkroute/
|
|
61
|
+
├── cli/ # Typer commands (root in cli/main.py)
|
|
62
|
+
│ └── interfaces/ # Per-database CLI sub-apps
|
|
63
|
+
├── constants/ # Per-database constants and DBConfig values
|
|
64
|
+
├── core/
|
|
65
|
+
│ ├── interfaces/ # BaseAPIInterface + per-database API clients
|
|
66
|
+
│ ├── utils/ # Shared helpers (query builders, parsing, BLAST)
|
|
67
|
+
│ ├── workflow/ # Multi-step download workflows
|
|
68
|
+
│ ├── cache.py # Cache helpers
|
|
69
|
+
│ └── export.py # Output/export helpers
|
|
70
|
+
├── logging/ # Unified logging setup
|
|
71
|
+
└── __init__.py # Public API (lazy) + __version__
|
|
72
|
+
|
|
73
|
+
tests/ # Mirrors the source tree
|
|
74
|
+
examples/ # Scripts for manual exploration
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Design Rules
|
|
78
|
+
|
|
79
|
+
- Avoid side effects on import (public top-level API is lazy via `__getattr__`).
|
|
80
|
+
- Use logging instead of `print`.
|
|
81
|
+
- New interfaces inherit from `BaseAPIInterface` and declare their `DBConfig`.
|
|
82
|
+
- Keep the public API small and explicit.
|
|
83
|
+
|
|
84
|
+
## Testing Notes
|
|
85
|
+
|
|
86
|
+
The test suite is designed to run offline.
|
|
87
|
+
|
|
88
|
+
- HTTP interactions are mocked (`niquests_mock`), isolated behind `conftest` fixtures.
|
|
89
|
+
- Test layout mirrors the source layout.
|
|
90
|
+
- New features should ship with focused unit tests and CLI coverage when applicable.
|
|
91
|
+
|
|
92
|
+
### Offline interface suite and fixtures
|
|
93
|
+
|
|
94
|
+
Every API interface has an offline test module under
|
|
95
|
+
`tests/core/interfaces/test_<api>.py`. Each one replays a frozen API response
|
|
96
|
+
from `tests/fixtures/<api>/<case>.json` and asserts three things:
|
|
97
|
+
|
|
98
|
+
- **fetch** builds the right URL/params and unwraps the body as expected;
|
|
99
|
+
- **parse** returns the expected keys/shape (not exact values);
|
|
100
|
+
- **fetch_single** round-trips through the cache (1 request on the first call,
|
|
101
|
+
0 on the second).
|
|
102
|
+
|
|
103
|
+
Non-HTTP / credentialed clients are mocked at the client boundary instead of via
|
|
104
|
+
`niquests_mock`: BRENDA (zeep SOAP `Client`), RefSeq (`Bio.Entrez`), BioGRID (API key
|
|
105
|
+
supplied explicitly), and the standalone UniProt id-mapping flow
|
|
106
|
+
(submit → status → details → results).
|
|
107
|
+
|
|
108
|
+
Fixtures are loaded with the helpers in `tests/_helpers.py`
|
|
109
|
+
(`load_fixture` / `load_fixture_text`). They are committed despite the global
|
|
110
|
+
`*.json` gitignore rule thanks to the `!tests/**/*.json` exception.
|
|
111
|
+
|
|
112
|
+
### Regenerating fixtures (network-gated)
|
|
113
|
+
|
|
114
|
+
`tests/_capture/capture.py` regenerates the fixtures from the real APIs. It is
|
|
115
|
+
**never** run by the test suite (and never on push / pull request) and refuses to
|
|
116
|
+
do anything unless `SILKROUTE_CAPTURE=1` is set:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
SILKROUTE_CAPTURE=1 uv run python -m tests._capture.capture # all APIs
|
|
120
|
+
SILKROUTE_CAPTURE=1 uv run python -m tests._capture.capture rhea chebi
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Each capture drives the real interface, so the request (URL, params, method,
|
|
124
|
+
body) matches production exactly, and records the raw HTTP body the interface
|
|
125
|
+
receives — the same payload the offline tests register with `niquests_mock`.
|
|
126
|
+
|
|
127
|
+
Credentialed / non-HTTP APIs are captured only when their env vars are present
|
|
128
|
+
(`SILKROUTE_BIOGRID_API_KEY`, `SILKROUTE_REFSEQ_EMAIL`,
|
|
129
|
+
`SILKROUTE_BRENDA_EMAIL`/`SILKROUTE_BRENDA_PASSWORD`); otherwise they are skipped
|
|
130
|
+
with a log line. These read from a gitignored `.env` at the repo root, loaded
|
|
131
|
+
automatically by the capture script.
|
|
132
|
+
|
|
133
|
+
Because fixtures are real bodies, re-capturing can change response shape and
|
|
134
|
+
require updating the affected test assertions — that is expected and the point:
|
|
135
|
+
the tests then reflect what the APIs actually return.
|
|
136
|
+
|
|
137
|
+
### Scheduled re-capture (`refresh-fixtures` workflow)
|
|
138
|
+
|
|
139
|
+
`.github/workflows/refresh-fixtures.yml` runs the capture script on the 1st and
|
|
140
|
+
15th of every month at 06:00 UTC (also on `workflow_dispatch`, with an optional
|
|
141
|
+
space-separated `apis` input). It always checks out and targets `dev`, never `main`
|
|
142
|
+
— the file only lives on the default branch because that is where GitHub fires
|
|
143
|
+
`schedule` from.
|
|
144
|
+
|
|
145
|
+
What happens next depends on the offline suite, run in-job against the fresh
|
|
146
|
+
fixtures:
|
|
147
|
+
|
|
148
|
+
| fixtures changed | `pytest -q` | outcome |
|
|
149
|
+
| --- | --- | --- |
|
|
150
|
+
| no | not run | nothing; job green |
|
|
151
|
+
| yes | passes | committed straight to `dev` |
|
|
152
|
+
| yes | fails | pushed to `chore/refresh-fixtures`, PR opened against `dev` |
|
|
153
|
+
|
|
154
|
+
So a PR appearing means an API changed shape and the assertions need reconciling:
|
|
155
|
+
fix them on the branch, and re-run `REGEN_FIELD_BASELINE=1 uv run pytest` if the
|
|
156
|
+
field-coverage baseline moved. The PR body carries the capture log and the tail of
|
|
157
|
+
the failing run. A re-run reuses the same branch and PR rather than stacking new
|
|
158
|
+
ones.
|
|
159
|
+
|
|
160
|
+
The job itself goes red only when the capture script exits non-zero, so a dead or
|
|
161
|
+
renamed endpoint is visible in the Actions tab. That is independent of the commit
|
|
162
|
+
decision: a partial capture whose fixtures still pass is committed to `dev` (the
|
|
163
|
+
APIs that answered gave valid bodies) *and* leaves the run red for the one that
|
|
164
|
+
did not.
|
|
165
|
+
|
|
166
|
+
Credentialed captures need repository secrets with the same names as the env vars
|
|
167
|
+
above (`SILKROUTE_BIOGRID_API_KEY`, `SILKROUTE_REFSEQ_EMAIL`,
|
|
168
|
+
`SILKROUTE_BRENDA_EMAIL`, `SILKROUTE_BRENDA_PASSWORD`); without them those three
|
|
169
|
+
APIs skip themselves and their fixtures stay frozen.
|
|
170
|
+
|
|
171
|
+
## Releasing
|
|
172
|
+
|
|
173
|
+
`.github/workflows/publish-pypi.yml` builds with `uv build` and publishes to PyPI
|
|
174
|
+
via [trusted publishing](https://docs.pypi.org/trusted-publishers/) (OIDC, no API
|
|
175
|
+
token stored in the repo). It triggers on any `v*` tag, and on `workflow_dispatch`
|
|
176
|
+
for a build-only dry run — the `publish` job is gated on `startsWith(github.ref,
|
|
177
|
+
'refs/tags/v')`, so a manual run only produces artifacts.
|
|
178
|
+
|
|
179
|
+
The version is dynamic: hatch reads `__version__` from `silkroute/__init__.py`. To
|
|
180
|
+
cut a release, bump it, commit, then tag the same number:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
git tag v0.2.0 && git push origin v0.2.0
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The build job refuses to continue when the tag and `__version__` disagree, because
|
|
187
|
+
a filename on PyPI cannot be reused after upload.
|
|
188
|
+
|
|
189
|
+
One-time setup on PyPI: add a trusted publisher for project `silkroute` with owner
|
|
190
|
+
`kren-ai-lab`, repository `silk-route`, workflow `publish-pypi.yml`, environment
|
|
191
|
+
`pypi`. The `pypi` GitHub environment is where any release approvals or reviewers
|
|
192
|
+
would go.
|
|
193
|
+
|
|
194
|
+
## Additional Context
|
|
195
|
+
|
|
196
|
+
For more architecture detail, see [AGENTS.md](AGENTS.md).
|
silkroute-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kren AI Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|