feat(python): add PackageData.from_rez(pkg) convenience#79
Merged
Conversation
The integration site for rez was eight lines of boilerplate per
package — `pyrer.PackageData(name=..., version=str(pkg.version),
requires=[str(r) for r in (pkg.requires or [])], variants=[[str(r)
for r in v] for v in (pkg.variants or [])])`. Same body every time.
Ship that as a classmethod on `PackageData` so the call site is one
line:
pkg_data = pyrer.PackageData.from_rez(pkg)
## Implementation
`#[classmethod] from_rez(_cls, pkg: &Bound<'_, PyAny>)` reads four
attributes off `pkg` via PyO3 duck typing — `pyrer` still does not
import `rez`, so any object exposing `name` / `version` / `requires`
/ `variants` works (tests use plain Python classes, no rez install
needed).
Handles, in one place:
- `version` → `str(version)` (rez's `Version` is not a `str`).
- Each `Requirement` in `requires` and inside each `variants` entry
→ `str(req)` (rez's `Requirement` likewise renders via `__str__`).
- `requires is None` and `variants is None` → empty list (rez models
"no requires" as `None`, not `[]`).
- Missing one of the four attributes → `AttributeError` from PyO3
surfaces naturally; the user knows immediately which object is
wrong.
Two small private helpers (`read_requirement_list`,
`read_variants_list`) share the iteration logic so both the top-level
`requires` and each variant entry go through the same code.
## Tests
Six new cases in `tests/test_rich_api.py`:
- plain attribute access (str fields, list-of-str requires)
- `requires`/`variants` is `None` → empty
- requirement-object `__str__` is honoured
- version-object `__str__` is honoured
- missing attribute raises `AttributeError`
- end-to-end: `from_rez` → `solve` produces the same result as the
four-field constructor
All 72 Python tests (7 + 58 + 14) pass.
## Docs
`README.md` and `rez-integration.md` integration recipes shrink from
8 lines of conversion to a one-line `PackageData.from_rez(pkg)` call.
The `pyrer`-doesn't-import-rez note is kept so users on non-rez
pipelines know the constructor is still there for them.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #78. The integration site for rez was eight lines of boilerplate per package:
```python
pyrer.PackageData(
name=fam.name,
version=str(pkg.version),
requires=[str(r) for r in (pkg.requires or [])],
variants=[[str(r) for r in v] for v in (pkg.variants or [])],
)
```
Same body every time. Ship it as a classmethod on `PackageData` so the call site collapses to one line:
```python
pyrer.PackageData.from_rez(pkg)
```
Implementation
`#[classmethod] from_rez(cls, pkg: &Bound<', PyAny>)` reads four attributes off `pkg` via PyO3 duck typing — `pyrer` still does not import `rez`, so any object exposing `name` / `version` / `requires` / `variants` works (tests use plain Python classes, no rez install needed).
Handles in one place:
Two small private helpers (`read_requirement_list`, `read_variants_list`) share the iteration logic.
Tests
Six new cases in `tests/test_rich_api.py`:
72 / 72 Python tests pass (7 + 58 + 14).
Docs
`README.md` and `rez-integration.md` integration recipes shrink from eight lines of conversion to a one-line `PackageData.from_rez(pkg)` call. The `pyrer`-doesn't-import-rez note stays so users on non-rez pipelines know the constructor is still available for them.
🤖 Generated with Claude Code