Skip to content

ci: pin pyproject2conda==0.22.1 to work around 0.23.0 regression#878

Merged
drbenvincent merged 2 commits into
mainfrom
ci/pin-pyproject2conda
Apr 30, 2026
Merged

ci: pin pyproject2conda==0.22.1 to work around 0.23.0 regression#878
drbenvincent merged 2 commits into
mainfrom
ci/pin-pyproject2conda

Conversation

@drbenvincent
Copy link
Copy Markdown
Collaborator

@drbenvincent drbenvincent commented Apr 30, 2026

Summary

The check-environment-yml CI job has been failing on every PR opened since 2026-04-29 with:

File ".../pyproject2conda/_normalized_requirements.py", line 115, in _iter_parts
    if self.channel:
       ^^^^^^^^^^^^
AttributeError: 'CondaRequirement' object has no attribute 'channel'

Root cause

The job does pip install pyproject2conda with no version constraint (ci.yml:51-52), so each CI run grabs whatever is latest on PyPI.

pyproject2conda 0.23.0 was published to PyPI on 2026-04-29 and contains a regression where CondaRequirement instances no longer expose the channel attribute that _iter_parts() still tries to read. This is hit during __hash__ of any conda requirement, so the tool blows up immediately when called with the args our workflow uses.

The local prek hook in .pre-commit-config.yaml is already pinned to v0.22.1 (the last good release), so local prek run --all-files is unaffected — only CI breaks.

Filed upstream as usnistgov/pyproject2conda#94.

Fix

Pin the CI pip install to >=0.22.1,<0.23 so it tracks the same 0.22.x line as the local prek hook (rev: v0.22.1) while still allowing a hypothetical 0.22.x patch backport to ship without a workflow edit. Added an inline comment explaining the failure mode so future bumps remember to lift CI and the prek hook in lockstep.

Why pin instead of work around?

The traceback lands in CondaRequirement.__hash___iter_parts(), which is invoked unconditionally as soon as pyproject2conda materialises any conda requirement. There is no plausible CLI flag, env extra, or pyproject.toml shape change that avoids that code path while still producing a usable conda yaml — the broken attribute access fires before any of our arguments matter. Pinning is therefore the right lever; alternative workarounds were not pursued because they cannot exist for this failure mode.

Evidence this is environmental, not PR-specific

Test plan

Follow-up

When pyproject2conda ships a fixed release, bump both .pre-commit-config.yaml (rev: v0.22.1 → newer) and .github/workflows/ci.yml (the version range → newer) together — or, preferably, merge #882 first so there is only one place to bump.

Tracked separately:

The check-environment-yml job does `pip install pyproject2conda` with no
version constraint, so each CI run grabs the latest release from PyPI.

pyproject2conda 0.23.0 was published on 2026-04-29 and regressed with:

    AttributeError: 'CondaRequirement' object has no attribute 'channel'

raised from `_normalized_requirements._iter_parts` during the call to
`pyproject2conda yaml ...`. This breaks the job for every PR opened
since 2026-04-29, regardless of whether the PR touches pyproject.toml
or environment.yml.

Pin the CI install to v0.22.1 to match the rev already pinned for the
local prek hook in .pre-commit-config.yaml. The two should be bumped
together once a fixed pyproject2conda release is available.

Made-with: Cursor
@drbenvincent drbenvincent requested a review from maresb April 30, 2026 12:33
@drbenvincent drbenvincent added bug Something isn't working devops DevOps related labels Apr 30, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.60%. Comparing base (deb8774) to head (0de4a8e).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #878   +/-   ##
=======================================
  Coverage   94.60%   94.60%           
=======================================
  Files          80       80           
  Lines       12764    12764           
  Branches      770      770           
=======================================
  Hits        12076    12076           
  Misses        485      485           
  Partials      203      203           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@read-the-docs-community
Copy link
Copy Markdown

read-the-docs-community Bot commented Apr 30, 2026

Documentation build overview

📚 causalpy | 🛠️ Build #32484936 | 📁 Comparing 0de4a8e against latest (deb8774)

  🔍 Preview build  

1 file changed
± 404.html

Replaces the strict ==0.22.1 pin with a range pin so a hypothetical
0.22.x patch backport can ship without a workflow edit, while still
excluding the 0.23.x line that broke us.

Also drops the release date from the inline comment (the version
identifier 0.23.0 is the durable reference; git blame recovers the
date) and expands the explanation of the failure mode for future
readers.

Made-with: Cursor
@drbenvincent
Copy link
Copy Markdown
Collaborator Author

Updated this PR off the back of an adversarial review. Two changes in 0de4a8e:

  1. Widened the pin from ==0.22.1 to >=0.22.1,<0.23. The strict equality was unnecessarily rigid — if upstream ever ships a 0.22.2 patch backport (e.g. a security fix), the range pin picks it up automatically while still excluding the broken 0.23.x line. The lower bound matches the prek hook's rev: v0.22.1; the upper bound is the meaningful one.

  2. Dropped the hardcoded release date from the inline comment (released 2026-04-29). The version identifier 0.23.0 is the durable reference and git blame recovers the date if anyone needs it. Replaced that line with a more useful description of the failure mode (_iter_parts__hash__) so future readers can tell at a glance whether a new release has actually fixed the right thing.

Also added a "Why pin instead of work around?" section to the PR body. Short version: the regression is in CondaRequirement.__hash__, which fires as soon as conda requirements are processed — there is no CLI flag or pyproject.toml shape that avoids that code path, so pinning is the only real lever and alternative workarounds were not pursued.

Follow-ups that came out of the review have been filed as separate issues / will be opened as a follow-up PR; links will be added to the PR body's "Follow-up" section as they land.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working devops DevOps related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants