Skip to content

Commit 0390ee7

Browse files
Merge pull request #26 from casework/release-0.3.0
Release 0.3.0
2 parents 7d8f676 + 1acc5e2 commit 0390ee7

File tree

104 files changed

+20419
-478
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+20419
-478
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ jobs:
2727

2828
steps:
2929
- uses: actions/checkout@v2
30+
- uses: actions/setup-java@v2
31+
with:
32+
distribution: 'adopt'
33+
java-version: '8'
3034
- name: Set up Python ${{ matrix.python-version }}
3135
uses: actions/setup-python@v2
3236
with:

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
[submodule "dependencies/CASE"]
2+
path = dependencies/CASE
3+
url = https://github.com/casework/CASE.git
14
[submodule "dependencies/CASE-Examples-QC"]
25
path = dependencies/CASE-Examples-QC
36
url = https://github.com/ajnelson-nist/CASE-Examples-QC.git

CONTRIBUTE.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Contributing to CASE-Utilities-Python
2+
3+
4+
## Deploying a new ontology version
5+
6+
1. After cloning this repository, ensure the CASE submodule is checked out. This can be done with either `git submodule init && git submodule update`, `make .git_submodule_init.done.log`, or `make check`.
7+
2. Update the CASE submodule pointer to the new tagged release.
8+
3. The version of CASE is also hard-coded in [`case_utils/ontology/version_info.py`](case_utils/ontology/version_info.py). Edit the variable `CURRENT_CASE_VERSION`.
9+
4. From the top source directory, run `make clean`. This guarantees a clean state of this repository as well as the ontology submodules.
10+
5. Still from the top source directory, run `make`.
11+
6. Any new `.ttl` files will be created under [`case_utils/ontology/`](case_utils/ontology/). Use `git add` to add each of them. (The patch-weight of these files could overshadow manual revisions, so it is fine to commit the built files after the manual changes are committed.)
12+
13+
Here is a sample sequence of shell commands to run the build:
14+
15+
```bash
16+
# (Starting from fresh `git clone`.)
17+
make check
18+
pushd dependencies/CASE
19+
git checkout master
20+
git pull
21+
popd
22+
git add dependencies/CASE
23+
# (Here, edits should be made to case_utils/ontology/version_info.py)
24+
make
25+
pushd case_utils/ontology
26+
git add case-0.6.0.ttl # Assuming CASE 0.6.0 was just released.
27+
# and/or
28+
git add uco-0.8.0.ttl # Assuming UCO 0.8.0 was adopted in CASE 0.6.0.
29+
popd
30+
make check
31+
# Assuming `make check` passes:
32+
git commit -m "Update CASE ontology pointer to version 0.6.0" dependencies/CASE case_utils/ontology/version_info.py
33+
git commit -m "Build CASE 0.6.0.ttl" case_utils/ontology/case-0.6.0.ttl
34+
```

Makefile

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,15 @@
1313

1414
SHELL := /bin/bash
1515

16-
PYTHON3 ?= $(shell which python3.9 2>/dev/null || which python3.8 2>/dev/null || which python3.7 2>/dev/null || which python3.6 2>/dev/null || which python3)
16+
PYTHON3 ?= python3
1717

18-
all:
18+
case_version := $(shell $(PYTHON3) case_utils/ontology/version_info.py)
19+
ifeq ($(case_version),)
20+
$(error Unable to determine CASE version)
21+
endif
22+
23+
all: \
24+
.ontology.done.log
1925

2026
.PHONY: \
2127
download
@@ -31,14 +37,35 @@ all:
3137
# Build an ontology terms list, which has a side effect of initiating further submodules.
3238
$(MAKE) \
3339
--directory dependencies/CASE-Examples-QC \
34-
download
40+
.git_submodule_init.done.log \
41+
.venv.done.log
3542
$(MAKE) \
3643
--directory dependencies/CASE-Examples-QC/tests \
3744
ontology_vocabulary.txt
45+
test -r dependencies/CASE/ontology/master/case.ttl \
46+
|| (git submodule init dependencies/CASE && git submodule update dependencies/CASE)
47+
test -r dependencies/CASE/ontology/master/case.ttl
48+
$(MAKE) \
49+
--directory dependencies/CASE \
50+
.git_submodule_init.done.log \
51+
.lib.done.log
52+
touch $@
53+
54+
.ontology.done.log: \
55+
dependencies/CASE/ontology/master/case.ttl
56+
# Do not rebuild the current ontology file if it is already present. It is expected not to change once built.
57+
# touch -c: Do not create the file if it does not exist. This will convince the recursive make nothing needs to be done if the file is present.
58+
touch -c case_utils/ontology/case-$(case_version).ttl
59+
touch -c case_utils/ontology/case-$(case_version)-subclasses.ttl
60+
$(MAKE) \
61+
--directory case_utils/ontology
62+
# Confirm the current monolithic file is in place.
63+
test -r case_utils/ontology/case-$(case_version).ttl
64+
test -r case_utils/ontology/case-$(case_version)-subclasses.ttl
3865
touch $@
3966

4067
check: \
41-
.git_submodule_init.done.log
68+
.ontology.done.log
4269
$(MAKE) \
4370
PYTHON3=$(PYTHON3) \
4471
--directory tests \
@@ -49,12 +76,32 @@ clean:
4976
--directory tests \
5077
clean
5178
@rm -f \
52-
.git_submodule_init.done.log
79+
.*.done.log
80+
@# 'clean' in the ontology directory should only happen when testing and building new ontology versions. Hence, it is not called from the top-level Makefile.
81+
@test ! -r dependencies/CASE/README.md \
82+
|| $(MAKE) \
83+
--directory dependencies/CASE \
84+
clean
85+
@# Restore CASE validation output files that do not affect CASE build process.
86+
@test ! -r dependencies/CASE/README.md \
87+
|| ( \
88+
cd dependencies/CASE \
89+
&& git checkout \
90+
-- \
91+
tests/examples \
92+
|| true \
93+
)
5394
@#Remove flag files that are normally set after deeper submodules and rdf-toolkit are downloaded.
5495
@rm -f \
5596
dependencies/CASE-Examples-QC/.git_submodule_init.done.log \
5697
dependencies/CASE-Examples-QC/.lib.done.log
5798

99+
# This recipe guarantees timestamp update order, and is otherwise intended to be a no-op.
100+
dependencies/CASE/ontology/master/case.ttl: \
101+
.git_submodule_init.done.log
102+
test -r $@
103+
touch $@
104+
58105
distclean: \
59106
clean
60107
@rm -rf \

README.md

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,33 @@ Installation is demonstrated in the `.venv.done.log` target of the [`tests/`](te
2020
## Usage
2121

2222

23+
### `case_validate`
24+
25+
This repository provides `case_validate` as an adaptation of the `pyshacl` command from [RDFLib's pySHACL](https://github.com/RDFLib/pySHACL). The command-line interface is adapted to run as though `pyshacl` were provided the full CASE ontology (and adopted full UCO ontology) as both a shapes and ontology graph. "Compiled" (or, "aggregated") CASE ontologies are in the [`case_utils/ontology/`](case_utils/ontology/) directory, and are installed with `pip`, so data validation can occur without requiring networking after this repository is installed.
26+
27+
To see a human-readable validation report of an instance-data file:
28+
29+
```bash
30+
case_validate input.json [input-2.json ...]
31+
```
32+
33+
If `input.json` is not conformant, a report will be emitted, and `case_validate` will exit with status `1`. (This is a `pyshacl` behavior, where `0` and `1` report validation success. Status of >`1` is for other errors.)
34+
35+
To produce the validation report as a machine-readable graph output, the `--format` flag can be used to modify the output format:
36+
37+
```bash
38+
case_validate --format turtle input.json > result.ttl
39+
```
40+
41+
To use one or more supplementary ontology files, the `--ontology-graph` flag can be used, more than once if desired, to supplement the selected CASE version:
42+
43+
```bash
44+
case_validate --ontology-graph internal_ontology.ttl --ontology-graph experimental_shapes.ttl input.json
45+
```
46+
47+
Other flags are reviewable with `case_validate --help`.
48+
49+
2350
### `case_file`
2451

2552
To characterize a file, including hashes:
@@ -39,6 +66,8 @@ case_file --disable-hashes sample.txt.json sample.txt
3966

4067
Two commands are provided to generate output from a SPARQL query and one or more input graphs. Input graphs can be any graph, such as instance data or supplementary ontology files that supply custom class definitions or other external ontologies.
4168

69+
These commands can be used with any RDF files to run arbitrary SPARQL queries. They have one additional behavior tailored to CASE: If a path query is used for subclasses, the CASE subclass hierarchy will be loaded to supplement the input graph. An expected use case of this feature is subclasses of `ObservableObject`. For instance, if a data graph included an object with only the class `uco-observable:File` specified, the query `?x a/rdfs:subClassOf* uco-observable:ObservableObject` would match `?x` against that object.
70+
4271

4372
#### `case_sparql_construct`
4473

@@ -62,8 +91,6 @@ case_sparql_select output.html input.sparql input.json [input-2.json ...]
6291
case_sparql_select output.md input.sparql input.json [input-2.json ...]
6392
```
6493

65-
Note that `case_sparql_select` is not guaranteed to function with Pythons below version 3.7.
66-
6794

6895
### `local_uuid`
6996

@@ -86,10 +113,9 @@ This project follows [SEMVER 2.0.0](https://semver.org/) where versions are decl
86113

87114
## Ontology versions supported
88115

89-
This repository supports the ontology versions that are linked as submodules in the [CASE Examples QC](https://github.com/ajnelson-nist/CASE-Examples-QC) repository. Currently, the ontology versions are:
116+
This repository supports the CASE ontology version that is linked as a submodule [here](dependencies/CASE). The CASE version is encoded as a variable (and checked in unit tests) in [`case_utils/ontology/version_info.py`](case_utils/ontology/version_info.py), and used throughout this code base, as `CURRENT_CASE_VERSION`.
90117

91-
* CASE - 0.4.0
92-
* UCO - 0.6.0
118+
For instructions on how to update the CASE version for an ontology release, see [`CONTRIBUTE.md`](CONTRIBUTE.md).
93119

94120

95121
## Repository locations

case_utils/__init__.py

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,19 @@
1111
#
1212
# We would appreciate acknowledgement if the software is used.
1313

14-
__version__ = "0.2.1"
14+
__version__ = "0.3.0"
1515

16-
import rdflib.util
16+
import typing
17+
import warnings
1718

18-
from . import local_uuid
19-
20-
def guess_format(fpath, fmap=None):
21-
"""
22-
This function is a wrapper around rdflib.util.guess_format(), adding that the .json extension should be recognized as JSON-LD.
23-
24-
:param fpath: File path.
25-
:type fpath: string
19+
import rdflib.util # type: ignore
2620

27-
:param fmap: Mapper dictionary; see rdflib.util.guess_format() for further description. Note that as in rdflib 5.0.0, supplying this argument overwrites, not augments, the suffix format map used by rdflib.
28-
:type fmap: dict
29-
30-
:returns: RDF file format, fit for rdflib.Graph.parse() or .serialize(); or, None if file extension not mapped.
31-
:rtype: string
32-
"""
33-
34-
assert fmap is None or isinstance(fmap, dict), "Type check failed"
21+
from . import local_uuid
3522

36-
if fmap is None:
37-
updated_fmap = {key:rdflib.util.SUFFIX_FORMAT_MAP[key] for key in rdflib.util.SUFFIX_FORMAT_MAP}
38-
if not "json" in updated_fmap:
39-
updated_fmap["json"] = "json-ld"
40-
if not "jsonld" in updated_fmap:
41-
updated_fmap["jsonld"] = "json-ld"
42-
else:
43-
updated_fmap = {k:fmap[k] for k in fmap}
23+
def guess_format(
24+
fpath : str,
25+
fmap : typing.Optional[typing.Dict[str, str]] = None
26+
) -> typing.Optional[str]:
27+
warnings.warn("The functionality in case_utils.guess_format is now upstream. Please revise your code to use rdflib.util.guess_format. The function arguments remain the same. case_utils.guess_format will be removed in case_utils 0.4.0.", DeprecationWarning)
4428

45-
return rdflib.util.guess_format(fpath, updated_fmap)
29+
return rdflib.util.guess_format(fpath, fmap) # type: ignore

0 commit comments

Comments
 (0)