From 8205a5633e1ac8042a89a3643eaa8c6845b692e5 Mon Sep 17 00:00:00 2001 From: Lawon Lewis Date: Wed, 9 Oct 2024 09:02:44 +1000 Subject: [PATCH 1/3] fix: allow overriding predicates via env var previous configuration would always fail pydantic validation, because it required passing a list of URIRefs which was is not possible from env var. This fix allows passing strings which are then converted to URIRefs via a custom field validator. --- prez/config.py | 44 ++++++++++++++++-------- prez/services/query_generation/search.py | 2 +- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/prez/config.py b/prez/config.py index f4a1c2d9..b53e629f 100755 --- a/prez/config.py +++ b/prez/config.py @@ -1,15 +1,14 @@ from os import environ from pathlib import Path -from typing import Optional, List, Tuple -from typing import Union, Any, Dict +from typing import Any, Dict, List, Optional, Tuple, Union import toml from pydantic import field_validator from pydantic_settings import BaseSettings -from rdflib import URIRef, DCTERMS, RDFS, SDO +from rdflib import DCTERMS, RDFS, SDO, URIRef from rdflib.namespace import SKOS -from prez.reference_data.prez_ns import REG, EP +from prez.reference_data.prez_ns import EP, REG class Settings(BaseSettings): @@ -40,19 +39,25 @@ class Settings(BaseSettings): order_lists_by_label: bool = True listing_count_limit: int = 100 search_count_limit: int = 10 - label_predicates: Optional[List[URIRef]] = [ + label_predicates: list = [ SKOS.prefLabel, DCTERMS.title, RDFS.label, SDO.name, ] - description_predicates: Optional[List[URIRef]] = [ + description_predicates: list = [ SKOS.definition, DCTERMS.description, SDO.description, ] - provenance_predicates: Optional[List[URIRef]] = [DCTERMS.provenance] - other_predicates: Optional[List[URIRef]] = [SDO.color, REG.status] + provenance_predicates: list = [DCTERMS.provenance] + search_predicates: list = [ + RDFS.label, + SKOS.prefLabel, + SDO.name, + DCTERMS.title, + ] + other_predicates: list = [SDO.color, REG.status] sparql_repo_type: str = "remote" sparql_timeout: int = 30 log_level: str = "INFO" @@ -66,12 +71,6 @@ class Settings(BaseSettings): prez_contact: Optional[Dict[str, Union[str, Any]]] = None disable_prefix_generation: bool = False default_language: str = "en" - default_search_predicates: Optional[List[URIRef]] = [ - RDFS.label, - SKOS.prefLabel, - SDO.name, - DCTERMS.title, - ] local_rdf_dir: str = "rdf" endpoint_structure: Optional[Tuple[str, ...]] = ("catalogs", "collections", "items") system_endpoints: Optional[List[URIRef]] = [ @@ -114,5 +113,22 @@ def get_version(cls, v): "PREZ_VERSION not set, and cannot find a pyproject.toml to extract the version." ) + @field_validator( + "label_predicates", + "description_predicates", + "provenance_predicates", + "search_predicates", + "other_predicates", + ) + def validate_predicates(cls, v): + try: + v = [URIRef(predicate) for predicate in v] + except ValueError as e: + raise ValueError( + "Could not parse predicates. predicates must be valid URIs no prefixes allowed " + f"original message: {e}" + ) + return v + settings = Settings() diff --git a/prez/services/query_generation/search.py b/prez/services/query_generation/search.py index 2cc0dca4..1da1e66d 100755 --- a/prez/services/query_generation/search.py +++ b/prez/services/query_generation/search.py @@ -57,7 +57,7 @@ def __init__( limit += 1 # increase the limit by one so we know if there are further pages of results. if not predicates: - predicates = settings.default_search_predicates + predicates = settings.search_predicates sr_uri: Var = Var(value="focus_node") pred: Var = Var(value="pred") From a652b5881b649f63f2b6e17737d7c90b73431bad Mon Sep 17 00:00:00 2001 From: Lawon Lewis Date: Wed, 9 Oct 2024 09:14:16 +1000 Subject: [PATCH 2/3] fix: bump python version there were failing tests under python 3.11. version really should be 3.12 anyway. --- poetry.lock | 59 +++++--------------------------------------------- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 55 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7d2b2913..a9af7d45 100644 --- a/poetry.lock +++ b/poetry.lock @@ -580,29 +580,6 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] -[[package]] -name = "importlib-metadata" -version = "8.5.0" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, - {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, -] - -[package.dependencies] -zipp = ">=3.20" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] -type = ["pytest-mypy"] - [[package]] name = "iniconfig" version = "2.0.0" @@ -1115,10 +1092,7 @@ files = [ ] [package.dependencies] -numpy = [ - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, -] +numpy = {version = ">=1.26.0", markers = "python_version >= \"3.12\""} python-dateutil = ">=2.8.2" pytz = ">=2020.1" tzdata = ">=2022.7" @@ -1291,8 +1265,8 @@ files = [ annotated-types = ">=0.6.0" pydantic-core = "2.23.4" typing-extensions = [ - {version = ">=4.6.1", markers = "python_version < \"3.13\""}, {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, ] [package.extras] @@ -1600,13 +1574,9 @@ files = [ [package.dependencies] html5lib = ">=1.1,<2" -importlib-metadata = {version = ">6", markers = "python_version < \"3.12\""} owlrl = ">=6.0.2,<7" packaging = ">=21.3" -prettytable = [ - {version = ">=3.5.0", markers = "python_version >= \"3.8\" and python_version < \"3.12\""}, - {version = ">=3.7.0", markers = "python_version >= \"3.12\""}, -] +prettytable = {version = ">=3.7.0", markers = "python_version >= \"3.12\""} rdflib = {version = ">=6.3.2,<8.0", markers = "python_full_version >= \"3.8.1\""} [package.extras] @@ -2222,29 +2192,10 @@ files = [ {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, ] -[[package]] -name = "zipp" -version = "3.20.2" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] -type = ["pytest-mypy"] - [extras] server = ["uvicorn"] [metadata] lock-version = "2.0" -python-versions = "^3.11" -content-hash = "4eb7cb6ad7a00c207d54301cf390d428b7e6e5371125dd004d8087ac855efe0d" +python-versions = "^3.12" +content-hash = "357971b22f72662bd6e49a31f9da34550b0b44facbd4640c1d29d5a1de5f6378" diff --git a/pyproject.toml b/pyproject.toml index 5b45c0a9..30b850bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ include = [ ] [tool.poetry.dependencies] -python = "^3.11" +python = "^3.12" uvicorn = {version = "^0.30.0", optional = true } httpx = "^0.27.0" rdflib = "^7.0.0" From 372ea1c48c17dc85937b01e52b4162980603096a Mon Sep 17 00:00:00 2001 From: Lawon Lewis Date: Wed, 9 Oct 2024 09:47:06 +1000 Subject: [PATCH 3/3] chore: add test cases --- tests/test_predicates.py | 88 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 tests/test_predicates.py diff --git a/tests/test_predicates.py b/tests/test_predicates.py new file mode 100644 index 00000000..c4259e61 --- /dev/null +++ b/tests/test_predicates.py @@ -0,0 +1,88 @@ +import pytest + +from prez.config import Settings + + +@pytest.mark.parametrize( + "label_predicates, error", + [ + [["https://schema.org/name"], None], + [["1", "2", "3"], None], + [[1], TypeError], + ["not a list", ValueError], + ], +) +def test_label_predicates(label_predicates, error): + if error: + with pytest.raises(error): + assert Settings(label_predicates=label_predicates) + else: + assert Settings(label_predicates=label_predicates) + + +@pytest.mark.parametrize( + "description_predicates, error", + [ + [["https://schema.org/description"], None], + [["1", "2", "3"], None], + [[1], TypeError], + ["not a list", ValueError], + ], +) +def test_description_predicates(description_predicates, error): + if error: + with pytest.raises(error): + assert Settings(description_predicates=description_predicates) + else: + assert Settings(description_predicates=description_predicates) + + +@pytest.mark.parametrize( + "provenance_predicates, error", + [ + [["https://schema.org/provenance"], None], + [["1", "2", "3"], None], + [[1], TypeError], + ["not a list", ValueError], + ], +) +def test_provenance_predicates(provenance_predicates, error): + if error: + with pytest.raises(error): + assert Settings(provenance_predicates=provenance_predicates) + else: + assert Settings(provenance_predicates=provenance_predicates) + + +@pytest.mark.parametrize( + "search_predicates, error", + [ + [["https://schema.org/search"], None], + [["1", "2", "3"], None], + [[1], TypeError], + ["not a list", ValueError], + ], +) +def test_search_predicates(search_predicates, error): + if error: + with pytest.raises(error): + assert Settings(search_predicates=search_predicates) + else: + assert Settings(search_predicates=search_predicates) + + +@pytest.mark.parametrize( + "other_predicates, error", + [ + [["https://schema.org/other"], None], + [["1", "2", "3"], None], + [[1], TypeError], + ["not a list", ValueError], + ], +) +def test_other_predicates(other_predicates, error): + if error: + with pytest.raises(error): + assert Settings(other_predicates=other_predicates) + else: + assert Settings(other_predicates=other_predicates)