Skip to content
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

Updated emmocheck to ahead to latest formulation of units #809

Merged
merged 19 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5a7b904
Updated emmocheck to ahead to latest formulation of units
jesper-friis Nov 24, 2024
850ad3d
Also ignore emmo.CGSUnit when checking unit dimension
jesper-friis Nov 24, 2024
692533a
Merge branch 'master' into update-emmocheck2
francescalb Dec 4, 2024
a7fe590
Merge branch 'master' into update-emmocheck2
jesper-friis Dec 4, 2024
f30a66b
Merge branch 'master' into update-emmocheck2
jesper-friis Dec 4, 2024
64d5073
Merge branch 'master' into update-emmocheck2
jesper-friis Dec 10, 2024
8fcc5d8
Fixing two new pylint issues
jesper-friis Dec 10, 2024
91794d5
Added some exceptions for EMMO unit dimension classes
jesper-friis Dec 12, 2024
5c642a9
Merge branch 'master' into update-emmocheck2
jesper-friis Dec 12, 2024
d314b2a
Merge branch 'emmocheck-unit-dimension' into update-emmocheck2
jesper-friis Dec 12, 2024
8ea482c
Also ignore CGSUnit
jesper-friis Dec 12, 2024
9ea1c8f
Merge branch 'master' into update-emmocheck2
jesper-friis Feb 2, 2025
9560af8
Removed Python 3.7 from CI Tests, but added Python 3.12 and 3.13 instead
jesper-friis Feb 2, 2025
eeff32b
Merge branch 'update-emmocheck2' of github.com:emmo-repo/EMMO-python …
jesper-friis Feb 2, 2025
f13883e
Removed test for Python 3.13
jesper-friis Feb 2, 2025
06463a4
Removed Python 3.7 and added Python 3.12 to setup.py
jesper-friis Feb 2, 2025
983c116
Allow missing elucidation for unit subclasses with a physical dimension
jesper-friis Feb 2, 2025
99e8ada
Trying to fix failing test
jesper-friis Feb 3, 2025
ed28f35
Added configuration to skip modules
jesper-friis Feb 3, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/ci_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- name: Checkout repository
Expand Down
29 changes: 27 additions & 2 deletions docs/tools-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,40 @@ optional arguments:
```
<!-- (Missing example with local and path) -->

### Example configuration file

Example of YAML configuration file provided with the `--configfile` option that will omit `myunits.MyUnitCategory1` and `myunits.MyUnitCategory1` from the *unit dimensions test*.
### Configuration file
The `--configfile` options expects a YAML configuration file that specifies what tests to skip or enable.

The following keywords are recognised in the YAML file:

- `skip`: List of tests to skip
- `enable`: List of tests to enable
- `<test_name>`: A name of a test. Recognised nested keywords are:
- `exceptions`: List of entities in the ontology to skip. Should be written
as `<ns0>.<name>`, where `<ns0>` is the last component of the base IRI
and `<name>` is the name of the entity.
- `skipmodules`: List of module names to skip the test for. The module
names may be written either as the full module IRI or as the last
component of the module IRI.

Example configuration file:

```console
test_description:
skipmodules:
- manufacturing
- conformityassessment

test_unit_dimensions:
exceptions:
- myunits.MyUnitCategory1
- myunits.MyUnitCategory2

skip:
- name_of_test_to_skip

enable:
- name_of_test_to_enable
```

---
Expand Down
113 changes: 112 additions & 1 deletion emmopy/emmocheck.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
# -*- coding: utf-8 -*-
# pylint: disable=too-many-lines,invalid-name
"""
A module for testing an ontology against conventions defined for EMMO.

A YAML file can be provided with additional test configurations.

Toplevel keywords in the YAML file:

- `skip`: List of tests to skip
- `enable`: List of tests to enable
- `<test_name>`: A name of a test. Recognised nested keywords are:
- `exceptions`: List of entities in the ontology to skip. Should be written
as `<ns0>.<name>`, where `<ns0>` is the last component of the base IRI
and `<name>` is the name of the entity.
- `skipmodules`: List of module names to skip the test for. The module
names may be written either as the full module IRI or as the last
component of the module IRI.

Example configuration file:

test_description:
skipmodules:
- manufacturing
- conformityassessment

test_unit_dimensions:
exceptions:
- myunits.MyUnitCategory1
Expand Down Expand Up @@ -194,6 +212,12 @@
Exceptions include entities from standard w3c vocabularies.

"""
# pylint: disable=invalid-name
MeasurementUnit = (
self.onto.MeasurementUnit
if "MeasurementUnit" in self.onto
else None
)
exceptions = set()
exceptions.update(self.get_config("test_description.exceptions", ()))
props = self.onto.world._props # pylint: disable=protected-access
Expand All @@ -214,6 +238,23 @@
if r in exceptions or any(r.startswith(v) for v in vocabs):
continue

# Skip units subclasses with a physical dimension
if (

Check warning on line 242 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L242

Added line #L242 was not covered by tests
MeasurementUnit
and issubclass(entity, MeasurementUnit)
and any(
str(r.property.prefLabel.first()) == "hasDimensionString"
for r in entity.get_indirect_is_a()
if hasattr(r, "property")
and hasattr(r.property, "prefLabel")
)
):
continue

Check warning on line 252 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L252

Added line #L252 was not covered by tests

# Check skipmodules
if skipmodule(self, "test_description", entity):
continue

Check warning on line 256 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L255-L256

Added lines #L255 - L256 were not covered by tests

label = str(get_label(entity))
with self.subTest(entity=entity, label=label):
self.assertTrue(
Expand Down Expand Up @@ -314,6 +355,10 @@
"emmo.SIBaseUnit",
"emmo.SIUnitSymbol",
"emmo.SIUnit",
"emmo.SIAcceptedDerivedUnit",
"emmo.SIDerivedUnit",
"emmo.SIAcceptedPrefixedUnit",
"emmo.CGSUnit",
)
)
if not hasattr(self.onto, "MeasurementUnit"):
Expand Down Expand Up @@ -378,6 +423,11 @@
"emmo.SIBaseUnit",
"emmo.SIUnitSymbol",
"emmo.SIUnit",
"emmo.SIDerivedUnit",
"emmo.SIAcceptedPrefixedUnit",
"emmo.SIAcceptedDerivedUnit",
"emmo.SIMetricPrefixedUnit",
"emmo.CGSUnit",
)
)
if not hasattr(self.onto, "MeasurementUnit"):
Expand Down Expand Up @@ -496,6 +546,7 @@
"metrology.ExactConstant",
"metrology.MeasuredConstant",
"metrology.DerivedQuantity",
"metrology.PhysicalQuantiyByDefinition",
"isq.ISQBaseQuantity",
"isq.InternationalSystemOfQuantity",
"isq.ISQDerivedQuantity",
Expand Down Expand Up @@ -531,6 +582,7 @@
"emmo.Intensive",
"emmo.Extensive",
"emmo.Concentration",
"emmo.PhysicalQuantiyByDefinition",
)
)
if not hasattr(self.onto, "PhysicalQuantity"):
Expand Down Expand Up @@ -565,7 +617,7 @@
issubclass(cls, self.onto.ISQDimensionlessQuantity)
)

def test_dimensional_unit(self):
def test_dimensional_unit_rc2(self):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we have two tests? Shuold we not just stick to one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Because EMMO changed since 1.0.0-rc2.

test_dimensional_unit() works for current version of EMMO.
test_dimensional_unit_rc2() works for previous version of EMMO.

Copy link
Collaborator Author

@jesper-friis jesper-friis Dec 13, 2024

Choose a reason for hiding this comment

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

The common way for software to handle changes in their dependencies is to keep the latest version in sync with the latest version of the dependencies. That is why test_dimensional_unit() is updated to the latest version of EMMO. In addition we kept a renamed copy of the test that works with EMMO up to 1.0.0-rc2.

To make the latest version of EMMOntoPy handle multiple versions of EMMO, it is not sufficient to rename the tests differently, we need a whole new formalisation to (preferably in a declarative way) specify what versions of EMMO each test is valid for. I added issue #821 for that.

"""Check correct syntax of dimension string of dimensional units."""

# This test requires that the ontology has imported SIDimensionalUnit
Expand All @@ -585,6 +637,38 @@
self.assertIsInstance(r, owlready2.Restriction)
self.assertRegex(r.value, regex)

def test_dimensional_unit(self):
"""Check correct syntax of dimension string of dimensional units."""

# This test requires that the ontology has imported SIDimensionalUnit
if "SIDimensionalUnit" not in self.onto:
self.skipTest("SIDimensionalUnit is not imported")

# pylint: disable=invalid-name
regex = re.compile(

Check warning on line 648 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L648

Added line #L648 was not covered by tests
"^T([+-][1-9][0-9]*|0) L([+-][1-9]|0) M([+-][1-9]|0) "
"I([+-][1-9]|0) (H|Θ)([+-][1-9]|0) N([+-][1-9]|0) "
"J([+-][1-9]|0)$"
)
for cls in self.onto.SIDimensionalUnit.__subclasses__():
with self.subTest(cls=cls, label=get_label(cls)):
dimstr = [

Check warning on line 655 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L653-L655

Added lines #L653 - L655 were not covered by tests
r.value
for r in cls.is_a
if isinstance(r, owlready2.Restriction)
and repr(r.property) == "emmo.hasDimensionString"
]
self.assertEqual(

Check warning on line 661 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L661

Added line #L661 was not covered by tests
len(dimstr),
1,
msg="expect one emmo:hasDimensionString value restriction",
)
self.assertRegex(

Check warning on line 666 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L666

Added line #L666 was not covered by tests
dimstr[0],
regex,
msg=f"invalid dimension string: '{dimstr[0]}'",
)

def test_physical_quantity_dimension(self):
"""Check that all physical quantities have `hasPhysicalDimension`.

Expand Down Expand Up @@ -734,6 +818,32 @@
checker(self.onto, self.ignore_namespace)


def skipmodule(testobj, testname, entity):
"""Return true if `entity` is in a module that should be skipped."""
skipmodules = testobj.get_config(f"{testname}.skipmodules")

Check warning on line 823 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L823

Added line #L823 was not covered by tests

if not skipmodules:
return False

Check warning on line 826 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L825-L826

Added lines #L825 - L826 were not covered by tests

# Infer base iri
if entity.namespace.ontology.base_iri != "https://w3id.org/emmo#":
base_iri = entity.namespace.ontology.base_iri.rstrip("/#")
elif hasattr(entity, "isDefinedBy") and entity.isDefinedBy:
base_iri = entity.isDefinedBy.first().rstrip("/#")

Check warning on line 832 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L829-L832

Added lines #L829 - L832 were not covered by tests
else:
base_iri = entity.namespace.ontology.base_iri.rstrip("/#")

Check warning on line 834 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L834

Added line #L834 was not covered by tests

for module in skipmodules:
module = module.rstrip("/#")
if "/" in module:
if module == base_iri:
return True
elif module == base_iri.rsplit("/", 1)[-1]:
return True

Check warning on line 842 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L836-L842

Added lines #L836 - L842 were not covered by tests

return False

Check warning on line 844 in emmopy/emmocheck.py

View check run for this annotation

Codecov / codecov/patch

emmopy/emmocheck.py#L844

Added line #L844 was not covered by tests


def main(
argv: list = None,
): # pylint: disable=too-many-locals,too-many-branches,too-many-statements
Expand Down Expand Up @@ -938,6 +1048,7 @@
"test_physical_quantity_dimension_annotation",
"test_quantity_dimension_beta3",
"test_physical_quantity_dimension",
"test_dimensional_unit_rc2",
]
)
msg = {name: "skipped by default" for name in skipped}
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ def fglob(patt):
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Information Analysis",
"Topic :: Scientific/Engineering :: Visualization",
Expand Down
4 changes: 2 additions & 2 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class H2O(emmo.Molecule):
emmo.hasSpatialDirectPart.exactly(2, onto.Hydrogen)
emmo.hasSpatialDirectPart.exactly(1, Oxygen)

# Create some
# Create some individuals
H1 = onto.Hydrogen()
H2 = onto.Hydrogen()
O = Oxygen()
Expand All @@ -59,7 +59,7 @@ class H2O(emmo.Molecule):
name_prefix = "myonto_"
onto.sync_attributes(name_policy="sequential", name_prefix=name_prefix)
assert f"{onto.base_iri}{name_prefix}0" in onto
assert f"{onto.base_iri}{name_prefix}6" in onto
assert f"{onto.base_iri}{name_prefix}3" in onto

name_prefix = "onto_"
onto.sync_attributes(name_policy="uuid", name_prefix=name_prefix)
Expand Down