Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1f421da
Add frontend for PKG population
NoB0 Nov 23, 2023
125a8e0
Add backend for population management
NoB0 Dec 12, 2023
f88b56b
Initial view with population form
NoB0 Dec 19, 2023
51a7038
Fix mypy issues
NoB0 Jan 9, 2024
dba14b2
Merge branch 'main' into feature/38-pkg-population-backend
NoB0 Jan 9, 2024
bdd615a
Fix tests
NoB0 Jan 9, 2024
5ca9d81
Black
NoB0 Jan 9, 2024
18d7990
Update CI pipeline
NoB0 Jan 12, 2024
3100850
Undo CI changes
NoB0 Jan 12, 2024
e3f158d
Merge branch 'main' into feature/add-population-frontend
NoB0 Jan 17, 2024
158709a
Update form based on new vocabulary
NoB0 Jan 17, 2024
13d3b9b
Formatting
NoB0 Jan 17, 2024
33d48cd
Merge branch 'main' into feature/38-pkg-population-backend
NoB0 Jan 17, 2024
5c248ca
Add Flask configurations
NoB0 Jan 17, 2024
c669028
Merge branch 'main' into feature/38-pkg-population-backend
NoB0 Feb 11, 2024
6139bf0
Merge branch 'main' into feature/add-population-frontend
NoB0 Feb 11, 2024
00c43f5
Update forms for PKG population
NoB0 Feb 11, 2024
eb36aa2
Remove useEffect
NoB0 Feb 11, 2024
cf1db27
Merge branch 'feature/add-population-frontend' into feature/38-pkg-po…
NoB0 Feb 11, 2024
121becd
Implement endpoint for statement management
NoB0 Feb 12, 2024
512f4d4
Update Concept interface
NoB0 Feb 12, 2024
93304fa
Merge branch 'feature/add-population-frontend' into feature/38-pkg-po…
NoB0 Feb 12, 2024
cedc27f
Remove preference form
NoB0 Feb 12, 2024
dad0ef3
Update parsing of request data
NoB0 Feb 13, 2024
38a6ee4
Remove unrelated files
NoB0 Feb 13, 2024
ed2ca6a
Fixes #104
NoB0 Feb 13, 2024
f50ab52
Add tests for statement management
NoB0 Feb 13, 2024
09fa0a5
Merge branch 'main' into feature/38-pkg-population-backend
NoB0 Mar 6, 2024
8c4faea
Update imports
NoB0 Mar 6, 2024
ac488e6
Remove changes related to frontend
NoB0 Mar 6, 2024
0278738
Uncomment code related to statement deletion
NoB0 Mar 6, 2024
2bf9654
Add test for delete
NoB0 Mar 6, 2024
5f15c71
Address review comments
NoB0 Mar 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ on:
env:
REPO_NAME: ${{ github.event.repository.name }}


jobs:
pre-commit:
if: always()
Expand Down Expand Up @@ -98,16 +97,15 @@ jobs:
pip install --upgrade pip
pip install -r requirements.txt
pip install pytest-github-actions-annotate-failures

- name: Install graphviz
uses: tlylt/install-graphviz@v1


- name: PyTest with code coverage
continue-on-error: true
run: |
pytest --junitxml pytest.xml --cov=. --cov-report=term-missing --cov-report=xml --cov-branch | tee pytest-coverage.txt

- name: Upload Coverage Results txt
if: always()
uses: actions/upload-artifact@v3
Expand Down
3 changes: 2 additions & 1 deletion pkg_api/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
from enum import Enum

from rdflib import Graph
from rdflib import Graph, Namespace
from rdflib.query import Result

from pkg_api.core.namespaces import PKGPrefixes
Expand All @@ -12,6 +12,7 @@
# Method to execute the SPARQL query

DEFAULT_STORE_PATH = "data/RDFStore"
DEFAULT_PKG_NAMESPACE = Namespace("http://example.com/pkg")


class RDFStore(Enum):
Expand Down
8 changes: 4 additions & 4 deletions pkg_api/server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@
from pkg_api.connector import DEFAULT_STORE_PATH
from pkg_api.pkg import DEFAULT_VISUALIZATION_PATH
from pkg_api.server.auth import AuthResource
from pkg_api.server.facts_management import PersonalFactsResource
from pkg_api.server.models import db
from pkg_api.server.nl_processing import NLResource
from pkg_api.server.pkg_exploration import PKGExplorationResource
from pkg_api.server.service_management import ServiceManagementResource
from pkg_api.server.statements_management import StatementsManagementResource


def create_app(testing: bool = False) -> Flask:
"""Create the Flask app and add the API resources.
"""Creates the Flask app and add the API resources.

Args:
testing: Enable testing mode. Defaults to False.

Returns:
The Flask app.
Flask app.
"""
app = Flask(__name__)

Expand All @@ -47,7 +47,7 @@ def create_app(testing: bool = False) -> Flask:

api.add_resource(AuthResource, "/auth")
api.add_resource(ServiceManagementResource, "/service")
api.add_resource(PersonalFactsResource, "/facts")
api.add_resource(StatementsManagementResource, "/statements")
api.add_resource(PKGExplorationResource, "/explore")
api.add_resource(NLResource, "/nl")

Expand Down
10 changes: 0 additions & 10 deletions pkg_api/server/facts_management.py

This file was deleted.

9 changes: 5 additions & 4 deletions pkg_api/server/pkg_exploration.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""PKG Exploration Resource."""

from typing import Any, Dict, Tuple

from flask import request
Expand All @@ -17,8 +18,8 @@ def get(self) -> Tuple[Dict[str, Any], int]:
data = request.json
try:
pkg = open_pkg(data)
except Exception as e:
return {"message": str(e)}, 400
except KeyError as e:
return {"message": e.args[0]}, 400

graph_img_path = pkg.visualize_graph()
pkg.close()
Expand All @@ -38,8 +39,8 @@ def post(self) -> Tuple[Dict[str, Any], int]:
data = request.json
try:
pkg = open_pkg(data)
except Exception as e:
return {"message": str(e)}, 400
except KeyError as e:
return {"message": e.args[0]}, 400

sparql_query = parse_query_request_data(data)

Expand Down
63 changes: 63 additions & 0 deletions pkg_api/server/statements_management.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Statements Management API Resource."""

from typing import Dict, Tuple

from flask import request
from flask_restful import Resource

from pkg_api.server.utils import (
open_pkg,
parse_query_statement_population_data,
)


class StatementsManagementResource(Resource):
def post(self) -> Tuple[Dict[str, str], int]:
"""Adds a statement to the PKG.

Raises:
KeyError: if there is missing information to open the user's PKG,
or if the statement is missing.

Returns:
A dictionary containing a message and the status code.
"""
data = request.json
try:
pkg = open_pkg(data)
except KeyError as e:
return {"message": e.args[0]}, 400

try:
pkg_data = parse_query_statement_population_data(data)
pkg.add_statement(pkg_data)
pkg.close()
except KeyError as e:
return {"message": e.args[0]}, 400

return {"message": "Statement added successfully"}, 200

def delete(self) -> Tuple[Dict[str, str], int]:
"""Deletes a statement from the PKG.

Raises:
KeyError: if there is missing information to open the user's PKG, or
if the statement is missing.

Returns:
A dictionary containing a message and the status code.
"""
data = request.json
try:
pkg = open_pkg(data)
except KeyError as e:
return {"message": e.args[0]}, 400

try:
pkg_data = parse_query_statement_population_data(data)
pkg.remove_statement(pkg_data)
pkg.close()
except KeyError as e:
return {"message": e.args[0]}, 400

return {"message": "Statement removed successfully"}, 200
82 changes: 79 additions & 3 deletions pkg_api/server/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
"""Utility functions for the server."""
from typing import Any, Dict

import uuid
from typing import Any, Dict, Union

from flask import current_app

from pkg_api.connector import RDFStore
from pkg_api.core.pkg_types import URI
from pkg_api.core.pkg_types import (
URI,
Concept,
PKGData,
Preference,
Triple,
TripleElement,
)
from pkg_api.pkg import PKG


Expand All @@ -14,13 +23,16 @@ def open_pkg(data: Dict[str, str]) -> PKG:
Args:
data: Request data.

Raises:
KeyError: If the owner URI is missing.

Returns:
A PKG instance.
"""
owner_uri = data.get("owner_uri", None)
owner_username = data.get("owner_username", None)
if owner_uri is None:
raise Exception("Missing owner URI")
raise KeyError("Missing owner URI")

store_path = current_app.config["STORE_PATH"]
visualization_path = current_app.config["VISUALIZATION_PATH"]
Expand All @@ -43,3 +55,67 @@ def parse_query_request_data(data: Dict[str, Any]) -> str:
A string containing SPARQL query.
"""
return data.get("sparql_query", None)


def _parse_triple_element(
element_data: Union[Dict[str, Any], str]
) -> TripleElement:
"""Parses a triple element received from HTTP request.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raises block missing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method does not raise any exception.

Args:
element_data: Data sent with HTTP request.

Returns:
Triple element.
"""
if element_data is not None:
value = (
element_data
if isinstance(element_data, str)
else element_data.get("value")
)
if isinstance(value, dict):
return TripleElement(value.get("description"), Concept(**value))
elif isinstance(value, str):
try:
return TripleElement(value, URI(value))
except Exception:
return TripleElement(value, None)

return None


def parse_query_statement_population_data(data: Dict[str, Any]) -> PKGData:
"""Parses the request data to execute SPARQL query.

Raises:
KeyError: If there is no natural language statement description.

Args:
data: Request data.

Returns:
Associated PKGData.
"""
description = data.get("description", None)
if description is None:
raise KeyError("Missing description")

# Parse triple elements
subject = _parse_triple_element(data.get("subject", None))
predicate = _parse_triple_element(data.get("predicate", None))
statement_object = _parse_triple_element(data.get("object", None))

# Parse preference
preference = data.get("preference", None)
if preference and -1.0 <= preference <= 1.0:
preference = Preference(statement_object, preference)
else:
preference = None

return PKGData(
id=uuid.uuid1(),
statement=description,
triple=Triple(subject, predicate, statement_object),
preference=preference,
)
5 changes: 5 additions & 0 deletions tests/pkg_api/server/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Fixtures for the pkg_api.server package."""

import os

import pytest
Expand All @@ -19,3 +20,7 @@ def client() -> Flask:
yield client
# Delete the test database
os.remove(f"{app.instance_path}/test.sqlite")
# Delete turtle files
for file in os.listdir(f"{app.config['STORE_PATH']}"):
if file.endswith(".ttl"):
os.remove(f"{app.config['STORE_PATH']}/{file}")
10 changes: 0 additions & 10 deletions tests/pkg_api/server/test_facts_management.py

This file was deleted.

Loading