Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
recalcitrantsupplant committed Feb 21, 2024
1 parent 1084863 commit 75c285d
Show file tree
Hide file tree
Showing 17 changed files with 309 additions and 232 deletions.
157 changes: 74 additions & 83 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions prez/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
)
from prez.config import settings
from prez.repositories import PyoxigraphRepo, RemoteSparqlRepo, OxrdflibRepo
from rdframe import CQLParser
from prez.services.query_generation.node_selection.cql import CQLParser


async def get_async_http_client():
Expand Down Expand Up @@ -110,7 +110,7 @@ async def cql_get_parser_dependency(request: Request):
query = json.loads(request.query_params["filter"])
context = json.load(
(
Path(__file__).parent.parent / "temp" / "default_cql_context.json"
Path(__file__).parent / "reference_data/cql/default_context.json"
).open()
)
cql_parser = CQLParser(cql=query, context=context)
Expand Down
22 changes: 11 additions & 11 deletions prez/models/profiles_and_mediatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@ def populate_requested_types(self):


async def populate_profile_and_mediatype(
profiles_mediatypes_model: ProfilesMediatypesInfo, system_repo: Repo
prof_model: ProfilesMediatypesInfo, system_repo: Repo
):
req_profiles = profiles_mediatypes_model.req_profiles
req_profiles_token = profiles_mediatypes_model.req_profiles_token
req_mediatypes = profiles_mediatypes_model.req_mediatypes
classes = profiles_mediatypes_model.classes
listing = profiles_mediatypes_model.listing
req_profiles = prof_model.req_profiles
req_profiles_token = prof_model.req_profiles_token
req_mediatypes = prof_model.req_mediatypes
classes = prof_model.classes
listing = prof_model.listing
(
profiles_mediatypes_model.profile,
profiles_mediatypes_model.mediatype,
profiles_mediatypes_model.selected_class,
profiles_mediatypes_model.profile_headers,
profiles_mediatypes_model.avail_profile_uris,
prof_model.profile,
prof_model.mediatype,
prof_model.selected_class,
prof_model.profile_headers,
prof_model.avail_profile_uris,
) = await get_profiles_and_mediatypes(
classes, system_repo, req_profiles, req_profiles_token, req_mediatypes, listing
)
19 changes: 19 additions & 0 deletions prez/reference_data/endpoints/endpoint_node_selection_shapes.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix shext: <http://example.com/shacl-extension#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix altr-ext: <http://www.w3.org/ns/dx/conneg/altr-ext#> .

ex:TopLevelCatalogs
a sh:NodeShape ;
Expand Down Expand Up @@ -110,4 +111,22 @@ ex:queryables a sh:NodeShape ;
}""" ] ;
shext:limit 100 ;
shext:offset 0 ;
.

ex:AltProfilesForListing
a sh:NodeShape ;
ont:hierarchyLevel 1 ;
sh:targetClass prez:ListingProfile ;
sh:property [
sh:path altr-ext:constrainsClass ;
]
.

ex:AltProfilesForObject
a sh:NodeShape ;
ont:hierarchyLevel 1 ;
sh:targetClass prez:ObjectProfile ;
sh:property [
sh:path altr-ext:constrainsClass ;
]
.
4 changes: 2 additions & 2 deletions prez/reference_data/profiles/ogc_records_profile.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ prez:OGCRecordsProfile
altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
altr-ext:hasNodeShape [
a sh:NodeShape ;
sh:targetClass dcat:Catalog , skos:Concept , geo:Feature , geo:FeatureCollection , skos:Collection , prez:SearchResult ;
sh:targetClass dcat:Catalog , skos:Concept , geo:Feature , geo:FeatureCollection , skos:Collection , prez:SearchResult , prez:CQLObjectList ;
altr-ext:hasDefaultProfile prez:OGCListingProfile
] , [
a sh:NodeShape ;
Expand All @@ -49,7 +49,7 @@ prez:OGCListingProfile
"text/turtle" ;
altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
altr-ext:constrainsClass dcat:Catalog , skos:Collection , geo:Feature , geo:FeatureCollection , skos:Concept ,
dcat:Resource , prof:Profile , prez:SearchResult ;
dcat:Resource , prof:Profile , prez:SearchResult , prez:CQLObjectList ;
sh:property [ sh:path rdf:type ]
.

Expand Down
31 changes: 4 additions & 27 deletions prez/reference_data/profiles/prez_default_profiles.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
.

<https://prez.dev/profile/open-object>
a prof:Profile ;
a prof:Profile , prez:ObjectProfile ;
dcterms:identifier "openobj"^^xsd:token ;
dcterms:description "An open profile for objects which will return all direct properties for a resource." ;
dcterms:title "Open profile" ;
Expand All @@ -50,7 +50,7 @@ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
.

<https://w3id.org/profile/mem>
a prof:Profile ;
a prof:Profile , prez:ListingProfile ;
dcterms:description "A very basic data model that lists the members of container objects only, i.e. not their other properties" ;
dcterms:identifier "mem"^^xsd:token ;
dcterms:title "Members" ;
Expand All @@ -71,7 +71,7 @@ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
.

altr-ext:alt-profile
a prof:Profile , sh:NodeShape ;
a prof:Profile , prez:ListingProfile , prez:ObjectProfile ;
dcterms:description "The representation of the resource that lists all other representations (profiles and Media Types)" ;
dcterms:identifier "alt"^^xsd:token ;
dcterms:title "Alternates Profile" ;
Expand All @@ -94,6 +94,7 @@ altr-ext:alt-profile
sh:property [
sh:path (
sh:union (
rdf:type
altr-ext:hasResourceFormat
altr-ext:hasDefaultResourceFormat
dcterms:description
Expand All @@ -103,27 +104,3 @@ altr-ext:alt-profile
)
] ;
.



<https://www.w3.org/TR/vocab-dcat/>
a prof:Profile , prez:CatPrezProfile ;
dcterms:description "Dataset Catalog Vocabulary (DCAT) is a W3C-authored RDF vocabulary designed to facilitate interoperability between data catalogs" ;
dcterms:identifier "dcat"^^xsd:token ;
dcterms:title "DCAT" ;
altr-ext:constrainsClass
dcat:Catalog ,
dcat:Dataset ,
dcat:Resource ,
prez:CatalogList ,
prez:ResourceList ;
altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
altr-ext:hasResourceFormat
"application/ld+json" ,
"application/rdf+xml" ,
"text/anot+turtle" ,
"text/turtle" ;
sh:property [
sh:path shext:allPredicateValues
] ;
.
1 change: 1 addition & 0 deletions prez/routers/cql.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ async def cql_get_endpoint(
request=request,
repo=repo,
system_repo=system_repo,
hierarchy_level=1,
endpoint_uri=endpoint_uri,
page=page,
per_page=per_page,
Expand Down
2 changes: 0 additions & 2 deletions prez/routers/ogc_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ async def collection_listing(
path_nodes={"path_node_1": IRI(value=path_node_1_uri)},
page=page,
per_page=per_page,
parent_uri=path_node_1_uri,
search_term=search_term,
)

Expand Down Expand Up @@ -104,7 +103,6 @@ async def item_listing(
},
page=page,
per_page=per_page,
parent_uri=path_node_1_uri,
search_term=search_term,
)

Expand Down
12 changes: 6 additions & 6 deletions prez/routers/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from rdflib import URIRef
from rdflib.namespace import Namespace

from prez.dependencies import get_repo
from prez.dependencies import get_repo, get_system_repo
from prez.reference_data.prez_ns import PREZ
from prez.repositories import Repo
from prez.services.listings import listing_function
Expand All @@ -24,15 +24,15 @@ async def search(
per_page: Optional[int] = 20,
search_term: Optional[str] = None,
repo: Repo = Depends(get_repo),
system_repo: Repo = Depends(get_repo),
system_repo: Repo = Depends(get_system_repo),
):
term = request.query_params.get("q")
endpoint_uri = URIRef(request.scope.get("route").name)
return await listing_function(
request,
repo,
system_repo,
endpoint_uri,
request=request,
repo=repo,
system_repo=system_repo,
endpoint_uri=endpoint_uri,
hierarchy_level=1,
page=page,
per_page=per_page,
Expand Down
1 change: 0 additions & 1 deletion prez/services/generate_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ async def get_profiles_and_mediatypes(
listing,
)
log.debug(f"ConnegP query: {query}")
# response = profiles_graph_cache.query(query)
response = await system_repo.send_queries([], [(None, query)])
# log.debug(f"ConnegP response:{results_pretty_printer(response)}")
if response[1][0][1] == []:
Expand Down
72 changes: 41 additions & 31 deletions prez/services/listings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from fastapi.responses import PlainTextResponse
from rdflib import URIRef, Literal
from rdflib.namespace import RDF, SH
from rdframe import CQLParser

from prez.cache import profiles_graph_cache, endpoints_graph_cache
from prez.config import settings
Expand All @@ -16,17 +15,18 @@
)
from prez.reference_data.prez_ns import PREZ
from prez.renderers.renderer import return_from_graph
from prez.repositories import Repo
from prez.services.link_generation import add_prez_links
from prez.services.query_generation.classes import get_classes
from prez.services.query_generation.count import CountQuery
from prez.repositories import Repo
from prez.services.query_generation.node_selection.endpoint_shacl import NodeShape
from prez.services.query_generation.node_selection.search import SearchQuery
from temp.grammar import *
from prez.services.query_generation.node_selection.cql import CQLParser

# from rdframe.grammar import SubSelect
# from rdframe import PrezQueryConstructor
from prez.services.query_generation.umbrella import PrezQueryConstructor
from prez.services.query_generation.node_selection.endpoint_shacl import NodeShape
from temp.grammar import *

log = logging.getLogger(__name__)

Expand All @@ -40,7 +40,6 @@ async def listing_function(
path_nodes: Dict[str, Var | IRI] = None,
page: int = 1,
per_page: int = 20,
parent_uri: Optional[URIRef] = None,
cql_parser: CQLParser = None,
search_term: Optional[str] = None,
endpoint_structure: Tuple[str] = settings.endpoint_structure,
Expand All @@ -52,19 +51,20 @@ async def listing_function(
# gather relevant info for the profile part of the query
# build the query
"""
if not path_nodes:
path_nodes = {}
queries = []
# determine possible SHACL node shapes for endpoint
node_selection_shape, target_classes = await determine_nodeshape(
endpoint_uri, hierarchy_level, parent_uri, path_nodes, repo, system_repo
ns_triples, ns_gpnt, target_classes = await get_shacl_node_selection(
endpoint_uri, hierarchy_level, path_nodes, repo, system_repo
)

if not path_nodes:
path_nodes = {}
if node_selection_shape:
ns = NodeShape(
uri=node_selection_shape, graph=endpoints_graph_cache, path_nodes=path_nodes
)

if not target_classes:
# then there is no target class - i.e. it's a search *only* or CQL *only* query (not SHACL + CQL or SHACL + Search)
if cql_parser:
target_classes = frozenset([PREZ.CQLObjectList])
elif search_term:
target_classes = frozenset([PREZ.SearchResult])
# determine the relevant profile
prof_and_mt_info = ProfilesMediatypesInfo(
request=request, classes=target_classes, system_repo=system_repo, listing=True
Expand All @@ -79,6 +79,13 @@ async def listing_function(
if prof_and_mt_info.profile == URIRef(
"http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"
):
ns = NodeShape(
uri=URIRef("http://example.org/ns#AltProfilesForListing"),
graph=endpoints_graph_cache,
path_nodes={"path_node_1": IRI(value=prof_and_mt_info.selected_class)}
)
ns_triples = ns.triples_list
ns_gpnt = ns.gpnt_list
endpoint_uri = URIRef("https://prez.dev/endpoint/system/alt-profiles-listing")
runtime_values["selectedClass"] = prof_and_mt_info.selected_class

Expand Down Expand Up @@ -108,8 +115,8 @@ async def listing_function(
listing_or_object="listing",
endpoint_uri=endpoint_uri,
profile_uri=selected_profile,
endpoint_shacl_triples=ns.triples_list,
endpoint_shacl_gpnt=ns.gpnt_list,
endpoint_shacl_triples=ns_triples,
endpoint_shacl_gpnt=ns_gpnt,
cql_triples=cql_triples_list,
cql_gpnt=cql_gpnt_list,
)
Expand Down Expand Up @@ -137,25 +144,15 @@ async def listing_function(
# add a count query if it's an annotated mediatype
if "anot+" in prof_and_mt_info.mediatype and not search_term:
subselect = copy.deepcopy(query_constructor.inner_select)
subselect.solution_modifier = None # remove the limit and offset from the subselect so that we can get a count
count_query = CountQuery(subselect=subselect).render()
queries.append(count_query)

# if prof_and_mt_info.profile == URIRef(
# "http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"
# ):
# count_class = PROF.Profile
# else:
# count_class = target_classes
# if count_class: # target_class may be unknown (None) for queries involving CQL
# queries.append(temp_listing_count(subselect, count_class))

if prof_and_mt_info.profile == URIRef(
"http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"
):
item_graph, _ = await system_repo.send_queries(queries, [])
if "anot+" in prof_and_mt_info.mediatype:
await add_prez_links(item_graph, system_repo, endpoint_structure)
await add_prez_links(item_graph, system_repo, endpoint_structure=("profiles",))
else:
item_graph, _ = await repo.send_queries(queries, [])
if "anot+" in prof_and_mt_info.mediatype:
Expand All @@ -174,9 +171,12 @@ async def listing_function(
)


async def determine_nodeshape(
endpoint_uri, hierarchy_level, parent_uri, path_nodes, repo, system_repo
async def get_shacl_node_selection(
endpoint_uri, hierarchy_level, path_nodes, repo, system_repo
):
"""
Determines the relevant nodeshape based on the endpoint, hierarchy level, and parent URI
"""
node_selection_shape = None
target_classes = []
relevant_ns_query = f"""SELECT ?ns ?tc
Expand All @@ -185,7 +185,7 @@ async def determine_nodeshape(
?ns <http://www.w3.org/ns/shacl#targetClass> ?tc ;
<https://prez.dev/ont/hierarchyLevel> {hierarchy_level} .
}}"""
_, r = await system_repo.send_queries([], [(parent_uri, relevant_ns_query)])
_, r = await system_repo.send_queries([], [(None, relevant_ns_query)])
tabular_results = r[0][1]
distinct_ns = set([result["ns"]["value"] for result in tabular_results])
if len(distinct_ns) == 1: # only one possible node shape
Expand Down Expand Up @@ -219,7 +219,17 @@ async def determine_nodeshape(
target_classes = list(
endpoints_graph_cache.objects(node_selection_shape, SH.targetClass)
)
return node_selection_shape, target_classes
ns_triples = []
ns_gpnt = []
if not path_nodes:
path_nodes = {}
if node_selection_shape:
ns = NodeShape(
uri=node_selection_shape, graph=endpoints_graph_cache, path_nodes=path_nodes
)
ns_triples = ns.triples_list
ns_gpnt = ns.gpnt_list
return ns_triples, ns_gpnt, target_classes


def find_instances(obj, cls):
Expand Down
Loading

0 comments on commit 75c285d

Please sign in to comment.