fix(update_pyproject_dependencies): handle '- pip:' dict deps in lower-bound yaml#174
fix(update_pyproject_dependencies): handle '- pip:' dict deps in lower-bound yaml#174ligerzero-ai wants to merge 1 commit into
Conversation
`load_yaml` iterates `data["dependencies"]` and calls
`split_dependency(dependency, "=", allow_no_version=True)` on each
entry. When a yaml conda env contains a `- pip:` block (PyPI-only
deps installed by conda's pip backend) the entry is a dict
(`{"pip": ["pkg==X.Y.Z", ...]}`) and `split_dependency`'s
`dependency.replace(" ", "")` raises
AttributeError: 'dict' object has no attribute 'replace'
This blocks the release workflow for any consumer that has
PyPI-only dependencies — for example, pyiron_workflow_lammps
(already carrying a local fork of this file in main) and
pyiron_workflow_atomistics (which depends on `lz-GB-code` via
pip on the v0.0.5 release we just attempted).
Patched `load_yaml` to detect a dict entry, look for a `pip:` key,
descend into the list, and parse the `==`-pinned entries via the
existing `split_dependency` helper. Non-pip dict entries raise a
clear ValueError pointing at the offending yaml file and entry.
The lammps fix uses `type(dependency) == dict` and
`"pip" in dependency.keys()`; cleaned up to `isinstance` and
plain `in` to satisfy ruff E721/SIM118 if anyone adds linting
to this script later.
Tested locally against pyiron_workflow_atomistics'
`.ci_support/lower_bound.yml` (16 bounds parsed correctly,
including `lz-GB-code==0.1.0` from the `- pip:` block) and a
synthetic yaml containing `[{"foobar": ["x"]}]` (raises the
new ValueError).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the existing pyiron/pyiron_workflow_lammps@main fix: forks .support/update_pyproject_dependencies.py and pyproject-release.yml locally with a dict-aware load_yaml() that descends into '- pip:' blocks. Unblocks the v0.0.5 PyPI release workflow, which crashed on the existing 'lz-GB-code==0.1.0' pip dependency in lower_bound.yml. Once pyiron/actions#174 lands and a new actions tag is cut, the local fork can be reverted in a follow-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
push-pull.yml wires to pyiron/actions@actions-4.0.8. release.yml uses a local fork of pyproject-release.yml + update_pyproject_dependencies.py that handles '- pip:' dict deps in lower-bound.yml (the upstream script crashes on this; fix proposed at pyiron/actions#174). Copied verbatim from pyiron_workflow_atomistics post-#35. .ci_support/environment.yml + lower-bound.yml pin the same versions as atomistics 0.0.5 so pip-check + the release-bounds script align. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
If I understand, the changes here are chronologically behind and not as well linted. Could you propagate those improvements here? @ligerzero-ai, I'm not familiar enough with everything we do in this repo to just read our code and then be like "yes, this will work", so what I usually do is point some PR that needs the change I'm making at the branch here and just make sure it works. It sounds like you basically already went through that process downstream with your forking, but that post is also AI so I just want some clarification that this has actually happened and succeeded. Finally, the release process on this repo is not used terribly often and not very friendly. From here, you'll want to:
Then whatever test repo you were pointing at the branch just keeps seamlessly working because now it's pointed at a release tag. |
|
@liamhuber yes, I had meant to write to you about this earlier (last year) but I had forgotten it. We had discussed the prospect of supporting the C.I. actions with pip-only packages, and this was the solution that I came up with at that time (I think October(?)) This is simply the AI summary of the fix. THe problem is that the current actions parses a dictionary that doesn't allow for the extra block below with pip-only installs in the environment.yml or something like that. I added functionality to parse the dictionary. I told the AI to look for it and propagate it back upstream, which is why this post exists. |
Problem
`load_yaml` in `.support/update_pyproject_dependencies.py` iterates the yaml's `dependencies` list and calls `split_dependency` on every entry. `split_dependency` does `dependency.replace(" ", "").split("=")` — which crashes when an entry is a dict instead of a string:
```
File "...update_pyproject_dependencies.py", line 126, in split_dependency
split = dependency.replace(" ", "").split(delimiter)
AttributeError: 'dict' object has no attribute 'replace'
```
This happens for any consumer with a `- pip:` block in its conda env yaml (PyPI-only deps installed via conda's pip backend) — for example:
```yaml
channels:
dependencies:
...
```
The current code parses the conda entries fine but explodes on the `- pip:` dict entry, blocking the release workflow.
Affected repos I know about:
Fix
Detect dict-typed entries; if the key is `pip`, descend into the value list and parse `==`-pinned entries via the same `split_dependency` helper. Any other dict key raises a clear `ValueError` naming the yaml file and the offending entry.
Diff (single function, no other touches):
```diff
yaml_bounds = {}
for dependency in data["dependencies"]:
```
Behavioural notes:
Notes vs. the lammps repo fork
The fork in `pyiron/pyiron_workflow_lammps@main:.github/actions/.support/update_pyproject_dependencies.py` carries the same logical fix but uses `type(dependency) == dict` and `"pip" in dependency.keys()`. I changed those to `isinstance(...)` / `"pip" in dependency` (ruff E721 / SIM118), and dropped two stray `print()` calls that look like leftover debug output. No semantic difference.
Test plan
Local smoke test against `pyiron_workflow_atomistics/.ci_support/lower_bound.yml`:
```
$ python -c "
import sys; sys.path.insert(0, '.support')
import update_pyproject_dependencies as m
bounds = m.load_yaml('.../lower_bound.yml')
print(bounds.get('lz-GB-code')) # 0.1.0 — captured from the pip: block
print(bounds.get('numpy')) # 1.22.0 — captured from the conda block
"
```
→ OK; 16 bounds parsed; `lz-GB-code` correctly picked up from the `- pip:` block.
Negative-case smoke (synthetic yaml with a non-`pip` dict entry):
```
$ python -c "import update_pyproject_dependencies as m; m.load_yaml('/tmp/bad.yml')"
ValueError: Unsupported dict-typed dependency entry in '/tmp/bad.yml': {'foobar': ['x']}. Only `pip:` sub-lists are recognised.
```
→ OK; raises clearly.
After this lands
I'll undo the local fork in `pyiron_workflow_atomistics` (PR pyiron/pyiron_workflow_atomistics#35) by reverting back to `uses: pyiron/actions/.github/workflows/pyproject-release.yml@`. Same option opens up for lammps.
🤖 Generated with Claude Code