Metadata-Version: 2.4
Name: simready-validate
Version: 2026.4.9
Summary: SimReady Validation Library
Author: NVIDIA Corporation
License-Expression: Apache-2.0
Project-URL: Homepage, https://www.nvidia.com
Keywords: nvidia,simready,validate
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: omniverse-asset-validator
Requires-Dist: omniverse-usd-profiles==1.10.22
Requires-Dist: usd-core>=22.11
Dynamic: license-file

# simready.validate

Standalone Python library for validating USD assets against SimReady profiles. Reports
which features passed or failed, with per-requirement detail on failures.

---

## Installation

```bash
pip install simready-validate
```

## Quick start

```python
import simready.validate as sv
from pathlib import Path

# Load profiles from your spec data (omit when running inside Kit)
specs = Path("/path/to/specs")
sv.initialize(
    rules_and_requirements_paths=[specs / "capabilities"],
    features_paths=[specs / "features"],
    profiles_paths=[specs / "profiles/profiles.toml"],
)

result = sv.validate_asset(sv.AssetValidationConfig(
    asset_path="/assets/props/crate_01/crate_01.usd",
    profile_id="Prop-Robotics-Neutral",
    profile_version="2.0.0",
))

if result is None:
    print("Could not validate — file missing, wrong extension, or no profile found.")
else:
    passed = all(f["passed"] for f in result.features_summary.values())
    print(f"{result.profile_id} v{result.profile_version}: {'PASSED' if passed else 'FAILED'}")
    for feat_id, data in result.features_summary.items():
        if not data["passed"]:
            print(f"  {feat_id}: failing {data.get('failing requirements')}")

sv.destroy()
```

---

## Key concepts

### Profiles

A **profile** is a named set of features (e.g. `Prop-Robotics-Neutral`, `Prop-Robotics-Physx`).
Each feature groups a set of validation requirements. Passing a profile means every requirement
of every feature in that profile passed.

Profile data (rules, features, profile TOML) is loaded via `initialize()`. When running inside
a Kit environment, profiles are already registered and `initialize()` can be omitted.

### Profile inference

If `profile_id` is omitted from `AssetValidationConfig`, the library reads the profile from
`SimReady_Metadata.validation.profile` stamped in the asset's USD `customLayerData`. This
allows previously-stamped assets to be re-validated without specifying the profile explicitly.

### Stamping results into USD

Setting `write_metadata=True` on `AssetValidationConfig` writes the validation outcome back
into the USD file's `customLayerData["SimReady_Metadata"]["validation"]`.

---

## Python API

### Initialization

```python
sv.initialize(
    rules_and_requirements_paths: list[Path],
    features_paths:               list[Path],
    profiles_paths:               list[Path],
) -> None

sv.destroy() -> None
```

### Validate a single asset

```python
sv.validate_asset(config: AssetValidationConfig) -> AssetValidationResult | None
```

Returns `None` if the file is missing, has the wrong extension (`.usd` / `.usda` only),
or has no profile in metadata and none was given.

### Validate multiple assets

```python
sv.validate_asset_list(
    configs:          list[AssetValidationConfig],
    report_file_path: str | None = None,          # merged JSON report
) -> list[AssetValidationResult | None]
```

### Configuration and result types

```python
@dataclass
class AssetValidationConfig:
    asset_path:      str       # path to .usd / .usda file
    profile_id:      str | None = None   # None → infer from USD metadata
    profile_version: str | None = None   # None → any registered version
    write_metadata:  bool = False         # stamp results into USD on full pass

@dataclass
class AssetValidationResult:
    asset_path:       str
    profile_id:       str
    profile_version:  str
    features_summary: dict[str, dict]   # feature_id → {version, passed, failing requirements}
    issues:           list              # raw failing issues from the engine
```

### Batch validation with JSON report

```python
configs = [
    sv.AssetValidationConfig(asset_path=str(p), profile_id="Prop-Robotics-Neutral")
    for p in Path("/assets").rglob("*.usd")
]

results = sv.validate_asset_list(configs, report_file_path="/reports/validation.json")

n_passed = sum(
    1 for r in results
    if r and all(f["passed"] for f in r.features_summary.values())
)
print(f"{n_passed}/{len(configs)} passed")
```

The JSON report is **merged** — new results for the same asset path override existing entries;
other entries are preserved. The parent directory must exist before calling.

---

## CLI

The `simready-validate` command is included with the package.

```bash
# Validate a single asset
simready-validate \
  --rules-path /specs/capabilities \
  --features-path /specs/features \
  --profiles-path /specs/profiles/profiles.toml \
  --profile Prop-Robotics-Neutral --version 2.0.0 \
  /assets/crate_01.usd

# Validate a list of assets and save a JSON report
simready-validate \
  --rules-path /specs/capabilities \
  --features-path /specs/features \
  --profiles-path /specs/profiles/profiles.toml \
  --profile Prop-Robotics-Neutral \
  --output /reports/results.json \
  --asset_list assets.txt

# Stamp results into the USD on a full pass
simready-validate ... --stamp-asset-validation /assets/crate_01.usd
```

| Flag | Description |
|------|-------------|
| `ASSET_PATH` | Single `.usd` / `.usda` file to validate |
| `--asset_list FILE` | Text file, one asset path per line |
| `--profile ID` | Profile to validate against (omit to infer from USD metadata) |
| `--version VER` | Profile version (requires `--profile`) |
| `--stamp-asset-validation` | Write results into USD `customLayerData` on full pass |
| `--output JSON` | Append results to a JSON report file |
| `--rules-path` / `--features-path` / `--profiles-path` | Load spec data from local paths (repeatable) |
| `-v` / `--verbose` | Per-issue detail on failure + DEBUG logging |

Exit code: `0` = all passed, `1` = any failed or not found.

---

## Metadata ownership

`simready.validate` owns only the `validation` sub-key of `SimReady_Metadata` in the USD
`customLayerData`. It never reads or writes `runtime_tests`, `asset_id`, or any other section.

```
customLayerData["SimReady_Metadata"]
├── asset_id        <- simready.create
├── validation      <- simready.validate
└── runtime_tests   <- simready.test
```

---

## License

Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
