From 02553f8f0c85595a29f641f280709c531cb6cb61 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 11 Jul 2024 23:06:31 +1000 Subject: [PATCH 1/5] 1. Change dcterms:identifier with prez:identifier datatype to prez:identifier datatype. 2. Expand accepted mediatypes on homepage --- prez/routers/management.py | 17 ++++++++++++----- prez/services/connegp_service.py | 21 +++++++++++++++++++++ prez/services/link_generation.py | 26 +++++++++++++------------- 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/prez/routers/management.py b/prez/routers/management.py index ca607078..707bc9ef 100755 --- a/prez/routers/management.py +++ b/prez/routers/management.py @@ -1,8 +1,9 @@ import logging import pickle +from typing import Optional from aiocache import caches -from fastapi import APIRouter +from fastapi import APIRouter, Query from rdflib import BNode from rdflib import Graph, URIRef, Literal from rdflib.collection import Collection @@ -12,23 +13,29 @@ from prez.cache import endpoints_graph_cache from prez.config import settings from prez.reference_data.prez_ns import PREZ -from prez.renderers.renderer import return_rdf -from prez.services.connegp_service import RDF_MEDIATYPES +from prez.renderers.renderer import return_rdf, return_from_graph +from prez.services.connegp_service import RDF_MEDIATYPES, MediaType router = APIRouter(tags=["Management"]) log = logging.getLogger(__name__) @router.get("/", summary="Home page", tags=["Prez"]) -async def index(): +async def index( + mediatype: Optional[MediaType] = Query( + MediaType("text/turtle"), alias="_mediatype", description="Requested mediatype" + ), +): """Returns the following information about the API""" + if "anot+" in mediatype.value: + mediatype = MediaType(mediatype.value.replace("anot+", "")) g = Graph() g.bind("prez", "https://prez.dev/") g.bind("ont", "https://prez.dev/ont/") g.add((URIRef(settings.system_uri), PREZ.version, Literal(settings.prez_version))) g += endpoints_graph_cache g += await return_annotation_predicates() - return await return_rdf(g, "text/turtle", profile_headers={}) + return await return_rdf(g, mediatype.value, profile_headers={}) @router.get("/purge-tbox-cache", summary="Reset Tbox Cache") diff --git a/prez/services/connegp_service.py b/prez/services/connegp_service.py index 59d99ad4..d3955a58 100755 --- a/prez/services/connegp_service.py +++ b/prez/services/connegp_service.py @@ -1,5 +1,6 @@ import logging import re +from enum import Enum from textwrap import dedent from pydantic import BaseModel @@ -35,6 +36,26 @@ "text/plain": "nt", # text/plain is the old/deprecated mimetype for n-triples } +class MediaType(str, Enum): + turtle = "text/turtle" + n3 = "text/n3" + nt = "application/n-triples" + json_ld = "application/ld+json" + xml = "application/rdf+xml" + anot_turtle = "text/anot+turtle" + anot_n3 = "text/anot+n3" + anot_nt = "application/anot+n-triples" + anot_json_ld = "application/anot+ld+json" + anot_xml = "application/anot+rdf+xml" + # Some common but incorrect mimetypes + application_rdf = "application/rdf" + application_rdf_xml = "application/rdf xml" + application_json = "application/json" + application_ld_json = "application/ld json" + text_ttl = "text/ttl" + text_ntriples = "text/ntriples" + text_plain = "text/plain" + class TokenError(Exception): def __init__(self, *args): diff --git a/prez/services/link_generation.py b/prez/services/link_generation.py index 79043fc0..94365a7b 100755 --- a/prez/services/link_generation.py +++ b/prez/services/link_generation.py @@ -2,7 +2,7 @@ import time from string import Template -from rdflib import Graph, Literal, URIRef, DCTERMS, BNode +from rdflib import Graph, Literal, URIRef from rdflib.namespace import SH, RDF from sparql_grammar_pydantic import ( IRI, @@ -46,11 +46,11 @@ async def add_prez_links(graph: Graph, repo: Repo, endpoint_structure): async def _link_generation( - uri: URIRef, - repo: Repo, - klasses, - graph: Graph, - endpoint_structure: str = settings.endpoint_structure, + uri: URIRef, + repo: Repo, + klasses, + graph: Graph, + endpoint_structure: str = settings.endpoint_structure, ): """ Generates links for the given URI if it is not already cached. @@ -72,10 +72,10 @@ async def _link_generation( ns for ns in available_nodeshapes if ns.uri - not in [ - URIRef("http://example.org/ns#CQL"), - URIRef("http://example.org/ns#Search"), - ] + not in [ + URIRef("http://example.org/ns#CQL"), + URIRef("http://example.org/ns#Search"), + ] ] # run queries for available nodeshapes to get link components for ns in available_nodeshapes: @@ -133,7 +133,7 @@ async def get_nodeshapes_constraining_class(klasses, uri): async def add_links_to_graph_and_cache( - curie_for_uri, graph, members_link, object_link, uri + curie_for_uri, graph, members_link, object_link, uri ): """ Adds links and identifiers to the given graph and cache. @@ -141,10 +141,10 @@ async def add_links_to_graph_and_cache( quads = [] quads.append((uri, PREZ["link"], Literal(object_link), uri)) quads.append( - (uri, DCTERMS.identifier, Literal(curie_for_uri, datatype=PREZ.identifier), uri) + (uri, PREZ.identifier, Literal(curie_for_uri), uri) ) if ( - members_link + members_link ): # TODO need to confirm the link value doesn't match the existing link value, as multiple endpoints can deliver the same class/have different links for the same URI existing_members_link = list( links_ids_graph_cache.quads((uri, PREZ["members"], None, uri)) From d9dbbe3ac8ce29c65b7f7ea56efff069f14b9783 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 11 Jul 2024 23:35:22 +1000 Subject: [PATCH 2/5] Add missing import --- prez/services/link_generation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prez/services/link_generation.py b/prez/services/link_generation.py index 94365a7b..536c785b 100755 --- a/prez/services/link_generation.py +++ b/prez/services/link_generation.py @@ -2,7 +2,7 @@ import time from string import Template -from rdflib import Graph, Literal, URIRef +from rdflib import Graph, Literal, URIRef, BNode from rdflib.namespace import SH, RDF from sparql_grammar_pydantic import ( IRI, From 38a973bec01e954364e4f4c4300a399fc9ccdb83 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 11 Jul 2024 23:06:31 +1000 Subject: [PATCH 3/5] 1. Change dcterms:identifier with prez:identifier datatype to prez:identifier datatype. 2. Expand accepted mediatypes on homepage --- prez/routers/management.py | 17 ++++++++++++----- prez/services/connegp_service.py | 21 +++++++++++++++++++++ prez/services/link_generation.py | 4 ++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/prez/routers/management.py b/prez/routers/management.py index ca607078..707bc9ef 100755 --- a/prez/routers/management.py +++ b/prez/routers/management.py @@ -1,8 +1,9 @@ import logging import pickle +from typing import Optional from aiocache import caches -from fastapi import APIRouter +from fastapi import APIRouter, Query from rdflib import BNode from rdflib import Graph, URIRef, Literal from rdflib.collection import Collection @@ -12,23 +13,29 @@ from prez.cache import endpoints_graph_cache from prez.config import settings from prez.reference_data.prez_ns import PREZ -from prez.renderers.renderer import return_rdf -from prez.services.connegp_service import RDF_MEDIATYPES +from prez.renderers.renderer import return_rdf, return_from_graph +from prez.services.connegp_service import RDF_MEDIATYPES, MediaType router = APIRouter(tags=["Management"]) log = logging.getLogger(__name__) @router.get("/", summary="Home page", tags=["Prez"]) -async def index(): +async def index( + mediatype: Optional[MediaType] = Query( + MediaType("text/turtle"), alias="_mediatype", description="Requested mediatype" + ), +): """Returns the following information about the API""" + if "anot+" in mediatype.value: + mediatype = MediaType(mediatype.value.replace("anot+", "")) g = Graph() g.bind("prez", "https://prez.dev/") g.bind("ont", "https://prez.dev/ont/") g.add((URIRef(settings.system_uri), PREZ.version, Literal(settings.prez_version))) g += endpoints_graph_cache g += await return_annotation_predicates() - return await return_rdf(g, "text/turtle", profile_headers={}) + return await return_rdf(g, mediatype.value, profile_headers={}) @router.get("/purge-tbox-cache", summary="Reset Tbox Cache") diff --git a/prez/services/connegp_service.py b/prez/services/connegp_service.py index 59d99ad4..d3955a58 100755 --- a/prez/services/connegp_service.py +++ b/prez/services/connegp_service.py @@ -1,5 +1,6 @@ import logging import re +from enum import Enum from textwrap import dedent from pydantic import BaseModel @@ -35,6 +36,26 @@ "text/plain": "nt", # text/plain is the old/deprecated mimetype for n-triples } +class MediaType(str, Enum): + turtle = "text/turtle" + n3 = "text/n3" + nt = "application/n-triples" + json_ld = "application/ld+json" + xml = "application/rdf+xml" + anot_turtle = "text/anot+turtle" + anot_n3 = "text/anot+n3" + anot_nt = "application/anot+n-triples" + anot_json_ld = "application/anot+ld+json" + anot_xml = "application/anot+rdf+xml" + # Some common but incorrect mimetypes + application_rdf = "application/rdf" + application_rdf_xml = "application/rdf xml" + application_json = "application/json" + application_ld_json = "application/ld json" + text_ttl = "text/ttl" + text_ntriples = "text/ntriples" + text_plain = "text/plain" + class TokenError(Exception): def __init__(self, *args): diff --git a/prez/services/link_generation.py b/prez/services/link_generation.py index 4311c006..18b5ffeb 100755 --- a/prez/services/link_generation.py +++ b/prez/services/link_generation.py @@ -2,7 +2,7 @@ import time from string import Template -from rdflib import Graph, Literal, URIRef, DCTERMS, BNode +from rdflib import Graph, Literal, URIRef from rdflib.namespace import SH, RDF from sparql_grammar_pydantic import ( IRI, @@ -145,7 +145,7 @@ async def add_links_to_graph_and_cache( quads.append((uri, PREZ["link"], Literal(object_link), uri)) for uri_in_link_string, curie_in_link_string in identifiers.items(): quads.append( - (uri_in_link_string, DCTERMS.identifier, Literal(curie_in_link_string, datatype=PREZ.identifier), uri) + (uri_in_link_string, PREZ.identifier, Literal(curie_in_link_string), uri) ) if ( members_link From 0e56730861457b24a30c7560cfe7afa2744d5fac Mon Sep 17 00:00:00 2001 From: david Date: Thu, 11 Jul 2024 23:35:22 +1000 Subject: [PATCH 4/5] Add missing import --- prez/services/link_generation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prez/services/link_generation.py b/prez/services/link_generation.py index 18b5ffeb..a23d6235 100755 --- a/prez/services/link_generation.py +++ b/prez/services/link_generation.py @@ -2,7 +2,7 @@ import time from string import Template -from rdflib import Graph, Literal, URIRef +from rdflib import Graph, Literal, URIRef, BNode from rdflib.namespace import SH, RDF from sparql_grammar_pydantic import ( IRI, From eba841126174ccbc3cd1928c1693687e2e92ca06 Mon Sep 17 00:00:00 2001 From: david Date: Thu, 25 Jul 2024 09:44:45 +1000 Subject: [PATCH 5/5] use connegp for homepage and utilise return from graph function to handle annotated mediatypes. --- prez/routers/management.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/prez/routers/management.py b/prez/routers/management.py index 707bc9ef..44d7d14e 100755 --- a/prez/routers/management.py +++ b/prez/routers/management.py @@ -3,7 +3,7 @@ from typing import Optional from aiocache import caches -from fastapi import APIRouter, Query +from fastapi import APIRouter, Query, Depends from rdflib import BNode from rdflib import Graph, URIRef, Literal from rdflib.collection import Collection @@ -12,9 +12,11 @@ from prez.cache import endpoints_graph_cache from prez.config import settings +from prez.dependencies import get_system_repo from prez.reference_data.prez_ns import PREZ from prez.renderers.renderer import return_rdf, return_from_graph -from prez.services.connegp_service import RDF_MEDIATYPES, MediaType +from prez.repositories import Repo +from prez.services.connegp_service import RDF_MEDIATYPES, MediaType, NegotiatedPMTs router = APIRouter(tags=["Management"]) log = logging.getLogger(__name__) @@ -22,20 +24,33 @@ @router.get("/", summary="Home page", tags=["Prez"]) async def index( - mediatype: Optional[MediaType] = Query( - MediaType("text/turtle"), alias="_mediatype", description="Requested mediatype" - ), + request: Request, + system_repo: Repo = Depends(get_system_repo) ): """Returns the following information about the API""" - if "anot+" in mediatype.value: - mediatype = MediaType(mediatype.value.replace("anot+", "")) + pmts = NegotiatedPMTs( + headers=request.headers, + params=request.query_params, + classes=[PREZ.Object], + system_repo=system_repo, + ) + await pmts.setup() g = Graph() g.bind("prez", "https://prez.dev/") g.bind("ont", "https://prez.dev/ont/") g.add((URIRef(settings.system_uri), PREZ.version, Literal(settings.prez_version))) g += endpoints_graph_cache g += await return_annotation_predicates() - return await return_rdf(g, mediatype.value, profile_headers={}) + return await return_from_graph( + graph=g, + mediatype=pmts.selected["mediatype"], + profile=pmts.selected["profile"], + profile_headers=pmts.generate_response_headers(), + selected_class=pmts.selected["class"], + repo=system_repo, + system_repo=system_repo + ) + @router.get("/purge-tbox-cache", summary="Reset Tbox Cache")