Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 22 additions & 46 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,73 +6,49 @@ on:
- main
pull_request:

env:
PYTHON_VERSION: 3.11

jobs:
linting:
formatting:
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v3

- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install poetry
run: pip install poetry
uses: actions/checkout@v5

- name: Determine dependencies
run: poetry lock

- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: poetry

- name: Install Dependencies using Poetry
run: poetry install
- name: Setup pixi
uses: prefix-dev/setup-pixi@v0

- name: Check formatting
run: poetry run ruff format --check .

- name: Lint
run: poetry run ruff check .
run: pixi run format --check .

testing:
linting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Check out the code
uses: actions/checkout@v5

- name: Install poetry
run: pip install poetry
- name: Setup pixi
uses: prefix-dev/setup-pixi@v0

- name: Determine dependencies
run: poetry lock
- name: Check code
run: pixi run lint

- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: poetry
testing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Install dependencies
run: poetry install
- name: Setup pixi
uses: prefix-dev/setup-pixi@v0

- name: Setup envmodules
run: |
sudo apt-get update
sudo apt-get install -y environment-modules

- name: Run pytest
shell: bash -el {0}
run: |
source /etc/profile.d/modules.sh
module --help
poetry run coverage run -m pytest
command -v module
pixi run test -v

- name: Run Coverage
run: poetry run coverage report -m
run: pixi run coverage-report
33 changes: 10 additions & 23 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,23 @@ jobs:
id: release
with:
release-type: python
package-name:

publish:
runs-on: ubuntu-latest
needs: release-please
if: ${{ needs.release-please.outputs.release_created }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v5

- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install poetry
run: pip install poetry

- name: Determine dependencies
run: poetry lock
- name: Setup pixi
uses: prefix-dev/setup-pixi@v0

- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: poetry

- name: Install Dependencies using Poetry
- name: Build source and wheel distribution + check build
run: |
poetry install
pixi run check-build

- name: Publish to PyPi
env:
PYPI_USERNAME: __token__
PYPI_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: poetry publish --build --username $PYPI_USERNAME --password $PYPI_PASSWORD
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_TOKEN }}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,4 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

poetry.lock
pixi.lock
77 changes: 59 additions & 18 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,26 +1,67 @@
[project]
name = "snakemake-software-deployment-plugin-envmodules"
version = "0.1.4"
description = ""
authors = [{ name = "Johannes Köster", email = "johannes.koester@uni-due.de" }]
description = "Software deployment plugin for Snakemake using environment modules."
readme = "README.md"
requires-python = ">=3.11,<4.0"
dependencies = ["snakemake-interface-software-deployment-plugins >=0.6.1,<1.0.0"]
repository = "https://github.com/your/plugin"
dependencies = [
"snakemake-interface-common (>=1.17.4,<2.0.0)",
"snakemake-interface-software-deployment-plugins (>=0.7.7,<1.0)",
]

[tool.pixi.pypi-dependencies]
snakemake-software-deployment-plugin-envmodules = { path = ".", editable = true }
#snakemake-interface-software-deployment-plugins = { path = "../snakemake-interface-software-deployment-plugins", editable = true }

[project.urls]
repository = "https://github.com/snakemake/snakemake-software-deployment-plugin-envmodules"
documentation = "https://snakemake.github.io/snakemake-plugin-catalog/plugins/software-deployment/envmodules.html"
[[project.authors]]
name = "Johannes Koester"
email = "johannes.koester@uni-due.de"

[build-system]
requires = [ "poetry-core>=2.0.0,<3.0.0",]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
[[tool.poetry.packages]]
include = "snakemake_software_deployment_plugin_envmodules"
from = "src"

[tool.poetry.group.dev.dependencies]
coverage = "^7.6.12"
pytest = "^8.3.5"
ruff = "^0.9.9"
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.pixi.project]
channels = ["conda-forge"]
platforms = ["osx-arm64", "linux-64"]

[tool.pixi.environments]
dev = { features = ["dev"] }
publish = { features = ["publish"] }

[tool.pixi.feature.dev.dependencies]
pytest = ">=8.3.5,<9"
ruff = ">=0.10.0,<0.11"
pytest-cov = ">=6.0.0,<7"

[tool.pixi.feature.dev.tasks]
format = "ruff format"
lint = "ruff check"
qc = { depends-on = ["format", "lint"] }
coverage-report = "coverage report -m"

[tool.pixi.feature.dev.tasks.test]
cmd = [
"pytest",
"--cov=snakemake_software_deployment_plugin_envmodules",
"--cov-report=xml:coverage-report/coverage.xml",
"--cov-report=term-missing",
"tests/test_plugin.py",
]

[tool.coverage.report]
exclude_lines = ["pass", "\\.\\.\\."]
fail_under = 70.0

# Publish
[tool.pixi.feature.publish.dependencies]
twine = ">=6.1.0,<7"
python-build = ">=1.2.2,<2"


[tool.pixi.feature.publish.tasks]
build = { cmd = "python -m build", description = "Build the package into the dist/ directory" }
check-build = { cmd = "python -m twine check dist/*", depends-on = [
"build",
], description = "Check that the package can be uploaded" }
17 changes: 11 additions & 6 deletions src/snakemake_software_deployment_plugin_envmodules/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Iterable, Tuple
import shlex
from typing import Iterable
import subprocess as sp
from snakemake_interface_software_deployment_plugins import (
EnvBase,
Expand All @@ -15,7 +16,7 @@
class EnvSpec(EnvSpecBase):
def __init__(self, *names: str):
super().__init__()
self.names: Tuple[str] = names
self.names: tuple[str, ...] = tuple(names)

def identity_attributes(self) -> Iterable[str]:
# The identity of the env spec is given by the names of the modules.
Expand All @@ -25,6 +26,9 @@ def source_path_attributes(self) -> Iterable[str]:
# no paths involved here
return ()

def __str__(self) -> str:
return ",".join(self.names)


class Env(EnvBase):
def __post_init__(self):
Expand All @@ -33,19 +37,20 @@ def __post_init__(self):

@EnvBase.once
def check(self) -> None:
if self.run_cmd("type module", stdout=sp.PIPE, stderr=sp.PIPE).returncode != 0:
res = self.run_cmd("type module", stdout=sp.PIPE, stderr=sp.STDOUT)
if res.returncode != 0:
raise WorkflowError(
"The module command is not available. "
"Please make sure that the environment modules are "
"available on your system."
"Please make sure that environment modules are "
f"available on your system: {res.stdout.decode()}"
)

def decorate_shellcmd(self, cmd: str) -> str:
# Decorate given shell command such that it runs within the environment.
# Unclear why that happens.
# one might have to say 'shopt -s expand_aliases;', but that did not
# help either...
return f"module purge && module load {' '.join(self.spec.names)}; {cmd}"
return f"module purge && module load {' '.join(shlex.quote(name) for name in self.spec.names)} && {cmd}"

def record_hash(self, hash_object) -> None:
# We just hash the names here as the best thing we can do for envmodules
Expand Down
18 changes: 15 additions & 3 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import os
from typing import Optional, Type
from snakemake_interface_software_deployment_plugins import EnvBase
from snakemake_interface_software_deployment_plugins import EnvBase, EnvSpecBase
from snakemake_interface_software_deployment_plugins.tests import (
TestSoftwareDeploymentBase,
)
from snakemake_interface_software_deployment_plugins.settings import (
SoftwareDeploymentSettingsBase,
)
from snakemake_software_deployment_plugin_envmodules import Env, EnvSpec, EnvSpecBase
from snakemake_software_deployment_plugin_envmodules import Env, EnvSpec

os.environ["MODULEPATH"] = "tests/modules"


class TestSoftwareDeployment(TestSoftwareDeploymentBase):
class Test(TestSoftwareDeploymentBase):
__test__ = True # activate automatic testing
shell_executable = ["bash", "-l", "-c"]

def get_software_deployment_provider_settings(
self,
Expand All @@ -30,6 +31,17 @@ def get_env_spec(self) -> EnvSpecBase:
# testing.
return EnvSpec("somecmd")

def get_settings_cls(self) -> Optional[Type[SoftwareDeploymentSettingsBase]]:
# Return the settings class that should be used for this plugin.
return None

def get_settings(
self,
) -> Optional[SoftwareDeploymentSettingsBase]:
# If your plugin has settings, return a valid settings object here.
# Otherwise, return None.
return None

def get_test_cmd(self) -> str:
# Return a command that should be executable without error in the environment
return "somecmd"