Skip to content

Commit b722e77

Browse files
authored
Merge pull request #153 from casework/release-0.15.0
Release 0.15.0
2 parents bc9041c + 5cd31f4 commit b722e77

File tree

10 files changed

+61
-218
lines changed

10 files changed

+61
-218
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ This repository can be installed from PyPI or from source.
1919
pip install case-utils
2020
```
2121

22-
Users who wish to install from PyPI should be aware that while CASE's ontology is in its pre-1.0.0 release state, backwards-incompatible ontology changes may occur. This may manifest as [`case_validate`](#case_validate) reporting data review errors after installing an updated `case_utils` version. Users may wish to pin `case_utils` within any dependent code bases to be less than the next unreleased SEMVER-minor version. (E.g. if `case_utils` version `0.8.0` is currently available, a newly adopting project might wish to track `case_utils<0.9.0` among its dependencies.)
22+
Users who wish to install from PyPI should be aware that though CASE's ontology is in its post-1.0.0 release state, this Python project is in a pre-1.0.0 release state. Backwards-incompatible ontology changes will only occur in accordance with [SEMVER](https://semver.org/). This Python project is not yet committed to its API, and backwards-incompatiable changes may occur. They are likely to occur with advance notice.
23+
24+
Users may wish to pin `case-utils` within any dependent code bases to be less than the next unreleased SEMVER-minor version. (E.g. if `case-utils` version `0.14.0` is currently available, a newly adopting project might wish to track `case-utils<0.15.0` among its dependencies.)
2325

2426

2527
### Installing from source
@@ -120,7 +122,7 @@ case_sparql_select output.md input.sparql input.json [input-2.json ...]
120122

121123
### `local_uuid`
122124

123-
This [module](case_utils/local_uuid.py) provides a wrapper UUID generator, `local_uuid()`. Its main purpose is making example data generate consistent identifiers, and intentionally includes mechanisms to make it difficult to activate this mode without awareness of the caller.
125+
_Migration:_ Functionality previously in [`case_utils.local_uuid`](case_utils/local_uuid.py) has been exported to [`cdo-local-uuid`](https://github.com/Cyber-Domain-Ontology/CDO-Utility-Local-UUID). A future `case-utils` release will drop this re-export.
124126

125127

126128
### Built versions

case_utils/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,4 @@
1414
#
1515
# We would appreciate acknowledgement if the software is used.
1616

17-
__version__ = "0.14.1.post0"
18-
19-
from . import local_uuid # noqa: F401
17+
__version__ = "0.15.0"

case_utils/case_file/__init__.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
This module creates a graph object that provides a basic UCO characterization of a single file. The gathered metadata is among the more "durable" file characteristics, i.e. characteristics that would remain consistent when transferring a file between locations.
1919
"""
2020

21-
__version__ = "0.5.1"
21+
__version__ = "0.6.0"
2222

2323
import argparse
2424
import datetime
@@ -28,7 +28,9 @@
2828
import typing
2929
import warnings
3030

31+
import cdo_local_uuid
3132
import rdflib
33+
from cdo_local_uuid import local_uuid
3234

3335
import case_utils.inherent_uuid
3436
from case_utils.namespace import (
@@ -94,7 +96,7 @@ def create_file_node(
9496
node_namespace = rdflib.Namespace(node_prefix)
9597

9698
if node_iri is None:
97-
node_slug = "File-" + case_utils.local_uuid.local_uuid()
99+
node_slug = "File-" + local_uuid()
98100
node_iri = node_namespace[node_slug]
99101
n_file = rdflib.URIRef(node_iri)
100102
graph.add((n_file, NS_RDF.type, NS_UCO_OBSERVABLE.File))
@@ -110,7 +112,7 @@ def create_file_node(
110112
n_file, NS_UCO_OBSERVABLE.FileFacet, namespace=node_namespace
111113
)
112114
else:
113-
n_file_facet = node_namespace["FileFacet-" + case_utils.local_uuid.local_uuid()]
115+
n_file_facet = node_namespace["FileFacet-" + local_uuid()]
114116

115117
graph.add(
116118
(
@@ -144,9 +146,7 @@ def create_file_node(
144146
n_file, NS_UCO_OBSERVABLE.ContentDataFacet, namespace=node_namespace
145147
)
146148
else:
147-
n_contentdata_facet = node_namespace[
148-
"ContentDataFacet-" + case_utils.local_uuid.local_uuid()
149-
]
149+
n_contentdata_facet = node_namespace["ContentDataFacet-" + local_uuid()]
150150

151151
graph.add((n_file, NS_UCO_CORE.hasFacet, n_contentdata_facet))
152152
graph.add(
@@ -248,7 +248,7 @@ def create_file_node(
248248
)
249249
)
250250
else:
251-
hash_uuid = case_utils.local_uuid.local_uuid()
251+
hash_uuid = local_uuid()
252252
n_hash = node_namespace["Hash-" + hash_uuid]
253253

254254
graph.add((n_contentdata_facet, NS_UCO_OBSERVABLE.hash, n_hash))
@@ -291,7 +291,7 @@ def main() -> None:
291291

292292
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)
293293

294-
case_utils.local_uuid.configure()
294+
cdo_local_uuid.configure()
295295

296296
NS_BASE = rdflib.Namespace(args.base_prefix)
297297

@@ -314,7 +314,7 @@ def main() -> None:
314314
context_dictionary = {k: v for (k, v) in graph.namespace_manager.namespaces()}
315315
serialize_kwargs["context"] = context_dictionary
316316

317-
node_iri = NS_BASE["File-" + case_utils.local_uuid.local_uuid()]
317+
node_iri = NS_BASE["File-" + local_uuid()]
318318
create_file_node(
319319
graph,
320320
args.in_file,

case_utils/case_validate/validate_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#
1515
# We would appreciate acknowledgement if the software is used.
1616

17-
__version__ = "0.1.0"
17+
__version__ = "0.2.0"
1818

1919
import importlib
2020
import logging
@@ -197,6 +197,7 @@ def disable_tbox_review(graph: rdflib.Graph) -> None:
197197
"Disjointedness-AP-OP-shape",
198198
"Disjointedness-C-DT-shape",
199199
"Disjointedness-DP-OP-shape",
200+
"List-shape",
200201
"ObjectProperty-shacl-constraints-shape",
201202
"ontologyIRI-versionIRI-prerequisite-shape",
202203
"versionIRI-nodeKind-shape",

case_utils/inherent_uuid.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
2. A pattern based on inherence generates UUIDv5s based on how an inherent object (a.k.a. UcoInherentCharacterizationThing) structurally relates to the object in which it inheres. For instance, a Facet is understood to only relate to its UcoObject by linking with the uco-core:hasFacet property. So, a Facet's UUID is determined uniquely by (1) the "UUID namespace" of its corresponding UcoObject, and (2) its OWL Class.
2424
A. The term "UUID namespace" is described in RFC 4122 Section 4.3 [#rfc4122s43]_ , and is not intended be confused with `rdflib.term.Namespace`. For any uco-core:UcoThing (or even owl:Thing), the function `inherence_uuid` defines the procedure for either extracting or generating a UUID for use as a namespace.
2525
26-
This module is independent of, and complements, `case_utils.local_uuid`, which provides deterministic UUIDs based on calling process's environment.
26+
This module is independent of, and complements, `cdo_local_uuid.local_uuid`, which provides deterministic UUIDs based on calling process's environment.
2727
2828
References
2929
==========
@@ -57,7 +57,7 @@
5757
>>> assert str(n_file_facet)[-36:] == str(n_file_facet_2)[-36:]
5858
"""
5959

60-
__version__ = "0.1.1"
60+
__version__ = "0.1.2"
6161

6262
import binascii
6363
import re

case_utils/local_uuid.py

Lines changed: 7 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -15,167 +15,18 @@
1515
# We would appreciate acknowledgement if the software is used.
1616

1717
"""
18-
This library is a wrapper for uuid, provided to generate repeatable UUIDs if requested.
19-
20-
The function local_uuid() should be used in code where a user could be expected to opt in to non-random UUIDs.
18+
This library was a wrapper for uuid, provided to generate repeatable UUIDs if requested. It is now a temporary re-export of functionality migrated to cdo_local_uuid.
2119
"""
2220

23-
__version__ = "0.4.1"
21+
__version__ = "0.5.0"
2422

2523
__all__ = ["configure", "local_uuid"]
2624

27-
import logging
28-
import os
29-
import pathlib
30-
import sys
31-
import typing
32-
import uuid
3325
import warnings
3426

35-
DEMO_UUID_BASE: typing.Optional[str] = None
36-
37-
DEMO_UUID_COUNTER: int = 0
38-
39-
_logger = logging.getLogger(pathlib.Path(__file__).name)
40-
41-
42-
def _is_relative_to(p1: pathlib.Path, p2: pathlib.Path) -> bool:
43-
"""
44-
This function provides pathlib.is_relative_to to Pythons before 3.9. After the End of Life of Python 3.8, this function can be removed.
45-
"""
46-
if sys.version_info < (3, 9):
47-
try:
48-
_ = p1.relative_to(p2)
49-
return True
50-
except ValueError:
51-
return False
52-
else:
53-
return p1.is_relative_to(p2)
54-
55-
56-
def configure() -> None:
57-
"""
58-
This function is part of setting up _demo_uuid() to generate non-random UUIDs. See _demo_uuid() documentation for further setup notes.
59-
"""
60-
global DEMO_UUID_BASE
61-
62-
# _logger.debug("sys.argv = %r.", sys.argv)
63-
64-
if os.getenv("DEMO_UUID_REQUESTING_NONRANDOM") == "NONRANDOM_REQUESTED":
65-
warnings.warn(
66-
"Environment variable DEMO_UUID_REQUESTING_NONRANDOM is deprecated. See case_utils.local_uuid._demo_uuid for usage notes on its replacement, CASE_DEMO_NONRANDOM_UUID_BASE. Proceeding with random UUIDs.",
67-
FutureWarning,
68-
)
69-
return
70-
71-
env_base_dir_name = os.getenv("CASE_DEMO_NONRANDOM_UUID_BASE")
72-
if env_base_dir_name is None:
73-
return
74-
75-
base_dir_original_path = pathlib.Path(env_base_dir_name)
76-
if not base_dir_original_path.exists():
77-
warnings.warn(
78-
"Environment variable CASE_DEMO_NONRANDOM_UUID_BASE is expected to refer to an existing directory. Proceeding with random UUIDs.",
79-
RuntimeWarning,
80-
)
81-
return
82-
if not base_dir_original_path.is_dir():
83-
warnings.warn(
84-
"Environment variable CASE_DEMO_NONRANDOM_UUID_BASE is expected to refer to a directory. Proceeding with random UUIDs.",
85-
RuntimeWarning,
86-
)
87-
return
88-
89-
# Component: An emphasis this is an example.
90-
demo_uuid_base_parts = ["example.org"]
91-
92-
# Component: Present working directory, relative to CASE_DEMO_NONRANDOM_UUID_BASE if that environment variable is an ancestor of pwd.
93-
base_dir_resolved_path = base_dir_original_path.resolve()
94-
srcdir_original_path = pathlib.Path(os.getcwd())
95-
srcdir_resolved_path = srcdir_original_path.resolve()
96-
# _logger.debug("base_dir_resolved_path = %r.", base_dir_resolved_path)
97-
# _logger.debug("srcdir_resolved_path = %r.", srcdir_resolved_path)
98-
try:
99-
srcdir_relative_path = srcdir_resolved_path.relative_to(base_dir_resolved_path)
100-
# _logger.debug("srcdir_relative_path = %r.", srcdir_relative_path)
101-
demo_uuid_base_parts.append(str(srcdir_relative_path))
102-
except ValueError:
103-
# If base_dir is not an ancestor directory of srcdir, default to srcdir.
104-
# _logger.debug("PWD is not relative to base path.")
105-
demo_uuid_base_parts.append(str(srcdir_resolved_path))
106-
107-
# Component: Command of argument vector.
108-
env_venv_name = os.getenv("VIRTUAL_ENV")
109-
if env_venv_name is None:
110-
demo_uuid_base_parts.append(sys.argv[0])
111-
else:
112-
command_original_path = pathlib.Path(sys.argv[0])
113-
# _logger.debug("command_original_path = %r.", command_original_path)
114-
command_resolved_path = command_original_path.resolve()
115-
# _logger.debug("command_resolved_path = %r.", command_resolved_path)
116-
117-
# The command could be a command embedded in a virtual
118-
# environment, or it could be a script external to any virtual
119-
# environment.
120-
venv_original_path = pathlib.Path(env_venv_name)
121-
venv_resolved_path = venv_original_path.resolve()
122-
if _is_relative_to(command_resolved_path, venv_resolved_path):
123-
command_relative_path = command_resolved_path.relative_to(
124-
venv_resolved_path
125-
)
126-
# _logger.debug("command_relative_path = %r.", command_relative_path)
127-
demo_uuid_base_parts.append(str(command_relative_path))
128-
else:
129-
demo_uuid_base_parts.append(str(command_original_path))
130-
131-
if len(sys.argv) > 1:
132-
# Component: Arguments of argument vector.
133-
demo_uuid_base_parts.extend(sys.argv[1:])
134-
135-
# _logger.debug("demo_uuid_base_parts = %r.", demo_uuid_base_parts)
136-
137-
DEMO_UUID_BASE = "/".join(demo_uuid_base_parts)
138-
139-
140-
def _demo_uuid() -> str:
141-
"""
142-
This function generates a repeatable UUID, drawing on non-varying elements of the environment and process call for entropy.
143-
144-
This function is not intended to be called outside of this module. Instead, local_uuid() should be called.
145-
146-
WARNING: This function was developed for use ONLY for reducing (but not eliminating) version-control edits to identifiers when generating sample data. It creates UUIDs that are decidedly NOT random, and should remain consistent on repeated calls to the importing script.
147-
148-
To prevent accidental non-random UUID usage, two setup steps need to be done before calling this function:
149-
150-
* An environment variable, CASE_DEMO_NONRANDOM_UUID_BASE, must be set to a string provided by the caller. The variable's required value is the path to some directory. The variable's recommended value is the equivalent of the Make variable "top_srcdir" - that is, the root directory of the containing Git repository, some parent of the current process's current working directory.
151-
* The configure() function in this module must be called.
152-
"""
153-
global DEMO_UUID_BASE
154-
global DEMO_UUID_COUNTER
155-
156-
if os.getenv("CASE_DEMO_NONRANDOM_UUID_BASE") is None:
157-
raise ValueError(
158-
"demo_uuid() called without CASE_DEMO_NONRANDOM_UUID_BASE in environment."
159-
)
160-
161-
if DEMO_UUID_BASE is None:
162-
raise ValueError("demo_uuid() called with DEMO_UUID_BASE unset.")
163-
164-
parts = [DEMO_UUID_BASE]
165-
166-
# Component: Incrementing counter.
167-
DEMO_UUID_COUNTER += 1
168-
parts.append(str(DEMO_UUID_COUNTER))
169-
170-
return str(uuid.uuid5(uuid.NAMESPACE_URL, "/".join(parts)))
171-
27+
from cdo_local_uuid import configure, local_uuid
17228

173-
def local_uuid() -> str:
174-
"""
175-
Generate either a UUID4, or if requested via environment configuration, a non-random demo UUID.
176-
"""
177-
global DEMO_UUID_BASE
178-
if DEMO_UUID_BASE is None:
179-
return str(uuid.uuid4())
180-
else:
181-
return _demo_uuid()
29+
warnings.warn(
30+
"case_utils.local_uuid has exported its functionality to cdo_local_uuid. Imports should be changed to use cdo_local_uuid. case_utils currently re-exports that functionality, but this will cease in a future release.",
31+
DeprecationWarning,
32+
)

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ license_files =
1919
[options]
2020
include_package_data = true
2121
install_requires =
22+
cdo-local-uuid >= 0.5.0, < 0.6.0
2223
pandas
2324
pyshacl >= 0.24.0
2425
rdflib < 8

tests/case_utils/case_file/Makefile

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,10 @@ sample.txt.json: \
117117
$(tests_srcdir)/src/isomorphic_diff.py \
118118
$(top_srcdir)/case_utils/case_file/__init__.py \
119119
$(top_srcdir)/case_utils/inherent_uuid.py \
120-
$(top_srcdir)/case_utils/local_uuid.py \
121120
$(top_srcdir)/case_utils/namespace.py \
122121
sample.txt-nocompact.json
123122
rm -f $@ _$@ __$@
124-
export CASE_DEMO_NONRANDOM_UUID_BASE="$(top_srcdir)" \
123+
export CDO_DEMO_NONRANDOM_UUID_BASE="$(top_srcdir)" \
125124
&& source $(tests_srcdir)/venv/bin/activate \
126125
&& case_file \
127126
--debug \
@@ -152,11 +151,10 @@ sample.txt.ttl: \
152151
$(tests_srcdir)/.venv.done.log \
153152
$(top_srcdir)/case_utils/case_file/__init__.py \
154153
$(top_srcdir)/case_utils/inherent_uuid.py \
155-
$(top_srcdir)/case_utils/local_uuid.py \
156154
$(top_srcdir)/case_utils/namespace.py \
157155
sample.txt.done.log
158156
rm -f _$@ __$@
159-
export CASE_DEMO_NONRANDOM_UUID_BASE="$(top_srcdir)" \
157+
export CDO_DEMO_NONRANDOM_UUID_BASE="$(top_srcdir)" \
160158
&& source $(tests_srcdir)/venv/bin/activate \
161159
&& case_file \
162160
--debug \
@@ -178,11 +176,10 @@ sample.txt-disable_hashes.ttl: \
178176
$(tests_srcdir)/.venv.done.log \
179177
$(top_srcdir)/case_utils/case_file/__init__.py \
180178
$(top_srcdir)/case_utils/inherent_uuid.py \
181-
$(top_srcdir)/case_utils/local_uuid.py \
182179
$(top_srcdir)/case_utils/namespace.py \
183180
sample.txt.done.log
184181
rm -f _$@ __$@
185-
export CASE_DEMO_NONRANDOM_UUID_BASE="$(top_srcdir)" \
182+
export CDO_DEMO_NONRANDOM_UUID_BASE="$(top_srcdir)" \
186183
&& source $(tests_srcdir)/venv/bin/activate \
187184
&& case_file \
188185
--debug \
@@ -206,11 +203,10 @@ sample.txt-nocompact.json: \
206203
$(tests_srcdir)/src/isomorphic_diff.py \
207204
$(top_srcdir)/case_utils/case_file/__init__.py \
208205
$(top_srcdir)/case_utils/inherent_uuid.py \
209-
$(top_srcdir)/case_utils/local_uuid.py \
210206
$(top_srcdir)/case_utils/namespace.py \
211207
sample.txt.done.log
212208
rm -f _$@
213-
export CASE_DEMO_NONRANDOM_UUID_BASE="$(top_srcdir)" \
209+
export CDO_DEMO_NONRANDOM_UUID_BASE="$(top_srcdir)" \
214210
&& source $(tests_srcdir)/venv/bin/activate \
215211
&& case_file \
216212
--debug \

0 commit comments

Comments
 (0)