Skip to content

Commit

Permalink
Added method to get context from model or store and another to expand…
Browse files Browse the repository at this point in the history
… a url using a context
  • Loading branch information
crisely09 committed Jul 4, 2023
1 parent 8c13274 commit 985f105
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}
encodingFormat: x._mediaType
name: x._filename
contentUrl: x._self
contentUrl: forge.expand_url(x.id)
atLocation:
{
type: Location
Expand Down
8 changes: 8 additions & 0 deletions kgforge/core/archetypes/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,14 @@ def _debug_query(query):
else:
print(*["Submitted query:", *query.splitlines()], sep="\n ")
print()

def expand_url(self, url: str, context: Context, is_file: bool, encoding: str) -> str:
"""Expand a given url using the store or model context
:param url: the idenfitier to be transformed
:param context: a Context object with vocabulary to be used in the construction of the URI
"""
pass


def _replace_in_sparql(qr, what, value, default_value, search_regex, replace_if_in_query=True):
Expand Down
28 changes: 23 additions & 5 deletions kgforge/core/forge.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

import re
import numpy as np
import yaml
from kgforge.core.commons.files import load_file_as_byte
from pandas import DataFrame
from rdflib import Graph
from urllib.parse import quote_plus, urlparse

from kgforge.core import Resource
from kgforge.core.archetypes import Mapping, Model, Resolver, Store
from kgforge.core.commons.context import Context
from kgforge.core.commons.actions import LazyAction
from kgforge.core.commons.dictionaries import with_defaults
from kgforge.core.commons.exceptions import ResolvingError
Expand Down Expand Up @@ -215,7 +218,6 @@ def __init__(self, configuration: Union[str, Dict], **kwargs) -> None:
self._model: Model = model(**model_config)

# Store.

store_config.update(model_context=self._model.context())
store_name = store_config.pop("name")
store = import_class(store_name, "stores")
Expand All @@ -234,8 +236,6 @@ def __init__(self, configuration: Union[str, Dict], **kwargs) -> None:
# Formatters.
self._formatters: Optional[Dict[str, str]] = config.pop("Formatters", None)

# Modeling User Interface.

@catch
def prefixes(self, pretty: bool = True) -> Optional[Dict[str, str]]:
"""
Expand Down Expand Up @@ -744,7 +744,6 @@ def as_json(
self._model.resolve_context,
)

@catch
@catch
def as_jsonld(
self,
Expand Down Expand Up @@ -880,7 +879,26 @@ def from_dataframe(
:return: Union[Resource, List[Resource]]
"""
return from_dataframe(data, na, nesting)


def get_context(self, origin : str ="model"):
"""Expose the context used in the model or in the store."""
if origin == "model":
return self._model.context()
elif origin == "store":
return self._store.context

def expand_url(self, url: str, context: Context = None,
is_file: bool = True, encoding: str = None):
"""
Construct an URI a given an id using the vocabulary given in the Context object.
:param url: the url to transform
:param context: a Context object that should be used to create the URI
:param encode: parameter to use to encode or not the uri, default is `utf-8`
"""
if context is None:
context = self.get_context("store")
return self._store.expand_url(url, context, is_file, encoding)

def prepare_resolvers(
config: Dict, store_config: Dict
Expand Down
27 changes: 27 additions & 0 deletions kgforge/specializations/stores/bluebrain_nexus.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,33 @@ def _initialize_service(
files_download_config=files_download_config,
**params,
)

def expand_url(self, url: str, context: Context, is_file, encoding):
# try decoding the url first
raw_url = unquote(url)
if is_file: # for files
url_base = '/'.join([self.endpoint, 'files', self.bucket])
else: # for resources
url_base = '/'.join([self.endpoint, 'resources', self.bucket])
matches = re.match(r"[\w\.:%/-]+/(\w+):(\w+)/[\w\.-/:%]+", raw_url)
if matches:
groups = matches.groups()
old_schema = f"{groups[0]}:{groups[1]}"
resolved = context.resolve(groups[0])
if raw_url.startswith(url_base):
print('I am here', resolved)
extended_schema = '/'.join([quote_plus(resolved), groups[1]])
url = raw_url.replace(old_schema, extended_schema)
return url
else:
extended_schema = '/'.join([resolved, groups[1]])
url = raw_url.replace(old_schema, extended_schema)
else:
url = raw_url
if url.startswith(url_base):
return url
uri = "/".join((url_base, quote_plus(url, encoding=encoding)))
return uri


def _error_message(error: HTTPError) -> str:
Expand Down
3 changes: 3 additions & 0 deletions kgforge/specializations/stores/demo_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ def _archive_id(rid: str, version: int) -> str:
@staticmethod
def _tag_id(rid: str, tag: str) -> str:
return f"{rid}_tag={tag}"

def expand_url(self, url: str, context: Context, is_file: bool, encoding: str) -> str:
return url

class RecordExists(Exception):
pass
Expand Down
5 changes: 3 additions & 2 deletions kgforge/specializations/stores/nexus/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ def __init__(
files_download_config: Dict,
**params,
):

nexus.config.set_environment(endpoint)
self.endpoint = endpoint
self.organisation = org
Expand Down Expand Up @@ -241,7 +240,9 @@ def __init__(

def get_project_context(self) -> Dict:
project_data = nexus.projects.fetch(self.organisation, self.project)
context = {"@base": project_data["base"], "@vocab": project_data["vocab"]}
print('api mappings', project_data['apiMappings'])
context = {"@base": project_data["base"], "@vocab": project_data["vocab"],
"api_mappings": project_data["apiMappings"]}
return context

def resolve_context(self, iri: str, local_only: Optional[bool] = False) -> Dict:
Expand Down
38 changes: 34 additions & 4 deletions tests/specializations/stores/test_bluebrain_nexus.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,19 @@
from urllib.parse import urljoin
from urllib.request import pathname2url
from uuid import uuid4
from kgforge.core.commons.sparql_query_builder import SPARQLQueryBuilder

import nexussdk
import pytest
from typing import Callable, Union, List
from collections import OrderedDict

from kgforge.core import Resource
from kgforge.core.archetypes import Store
from kgforge.core.commons.context import Context
from kgforge.core.conversions.rdf import _merge_jsonld
from kgforge.core.wrappings.dict import wrap_dict
from kgforge.core.wrappings.paths import Filter, create_filters_from_dict
from kgforge.core.commons.sparql_query_builder import SPARQLQueryBuilder
from kgforge.specializations.stores.bluebrain_nexus import (
BlueBrainNexus,
_create_select_query,
Expand All @@ -40,10 +41,10 @@
from kgforge.specializations.stores.nexus import Service

BUCKET = "test/kgforge"
NEXUS = "https://nexus-instance.org/"
NEXUS = "https://nexus-instance.org"
TOKEN = "token"
NEXUS_PROJECT_CONTEXT = {"base": "http://data.net/", "vocab": "http://vocab.net/"}

NEXUS_PROJECT_CONTEXT = {"base": "http://data.net", "vocab": "http://vocab.net",
"apiMappings": [{'namespace': 'https://neuroshapes.org/dash/', 'prefix': 'datashapes'}]}
VERSIONED_TEMPLATE = "{x.id}?rev={x._store_metadata._rev}"
FILE_RESOURCE_MAPPING = os.sep.join(
(os.path.curdir, "tests", "data", "nexus-store", "file-to-resource-mapping.hjson")
Expand Down Expand Up @@ -130,6 +131,11 @@ def nexus_store_unauthorized():
return BlueBrainNexus(endpoint=NEXUS, bucket=BUCKET, token="invalid token")


@pytest.fixture
def nexus_context():
return Context(NEXUS_PROJECT_CONTEXT)


def test_config_error():
with pytest.raises(ValueError):
BlueBrainNexus(endpoint="test", bucket="invalid", token="")
Expand Down Expand Up @@ -165,6 +171,30 @@ def test_to_resource(nexus_store, registered_building, building_jsonld):
assert str(result._store_metadata) == str(registered_building._store_metadata)


@pytest.mark.parametrize("url,expected",
[
pytest.param(
("myverycoolid123456789"),
("https://nexus-instance.org/files/test/kgforge/myverycoolid123456789"),
id="simple-id",
),
pytest.param(
("https://nexus-instance.org/files/test/kgforge/myverycoolid123456789"),
("https://nexus-instance.org/files/test/kgforge/myverycoolid123456789"),
id="same-id",
),
# pytest.param(
# ("https://nexus-instance.org/files/test/kgforge/datashapes:example/myverycoolid123456789"),
# ("https://nexus-instance.org/files/test/kgforge/https%3A%2F%2Fbbp.epfl.ch%2Fneurosciencegraph%2Fdata%2Fdatashapes/example/myverycoolid123456789"),
# id="schema-id",
# ),
])
def test_expand_url(nexus_store, nexus_context, url, expected):
uri = nexus_store.expand_url(url, context=nexus_context, is_file=True, encoding=None)
print(uri)
assert expected == uri


class TestQuerying:
@pytest.fixture
def context(self):
Expand Down

0 comments on commit 985f105

Please sign in to comment.