Metadata-Version: 2.4
Name: pyowl2-profiles
Version: 0.1.0
Summary: Fast OWL 2 profile detection (EL/RL/QL/DL) over pyoxigraph
Project-URL: Homepage, https://github.com/MaastrichtU-IDS/pyowl2-profiles
Project-URL: Repository, https://github.com/MaastrichtU-IDS/pyowl2-profiles
Project-URL: Issues, https://github.com/MaastrichtU-IDS/pyowl2-profiles/issues
Author-email: Michel Dumontier <michel.dumontier@maastrichtuniversity.nl>
License-Expression: MIT
License-File: LICENSE
Keywords: dl,el,ontology,owl,profile,ql,rdf,rl,semantic-web
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: pyoxigraph>=0.4
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Description-Content-Type: text/markdown

# pyowl2-profiles

Fast OWL 2 profile detection (EL/RL/QL/DL) over [pyoxigraph](https://github.com/oxigraph/oxigraph).

![PyPI](https://img.shields.io/pypi/v/pyowl2-profiles)
![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)
![Python versions](https://img.shields.io/pypi/pyversions/pyowl2-profiles)

## Installation

```bash
pip install pyowl2-profiles
```

## Quick start

```python
import pyoxigraph
from pyowl2_profiles import detect_profiles, PROFILE_NAMES

# Load your ontology into a pyoxigraph store
store = pyoxigraph.Store()
with open("my-ontology.ttl", "rb") as f:
    store.load(f.read(), pyoxigraph.RdfFormat.TURTLE)

# Run detection
result = detect_profiles(store, graph_iri=None)

# Check verdicts
for profile in PROFILE_NAMES:  # ("el", "rl", "ql", "dl")
    r = result[profile]
    status = "IN" if r["in_profile"] else "OUT"
    print(f"OWL 2 {profile.upper()}: {status}  ({r['total_violations']} violations)")

# Inspect violation samples
for sample in result["el"]["sample_violations"][:3]:
    print(f"  {sample['axiom_type']}: {sample['subject_iri']}")
```

## Why this library

- **No JVM.** ROBOT requires Java; pyowl2-profiles runs entirely in Python with no external runtime.
- **No second parse.** If you already have data in a pyoxigraph store (e.g., from a pipeline), detection adds only a few lightweight SPARQL queries.
- **Fast.** On moderate-sized ontologies (< 1M triples), detection completes in under a second. Cold-start (load + detect) is 10-1400x faster than ROBOT depending on ontology size.
- **Standard Python packaging.** `pip install`, import, done.

## CLI usage

### Detect profiles for a file

```bash
pyowl2-profiles detect my-ontology.ttl
pyowl2-profiles detect my-ontology.ttl --format json
pyowl2-profiles detect my-ontology.ttl --profile EL
```

### Benchmark against ROBOT

```bash
# Requires robot on PATH
pyowl2-profiles benchmark onto1.ttl onto2.owl --csv results.csv

# Skip ROBOT, ours only
pyowl2-profiles benchmark onto1.ttl --skip-robot
```

## Validation

Validated against ROBOT 1.9.10 on a 19-ontology biomedical fleet: **19/19 (100%) verdict agreement** across all four profiles (EL, RL, QL, DL).

See [docs/usage.md](docs/usage.md) for a detailed walkthrough and benchmark methodology.

## API reference

### `detect_profiles(store, graph_iri=None, ontology_id="", version_id="") -> dict`

Run all four OWL 2 profile checks against a pyoxigraph.Store.

**Parameters:**
- `store` — `pyoxigraph.Store` containing the ontology triples
- `graph_iri` — named graph IRI to query, or `None` for the default graph
- `ontology_id` — optional string identifier (informational only)
- `version_id` — optional version string (informational only)

**Returns** a dict with keys `"el"`, `"rl"`, `"ql"`, `"dl"`, `"indexed_at"`. Each profile value is a dict with:
- `in_profile` (bool) — True if no violations found
- `total_violations` (int) — total violation count
- `violations_by_axiom_type` (dict[str, int]) — per-type counts
- `sample_violations` (list[dict]) — up to 50 example violations, each with `axiom_type`, `subject_iri`, `manchester` (rendered tokens), and optionally `details`

### `ProfileViolation`

Frozen dataclass for a single violation: `profile`, `axiom_type`, `subject_iri`, `details`, `manchester`.

### `PROFILE_NAMES`

`("el", "rl", "ql", "dl")` — the four OWL 2 profiles in subset order.

### `ProfileName`

Type alias: `Literal["el", "rl", "ql", "dl"]`.

## Acknowledgement

Originally extracted from [OntoExplorer](https://github.com/MaastrichtU-IDS/ontoexplorer),
a FAIR ontology repository at Maastricht University Institute of Data Science.

## License

MIT — see [LICENSE](LICENSE).