瀏覽代碼

Merge branch 'release-0.2.0'

Arkadiusz Ryś 3 年之前
父節點
當前提交
a21c2306d6

+ 2 - 2
.editorconfig

@@ -8,10 +8,10 @@ indent_style = space
 insert_final_newline = true
 trim_trailing_whitespace = true
 
-[*.{css, html, yml, yaml, js, xml}]
+[*.{css,html,yml,yaml,js,xml}]
 indent_size = 2
 
-[{*.log, LICENSE}]
+[{*.log,LICENSE}]
 insert_final_newline = false
 
 [*.rst]

+ 0 - 2
.gitlab-ci.yml

@@ -53,7 +53,6 @@ build-windows-exe:
   stage: build
   before_script:
     - echo "Building windows executable"
-    - apt install -qy zip tree
   script:
     - xvfb-run sh -c "wine python.exe -m pip install --upgrade pip; wineserver -w"
     - xvfb-run sh -c "wine python.exe -m pip install --no-warn-script-location -r requirements.txt; wineserver -w"
@@ -61,7 +60,6 @@ build-windows-exe:
 #    - xvfb-run sh -c "wine pyinstaller graph_exploring_tool/__main__.py --name get.exe --paths=graph_exploring_tool --noconfirm; wineserver -w"
     - xvfb-run sh -c "wine pyinstaller graph_exploring_tool/__main__.py --name get.exe --paths=graph_exploring_tool --windowed --noconfirm; wineserver -w"
     - ls -la dist
-    - tree dist
     - mv dist/get.exe/* ./
   after_script:
     - rm -rf build # excluding build from artifacts doesn't work because of untracked being set to true

+ 5 - 0
HISTORY.rst

@@ -2,6 +2,11 @@
 History
 =======
 
+0.2.0 (2023-07-18)
+------------------
+* Improve default palette templates.
+* Add invalid query status text.
+
 0.1.0 (2023-05-05)
 ------------------
 * Release bundled windows exe.

+ 106 - 10
README.rst

@@ -6,14 +6,39 @@ Graph Exploring Tool
    :alt: Screenshot of the user interface
 
 Virtual Knowledge Graph exploration tool built for use with a graph based on the FTG+PM concept.
+We add prefix translation for general concepts and the `SDO2L vocabulary <https://msdl.uantwerpen.be/git/lucasalbertins/DTDesign/src/joeri/examples/oml/SystemDesignOntology2Layers>`_.
+The translated prefixes can be extended:
+
+.. code-block:: toml
+
+   # Functions and services
+   [[prefixes]]
+   name = "dtf"
+   ...
+   [[prefixes]]
+   name = "traceability_model"
+   namespace = "http://ua.be/sdo2l/vocabulary/formalisms/traceability_model#"
+   [[prefixes]]
+   name = "xopp"
+   namespace = "http://ua.be/sdo2l/vocabulary/formalisms/xopp#"
+   [[prefixes]]
+   name = "federation"
+   namespace = "http://ua.be/sdo2l/vocabulary/federation#"
+
+The `Modifying settings`_ section goes into more detail on this file.
 
+Why?
+----
+
+This tool allows a user to explore the knowledge graph using predefined SPARQL queries.
+Therefore, SPARQL knowledge requirements are minimized while still allowing service invoking and data extraction.
 
 Installation
 ------------
 
-If you are on Windows you can download the binary at URL and run it by double-clicking it.
+If you are on Windows, you can download the binary at URL and run it by double-clicking it.
 
-We also provide the option to install the package from a repository. If this is your prefered method please follow along.
+We also provide the option to install the package from a repository. If this is your preferred method, please follow along.
 
 ..
    .. code-block:: shell
@@ -30,7 +55,7 @@ We also provide the option to install the package from a repository. If this is
 .. role:: bash(code)
    :language: bash
 
-To run the application you can use :bash:`python3 -m graph-exploring-tool`.
+To run the application, you can use :bash:`python3 -m graph-exploring-tool`.
 
 For WSL check out: https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps
 
@@ -62,7 +87,7 @@ The tool separates actions into multiple panels.
 1. The left Query Palette panel **(red)** allows you to load a predefined template. Hovering over the name of the template will provide a tooltip with the description of the action carried out by that template.
 2. The center and main Query Editor panel **(green)** is where the template is shown once it has been chosen. You can change the template itself or use the provided fields **(blue)** to insert references into the template itself.
    The reference fields support dragging and dropping.
-   To perform the query you need to click the Query button.
+   To perform the query, you need to click the Query button.
 3. The small one line panel **(yellow)** show the status. This includes messages whether a query was successful. Any error will also be displayed right here.
 4. The most important panel is the Results panel **(orange)**. Any information returned by the query will be displayed here.
    You can drag and drop any of the fields in the result onto the parameters fields in the template.
@@ -74,17 +99,88 @@ Workflow
 We propose a simple workflow:
 You open up the FTGPM++ (workflow diagram) and look at what is of interest to you.
 Let's say you are interested in finding all the individuals (or instances) of a certain type.
-You look at the Query Palette panel. You see the first options which is what you need.
+You look at the Query Palette panel. You see the first option, which is what you need.
 Now you click on this (Find Individuals) button. Here you see that you need to specify two parameters.
 
 - We need to know what class the individuals you're looking for belong to and perhaps a relation to another individual.
 
-The example assumes you want to find all Formalisms and their name.
-At this point you can execute the query by clicking the Query button.
+The example assumes you want to find all `Formalisms` and their name.
+At this point, you can execute the query by clicking the Query button.
 The list of corresponding individuals will now be visible in the Results panel.
 You can now use these results to further query the graph.
 
-Why?
-----
+Outlier detection workflow demo
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To give a concrete example, we follow a workflow for figuring out outliers in a CSV file created during the `enactment process <https://msdl.uantwerpen.be/git/lucasalbertins/wee/wiki/Basic+Tutorial>`_.
+You start by opening the GUI.
+You can then double-check the settings, like the endpoint.
+If all settings are correct, you can proceed by choosing the `Outlier Function` in the `Query Palette`.
+
+The `Visual Query Editor` will now have the following `Query` pre-set for you.
+
+.. code-block:: sql
+
+   SELECT ?outlier ?outlier_relation ?outlier_value WHERE {
+     SERVICE <{{ service_endpoint }}> {
+       SELECT ?outlier ?outlier_relation ?outlier_value WHERE {
+         BIND(dtf:outlier("{{ outlier_file }}", "{{ outlier_column }}", "{{ outlier_artifact }}") AS ?outlier)
+       }
+     }
+   }
+
+You don't need to understand the SPARQL query itself. What you are likely interested in are the fields below the `Query`.
+
+- `http://127.0.0.1:8000/`
+- `rotation.csv`
+- `2`
+- `<http://ua.be/drivetrain/description/artifacts/artifacts#drivetrain-sensor-data-v1>`
+
+They are, in sequential order, the service, the file, the column, and the artifact URI.
+The first field, `http://127.0.0.1:8000/`, is the `URI to a (in this case local) service for outliers <https://msdl.uantwerpen.be/git/arys/spendpoint>`_ we provide.
+
+Once you're satisfied with the fields you filled in you can gently press the `Query` button.
+You should be greeted by a results resembling the following image.
+
+.. |results| image:: docs/results.png
+   :alt: Screenshot including the results of an outlier query
+   :width: 100%
+
+Congratulations! You have successfully performed outlier detection on the enactment artifact.
+
+Advanced usage
+--------------
+
+.. _Modifying settings:
+Modifying settings
+~~~~~~~~~~~~~~~~~~
+
+All settings are stored in the :bash:`data/configuration.toml` file.
+There isn't much of value for an end user to change.
+The 4 settings available are:
+
+- The :bash:`endpoint_sparql`: where to send the queries.
+- The :bash:`example_prefix`: the initial prefix shown in the interface.
+- The :bash:`example_query`: the initial query shown in the interface.
+- A list of :bash:`prefixes` which have a :bash:`name` and :bash:`namespace`: these are used for simplifying queries.
+
+Adding templates
+~~~~~~~~~~~~~~~~
+
+You can add more templates by creating a :bash:`.toml` file under :bash:`data/palette/`.
+Each template has required fields.
+
+- A :bash:`group`: What group this template belongs to in the palette panel.
+- The :bash:`name`: A short identifier for the template.
+- The :bash:`prefix` list: A string containing the full prefix for the query.
+- The :bash:`query` template: The query itself. Placeholder can be defined between double curly brackets.
+- The :bash:`description`: A longer description for the template, which will be shown as the tooltip.
+- Whether :bash:`visual_support` is enabled: Deprecated. Always true.
+- A list of :bash:`replacements` each having 3 fields: One needs to be defined for each placeholder in the query.
+
+  - The :bash:`placeholder`: Which placeholder gets replaced.
+  - The :bash:`suggestion`: The initial value of the replacement.
+  - The :bash:`description`: What should be put in the field.
 
-TODO Explain what problem is solved.
+You need to restart the interface after you create a new file.
+The new template will now be available as a choice in the palette panel.

+ 70 - 26
data/configuration.toml

@@ -1,6 +1,9 @@
-endpoint_sparql = "http://127.0.0.1:3030/Drivetrain/sparql" # Fuseki SPARQL endpoint for the drivetrain
-#endpoint_sparql = "http://127.0.0.1:8000/"
-#endpoint_sparql = "https://fuseki.rys.app/example/"
+#endpoint_sparql = "http://127.0.0.1:3030/SystemDesignOntology2Layers/sparql" # Fuseki SPARQL endpoint for the drivetrain
+endpoint_sparql = "https://fuseki.rys.app/SystemDesignOntology2Layers/" # Fuseki SPARQL endpoint for the drivetrain
+#endpoint_sparql = "http://127.0.0.1:3030/Drivetrain/sparql" # Fuseki SPARQL endpoint for the drivetrain
+#endpoint_sparql = "http://127.0.0.1:8000/" # Fuseki SPARQL endpoint (default spendpoint dev uri)
+#endpoint_sparql = "https://fuseki.rys.app/example/" # Deployement endpoint
+
 example_prefix = '''
 PREFIX xsd:  <http://www.w3.org/2001/XMLSchema#>
 PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
@@ -41,46 +44,87 @@ namespace = "http://purl.org/dc/elements/1.1/"
 [[prefixes]]
 name = "vim4"
 namespace = "http://bipm.org/jcgm/vim4#"
+[[prefixes]]
+name = "swrl"
+namespace = "http://www.w3.org/2003/11/swrl#"
 # Digital Twin Design
 [[prefixes]]
-name = "art"
+name = "artifacts_ftg"
+namespace = "http://ua.be/sdo2l/description/artifacts/FTG_ftg#"
+## Drivetrain
+[[prefixes]]
+name = "dart"
 namespace = "http://ua.be/drivetrain/description/artifacts/artifacts#"
 [[prefixes]]
-name = "tabular"
-namespace = "http://ua.be/sdo2l/vocabulary/base/tabular#"
+name = "dftg"
+namespace = "http://ua.be/drivetrain/description/ftg#"
+## SDO2L
 [[prefixes]]
-name = "ftg"
-namespace = "http://ua.be/sdo2l/vocabulary/ftg#"
+name = "acyclic"
+namespace = "http://ua.be/sdo2l/vocabulary/base/acyclic#"
 [[prefixes]]
 name = "base"
-namespace = "http://ua.be/sdo2l/vocabulary/base#"
+namespace = "http://ua.be/sdo2l/vocabulary/base/base#"
+[[prefixes]]
+name = "file"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/file#"
+[[prefixes]]
+name = "ftg"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/ftg#"
+[[prefixes]]
+name = "traces"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/processtraces#"
+[[prefixes]]
+name = "shaclproperty"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/shaclproperty#"
+[[prefixes]]
+name = "system"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/system#"
 [[prefixes]]
-name = "comp"
-namespace = "http://ua.be/sdo2l/vocabulary/component#"
+name = "violation"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/violation#"
 [[prefixes]]
 name = "code"
-namespace = "http://ua.be/sdo2l/vocabulary/base/code#"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/code#"
 [[prefixes]]
-name = "script"
-namespace = "http://ua.be/sdo2l/vocabulary/base/script#"
+name = "component"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/component#"
 [[prefixes]]
-name = "file"
-namespace = "http://ua.be/sdo2l/vocabulary/base/file#"
+name = "csas"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/cs_as#"
 [[prefixes]]
-name = "swrl"
-namespace = "http://www.w3.org/2003/11/swrl#"
+name = "dict"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/dict#"
 [[prefixes]]
-name = "traces"
-namespace = "http://ua.be/sdo2l/vocabulary/processtraces#"
+name = "drawio"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/drawio#"
 [[prefixes]]
-name = "wf"
-namespace = "http://ua.be/sdo2l/vocabulary/workflow#"
+name = "object_diagram"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/object_diagram#"
+[[prefixes]]
+name = "pm"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/pm#"
+[[prefixes]]
+name = "requirement"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/requirement#"
+[[prefixes]]
+name = "richtext"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/richtext#"
+[[prefixes]]
+name = "script"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/script#"
+[[prefixes]]
+name = "tabular"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/tabular#"
 [[prefixes]]
 name = "text"
-namespace = "http://ua.be/sdo2l/vocabulary/base/text#"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/text#"
+[[prefixes]]
+name = "traceability_model"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/traceability_model#"
+[[prefixes]]
+name = "xopp"
+namespace = "http://ua.be/sdo2l/vocabulary/formalisms/xopp#"
 [[prefixes]]
 name = "federation"
 namespace = "http://ua.be/sdo2l/vocabulary/federation#"
-[[prefixes]]
-name = "dftg"
-namespace = "http://ua.be/drivetrain/description/ftg#"

+ 2 - 2
data/palette/find_class_property.toml

@@ -48,6 +48,6 @@ description = "Find all the classes using a property."
 visual_support = true
 
 [[replacements]]
-placeholder = "Property"
-suggestion  = "base:hasName"
+placeholder = "class"
+suggestion  = "ftg:hasName"
 description = "Which property do the classes need to have?"

+ 1 - 1
data/palette/find_individuals.toml

@@ -54,5 +54,5 @@ description = "What class of individual are you looking for?"
 
 [[replacements]]
 placeholder = "relation"
-suggestion  = "base:hasName"
+suggestion  = "rdf:type"
 description = "What is the relation you are looking for?"

+ 4 - 3
data/palette/find_older_versions.toml

@@ -39,8 +39,9 @@ PREFIX xopp:       <http://ua.be/sdo2l/vocabulary/formalisms/xopp#>
 PREFIX federation: <http://ua.be/sdo2l/vocabulary/federation#>
 '''
 query = '''
-SELECT ?older WHERE {
-  {{ artifact }} base:newVersionOf+ ?older
+SELECT ?old ?new WHERE {
+  {{ artifact }} base:nextVersionOf+ ?old .
+  OPTIONAL { {{ artifact }} owl:sameAs ?new }
 }
 '''
 description = "Find all the older versions of an artifact."
@@ -48,5 +49,5 @@ visual_support = true
 
 [[replacements]]
 placeholder = "artifact"
-suggestion  = "art:drivetrain-sensor-data-v2"
+suggestion  = "<http://ua.be/sdo2l/description/traces/my_pt#sketch-v2.xopp>"
 description = "For which artifact are you looking for older versions?"

+ 4 - 4
data/palette/find_pm_relation.toml

@@ -39,11 +39,11 @@ PREFIX xopp:       <http://ua.be/sdo2l/vocabulary/formalisms/xopp#>
 PREFIX federation: <http://ua.be/sdo2l/vocabulary/federation#>
 '''
 query = '''
-SELECT DISTINCT ?from ?output ?atname WHERE {
+SELECT DISTINCT * WHERE {
   ?from a {{ from_class }} .
   ?from {{ relation }} ?output .
   ?output a {{ to_class }} .
-  ?output {{ extra_relation }} ?atname .
+  OPTIONAL { ?output {{ extra_relation }} ?name }
 }
 '''
 description = "Find the PM."
@@ -56,7 +56,7 @@ description = "Which starting class?"
 
 [[replacements]]
 placeholder = "relation"
-suggestion  = "ftg:outputs"
+suggestion  = "ftg:hasOutput"
 description = "Relation between the classes?"
 
 [[replacements]]
@@ -66,5 +66,5 @@ description = "The ending class?"
 
 [[replacements]]
 placeholder = "extra_relation"
-suggestion  = "base:hasName"
+suggestion  = "base:hasGUID"
 description = "End class relation?"

+ 13 - 4
data/palette/match_artifact_formalism.toml

@@ -39,9 +39,18 @@ PREFIX xopp:       <http://ua.be/sdo2l/vocabulary/formalisms/xopp#>
 PREFIX federation: <http://ua.be/sdo2l/vocabulary/federation#>
 '''
 query = '''
-SELECT ?pmArtInstance ?formalism WHERE {
-  {{ artifact }} traces:relatesTo ?pmArtInstance .
-  ?pmArtInstance base:isDefinedBy ?formalism .
+SELECT DISTINCT ?t_guid ?f_guid ?element ?rel ?va ?location WHERE {
+   ?individual a ?type .
+   ?type rdfs:subClassOf* ftg:Transformation .
+   ?individual base:hasGUID ?t_guid .
+   ?individual ftg:hasOutput ?formalism .
+   ?formalism base:hasGUID ?f_guid .
+   ?formalism pm:occursAsArtifact ?iri .
+   ?element traces:relatesTo ?iri .
+   ?element a ?atype .
+   ?atype rdfs:subClassOf traces:Artifact .
+   OPTIONAL { ?element traces:hasLocation ?location }
+   ?element owl:sameAs {{ artifact }}
 }
 '''
 description = "Find the formalism corresponding to an artifact."
@@ -49,5 +58,5 @@ visual_support = true
 
 [[replacements]]
 placeholder = "artifact"
-suggestion  = "art:torque-profile"
+suggestion  = "<http://ua.be/sdo2l/description/traces/my_pt#sketch-v1.xopp>"
 description = "For which artifact do you want to find the formalism?"

二進制
docs/results.png


+ 1 - 1
graph_exploring_tool/__init__.py

@@ -1,3 +1,3 @@
 """Graph Exploring Tool."""
-__version__ = "0.1.0"
+__version__ = "0.2.0"
 __version_info__ = tuple((int(num) if num.isdigit() else num for num in __version__.replace("-", ".", 1).split(".")))

+ 1 - 1
graph_exploring_tool/graphical/interface.py

@@ -4,7 +4,6 @@ from typing import List
 
 import arklog
 import dearpygui.dearpygui as dpg
-from dearpygui import demo
 
 from graph_exploring_tool.configuration import Configuration
 from graph_exploring_tool.graphical.constants import PRIMARY_WINDOW_TAG, MAIN_QUERY_GROUP_TAG, MAIN_DIAGRAM_GROUP_TAG
@@ -39,6 +38,7 @@ def interface(configuration: Configuration, palette: List[QueryTemplate], width=
         add_main_menu()
         create_query_group(configuration, palette)
         create_diagram_group()
+    # from dearpygui import demo
     # demo.show_demo()
     dpg.setup_dearpygui()
     dpg.show_viewport()

+ 8 - 1
graph_exploring_tool/graphical/query_group.py

@@ -1,5 +1,6 @@
 import enum
 import logging
+import urllib
 from itertools import groupby
 from typing import List, Union, Optional
 from urllib.error import URLError
@@ -88,7 +89,7 @@ def create_query_palette(query_palette: List[QueryTemplate]):
 def create_query_options(endpoint: str):
     with dpg.group(horizontal=True):
         dpg.add_combo(("Visual", "Textual"), default_value="Visual", callback=_mode_select, width=100, tag=EDITOR_SELECTOR_TAG)
-        dpg.add_input_text(default_value=endpoint, width=300, enabled=False, tag=ENDPOINT_TEXTINPUT_TAG)
+        dpg.add_input_text(default_value=endpoint, width=500, enabled=True, tag=ENDPOINT_TEXTINPUT_TAG)
         dpg.add_checkbox(label="debug", callback=_config)
         dpg.add_checkbox(label="annotate", default_value=False, callback=_config) # TODO Actually make this annotate the result data with its type
 
@@ -217,8 +218,14 @@ def _perform_query(sender: int, mode: str, user_data: Optional[dict]):
                 placeholder = dpg.get_item_user_data(replacement_field).placeholder
                 query_text = query_text.replace(f"{{{{ {placeholder} }}}}", value)
         query_result = query.perform_query(endpoint, prefix_text + "\n" + query_text, use_post_method)
+    except urllib.error.HTTPError as e:
+        logging.exception(e)
+        if e.code in [400]:
+            set_status_text(f"Invalid query.", StatusMessageType.ERROR)
+        return
     except URLError as e:
         logging.error(f"Connection to '{endpoint}' failed.")
+        logging.exception(e)
         set_status_text(f"Connection to '{endpoint}' failed.", StatusMessageType.ERROR)
         return
     if use_post_method:

+ 2 - 2
graph_exploring_tool/main.py

@@ -21,7 +21,7 @@ def handler(signal_code, _) -> None:
 
 
 def load_palette(palette_directory: Path) -> List:
-    """"""
+    """Grab all the toml files in the palette directory and load them into memory."""
     for query_path in palette_directory.rglob("*.toml"):
         logging.debug(f"Loading palette query '{query_path}'.")
         query_configuration = toml.loads(query_path.read_text(encoding="utf-8"))
@@ -41,7 +41,7 @@ def launch():
         configuration = toml.loads((data_dir / Path("configuration.toml")).read_text(encoding="utf-8"))
         configuration = dacite.from_dict(data_class=Configuration, data=configuration, )
     except FileNotFoundError as e:
-        logging.error(f"Configuration not found. {e}")
+        logging.error(f"Configuration 'configuration.toml' not found. {e}")
         return 8
 
     logging.debug("Configuration:")

+ 11 - 14
graph_exploring_tool/query.py

@@ -1,10 +1,9 @@
+import json.decoder
 from dataclasses import dataclass, field
 from typing import List
 from urllib.error import URLError
-
+import owly
 import arklog
-from SPARQLWrapper import SPARQLWrapper, JSON, POSTDIRECTLY
-from SPARQLWrapper.SPARQLExceptions import QueryBadFormed
 
 arklog.set_config_logging()
 
@@ -35,7 +34,7 @@ class QueryTemplate:
     replacements: List[Replacement] = field(default_factory=list)
     modifies: bool = False
 
-# TODO Rewrite this
+# TODO Rewrite this (use dict from config + merge per query)
 reverse_prefix = {
     "https://ontology.rys.app/dt/function/": "dtf",
 
@@ -73,20 +72,18 @@ reverse_prefix = {
     "http://ua.be/sdo2l/vocabulary/formalisms/traceability_model#": "traceability_model",
     "http://ua.be/sdo2l/vocabulary/formalisms/xopp#": "xopp",
     "http://ua.be/sdo2l/vocabulary/federation#": "federation",
+
+    "http://ua.be/sdo2l/description/artifacts/FTG_ftg#": "artifacts_ftg",
 }
 
 
-def perform_query(endpoint: str, query_text: str, post: bool = False) -> dict:
+def perform_query(endpoint_uri: str, query_text: str, post: bool = False) -> dict:
     """"""
-    sparql = SPARQLWrapper(endpoint)
-    sparql.setReturnFormat(JSON)
-    if post:
-        sparql.setRequestMethod(POSTDIRECTLY)
-    sparql.setQuery(query_text)
+    endpoint = owly.Endpoint(endpoint_uri)
     try:
-        ret = sparql.query().convert()
-    except QueryBadFormed:
-        raise
+        result = endpoint.perform_query(query_text)
     except URLError:
         raise
-    return ret
+    except json.decoder.JSONDecodeError:
+        raise
+    return result.as_json()

+ 12 - 10
pyproject.toml

@@ -20,32 +20,34 @@ dynamic = ["version", "description"]
 license = {file = "LICENSE"}
 keywords = ["graph"]
 dependencies = [
+    "owly~=0.0.2",
     "toml~=0.10.2",
     "arklog~=0.5.1",
-    "dacite~=1.8.0",
+    "dacite~=1.8.1",
     "rdflib~=6.3.2",
-    "sparqlwrapper~=2.0.0",
 ]
 
 [project.optional-dependencies]
 test = [
-    "pytest~=7.2.2",
+    "pytest~=7.4.0",
 ]
 doc = [
-    "sphinx~=6.1.3",
+    "sphinx~=7.0.1",
 ]
 dev = [
-    "tox~=4.4.8",
-    "pip~=23.0.1",
-    "flit~=3.8.0",
+    "tox~=4.6.4",
+    "pip~=23.2",
+    "flit~=3.9.0",
     "twine~=4.0.2",
-    "invoke~=2.0.0",
+    "invoke~=2.2.0",
     "jinja2~=3.1.2",
     "flake8~=6.0.0",
-    "coverage~=7.2.2",
+    "coverage~=7.2.7",
+    "pyinstaller~=5.13.0",
+    "pyinstaller-hooks-contrib~=2023.5",
 ]
 graphical = [
-    "dearpygui~=1.9.0",
+    "dearpygui~=1.9.1",
 ]
 
 [project.urls]

+ 15 - 15
requirements.txt

@@ -1,28 +1,28 @@
 # Graph Exploring Tool
-toml          ~= 0.10.2
-arklog        ~= 0.5.1
-dacite        ~= 1.8.0
-rdflib        ~= 6.3.2
-sparqlwrapper ~= 2.0.0
+owly   ~= 0.0.2
+toml   ~= 0.10.2
+arklog ~= 0.5.1
+dacite ~= 1.8.1
+rdflib ~= 6.3.2
 # Test
-pytest ~= 7.3.1
+pytest ~= 7.4.0
 # Doc
-sphinx ~= 7.0.0
+sphinx ~= 7.0.1
 # Dev
-tox         ~= 4.5.1
-pip         ~= 23.1.2
-flit        ~= 3.8.0
+tox         ~= 4.6.4
+pip         ~= 23.2
+flit        ~= 3.9.0
 twine       ~= 4.0.2
-invoke      ~= 2.1.1
+invoke      ~= 2.2.0
 jinja2      ~= 3.1.2
 flake8      ~= 6.0.0
-coverage    ~= 7.2.5
-pyinstaller ~= 5.10.1
-pyinstaller-hooks-contrib ~= 2023.2
+coverage    ~= 7.2.7
+pyinstaller ~= 5.13.0
+pyinstaller-hooks-contrib ~= 2023.5
 # pylode        ~= 3.0.4
 # owlready2     ~= 0.40
 # graphviz      ~= 0.20.1
 # pyshacl[js]   ~= 0.20.0
 # pydot         ~= 1.4.2
 # Graphical
-dearpygui   ~= 1.9.0
+dearpygui   ~= 1.9.1

+ 37 - 5
tasks.py

@@ -3,11 +3,11 @@ from pathlib import Path
 from invoke import task
 from jinja2 import Template
 
+system = "graph_exploring_tool"  # Directory name of the project
 
 @task
 def lint(c):
     """"""
-    system = "graph_exploring_tool"
     c.run(f"python3 -m black {system}")
     c.run(f"python3 -m pylint {system}")
 
@@ -18,21 +18,50 @@ def documentation(c):
     c.run("python3 -m sphinx docs docs/build/html")
 
 
+@task(name="preview", aliases=("rst",))
+def preview(c):
+    """Show a preview of the README file."""
+    rst_view = c.run(f"restview --listen=8888 --browser --pypi-strict README.rst", asynchronous=True, out_stream=sys.stdout)
+    print("Listening on http://localhost:8888/")
+    rst_view.join()
+
+
+@task
+def clean(c):
+    """Remove all artefacts."""
+    patterns = ["build", "docs/build"]
+    for pattern in patterns:
+        c.run(f"rm -rf {pattern}")
+
+
 @task
 def test(c):
     """Run all tests under the tests directory."""
     c.run("python3 -m unittest discover tests 'test_*' -v")
 
 
+@task
+def coverage(c):
+    """Run coverage from the 'tests' directory."""
+    c.run("coverage run --source . -m unittest discover tests 'test_*' -v")
+    c.run("coverage html")
+
+
+@task
+def minimum(c):
+    """Check the minimum required python version for the project."""
+    c.run("vermin --no-parse-comments .")
+
+
 @task(name="migrate")
 def migrate_requirements(c):
     """Copy requirements from the requirements.txt file to pyproject.toml."""
     lines = Path("requirements.txt").read_text().split("\n")
-    current = "graph_exploring_tool"
+    current = system.lower().replace("-", "_")
     requirements = {current: [], "test": [], "doc": [], "graphical": [], "dev": []}
     for line in lines:
         if line.startswith("#"):
-            candidate = line[1:].lower().strip().replace(" ", "_")
+            candidate = line[1:].lower().strip().replace(" ", "_").replace("-", "_")
             if candidate in requirements.keys():
                 current = candidate
                 continue
@@ -50,7 +79,10 @@ def release(c, version):
         print("Version can be either major, minor or patch.")
         return
 
-    from graph_exploring_tool import __version_info__, __version__
+    import importlib
+    current_module = importlib.import_module(system)
+    __version_info__ = current_module.__version_info__
+    __version__ = current_module.__version__
     _major, _minor, _patch = __version_info__
 
     if version == "patch":
@@ -64,7 +96,7 @@ def release(c, version):
         _patch = 0
 
     c.run(f"git checkout -b release-{_major}.{_minor}.{_patch} dev")
-    c.run(f"sed -i 's/{__version__}/{_major}.{_minor}.{_patch}/g' graph_exploring_tool/__init__.py")
+    c.run(f"sed -i 's/{__version__}/{_major}.{_minor}.{_patch}/g' {system}/__init__.py")
     print(f"Update the readme for version {_major}.{_minor}.{_patch}.")
     input("Press enter when ready.")
     c.run(f"git add -u")