Metadata-Version: 2.4
Name: ghga-jsonsubschema
Version: 0.2.0
Summary: A tool to check whether a JSON schema is subset/subschema of another JSON schema.
Author: Avraham Shinnar, Martin Hirzel
Author-email: Andrew Habib <andrew.a.habib@gmail.com>, The GHGA Authors <contact@ghga.de>
Maintainer-email: The GHGA Authors <contact@ghga.de>
License: Apache 2.0
Project-URL: Repository, https://github.com/ghga-de/ghga
Project-URL: Release Notes, https://github.com/ghga-de/ghga/releases
Project-URL: Issue Tracker, https://github.com/ghga-de/ghga/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Topic :: Software Development :: Libraries
Classifier: Intended Audience :: Developers
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: greenery<5,>=4.2
Requires-Dist: jsonref<2,>=1.1
Requires-Dist: jsonschema<5,>=4.26
Requires-Dist: portion<3,>=2.6
Provides-Extra: dev
Requires-Dist: coverage[toml]>=7; extra == "dev"
Requires-Dist: pytest-cov>=6; extra == "dev"
Requires-Dist: mypy>=2.1; extra == "dev"
Requires-Dist: pre-commit>=4; extra == "dev"
Requires-Dist: pytest>=9; extra == "dev"
Requires-Dist: ruff>=0.15; extra == "dev"
Dynamic: license-file

[![PyPI version shields.io](https://img.shields.io/pypi/v/ghga-jsonsubschema.svg)](https://pypi.org/project/ghga-jsonsubschema/)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/ghga-jsonsubschema.svg)](https://pypi.org/project/ghga-jsonsubschema/)

# GHGA JSON Subschema

> **Note:** This is a fork of [IBM/jsonsubschema](https://github.com/ibm/jsonsubschema) maintained by the [German Human Genome-Phenome Archive (GHGA)](https://www.ghga.de/). It was created to bring in necessary fixes, updates, and functionality required by GHGA-related projects.

**ghga-jsonsubschema** checks if one JSON schema is a subschema (subtype) of another.

For any two JSON schemas s1 and s2, s1 <: s2 (reads s1 is subschema/subtype of s2) if every JSON document instance that validates against s1 also validates against s2.

jsonsubschema is very useful in analysing schema evolution and ensuring that newer schema versions are backward compatible.
jsonsubschema also enables static type checking on different components of a system that uses JSON schema to describe data interfaces among the system's different components.

For a practical overview of the architecture, purpose, and usage of this library, please see [DETAILS.md](https://github.com/ghga-de/ghga/blob/main/libs/ghga-jsonsubschema/DETAILS.md). For the formal foundations and deep technical details, please refer to the [ISSTA 2021 paper](https://dl.acm.org/doi/10.1145/3460319.3464796) by Andrew Habib, Avraham Shinnar, Martin Hirzel, and Michael Pradel, the original authors of this library.

## Installation

### Requirements

* Python 3.11+

### Install from PyPI

```sh
pip install ghga-jsonsubschema
```

### Install from source

The unreleased version can be installed straight from the monorepo, without cloning it:

```sh
pip install "git+https://github.com/ghga-de/ghga.git#subdirectory=libs/ghga-jsonsubschema"
```

## Running subschema

JSON subschema provides two usage interfaces:

### CLI interface

First, create two JSON schema examples by executing the following:

```sh
echo '{"type": ["null", "string"]}' > s1.json
echo '{"type": ["string", "null"], "not": {"enum": [""]}}' > s2.json
```

Then, invoke the CLI by executing:

```sh
python -m jsonsubschema s2.json s1.json
```

### Python API

```python
from jsonsubschema import is_subschema

def main():
    s1 = {'type': "integer"}
    s2 = {'type': ["integer", "string"]}

    print(f'LHS <: RHS {is_subschema(s1, s2)}')

if __name__ == "__main__":
    main()
```

## Development

This package is developed in the [GHGA monorepo](https://github.com/ghga-de/ghga), where
it lives in `libs/ghga-jsonsubschema`. Clone that repository and work inside this
package's directory:

```sh
git clone https://github.com/ghga-de/ghga.git
cd ghga/libs/ghga-jsonsubschema
uv sync --extra dev
uv run pre-commit install
```

All further commands should be run from this directory as well.

Run the test suite:

```sh
uv run pytest tests/
```

Run the test suite with coverage:

```sh
uv run pytest --cov tests/
```

Note that `uv sync` uses the monorepo's shared environment and lockfile at the repository
root, but installs only this package and its dependencies. To work on the monorepo as a
whole, with all of its packages installed, run `just sync` from the repository root; its
[README](https://github.com/ghga-de/ghga#readme) describes the available tasks.

## Changes made by GHGA

This fork is based on version 0.0.8 of [IBM/jsonsubschema](https://github.com/ibm/jsonsubschema) and introduces additional changes:

* Public API names have been changed to align with PEP 8.
* The minimum required Python version is now 3.11.
* Packaging uses more modern conventions.
* Tests have been converted from `unittest` to `pytest`.
* An empty `enum` is now treated as an uninhabited schema.
* Bugs inherited from upstream have been fixed: negating a numeric schema now
  respects `exclusiveMinimum`/`exclusiveMaximum`, intersecting numeric schemas
  no longer drops exclusive bounds, nested `anyOf` unions are now fully
  flattened (previously, adjacent nested unions could make two equivalent
  schemas compare as unrelated), and arrays with at most one item are now
  recognized as satisfying `uniqueItems`.
* The `dependencies` keyword (which upstream silently ignores) now raises
  `exceptions.UnsupportedDependencies` instead of potentially returning
  unsound verdicts.
* Negating an integer schema (e.g.
  `{"not": {"type": "integer", "minimum": 10, "maximum": 20}}`) now yields
  the exact complement — including the non-integer numbers, represented
  internally as `{"type": "number", "not": {"multipleOf": 1}}` — where
  upstream silently computes a too-small complement that can yield unsound
  verdicts. Only negating a numeric schema with a non-trivial `multipleOf`
  (whose complement would contain the non-multiples) raises
  `exceptions.UnsupportedNegatedNumeric` instead of returning potentially
  wrong results.
* Uninhabited numeric schemas whose `multipleOf` has no multiple within the
  schema's bounds are now recognized as such, and subtype checks of numeric
  schemas admitting a single value are now exact (e.g.
  `{"type": "integer"}` is now a subschema of
  `{"type": "number", "multipleOf": 0.5}`).

## License

This repository is distributed under the terms of the Apache 2.0 License, see [LICENSE.txt](https://github.com/ghga-de/ghga/blob/main/libs/ghga-jsonsubschema/LICENSE.txt).
