linkml-reference-validator 0.4.0__tar.gz → 0.5.1__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.4.0 → linkml_reference_validator-0.5.1}/PKG-INFO +1 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/concepts/how-it-works.md +64 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/fetch-full-text-and-pdfs.md +9 -5
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/repair-validation-errors.md +37 -3
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/validate-titles.md +17 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/reference/cache-format.md +16 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/reference/cli.md +3 -3
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/troubleshooting.md +65 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/cache.py +63 -5
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/cli/lookup.py +6 -17
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/cli/repair.py +144 -38
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/extract/html.py +37 -40
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/extract/pdf.py +76 -13
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/extract/svg.py +9 -18
- linkml_reference_validator-0.5.1/src/linkml_reference_validator/etl/extract/untrusted_xml.py +57 -0
- linkml_reference_validator-0.5.1/src/linkml_reference_validator/etl/extract/xml.py +536 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/json_api.py +7 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/openalex.py +2 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/unpaywall.py +2 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/identifiers.py +23 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/reference_fetcher.py +334 -91
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/doi.py +56 -20
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/file.py +22 -17
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/json_api.py +3 -8
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/pmid.py +94 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/url.py +10 -4
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/utils.py +43 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/field_detection.py +80 -23
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/models.py +84 -8
- linkml_reference_validator-0.5.1/src/linkml_reference_validator/plugins/reference_validation_plugin.py +1019 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/validation/fuzzy_text_utils.py +4 -2
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/validation/repairer.py +153 -26
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/validation/supporting_text_validator.py +166 -20
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMC_TEST002.md +1 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMID_TEST003.md +1 -1
- linkml_reference_validator-0.5.1/tests/test_cache_filename_collisions.py +168 -0
- linkml_reference_validator-0.5.1/tests/test_cache_read_robustness.py +235 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_cache_validation.py +12 -4
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_cli_cache_reference.py +17 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_doi_preprint.py +4 -4
- linkml_reference_validator-0.5.1/tests/test_doi_url_encoding.py +82 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_e2e_integration.py +1 -1
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_empty_snippets.py +2 -2
- linkml_reference_validator-0.5.1/tests/test_field_detection_qualifiers.py +207 -0
- linkml_reference_validator-0.5.1/tests/test_file_reference_cache.py +131 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_frontmatter_and_doi_case.py +3 -3
- linkml_reference_validator-0.5.1/tests/test_greek_variants.py +54 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_html_fulltext_acceptance.py +5 -2
- linkml_reference_validator-0.5.1/tests/test_html_scope_text.py +206 -0
- linkml_reference_validator-0.5.1/tests/test_inline_abstract_headings.py +127 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_jats_tables.py +15 -8
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_json_api_source.py +6 -6
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_ligature_normalization.py +6 -2
- linkml_reference_validator-0.5.1/tests/test_long_cache_filenames.py +115 -0
- linkml_reference_validator-0.5.1/tests/test_meaning_symbols.py +121 -0
- linkml_reference_validator-0.5.1/tests/test_multivalued_reference.py +248 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_no_cache_downgrade.py +7 -3
- linkml_reference_validator-0.5.1/tests/test_plugin_value_shapes.py +348 -0
- linkml_reference_validator-0.5.1/tests/test_publisher_typography.py +138 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_reference_fetcher.py +9 -9
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_repair.py +221 -0
- linkml_reference_validator-0.5.1/tests/test_repair_data_output.py +315 -0
- linkml_reference_validator-0.5.1/tests/test_repair_thresholds.py +243 -0
- linkml_reference_validator-0.5.1/tests/test_source_network_errors.py +323 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_sources.py +1 -1
- linkml_reference_validator-0.5.1/tests/test_title_only_shapes.py +335 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_title_validation.py +1 -0
- linkml_reference_validator-0.5.1/tests/test_welded_markers.py +184 -0
- linkml_reference_validator-0.5.1/tests/test_word_boundaries.py +151 -0
- linkml_reference_validator-0.5.1/tests/test_xml_extractor_text.py +333 -0
- linkml_reference_validator-0.4.0/src/linkml_reference_validator/etl/extract/xml.py +0 -253
- linkml_reference_validator-0.4.0/src/linkml_reference_validator/plugins/reference_validation_plugin.py +0 -642
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.claude/.mcp.json +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.claude/settings.json +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.copier-answers.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.devcontainer/devcontainer.json +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.devcontainer/post_create.sh +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.editorconfig +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/actions/claude-code-action/action.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/actions/claude-issue-summarize-action/action.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/actions/claude-issue-triage-action/action.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/ai-controllers.json +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/copilot-instructions.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/copilot-setup-steps.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/dependabot.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/claude-code-review.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/claude-issue-summarize.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/claude-issue-triage.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/claude-ontology-review.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/claude.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/deploy-docs.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/dragon-ai.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/main.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.github/workflows/pypi-publish.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.gitignore +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.goosehints +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.pre-commit-config.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/.yamllint.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/AGENTS.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/BUG_GEO_ACCESSION_TO_UID.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/BUG_ZENODO_DOI_AND_URL_HANDLING.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/CLAUDE.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/CLI-ISSUES.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/CODE_OF_CONDUCT.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/CONTRIBUTING.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/FEATURE_REQUEST_REPAIR.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/LICENSE +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/README.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/REVIEW2.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/REVIEW3.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/ai.just +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/benchmarks/repeated_quotes.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/copilot-instructions.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/about.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/assets/zotero-find-full-text.png +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/concepts/content-types.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/concepts/editorial-conventions.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/elements/.gitkeep +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/add-reference-source.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/export-cache-to-zotero.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/skip-unsupported-references.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/use-local-files-and-urls.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/validate-clinical-trials.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/validate-dois.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/validate-entrez.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/validate-obo-files.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/validate-urls.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/index.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/notebooks/01_getting_started.ipynb +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/notebooks/02_advanced_usage.ipynb +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/notebooks/03_python_api.ipynb +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/notebooks/04_obo_validation.ipynb +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/notebooks/05_geo_validation.ipynb +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/quickstart.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/reference/splitting.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/setup-guide.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/superpowers/plans/2026-06-12-modular-pdf-fulltext-fetching.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/superpowers/plans/2026-08-05-private-library-full-text.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/superpowers/specs/2026-06-12-modular-pdf-fulltext-fetching-design.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/superpowers/specs/2026-08-05-private-library-full-text-design.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/templates-linkml/README.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/todo.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/tutorials/complete-workflow.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/examples/README.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/justfile +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/mkdocs.yml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/mypy.ini +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/notebooks/01_getting_started.ipynb +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/notebooks/02_advanced_usage.ipynb +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/notebooks/03_python_api.ipynb +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/notebooks/README.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/project/README.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/project.justfile +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/pyproject.toml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/pytest.ini +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/skills/linkml-reference-validator/SKILL.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/skills/linkml-reference-validator/references/configuration.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/skills/linkml-reference-validator/references/guardrails.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/_version.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/cli/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/cli/cache.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/cli/shared.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/cli/validate.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/acquire.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/csl_export.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/extract/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/extract/base.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/extract/drawio.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/extract/svg_geometry.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/base.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/bioc.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/bookshelf.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/epmc.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/epmc_preprint.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/loader.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/pmc.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/fulltext/zotero.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/rules.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/base.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/clinicaltrials.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/entrez.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/loader.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/sources/ppr.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/etl/text_extractor.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/matching.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/plugins/REVIEW.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/plugins/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/src/linkml_reference_validator/validation/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/__init__.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/conftest.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/data/test_data_deep_nesting_invalid.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/data/test_data_deep_nesting_valid.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/data/test_data_invalid.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/data/test_data_valid.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/data/test_schema.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/data/test_schema_deep_nesting.yaml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/GEO_GSE12345.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMC_TEST001.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMC_TEST001.txt +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMC_TEST002.txt +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMID_TEST001.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMID_TEST001.txt +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMID_TEST002.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMID_TEST002.txt +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/PMID_TEST003.txt +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/bookshelf/esummary_20301710.xml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/bookshelf/gene_NBK1116/men1.nxml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/bookshelf/pubmed_20301710.xml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/clinicaltrials_NCT00000001.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/fulltext_html/README.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/fulltext_html/dspace-32894695.html +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/fulltext_html/iris-19049553.html +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/fulltext_html/plos-0000308.html +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/jats/PMC5593426.xml +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/jats/README.md +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/fixtures/sample.obo +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_absent_abstract_recovery.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_acquire.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_bookshelf_provider.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_bot_challenge.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_cache_author_recovery.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_cli.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_cli_cache_enrich.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_cli_cache_export.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_cli_lookup.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_cli_repair.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_clinicaltrials_cache.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_clinicaltrials_integration.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_deep_nesting.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_drawio.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_epmc_preprint_provider.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_extractor_fidelity.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_extractors.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_field_detection.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_fulltext_loader.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_fulltext_providers.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_fuzzy_suggestions.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_geo_integration.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_identifiers.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_meaning_changes.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_models.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_normalized_content_cache.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_open_access_policy.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_optional_linkml_dependency.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_pdf_url_title.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_plugin_integration.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_pmc_fulltext.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_pmid_network.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_ppr_source.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_real_validation.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_rules.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_serve_stale_html_optin.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_source_utils.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_split_supporting_text.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_supporting_text_validator.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_svg_edges.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_svg_extractor.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_text_extractor.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_trust_cached_entries.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_unknown_slot_traversal.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_url_fragment_cache.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_url_html_sanitize.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_url_html_to_text.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_url_source_cache_version.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_validation_config.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_validation_counts.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/tests/test_zotero_provider.py +0 -0
- {linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/uv.lock +0 -0
{linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/concepts/how-it-works.md
RENAMED
|
@@ -13,7 +13,23 @@ linkml-reference-validator validates that quoted text (supporting text) actually
|
|
|
13
13
|
Before matching, both the supporting text and reference content are normalized:
|
|
14
14
|
|
|
15
15
|
- **Lowercased**: `"MUC1"` → `"muc1"`
|
|
16
|
-
- **Punctuation removed**: `"c-Abl"` → `"c abl"`
|
|
16
|
+
- **Punctuation removed**: `"c-Abl"` → `"c abl"` (a point or comma between
|
|
17
|
+
digits is kept, so `"10.5"` stays one number)
|
|
18
|
+
- **Meaning-bearing symbols kept as words**: `<` `>` `≤` `≥` become `lt` `gt`
|
|
19
|
+
`le` `ge`, `±` (or `+/-`) becomes `pm`, and a minus sign before a number stays
|
|
20
|
+
on it, so `"p < 0.05"` does not match `"p > 0.05"` and `"2.5 fold"` does not
|
|
21
|
+
match `"-2.5 fold"`. ASCII and Unicode spellings are equivalent (`<=` and `≤`,
|
|
22
|
+
`-` and `−`). Publisher spellings count too: MEDLINE's `>/=` and `</=` for
|
|
23
|
+
`≥` and `≤`, a middle-dot decimal (`57·4` is `57.4`), and an en dash or
|
|
24
|
+
Unicode hyphen printed as a minus sign (`z score, –1.98`) or inside `+/–`.
|
|
25
|
+
A `−` set off from its number by a space (`from − 2.92`) is still a sign,
|
|
26
|
+
unless a number comes before it (`10 − 2` is a subtraction). A hyphen or en
|
|
27
|
+
dash after a word or digit (`IL-6`, `3-5`, `1–12`) is still punctuation. A
|
|
28
|
+
dash after a space and before a digit is a sign, so a range spaced on one
|
|
29
|
+
side only (`18 –65`) reads as `18` and `-65`; quote it as the source
|
|
30
|
+
prints it. A middle dot after a letter-joined number is not a decimal
|
|
31
|
+
point, so `MgCl2·6H2O` keeps its hydrate dot (and `pH7·4` does not read as
|
|
32
|
+
`pH7.4`; `pH 7·4` does).
|
|
17
33
|
- **Whitespace collapsed**: Multiple spaces become single space
|
|
18
34
|
- **Editorial notes removed**: `"[mucin 1]"` → `""`
|
|
19
35
|
|
|
@@ -36,6 +52,34 @@ reference_content = "...The MUC1 oncoprotein blocks nuclear..."
|
|
|
36
52
|
# Match: "muc1 oncoprotein" found in normalized reference
|
|
37
53
|
```
|
|
38
54
|
|
|
55
|
+
**Matches start and end on whole words:**
|
|
56
|
+
|
|
57
|
+
A quote may not begin or end inside a word of the reference. Otherwise a quote
|
|
58
|
+
stating the opposite of the paper would pass:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
supporting_text = "activates AKT signaling"
|
|
62
|
+
reference_content = "...Loss of PTEN inactivates AKT signaling..."
|
|
63
|
+
# NOT FOUND: "activates" only occurs inside "inactivates"
|
|
64
|
+
|
|
65
|
+
supporting_text = "5 mM H2O2"
|
|
66
|
+
reference_content = "...treated with 10.5 mM H2O2..."
|
|
67
|
+
# NOT FOUND: "5" only occurs inside "10.5"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Each part of a quote split with `...` is held to the same rule.
|
|
71
|
+
|
|
72
|
+
One allowance: when a quote ends in a letter, the reference word it ends on may
|
|
73
|
+
carry trailing digits. Full-text extraction welds superscript citations onto the
|
|
74
|
+
word before them, so `tumor suppressor<sup>12</sup>` reads as `suppressor12`,
|
|
75
|
+
and a quote of `PTEN is a tumor suppressor` must still match. A quote ending in
|
|
76
|
+
a digit gets no allowance (`10` never matches `105`). The same allowance means a
|
|
77
|
+
quote ending in `AKT` matches `AKT1`, as plain substring matching always did.
|
|
78
|
+
|
|
79
|
+
Because a point or comma between digits stays part of the number, numbers must
|
|
80
|
+
be quoted with the reference's own separators: `days 3, 5 and 7` does not match
|
|
81
|
+
`days 3,5 and 7`, and `10 000` does not match `10,000`.
|
|
82
|
+
|
|
39
83
|
**Empty excerpts are rejected:**
|
|
40
84
|
|
|
41
85
|
An empty or whitespace-only excerpt is always an error, never a pass. The
|
|
@@ -224,6 +268,16 @@ content_type: abstract_only
|
|
|
224
268
|
The MUC1 oncoprotein blocks nuclear targeting...
|
|
225
269
|
```
|
|
226
270
|
|
|
271
|
+
An entry with no title has no `# title`, authors or journal lines, but it still
|
|
272
|
+
gets the `## Content` marker. The content is everything after the first exact
|
|
273
|
+
`## Content` line of that header, so a heading in the text such as
|
|
274
|
+
`## Contents of the kit` stays part of the content. A file written before untitled
|
|
275
|
+
entries got the marker is read whole.
|
|
276
|
+
|
|
277
|
+
A cache file whose frontmatter is empty, isn't valid YAML, or isn't a mapping is
|
|
278
|
+
treated as missing. Validation re-fetches the reference and rewrites the file,
|
|
279
|
+
and tools that walk the cache skip the file with a warning.
|
|
280
|
+
|
|
227
281
|
### Cache Benefits
|
|
228
282
|
|
|
229
283
|
- **Offline usage**: Work without network after initial fetch
|
|
@@ -254,6 +308,15 @@ The plugin discovers fields via:
|
|
|
254
308
|
- `slot_uri` attribute (e.g., `slot_uri: dcterms:title`)
|
|
255
309
|
- Fallback slot names (`reference`, `supporting_text`, `title`)
|
|
256
310
|
|
|
311
|
+
Besides the URIs above, a URI of your own counts as a reference or excerpt
|
|
312
|
+
field when its local name *ends* in the word. One `Field`, `Slot` or `Value`
|
|
313
|
+
suffix may follow it, and for references also an identifier suffix such as
|
|
314
|
+
`Id` or `Uri`. So `ex:reference`, `ex:cross_reference`, `ex:myReferenceField`
|
|
315
|
+
and `ex:reference_id` are reference fields, and `ex:myExcerptField` is an
|
|
316
|
+
excerpt field. `ex:referenceType`, `ex:excerpt_location` and `ex:excerpt_id`
|
|
317
|
+
describe a reference or excerpt, so they are not. If a field of yours is missed
|
|
318
|
+
(say `ex:excerpt_text`), declare it with `implements` or one of the URIs above.
|
|
319
|
+
|
|
257
320
|
## Editorial Conventions
|
|
258
321
|
|
|
259
322
|
### Square Brackets `[...]`
|
|
@@ -405,14 +405,18 @@ fetcher does not crawl repository download links. If every provider completes
|
|
|
405
405
|
without usable text or an error, the reference retains its original abstract
|
|
406
406
|
and records `full_text_attempted: true`.
|
|
407
407
|
|
|
408
|
-
New `full_text_html` cache entries carry `html_full_text_version:
|
|
409
|
-
|
|
410
|
-
|
|
408
|
+
New `full_text_html` cache entries carry `html_full_text_version: 2`. Entries
|
|
409
|
+
with an older stamp, or none, are refreshed on their next validation read.
|
|
410
|
+
Version 2 keeps all of an article region's text rather than only its `<p>`
|
|
411
|
+
text, so lists, tables, headings and bare `<div>` text can be quoted. This migration covers all providers because cached plain text
|
|
411
412
|
cannot establish which HTML body structure was present. It does not invalidate
|
|
412
413
|
current PDF, XML, or abstract caches.
|
|
413
414
|
|
|
414
|
-
If refreshing an
|
|
415
|
-
|
|
415
|
+
If refreshing an entry stamped `html_full_text_version: 1` or later fails,
|
|
416
|
+
validation falls back to it with a warning, as for other content types: it is a
|
|
417
|
+
checked article body, though it may lack list and table text. If refreshing an
|
|
418
|
+
entry with no stamp fails, validation does **not** fall back to that entry: its
|
|
419
|
+
text may be repository metadata rather than article evidence. The
|
|
416
420
|
file remains untouched for inventory/export, and the next validation run retries
|
|
417
421
|
recovery. Once the source is available, normal fetching replaces it with a
|
|
418
422
|
verified article or the available metadata/abstract. Other content types retain
|
|
@@ -26,7 +26,10 @@ The distinct letters `Æ/æ` and `Œ/œ` remain distinct from `AE/ae` and `OE/oe
|
|
|
26
26
|
Equating these letters would accept spelling changes beyond typographic repair.
|
|
27
27
|
Validation uses an explicit ligature table instead of broad Unicode NFKC
|
|
28
28
|
normalization so this change does not equate scientific notation such as `H₂O`
|
|
29
|
-
with `H2O
|
|
29
|
+
with `H2O` or `10⁶` with `106`. The micro sign `µ` and Greek `μ` *are* treated
|
|
30
|
+
as the same letter, since sources use them interchangeably (`5 µM` matches
|
|
31
|
+
`5 μM`), as are the variant Greek forms `ϕ ϵ ϑ ϐ ϖ ϰ ϱ` and the ordinary
|
|
32
|
+
letters they stand for.
|
|
30
33
|
|
|
31
34
|
### Unmapped PDF glyphs do not match
|
|
32
35
|
|
|
@@ -87,6 +90,18 @@ The repair command uses confidence thresholds to determine how to handle each er
|
|
|
87
90
|
| **LOW** | 0.50-0.80 | Flag for manual review |
|
|
88
91
|
| **VERY_LOW** | 0.00-0.50 | Recommend removal |
|
|
89
92
|
|
|
93
|
+
The score ranges are the defaults. A fuzzy match is graded by the repair
|
|
94
|
+
config's `auto_fix_threshold`, `suggest_threshold` and `removal_threshold`, so
|
|
95
|
+
raising `auto_fix_threshold` (or passing `--auto-fix-threshold`) turns
|
|
96
|
+
borderline auto-fixes into suggestions, and lowering it does the reverse. The
|
|
97
|
+
three must be in order, `removal <= suggest <= auto_fix`. A lower threshold
|
|
98
|
+
you leave unset follows one you set below it (`auto_fix_threshold: 0.75` alone
|
|
99
|
+
also lowers `suggest_threshold` to 0.75), and `--auto-fix-threshold` lowers the
|
|
100
|
+
other two with it. Thresholds you set out of order are an error.
|
|
101
|
+
The flag overrides the config file only when it is given. Character
|
|
102
|
+
normalization and ellipsis repairs are not scored, so the thresholds do not
|
|
103
|
+
apply to them.
|
|
104
|
+
|
|
90
105
|
## Repair Strategies
|
|
91
106
|
|
|
92
107
|
### 1. Character Normalization (High Confidence)
|
|
@@ -105,11 +120,30 @@ supporting_text: "CO₂ levels were measured"
|
|
|
105
120
|
|
|
106
121
|
Common mappings:
|
|
107
122
|
- `CO2` → `CO₂`
|
|
123
|
+
- `H2O2` → `H₂O₂`
|
|
108
124
|
- `H2O` → `H₂O`
|
|
109
125
|
- `O2` → `O₂`
|
|
110
126
|
- `+/-` → `±`
|
|
111
127
|
- `+-` → `±`
|
|
112
128
|
|
|
129
|
+
Where a mapping starts or ends with a letter or digit, it applies only if no
|
|
130
|
+
letter or digit sits directly next to it on that side. So `O2` is left alone in
|
|
131
|
+
`CDKN2A` and `N2` in `HEK293N2`. The same rule also skips formulas joined to a
|
|
132
|
+
coefficient or prefix, such as `6CO2`, `2H2O2` and `pCO2`. Fix those by hand.
|
|
133
|
+
A mapping that starts and ends with punctuation, such as `+/-`, applies
|
|
134
|
+
anywhere, so `5+/-2` becomes `5±2`. All mappings are applied in one pass,
|
|
135
|
+
longest first.
|
|
136
|
+
|
|
137
|
+
Validation reads `+-` (except before a letter), `+/-` and `±` all as the same
|
|
138
|
+
word, ignores other punctuation, spells out Greek letters and folds ligatures,
|
|
139
|
+
so it cannot confirm a mapping that changes only those, such as `+-` → `±` or a
|
|
140
|
+
custom `alpha` → `α`. Such a mapping is kept only when the reference contains
|
|
141
|
+
the repaired text exactly as written, apart from case and whitespace.
|
|
142
|
+
That is what keeps `Ca2+-dependent` from becoming `Ca2±dependent`.
|
|
143
|
+
|
|
144
|
+
Quotes with `...` or `[editorial brackets]` are checked part by part, the same
|
|
145
|
+
way validation checks them.
|
|
146
|
+
|
|
113
147
|
### 2. Ellipsis Insertion (Medium Confidence)
|
|
114
148
|
|
|
115
149
|
When text parts exist in the reference but aren't contiguous:
|
|
@@ -245,8 +279,8 @@ linkml-reference-validator repair data <DATA_FILE> --schema <SCHEMA> [OPTIONS]
|
|
|
245
279
|
- `--schema PATH` - Path to LinkML schema (required)
|
|
246
280
|
- `--target-class CLASS` - Target class to validate
|
|
247
281
|
- `--dry-run / --no-dry-run` - Show changes without applying (default: dry-run)
|
|
248
|
-
- `--auto-fix-threshold FLOAT` - Minimum similarity for auto-fixes (default: 0.95)
|
|
249
|
-
- `--output PATH` - Output file path (default: overwrite with backup
|
|
282
|
+
- `--auto-fix-threshold FLOAT` - Minimum similarity for auto-fixes (default: the config file's `auto_fix_threshold`, else 0.95)
|
|
283
|
+
- `--output PATH` - Output file path (default: overwrite the input, keeping a `.bak` backup). When given with `--no-dry-run`, it is always written, as an unchanged copy of the input when there is nothing to fix, and the input itself is not touched, so no backup is made
|
|
250
284
|
- `--config PATH` - Path to repair configuration file
|
|
251
285
|
- `--cache-dir PATH` - Directory for caching references
|
|
252
286
|
- `--verbose` - Show detailed output
|
{linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/how-to/validate-titles.md
RENAMED
|
@@ -106,6 +106,23 @@ classes:
|
|
|
106
106
|
title: "MUC1 oncoprotein blocks nuclear targeting of c-Abl"
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
The reference may take the same shapes as for excerpts:
|
|
110
|
+
|
|
111
|
+
- **A list of one** is checked like a single reference.
|
|
112
|
+
- **Several references with one title field** pass if the title is any one
|
|
113
|
+
reference's title, since it names one paper. If it is none of them, a single
|
|
114
|
+
error names each reference with its own reason. A reference whose prefix is
|
|
115
|
+
skipped vouches for nothing.
|
|
116
|
+
- **Reference objects with their own `title`**, listed or not, and with no title
|
|
117
|
+
field beside them, each have that title checked against their own reference.
|
|
118
|
+
- **A reference with no usable identifier** (an object without `id`, an empty
|
|
119
|
+
string) is reported as an error, not skipped.
|
|
120
|
+
|
|
121
|
+
With an excerpt as well, the title field is checked the same way: against the
|
|
122
|
+
one reference, or, with several, passing if it is any one reference's title.
|
|
123
|
+
It replaces any `title` a reference object carries. Without a title field,
|
|
124
|
+
each reference object's own `title` is checked with the excerpt.
|
|
125
|
+
|
|
109
126
|
## Combined Validation
|
|
110
127
|
|
|
111
128
|
When both title and excerpt fields are present, both are validated together:
|
{linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/reference/cache-format.md
RENAMED
|
@@ -117,7 +117,22 @@ assert header.model_dump()["database"] == "Orphanet"
|
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
The checker derives the filename from the stored `reference_id` by replacing
|
|
120
|
-
`:`, `/`, `?`, and `=` with `_` and appending `.md`.
|
|
120
|
+
`:`, `/`, `?`, and `=` with `_` and appending `.md`. A name that would exceed 200
|
|
121
|
+
bytes of UTF-8 is cut on a character boundary and ends in `_` plus the first 16
|
|
122
|
+
hex digits of the SHA-256 of the full `reference_id` (lowercased for a DOI), so
|
|
123
|
+
a long `url:` reference fits common filesystems' 255-byte limit and two long IDs
|
|
124
|
+
sharing a prefix still get different files. Shorter names are unchanged.
|
|
125
|
+
|
|
126
|
+
Because the replacement is lossy, distinct references can sanitize to the same
|
|
127
|
+
name, such as `url:https://ex.org/a?b=c` and `url:https://ex.org/a/b/c`. The
|
|
128
|
+
first one written keeps that name. When the name is already held by a file whose
|
|
129
|
+
`reference_id` is a different reference, the other one is written under the same
|
|
130
|
+
name ending in `_` and the 16-hex-digit hash of its own ID instead, and the
|
|
131
|
+
checker accepts that name for it. An entry is never served for a reference other
|
|
132
|
+
than the one it records: a hand-written entry whose `reference_id` is a
|
|
133
|
+
placeholder, or an alias spelling such as `pubmed:123` in `PMID_123.md`, is now
|
|
134
|
+
treated as a miss and fetched afresh under the disambiguated name. DOI filenames
|
|
135
|
+
are compared
|
|
121
136
|
case-insensitively, matching the fetcher's existing behavior. Other filenames must
|
|
122
137
|
match exactly. This uses the ID already stored in the file, without applying
|
|
123
138
|
configured prefix aliases or requiring a currently registered reference source.
|
|
@@ -467,7 +467,7 @@ linkml-reference-validator repair text [OPTIONS] TEXT REFERENCE_ID
|
|
|
467
467
|
- `--cache-dir PATH, -c PATH` - Directory for caching references
|
|
468
468
|
- `--config PATH` - Path to configuration file (.yaml)
|
|
469
469
|
- `--verbose, -v` - Verbose output with detailed logging
|
|
470
|
-
- `--auto-fix-threshold FLOAT, -a FLOAT` - Minimum similarity for auto-fixes (default: 0.95)
|
|
470
|
+
- `--auto-fix-threshold FLOAT, -a FLOAT` - Minimum similarity for auto-fixes (default: the config file's `auto_fix_threshold`, else 0.95)
|
|
471
471
|
- `--help` - Show help message
|
|
472
472
|
|
|
473
473
|
### Examples
|
|
@@ -542,8 +542,8 @@ linkml-reference-validator repair data [OPTIONS] DATA_FILE
|
|
|
542
542
|
- `--schema PATH, -s PATH` (required) - Path to LinkML schema file
|
|
543
543
|
- `--target-class TEXT, -t TEXT` - Target class to validate
|
|
544
544
|
- `--dry-run / --no-dry-run, -n / -N` - Show changes without applying (default: dry-run)
|
|
545
|
-
- `--auto-fix-threshold FLOAT, -a FLOAT` - Minimum similarity for auto-fixes (default: 0.95)
|
|
546
|
-
- `--output PATH, -o PATH` - Output file path (default: overwrite with backup
|
|
545
|
+
- `--auto-fix-threshold FLOAT, -a FLOAT` - Minimum similarity for auto-fixes (default: the config file's `auto_fix_threshold`, else 0.95)
|
|
546
|
+
- `--output PATH, -o PATH` - Output file path (default: overwrite the input, keeping a `.bak` backup). When given with `--no-dry-run`, it is always written, as an unchanged copy of the input when there is nothing to fix, and the input itself is not touched, so no backup is made
|
|
547
547
|
- `--config PATH` - Path to configuration file (.yaml)
|
|
548
548
|
- `--cache-dir PATH, -c PATH` - Directory for caching references
|
|
549
549
|
- `--verbose, -v` - Verbose output with detailed logging
|
{linkml_reference_validator-0.4.0 → linkml_reference_validator-0.5.1}/docs/troubleshooting.md
RENAMED
|
@@ -724,6 +724,57 @@ attributes:
|
|
|
724
724
|
slot_uri: linkml:authoritative_reference
|
|
725
725
|
```
|
|
726
726
|
|
|
727
|
+
### Citing several references for one excerpt
|
|
728
|
+
|
|
729
|
+
A reference slot may be `multivalued: true`, holding a list of identifiers
|
|
730
|
+
(or inlined objects with an `id`). The excerpt then passes if **any** listed
|
|
731
|
+
reference contains it: a statement can rest on several papers, and its quote
|
|
732
|
+
comes from one of them. References are tried in order, and the remaining ones
|
|
733
|
+
are not fetched once one passes. A reference whose prefix is in
|
|
734
|
+
`skip_prefixes` is not evidence either way: the other references still decide,
|
|
735
|
+
and the excerpt is counted as skipped only if every listed reference is skipped.
|
|
736
|
+
If none holds the excerpt, a single error names each reference with its own
|
|
737
|
+
reason. The excerpt counts once in "Snippets
|
|
738
|
+
checked", however many references were tried.
|
|
739
|
+
|
|
740
|
+
A title slot names one paper, so it is compared only when a single reference
|
|
741
|
+
is listed. With several, give each listed object its own `title`.
|
|
742
|
+
|
|
743
|
+
Before this, a list was silently ignored: its excerpts were never compared and a
|
|
744
|
+
fabricated quote passed with exit code 0.
|
|
745
|
+
|
|
746
|
+
### Several excerpts, or evidence in a keyed mapping
|
|
747
|
+
|
|
748
|
+
An excerpt slot may also be `multivalued: true`. Each listed excerpt is checked
|
|
749
|
+
on its own against the reference, and reported at its own path, such as
|
|
750
|
+
`supporting_text[1]`: a true excerpt beside a fabricated one does not carry it.
|
|
751
|
+
A blank item, or one that is not text, is an error at its index. Before this,
|
|
752
|
+
a list of excerpts crashed `validate data` with `TypeError: expected string or
|
|
753
|
+
bytes-like object, got 'list'`.
|
|
754
|
+
|
|
755
|
+
Evidence objects in a multivalued slot written as a mapping from identifier to
|
|
756
|
+
object (`inlined_as_list: false`) are each validated, at a path such as
|
|
757
|
+
`has_evidence[E1].supporting_text`; the key is used as the object's identifier
|
|
758
|
+
(or `key` slot) when the object omits it. A dict is read this way only when the
|
|
759
|
+
class has an identifier or key slot and none of the dict's keys is a slot of
|
|
760
|
+
the class; a dict with such a key is a single object written without the list,
|
|
761
|
+
and is validated as one. A compact (non-object) entry in a mapping is left to
|
|
762
|
+
schema validation, and does not stop the objects beside it being checked. Before this, the objects in such a mapping were never
|
|
763
|
+
visited, and a fabricated quote passed with exit code 0. The list form of the
|
|
764
|
+
same slot was, and is, validated the same way.
|
|
765
|
+
|
|
766
|
+
### "Reference at '...' has no usable identifier"
|
|
767
|
+
|
|
768
|
+
**Cause:**
|
|
769
|
+
The reference slot holds a value, but no identifier can be read from it: an
|
|
770
|
+
inlined object with no `id` (or `reference_id`), an empty string, a number, or
|
|
771
|
+
a `null` list item. The excerpt beside it cannot be checked, so this is an
|
|
772
|
+
error rather than a silent pass.
|
|
773
|
+
|
|
774
|
+
**Solution:**
|
|
775
|
+
Give the reference an identifier, e.g. `reference: {id: PMID:12345678}`. An
|
|
776
|
+
excerpt with no reference value at all is not affected by this check.
|
|
777
|
+
|
|
727
778
|
### "Reference base directory not found"
|
|
728
779
|
|
|
729
780
|
**Cause:**
|
|
@@ -905,6 +956,20 @@ XML remains available with the existing stale-cache warning and is not rewritten
|
|
|
905
956
|
it may still lack table rows. A later process retries the refresh. Existing
|
|
906
957
|
stale HTML rejection remains unchanged.
|
|
907
958
|
|
|
959
|
+
`xml_extraction_version: 2` fixes body text that version 1 could get wrong. A
|
|
960
|
+
paragraph nested in another (a `<list>` or `<fig>` inside `<p>`, which JATS
|
|
961
|
+
does routinely) was emitted twice; adjacent list items and lines split by
|
|
962
|
+
`<break/>` were welded together ("alpha itembeta item"); HTML named entities
|
|
963
|
+
such as ` ` and `—`, which PMC's external DTD defines but which is
|
|
964
|
+
never loaded, were dropped and glued the words either side; and a document
|
|
965
|
+
declaring its own entity in an internal DTD subset lost its whole body. A quote
|
|
966
|
+
spanning any of these could fail against correct text. Version 1 XML entries
|
|
967
|
+
are refreshed on the next fetch, as above. Whitespace inside a paragraph is now
|
|
968
|
+
collapsed to single spaces (a no-break space included), as it already was in
|
|
969
|
+
table cells.
|
|
970
|
+
The HTML-entity repair applies to UTF-8 and other ASCII-compatible encodings
|
|
971
|
+
only; in a UTF-16 or UTF-32 document an undeclared ` ` is still dropped.
|
|
972
|
+
|
|
908
973
|
Entries that record *no* content carry their own stamp. A cache entry written
|
|
909
974
|
as `content_type: unavailable` is a claim about what an extractor could not
|
|
910
975
|
find, so an extractor fix can make it wrong -- and because such an entry carries
|
|
@@ -5,6 +5,7 @@ Unknown fields are preserved, so consumers can add metadata without a namespace.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from dataclasses import dataclass, field
|
|
8
|
+
import hashlib
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
import re
|
|
10
11
|
|
|
@@ -154,9 +155,64 @@ def legacy_cache_filename(reference_id: str) -> str:
|
|
|
154
155
|
return _sanitized_filename(reference_id)
|
|
155
156
|
|
|
156
157
|
|
|
158
|
+
#: The longest cache filename written, in UTF-8 bytes. Common filesystems allow
|
|
159
|
+
#: 255; this leaves room for a ``.txt`` legacy probe and other tools' suffixes.
|
|
160
|
+
MAX_CACHE_FILENAME_BYTES = 200
|
|
161
|
+
|
|
162
|
+
#: Hex digits of the reference ID's SHA-256 kept in a capped filename.
|
|
163
|
+
_FILENAME_HASH_CHARS = 16
|
|
164
|
+
|
|
165
|
+
|
|
157
166
|
def _sanitized_filename(reference_id: str) -> str:
|
|
158
|
-
"""Sanitize a reference ID into a filename, keeping everything else verbatim.
|
|
159
|
-
|
|
167
|
+
"""Sanitize a reference ID into a filename, keeping everything else verbatim.
|
|
168
|
+
|
|
169
|
+
A name over ``MAX_CACHE_FILENAME_BYTES`` is cut on a character boundary and
|
|
170
|
+
ends in ``_`` plus a hash of the full ID, so it fits the filesystem and two
|
|
171
|
+
long IDs that share a prefix still get different files (#132). A DOI is
|
|
172
|
+
hashed case-insensitively, so case variants of one DOI still differ only in
|
|
173
|
+
case, as the fetcher's case-variant lookup and the checker expect.
|
|
174
|
+
|
|
175
|
+
>>> _sanitized_filename("PMID:1")
|
|
176
|
+
'PMID_1.md'
|
|
177
|
+
>>> name = _sanitized_filename("url:https://example.org/?q=" + "x" * 300)
|
|
178
|
+
>>> len(name.encode("utf-8")) <= MAX_CACHE_FILENAME_BYTES, name[-20:]
|
|
179
|
+
(True, '_8d32b36eb989401f.md')
|
|
180
|
+
"""
|
|
181
|
+
name = re.sub(r"[:/?=]", "_", reference_id)
|
|
182
|
+
if len(name.encode("utf-8")) + len(".md") <= MAX_CACHE_FILENAME_BYTES:
|
|
183
|
+
return name + ".md"
|
|
184
|
+
return _hashed_filename(name, reference_id)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def disambiguated_cache_filename(reference_id: str) -> str:
|
|
188
|
+
"""Return the filename for a reference whose usual name another one holds.
|
|
189
|
+
|
|
190
|
+
Sanitizing maps ``:`` ``/`` ``?`` and ``=`` to ``_``, so distinct
|
|
191
|
+
references can share :func:`cache_filename`: ``url:https://ex.org/a?b=c``
|
|
192
|
+
and ``url:https://ex.org/a/b/c``. The first writer keeps the shared name;
|
|
193
|
+
the other is written here, under the same name ending in a hash of its own
|
|
194
|
+
ID, so no existing entry is renamed (#131).
|
|
195
|
+
|
|
196
|
+
>>> disambiguated_cache_filename("url:https://ex.org/a/b/c")
|
|
197
|
+
'url_https___ex.org_a_b_c_5acbea067cb82733.md'
|
|
198
|
+
"""
|
|
199
|
+
key = cache_key(reference_id)
|
|
200
|
+
return _hashed_filename(re.sub(r"[:/?=]", "_", key), key)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _hashed_filename(name: str, reference_id: str) -> str:
|
|
204
|
+
"""``name``, cut to fit, ending in ``_`` and a hash of ``reference_id``.
|
|
205
|
+
|
|
206
|
+
A DOI is hashed case-insensitively, so case variants of one DOI still
|
|
207
|
+
differ only in case.
|
|
208
|
+
"""
|
|
209
|
+
digest_source = (
|
|
210
|
+
reference_id.casefold() if reference_id.upper().startswith("DOI:") else reference_id
|
|
211
|
+
)
|
|
212
|
+
digest = hashlib.sha256(digest_source.encode("utf-8")).hexdigest()[:_FILENAME_HASH_CHARS]
|
|
213
|
+
room = MAX_CACHE_FILENAME_BYTES - len(".md") - len("_") - len(digest)
|
|
214
|
+
prefix = name.encode("utf-8")[:room].decode("utf-8", errors="ignore")
|
|
215
|
+
return f"{prefix}_{digest}.md"
|
|
160
216
|
|
|
161
217
|
|
|
162
218
|
def _same_reference_id(first: str, second: str) -> bool:
|
|
@@ -257,11 +313,13 @@ def _validate_cache_file(
|
|
|
257
313
|
|
|
258
314
|
reference_id = result.frontmatter.reference_id
|
|
259
315
|
expected = cache_filename(reference_id)
|
|
260
|
-
# A fragment-keyed name from before #114 is still read, so still valid
|
|
261
|
-
|
|
316
|
+
# A fragment-keyed name from before #114 is still read, so still valid, as
|
|
317
|
+
# is the name a reference gets when another holds its usual one (#131).
|
|
318
|
+
disambiguated = disambiguated_cache_filename(reference_id)
|
|
319
|
+
accepted = {expected, legacy_cache_filename(reference_id), disambiguated}
|
|
262
320
|
matches = path.name in accepted
|
|
263
321
|
if reference_id.upper().startswith("DOI:"):
|
|
264
|
-
matches = path.name.casefold()
|
|
322
|
+
matches = path.name.casefold() in {expected.casefold(), disambiguated.casefold()}
|
|
265
323
|
if not matches:
|
|
266
324
|
result.findings.append(
|
|
267
325
|
CacheFinding(
|
|
@@ -9,7 +9,10 @@ import typer
|
|
|
9
9
|
from ruamel.yaml import YAML
|
|
10
10
|
from typing_extensions import Annotated
|
|
11
11
|
|
|
12
|
-
from linkml_reference_validator.etl.reference_fetcher import
|
|
12
|
+
from linkml_reference_validator.etl.reference_fetcher import (
|
|
13
|
+
ReferenceFetcher,
|
|
14
|
+
markdown_body_lines,
|
|
15
|
+
)
|
|
13
16
|
from linkml_reference_validator.models import ReferenceContent
|
|
14
17
|
from .shared import (
|
|
15
18
|
CacheDirOption,
|
|
@@ -128,22 +131,8 @@ def _format_as_markdown(reference: ReferenceContent, fetcher: ReferenceFetcher)
|
|
|
128
131
|
yaml_obj.dump(frontmatter, stream)
|
|
129
132
|
|
|
130
133
|
lines = ["---", stream.getvalue().rstrip(), "---", ""]
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if reference.authors:
|
|
134
|
-
lines.append(f"**Authors:** {', '.join(reference.authors)}")
|
|
135
|
-
if reference.journal:
|
|
136
|
-
journal_info = reference.journal
|
|
137
|
-
if reference.year:
|
|
138
|
-
journal_info += f" ({reference.year})"
|
|
139
|
-
lines.append(f"**Journal:** {journal_info}")
|
|
140
|
-
if reference.doi:
|
|
141
|
-
lines.append(f"**DOI:** [{reference.doi}](https://doi.org/{reference.doi})")
|
|
142
|
-
lines.append("")
|
|
143
|
-
lines.append("## Content")
|
|
144
|
-
lines.append("")
|
|
145
|
-
if reference.content:
|
|
146
|
-
lines.append(reference.content)
|
|
134
|
+
# The same body the cache writer emits, so the output reads back as saved.
|
|
135
|
+
lines.extend(markdown_body_lines(reference))
|
|
147
136
|
return "\n".join(lines)
|
|
148
137
|
|
|
149
138
|
|