Skip to content

fix: make identity_attributes/source_path_attributes classmethods#15

Merged
johanneskoester merged 3 commits into
snakemake:mainfrom
jiangyun-fun:fix/classmethod-identity-attributes
Jun 28, 2026
Merged

fix: make identity_attributes/source_path_attributes classmethods#15
johanneskoester merged 3 commits into
snakemake:mainfrom
jiangyun-fun:fix/classmethod-identity-attributes

Conversation

@jiangyun-fun

@jiangyun-fun jiangyun-fun commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Problem

EnvSpec.identity_attributes and EnvSpec.source_path_attributes are defined as instance methods (self), but the interface base (snakemake_interface_software_deployment_plugins.EnvSpecBase) and the sibling plugins (conda, container) declare them as @classmethod (cls).

Impact

EnvSpecBase.__hash__ -> managed_identity_attributes() (a classmethod) calls cls.identity_attributes(). Because this plugin's identity_attributes is an instance method, that call raises:

TypeError: EnvSpec.identity_attributes() missing 1 required positional argument: 'self'

So every envmodules spec is unhashable. Anywhere a spec is used as a dict key or set member it crashes — in particular SoftwareDeploymentManager.get_env() does if env_spec in self.specs_to_envs:, which hashes the spec. This breaks standalone envmodules(...) usage and the fallback chain envmodules(...) or conda(...) (the headline composition form).

Fix

Make both methods @classmethod, matching the interface and the other plugins:

@classmethod
def identity_attributes(cls) -> Iterable[str]:
    yield "names"

@classmethod
def source_path_attributes(cls) -> Iterable[str]:
    return ()

Neither body uses self, so this is a drop-in fix.

Verification

After the change, envmodules specs are hashable (hash(spec) succeeds) and get_env() no longer crashes on the fallback path.

Context: snakemake/snakemake#4209; related interface fix: snakemake/snakemake-interface-software-deployment-plugins#58.

Summary by CodeRabbit

  • Bug Fixes
    • Improved environment identity and source-path attribute handling, making environment identification and hashing more consistent.
    • Fixed shell command generation to correctly load and quote module names containing unsafe characters (e.g., spaces).
    • Ensured environment specifications implement correct equality and hashing, including reliable dictionary-key usage.
  • Tests
    • Added unit tests to cover environment identity attributes, string formatting, hashing/record hashing, and decorated shell command behavior.

These were defined as instance methods (self), but the interface base and
the other plugins (conda, container) declare them as @classmethod (cls).
As instance methods they broke __hash__ (managed_identity_attributes calls
cls.identity_attributes()), so any envmodules spec crashed when used as a
dict key -- e.g. in the fallback chain `envmodules(...) or conda(...)`,
where get_env() looks the spec up in specs_to_envs. The bodies do not use
self, so making them classmethods is a drop-in fix.
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7b3cfd53-757b-4de0-8988-611451c81bbc

📥 Commits

Reviewing files that changed from the base of the PR and between 7b3bc51 and f33739a.

📒 Files selected for processing (1)
  • tests/test_plugin.py
💤 Files with no reviewable changes (1)
  • tests/test_plugin.py

📝 Walkthrough

Walkthrough

EnvSpec attribute providers were converted to class methods. Tests were added for EnvSpec formatting, identity, hashing, shell command decoration, hash recording, and software reporting.

Changes

EnvSpec and Env behavior

Layer / File(s) Summary
EnvSpec attribute providers
src/snakemake_software_deployment_plugin_envmodules/__init__.py
EnvSpec.identity_attributes and EnvSpec.source_path_attributes are class methods and keep returning names and no source-path attributes.
EnvSpec and Env tests
tests/test_plugin.py
Adds imports, helpers, and assertions for EnvSpec formatting, identity, hashing, dictionary-key use, Env.decorate_shellcmd, Env.record_hash, and Env.report_software.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning This PR fixes EnvSpec classmethods and hashability in envmodules, but it does not implement #58's concrete Env/EnvSpec loading in load_plugin(). Update SoftwareDeploymentPluginRegistry.load_plugin() to use module.Env and module.EnvSpec, and verify plugin.env_spec_cls resolves to the concrete class.
Out of Scope Changes check ⚠️ Warning The patch centers on envmodules hashability and test coverage, which is outside #58's concrete plugin-loading requirement. Split the hashability regression fix into a separate PR, or change the patch to address the plugin registry's concrete class loading.
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main code change: converting EnvSpec methods to classmethods.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@johanneskoester

Copy link
Copy Markdown
Contributor

@jiangyun-fun do you want to add some additional tests to raise the coverage?

Adds unit tests for EnvSpec (names, __str__, identity_attributes,
source_path_attributes, __hash__/__eq__, dict-key usability) and the pure
Env methods (decorate_shellcmd, record_hash, report_software). The hash tests
guard the classmethod fix. Coverage rises from 64.86% to 83.78%, clearing the
fail-under=70 gate. Env.check/__post_init__/contains_executable stay uncovered
as they require a live `module` command.
@jiangyun-fun

Copy link
Copy Markdown
Contributor Author

Thanks, @johanneskoester! Done as requested — coverage is now ~84% (clears the gate); the hash tests guard the classmethod fix.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_plugin.py`:
- Around line 99-108: The test in test_envspec_hash_and_equality_use_names is
asserting a stronger hash contract than Python guarantees by checking hash(a) !=
hash(c) for unequal objects. Remove that assertion and update the test to
validate distinctness through the existing equality semantics in _spec and
EnvSpec hashing, for example by asserting the set size for a, b, and c instead
of requiring different hash values for non-equal instances.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1d1fde9e-4aba-4bb7-850b-cb2aa54d3b7c

📥 Commits

Reviewing files that changed from the base of the PR and between 195f695 and 7b3bc51.

📒 Files selected for processing (2)
  • src/snakemake_software_deployment_plugin_envmodules/__init__.py
  • tests/test_plugin.py

Comment thread tests/test_plugin.py
Comment thread tests/test_plugin.py Outdated
Removed the test for reporting empty software in the environment.
@johanneskoester johanneskoester enabled auto-merge (squash) June 28, 2026 14:09
@johanneskoester johanneskoester merged commit 58af01a into snakemake:main Jun 28, 2026
5 of 6 checks passed
johanneskoester pushed a commit that referenced this pull request Jun 28, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.2.1](v0.2.0...v0.2.1)
(2026-06-28)


### Bug Fixes

* make identity_attributes/source_path_attributes classmethods
([#15](#15))
([58af01a](58af01a))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants