Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate component create to nf test #2490

Merged
merged 119 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
5283677
generalize nextflow_cmd to run_cmd to use the same structure for nf-test
mashehu Oct 24, 2023
0081766
initial changes for nf-test
mashehu Oct 24, 2023
d9126e5
move tags.yml to correct position
mashehu Oct 24, 2023
ecda687
Update nf_core/utils.py
mashehu Oct 24, 2023
955321b
convert all cmds
mashehu Oct 24, 2023
0a4afac
first running version
mashehu Oct 24, 2023
ca233d1
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Oct 24, 2023
86613b6
replace params
mashehu Oct 24, 2023
e0c30cd
fix typing errors
mashehu Oct 24, 2023
a9f55ba
add TODO comments to main.nf.test and fix tags.yml template rendering
mirpedrol Oct 25, 2023
865d613
add todo comment for chained modules
mirpedrol Oct 25, 2023
d767c78
add real example to main.nf.test
mirpedrol Oct 26, 2023
876eab3
add tags.yml to prettierignore
mirpedrol Oct 26, 2023
3b9f031
add main.nf.test to template instead of using nf-test
mirpedrol Oct 26, 2023
79215fb
generalize nextflow_cmd to run_cmd to use the same structure for nf-test
mashehu Oct 24, 2023
7cab286
initial changes for nf-test
mashehu Oct 24, 2023
f41d410
move tags.yml to correct position
mashehu Oct 24, 2023
cbc398a
convert all cmds
mashehu Oct 24, 2023
8d7794a
first running version
mashehu Oct 24, 2023
1a58690
replace params
mashehu Oct 24, 2023
86db72b
fix typing errors
mashehu Oct 24, 2023
7a7fd93
add TODO comments to main.nf.test and fix tags.yml template rendering
mirpedrol Oct 25, 2023
11773ef
add todo comment for chained modules
mirpedrol Oct 25, 2023
eafb3b5
add real example to main.nf.test
mirpedrol Oct 26, 2023
56086c6
add tags.yml to prettierignore
mirpedrol Oct 26, 2023
63c3188
add main.nf.test to template instead of using nf-test
mirpedrol Oct 26, 2023
4038131
modules create tests check for main.nf.test
mirpedrol Oct 31, 2023
43bf218
remove outputDir from the modules template
mirpedrol Oct 31, 2023
4ffc3cf
add nf-test to subworkflows
mirpedrol Oct 31, 2023
db10253
subworkflows create tests check for main.nf.test
mirpedrol Oct 31, 2023
a3eae4d
Merge branch 'migrate-component-create-to-nf_test' of https://github.…
mirpedrol Oct 31, 2023
80ddddb
fix tags for subtools, add version assertion to template
mashehu Nov 1, 2023
617010e
fix quotes in templates
mashehu Nov 1, 2023
04efb40
add first version of the `create-snapshot` command
mashehu Nov 1, 2023
71c441c
install all type specific dependencies in CI step
mashehu Nov 1, 2023
a7cfdd5
add new command 🙃
mashehu Nov 2, 2023
d6b9f6c
remove tests for modules create_test_yml
mashehu Nov 2, 2023
6b0ff49
remove more mentions of test_yml_builder
mashehu Nov 2, 2023
0045d4d
add types to create-snapshot and use component_type
mirpedrol Nov 2, 2023
61459f5
add subworkflows create-snapshot
mirpedrol Nov 2, 2023
6b63566
add linting for snapshot file
mashehu Nov 6, 2023
73487dd
add correct tags to subworkflow template
mashehu Nov 6, 2023
cdf5f63
fix smaller things according to mypy
mashehu Nov 6, 2023
a1743cd
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 6, 2023
bff7e89
add pytests for components snapshot generator
mirpedrol Nov 7, 2023
2f5312a
add more typing
mashehu Nov 7, 2023
ef52c75
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 7, 2023
f42fe20
run create-snapshot tests from modules root directory
mirpedrol Nov 7, 2023
6ef6268
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 7, 2023
e79d4d3
fix checking if PROFILE exists
mirpedrol Nov 7, 2023
c7bc5b7
add new environment.yml setup to template according to #2495
mashehu Nov 8, 2023
3f46c16
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 8, 2023
53b23b7
use set_wd for tests
mirpedrol Nov 8, 2023
c4683f0
check md5sums and add snapshot test for a subworkflow
mirpedrol Nov 8, 2023
2a640cc
append error messages to self.errors
mashehu Nov 8, 2023
fa0c6f3
add --dir option to create-snapshot command
mirpedrol Nov 8, 2023
f5ddc64
add no test found error and test for this
mirpedrol Nov 9, 2023
163019d
add test for unstable snapshot
mirpedrol Nov 9, 2023
8ebf36a
don't assert run() function from snapshot generator
mirpedrol Nov 9, 2023
749ba53
Update tests/components/create_snapshot.py
mirpedrol Nov 9, 2023
b1b57d3
add linting code for environemnt.yml
mashehu Nov 13, 2023
5aad9c4
add hint for language server, update to new new for schema file
mashehu Nov 13, 2023
aaa5945
add types
mashehu Nov 13, 2023
9fe1c3e
add schema based validation to environment yaml linting, add tests
mashehu Nov 13, 2023
92fd677
Merge branch 'dev' into migrate-component-create-to-nf_test
mashehu Nov 13, 2023
2d51ff8
fix mypy
mashehu Nov 13, 2023
74139bd
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 13, 2023
54bb5b6
fix type error
mashehu Nov 13, 2023
28c1c76
add nf-test dependency
mashehu Nov 13, 2023
dc7a330
install nf-test for ci
mashehu Nov 13, 2023
1ce81c0
switch bump_version to use environemt.yml
mashehu Nov 14, 2023
32ef61b
update modules in pipeline template
mashehu Nov 14, 2023
ab113c7
fix test for updated snapshot
mashehu Nov 14, 2023
bec4bb3
test for name mismatch in environment.yml
mashehu Nov 14, 2023
0622fbc
make nicer diff for nf-test error
mashehu Nov 14, 2023
4c30da3
fix error in download test
mashehu Nov 14, 2023
2ca1764
don't convert arrays to strings in licence field
mashehu Nov 14, 2023
6e2dc70
add nf-test to CI
mashehu Nov 14, 2023
cb175e7
fix environment.yml linting
mashehu Nov 14, 2023
38d9db7
rely on environment.yml for bioconda versions
mashehu Nov 14, 2023
91c24e6
fix tests
mashehu Nov 14, 2023
dc6d033
fix types
mashehu Nov 14, 2023
d82bf66
remove subworkflows test_yml_builder and fix subworkflow tests
mirpedrol Nov 15, 2023
24ff636
fix nf-test setup in CI
mashehu Nov 15, 2023
20ae7b1
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 15, 2023
72a78c0
fix assertion value
mashehu Nov 15, 2023
d687430
handle local modules without nf-test
mashehu Nov 15, 2023
f673a89
add linting for nf-test and remove linting for pytests
mirpedrol Nov 15, 2023
bb070c6
fix linting components errors
mirpedrol Nov 15, 2023
e19a4a2
remove tmp dir manually if we find a PermissionError
mirpedrol Nov 16, 2023
5e02619
fix launch tests, move tmp pipeline creation to utils to share betwee…
mashehu Nov 16, 2023
316055f
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 16, 2023
7b0683e
fix tests by correcting raised error type
mashehu Nov 16, 2023
22a9071
fix tests, switch to pdiff instead of icdiff, because it handles widt…
mashehu Nov 16, 2023
a8f6332
revert e19a4a250bf7a8a4ebd484f94cc39b324642081f
mirpedrol Nov 16, 2023
5347b56
Apply suggestions from code review
mashehu Nov 16, 2023
fc0a3fc
remove debugging raise introduced by mistake
mirpedrol Nov 16, 2023
d12560d
move create-snapshot command to test command
mirpedrol Nov 20, 2023
300289e
move modules and subworkflows test tests to components
mirpedrol Nov 20, 2023
c254699
add test for generate snapshot once
mirpedrol Nov 20, 2023
bb640bb
update README
mashehu Nov 20, 2023
c550823
Apply suggestions from code review
mashehu Nov 20, 2023
2b15177
fix typing errors
mashehu Nov 20, 2023
8d5550e
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 20, 2023
f4a48b5
remove last traces of create-snapshot or create-test-yml
mashehu Nov 20, 2023
9f2f905
fix parameters
mashehu Nov 20, 2023
f288520
update changelog
mashehu Nov 20, 2023
7722d52
rename create_snapshot functions and files
mashehu Nov 20, 2023
71c0b08
simplify obsolete check
mashehu Nov 21, 2023
d29643e
add back option to handle pytest based modules in bump_version
mashehu Nov 21, 2023
4d08f6d
rename generator to test to make it hopefully less confusing
mashehu Nov 21, 2023
0c120ab
automatically sort dependencies in environment.yml while linting
mashehu Nov 21, 2023
dc5c7cb
fix types
mashehu Nov 21, 2023
bcf22a1
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 21, 2023
a5a3fd4
fix typo
mashehu Nov 21, 2023
41b61c1
fix import statement
mashehu Nov 21, 2023
d2df78a
Update nf_core/components/components_test.py
mashehu Nov 21, 2023
75a07c4
remove self.run_tests
mashehu Nov 21, 2023
b4ff558
Merge branch 'migrate-component-create-to-nf_test' of github.com:mash…
mashehu Nov 21, 2023
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
102 changes: 46 additions & 56 deletions nf_core/components/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
import os
import re
import subprocess
from pathlib import Path
from typing import Optional

import jinja2
import questionary
import rich
import yaml
from packaging.version import parse as parse_version

import nf_core
Expand All @@ -27,16 +28,16 @@
class ComponentCreate(ComponentCommand):
def __init__(
self,
component_type,
directory=".",
component="",
author=None,
process_label=None,
has_meta=None,
force=False,
conda_name=None,
conda_version=None,
empty_template=False,
component_type: str,
directory: str = ".",
component: str = "",
author: Optional[str] = None,
process_label: Optional[str] = None,
has_meta: Optional[str] = None,
force: bool = False,
conda_name: Optional[str] = None,
conda_version: Optional[str] = None,
empty_template: bool = False,
):
super().__init__(component_type, directory)
self.directory = directory
Expand Down Expand Up @@ -71,23 +72,23 @@ def create(self):

If <directory> is a pipeline, this function creates a file called:
'<directory>/modules/local/tool.nf'
OR
OR
'<directory>/modules/local/tool_subtool.nf'
OR for subworkflows
OR for subworkflows
'<directory>/subworkflows/local/subworkflow_name.nf'

If <directory> is a clone of nf-core/modules, it creates or modifies the following files:

For modules:

```tree
modules/modules/nf-core/tool/subtool/
* main.nf
* meta.yml
modules/tests/modules/nf-core/tool/subtool/
* main.nf
* test.yml
* nextflow.config
tests/config/pytest_modules.yml
├── main.nf
├── meta.yml
└── tests
├── main.nf.test
└── tags.yml
```

The function will attempt to automatically find a Bioconda package called <component>
and matching Docker / Singularity images from BioContainers.
Expand Down Expand Up @@ -147,32 +148,23 @@ def create(self):
# Create component template with jinja2
self._render_template()

if self.repo_type == "modules":
# Add entry to pytest_modules.yml
try:
with open(os.path.join(self.directory, "tests", "config", "pytest_modules.yml"), "r") as fh:
pytest_modules_yml = yaml.safe_load(fh)
if self.subtool:
pytest_modules_yml[self.component_name] = [
f"modules/{self.org}/{self.component}/{self.subtool}/**",
f"tests/modules/{self.org}/{self.component}/{self.subtool}/**",
]
# generate nf-tests
nf_core.utils.run_cmd("nf-test", f"generate process {self.file_paths['main.nf']}")
# move generated main.nf.test file into test directory

Path("main.nf.test").rename(self.file_paths[os.path.join(self.component_type, "test", "main.nf.test")])

# inside main.nf.test replace the path to the main.nf file with the relative path for the script
with open(self.file_paths["tests/main.nf.test"], "r") as f:
lines = f.readlines()
with open(self.file_paths["tests/main.nf.test"], "w") as f:
for line in lines:
if line.startswith("script"):
f.write(f"script ../main.nf\n")
else:
pytest_modules_yml[
("" if self.component_type == "modules" else self.component_type + "/") + self.component_name
] = [
f"{self.component_type}/{self.org}/{self.component}/**",
f"tests/{self.component_type}/{self.org}/{self.component}/**",
]
pytest_modules_yml = dict(sorted(pytest_modules_yml.items()))
with open(os.path.join(self.directory, "tests", "config", "pytest_modules.yml"), "w") as fh:
yaml.dump(pytest_modules_yml, fh, sort_keys=True, Dumper=nf_core.utils.custom_yaml_dumper())
except FileNotFoundError:
raise UserWarning("Could not open 'tests/config/pytest_modules.yml' file!")
f.write(line)

new_files = list(self.file_paths.values())
if self.repo_type == "modules":
new_files.append(os.path.join(self.directory, "tests", "config", "pytest_modules.yml"))
log.info("Created / edited following files:\n " + "\n ".join(new_files))

def _get_bioconda_tool(self):
Expand Down Expand Up @@ -362,17 +354,12 @@ def _get_component_dirs(self):
file_paths[os.path.join(self.component_type, "main.nf")] = component_file

if self.repo_type == "modules":
software_dir = os.path.join(self.directory, self.component_type, self.org, self.component_dir)
test_dir = os.path.join(self.directory, "tests", self.component_type, self.org, self.component_dir)
component_dir = os.path.join(self.directory, self.component_type, self.org, self.component_dir)

# Check if module/subworkflow directories exist already
if os.path.exists(software_dir) and not self.force_overwrite:
if os.path.exists(component_dir) and not self.force_overwrite:
raise UserWarning(
f"{self.component_type[:-1]} directory exists: '{software_dir}'. Use '--force' to overwrite"
)
if os.path.exists(test_dir) and not self.force_overwrite:
raise UserWarning(
f"{self.component_type[:-1]} test directory exists: '{test_dir}'. Use '--force' to overwrite"
f"{self.component_type[:-1]} directory exists: '{component_dir}'. Use '--force' to overwrite"
)

if self.component_type == "modules":
Expand Down Expand Up @@ -403,11 +390,14 @@ def _get_component_dirs(self):

# Set file paths
# For modules - can be tool/ or tool/subtool/ so can't do in template directory structure
file_paths[os.path.join(self.component_type, "main.nf")] = os.path.join(software_dir, "main.nf")
file_paths[os.path.join(self.component_type, "meta.yml")] = os.path.join(software_dir, "meta.yml")
file_paths[os.path.join("tests", "main.nf")] = os.path.join(test_dir, "main.nf")
file_paths[os.path.join("tests", "test.yml")] = os.path.join(test_dir, "test.yml")
file_paths[os.path.join("tests", "nextflow.config")] = os.path.join(test_dir, "nextflow.config")
file_paths[os.path.join(self.component_type, "main.nf")] = os.path.join(component_dir, "main.nf")
file_paths[os.path.join(self.component_type, "meta.yml")] = os.path.join(component_dir, "meta.yml")
file_paths[os.path.join(self.component_type, "test", "main.nf.test")] = os.path.join(
component_dir, "test", "main.nf.test"
)
file_paths[os.path.join(self.component_type, "test", "tags.yml")] = os.path.join(
component_dir, "test", "tags.yml"
)

return file_paths

Expand Down
8 changes: 4 additions & 4 deletions nf_core/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ def get_local_wf(workflow, revision=None):

# Wasn't local, fetch it
log.info(f"Downloading workflow: {workflow} ({revision})")
pull_cmd = f"nextflow pull {workflow}"
pull_cmd = f"pull {workflow}"
if revision is not None:
pull_cmd += f" -r {revision}"
nf_core.utils.nextflow_cmd(pull_cmd)
nf_core.utils.run_cmd("nextflow", pull_cmd)
local_wf = LocalWorkflow(workflow)
local_wf.get_local_nf_workflow_details()
return local_wf.local_path
Expand Down Expand Up @@ -128,7 +128,7 @@ def get_local_nf_workflows(self):
# Fetch details about local cached pipelines with `nextflow list`
else:
log.debug("Getting list of local nextflow workflows")
nflist_raw = nf_core.utils.nextflow_cmd("nextflow list")
nflist_raw = nf_core.utils.run_cmd("nextflow", "list")
for wf_name in nflist_raw.splitlines():
if not str(wf_name).startswith("nf-core/"):
self.local_unmatched.append(wf_name)
Expand Down Expand Up @@ -342,7 +342,7 @@ def get_local_nf_workflow_details(self):

# Use `nextflow info` to get more details about the workflow
else:
nfinfo_raw = str(nf_core.utils.nextflow_cmd(f"nextflow info -d {self.full_name}"))
nfinfo_raw = str(nf_core.utils.run_cmd("nextflow", f"info -d {self.full_name}"))
re_patterns = {"repository": r"repository\s*: (.*)", "local_path": r"local path\s*: (.*)"}
for key, pattern in re_patterns.items():
m = re.search(pattern, nfinfo_raw)
Expand Down
2 changes: 2 additions & 0 deletions nf_core/module-template/modules/tests/tags.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{ { component_name_underscore } }:
- "modules/{{ org }}/{{ component_dir }}/**"
18 changes: 0 additions & 18 deletions nf_core/module-template/tests/main.nf

This file was deleted.

5 changes: 0 additions & 5 deletions nf_core/module-template/tests/nextflow.config

This file was deleted.

18 changes: 0 additions & 18 deletions nf_core/module-template/tests/test.yml

This file was deleted.

18 changes: 11 additions & 7 deletions nf_core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import sys
import time
from pathlib import Path
from typing import ByteString, Optional, Union

import git
import prompt_toolkit
Expand Down Expand Up @@ -269,7 +270,7 @@ def fetch_wf_config(wf_path, cache_config=True):
log.debug("No config cache found")

# Call `nextflow config`
nfconfig_raw = nextflow_cmd(f"nextflow config -flat {wf_path}")
nfconfig_raw = nextflow_cmd("nextflow", f"config -flat {wf_path}")
mashehu marked this conversation as resolved.
Show resolved Hide resolved
for l in nfconfig_raw.splitlines():
ul = l.decode("utf-8")
try:
Expand Down Expand Up @@ -303,17 +304,20 @@ def fetch_wf_config(wf_path, cache_config=True):
return config


def nextflow_cmd(cmd):
"""Run a Nextflow command and capture the output. Handle errors nicely"""
def run_cmd(executable: str, cmd: str) -> Union[Optional[ByteString], str]:
"""Run a specified command and capture the output. Handle errors nicely."""
full_cmd = f"{executable} {cmd}"
try:
nf_proc = subprocess.run(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
return nf_proc.stdout
proc = subprocess.run(shlex.split(full_cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
return proc.stdout
except OSError as e:
if e.errno == errno.ENOENT:
raise AssertionError("It looks like Nextflow is not installed. It is required for most nf-core functions.")
raise AssertionError(
f"It looks like {executable} is not installed. Please ensure it is available in your PATH."
)
except subprocess.CalledProcessError as e:
raise AssertionError(
f"Command '{cmd}' returned non-zero error code '{e.returncode}':\n[red]> {e.stderr.decode()}{e.stdout.decode()}"
f"Command '{full_cmd}' returned non-zero error code '{e.returncode}':\n[red]> {e.stderr.decode()}{e.stdout.decode()}"
)


Expand Down
6 changes: 3 additions & 3 deletions tests/test_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import nf_core.utils
from nf_core.download import ContainerError, DownloadWorkflow, WorkflowRepo
from nf_core.synced_repo import SyncedRepo
from nf_core.utils import NFCORE_CACHE_DIR, NFCORE_DIR, nextflow_cmd
from nf_core.utils import NFCORE_CACHE_DIR, NFCORE_DIR, run_cmd

from .utils import with_temporary_file, with_temporary_folder

Expand Down Expand Up @@ -156,8 +156,8 @@ def test_find_container_images_config_basic(self, tmp_path, mock_fetch_wf_config
@mock.patch("nf_core.utils.fetch_wf_config")
def test__find_container_images_config_nextflow(self, tmp_path, mock_fetch_wf_config):
download_obj = DownloadWorkflow(pipeline="dummy", outdir=tmp_path)
nfconfig_raw = nextflow_cmd(
f"nextflow config -flat {Path(__file__).resolve().parent / 'data/mock_config_containers'}"
nfconfig_raw = run_cmd(
"nextflow", f"config -flat {Path(__file__).resolve().parent / 'data/mock_config_containers'}"
)
config = {}
for l in nfconfig_raw.splitlines():
Expand Down
Loading