> For the complete documentation index, see [llms.txt](https://docs-lunar.earthly.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-lunar.earthly.dev/release-notes/python-sdk/2025.md).

# 2025

## v0.2.2 (2025-12-19) <a href="#python-sdk-v0-2-2" id="python-sdk-v0-2-2"></a>

### Features

* Checks can now be marked as not applicable to a component (for example, a Go-specific check on a repository with no Go code): calling the new `Check.skip(reason)` method reports the check with the new `skipped` status (`CheckStatus.SKIPPED`) and discards any assertions recorded before the skip.

## v0.2.1 (2025-11-06) <a href="#python-sdk-v0-2-1" id="python-sdk-v0-2-1"></a>

### Features

* `Check` and `Node` gain `get_value_or_default(path, default)`, which returns the given default when there is no value at the path — instead of raising an error or, while data collection is still in progress, marking the check pending.

## v0.2.0 (2025-11-05) <a href="#python-sdk-v0-2-0" id="python-sdk-v0-2-0"></a>

### Breaking changes

#### Node-based data access API <a href="#python-sdk-node-data-access-api" id="python-sdk-node-data-access-api"></a>

The SDK's data access layer is rebuilt around the new `Node` class, which represents a location in the component JSON and navigates relative to that location. `Check.get_node(path)` returns a `Node`; nodes expose `get_value`, `get_all_values`, `exists`, and `get_node`, with paths resolved relative to the node and data accessed lazily. Checks and nodes can also be iterated — lists yield child nodes, dicts yield keys — and `items()` yields key/child-node pairs.

Upgrading from 0.1.x requires policy changes:

* `ComponentData` and `Path` are removed. Build a `Node` instead — `Node.from_bundle_file`, `Node.from_bundle_json`, `Node.from_component_json_file`, or `Node.from_component_json` — and pass it to `Check(name, node=...)`. When no node is given, checks still load the component JSON automatically from `LUNAR_BUNDLE_PATH`.
* `check.get(path)` is renamed to `check.get_value(path)`, and `check.get_all(path)` to `check.get_all_values(path)`. Both now default to `.`, the current node's value.
* Paths use a strict JSON path grammar — dot segments (`.foo`), bracketed keys (`['foo-bar']`), and array indexes (`[0]`) — that can be concatenated for relative navigation. General JSONPath expressions such as `$` roots, wildcards, and filters are no longer accepted. Because the SDK now parses paths itself, the `jsonpath-ng` dependency is gone and `lunar-policy` has no runtime dependencies.
* `CheckStatus.NO_DATA` is renamed to `CheckStatus.PENDING`; policy code that references the old member must be updated. The status value reported in check results is still `no-data`.

## v0.1.7 (2025-10-01) <a href="#python-sdk-v0-1-7" id="python-sdk-v0-1-7"></a>

### Improvements

* `lunar-policy` can now be installed on Python 3.9 and newer; earlier releases required Python 3.13.

## v0.1.6 (2025-08-20) <a href="#python-sdk-v0-1-6" id="python-sdk-v0-1-6"></a>

### Breaking changes

* Component data loaded with `ComponentData.from_file` or `ComponentData.from_json` must now include a `bundle_info` key, which carries the workflow-completion signal; Lunar-provided data includes it automatically, but hand-written fixtures used for local policy testing need to add it, and `ComponentData.from_component_json` accepts a new optional `bundle_info` argument.
* The `get_or_default` and `get_all_or_default` methods are removed; use `exists()` to probe for optional data, or catch `NoDataError` where a default value is genuinely wanted.

### Features

* The new `assert_exists(Path(path))` assertion and `exists(path)` helper test whether a path is present in the component data; `assert_exists` requires a `Path` object, while `exists` accepts a path string. Before all CI workflows for the commit have finished, a missing path keeps the usual `no-data` behavior; afterward, `assert_exists` fails the check and `exists` returns `False`.

### Improvements

#### Missing data becomes conclusive once collectors finish <a href="#python-sdk-collectors-finished-no-data" id="python-sdk-collectors-finished-no-data"></a>

Checks now distinguish data that has not been collected yet from data that is conclusively absent. Lunar records in the component data whether all CI workflows for the commit have completed, and the SDK reads that signal whenever a queried path has no data.

While workflows are still running, missing data behaves as before: the check ends early and reports `no-data`, and Lunar re-evaluates the policy as more data is collected. Once all workflows have finished, missing data is no longer treated as pending: `assert_exists` fails the check, `exists` returns `False`, and other assertions or `get` calls that hit a missing path report an `error` instead of leaving the check `no-data` indefinitely.

* `NoDataError` can now be imported directly from the package root (`from lunar_policy import NoDataError`), for policies that handle missing data themselves.

### Bug fixes

* Result reporting is fixed for policy scripts that define more than one check: each check's results are now emitted on a separate line, so checks after the first are no longer misread.

## v0.1.5 (2025-06-27) <a href="#python-sdk-v0-1-5" id="python-sdk-v0-1-5"></a>

### Features

* Policy scripts can now write ordinary log output to stdout: check results are emitted with the marker Lunar provides via `LUNAR_LOG_PREFIX`, so the platform can separate result reporting from anything else the script prints and capture the rest as script logs; when the marker is not set, output is unchanged.

### Bug fixes

* The missing-data check status is now reported as `no-data` instead of `no_data`, making the value consistent with the rest of Lunar; it previously surfaced as `no_data` in the checks SQL view.

## v0.1.4 (2025-06-03) <a href="#python-sdk-v0-1-4" id="python-sdk-v0-1-4"></a>

### Breaking changes

* The `submit()` method on `Check` is removed — results are submitted automatically when the `with` block exits — and `name` is now a read-only property; the previously public `description` attribute is now internal.
* The `SnippetData` class is renamed to `ComponentData`, matching what it holds — the component JSON a policy evaluates; update imports and references, the `from_file`, `from_json`, and `from_component_json` constructors are unchanged.
* `Check.failure_reasons` now returns a list of failure messages instead of a single comma-separated string.

### Features

* New `get_or_default` and `get_all_or_default` methods on `Check` return a default value instead of ending the check as `no_data` when a path has no data.

### Improvements

* Unexpected exceptions inside a check now produce a distinct `error` check status instead of being recorded as an assertion failure, separating broken policy code from genuine policy violations; the new value is available as `CheckStatus.ERROR`.
* When a check ends early because data is missing, the recorded result now includes a message naming the path that had no data (for example, `No data found for .sbom`).

## v0.1.3 (2025-05-28) <a href="#python-sdk-v0-1-3" id="python-sdk-v0-1-3"></a>

### Breaking changes

#### Explicit Path objects for component-data queries <a href="#python-sdk-explicit-path-objects" id="python-sdk-explicit-path-objects"></a>

Component-data lookups in assertions are now expressed with the new `Path` class, and assertions no longer guess whether a string argument is a JSON path: a plain string is always treated as a literal value.

```python
from lunar_policy import Check, Path

with Check("readme") as c:
    c.assert_true(Path(".readme.exists"))           # queries the component JSON
    c.assert_equals(c.get(".language"), ".net")     # ".net" is a literal value
```

Previously, any string beginning with `.` was interpreted as a path, which made it impossible to assert against literal values that merely look like paths. `Path` replaces the former `JsonPathExpression` class, and paths may now be written with an explicit `$` root prefix (for example `Path("$.readme.exists")`); either way they are evaluated from the root of the component JSON. String arguments to `get` and `get_all` are still interpreted as paths.

* The `assert_exists` and `assert_missing` assertions are removed; assert on the value itself instead.
* A check now ends at the first missing-data access, recording a single `no_data` result and skipping the rest of the block, instead of every assertion reporting `no_data` individually; accordingly, `get` and `get_all` raise `NoDataError` when a path has no data — handled automatically by the `Check` context manager — instead of returning `None` or an empty list.

### Features

* The new `fail()` method on `Check` explicitly fails a check with an optional failure message, for conditions the built-in assertions cannot express.
* New `status` and `failure_reasons` properties on `Check` expose the outcome of a check — useful for unit-testing policies; statuses are values of the `CheckStatus` enum, which replaces `OpResult`.
* The new `SnippetData.from_component_json` constructor loads a plain component JSON document as both the merged view and a single delta, so a policy can be exercised against a raw component JSON.

### Improvements

* An unhandled exception inside a `with Check(...)` block is now recorded on the check as a failed assertion carrying the error message, so the failure shows up in the check results rather than only in the script's output; the exception still propagates after the check is submitted.

### Bug fixes

* `lunar_policy.__version__` now reports the package version; it previously reported `0.0.1` regardless of the installed release.

## v0.1.2 (2025-05-20) <a href="#python-sdk-v0-1-2" id="python-sdk-v0-1-2"></a>

### Breaking changes

#### Package renamed to lunar-policy <a href="#python-sdk-lunar-policy-package-rename" id="python-sdk-lunar-policy-package-rename"></a>

The Policy Python SDK is now published on PyPI as `lunar-policy`, replacing the `lunar-checks` name; the package was originally published as `lunar-snippets`. Install it with `pip install lunar-policy` and import it as `lunar_policy`:

```python
from lunar_policy import Check
```

Aside from the name, the package contents are identical to `lunar-checks` 0.1.1. Update policy dependencies and imports to the new name; the older package names no longer receive updates.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs-lunar.earthly.dev/release-notes/python-sdk/2025.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
