Skip to content

Commit

Permalink
update checks page auto
Browse files Browse the repository at this point in the history
  • Loading branch information
anitacaron committed Nov 25, 2024
1 parent 3290f59 commit ff854d6
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 201 deletions.
45 changes: 21 additions & 24 deletions principles/checks/fp_001.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: check
id: fp_001
id: 1
title: Open Automated Check
---

Expand Down Expand Up @@ -39,11 +39,11 @@ See [Open Implementation](http://obofoundry.org/principles/fp-001-open.html#impl
The registry data entry is validated with JSON schema using the [license schema](https://raw.githubusercontent.com/OBOFoundry/OBOFoundry.github.io/master/util/schema/license.json). The license schema ensures that a license entry is present and that the entry has a `url` and `label`. The license schema also checks that the license is one of the CC0 or CC-BY licenses. OWL API is then used to check the ontology as an `OWLOntology` object. Annotations on the ontology are retrieved and the `dcterms:license` property is found. The python script ensures that the correct `dcterms:license` property is used. The script compares this license to the registry license to ensure that they are the same.

```python
import jsonschema
import dash_utils
import jsonschema


def is_open(ontology, data):
def is_open(ontology, data, schema):
"""Check FP 1 - Open.
This method checks the following:
Expand All @@ -63,7 +63,7 @@ def is_open(ontology, data):
ERROR, WARN, INFO, or PASS string with optional message.
"""

v = OpenValidator(ontology, data)
v = OpenValidator(ontology, data, schema)

loadable = False
if ontology:
Expand Down Expand Up @@ -91,7 +91,7 @@ class OpenValidator():
license (None if missing)
"""

def __init__(self, ontology, data):
def __init__(self, ontology, data, schema):
"""Instantiate an OpenValidator.
Args:
Expand All @@ -105,7 +105,7 @@ class OpenValidator():

self.is_open = None
if self.registry_license is not None:
self.is_open = check_registry_license(data)
self.is_open = check_registry_license(data, schema)

self.ontology_license = None
self.correct_property = None
Expand Down Expand Up @@ -134,18 +134,18 @@ class OpenValidator():
annotations = ontology.getAnnotations()
license = dash_utils.get_ontology_annotation_value(annotations,
license_prop)
bad_license = dash_utils.get_ontology_annotation_value(
annotations, bad_license_prop)

bad_licenses = list(filter(None, [dash_utils.get_ontology_annotation_value(annotations, prop) for prop in bad_license_props]))

if license:
self.ontology_license = license
self.correct_property = True
elif bad_license:
self.ontology_license = bad_license
elif len(bad_licenses) > 0:
self.ontology_license = bad_licenses[0]
self.correct_property = False


def big_is_open(file, data):
def big_is_open(file, data, schema):
"""Check FP 1 - Open.
This method checks the following:
Expand All @@ -165,7 +165,7 @@ def big_is_open(file, data):
ERROR, WARN, INFO, or PASS string with optional message.
"""

v = BigOpenValidator(file, data)
v = BigOpenValidator(file, data, schema)
return process_results(v.registry_license,
v.ontology_license,
v.is_open,
Expand All @@ -188,7 +188,7 @@ class BigOpenValidator():
license (None if missing)
"""

def __init__(self, file, data):
def __init__(self, file, data, schema):
"""Instantiate a BigOpenValidator.
Args:
Expand All @@ -202,7 +202,7 @@ class BigOpenValidator():

self.is_open = None
if self.registry_license is not None:
self.is_open = check_registry_license(data)
self.is_open = check_registry_license(data, schema)

self.ontology_license = None
self.correct_property = None
Expand Down Expand Up @@ -276,7 +276,7 @@ class BigOpenValidator():
# ---------- UTILITY METHODS ---------- #


def check_registry_license(data):
def check_registry_license(data, schema):
"""Use the JSON license schema to validate the registry data.
This ensures that the license is present and one of the CC0 or CC-BY
Expand All @@ -290,7 +290,7 @@ def check_registry_license(data):
"""

try:
jsonschema.validate(data, license_schema)
jsonschema.validate(data, schema)
return True
except jsonschema.exceptions.ValidationError as ve:
return False
Expand All @@ -304,7 +304,7 @@ def compare_licenses(registry_license, ontology_license):
ontology_license (str): license URL from the ontology
Return:
True if registry license matches ontology licences;
True if registry license matches ontology license;
False if the licenses do not match;
None if one or both licenses are missing.
"""
Expand Down Expand Up @@ -380,7 +380,7 @@ def process_results(registry_license,
level = 'ERROR'
issues.append(missing_ontology_license)

# matches_ontology = None if missing ontology licenese
# matches_ontology = None if missing ontology license
if matches_ontology is False:
level = 'ERROR'
issues.append(no_match.format(ontology_license, registry_license))
Expand All @@ -395,11 +395,8 @@ def process_results(registry_license,
return {'status': level, 'comment': ' '.join(issues)}


# correct dc license property namespace
# correct dc license property
license_prop = 'http://purl.org/dc/terms/license'
# incorrect dc license property namespace
bad_license_prop = 'http://purl.org/dc/elements/1.1/license'

# license JSON schema for registry validation
license_schema = dash_utils.load_schema('dependencies/license.json')
# incorrect dc license properties
bad_license_props = ['http://purl.org/dc/elements/1.1/license', 'http://purl.org/dc/elements/1.1/rights', 'http://purl.org/dc/terms/rights']
```
29 changes: 6 additions & 23 deletions principles/checks/fp_002.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,19 @@ import dash_utils
from dash_utils import format_msg


def is_common_format(ontology):
def is_common_format(syntax):
"""Check FP 2 - Common Format.
Args:
ontology (OWLOntology): ontology object
syntax (str): the syntax as determined by ROBOT metrics
Return:
PASS if OWLOntology is not None, ERROR otherwise.
"""
if ontology is None:
return {'status': 'ERROR', 'comment': 'Unable to load ontology'}
else:
if syntax is None:
return {'status': 'ERROR', 'comment': 'Unknown format'}
elif syntax == "RDF/XML Syntax":
return {'status': 'PASS'}


def big_is_common_format(good_format):
"""Check FP 2 - Common Format on large ontologies
Args:
good_format (bool): True if ontology could be parsed by Jena
Return:
PASS if good_format, ERROR otherwise.
"""
if good_format is None:
return {'status': 'ERROR',
'comment': 'Unable to load ontology (may be too large)'}
elif good_format is False:
return {'status': 'ERROR',
'comment': 'Unable to parse ontology'}
else:
return {'status': 'PASS'}
return {'status': 'WARN', 'comment': f'OWL syntax ({syntax}), but should be RDF/XML'}
```
64 changes: 44 additions & 20 deletions principles/checks/fp_003.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,19 @@ The full OBO Foundry ID Policy can be found [here](http://www.obofoundry.org/id-
All entity IRIs are retrieved from the ontology, excluding annotation properties. Annotation properties may use hashtags and words due to legacy OBO conversions for subset properties. All other IRIs are checked if they are in the ontology's namespace. If the IRI begins with the ontology namespace, the next character must be an underscore. If not, this is an error. The IRI is also compared to a regex pattern to check if the local ID after the underscore is numeric. If not, this is a warning.

```python
import dash_utils
import os
import re

from dash_utils import format_msg
import dash_utils

iri_pattern = r'http:\/\/purl\.obolibrary\.org\/obo\/%s_[0-9]{1,9}'
owl_deprecated = 'http://www.w3.org/2002/07/owl#deprecated'

error_msg = '{0} invalid IRIs'
error_msg = '{} invalid IRIs. The Ontology IRI is {}valid.'
warn_msg = '{0} warnings on IRIs'


def has_valid_uris(robot_gateway, namespace, ontology):
def has_valid_uris(robot_gateway, namespace, ontology, ontology_dir):
"""Check FP 3 - URIs.
This check ensures that all ontology entities follow NS_LOCALID.
Expand All @@ -67,6 +66,7 @@ def has_valid_uris(robot_gateway, namespace, ontology):
otherwise.
"""
if not ontology:
dash_utils.write_empty(os.path.join(ontology_dir, 'fp3.tsv'), ["Status", "Issue"])
return {'status': 'ERROR', 'comment': 'Unable to load ontology'}

entities = robot_gateway.OntologyHelper.getEntities(ontology)
Expand Down Expand Up @@ -95,10 +95,14 @@ def has_valid_uris(robot_gateway, namespace, ontology):
elif check == 'WARN':
warn.append(iri)

return save_invalid_uris(namespace, error, warn)
ontology_iri = dash_utils.get_ontology_iri(ontology)

valid_iri = is_valid_ontology_iri(ontology_iri, namespace)

return save_invalid_uris(error, warn, ontology_dir, valid_iri)

def big_has_valid_uris(namespace, file):

def big_has_valid_uris(namespace, file, ontology_dir):
"""Check FP 3 - URIs on a big ontology.
This check ensures that all ontology entities follow NS_LOCALID.
Expand All @@ -112,6 +116,7 @@ def big_has_valid_uris(namespace, file):
Args:
namespace (str): ontology ID
file (str): path to ontology file
ontology_dir (str):
Return:
INFO if ontology IRIs cannot be parsed. ERROR if any errors, WARN if
Expand All @@ -134,6 +139,7 @@ def big_has_valid_uris(namespace, file):
if 'Ontology' and 'about' in line:
if not owl and not rdf:
# did not find OWL and RDF - end now
dash_utils.write_empty(os.path.join(ontology_dir, 'fp3.tsv'), ["Status", "Issue"])
return {'status': 'ERROR',
'comment': 'Unable to parse ontology'}

Expand Down Expand Up @@ -171,11 +177,20 @@ def big_has_valid_uris(namespace, file):

if not valid:
# not valid ontology
dash_utils.write_empty(os.path.join(ontology_dir, 'fp3.tsv'), ["Status", "Issue"])
return {'status': 'ERROR',
'comment': 'Unable to parse ontology'}

return save_invalid_uris(namespace, error, warn)
return save_invalid_uris(error, warn, ontology_dir)


def is_valid_ontology_iri(iri, namespace):
if iri:
if iri == 'http://purl.obolibrary.org/obo/{0}.owl'.format(namespace):
return True
if iri == 'http://purl.obolibrary.org/obo/{0}/{0}-base.owl'.format(namespace):
return True
return False

def check_uri(namespace, iri):
"""Check if a given IRI is valid.
Expand All @@ -193,43 +208,52 @@ def check_uri(namespace, iri):
return True
if iri.startswith(namespace):
# all NS IRIs must follow NS_
if not iri.startwith(namespace + '_'):
if not iri.startswith(namespace + '_'):
return 'ERROR'
# it is recommended to follow NS_NUMID
elif not re.match(pattern, iri, re.IGNORECASE):
return 'WARN'
return True


def save_invalid_uris(ns, error, warn):
def save_invalid_uris(error, warn, ontology_dir, valid_ontology_iri = True):
"""Save invalid (error or warning) IRIs to a report file
(reports/dashboard/*/fp3.tsv).
Args:
ns (str): ontology ID
error (list): list of ERROR IRIs
warn (list): list of WARN IRIs
ontology_dir (str):
Return:
ERROR or WARN with detailed message, or PASS if no errors or warnings.
"""
if len(error) > 0 or len(warn) > 0:
file = 'build/dashboard/{0}/fp3.tsv'.format(ns)
with open(file, 'w+') as f:
for e in error:
f.write('ERROR\t{0}\n'.format(e))
for w in warn:
f.write('WARN\t{0}\n'.format(w))
# write a report (maybe empty)
file = os.path.join(ontology_dir, 'fp3.tsv')

with open(file, 'w+') as f:
f.write('Status\tIssue\n')
for e in error:
f.write('ERROR\t{0}\n'.format(e))
for w in warn:
f.write('WARN\t{0}\n'.format(w))

o_iri_msg=""
if not valid_ontology_iri:
o_iri_msg = "not "

if len(error) > 0 and len(warn) > 0:
return {'status': 'ERROR',
'file': 'fp3',
'comment': ' '.join([error_msg.format(len(error)),
'comment': ' '.join([error_msg.format(len(error), o_iri_msg),
warn_msg.format(len(warn))])}
elif len(error) > 0:
return {'status': 'ERROR',
'file': 'fp3',
'comment': error_msg.format(len(error))}
'comment': error_msg.format(len(error), o_iri_msg)}
elif not valid_ontology_iri:
return {'status': 'ERROR',
'file': 'fp3',
'comment': error_msg.format(0, o_iri_msg)}
elif len(warn) > 0:
return {'status': 'ERROR',
'file': 'fp3',
Expand Down
Loading

0 comments on commit ff854d6

Please sign in to comment.