linkml-reference-validator 0.3.0rc2__tar.gz → 0.3.1rc1__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.0rc2 → linkml_reference_validator-0.3.1rc1}/PKG-INFO +2 -2
- linkml_reference_validator-0.3.1rc1/benchmarks/repeated_quotes.py +49 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/concepts/content-types.md +1 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/use-local-files-and-urls.md +49 -2
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/validate-urls.md +57 -16
- linkml_reference_validator-0.3.1rc1/docs/reference/cache-format.md +150 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/troubleshooting.md +45 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/mkdocs.yml +1 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/pyproject.toml +1 -1
- linkml_reference_validator-0.3.1rc1/src/linkml_reference_validator/__init__.py +23 -0
- linkml_reference_validator-0.3.1rc1/src/linkml_reference_validator/cache.py +251 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/acquire.py +71 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/extract/__init__.py +5 -2
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/extract/html.py +225 -7
- linkml_reference_validator-0.3.1rc1/src/linkml_reference_validator/etl/extract/pdf.py +136 -0
- linkml_reference_validator-0.3.1rc1/src/linkml_reference_validator/etl/extract/svg.py +897 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/extract/xml.py +3 -14
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/pmc.py +5 -9
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/reference_fetcher.py +275 -142
- linkml_reference_validator-0.3.1rc1/src/linkml_reference_validator/etl/rules.py +195 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/file.py +35 -3
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/pmid.py +2 -6
- linkml_reference_validator-0.3.1rc1/src/linkml_reference_validator/etl/sources/url.py +273 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/matching.py +6 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/models.py +12 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/validation/fuzzy_text_utils.py +103 -2
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/validation/repairer.py +12 -5
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/validation/supporting_text_validator.py +59 -9
- linkml_reference_validator-0.3.1rc1/tests/test_cache_validation.py +512 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_extractor_fidelity.py +11 -20
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_jats_tables.py +3 -1
- linkml_reference_validator-0.3.1rc1/tests/test_normalized_content_cache.py +71 -0
- linkml_reference_validator-0.3.1rc1/tests/test_pdf_url_title.py +228 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_reference_fetcher.py +9 -1
- linkml_reference_validator-0.3.1rc1/tests/test_rules.py +129 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_serve_stale_html_optin.py +59 -0
- linkml_reference_validator-0.3.1rc1/tests/test_svg_extractor.py +1047 -0
- linkml_reference_validator-0.3.1rc1/tests/test_trust_cached_entries.py +81 -0
- linkml_reference_validator-0.3.1rc1/tests/test_url_html_sanitize.py +160 -0
- linkml_reference_validator-0.3.1rc1/tests/test_url_html_to_text.py +226 -0
- linkml_reference_validator-0.3.1rc1/tests/test_url_source_cache_version.py +147 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/uv.lock +1 -1
- linkml_reference_validator-0.3.0rc2/src/linkml_reference_validator/__init__.py +0 -5
- linkml_reference_validator-0.3.0rc2/src/linkml_reference_validator/etl/extract/pdf.py +0 -74
- linkml_reference_validator-0.3.0rc2/src/linkml_reference_validator/etl/sources/url.py +0 -148
- linkml_reference_validator-0.3.0rc2/tests/test_pmc_modern_container.py +0 -59
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.claude/.mcp.json +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.claude/settings.json +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.copier-answers.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.devcontainer/devcontainer.json +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.devcontainer/post_create.sh +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.editorconfig +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/actions/claude-code-action/action.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/actions/claude-issue-summarize-action/action.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/actions/claude-issue-triage-action/action.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/ai-controllers.json +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/copilot-instructions.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/copilot-setup-steps.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/dependabot.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/claude-code-review.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/claude-issue-summarize.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/claude-issue-triage.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/claude-ontology-review.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/claude.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/deploy-docs.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/dragon-ai.yml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/main.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.github/workflows/pypi-publish.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.gitignore +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.goosehints +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.pre-commit-config.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/.yamllint.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/AGENTS.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/BUG_GEO_ACCESSION_TO_UID.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/BUG_ZENODO_DOI_AND_URL_HANDLING.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/CLAUDE.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/CLI-ISSUES.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/CODE_OF_CONDUCT.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/CONTRIBUTING.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/FEATURE_REQUEST_REPAIR.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/LICENSE +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/README.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/REVIEW2.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/REVIEW3.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/ai.just +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/copilot-instructions.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/about.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/assets/zotero-find-full-text.png +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/concepts/editorial-conventions.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/concepts/how-it-works.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/elements/.gitkeep +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/add-reference-source.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/export-cache-to-zotero.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/fetch-full-text-and-pdfs.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/repair-validation-errors.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/skip-unsupported-references.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/validate-clinical-trials.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/validate-dois.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/validate-entrez.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/validate-obo-files.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/how-to/validate-titles.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/index.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/notebooks/01_getting_started.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/notebooks/02_advanced_usage.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/notebooks/03_python_api.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/notebooks/04_obo_validation.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/notebooks/05_geo_validation.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/quickstart.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/reference/cli.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/reference/splitting.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/setup-guide.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/superpowers/plans/2026-06-12-modular-pdf-fulltext-fetching.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/superpowers/plans/2026-08-05-private-library-full-text.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/superpowers/specs/2026-06-12-modular-pdf-fulltext-fetching-design.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/superpowers/specs/2026-08-05-private-library-full-text-design.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/templates-linkml/README.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/todo.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/tutorials/complete-workflow.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/examples/README.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/justfile +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/mypy.ini +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/notebooks/01_getting_started.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/notebooks/02_advanced_usage.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/notebooks/03_python_api.ipynb +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/notebooks/README.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/project/README.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/project.justfile +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/pytest.ini +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/_version.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/cli/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/cli/cache.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/cli/lookup.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/cli/repair.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/cli/shared.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/cli/validate.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/csl_export.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/extract/base.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/base.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/epmc_preprint.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/json_api.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/loader.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/openalex.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/unpaywall.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/fulltext/zotero.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/identifiers.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/base.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/clinicaltrials.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/doi.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/entrez.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/json_api.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/loader.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/ppr.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/sources/utils.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/etl/text_extractor.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/field_detection.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/plugins/REVIEW.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/plugins/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/plugins/reference_validation_plugin.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/src/linkml_reference_validator/validation/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/__init__.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/conftest.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/data/test_data_deep_nesting_invalid.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/data/test_data_deep_nesting_valid.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/data/test_data_invalid.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/data/test_data_valid.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/data/test_schema.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/data/test_schema_deep_nesting.yaml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/GEO_GSE12345.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMC_TEST001.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMC_TEST001.txt +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMC_TEST002.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMC_TEST002.txt +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMID_TEST001.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMID_TEST001.txt +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMID_TEST002.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMID_TEST002.txt +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMID_TEST003.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/PMID_TEST003.txt +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/clinicaltrials_NCT00000001.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/fulltext_html/README.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/fulltext_html/dspace-32894695.html +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/fulltext_html/iris-19049553.html +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/fulltext_html/plos-0000308.html +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/jats/PMC5593426.xml +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/jats/README.md +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/fixtures/sample.obo +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_absent_abstract_recovery.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_acquire.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_cache_author_recovery.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_cli.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_cli_cache_enrich.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_cli_cache_export.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_cli_cache_reference.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_cli_lookup.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_cli_repair.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_clinicaltrials_cache.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_clinicaltrials_integration.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_deep_nesting.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_doi_preprint.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_e2e_integration.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_empty_snippets.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_epmc_preprint_provider.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_extractors.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_field_detection.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_frontmatter_and_doi_case.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_fulltext_loader.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_fulltext_providers.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_fuzzy_suggestions.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_geo_integration.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_html_fulltext_acceptance.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_identifiers.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_json_api_source.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_ligature_normalization.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_models.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_no_cache_downgrade.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_open_access_policy.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_optional_linkml_dependency.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_plugin_integration.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_pmc_fulltext.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_pmid_network.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_ppr_source.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_real_validation.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_repair.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_source_utils.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_sources.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_split_supporting_text.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_supporting_text_validator.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_text_extractor.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_title_validation.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_unknown_slot_traversal.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_validation_config.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_validation_counts.py +0 -0
- {linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/tests/test_zotero_provider.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: linkml_reference_validator
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1rc1
|
|
4
4
|
Summary: Validation of supporting text from references and publications
|
|
5
5
|
Author-email: Chris Mungall <cjmungall@lbl.gov>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -10,7 +10,7 @@ Requires-Dist: beautifulsoup4>=4.9.0
|
|
|
10
10
|
Requires-Dist: biopython>=1.80
|
|
11
11
|
Requires-Dist: jsonpath-ng>=1.6.0
|
|
12
12
|
Requires-Dist: linkml-runtime>=1.9.4
|
|
13
|
-
Requires-Dist: lxml>=
|
|
13
|
+
Requires-Dist: lxml>=5.0.0
|
|
14
14
|
Requires-Dist: pydantic>=2.0.0
|
|
15
15
|
Requires-Dist: pypdf>=4.0.0
|
|
16
16
|
Requires-Dist: rapidfuzz>=3.14.3
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Time repeated matching against a local UTF-8 document, without network access.
|
|
2
|
+
|
|
3
|
+
Run the same script and input with each checkout's package on PYTHONPATH:
|
|
4
|
+
uv run python benchmarks/repeated_quotes.py /path/to/cached/publication.md
|
|
5
|
+
|
|
6
|
+
Only successful matching is timed; this is a CPU microbenchmark, not end-to-end
|
|
7
|
+
CLI validation. It includes each validator's first normalization of the body.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import json
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from statistics import median
|
|
15
|
+
from time import perf_counter
|
|
16
|
+
|
|
17
|
+
from linkml_reference_validator.models import ReferenceContent, ReferenceValidationConfig
|
|
18
|
+
from linkml_reference_validator.validation.supporting_text_validator import SupportingTextValidator
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main() -> None:
|
|
22
|
+
"""Report median time to match evenly spaced literal excerpts from a document."""
|
|
23
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
24
|
+
parser.add_argument("document", type=Path)
|
|
25
|
+
parser.add_argument("--quotes", type=int, default=100)
|
|
26
|
+
parser.add_argument("--rounds", type=int, default=3)
|
|
27
|
+
args = parser.parse_args()
|
|
28
|
+
content = args.document.read_text(encoding="utf-8")
|
|
29
|
+
# Each query is taken verbatim from the source; avoid editorial-bracket and
|
|
30
|
+
# ellipsis syntax, which would change what the matching API searches for.
|
|
31
|
+
candidates = [m.group() for m in re.finditer(r"[\w ,;:-]{30,100}", content)]
|
|
32
|
+
if args.quotes < 1 or args.rounds < 1 or not candidates:
|
|
33
|
+
parser.error("positive --quotes/--rounds and a document with prose are required")
|
|
34
|
+
quotes = [candidates[i * len(candidates) // args.quotes] for i in range(args.quotes)]
|
|
35
|
+
reference = ReferenceContent(reference_id="TEST:benchmark", content=content)
|
|
36
|
+
elapsed = []
|
|
37
|
+
for _ in range(args.rounds):
|
|
38
|
+
validator = SupportingTextValidator(ReferenceValidationConfig())
|
|
39
|
+
start = perf_counter()
|
|
40
|
+
for quote in quotes:
|
|
41
|
+
if not validator.find_text_in_reference(quote, reference).found:
|
|
42
|
+
raise SystemExit(f"Excerpt unexpectedly failed validation: {quote!r}")
|
|
43
|
+
elapsed.append(perf_counter() - start)
|
|
44
|
+
print(json.dumps({"characters": len(content), "quotes": len(quotes),
|
|
45
|
+
"rounds_seconds": elapsed, "median_seconds": median(elapsed)}))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
main()
|
|
@@ -11,6 +11,7 @@ When fetching references, the validator tracks what type of content was retrieve
|
|
|
11
11
|
| `abstract_only` | PMID, DOI | Only the abstract was available |
|
|
12
12
|
| `summary` | GEO, BioProject, BioSample, ClinicalTrials | Database summary/description field |
|
|
13
13
|
| `local_file` | file: | Content read from local filesystem |
|
|
14
|
+
| `local_svg` | file: (`.svg`) | Text an SVG figure renders, a blank line between labels; a quote must fall within one label |
|
|
14
15
|
| `url` | url: | Content fetched from web URL |
|
|
15
16
|
| `unavailable` | Any | No content could be retrieved |
|
|
16
17
|
|
|
@@ -89,7 +89,7 @@ URLs are cached the same way as PMID and DOI references:
|
|
|
89
89
|
|
|
90
90
|
### Title Extraction
|
|
91
91
|
|
|
92
|
-
For HTML pages, the title is
|
|
92
|
+
For HTML pages, the title is the `citation_title` meta tag when present, then the `<title>` tag. For PDFs, the validator tries a publisher landing page's `citation_title` and then the PDF's embedded title. When neither is found, and for other content types, the URL itself is used as the title. See [Validating URLs](validate-urls.md#titles).
|
|
93
93
|
|
|
94
94
|
### Example: Validating Against a Web Page
|
|
95
95
|
|
|
@@ -105,6 +105,51 @@ linkml-reference-validator validate text \
|
|
|
105
105
|
url:https://example.com/pangram-examples.html
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
## Diagrams as References (SVG)
|
|
109
|
+
|
|
110
|
+
A `file:` reference can point at an `.svg` figure, such as a pathway diagram.
|
|
111
|
+
The quote is then matched against the text the figure **renders**, not its
|
|
112
|
+
markup:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
linkml-reference-validator validate text \
|
|
116
|
+
"loss of PTEN activates AKT" \
|
|
117
|
+
file:./figures/pathway.svg
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- Each `<text>` element is one label. A label split over several `<tspan>`
|
|
121
|
+
lines can be quoted across the break.
|
|
122
|
+
- A quote must fall within one label. A figure with a `PTEN` label and a
|
|
123
|
+
separate `activates AKT` label does not support `"PTEN activates AKT"`,
|
|
124
|
+
however close together they sit: neither label says it. To cite both, quote
|
|
125
|
+
them as separate parts, `"PTEN ... activates AKT"`.
|
|
126
|
+
- HTML labels inside `<foreignObject>`, which is how drawio's **Export as SVG**
|
|
127
|
+
writes them, are read too.
|
|
128
|
+
- Text the reader cannot see is never quotable. That covers `<desc>`, `<title>`,
|
|
129
|
+
`<metadata>`, comments, attribute values (`id`, `fill`, `class`, ...),
|
|
130
|
+
`<defs>`/`<symbol>` content that no `<use>` draws, and text hidden by
|
|
131
|
+
`display:none`, `visibility:hidden`, zero `opacity`, `fill="none"` or a zero
|
|
132
|
+
`font-size`, whether set on the element, inherited from a group, or set by a
|
|
133
|
+
`<style>` rule.
|
|
134
|
+
- If the extractor cannot tell what the figure renders, the reference is
|
|
135
|
+
`unavailable` rather than read as raw markup. That happens when a `<style>`
|
|
136
|
+
rule hides or shows text through a selector other than a type, class or id
|
|
137
|
+
selector (`g > text`, `:first-child`, `@media`), when visibility depends on
|
|
138
|
+
`var()` or `calc()`, when a stylesheet is imported or linked, when the SVG
|
|
139
|
+
contains a `<script>` or animates visibility, or when something changes the
|
|
140
|
+
characters drawn: CSS `content`, a string `list-style-type` or `quotes`,
|
|
141
|
+
`-webkit-text-security`, a `unicode-bidi` override, `<bdo>`, or a bidi
|
|
142
|
+
control character in the text.
|
|
143
|
+
|
|
144
|
+
Known limits: a label drawn as several `<text>` elements, one per line, is
|
|
145
|
+
read as several labels, so quote its lines with `...` between them. Text
|
|
146
|
+
clipped by `clip-path` or `mask`, placed outside the
|
|
147
|
+
`viewBox`, scaled to nothing, covered by another shape, drawn in the
|
|
148
|
+
background colour, or cut short by CSS `text-overflow` or `-webkit-line-clamp`
|
|
149
|
+
is still read. Text converted to outlines is not text and
|
|
150
|
+
cannot be quoted. Native `.drawio` files and connector (edge) labels between
|
|
151
|
+
nodes are not yet supported.
|
|
152
|
+
|
|
108
153
|
## Using in Data Files
|
|
109
154
|
|
|
110
155
|
Both file and URL references work in LinkML data files:
|
|
@@ -145,6 +190,8 @@ Both file and URL references work in LinkML data files:
|
|
|
145
190
|
|
|
146
191
|
## Limitations
|
|
147
192
|
|
|
148
|
-
- **
|
|
193
|
+
- **Local files are read as text**, apart from `.svg` figures (see above).
|
|
194
|
+
An `.html` file is matched against its raw markup.
|
|
195
|
+
- **Local PDF files**: Not yet supported as `file:` references. PDFs fetched by `url:` are supported.
|
|
149
196
|
- **Authentication**: URLs requiring login are not supported
|
|
150
197
|
- **Dynamic content**: JavaScript-rendered pages may not work
|
|
@@ -15,8 +15,8 @@ The linkml-reference-validator supports validating references that point to web
|
|
|
15
15
|
When a reference field contains a URL, the validator:
|
|
16
16
|
|
|
17
17
|
1. Fetches the web page content
|
|
18
|
-
2. Extracts the page title
|
|
19
|
-
3.
|
|
18
|
+
2. Extracts the page title (see [Titles](#titles))
|
|
19
|
+
3. Converts HTML to readable text and caches it for future validations
|
|
20
20
|
4. Validates your supporting text against the page content
|
|
21
21
|
|
|
22
22
|
## URL Format
|
|
@@ -79,14 +79,54 @@ When the validator encounters a URL reference, it:
|
|
|
79
79
|
|
|
80
80
|
The fetcher stores:
|
|
81
81
|
|
|
82
|
-
- **Title**:
|
|
83
|
-
- **Content**:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
HTML
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
- **Title**: See [Titles](#titles)
|
|
83
|
+
- **Content**: Readable text for HTML pages; plain text and XML as received;
|
|
84
|
+
extracted text for PDFs
|
|
85
|
+
- **Content type**: `url` for pages, `full_text_pdf` for PDFs with text
|
|
86
|
+
|
|
87
|
+
HTML is converted to readable text before it is cached. A quote copied from
|
|
88
|
+
the page then matches even when it runs through a link, bold or italic text,
|
|
89
|
+
and a cached page can be read, and diffed, line by line:
|
|
90
|
+
|
|
91
|
+
- Inline tags (`<a>`, `<b>`, `<em>`, `<span>`, ...) are removed and their
|
|
92
|
+
text is kept in place.
|
|
93
|
+
- Block-level tags (`<p>`, `<li>`, `<h1>`-`<h6>`, `<div>`, `<br>`, ...) start
|
|
94
|
+
a new line.
|
|
95
|
+
- A table row is one line, its cells separated by ` | `. Normalization drops
|
|
96
|
+
the `|`, so a quote copied from a rendered row with its cells separated by
|
|
97
|
+
spaces still matches.
|
|
98
|
+
- `<pre>` keeps its whitespace. Elsewhere whitespace collapses to one space.
|
|
99
|
+
- Entities such as `&` are unescaped.
|
|
100
|
+
|
|
101
|
+
The whole page is kept, including navigation, sidebars and footers; it is not
|
|
102
|
+
narrowed to the article body. Because caches are often committed to public
|
|
103
|
+
repositories and page scripts routinely carry signed asset URLs and API keys,
|
|
104
|
+
`<script>`, `<style>`, `<noscript>` and `<template>` elements and HTML comments
|
|
105
|
+
are removed with their text, and no tag attribute reaches the cache.
|
|
106
|
+
|
|
107
|
+
#### Titles
|
|
108
|
+
|
|
109
|
+
For HTML pages the title is the `citation_title` meta tag when present (the
|
|
110
|
+
Highwire / Google Scholar convention, which names the article rather than the
|
|
111
|
+
site), then the `<title>` tag.
|
|
112
|
+
|
|
113
|
+
For PDFs the validator tries, in order:
|
|
114
|
+
|
|
115
|
+
1. The `citation_title` of the publisher's landing page, where a known rule
|
|
116
|
+
maps the PDF URL to it. Currently J-STAGE: `.../_pdf` becomes
|
|
117
|
+
`.../_article`.
|
|
118
|
+
2. The PDF's embedded `/Title` metadata, ignoring placeholders such as
|
|
119
|
+
`Microsoft Word - draft.doc`, bare filenames and `Untitled`.
|
|
120
|
+
3. The URL itself.
|
|
121
|
+
|
|
122
|
+
So a PDF entry whose `title` equals its URL is one for which no title was
|
|
123
|
+
found.
|
|
124
|
+
|
|
125
|
+
The landing-page rules and the placeholder titles are kept in
|
|
126
|
+
`src/linkml_reference_validator/etl/rules.py`, with the other publisher and
|
|
127
|
+
site rules. Each rule sits beside examples of what it must and must not match.
|
|
128
|
+
To support another publisher, add a rule there with at least one example;
|
|
129
|
+
`tests/test_rules.py` fails for a rule without one.
|
|
90
130
|
|
|
91
131
|
### 3. Caching
|
|
92
132
|
|
|
@@ -104,9 +144,9 @@ content_type: url
|
|
|
104
144
|
## Content
|
|
105
145
|
|
|
106
146
|
<html>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
147
|
+
<head>
|
|
148
|
+
<title>Chapter 3: Cell Structure and Function</title>
|
|
149
|
+
</head>
|
|
110
150
|
...
|
|
111
151
|
```
|
|
112
152
|
|
|
@@ -145,10 +185,11 @@ URL validation is designed for static web pages. It may not work well with:
|
|
|
145
185
|
|
|
146
186
|
### Raw Content
|
|
147
187
|
|
|
148
|
-
The validator stores
|
|
188
|
+
The validator stores the page's text, not its markup. For HTML pages:
|
|
149
189
|
|
|
150
|
-
-
|
|
151
|
-
|
|
190
|
+
- Text that only appears in an attribute, such as an image's `alt` text, is
|
|
191
|
+
not kept
|
|
192
|
+
- Text inside `<noscript>` or `<template>` is not kept
|
|
152
193
|
- Complex HTML layouts may require careful text extraction
|
|
153
194
|
|
|
154
195
|
### No Rendering
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Reference cache format and validation
|
|
2
|
+
|
|
3
|
+
The library owns the contract for Markdown cache files. Use its public model and
|
|
4
|
+
checkers instead of maintaining a downstream copy of the frontmatter fields:
|
|
5
|
+
|
|
6
|
+
```python
|
|
7
|
+
from linkml_reference_validator import (
|
|
8
|
+
CacheFrontmatter,
|
|
9
|
+
scan_cache_dir,
|
|
10
|
+
validate_cache_file,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
result = validate_cache_file("references_cache/PMID_12345.md")
|
|
14
|
+
for finding in result.findings:
|
|
15
|
+
print(result.path, finding.code, finding.field, finding.message)
|
|
16
|
+
|
|
17
|
+
results = scan_cache_dir("references_cache")
|
|
18
|
+
invalid = [result for result in results if not result.is_valid]
|
|
19
|
+
if invalid:
|
|
20
|
+
raise SystemExit(f"{len(invalid)} invalid cache files")
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
These functions read files without fetching references, refreshing extraction
|
|
24
|
+
stamps, or rewriting the cache. They return `CacheValidationResult` objects with
|
|
25
|
+
`path`, `frontmatter`, `findings`, and an `is_valid` property. `frontmatter` is a
|
|
26
|
+
`CacheFrontmatter` instance when the header passes validation, including when the
|
|
27
|
+
filename fails its separate check; otherwise it is `None`.
|
|
28
|
+
|
|
29
|
+
`scan_cache_dir(directory, recursive=False)` returns a list in path order. It
|
|
30
|
+
checks immediate `*.md` files by default; pass `recursive=True` to include nested
|
|
31
|
+
directories. It skips symlinked directories during recursion but reads symlinked
|
|
32
|
+
Markdown files. Non-Markdown files, including legacy `.txt` caches and downloaded
|
|
33
|
+
XML/PDF files, are outside this contract and are ignored. An existing empty directory returns `[]`. Missing,
|
|
34
|
+
unreadable, or non-directory scan roots raise `OSError` (including its subclasses)
|
|
35
|
+
so a mistaken path cannot silently pass a gate. Individual file errors are
|
|
36
|
+
reported as findings and do not stop the scan.
|
|
37
|
+
|
|
38
|
+
## Frontmatter contract
|
|
39
|
+
|
|
40
|
+
Files contain UTF-8 text without a byte-order mark (BOM), with a YAML mapping
|
|
41
|
+
between opening and closing `---` lines, beginning on the first line. The remaining
|
|
42
|
+
text is an unrestricted Markdown body. Duplicate YAML keys are invalid.
|
|
43
|
+
|
|
44
|
+
Only `reference_id` and `content_type` are required; both must be nonblank strings.
|
|
45
|
+
All other known fields are optional and may be null:
|
|
46
|
+
|
|
47
|
+
- Bibliography: `title`, `authors`, `journal`, `year`, `doi`, `keywords`, and
|
|
48
|
+
`publication_types`.
|
|
49
|
+
- Extraction stamps: `extractor_version`, `html_full_text_version`,
|
|
50
|
+
`xml_extraction_version`, `url_source_version`, `svg_extraction_version`, and
|
|
51
|
+
`absent_content_version`.
|
|
52
|
+
- Publication status: `is_preprint` and `peer_review_status`.
|
|
53
|
+
- Full-text metadata: `full_text_attempted`, `full_text_declined`,
|
|
54
|
+
`full_text_provider`, `full_text_url`, `oa_status`, `license`, `local_pdf_path`,
|
|
55
|
+
`full_text_access_type`, and `full_text_source_item_id`.
|
|
56
|
+
- Captured fields and attachments: `extra_fields_captured` and
|
|
57
|
+
`supplementary_files`.
|
|
58
|
+
|
|
59
|
+
Known fields are checked without coercion. Extraction stamps and supplementary
|
|
60
|
+
file sizes are integers (booleans do not count); `is_preprint` and
|
|
61
|
+
`full_text_attempted` are booleans. Authors, keywords, publication types, and
|
|
62
|
+
captured field names are lists of strings. `year` accepts a string or an integer
|
|
63
|
+
for compatibility with older unquoted YAML years. Other scalar metadata is text.
|
|
64
|
+
Each supplementary file requires a nonempty string `filename`; its optional fields
|
|
65
|
+
are `download_url`, `content_type`, `size_bytes`, `checksum`, `description`, and
|
|
66
|
+
`local_path`. Older cache files may contain unquoted numeric values in fields
|
|
67
|
+
such as `checksum` that require strings. These are reported as `invalid_field`;
|
|
68
|
+
quote the intended text to repair them. The lenient fetcher also recovers numeric
|
|
69
|
+
and boolean scalars in string-valued metadata fields (including attachment
|
|
70
|
+
metadata) by converting their parsed values to strings. The field types come
|
|
71
|
+
from the public model; reference IDs, version stamps, booleans, lists, and
|
|
72
|
+
unknown extension fields are not coerced.
|
|
73
|
+
A cache rewrite then quotes these strings and retains consumer extensions.
|
|
74
|
+
This compatibility recovery applies only to disk reads, not source plugin output
|
|
75
|
+
or the public validator. It cannot reconstruct leading zeros or original
|
|
76
|
+
scientific notation already lost during YAML parsing; check the source when the
|
|
77
|
+
exact spelling matters.
|
|
78
|
+
|
|
79
|
+
**Unknown keys are allowed and preserved**, both in the header and in
|
|
80
|
+
supplementary-file metadata. No extension namespace is required: a consumer's
|
|
81
|
+
`database: Orphanet` is valid. String vocabularies such as `content_type`,
|
|
82
|
+
`peer_review_status`, and `full_text_access_type` are open, so future values do not
|
|
83
|
+
break older consumers. Extraction stamps may be absent, old, or newer than this
|
|
84
|
+
library; format validity does not imply freshness.
|
|
85
|
+
|
|
86
|
+
When rewriting an existing cache with a valid header for the same reference,
|
|
87
|
+
the fetcher carries over unknown fields, including explicit null values. Unknown
|
|
88
|
+
fields are retained as-is, not recalculated or certified current on refresh;
|
|
89
|
+
this also applies to fields written by a newer version of the library. Known
|
|
90
|
+
fields always come from the new reference. Attachment extensions follow filenames
|
|
91
|
+
that are unique in both the old and new attachment lists; removed or ambiguous
|
|
92
|
+
attachments do not transfer their extensions. Preservation reads only the file
|
|
93
|
+
being overwritten, so metadata is not copied between public and private caches
|
|
94
|
+
or between different references whose sanitized filenames collide. A damaged
|
|
95
|
+
header that remains invalid after legacy scalar recovery cannot supply validated
|
|
96
|
+
extensions: the fetcher logs a warning and permits
|
|
97
|
+
a fresh fetch to repair the file.
|
|
98
|
+
|
|
99
|
+
The writer omits empty optional attachment strings, retaining the historical
|
|
100
|
+
serialization policy. Invalid known metadata supplied by a source or carried
|
|
101
|
+
through a lenient read raises `pydantic.ValidationError` before a cache write;
|
|
102
|
+
`fetch()` propagates that error. An existing cache file is left intact. This
|
|
103
|
+
makes a source's type-contract error visible instead of silently coercing values
|
|
104
|
+
or reporting a successful cache write that never happened.
|
|
105
|
+
|
|
106
|
+
`CacheFrontmatter` is a public Pydantic model released with the library. The writer
|
|
107
|
+
serializes this same model. To inspect the complete, machine-readable contract:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
schema = CacheFrontmatter.model_json_schema()
|
|
111
|
+
header = CacheFrontmatter.model_validate({
|
|
112
|
+
"reference_id": "PMID:12345",
|
|
113
|
+
"content_type": "abstract_only",
|
|
114
|
+
"database": "Orphanet",
|
|
115
|
+
})
|
|
116
|
+
assert header.model_dump()["database"] == "Orphanet"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The checker derives the filename from the stored `reference_id` by replacing
|
|
120
|
+
`:`, `/`, `?`, and `=` with `_` and appending `.md`. DOI filenames are compared
|
|
121
|
+
case-insensitively, matching the fetcher's existing behavior. Other filenames must
|
|
122
|
+
match exactly. This uses the ID already stored in the file, without applying
|
|
123
|
+
configured prefix aliases or requiring a currently registered reference source.
|
|
124
|
+
|
|
125
|
+
## Findings and local policy
|
|
126
|
+
|
|
127
|
+
Each `CacheFinding` has a stable `code`, a human-readable `message`, and a `field`
|
|
128
|
+
when applicable. Field locations use dotted paths, for example `authors.0` or
|
|
129
|
+
`supplementary_files.0.size_bytes`.
|
|
130
|
+
|
|
131
|
+
| Code | Meaning |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| `read_error` | The file cannot be read or is not valid UTF-8. |
|
|
134
|
+
| `invalid_frontmatter` | Delimiters are missing/misplaced or the YAML is not a mapping. |
|
|
135
|
+
| `invalid_yaml` | YAML parsing failed, including duplicate keys. |
|
|
136
|
+
| `invalid_field` | A required field is absent or a known field has an invalid type/value. |
|
|
137
|
+
| `filename_mismatch` | The filename does not match the stored reference ID. |
|
|
138
|
+
|
|
139
|
+
Apply local requirements after `result.is_valid`, using `result.frontmatter`.
|
|
140
|
+
Requiring authors or a journal for particular reference sources, for example,
|
|
141
|
+
is a consumer policy rather than a format rule. The ordinary fetcher's reader
|
|
142
|
+
remains lenient for recovering old cache data; the checker reports malformed
|
|
143
|
+
known fields instead of silently recovering them. In particular, the reader
|
|
144
|
+
accepts text before the opening frontmatter delimiter; the checker requires the
|
|
145
|
+
opening delimiter on the first line.
|
|
146
|
+
|
|
147
|
+
Validation cannot prove that a file was never hand-edited, that its text agrees
|
|
148
|
+
with the publication, or that its bibliography is complete. A well-formed edit
|
|
149
|
+
still passes; use version-control review or an external integrity record to
|
|
150
|
+
track changes when needed.
|
{linkml_reference_validator-0.3.0rc2 → linkml_reference_validator-0.3.1rc1}/docs/troubleshooting.md
RENAMED
|
@@ -902,6 +902,51 @@ rather than as `unavailable`, so it falls outside this stamp and is not
|
|
|
902
902
|
re-tested. Clear such entries by hand if you were running that setting before
|
|
903
903
|
this version.
|
|
904
904
|
|
|
905
|
+
`url:` entries carry their own stamp, `url_source_version`. Version 1 is
|
|
906
|
+
two URLSource changes: HTML is sanitized before caching, so page scripts,
|
|
907
|
+
comments and attributes stop reaching the cache (issue #92), and a PDF's title
|
|
908
|
+
is recovered from a publisher landing page or its embedded metadata rather than
|
|
909
|
+
set to its URL (issue #93). Version 2 caches an HTML page as readable text
|
|
910
|
+
rather than markup, so a quote that runs through a link or bold text matches
|
|
911
|
+
(issue #102). Every quote that matched the version 1 markup still matches the
|
|
912
|
+
text, provided the page itself has not changed. A `url:` entry with a missing or older stamp is
|
|
913
|
+
re-fetched once on the next validation fetch. If the page cannot be reached,
|
|
914
|
+
the old entry is still served and is not rewritten, so a later run retries.
|
|
915
|
+
Other sources are unaffected. With `trust_cached_entries` set, old entries are
|
|
916
|
+
served as they are and are not refreshed.
|
|
917
|
+
|
|
918
|
+
`file:` references to `.svg` figures carry their own stamp,
|
|
919
|
+
`svg_extraction_version`. Version 1 reads a figure as the text it renders
|
|
920
|
+
(issue #104); before it, the file was cached as raw markup, so a quote could
|
|
921
|
+
match a `<desc>`, an attribute value or hidden text. Such an entry is re-read
|
|
922
|
+
once on the next validation fetch. **A quote that only matched the markup will
|
|
923
|
+
then fail**, which is the point: cite text the figure actually shows. Unlike
|
|
924
|
+
other stale entries, an old SVG entry is never served in place of a fresh
|
|
925
|
+
read: not when the file has moved, not when the new read finds no rendered
|
|
926
|
+
text, and not with `trust_cached_entries`. The file is the source, and its raw
|
|
927
|
+
markup is not evidence. Version 2 separates a figure's labels, so a quote is
|
|
928
|
+
matched within one label; version 1 entries are re-read once for it.
|
|
929
|
+
|
|
930
|
+
**A quote that verified against a `url:` page can fail after that refresh.**
|
|
931
|
+
Sanitizing removes `<noscript>` and `<template>` elements with their text.
|
|
932
|
+
Some publisher pages put a fallback copy of the abstract inside `<noscript>`,
|
|
933
|
+
for readers without JavaScript. A quote that only ever matched that copy will
|
|
934
|
+
stop matching once the entry is re-fetched. If the same text appears elsewhere
|
|
935
|
+
on the page, nothing changes. If it does not, cite a source that carries it,
|
|
936
|
+
such as the `PMID:` or `DOI:` of the article.
|
|
937
|
+
|
|
938
|
+
**The version 2 refresh rewrites every cached HTML page.** Each `url:` HTML
|
|
939
|
+
entry changes from one line of markup to many lines of text, so expect a large
|
|
940
|
+
diff in a committed cache. The refresh fetches each page again, so a page that
|
|
941
|
+
has changed or gone since it was cached can stop supporting a quote; an
|
|
942
|
+
unreachable page keeps its old entry, as above. To keep that diff reviewable,
|
|
943
|
+
refresh in a commit of its own: right after upgrading, run your usual
|
|
944
|
+
validation on an otherwise unchanged checkout and commit only the rewritten
|
|
945
|
+
cache files, before any curation changes. Entries are refreshed only as a
|
|
946
|
+
validation uses them (see
|
|
947
|
+
[Cached references re-fetched after upgrading](#cached-references-re-fetched-after-upgrading)),
|
|
948
|
+
so a page no validation cites keeps its old entry until one does.
|
|
949
|
+
|
|
905
950
|
**A cache-wide refresh adds one line to every enriched entry.** Both index
|
|
906
951
|
providers now set `access_type` where they previously left it unset, so a
|
|
907
952
|
refreshed public entry gains a `full_text_access_type: open` line. It means the
|
|
@@ -52,6 +52,7 @@ nav:
|
|
|
52
52
|
- Editorial Conventions: concepts/editorial-conventions.md
|
|
53
53
|
- Reference:
|
|
54
54
|
- CLI Reference: reference/cli.md
|
|
55
|
+
- Cache Format and Validation: reference/cache-format.md
|
|
55
56
|
- Supporting Text Splitting: reference/splitting.md
|
|
56
57
|
- Troubleshooting: troubleshooting.md
|
|
57
58
|
- Roadmap: todo.md
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
try:
|
|
2
|
+
from linkml_reference_validator._version import __version__, __version_tuple__
|
|
3
|
+
except ImportError: # pragma: no cover
|
|
4
|
+
__version__ = "0.0.0"
|
|
5
|
+
__version_tuple__ = (0, 0, 0)
|
|
6
|
+
|
|
7
|
+
from linkml_reference_validator.cache import (
|
|
8
|
+
CacheFinding,
|
|
9
|
+
CacheFrontmatter,
|
|
10
|
+
CacheSupplementaryFile,
|
|
11
|
+
CacheValidationResult,
|
|
12
|
+
scan_cache_dir,
|
|
13
|
+
validate_cache_file,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"CacheFinding",
|
|
18
|
+
"CacheFrontmatter",
|
|
19
|
+
"CacheSupplementaryFile",
|
|
20
|
+
"CacheValidationResult",
|
|
21
|
+
"scan_cache_dir",
|
|
22
|
+
"validate_cache_file",
|
|
23
|
+
]
|