-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature 1419 competency question coverage report #1420
Merged
Merged
Changes from 37 commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
341af86
Added draft of competency question coverage check
areleu a20dd8c
Added some flexibility to etd
areleu 0ae1d00
Removed competency question coverage
areleu 6ad2675
Added pytest infrastructure
areleu 0deaf93
Added extra pytest dependencies
areleu 707ffa8
Added pytest to CI
areleu 9137ead
Try latest robot version
areleu f7744cd
Refer to source for ETD
areleu af34b07
Refer to version in CI
areleu 05cb1eb
Another try with robot and etd
areleu 0557e97
Fixed etd path
areleu 08c051c
Problems with robot versions?
areleu 4d51b06
Probably an issue when converting from omn to owl
areleu 58cb9ce
Renamed CQs and reorganized their folder structure
areleu 724429b
Updated CQ discovery glob
areleu 96e2f64
Restructured levels
areleu 2919672
Renamed rest of CQs
areleu 157a9bd
First attempt to makea badge
areleu f0bd83b
Added correct path to report
areleu ee86e57
Added coverage badge to readme as example
areleu 447d1d4
Report always uploads
areleu 81a49a0
Wrong competency questions make the test fail
areleu ef4048d
Added missing terms to the report
areleu 12cf373
Created job dependency tree
areleu 1215f39
Added checkout to test pipeline
areleu 32b75b3
Dont upload jar files
areleu 04af58c
Merge branch 'feature-1020-export-of-existing-terms-and-definitions' …
areleu ca9b29c
Updated glossary directory
areleu d8fdf16
Fixed glossary path not being written
areleu 9d29f9e
Merge branch 'dev' into feature-1419-competency-question-coverage-report
areleu 296f5b2
Updated competency test
areleu 9bc2f2c
Revert omn change
areleu 904629c
Merge branch 'dev' into feature-1419-competency-question-coverage-report
areleu 398edc5
Unified biofuel is renewable query and deleted duplicate
areleu 5a1542b
Fixed name of question 041
areleu 370adf6
Renamed questions to be consistent with old names, restored deleted d…
areleu 1e0faf4
Fix test 047 implementation
areleu fb15b9c
Reworked deprecated runs
areleu fe05602
Updated gitignore
areleu ff58eed
Removed run questions script
areleu db69fd4
Created implementing folder
areleu 2fe3043
Added option to fail on tets in implementation
areleu 72f153f
Updated changelog
areleu 7da2c11
Merge branch 'dev' into feature-1419-competency-question-coverage-report
areleu 4138490
Merge branch 'dev' into feature-1419-competency-question-coverage-report
areleu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,50 @@ jobs: | |
- name: make | ||
run: | | ||
make | ||
- name: validate-profile | ||
run: | | ||
echo "java -jar build/robot.jar validate-profile --input build/oeo/$(cat VERSION)/oeo-full.owl --profile Full -vvv --output merged-validation.txt" | ||
java -jar build/robot.jar validate-profile --input build/oeo/$(cat VERSION)/oeo-full.owl --profile Full -vvv --output merged-validation.txt | ||
- name: verify | ||
run: | | ||
java -jar build/robot.jar verify --input build/oeo/$(cat VERSION)/oeo-full.owl --queries tests/verify/* | ||
- uses: actions/upload-artifact@master | ||
with: | ||
name: build-artifacts | ||
path: build/oeo | ||
test: | ||
runs-on: ubuntu-latest | ||
needs: build | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: '3.7' | ||
architecture: x64 | ||
- uses: actions/setup-java@v2 | ||
with: | ||
distribution: 'adopt' | ||
java-version: '11' | ||
- uses: actions/download-artifact@master | ||
with: | ||
name: build-artifacts | ||
path: build/oeo | ||
- name: install python dependencies | ||
run: pip install -r src/scripts/requirements.txt | ||
- name: setup robot 1.9.0 | ||
run: | | ||
wget https://github.com/ontodev/robot/releases/download/v1.9.0/robot.jar -O build/robot19.jar | ||
- name: Build ETD xlsx | ||
run: | | ||
java -jar build/robot19.jar merge --input build/oeo/$(cat VERSION)/oeo-full.omn \ | ||
--include-annotations true \ | ||
export --header "ID|LABEL|definition" \ | ||
--prefix "OEO: http://openenergy-platform.org/ontology/oeo/OEO_" \ | ||
--sort "LABEL" \ | ||
--export $(pwd)/build/oeo/$(cat VERSION)/etd.xlsx | ||
- name: Build ETD csv | ||
run: | | ||
python $(pwd)/src/scripts/etd/etd.py $(pwd)/build/oeo/$(cat VERSION) | ||
- name: consistency | ||
run: | | ||
wget https://github.com/owlcs/releases/raw/master/HermiT/org.semanticweb.hermit-packaged-1.4.6.519-SNAPSHOT.jar -O build/hermit.jar | ||
|
@@ -22,21 +66,48 @@ jobs: | |
fi | ||
echo "Ontology is inconsistent: $OUT" | ||
exit 1 | ||
- name: validate-profile | ||
run: | | ||
echo "java -jar build/robot.jar validate-profile --input build/oeo/$(cat VERSION)/oeo-full.owl --profile Full -vvv --output merged-validation.txt" | ||
java -jar build/robot.jar validate-profile --input build/oeo/$(cat VERSION)/oeo-full.owl --profile Full -vvv --output merged-validation.txt | ||
- name: verify | ||
run: | | ||
java -jar build/robot.jar verify --input build/oeo/$(cat VERSION)/oeo-full.owl --queries tests/verify/* | ||
- name: competency | ||
run: | | ||
bash tests/competency_questions/run_questions.sh "java -jar build/hermit.jar" $(pwd)/build/oeo/$(cat VERSION)/oeo-full.owl true | ||
bash tests/competency_questions/run_questions.sh "java -jar build/hermit.jar" $(pwd)/build/oeo/$(cat VERSION)/oeo-full.owl false | ||
- name: Upload Artifacts | ||
- name: Upload Ontology | ||
if: always() | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: build-files | ||
path: | | ||
build/**/* | ||
!build/**/*.jar | ||
!build/**/*.jar | ||
- name: competency | ||
continue-on-error: true | ||
run: | | ||
pytest -s -v | ||
# bash tests/competency_questions/run_questions.sh "java -jar build/hermit.jar" $(pwd)/build/oeo/$(cat VERSION)/oeo-full.owl true | ||
# bash tests/competency_questions/run_questions.sh "java -jar build/hermit.jar" $(pwd)/build/oeo/$(cat VERSION)/oeo-full.owl false | ||
- name: Upload Artifacts | ||
if: always() | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: test-report | ||
path: build/report.json | ||
- name: Get Coverage for badge | ||
run : | | ||
echo "COVERAGE=$(head build/report.json | grep -o '"coverage": "[^"]*"' | grep -o '[^"]*\%')" >> $GITHUB_ENV | ||
REF=${{ github.ref }} | ||
IFS='/' read -ra PATHS <<< "$REF" | ||
BRANCH_NAME="${PATHS[1]}_${PATHS[2]}" | ||
echo "BRANCH=$(echo ${BRANCH_NAME})" >> $GITHUB_ENV | ||
- name: Coverage Badge | ||
uses: schneegans/[email protected] | ||
with: | ||
auth: ${{ secrets.GIST_SECRET }} | ||
gistID: 6d00affa9fbc89c79684d62091d96551 | ||
filename: open_energy_ontology__${{ env.BRANCH }}.json | ||
label: CQ Coverage | ||
message: ${{ env.COVERAGE }} | ||
color: green | ||
# bash tests/competency_questions/run_questions.sh "java -jar build/hermit.jar" $(pwd)/build/oeo/$(cat VERSION)/oeo-full.owl true | ||
# bash tests/competency_questions/run_questions.sh "java -jar build/hermit.jar" $(pwd)/build/oeo/$(cat VERSION)/oeo-full.owl false | ||
# - name: Upload Artifacts | ||
# uses: actions/upload-artifact@v3 | ||
# with: | ||
# name: build-files | ||
# path: | | ||
# build/**/* | ||
# !build/**/*.jar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
pandas | ||
tabulate | ||
openpyxl | ||
openpyxl | ||
pytest | ||
pytest_harvest |
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
|
||
|
||
def pytest_addoption(parser): | ||
parser.addoption("--selected", action="store", default="") | ||
parser.addoption("--report", action="store", default="report.json") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
from glob import glob | ||
import pandas as pd | ||
from subprocess import Popen, PIPE | ||
from pathlib import Path | ||
import json | ||
import re | ||
from pytest_harvest import saved_fixture | ||
import pytest | ||
import os | ||
import shutil | ||
|
||
CWD = os.getcwd() | ||
with open(Path(CWD).joinpath("VERSION").as_posix()) as version_file: | ||
__version__ = version_file.readlines()[0].strip() | ||
|
||
HERMIT_JAR = Path(CWD).joinpath("build/hermit.jar").as_posix() | ||
JAVA_PATH = shutil.which("java") | ||
ONTOLOGY_PATH = ( | ||
Path(CWD) | ||
.joinpath("build/oeo") | ||
.joinpath(f"{__version__}") | ||
.joinpath("oeo-full.omn") | ||
.as_posix() | ||
) | ||
EXISTING_TERMS_AND_DEFINITONS = ( | ||
Path(CWD).joinpath("build/oeo").joinpath(f"{__version__}").joinpath("glossary/glossary.csv") | ||
) | ||
COMPETENCY_QUESTION_DIRECTORY = Path(CWD).joinpath("tests/competency_questions") | ||
|
||
|
||
@pytest.fixture | ||
@saved_fixture | ||
def existing_terms_and_definitons(): | ||
""" | ||
Fixture containing the final report | ||
""" | ||
terms_and_definitions = pd.read_csv(EXISTING_TERMS_AND_DEFINITONS) | ||
return list(terms_and_definitions["ID"]) | ||
|
||
|
||
def pytest_generate_tests(metafunc): | ||
if "competency_question_path" in metafunc.fixturenames: | ||
competency_question_list = [ | ||
p for p in glob(COMPETENCY_QUESTION_DIRECTORY.as_posix() + "/**/*.omn", recursive=True) | ||
] | ||
selected_filer = metafunc.config.getoption("--selected") | ||
competency_question_list = [ | ||
cq for cq in competency_question_list if selected_filer in cq | ||
] | ||
metafunc.parametrize("competency_question_path", competency_question_list) | ||
|
||
|
||
def check_competency_question(conclusion, premise): | ||
"""Check competency question against the given ontology | ||
|
||
Args: | ||
conclusion (str): A filepath to the competency question. | ||
premise (str): A filepath to the reference ontology. | ||
|
||
Raises: | ||
RuntimeError: If calling HermiT raises an error this will be raised as a RuntimeError. | ||
|
||
Returns: | ||
(boolean): Returns True if the competency question was sucessfully checked against the ontology. | ||
""" | ||
conclusion = Path(conclusion).resolve().as_posix() | ||
p = Popen( | ||
[ | ||
f"{JAVA_PATH}", | ||
"-jar", | ||
f"{HERMIT_JAR}", | ||
f"--premise=file:///{premise}", | ||
f"--conclusion=file:///{conclusion}", | ||
"-E", | ||
], | ||
stdin=PIPE, | ||
stdout=PIPE, | ||
stderr=PIPE, | ||
) | ||
output, err = p.communicate(b"input data that is passed to subprocess' stdin") | ||
if len(err) == 0: | ||
return eval(output.strip().capitalize()) | ||
else: | ||
raise RuntimeError(f"{err}") | ||
|
||
|
||
def search_term_in_question_file(question, pattern=r"\w+_\d{8}"): | ||
"""Search all the Ontology terms in a specific competency question file | ||
|
||
Args: | ||
question (sts): Filepath to the competency question file | ||
pattern (regexp, optional): Regular expression of the terms to be searched. Defaults to r"\w+_\d{8}". | ||
|
||
Returns: | ||
list: List of all the terms covered by the CQ. | ||
""" | ||
terms = [] | ||
with open(question, "r") as question_file: | ||
for line in question_file.readlines(): | ||
terms.extend(re.findall(pattern, line)) | ||
return terms | ||
|
||
|
||
def test_competency_question( | ||
competency_question_path, existing_terms_and_definitons, results_bag | ||
): | ||
"""Metatest to produce competency question tests.""" | ||
results_bag.questions = {} | ||
results_bag.terms = {} | ||
name = Path(competency_question_path).stem | ||
is_soundness = True if "soundness" in competency_question_path else False | ||
failure = "" | ||
query_result = False | ||
if not name in results_bag.questions: | ||
results_bag.questions[name] = {"passed": False, "covers": []} | ||
try: | ||
query_result = check_competency_question( | ||
competency_question_path, ONTOLOGY_PATH | ||
) | ||
if is_soundness: | ||
query_result = not query_result | ||
results_bag.questions[name]["passed"] = query_result | ||
except RuntimeError as e: | ||
results_bag.questions[name]["passed"] = False | ||
results_bag.questions[name]["error"] = str(e) | ||
failure = str(e) | ||
|
||
terms = search_term_in_question_file(competency_question_path) | ||
results_bag.questions[name]["covers"].extend(terms) | ||
results_bag.questions[name]["covers"] = list( | ||
set(results_bag.questions[name]["covers"]) | ||
) | ||
for term in terms: | ||
if term in existing_terms_and_definitons: | ||
if not term in results_bag.terms: | ||
results_bag.terms[term] = {"covered": False, "by": []} | ||
results_bag.terms[term]["covered"] = True | ||
results_bag.terms[term]["by"].append(name) | ||
if len(failure) > 0: | ||
raise RuntimeError(failure) | ||
|
||
assert query_result, f"{name} failed" | ||
|
||
|
||
def test_synthesis(fixture_store, existing_terms_and_definitons): | ||
"""This test should run at the end. Produces the final report. | ||
|
||
Args: | ||
fixture_store (fixture): These are all the availible fixtures. | ||
existing_terms_and_definitons (fixture): Fixture with existing terms and definitions. | ||
""" | ||
initial_terms = {t : {"covered": False, "by": []} for t in existing_terms_and_definitons if "OEO_" in t} | ||
report = {"coverage": "0%", "questions": {}, "terms": initial_terms} | ||
for v in fixture_store["results_bag"].values(): | ||
report["questions"].update(v["questions"]) | ||
for term in v["terms"].keys(): | ||
if term in report["terms"]: | ||
report["terms"][term] ["covered"] = True | ||
report["terms"][term]["by"].extend(v["terms"][term]["by"]) | ||
report["terms"][term]["by"] = list(set(report["terms"][term]["by"])) | ||
report["terms"][term]["by"] = list(set(report["terms"][term]["by"])) | ||
else: | ||
report["terms"][term] = { | ||
"covered": True, | ||
"by": list(set(report["terms"][term]["by"])), | ||
} | ||
|
||
coverage = sum([1 for c in report.get("terms", {}).values() if c["covered"]]) / len( | ||
[term for term in existing_terms_and_definitons if "OEO_" in term] | ||
) | ||
report["coverage"] = "{:.0%}".format(coverage) | ||
with open(Path(CWD).joinpath("build/report.json"), "w") as f: | ||
json.dump(report, f, indent=4) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, the answer this competency question is neither false not right, but the question is undecidable, because one needs additional information about the biofuel to decide this question. Same with Q29.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I will handle this differently, I will add a folder where all the deprecated questions are to me moved, without changing their conditions at all. I will also add the option to run the deprecated questions by adding the "--deprecated" flag to the pytest call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that is a good solution.