linkml-reference-validator 0.3.0rc1__tar.gz → 0.3.0rc2__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.
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/PKG-INFO +1 -1
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/pmc.py +43 -3
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/reference_fetcher.py +10 -2
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/pmid.py +6 -3
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/models.py +14 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_no_cache_downgrade.py +15 -1
- linkml_reference_validator-0.3.0rc2/tests/test_pmc_modern_container.py +59 -0
- linkml_reference_validator-0.3.0rc2/tests/test_serve_stale_html_optin.py +75 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.claude/.mcp.json +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.claude/settings.json +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.copier-answers.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.devcontainer/devcontainer.json +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.devcontainer/post_create.sh +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.editorconfig +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/actions/claude-code-action/action.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/actions/claude-issue-summarize-action/action.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/actions/claude-issue-triage-action/action.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/ai-controllers.json +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/copilot-instructions.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/copilot-setup-steps.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/dependabot.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/claude-code-review.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/claude-issue-summarize.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/claude-issue-triage.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/claude-ontology-review.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/claude.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/deploy-docs.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/dragon-ai.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/main.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/workflows/pypi-publish.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.gitignore +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.goosehints +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.pre-commit-config.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.yamllint.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/AGENTS.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/BUG_GEO_ACCESSION_TO_UID.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/BUG_ZENODO_DOI_AND_URL_HANDLING.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/CLAUDE.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/CLI-ISSUES.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/CODE_OF_CONDUCT.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/CONTRIBUTING.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/FEATURE_REQUEST_REPAIR.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/LICENSE +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/README.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/REVIEW2.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/REVIEW3.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/ai.just +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/copilot-instructions.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/about.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/assets/zotero-find-full-text.png +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/concepts/content-types.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/concepts/editorial-conventions.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/concepts/how-it-works.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/elements/.gitkeep +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/add-reference-source.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/export-cache-to-zotero.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/fetch-full-text-and-pdfs.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/repair-validation-errors.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/skip-unsupported-references.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/use-local-files-and-urls.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/validate-clinical-trials.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/validate-dois.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/validate-entrez.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/validate-obo-files.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/validate-titles.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/how-to/validate-urls.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/index.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/notebooks/01_getting_started.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/notebooks/02_advanced_usage.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/notebooks/03_python_api.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/notebooks/04_obo_validation.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/notebooks/05_geo_validation.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/quickstart.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/reference/cli.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/reference/splitting.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/setup-guide.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/superpowers/plans/2026-06-12-modular-pdf-fulltext-fetching.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/superpowers/plans/2026-08-05-private-library-full-text.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/superpowers/specs/2026-06-12-modular-pdf-fulltext-fetching-design.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/superpowers/specs/2026-08-05-private-library-full-text-design.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/templates-linkml/README.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/todo.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/troubleshooting.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/tutorials/complete-workflow.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/examples/README.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/justfile +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/mkdocs.yml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/mypy.ini +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/notebooks/01_getting_started.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/notebooks/02_advanced_usage.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/notebooks/03_python_api.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/notebooks/README.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/project/README.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/project.justfile +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/pyproject.toml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/pytest.ini +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/_version.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/cli/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/cli/cache.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/cli/lookup.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/cli/repair.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/cli/shared.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/cli/validate.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/acquire.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/csl_export.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/extract/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/extract/base.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/extract/html.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/extract/pdf.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/extract/xml.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/base.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/epmc_preprint.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/json_api.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/loader.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/openalex.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/unpaywall.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/fulltext/zotero.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/identifiers.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/base.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/clinicaltrials.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/doi.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/entrez.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/file.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/json_api.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/loader.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/ppr.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/url.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/sources/utils.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/etl/text_extractor.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/field_detection.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/matching.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/plugins/REVIEW.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/plugins/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/plugins/reference_validation_plugin.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/validation/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/validation/fuzzy_text_utils.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/validation/repairer.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/src/linkml_reference_validator/validation/supporting_text_validator.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/conftest.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/data/test_data_deep_nesting_invalid.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/data/test_data_deep_nesting_valid.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/data/test_data_invalid.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/data/test_data_valid.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/data/test_schema.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/data/test_schema_deep_nesting.yaml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/GEO_GSE12345.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMC_TEST001.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMC_TEST001.txt +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMC_TEST002.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMC_TEST002.txt +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMID_TEST001.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMID_TEST001.txt +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMID_TEST002.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMID_TEST002.txt +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMID_TEST003.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/PMID_TEST003.txt +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/clinicaltrials_NCT00000001.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/fulltext_html/README.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/fulltext_html/dspace-32894695.html +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/fulltext_html/iris-19049553.html +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/fulltext_html/plos-0000308.html +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/jats/PMC5593426.xml +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/jats/README.md +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/fixtures/sample.obo +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_absent_abstract_recovery.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_acquire.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_cache_author_recovery.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_cli.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_cli_cache_enrich.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_cli_cache_export.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_cli_cache_reference.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_cli_lookup.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_cli_repair.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_clinicaltrials_cache.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_clinicaltrials_integration.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_deep_nesting.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_doi_preprint.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_e2e_integration.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_empty_snippets.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_epmc_preprint_provider.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_extractor_fidelity.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_extractors.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_field_detection.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_frontmatter_and_doi_case.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_fulltext_loader.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_fulltext_providers.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_fuzzy_suggestions.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_geo_integration.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_html_fulltext_acceptance.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_identifiers.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_jats_tables.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_json_api_source.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_ligature_normalization.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_models.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_open_access_policy.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_optional_linkml_dependency.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_plugin_integration.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_pmc_fulltext.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_pmid_network.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_ppr_source.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_real_validation.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_reference_fetcher.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_repair.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_source_utils.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_sources.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_split_supporting_text.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_supporting_text_validator.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_text_extractor.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_title_validation.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_unknown_slot_traversal.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_validation_config.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_validation_counts.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/tests/test_zotero_provider.py +0 -0
- {linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/uv.lock +0 -0
|
@@ -6,7 +6,7 @@ fetched from the PMC XML API (with an HTML fallback) and extracted via XMLExtrac
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
import time
|
|
9
|
-
from typing import Optional, Union
|
|
9
|
+
from typing import Any, Optional, Union
|
|
10
10
|
|
|
11
11
|
from Bio import Entrez # type: ignore
|
|
12
12
|
from bs4 import BeautifulSoup # type: ignore
|
|
@@ -38,6 +38,45 @@ class TransientFullTextError(RuntimeError):
|
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
#: Classes PMC has used for the article body. ``main-article-body`` is what it
|
|
42
|
+
#: serves now, on a ``<section>``; the two ``div`` classes are the older markup
|
|
43
|
+
#: and are kept so entries cached against them still re-extract.
|
|
44
|
+
#:
|
|
45
|
+
#: Deliberately not ``body``, which PMC pairs with ``main-article-body`` on the
|
|
46
|
+
#: same element. Matching it alone would match every page's ``<body>``, and the
|
|
47
|
+
#: structural test is the only thing standing between this fetch and caching a
|
|
48
|
+
#: bot-check interstitial served on an HTTP 200.
|
|
49
|
+
PMC_ARTICLE_BODY_CLASSES = ("main-article-body", "article-body", "tsec")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _find_pmc_article_body(soup: BeautifulSoup) -> Optional[Any]:
|
|
53
|
+
"""Return PMC's article-body element, or None if the page has none.
|
|
54
|
+
|
|
55
|
+
Matches on class rather than element name: the container moved from ``div``
|
|
56
|
+
to ``section`` when PMC changed its markup, so pinning the tag is what broke
|
|
57
|
+
the previous version for every article.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
soup: A parsed PMC article page
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
The article-body element, or None
|
|
64
|
+
|
|
65
|
+
Examples:
|
|
66
|
+
>>> from bs4 import BeautifulSoup
|
|
67
|
+
>>> html = '<section class="body main-article-body"><p>Text.</p></section>'
|
|
68
|
+
>>> _find_pmc_article_body(BeautifulSoup(html, "html.parser")) is not None
|
|
69
|
+
True
|
|
70
|
+
>>> _find_pmc_article_body(BeautifulSoup("<body><p>x</p></body>", "html.parser")) is None
|
|
71
|
+
True
|
|
72
|
+
"""
|
|
73
|
+
for class_name in PMC_ARTICLE_BODY_CLASSES:
|
|
74
|
+
found = soup.find(class_=class_name)
|
|
75
|
+
if found is not None:
|
|
76
|
+
return found
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
41
80
|
@FullTextProviderRegistry.register
|
|
42
81
|
class PMCFullTextProvider(FullTextProvider):
|
|
43
82
|
"""Provide PMC full text for a reference identified by PMID/PMCID.
|
|
@@ -132,7 +171,8 @@ class PMCFullTextProvider(FullTextProvider):
|
|
|
132
171
|
|
|
133
172
|
This is the one page fetch the OA providers' "a landing page is not full
|
|
134
173
|
text" rule does not cover, and what makes it safe is the requirement
|
|
135
|
-
below: text is returned only from
|
|
174
|
+
below: text is returned only from an element carrying one of
|
|
175
|
+
:data:`PMC_ARTICLE_BODY_CLASSES`.
|
|
136
176
|
A bot-check interstitial -- which PMC serves on an HTTP 200, so no status
|
|
137
177
|
check sees it -- carries neither, so this yields ``None`` rather than
|
|
138
178
|
caching the page. The ``oa_url`` fallback that was removed had no such
|
|
@@ -152,7 +192,7 @@ class PMCFullTextProvider(FullTextProvider):
|
|
|
152
192
|
)
|
|
153
193
|
|
|
154
194
|
soup = BeautifulSoup(response.content, "html.parser")
|
|
155
|
-
article_body =
|
|
195
|
+
article_body = _find_pmc_article_body(soup)
|
|
156
196
|
if article_body:
|
|
157
197
|
# The region is selected here, but the text comes out of the shared
|
|
158
198
|
# extractor rather than a private copy of the paragraph walk, so
|
|
@@ -424,7 +424,11 @@ class ReferenceFetcher:
|
|
|
424
424
|
if force_refresh:
|
|
425
425
|
return FetchOutcome(content=None)
|
|
426
426
|
|
|
427
|
-
stale = self._load_from_disk(
|
|
427
|
+
stale = self._load_from_disk(
|
|
428
|
+
normalized_reference_id,
|
|
429
|
+
allow_stale=True,
|
|
430
|
+
allow_stale_html=self.config.serve_stale_html_full_text,
|
|
431
|
+
)
|
|
428
432
|
if stale is None:
|
|
429
433
|
return FetchOutcome(content=None)
|
|
430
434
|
|
|
@@ -520,7 +524,11 @@ class ReferenceFetcher:
|
|
|
520
524
|
# May its text be served? Asked without the bypass, so stale HTML is
|
|
521
525
|
# withheld here exactly as _stale_fallback withholds it, and validation
|
|
522
526
|
# falls back to the freshly fetched abstract.
|
|
523
|
-
servable = self._load_from_disk(
|
|
527
|
+
servable = self._load_from_disk(
|
|
528
|
+
normalized_reference_id,
|
|
529
|
+
allow_stale=True,
|
|
530
|
+
allow_stale_html=self.config.serve_stale_html_full_text,
|
|
531
|
+
)
|
|
524
532
|
return FetchOutcome(content=servable or fresh, served_stale=True)
|
|
525
533
|
|
|
526
534
|
def _report_shrinking_refresh(
|
|
@@ -582,9 +582,12 @@ class PMIDSource(ReferenceSource):
|
|
|
582
582
|
return None
|
|
583
583
|
|
|
584
584
|
soup = BeautifulSoup(response.content, "html.parser")
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
)
|
|
585
|
+
# Shared with the PMC full-text provider: the container moved from a
|
|
586
|
+
# ``div`` to a ``section`` and changed class, so both call sites went
|
|
587
|
+
# blind at once (dismech#12672).
|
|
588
|
+
from linkml_reference_validator.etl.fulltext.pmc import _find_pmc_article_body
|
|
589
|
+
|
|
590
|
+
article_body = _find_pmc_article_body(soup)
|
|
588
591
|
|
|
589
592
|
if article_body:
|
|
590
593
|
# Region selected here, text extracted by the shared extractor, for
|
|
@@ -510,6 +510,20 @@ class ReferenceValidationConfig(BaseModel):
|
|
|
510
510
|
"when a metadata source does not already return full text."
|
|
511
511
|
),
|
|
512
512
|
)
|
|
513
|
+
serve_stale_html_full_text: bool = Field(
|
|
514
|
+
default=False,
|
|
515
|
+
description=(
|
|
516
|
+
"If True, serve a stale full_text_html cache entry as evidence instead "
|
|
517
|
+
"of withholding it. Off by default: a pre-stamp HTML entry may be a "
|
|
518
|
+
"publisher landing page rather than the article, and the default "
|
|
519
|
+
"assumes a re-fetch can repair it. Set this only for a cache you "
|
|
520
|
+
"control and review -- for a PMC-only article the repair route is "
|
|
521
|
+
"unreachable (PMC answers a Python HTTP client with a bot-check "
|
|
522
|
+
"interstitial on an HTTP 200), so the guard withholds text that "
|
|
523
|
+
"cannot be recovered. Affects serving only, never overwriting, and "
|
|
524
|
+
"the entry is left un-stamped so a later run still retries."
|
|
525
|
+
),
|
|
526
|
+
)
|
|
513
527
|
full_text_providers: list[str] = Field(
|
|
514
528
|
default_factory=lambda: ["pmc", "epmc_preprint", "unpaywall", "openalex"],
|
|
515
529
|
description=(
|
|
@@ -76,7 +76,21 @@ def _write_cache(cache_dir, reference_id, content_type, body, stamped=False):
|
|
|
76
76
|
|
|
77
77
|
@pytest.fixture
|
|
78
78
|
def fetcher(tmp_path):
|
|
79
|
-
|
|
79
|
+
"""A fetcher with the full-text chain off.
|
|
80
|
+
|
|
81
|
+
These tests are about what a *refresh that loses full text* does to the
|
|
82
|
+
cached file, so the chain has to be absent rather than merely expected to
|
|
83
|
+
fail. With it on they reach the network: the PMC HTML fallback fires and the
|
|
84
|
+
outcome depends on what PMC serves for PMC21078 that minute. They passed for
|
|
85
|
+
a while only because the fallback's container selector matched nothing at
|
|
86
|
+
all -- fixing that (dismech#12672) turned two of them red, which is the test
|
|
87
|
+
depending on a bug rather than the bug being load-bearing.
|
|
88
|
+
"""
|
|
89
|
+
return ReferenceFetcher(
|
|
90
|
+
ReferenceValidationConfig(
|
|
91
|
+
cache_dir=tmp_path, email="me@example.org", fetch_full_text=False
|
|
92
|
+
)
|
|
93
|
+
)
|
|
80
94
|
|
|
81
95
|
|
|
82
96
|
def _fetch_returning(fetcher, content_type, body):
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""PMC's current article markup must be recognised by the HTML fallback.
|
|
2
|
+
|
|
3
|
+
The fallback looked for ``div.article-body`` or ``div.tsec``. PMC serves neither
|
|
4
|
+
today: the article sits in ``<section class="body main-article-body">`` -- a
|
|
5
|
+
different element *and* a different class. So the path declined for every PMC
|
|
6
|
+
article, and the "retry when the source serves full text again to repair it"
|
|
7
|
+
advice printed when a stale ``full_text_html`` entry is withheld pointed at a
|
|
8
|
+
route that could never succeed (reported downstream as monarch-initiative/dismech#12672).
|
|
9
|
+
|
|
10
|
+
The structural test is what makes this fetch safe -- a bot-check interstitial
|
|
11
|
+
arrives on an HTTP 200 and carries no article container -- so widening the
|
|
12
|
+
selector must not widen it to something an interstitial or a navigation page
|
|
13
|
+
would satisfy.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
from bs4 import BeautifulSoup
|
|
20
|
+
|
|
21
|
+
from linkml_reference_validator.etl.fulltext.pmc import _find_pmc_article_body
|
|
22
|
+
|
|
23
|
+
BODY = "<p>" + ("Real article prose. " * 40) + "</p>"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.mark.parametrize(
|
|
27
|
+
"markup,label",
|
|
28
|
+
[
|
|
29
|
+
(f'<section class="body main-article-body">{BODY}</section>', "current PMC"),
|
|
30
|
+
(f'<div class="article-body">{BODY}</div>', "legacy div.article-body"),
|
|
31
|
+
(f'<div class="tsec">{BODY}</div>', "legacy div.tsec"),
|
|
32
|
+
(f'<section class="main-article-body">{BODY}</section>', "class without 'body'"),
|
|
33
|
+
],
|
|
34
|
+
)
|
|
35
|
+
def test_article_containers_are_found(markup, label):
|
|
36
|
+
soup = BeautifulSoup(markup, "html.parser")
|
|
37
|
+
assert _find_pmc_article_body(soup) is not None, f"{label} should be recognised"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.mark.parametrize(
|
|
41
|
+
"markup,label",
|
|
42
|
+
[
|
|
43
|
+
("<html><body><p>Checking your browser before accessing.</p></body></html>",
|
|
44
|
+
"bot-check interstitial"),
|
|
45
|
+
("<html><body><nav><a href='/'>Home</a></nav></body></html>", "navigation page"),
|
|
46
|
+
("<html><body><div class='usa-banner'>An official website</div></body></html>",
|
|
47
|
+
"banner chrome only"),
|
|
48
|
+
],
|
|
49
|
+
)
|
|
50
|
+
def test_pages_without_an_article_container_are_declined(markup, label):
|
|
51
|
+
soup = BeautifulSoup(markup, "html.parser")
|
|
52
|
+
assert _find_pmc_article_body(soup) is None, f"{label} must not be accepted"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_a_bare_body_element_is_not_an_article_container():
|
|
56
|
+
"""``<body>`` is on every page, so matching class="body" alone would accept
|
|
57
|
+
an interstitial. Only the article-body classes count."""
|
|
58
|
+
soup = BeautifulSoup(f"<html><body>{BODY}</body></html>", "html.parser")
|
|
59
|
+
assert _find_pmc_article_body(soup) is None
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""A consumer with a reviewed, committed cache can opt into serving stale HTML.
|
|
2
|
+
|
|
3
|
+
Refusing stale ``full_text_html`` is right by default: a pre-fix entry may be a
|
|
4
|
+
publisher landing page, and #12009 found exactly that stored as full text. But
|
|
5
|
+
the refusal assumes the entry can be repaired by re-fetching, and for a
|
|
6
|
+
PMC-only article it cannot -- PMC answers a Python HTTP client with a bot-check
|
|
7
|
+
interstitial on an HTTP 200 regardless of headers, so the advertised repair route
|
|
8
|
+
is unreachable.
|
|
9
|
+
|
|
10
|
+
For a consumer whose cache is committed and reviewed, that turns a guard into
|
|
11
|
+
data loss: every snippet quoting the body of any pre-stamp HTML entry fails, on
|
|
12
|
+
files the pull request never touched (monarch-initiative/dismech#12672 --
|
|
13
|
+
1,654 such files, ~294 of them with a snippet that is not in the abstract).
|
|
14
|
+
|
|
15
|
+
``serve_stale_html_full_text`` lets that consumer say so explicitly. It changes
|
|
16
|
+
only what may be *served*; nothing about overwriting, and nothing by default.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from unittest.mock import patch
|
|
22
|
+
|
|
23
|
+
from linkml_reference_validator.etl.reference_fetcher import ReferenceFetcher
|
|
24
|
+
from linkml_reference_validator.models import (
|
|
25
|
+
ReferenceValidationConfig,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
BODY_SENTENCE = "A sentence that exists only in the article body."
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _cache(tmp_path):
|
|
32
|
+
(tmp_path / "PMID_30929739.md").write_text(
|
|
33
|
+
"---\nreference_id: PMID:30929739\ntitle: A paper\n"
|
|
34
|
+
f"content_type: full_text_html\n---\n\n## Content\n\n{BODY_SENTENCE}\n",
|
|
35
|
+
encoding="utf-8",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _fetch(tmp_path, **cfg):
|
|
40
|
+
_cache(tmp_path)
|
|
41
|
+
fetcher = ReferenceFetcher(
|
|
42
|
+
ReferenceValidationConfig(
|
|
43
|
+
cache_dir=tmp_path, email="me@example.org", fetch_full_text=False, **cfg
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
class _Source:
|
|
48
|
+
def fetch(self, identifier, config):
|
|
49
|
+
return None # the source yields nothing: the stale-fallback path
|
|
50
|
+
|
|
51
|
+
with patch(
|
|
52
|
+
"linkml_reference_validator.etl.reference_fetcher"
|
|
53
|
+
".ReferenceSourceRegistry.get_source",
|
|
54
|
+
return_value=_Source,
|
|
55
|
+
):
|
|
56
|
+
return fetcher.fetch("PMID:30929739")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_stale_html_is_withheld_by_default(tmp_path):
|
|
60
|
+
"""The default must not change: an unrepaired entry is still not quotable."""
|
|
61
|
+
assert _fetch(tmp_path) is None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_stale_html_is_served_when_the_consumer_opts_in(tmp_path):
|
|
65
|
+
content = _fetch(tmp_path, serve_stale_html_full_text=True)
|
|
66
|
+
assert content is not None, "opting in must make the cached body servable"
|
|
67
|
+
assert BODY_SENTENCE in (content.content or "")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_opting_in_does_not_stamp_or_rewrite_the_entry(tmp_path):
|
|
71
|
+
"""Serving is not migrating. The entry stays stale so a later run retries."""
|
|
72
|
+
_fetch(tmp_path, serve_stale_html_full_text=True)
|
|
73
|
+
text = (tmp_path / "PMID_30929739.md").read_text(encoding="utf-8")
|
|
74
|
+
assert "extractor_version" not in text
|
|
75
|
+
assert BODY_SENTENCE in text
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.claude/.mcp.json
RENAMED
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.claude/settings.json
RENAMED
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.copier-answers.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.github/dependabot.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/.pre-commit-config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/CODE_OF_CONDUCT.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/copilot-instructions.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/elements/.gitkeep
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/quickstart.md
RENAMED
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/reference/cli.md
RENAMED
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/setup-guide.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/docs/troubleshooting.md
RENAMED
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/examples/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/notebooks/README.md
RENAMED
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/project/README.md
RENAMED
|
File without changes
|
{linkml_reference_validator-0.3.0rc1 → linkml_reference_validator-0.3.0rc2}/project.justfile
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|