diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b290e09..237c9ed 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,20 +1,21 @@ { + "$schema": "https://raw.githubusercontent.com/devcontainers/spec/main/schemas/devContainer.schema.json", "name": "nfcore", - "image": "nfcore/gitpod:latest", - "remoteUser": "gitpod", - "runArgs": ["--privileged"], + "image": "nfcore/devcontainer:latest", - // Configure tool-specific properties. - "customizations": { - // Configure properties specific to VS Code. - "vscode": { - // Set *default* container specific settings.json values on container create. - "settings": { - "python.defaultInterpreterPath": "/opt/conda/bin/python" - }, + "remoteUser": "root", + "privileged": true, - // Add the IDs of extensions you want installed when the container is created. - "extensions": ["ms-python.python", "ms-python.vscode-pylance", "nf-core.nf-core-extensionpack"] - } + "remoteEnv": { + // Workspace path on the host for mounting with docker-outside-of-docker + "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" + }, + + "onCreateCommand": "./.devcontainer/setup.sh", + + "hostRequirements": { + "cpus": 4, + "memory": "16gb", + "storage": "32gb" } } diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100755 index 0000000..d1f7d9f --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Customise the terminal command prompt +echo "export PROMPT_DIRTRIM=2" >> $HOME/.bashrc +echo "export PS1='\[\e[3;36m\]\w ->\[\e[0m\\] '" >> $HOME/.bashrc +export PROMPT_DIRTRIM=2 +export PS1='\[\e[3;36m\]\w ->\[\e[0m\\] ' + +# Update Nextflow +nextflow self-update + +# Update welcome message +echo "Welcome to the nf-core/funcprofiler devcontainer!" > /usr/local/etc/vscode-dev-containers/first-run-notice.txt diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 3bca66c..0000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,125 +0,0 @@ -# `nf-core/funcprofiler`: Contributing Guidelines - -Hi there! -Many thanks for taking an interest in improving nf-core/funcprofiler. - -We try to manage the required tasks for nf-core/funcprofiler using GitHub issues, you probably came to this page when creating one. -Please use the pre-filled template to save time. - -However, don't be put off by this template - other more general issues and suggestions are welcome! -Contributions to the code are even more welcome ;) - -> [!NOTE] -> If you need help using or modifying nf-core/funcprofiler then the best place to ask is on the nf-core Slack [#funcprofiler](https://nfcore.slack.com/channels/funcprofiler) channel ([join our Slack here](https://nf-co.re/join/slack)). - -## Contribution workflow - -If you'd like to write some code for nf-core/funcprofiler, the standard workflow is as follows: - -1. Check that there isn't already an issue about your idea in the [nf-core/funcprofiler issues](https://github.com/nf-core/funcprofiler/issues) to avoid duplicating work. If there isn't one already, please create one so that others know you're working on this -2. [Fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the [nf-core/funcprofiler repository](https://github.com/nf-core/funcprofiler) to your GitHub account -3. Make the necessary changes / additions within your forked repository following [Pipeline conventions](#pipeline-contribution-conventions) -4. Use `nf-core pipelines schema build` and add any new parameters to the pipeline JSON schema (requires [nf-core tools](https://github.com/nf-core/tools) >= 1.10). -5. Submit a Pull Request against the `dev` branch and wait for the code to be reviewed and merged - -If you're not used to this workflow with git, you can start with some [docs from GitHub](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests) or even their [excellent `git` resources](https://try.github.io/). - -## Tests - -You have the option to test your changes locally by running the pipeline. For receiving warnings about process selectors and other `debug` information, it is recommended to use the debug profile. Execute all the tests with the following command: - -```bash -nf-test test --profile debug,test,docker --verbose -``` - -When you create a pull request with changes, [GitHub Actions](https://github.com/features/actions) will run automatic tests. -Typically, pull-requests are only fully reviewed when these tests are passing, though of course we can help out before then. - -There are typically two types of tests that run: - -### Lint tests - -`nf-core` has a [set of guidelines](https://nf-co.re/developers/guidelines) which all pipelines must adhere to. -To enforce these and ensure that all pipelines stay in sync, we have developed a helper tool which runs checks on the pipeline code. This is in the [nf-core/tools repository](https://github.com/nf-core/tools) and once installed can be run locally with the `nf-core pipelines lint ` command. - -If any failures or warnings are encountered, please follow the listed URL for more documentation. - -### Pipeline tests - -Each `nf-core` pipeline should be set up with a minimal set of test-data. -`GitHub Actions` then runs the pipeline on this data to ensure that it exits successfully. -If there are any failures then the automated tests fail. -These tests are run both with the latest available version of `Nextflow` and also the minimum required version that is stated in the pipeline code. - -## Patch - -:warning: Only in the unlikely and regretful event of a release happening with a bug. - -- On your own fork, make a new branch `patch` based on `upstream/main` or `upstream/master`. -- Fix the bug, and bump version (X.Y.Z+1). -- Open a pull-request from `patch` to `main`/`master` with the changes. - -## Getting help - -For further information/help, please consult the [nf-core/funcprofiler documentation](https://nf-co.re/funcprofiler/usage) and don't hesitate to get in touch on the nf-core Slack [#funcprofiler](https://nfcore.slack.com/channels/funcprofiler) channel ([join our Slack here](https://nf-co.re/join/slack)). - -## Pipeline contribution conventions - -To make the `nf-core/funcprofiler` code and processing logic more understandable for new contributors and to ensure quality, we semi-standardise the way the code and other contributions are written. - -### Adding a new step - -If you wish to contribute a new step, please use the following coding standards: - -1. Define the corresponding input channel into your new process from the expected previous process channel. -2. Write the process block (see below). -3. Define the output channel if needed (see below). -4. Add any new parameters to `nextflow.config` with a default (see below). -5. Add any new parameters to `nextflow_schema.json` with help text (via the `nf-core pipelines schema build` tool). -6. Add sanity checks and validation for all relevant parameters. -7. Perform local tests to validate that the new code works as expected. -8. If applicable, add a new test in the `tests` directory. -9. Update MultiQC config `assets/multiqc_config.yml` so relevant suffixes, file name clean up and module plots are in the appropriate order. If applicable, add a [MultiQC](https://https://multiqc.info/) module. -10. Add a description of the output files and if relevant any appropriate images from the MultiQC report to `docs/output.md`. - -### Default values - -Parameters should be initialised / defined with default values within the `params` scope in `nextflow.config`. - -Once there, use `nf-core pipelines schema build` to add to `nextflow_schema.json`. - -### Default processes resource requirements - -Sensible defaults for process resource requirements (CPUs / memory / time) for a process should be defined in `conf/base.config`. These should generally be specified generic with `withLabel:` selectors so they can be shared across multiple processes/steps of the pipeline. A nf-core standard set of labels that should be followed where possible can be seen in the [nf-core pipeline template](https://github.com/nf-core/tools/blob/main/nf_core/pipeline-template/conf/base.config), which has the default process as a single core-process, and then different levels of multi-core configurations for increasingly large memory requirements defined with standardised labels. - -The process resources can be passed on to the tool dynamically within the process with the `${task.cpus}` and `${task.memory}` variables in the `script:` block. - -### Naming schemes - -Please use the following naming schemes, to make it easy to understand what is going where. - -- initial process channel: `ch_output_from_` -- intermediate and terminal channels: `ch__for_` - -### Nextflow version bumping - -If you are using a new feature from core Nextflow, you may bump the minimum required version of nextflow in the pipeline with: `nf-core pipelines bump-version --nextflow . [min-nf-version]` - -### Images and figures - -For overview images and other documents we follow the nf-core [style guidelines and examples](https://nf-co.re/developers/design_guidelines). - -## GitHub Codespaces - -This repo includes a devcontainer configuration which will create a GitHub Codespaces for Nextflow development! This is an online developer environment that runs in your browser, complete with VSCode and a terminal. - -To get started: - -- Open the repo in [Codespaces](https://github.com/nf-core/funcprofiler/codespaces) -- Tools installed - - nf-core - - Nextflow - -Devcontainer specs: - -- [DevContainer config](.devcontainer/devcontainer.json) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f7d3c8b..1b90bf3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,14 +8,14 @@ These are the most common things requested on pull requests (PRs). Remember that PRs should be made against the dev branch, unless you're preparing a pipeline release. -Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/funcprofiler/tree/main/.github/CONTRIBUTING.md) +Learn more about contributing: [CONTRIBUTING.md](https://github.com/nf-core/funcprofiler/tree/main/docs/CONTRIBUTING.md) --> ## PR checklist - [ ] This comment contains a description of changes (with reason). - [ ] If you've fixed a bug or added code that should be tested, add tests! -- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/funcprofiler/tree/main/.github/CONTRIBUTING.md) +- [ ] If you've added a new tool - have you followed the pipeline conventions in the [contribution docs](https://github.com/nf-core/funcprofiler/tree/main/docs/CONTRIBUTING.md) - [ ] If necessary, also make a PR on the nf-core/funcprofiler _branch_ on the [nf-core/test-datasets](https://github.com/nf-core/test-datasets) repository. - [ ] Make sure your code lints (`nf-core pipelines lint`). - [ ] Ensure the test suite passes (`nextflow run . -profile test,docker --outdir `). diff --git a/.github/actions/get-shards/action.yml b/.github/actions/get-shards/action.yml index 3408527..e2833ee 100644 --- a/.github/actions/get-shards/action.yml +++ b/.github/actions/get-shards/action.yml @@ -21,7 +21,7 @@ runs: using: "composite" steps: - name: Install nf-test - uses: nf-core/setup-nf-test@v1 + uses: nf-core/setup-nf-test@4069fbbaabe94c08faba4ad261bfa88225ba133f # v2 with: version: ${{ env.NFT_VER }} - name: Get number of shards diff --git a/.github/actions/nf-test/action.yml b/.github/actions/nf-test/action.yml index bf44d96..d5c04a1 100644 --- a/.github/actions/nf-test/action.yml +++ b/.github/actions/nf-test/action.yml @@ -20,38 +20,43 @@ runs: using: "composite" steps: - name: Setup Nextflow - uses: nf-core/setup-nextflow@v2 + uses: nf-core/setup-nextflow@893c28b667aedeba26e37f296d260ccc5bc4d914 # v3 with: version: "${{ env.NXF_VERSION }}" - name: Set up Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7 with: - python-version: "3.13" + python-version: "3.14" - name: Install nf-test - uses: nf-core/setup-nf-test@v1 + uses: nf-core/setup-nf-test@4069fbbaabe94c08faba4ad261bfa88225ba133f # v2 with: version: "${{ env.NFT_VER }}" install-pdiff: true - name: Setup apptainer if: contains(inputs.profile, 'singularity') - uses: eWaterCycle/setup-apptainer@main + uses: eWaterCycle/setup-apptainer@3f706d898c9db585b1d741b4692e66755f3a1b40 # v2.0.0 - name: Set up Singularity if: contains(inputs.profile, 'singularity') shell: bash run: | + # The runner image restricts unprivileged user namespaces, which non-suid + # apptainer needs to start a container at all. + sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true mkdir -p $NXF_SINGULARITY_CACHEDIR mkdir -p $NXF_SINGULARITY_LIBRARYDIR - name: Conda setup if: contains(inputs.profile, 'conda') - uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3 + uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4 with: auto-update-conda: true conda-solver: libmamba + channels: conda-forge + channel-priority: flexible conda-remove-defaults: true - name: Run nf-test diff --git a/.github/workflows/awsfulltest.yml b/.github/workflows/awsfulltest.yml index 39b4062..4f60919 100644 --- a/.github/workflows/awsfulltest.yml +++ b/.github/workflows/awsfulltest.yml @@ -23,26 +23,44 @@ jobs: echo "revision=${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'release') && github.sha || 'dev' }}" >> "$GITHUB_OUTPUT" - name: Launch workflow via Seqera Platform - uses: seqeralabs/action-tower-launch@v2 - # TODO nf-core: You can customise AWS full pipeline tests as required + uses: seqeralabs/action-tower-launch@51565b514bff1827cf34620de25d0055759f1fc9 # v2 # Add full size test data (but still relatively small datasets for few samples) # on the `test_full.config` test runs with only one set of parameters with: - workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} + workspace_id: ${{ vars.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} - compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} + compute_env: ${{ vars.TOWER_COMPUTE_ENV }} revision: ${{ steps.revision.outputs.revision }} - workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/funcprofiler/work-${{ steps.revision.outputs.revision }} + workdir: s3://${{ vars.AWS_S3_BUCKET }}/work/funcprofiler/work-${{ steps.revision.outputs.revision }} + nextflow_config: | + plugins { + id 'nf-slack@0.5.0' + } + slack { + enabled = true + bot { + token = '${{ secrets.NFSLACK_BOT_TOKEN }}' + channel = 'funcprofiler' + } + onStart { + enabled = false + } + onComplete { + message = ':white_check_mark: *funcprofiler/test_full* completed successfully! :tada:' + } + onError { + message = ':x: *funcprofiler/test_full* failed :crying_cat_face:' + } + } parameters: | { - "hook_url": "${{ secrets.MEGATESTS_ALERTS_SLACK_HOOK_URL }}", - "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/funcprofiler/results-${{ steps.revision.outputs.revision }}" + "outdir": "s3://${{ vars.AWS_S3_BUCKET }}/funcprofiler/results-${{ steps.revision.outputs.revision }}" } profiles: test_full - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: Seqera Platform debug log file path: | - seqera_platform_action_*.log - seqera_platform_action_*.json + tower_action_*.log + tower_action_*.json diff --git a/.github/workflows/awstest.yml b/.github/workflows/awstest.yml index 49116c5..1daec37 100644 --- a/.github/workflows/awstest.yml +++ b/.github/workflows/awstest.yml @@ -12,22 +12,22 @@ jobs: steps: # Launch workflow using Seqera Platform CLI tool action - name: Launch workflow via Seqera Platform - uses: seqeralabs/action-tower-launch@v2 + uses: seqeralabs/action-tower-launch@51565b514bff1827cf34620de25d0055759f1fc9 # v2 with: - workspace_id: ${{ secrets.TOWER_WORKSPACE_ID }} + workspace_id: ${{ vars.TOWER_WORKSPACE_ID }} access_token: ${{ secrets.TOWER_ACCESS_TOKEN }} - compute_env: ${{ secrets.TOWER_COMPUTE_ENV }} + compute_env: ${{ vars.TOWER_COMPUTE_ENV }} revision: ${{ github.sha }} - workdir: s3://${{ secrets.AWS_S3_BUCKET }}/work/funcprofiler/work-${{ github.sha }} + workdir: s3://${{ vars.AWS_S3_BUCKET }}/work/funcprofiler/work-${{ github.sha }} parameters: | { - "outdir": "s3://${{ secrets.AWS_S3_BUCKET }}/funcprofiler/results-test-${{ github.sha }}" + "outdir": "s3://${{ vars.AWS_S3_BUCKET }}/funcprofiler/results-test-${{ github.sha }}" } profiles: test - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: Seqera Platform debug log file path: | - seqera_platform_action_*.log - seqera_platform_action_*.json + tower_action_*.log + tower_action_*.json diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index a6d4926..f16c675 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -2,11 +2,13 @@ name: nf-core branch protection # This workflow is triggered on PRs to `main`/`master` branch on the repository # It fails when someone tries to make a PR against the nf-core `main`/`master` branch instead of `dev` on: - pull_request_target: + pull_request: branches: - main - master +permissions: {} + jobs: test: runs-on: ubuntu-latest @@ -14,33 +16,47 @@ jobs: # PRs to the nf-core repo main/master branch are only ok if coming from the nf-core repo `dev` or any `patch` branches - name: Check PRs if: github.repository == 'nf-core/funcprofiler' + env: + HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} run: | - { [[ ${{github.event.pull_request.head.repo.full_name }} == nf-core/funcprofiler ]] && [[ $GITHUB_HEAD_REF == "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] + { [[ "$HEAD_REPO" == nf-core/funcprofiler ]] && [[ $GITHUB_HEAD_REF == "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] - # If the above check failed, post a comment on the PR explaining the failure - # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets - - name: Post PR comment + # If the above check failed, build a comment to be posted by the shared poster workflow + - name: Build PR comment if: failure() - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 - with: - message: | - ## This PR is against the `${{github.event.pull_request.base.ref}}` branch :x: + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + BASE_REF: ${{ github.event.pull_request.base.ref }} + HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} + PR_USER: ${{ github.event.pull_request.user.login }} + run: | + mkdir -p pr-comment + echo "$PR_NUMBER" > pr-comment/pr_number.txt + echo "branch" > pr-comment/header.txt + cat > pr-comment/comment.md <> "$GITHUB_OUTPUT" + - name: Install dependencies run: | python -m pip install --upgrade pip - pip install git+https://github.com/nf-core/tools.git@dev + pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} - name: Make a cache directory for the container images run: | @@ -127,7 +135,7 @@ jobs: fi - name: Upload Nextflow logfile for debugging purposes - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: nextflow_logfile.txt path: .nextflow.log* diff --git a/.github/workflows/fix_linting.yml b/.github/workflows/fix_linting.yml index 19f7b8d..96ae9d8 100644 --- a/.github/workflows/fix_linting.yml +++ b/.github/workflows/fix_linting.yml @@ -13,13 +13,13 @@ jobs: runs-on: ubuntu-latest steps: # Use the @nf-core-bot token to check out so we can push later - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: token: ${{ secrets.nf_core_bot_auth_token }} # indication that the linting is being fixed - name: React on comment - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 with: comment-id: ${{ github.event.comment.id }} reactions: eyes @@ -31,30 +31,26 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.nf_core_bot_auth_token }} - # Install and run pre-commit - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 - with: - python-version: "3.13" - - - name: Install pre-commit - run: pip install pre-commit + - name: Install Nextflow + uses: nf-core/setup-nextflow@893c28b667aedeba26e37f296d260ccc5bc4d914 # v3 - - name: Run pre-commit - id: pre-commit - run: pre-commit run --all-files + # Install and run prek + - name: Run prek + id: prek + uses: j178/prek-action@5337cb91e0fa35a7ff31b9ca345126d8bbbcdf16 # v2 continue-on-error: true # indication that the linting has finished - name: react if linting finished succesfully - if: steps.pre-commit.outcome == 'success' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + if: steps.prek.outcome == 'success' + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 with: comment-id: ${{ github.event.comment.id }} reactions: "+1" - name: Commit & push changes id: commit-and-push - if: steps.pre-commit.outcome == 'failure' + if: steps.prek.outcome == 'failure' run: | git config user.email "core@nf-co.re" git config user.name "nf-core-bot" @@ -67,21 +63,21 @@ jobs: - name: react if linting errors were fixed id: react-if-fixed if: steps.commit-and-push.outcome == 'success' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 with: comment-id: ${{ github.event.comment.id }} reactions: hooray - name: react if linting errors were not fixed if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 with: comment-id: ${{ github.event.comment.id }} reactions: confused - name: react if linting errors were not fixed if: steps.commit-and-push.outcome == 'failure' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 with: issue-number: ${{ github.event.issue.number }} body: | diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 8b0f88c..f25e608 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -11,33 +11,31 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up Python 3.13 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 - with: - python-version: "3.13" - - - name: Install pre-commit - run: pip install pre-commit + - name: Install Nextflow + uses: nf-core/setup-nextflow@893c28b667aedeba26e37f296d260ccc5bc4d914 # v3 - - name: Run pre-commit - run: pre-commit run --all-files + - name: Run prek + uses: j178/prek-action@5337cb91e0fa35a7ff31b9ca345126d8bbbcdf16 # v2 nf-core: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Install Nextflow - uses: nf-core/setup-nextflow@v2 + uses: nf-core/setup-nextflow@893c28b667aedeba26e37f296d260ccc5bc4d914 # v3 - - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7 with: - python-version: "3.13" + python-version: "3.14" architecture: "x64" + - name: Setup uv + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + - name: read .nf-core.yml uses: pietrobolcato/action-read-yaml@9f13718d61111b69f30ab4ac683e67a56d254e1d # 1.1.0 id: read_yml @@ -45,12 +43,10 @@ jobs: config: ${{ github.workspace }}/.nf-core.yml - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + run: uv tool install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} - name: Run nf-core pipelines lint - if: ${{ github.base_ref != 'master' }} + if: ${{ github.base_ref != 'master' && github.base_ref != 'main' }} env: GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -58,7 +54,7 @@ jobs: run: nf-core -l lint_log.txt pipelines lint --dir ${GITHUB_WORKSPACE} --markdown lint_results.md - name: Run nf-core pipelines lint --release - if: ${{ github.base_ref == 'master' }} + if: ${{ github.base_ref == 'master' || github.base_ref == 'main' }} env: GITHUB_COMMENTS_URL: ${{ github.event.pull_request.comments_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -71,10 +67,28 @@ jobs: - name: Upload linting log file artifact if: ${{ always() }} - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 with: name: linting-logs path: | lint_log.txt lint_results.md PR_number.txt + + # Build a comment for the shared pr-comment.yml poster to publish on the PR + - name: Prepare PR comment + if: ${{ always() }} + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + mkdir -p pr-comment + echo "$PR_NUMBER" > pr-comment/pr_number.txt + echo "lint" > pr-comment/header.txt + [ -f lint_results.md ] && cp lint_results.md pr-comment/comment.md || true + + - name: Upload PR comment artifact + if: ${{ always() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: pr-comment + path: pr-comment/ diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml deleted file mode 100644 index d43797d..0000000 --- a/.github/workflows/linting_comment.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: nf-core linting comment -# This workflow is triggered after the linting action is complete -# It posts an automated comment to the PR, even if the PR is coming from a fork - -on: - workflow_run: - workflows: ["nf-core linting"] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Download lint results - uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11 - with: - workflow: linting.yml - workflow_conclusion: completed - - - name: Get PR number - id: pr_number - run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT - - - name: Post PR comment - uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - number: ${{ steps.pr_number.outputs.pr_number }} - path: linting-logs/lint_results.md diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index 9d7642e..d089b70 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -18,7 +18,7 @@ concurrency: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NFT_VER: "0.9.2" + NFT_VER: "0.9.5" NFT_WORKDIR: "~" NXF_ANSI_LOG: false NXF_SINGULARITY_CACHEDIR: ${{ github.workspace }}/.singularity @@ -40,7 +40,7 @@ jobs: rm -rf ./* || true rm -rf ./.??* || true ls -la ./ - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 @@ -50,7 +50,7 @@ jobs: env: NFT_VER: ${{ env.NFT_VER }} with: - max_shards: 7 + max_shards: 19 - name: debug run: | @@ -68,24 +68,22 @@ jobs: fail-fast: false matrix: shard: ${{ fromJson(needs.nf-test-changes.outputs.shard) }} - profile: [conda, docker, singularity] + profile: [docker, singularity, conda] isMain: - ${{ github.base_ref == 'master' || github.base_ref == 'main' }} # Exclude conda and singularity on dev exclude: - - isMain: false - profile: "conda" - isMain: false profile: "singularity" NXF_VER: - - "24.10.5" + - "25.10.4" - "latest-everything" env: NXF_ANSI_LOG: false TOTAL_SHARDS: ${{ needs.nf-test-changes.outputs.total_shards }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 @@ -95,11 +93,24 @@ jobs: continue-on-error: ${{ matrix.NXF_VER == 'latest-everything' }} env: NFT_WORKDIR: ${{ env.NFT_WORKDIR }} + NXF_VERSION: ${{ matrix.NXF_VER }} with: profile: ${{ matrix.profile }} shard: ${{ matrix.shard }} total_shards: ${{ env.TOTAL_SHARDS }} - + - name: list contents + run: ls -R "${{ env.NFT_WORKDIR }}" + - name: list funcprofilercontents + run: ls -R /home/runner/_work/funcprofiler/funcprofiler/ + - name: Upload artifact + if: ${{ always() }} + uses: actions/upload-artifact@v7 + with: + name: my-artifact-${{ matrix.profile }}-${{ matrix.NXF_VER }}-${{ matrix.shard }} + path: | + /home/runner/_work/funcprofiler/funcprofiler/ + !/home/runner/_work/funcprofiler/funcprofiler/**/work/conda/ + retention-days: 2 - name: Report test status if: ${{ always() }} run: | @@ -115,10 +126,26 @@ jobs: fi fi + # continue-on-error keeps latest-everything from failing the job, so it never shows up in + # `needs.nf-test.result` downstream and CI stays green. Surface it via a PR comment instead; + # other NXF_VER failures already fail the job/CI directly, so no comment is needed for those. + - name: Prepare PR comment fragment + if: ${{ always() && steps.run_nf_test.outcome == 'failure' && matrix.NXF_VER == 'latest-everything' }} + run: | + mkdir -p pr-comment-fragment + echo "* ❌ \`${{ matrix.profile }}\` | \`${{ matrix.NXF_VER }}\` | Shard ${{ matrix.shard }}/${{ env.TOTAL_SHARDS }}" > pr-comment-fragment/fragment.md + + - name: Upload PR comment fragment + if: ${{ always() && steps.run_nf_test.outcome == 'failure' && matrix.NXF_VER == 'latest-everything' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: pr-comment-fragment-${{ strategy.job-index }} + path: pr-comment-fragment/ + confirm-pass: needs: [nf-test] if: always() - runs-on: # use self-hosted runners + runs-on: # use self-hosted runners - runs-on=${{ github.run_id }}-confirm-pass - runner=2cpu-linux-x64 steps: @@ -141,3 +168,44 @@ jobs: echo "DEBUG: toJSON(needs) = ${{ toJSON(needs) }}" echo "DEBUG: toJSON(needs.*.result) = ${{ toJSON(needs.*.result) }}" echo "::endgroup::" + + - name: Download PR comment fragments + if: ${{ always() }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + continue-on-error: true + with: + pattern: pr-comment-fragment-* + path: pr-comment-fragments + merge-multiple: true + + # Build a comment for the shared pr-comment.yml poster to publish on the PR. + # Based on the fragments above (not needs.*.result) so non-blocking failures are still reported. + - name: Prepare PR comment + if: ${{ always() }} + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + mkdir -p pr-comment + echo "$PR_NUMBER" > pr-comment/pr_number.txt + echo "nf-test" > pr-comment/header.txt + if [ -d pr-comment-fragments ] && [ -n "$(ls -A pr-comment-fragments)" ]; then + { + echo "## ❌ nf-test failed with latest Nextflow version" + echo "" + echo "> [!NOTE]" + echo "> Tests with Nextflow's latest version failed but it will not cause a CI workflow failure." + echo "> Please check if the failure is expected with newer (edge-)releases of Nextflow or if it needs fixing." + echo "" + cat pr-comment-fragments/*.md + echo "" + echo "See the [full run](${RUN_URL}) for details." + } > pr-comment/comment.md + fi + + - name: Upload PR comment artifact + if: ${{ always() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: pr-comment + path: pr-comment/ diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml new file mode 100644 index 0000000..ab7b59d --- /dev/null +++ b/.github/workflows/pr-comment.yml @@ -0,0 +1,82 @@ +name: Post PR comment +# Shared, privileged comment poster. +# +# This is the single workflow that runs with a write token. It is triggered +# after any of the listed "producer" workflows complete on a pull request. +# Each producer runs untrusted PR code (if any) with a read-only token and +# uploads a `pr-comment` artifact describing the comment to post; this workflow +# only ever reads that plain-text artifact, so no PR code is executed here. +# +# Artifact contract (uploaded by producers under the name `pr-comment`): +# pr_number.txt - the pull request number +# header.txt - sticky-comment identifier (keeps comment types separate) +# comment.md - the Markdown body (omit the file to post nothing) + +on: + workflow_run: + workflows: + - "nf-core linting" + - "nf-core template version comment" + - "nf-core branch protection" + - "Run nf-test" + +permissions: + actions: read + contents: read + pull-requests: write + +jobs: + post-comment: + runs-on: ubuntu-latest + if: github.event.workflow_run.event == 'pull_request' + steps: + - name: Download PR comment artifact + uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21 + with: + run_id: ${{ github.event.workflow_run.id }} + name: pr-comment + path: pr-comment + if_no_artifact_found: ignore + + - name: Read comment metadata + id: meta + run: | + echo "::group::Downloaded pr-comment contents" + ls -la pr-comment 2>/dev/null || echo "No pr-comment/ directory was downloaded." + echo "::endgroup::" + + if [ ! -d pr-comment ]; then + echo "No pr-comment artifact found; nothing to post." + exit 0 + fi + + if [ ! -f pr-comment/comment.md ]; then + echo "Artifact present but no comment.md; nothing to post." + exit 0 + fi + + pr_number=$(cat pr-comment/pr_number.txt) + header=$(cat pr-comment/header.txt) + echo "Found comment.md (header='$header', pr_number='$pr_number')." + + # Guard against anything unexpected ending up in the PR number. + case "$pr_number" in + ''|*[!0-9]*) + echo "Invalid PR number: '$pr_number'" + exit 1 + ;; + esac + + echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT" + echo "header=$header" >> "$GITHUB_OUTPUT" + echo "post=true" >> "$GITHUB_OUTPUT" + echo "Will post comment to PR #${pr_number}." + + - name: Post PR comment + if: steps.meta.outputs.post == 'true' + uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + number: ${{ steps.meta.outputs.pr_number }} + header: ${{ steps.meta.outputs.header }} + path: pr-comment/comment.md diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index 0f73249..4974f44 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -14,7 +14,11 @@ jobs: run: | echo "topics=$(curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .topics[]' | awk '{print "#"$0}' | tr '\n' ' ')" | sed 's/-//g' >> $GITHUB_OUTPUT - - uses: rzr/fediverse-action@master + - name: get description + id: get_description + run: | + echo "description=$(curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .description')" >> $GITHUB_OUTPUT + - uses: rzr/fediverse-action@66c2cbb5b1997666b0e28d597631b6a4f09a2719 # v0.0.6 with: access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} host: "mstdn.science" # custom host if not "mastodon.social" (default) @@ -22,7 +26,7 @@ jobs: # https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#release message: | Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! - + ${{ steps.get_description.outputs.description }} Please see the changelog: ${{ github.event.release.html_url }} ${{ steps.get_topics.outputs.topics }} #nfcore #openscience #nextflow #bioinformatics @@ -30,7 +34,7 @@ jobs: bsky-post: runs-on: ubuntu-latest steps: - - uses: zentered/bluesky-post-action@6461056ea355ea43b977e149f7bf76aaa572e5e8 # v0.3.0 + - uses: zentered/bluesky-post-action@5a91cc2ad10a304a4e96c16182dbe4918710bcf6 # v0.4.0 with: post: | Pipeline release! ${{ github.repository }} v${{ github.event.release.tag_name }} - ${{ github.event.release.name }}! diff --git a/.github/workflows/template-version-comment.yml b/.github/workflows/template-version-comment.yml index beb5c77..149e285 100644 --- a/.github/workflows/template-version-comment.yml +++ b/.github/workflows/template-version-comment.yml @@ -2,14 +2,17 @@ name: nf-core template version comment # This workflow is triggered on PRs to check if the pipeline template version matches the latest nf-core version. # It posts a comment to the PR, even if it comes from a fork. -on: pull_request_target +on: + pull_request: + +permissions: {} jobs: - template_version: + check_template_version: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: ref: ${{ github.event.pull_request.head.sha }} @@ -22,25 +25,36 @@ jobs: - name: Install nf-core run: | python -m pip install --upgrade pip - pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + pip install nf-core + + - name: Build PR comment if template is outdated + # The fork-controlled version is passed via the environment and only ever + # used as quoted shell data (never interpolated into a command), so it + # cannot be used for script injection. + env: + PR_VERSION: ${{ steps.read_yml.outputs['nf_core_version'] }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + mkdir -p pr-comment + echo "$PR_NUMBER" > pr-comment/pr_number.txt + echo "template-version" > pr-comment/header.txt + + latest_version=$(nf-core --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) - - name: Check nf-core outdated - id: nf_core_outdated - run: echo "OUTPUT=$(pip list --outdated | grep nf-core)" >> ${GITHUB_ENV} + if [ -n "$PR_VERSION" ] && [ -n "$latest_version" ] && [ "$PR_VERSION" != "$latest_version" ]; then + cat > pr-comment/comment.md < [!WARNING] + > Newer version of the nf-core template is available. + > + > Your pipeline is using an old version of the nf-core template: ${PR_VERSION}. + > Please update your pipeline to the latest version. + > + > For more documentation on how to update your pipeline, please see the [Synchronisation documentation](https://nf-co.re/docs/developing/template-syncs/overview). + EOF + fi - - name: Post nf-core template version comment - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 - if: | - contains(env.OUTPUT, 'nf-core') + - name: Upload PR comment artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - repo-token: ${{ secrets.NF_CORE_BOT_AUTH_TOKEN }} - allow-repeats: false - message: | - > [!WARNING] - > Newer version of the nf-core template is available. - > - > Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. - > Please update your pipeline to the latest version. - > - > For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). - # + name: pr-comment + path: pr-comment/ diff --git a/.gitignore b/.gitignore index a42ce01..393cd5f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,12 @@ testing/ testing* *.pyc null/ +*~ +.nf-test/ +.nf-test.log +dontcommit +tmp/ +.data/ +*.code-workspace +.lineage/ +conf/tmp.config diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 83599f6..0000000 --- a/.gitpod.yml +++ /dev/null @@ -1,10 +0,0 @@ -image: nfcore/gitpod:latest -tasks: - - name: Update Nextflow and setup pre-commit - command: | - pre-commit install --install-hooks - nextflow self-update - -vscode: - extensions: - - nf-core.nf-core-extensionpack # https://github.com/nf-core/vscode-extensionpack diff --git a/.hooks/block_pipeline_outdir.sh b/.hooks/block_pipeline_outdir.sh new file mode 100755 index 0000000..e9ba4f9 --- /dev/null +++ b/.hooks/block_pipeline_outdir.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# This hook is used to block commits if they include staged files inside a directory +# which also contains a subdirectory called `pipeline_info`. The purpose of this is to +# prevent users from inadvertently committing output from pipeline test runs inside the +# development directory. + +set -e + +status=0 +seen_dirs="" + +while IFS= read -r file; do + # The offending output bundle's root is the ancestor directory that has + # `pipeline_info` as an immediate child, so callers can restore it in one go. + if [[ "$file" == pipeline_info/* ]]; then + top_dir="pipeline_info" + elif [[ "$file" == */pipeline_info/* ]]; then + top_dir="${file%%/pipeline_info/*}" + else + top_dir="" + dir=$(dirname "$file") + while [[ "$dir" != "." && "$dir" != "/" ]]; do + if [[ -d "$dir/pipeline_info" ]]; then + top_dir="$dir" + break + fi + dir=$(dirname "$dir") + done + fi + + if [[ -n "$top_dir" ]]; then + echo "❌ Commit blocked: Please do not commit output from pipeline test runs to the pipeline code itself: $file" + status=1 + case "$seen_dirs" in + *"|$top_dir|"*) ;; + *) + echo "Run 'git restore --staged $top_dir' to remove the whole output folder from the staging area." + seen_dirs="$seen_dirs|$top_dir|" + ;; + esac + fi +done < <(git diff --cached --name-only) + +exit "$status" diff --git a/.nf-core.yml b/.nf-core.yml index f7b23f8..8ceb31e 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -1,15 +1,19 @@ +lint: + files_unchanged: + - assets/nf-core-funcprofiler_logo_light.png + - .github/PULL_REQUEST_TEMPLATE.md + - .github/workflows/linting.yml + - .github/workflows/branch.yml + - .gitignore +nf_core_version: 4.1.0 repository_type: pipeline -nf_core_version: 3.3.2 - -lint: {} - template: - org: nf-core - name: funcprofiler + author: Nick Waters, Vini Salazar, Yixuan Yang, Mirae Baichoo description: Read-based functional profiling of microbiome sequencing data - author: Nick Waters - version: 1.0.0dev - force: true - outdir: . + force: false is_nfcore: true + name: funcprofiler + org: nf-core + outdir: . + version: 1.0.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bb41bee..e9503db 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,24 +4,47 @@ repos: hooks: - id: prettier additional_dependencies: - - prettier@3.6.2 + - prettier@3.9.6 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] exclude: | (?x)^( .*ro-crate-metadata.json$| - modules/nf-core/.*| - subworkflows/nf-core/.*| + modules/(?!local/).*| + subworkflows/(?!local/).*| .*\.snap$ )$ - id: end-of-file-fixer exclude: | (?x)^( .*ro-crate-metadata.json$| - modules/nf-core/.*| - subworkflows/nf-core/.*| + modules/(?!local/).*| + subworkflows/(?!local/).*| .*\.snap$ )$ + - id: check-added-large-files + args: [--maxkb=5000] + exclude: | + (?x)^( + .*ro-crate-metadata.json$| + .*\.snap$| + lib/nfcore_external_java_deps.jar$| + docs/.*\.(svg|pdf)$| + assets/.*$ + )$ + - id: check-merge-conflict + - repo: https://github.com/seqeralabs/nf-lint-pre-commit + rev: v0.3.0 + hooks: + - id: nextflow-lint + files: '\.nf$|nextflow\.config$' + args: ["-output", "json"] + - repo: local + hooks: + - id: block-pipeline-outdir + name: Prevent committing output from pipeline test runs to the pipeline code itself + entry: ./.hooks/block_pipeline_outdir.sh + language: script diff --git a/.prettierignore b/.prettierignore index edd29f0..63cde50 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,4 @@ email_template.html -adaptivecard.json -slackreport.json .nextflow* work/ data/ @@ -10,4 +8,7 @@ testing/ testing* *.pyc bin/ +.nf-test/ ro-crate-metadata.json +modules/nf-core/ +subworkflows/nf-core/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a029db..1d93637 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## v1.0.0dev - [date] +## v1.0.0 - [unreleased] Initial release of nf-core/funcprofiler, created with the [nf-core](https://nf-co.re/) template. +Read-based functional profiling of short-read microbiome sequencing data with the following profilers, all off by default and each enabled with its own `--run_` flag: + +- [HUMAnN](https://huttenhower.sph.harvard.edu/humann/) v3 and v4, each preceded by a [MetaPhlAn](https://github.com/biobakery/MetaPhlAn) taxonomic prescreen and followed by `humann_regroup_table` +- [FMH FunProfiler](https://github.com/KoslickiLab/fmh-funprofiler) +- [mi-faser](https://bromberglab.org/project/mifaser/) +- [RGI](https://github.com/arpcard/rgi) `bwt`, against CARD +- [DIAMOND](https://github.com/bbuchfink/diamond) `blastx` (beta) +- [eggNOG-mapper](https://github.com/eggnogdb/eggnog-mapper) (beta) + +This release performs no read QC or preprocessing; reads are expected to arrive already trimmed, quality filtered and host decontaminated. +Long-read platforms are not supported. + ### `Added` ### `Fixed` diff --git a/CITATIONS.md b/CITATIONS.md index 5f71d8d..7faf7a8 100644 --- a/CITATIONS.md +++ b/CITATIONS.md @@ -10,14 +10,56 @@ ## Pipeline tools -- [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) + -> Andrews, S. (2010). FastQC: A Quality Control Tool for High Throughput Sequence Data [Online]. +- [DIAMOND](https://github.com/bbuchfink/diamond/) + +> Buchfink B, Reuter K, Drost HG. Sensitive protein alignments at tree-of-life scale using DIAMOND. Nat Methods. 2021 Apr;18(4):366-368. doi: 10.1038/s41592-021-01101-x. PubMed PMID: 33828273. + +> Buchfink B, Xie C, Huson DH. Fast and sensitive protein alignment using DIAMOND. Nat Methods. 2015 Jan;12(1):59-60. doi: 10.1038/nmeth.3176. Epub 2014 Nov 17. PMID: 25402007. + +- [eggNOG-mapper](https://github.com/eggnogdb/eggnog-mapper) + +> Cantalapiedra CP, Hernández-Plaza A, Letunic I, Bork P, Huerta-Cepas J. eggNOG-mapper v2: Functional Annotation, Orthology Assignments, and Domain Prediction at the Metagenomic Scale. Mol Biol Evol. 2021 Dec 9;38(12):5825-5829. doi: 10.1093/molbev/msab293. PubMed PMID: 34597405. + +- [fmh-funprofiler](https://pubmed.ncbi.nlm.nih.gov/39230701/) + +> Hera MR, Liu S, Wei W, Rodriguez JS, Ma C, Koslicki D. Metagenomic functional profiling: to sketch or not to sketch? Bioinformatics. 2024 Sep 1;40(Suppl 2):ii165-ii173. doi: 10.1093/bioinformatics/btae397. PMID: 39230701; PMCID: PMC11373326. + +- [HUMAnN](http://huttenhower.sph.harvard.edu/humann) + +> Beghini F, McIver L, Blanco-Mìguez A, Dubois L, Asnicar F, Maharjan S ,Mailyan A, Thomas AM, Manghi P, Valles-Colomer M, Weingart G ,Zhang Y, Zolfo M,Huttenhower C, Franzosa EA, Segata N. Integrating taxonomic, functional, and strain-level profiling of diverse microbial communities with bioBakery 3. eLife 2021;10:e65088 + +- [mi-faser](https://academic.oup.com/nar/advance-article/doi/10.1093/nar/gkx1209/4670955) + +> Zhu C, Miller M, Marpaka S, Vaysberg P, Rühlemann M, Wu G, Heinsen FA, Tempel M, Zhao L, Leib W, Franke A, Bromberg Y. Functional sequencing read annotation for high precision microbiome analysis. Nucleic Acids Research. Volume 46, Issue 4. 2017. doi: 10.1093/nar/gkx1209. + +> Mahlich Y, Zhu C, Chung H, Velaga PK, De Paolis Kaluza MC, Radivojac P, Friedberg I, Bromberg Y. Learning from the unknown: exploring the range of bacterial functionality. Nucleic Acids Res. 2023 Oct 27;51(19):10162-10175. doi: 10.1093/nar/gkad757. PubMed PMID: 37739408. + +> Zhu C, Delmont TO, Vogel TM, Bromberg Y. Functional Basis of Microorganism Classification. PLoS Comput Biol. 2015 Aug 28;11(8):e1004472. doi: 10.1371/journal.pcbi.1004472. PubMed PMID: 26317871. + +- [MetaPhlAn3](http://segatalab.cibio.unitn.it/tools/metaphlan/index.html) + +> Beghini F, McIver LJ, Blanco-Míguez A, Dubois L, Asnicar F, Maharjan S, Mailyan A, Manghi P, Scholz M, Thomas AM, Valles-Colomer M, Weingart G, Zhang Y, Zolfo M, Huttenhower C, Franzosa EA, Segata N. Integrating taxonomic, functional, and strain-level profiling of diverse microbial communities with bioBakery 3. Elife. 2021 May 4;10:e65088. doi: 10.7554/eLife.65088. PMID: 33944776; PMCID: PMC8096432. + +- [MetaPhlAn4](http://segatalab.cibio.unitn.it/tools/metaphlan/index.html) + +> Blanco-Míguez A, Beghini F, Cumbo F, McIver LJ, Thompson KN, Zolfo M, Manghi P, Dubois L, Huang KD, Thomas AM, Nickols WA, Piccinno G, Piperni E, Punčochář M, Valles-Colomer M, Tett A, Giordano F, Davies R, Wolf J, Berry SE, Spector TD, Franzosa EA, Pasolli E, Asnicar F, Huttenhower C, Segata N. Extending and improving metagenomic taxonomic profiling with uncharacterized species using MetaPhlAn 4. Nat Biotechnol. 2023 Nov;41(11):1633-1644. doi: 10.1038/s41587-023-01688-w. Epub 2023 Feb 23. PMID: 36823356; PMCID: PMC10635831. - [MultiQC](https://pubmed.ncbi.nlm.nih.gov/27312411/) > Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics. 2016 Oct 1;32(19):3047-8. doi: 10.1093/bioinformatics/btw354. Epub 2016 Jun 16. PubMed PMID: 27312411; PubMed Central PMCID: PMC5039924. +- [RGI/CARD](https://pubmed.ncbi.nlm.nih.gov/36263822/) + +> Alcock BP, Huynh W, Chalil R, Smith KW, Raphenya AR, Wlodarski MA, Edalatmand A, Petkau A, Syed SA, Tsang KK, Baker SJC, Dave M, McCarthy MC, Mukiri KM, Nasir JA, Golbon B, Imtiaz H, Jiang X, Kaur K, Kwong M, Liang ZC, Niu KC, Shan P, Yang JYJ, Gray KL, Hoad GR, Jia B, Bhando T, Carfrae LA, Farha MA, French S, Gordzevich R, Rachwalski K, Tu MM, Bordeleau E, Dooley D, Griffiths E, Zubyk HL, Brown ED, Maguire F, Beiko RG, Hsiao WWL, Brinkman FSL, Van Domselaar G, McArthur AG. CARD 2023: expanded curation, support for machine learning, and resistome prediction at the Comprehensive Antibiotic Resistance Database. Nucleic Acids Res. 2023 Jan 6;51(D1):D690-D699. doi: 10.1093/nar/gkac920. PMID: 36263822; PMCID: PMC9825576. + +> McArthur AG, Waglechner N, Nizam F, Yan A, Azad MA, Baylay AJ, Bhullar K, Canova MJ, De Pascale G, Ejim L, Kalan L, King AM, Koteva K, Morar M, Mulvey MR, O'Brien JS, Pawlowski AC, Piddock LJ, Spanogiannopoulos P, Sutherland AD, Tang I, Taylor PL, Thaker M, Wang W, Yan M, Yu T, Wright GD. The comprehensive antibiotic resistance database. Antimicrob Agents Chemother. 2013 Jul;57(7):3348-57. doi: 10.1128/AAC.00419-13. Epub 2013 May 6. PMID: 23650175; PMCID: PMC3697360. + +- [seqkit](https://pubmed.ncbi.nlm.nih.gov/27706213/) + +> Shen W, Le S, Li Y, Hu F. SeqKit: A Cross-Platform and Ultrafast Toolkit for FASTA/Q File Manipulation. PLoS One. 2016 Oct 5;11(10):e0163962. doi: 10.1371/journal.pone.0163962. PMID: 27706213; PMCID: PMC5051824. + ## Software packaging/containerisation tools - [Anaconda](https://anaconda.com) diff --git a/README.md b/README.md index 770a6da..5109d6e 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,13 @@ +[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/funcprofiler) [![GitHub Actions CI Status](https://github.com/nf-core/funcprofiler/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/funcprofiler/actions/workflows/nf-test.yml) [![GitHub Actions Linting Status](https://github.com/nf-core/funcprofiler/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/funcprofiler/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/funcprofiler/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) [![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) -[![Nextflow](https://img.shields.io/badge/version-%E2%89%A524.10.5-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) -[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.3.2-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.3.2) +[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.4-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) +[![nf-core template version](https://img.shields.io/badge/nf--core_template-4.1.0-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/4.1.0) [![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/) [![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/) [![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/) @@ -20,52 +21,67 @@ ## Introduction -**nf-core/funcprofiler** is a bioinformatics pipeline that ... +**nf-core/funcprofiler** is a bioinformatics pipeline for read-based functional profiling of microbiome sequencing data. It accepts already preprocessed short-read FASTQ files and runs one or more functional profilers against user-supplied databases, producing gene family abundances, pathway abundances, pathway coverages, and antimicrobial resistance profiles. Long-read platforms are not supported in this release. - +### Pipeline Summary - -1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/)) +![](./assets/pipeline_light.svg) + +Supported profilers and current status: + +1. [**HUMANn v3**](https://huttenhower.sph.harvard.edu/humann/) — functional profiling via MetaPhlAn + HUMANn 3 (`--run_humann_v3`) +2. [**HUMANn v4**](https://docs.google.com/document/d/1rCx5JkuO7wCKWrL8_-UJx_FkopJAfcDFtZktgPspak0/edit?tab=t.0#heading=h.i5hn0zprhwld) — functional profiling via MetaPhlAn + HUMANn 4 (`--run_humann_v4`) +3. [**FMH FunProfiler**](https://github.com/KoslickiLab/fmh-funprofiler) — sketch-based functional profiling (`--run_fmhfunprofiler`) +4. [**RGI**](https://github.com/arpcard/rgi) — antimicrobial resistance gene identification (`--run_rgi`, available) +5. [**mifaser**](https://bromberglab.org/project/mifaser/) — functional profiling via mifaser (`--run_mifaser`, available) +6. [**DIAMOND**](https://github.com/bbuchfink/diamond) — alignment with DIAMOND blastx (`--run_diamond`, work in progress / beta) +7. [**eggNOG-mapper**](https://github.com/eggnogdb/eggnog-mapper) — functional annotation, orthology assignments and domain prediction (`--run_eggnogmapper`, work in progress / beta) + +> [!WARNING] +> DIAMOND and eggNOG-mapper support is currently in beta and should be treated as work in progress. These modules are still being validated in the full pipeline, including database handling, output behavior, and downstream reporting. Use them with caution, expect potential issues, and independently review results before using them for production analyses or interpretation. ## Usage > [!NOTE] -> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data. - - +Then prepare a databases sheet — see [docs/usage.md](docs/usage.md) for the full format. Here is an abbreviated example for running HUMANn (which requires 4 databases): -Now, you can run the pipeline using: +`databases.csv` - +```csv +tool,db_name,db_entity,db_params,db_path +humann_v3,uniref90_v3,humann_metaphlan,,/data/databases/metaphlan_db +humann_v3,uniref90_v3,humann_nucleotide,,/data/databases/chocophlan +humann_v3,uniref90_v3,humann_protein,,/data/databases/uniref90_diamond +humann_v3,uniref90_v3,humann_utility,,/data/databases/utility_mapping +``` + +Now, you can run the pipeline using: ```bash nextflow run nf-core/funcprofiler \ -profile \ --input samplesheet.csv \ - --outdir + --outdir \ + --databases databases.csv \ + --run_humann_v3 ``` > [!WARNING] -> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files). +> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/running/run-pipelines#using-parameter-files). For more details and further functionality, please refer to the [usage documentation](https://nf-co.re/funcprofiler/usage) and the [parameter documentation](https://nf-co.re/funcprofiler/parameters). @@ -77,25 +93,24 @@ For more details about the output files and reports, please refer to the ## Credits -nf-core/funcprofiler was originally written by Nick Waters. +nf-core/funcprofiler was originally written by Nick Waters, Vini Salazar, Yixuan Yang, Mirae Baichoo. We thank the following people for their extensive assistance in the development of this pipeline: - +- Matthias Hörtenhuber +- James Fellows Yates +- Jonas Scheid ## Contributions and Support -If you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md). +If you would like to contribute to this pipeline, please see the [contributing guidelines](docs/CONTRIBUTING.md). For further information or help, don't hesitate to get in touch on the [Slack `#funcprofiler` channel](https://nfcore.slack.com/channels/funcprofiler) (you can join with [this invite](https://nf-co.re/join/slack)). ## Citations - - - An extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file. You can cite the `nf-core` publication as follows: diff --git a/assets/adaptivecard.json b/assets/adaptivecard.json deleted file mode 100644 index 4a0a4e4..0000000 --- a/assets/adaptivecard.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "type": "message", - "attachments": [ - { - "contentType": "application/vnd.microsoft.card.adaptive", - "contentUrl": null, - "content": { - "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "msteams": { - "width": "Full" - }, - "type": "AdaptiveCard", - "version": "1.2", - "body": [ - { - "type": "TextBlock", - "size": "Large", - "weight": "Bolder", - "color": "<% if (success) { %>Good<% } else { %>Attention<%} %>", - "text": "nf-core/funcprofiler v${version} - ${runName}", - "wrap": true - }, - { - "type": "TextBlock", - "spacing": "None", - "text": "Completed at ${dateComplete} (duration: ${duration})", - "isSubtle": true, - "wrap": true - }, - { - "type": "TextBlock", - "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors. The full error message was: ${errorReport}.<% } %>", - "wrap": true - }, - { - "type": "TextBlock", - "text": "The command used to launch the workflow was as follows:", - "wrap": true - }, - { - "type": "TextBlock", - "text": "${commandLine}", - "isSubtle": true, - "wrap": true - } - ], - "actions": [ - { - "type": "Action.ShowCard", - "title": "Pipeline Configuration", - "card": { - "type": "AdaptiveCard", - "\$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "body": [ - { - "type": "FactSet", - "facts": [<% out << summary.collect{ k,v -> "{\"title\": \"$k\", \"value\" : \"$v\"}"}.join(",\n") %> - ] - } - ] - } - } - ] - } - } - ] -} diff --git a/assets/methods_description_template.yml b/assets/methods_description_template.yml index d1de92d..7900625 100644 --- a/assets/methods_description_template.yml +++ b/assets/methods_description_template.yml @@ -3,7 +3,6 @@ description: "Suggested text and references to use when describing pipeline usag section_name: "nf-core/funcprofiler Methods Description" section_href: "https://github.com/nf-core/funcprofiler" plot_type: "html" -## TODO nf-core: Update the HTML below to your preferred methods description, e.g. add publication citation for this pipeline ## You inject any metadata in the Nextflow '${workflow}' object data: |

Methods

diff --git a/assets/multiqc_config.yml b/assets/multiqc_config.yml index 4b613e4..6d55204 100644 --- a/assets/multiqc_config.yml +++ b/assets/multiqc_config.yml @@ -1,7 +1,7 @@ report_comment: > - This report has been generated by the nf-core/funcprofiler + This report has been generated by the nf-core/funcprofiler analysis pipeline. For information about how to interpret these results, please see the - documentation. + documentation. report_section_order: "nf-core-funcprofiler-methods-description": order: -1000 diff --git a/assets/nf-core-funcprofiler_logo_light.png b/assets/nf-core-funcprofiler_logo_light.png index e2abc52..2f68d36 100644 Binary files a/assets/nf-core-funcprofiler_logo_light.png and b/assets/nf-core-funcprofiler_logo_light.png differ diff --git a/assets/nf-metro_command.sh b/assets/nf-metro_command.sh new file mode 100644 index 0000000..3902fdd --- /dev/null +++ b/assets/nf-metro_command.sh @@ -0,0 +1,8 @@ +# --x-spacing 110 is load-bearing: the layout was tuned at that spacing. +# The committed SVGs also carry manual geometry corrections that nf-metro has no +# directive for (the 'Short reads' caption re-anchored clear of the exit port, +# the database bundle and report lane routed below the reads trunk, the two file +# icons centred in their section boxes), so a plain re-render will not reproduce +# them byte-for-byte. +nf-metro render pipeline.mmd -o pipeline_light.svg --logo nf-core-funcprofiler_logo_light.png --theme light --animate --x-spacing 110 +nf-metro render pipeline.mmd -o pipeline_nf-core.svg --logo nf-core-funcprofiler_logo_light.png --theme nfcore --animate --x-spacing 110 diff --git a/assets/pipeline.mmd b/assets/pipeline.mmd new file mode 100644 index 0000000..69f8ed3 --- /dev/null +++ b/assets/pipeline.mmd @@ -0,0 +1,140 @@ +%%metro title: nf-core/funcprofiler +%%metro logo: nf-core-funcprofiler_logo_light.png +%%metro line_spread: bundle + + +%% One line per input type, as on the nf-core/taxprofiler tube map: the tool a +%% route ends at is already named by the station it stops at. Blue stops at +%% 'merge & concat' and green carries everything downstream of it, RGI included. +%% That is a deliberate simplification: RGI is actually fed the unconcatenated +%% reads (subworkflows/local/profile/main.nf:41 builds its channel from 'reads' +%% with singleFqTool = false, every other tool from 'reads_concat'), but drawing +%% that ran a second blue strand through the profiling block for one tool. +%%metro line: shortread | Short reads | #1B7FC4 +%%metro line: concat | Concatenated reads | #14795A +%% The reports branch. Orange so the split at the results junction reads as two +%% different things leaving it, not one bundle drawn twice. It runs from every +%% profiler, not just from the junction: that is what MultiQC actually collates, +%% and it is also what lifts the junction onto the top lane, level with Output. +%% A junction station otherwise centres on the mean row of its inputs, which +%% with seven profiler lanes is three rows down; giving it a line that reaches a +%% row-0 station pulls it up. +%%metro line: report | Summary statistics | #E8871A +%% Three strands so the databases read as a bundle, as on the taxprofiler map. +%% Three hues of the same purple, not three different colours: they are one +%% thing. legend_combo collapses them into one striped legend row. +%%metro line: db | Databases | #6D3F9E +%%metro line: db2 | Databases | #A263C9 +%%metro line: db3 | Databases | #C89BE0 +%%metro legend_combo: db, db2, db3 | Databases + +%%metro marker_legend: circle, open | Opt-in +%%metro marker_legend: circle, #333333 | Runs by default + +%% Filled markers take the colour of the line they sit on rather than a flat +%% #333333, so the dot reads as part of its route. +%%metro marker: prep | circle, #1B7FC4 +%%metro marker: multiqc | circle, #E8871A +%%metro marker: hub | circle, #14795A +%%metro marker: results | circle, #14795A + +%%metro files: input_reads | fastq | Short reads | banner +%%metro files: input_dbs | db | Databases | banner +%%metro file: out_tables | tsv | Abundance tables | banner + +%% Three grid rows, with Functional profiling spanning all three. Input is on +%% row 0 level with the top of profiling and Run merging directly beneath it +%% on row 1; Summary statistics shares row 1, under Output. The third row +%% is what puts Run merging where it belongs: a spanning section dumps its +%% leftover height into the row above the last one it occupies, so with only two +%% rows the whole slack landed between Input and Run merging and pushed +%% Run merging to the bottom of the canvas. +%%metro grid: input | 0,0 +%%metro grid: merging | 0,1 +%%metro grid: profiling | 1,0,3 +%%metro grid: qc | 2,1 +%%metro grid: output | 2,0 + +graph LR + subgraph input[Input] + %% TB is what makes the drop into Run merging a single straight line: + %% the exit port moves to the bottom of the icon instead of its right + %% edge, so the route never has to cross this section's boundary + %% sideways. It does put the 'Short reads' caption under the port + %% circle, which a post-render pass moves to the icon's top right. + %%metro direction: TB + %%metro exit: bottom | shortread + input_reads([Short reads]) + end + + subgraph merging[Run merging] + %% Entry hint only. Without it blue U-turns around this section. An + %% explicit '%%metro exit:' on Input changes nothing: the descent still + %% steps 10px sideways where it crosses this section's top edge, because + %% the route leaves Input at the section boundary (x=207) and the entry + %% port sits at the inset (x=197). + %%metro entry: top | shortread + prep(merge & concat) + end + + subgraph profiling[Functional profiling] + input_dbs([Databases]) + hub(( )) + %% RGI first: it is the only station the paired line reaches, and a + %% branching line declared later strikes through the labels above it. + rgi(RGI) + metaphlan3(MetaPhlAn) + humann3(HUMAnN v3) + metaphlan4(MetaPhlAn) + humann4(HUMAnN v4) + eggnog(eggNOG-mapper) + fmhfunprofiler(FMH FunProfiler) + mifaser(mi-faser) + diamond(DIAMOND) + %% Unnamed junction: the seven profiler outputs join here, and the split + %% to the tables and to MultiQC happens once instead of seven times. + results(( )) + end + + subgraph qc[Summary statistics] + multiqc(MultiQC) + end + + subgraph output[Output] + out_tables([Abundance tables]) + end + + %% Runs of one sample are merged first, and the map then treats every + %% profiler as reading the concatenated FASTQ. See the note on the lines. + input_reads -->|shortread| prep + prep -->|concat| hub + hub -->|concat| rgi + + hub -->|concat| metaphlan3 + hub -->|concat| metaphlan4 + hub -->|concat| eggnog + hub -->|concat| fmhfunprofiler + hub -->|concat| mifaser + hub -->|concat| diamond + + metaphlan3 -->|concat| humann3 + metaphlan4 -->|concat| humann4 + + %% The database bundle terminates at the hub. It does not continue into the + %% profiler lanes: the hub is where the databases are handed over. + input_dbs -->|db,db2,db3| hub + + %% Results leave the profilers as one bundle and split at the section edge. + rgi -->|concat,report| results + humann3 -->|concat,report| results + humann4 -->|concat,report| results + eggnog -->|concat,report| results + fmhfunprofiler -->|concat,report| results + mifaser -->|concat,report| results + diamond -->|concat,report| results + + %% Two branches off the junction: tables on green, run statistics on orange. + %% Orange reaches the junction from each profiler above, so the junction is + %% a real interchange rather than the point where the reports appear. + results -->|concat| out_tables + results -->|report| multiqc diff --git a/assets/pipeline_light.svg b/assets/pipeline_light.svg new file mode 100644 index 0000000..0e1435f --- /dev/null +++ b/assets/pipeline_light.svg @@ -0,0 +1,213 @@ + + + + +{"groups":[{"color":"#1B7FC4","id":"shortread","label":"Short reads"},{"color":"#14795A","id":"concat","label":"Concatenated reads"},{"color":"#E8871A","id":"report","label":"Summary statistics"},{"color":"#6D3F9E","id":"db","label":"Databases"},{"color":"#A263C9","id":"db2","label":"Databases"},{"color":"#C89BE0","id":"db3","label":"Databases"}],"height":749,"match":{"flags":"i","target":"fqProcessName","type":"regex"},"nodes":[{"groups":["shortread"],"h":12.0,"id":"input_reads","label":"Short reads","patterns":[],"r":6.0,"region":"input","rx":6.0,"w":12.0,"x":207.0,"y":116.8},{"groups":["concat","shortread"],"h":12.0,"id":"prep","label":"merge & concat","patterns":[],"r":6.0,"region":"merging","rx":6.0,"w":12.0,"x":262.0,"y":294.8},{"groups":["db","db2","db3"],"h":20.0,"id":"input_dbs","label":"Databases","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":410.0,"y":179.2},{"groups":["concat","db","db2","db3"],"h":28.0,"id":"hub","label":"hub","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":586.0,"y":124.8},{"groups":["concat","report"],"h":16.0,"id":"rgi","label":"RGI","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":762.0,"y":130.8},{"groups":["concat"],"h":12.0,"id":"metaphlan3","label":"MetaPhlAn","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":762.0,"y":424.8},{"groups":["concat","report"],"h":16.0,"id":"humann3","label":"HUMAnN v3","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":872.0,"y":422.8},{"groups":["concat"],"h":12.0,"id":"metaphlan4","label":"MetaPhlAn","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":762.0,"y":483.2},{"groups":["concat","report"],"h":16.0,"id":"humann4","label":"HUMAnN v4","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":872.0,"y":481.2},{"groups":["concat","report"],"h":16.0,"id":"eggnog","label":"eggNOG-mapper","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":762.0,"y":189.2},{"groups":["concat","report"],"h":16.0,"id":"fmhfunprofiler","label":"FMH FunProfiler","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":762.0,"y":247.6},{"groups":["concat","report"],"h":16.0,"id":"mifaser","label":"mi-faser","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":762.0,"y":306.0},{"groups":["concat","report"],"h":16.0,"id":"diamond","label":"DIAMOND","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":762.0,"y":364.4},{"groups":["concat","report"],"h":16.0,"id":"results","label":"results","patterns":[],"r":6.0,"region":"profiling","rx":6.0,"w":12.0,"x":1048.0,"y":130.8},{"groups":["report"],"h":12.0,"id":"multiqc","label":"MultiQC","patterns":[],"r":6.0,"region":"qc","rx":6.0,"w":12.0,"x":1253.0,"y":294.8},{"groups":["concat"],"h":12.0,"id":"out_tables","label":"Abundance tables","patterns":[],"r":6.0,"region":"output","rx":6.0,"w":12.0,"x":1279.0,"y":132.8}],"regions":[{"id":"input","label":"Input"},{"id":"merging","label":"Run merging"},{"id":"profiling","label":"Functional profiling"},{"id":"qc","label":"Summary statistics"},{"id":"output","label":"Output"}],"title":"nf-core/funcprofiler","version":"1.0","width":1415} + + + + +1 + + + +2 + + + +3 + + + +5 + + + +4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +fastq +Short reads + + + + + + + + + + + + + + + +db +Databases + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +tsv +Abundance tables + + + +merge & concat + +MultiQC + +RGI + +eggNOG-mapper + +FMH FunProfiler + +mi-faser + +DIAMOND + +MetaPhlAn + +MetaPhlAn + +HUMAnN v3 + +HUMAnN v4 + + + +Short reads + +Concatenated reads + +Summary statistics + + + +Databases + +Opt-in + +Runs by default +created with nf-metro v1.1.0 + diff --git a/assets/pipeline_nf-core.svg b/assets/pipeline_nf-core.svg new file mode 100644 index 0000000..659d39f --- /dev/null +++ b/assets/pipeline_nf-core.svg @@ -0,0 +1,209 @@ + + + + +{"groups":[{"color":"#1B7FC4","id":"shortread","label":"Short reads"},{"color":"#14795A","id":"concat","label":"Concatenated reads"},{"color":"#E8871A","id":"report","label":"Summary statistics"},{"color":"#6D3F9E","id":"db","label":"Databases"},{"color":"#A263C9","id":"db2","label":"Databases"},{"color":"#C89BE0","id":"db3","label":"Databases"}],"height":749,"match":{"flags":"i","target":"fqProcessName","type":"regex"},"nodes":[{"groups":["shortread"],"h":10.0,"id":"input_reads","label":"Short reads","patterns":[],"r":5.0,"region":"input","rx":5.0,"w":10.0,"x":207.0,"y":116.8},{"groups":["concat","shortread"],"h":10.0,"id":"prep","label":"merge & concat","patterns":[],"r":5.0,"region":"merging","rx":5.0,"w":10.0,"x":262.0,"y":294.8},{"groups":["db","db2","db3"],"h":18.0,"id":"input_dbs","label":"Databases","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":410.0,"y":179.2},{"groups":["concat","db","db2","db3"],"h":26.0,"id":"hub","label":"hub","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":586.0,"y":124.8},{"groups":["concat","report"],"h":14.0,"id":"rgi","label":"RGI","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":762.0,"y":130.8},{"groups":["concat"],"h":10.0,"id":"metaphlan3","label":"MetaPhlAn","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":762.0,"y":424.8},{"groups":["concat","report"],"h":14.0,"id":"humann3","label":"HUMAnN v3","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":872.0,"y":422.8},{"groups":["concat"],"h":10.0,"id":"metaphlan4","label":"MetaPhlAn","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":762.0,"y":483.2},{"groups":["concat","report"],"h":14.0,"id":"humann4","label":"HUMAnN v4","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":872.0,"y":481.2},{"groups":["concat","report"],"h":14.0,"id":"eggnog","label":"eggNOG-mapper","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":762.0,"y":189.2},{"groups":["concat","report"],"h":14.0,"id":"fmhfunprofiler","label":"FMH FunProfiler","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":762.0,"y":247.6},{"groups":["concat","report"],"h":14.0,"id":"mifaser","label":"mi-faser","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":762.0,"y":306.0},{"groups":["concat","report"],"h":14.0,"id":"diamond","label":"DIAMOND","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":762.0,"y":364.4},{"groups":["concat","report"],"h":14.0,"id":"results","label":"results","patterns":[],"r":5.0,"region":"profiling","rx":5.0,"w":10.0,"x":1048.0,"y":130.8},{"groups":["report"],"h":10.0,"id":"multiqc","label":"MultiQC","patterns":[],"r":5.0,"region":"qc","rx":5.0,"w":10.0,"x":1253.0,"y":294.8},{"groups":["concat"],"h":10.0,"id":"out_tables","label":"Abundance tables","patterns":[],"r":5.0,"region":"output","rx":5.0,"w":10.0,"x":1279.0,"y":132.8}],"regions":[{"id":"input","label":"Input"},{"id":"merging","label":"Run merging"},{"id":"profiling","label":"Functional profiling"},{"id":"qc","label":"Summary statistics"},{"id":"output","label":"Output"}],"title":"nf-core/funcprofiler","version":"1.0","width":1415} + + + + +1 + + + +2 + + + +3 + + + +5 + + + +4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +fastq +Short reads + + + + + + + + + + + + + + + +db +Databases + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +tsv +Abundance tables + + + +merge & concat + +MultiQC + +RGI + +eggNOG-mapper + +FMH FunProfiler + +mi-faser + +DIAMOND + +MetaPhlAn + +MetaPhlAn + +HUMAnN v3 + +HUMAnN v4 + + + +Short reads + +Concatenated reads + +Summary statistics + + + +Databases + +Opt-in + +Runs by default +created with nf-metro v1.1.0 + diff --git a/assets/schema_database.json b/assets/schema_database.json new file mode 100644 index 0000000..1937796 --- /dev/null +++ b/assets/schema_database.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/nf-core/funcprofiler/main/assets/schema_database.json", + "title": "nf-core/funcprofiler pipeline - params.database schema", + "description": "Schema for the file provided with params.database", + "type": "array", + "items": { + "type": "object", + "properties": { + "tool": { + "type": "string", + "enum": ["humann_v3", "humann_v4", "fmhfunprofiler", "rgi", "mifaser", "diamond", "eggnogmapper"], + "errorMessage": "Invalid tool name. Please see documentation for all supported profilers.", + "meta": ["tool"] + }, + "db_name": { + "type": "string", + "pattern": "^\\S+$", + "help_text": "Name of the database as a whole, i.e. the release or version you want recorded in the results (e.g. `uniref90_v3`). All rows belonging to the same database must share this name.", + "errorMessage": "A unique name of the database should be provided.", + "meta": ["db_name"] + }, + "db_entity": { + "type": "string", + "enum": [ + "humann_metaphlan", + "humann_nucleotide", + "humann_utility", + "humann_protein", + "eggnogmapper_db", + "eggnogmapper_data_dir" + ], + "help_text": "Name of the individual component (entity) of the database given in `db_name`. Tools that take a single database file or directory leave this empty; tools that need several components require one row per component, all sharing the same `db_name`. HUMAnN needs `humann_metaphlan`, `humann_nucleotide`, `humann_protein` and `humann_utility`; eggNOG-mapper needs `eggnogmapper_db` and `eggnogmapper_data_dir`.", + "errorMessage": "Invalid db_entity. For HUMAnN, specify whether db_path is the humann_metaphlan, humann_nucleotide, humann_protein or humann_utility component; for eggnogmapper, specify eggnogmapper_db or eggnogmapper_data_dir. Leave empty for tools that take a single database.", + "meta": ["db_entity"] + }, + "db_params": { + "type": "string", + "pattern": "^[^\"']*$", + "errorMessage": "Invalid database db_params entry. No quotes allowed.", + "meta": ["db_params"] + }, + "db_path": { + "type": "string", + "exists": true, + "format": "path", + "errorMessage": "db_path should be either a file path or a directory." + } + }, + "required": ["tool", "db_name", "db_path"] + }, + "uniqueEntries": ["tool", "db_name", "db_entity"] +} diff --git a/assets/schema_input.json b/assets/schema_input.json index 6529c93..1cf6b5a 100644 --- a/assets/schema_input.json +++ b/assets/schema_input.json @@ -8,26 +8,59 @@ "type": "object", "properties": { "sample": { - "type": "string", - "pattern": "^\\S+$", - "errorMessage": "Sample name must be provided and cannot contain spaces", + "type": ["string", "integer"], + "pattern": "^[^\\s]+$", + "errorMessage": "Sample name must be a string or an integer and cannot contain spaces", "meta": ["id"] }, + "run_accession": { + "type": ["string", "integer"], + "pattern": "^[^\\s]+$", + "errorMessage": "Run accession must be provided and cannot contain spaces." + }, + "instrument_platform": { + "type": "string", + "enum": [ + "ABI_SOLID", + "BGISEQ", + "CAPILLARY", + "COMPLETE_GENOMICS", + "DNBSEQ", + "HELICOS", + "ILLUMINA", + "ION_TORRENT", + "LS454" + ], + "errorMessage": "Sequencing platform must be provided. Long-read platforms (OXFORD_NANOPORE, PACBIO_SMRT) are not supported." + }, "fastq_1": { "type": "string", - "format": "file-path", "exists": true, - "pattern": "^([\\S\\s]*\\/)?[^\\s\\/]+\\.f(ast)?q\\.gz$", - "errorMessage": "FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" + "format": "file-path", + "pattern": "^\\S+\\.f(ast)?q\\.gz$", + "errorMessage": "Gzipped FastQ file for reads 1 must be provided, cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" }, "fastq_2": { "type": "string", + "exists": true, "format": "file-path", + "pattern": "^\\S+\\.f(ast)?q\\.gz$", + "errorMessage": "Gzipped FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'. If not applicable, leave it empty." + }, + "fasta": { + "type": "string", "exists": true, - "pattern": "^([\\S\\s]*\\/)?[^\\s\\/]+\\.f(ast)?q\\.gz$", - "errorMessage": "FastQ file for reads 2 cannot contain spaces and must have extension '.fq.gz' or '.fastq.gz'" + "format": "file-path", + "pattern": "^\\S+\\.(fasta|fas|fna|fa)\\.gz?$", + "errorMessage": "FastA input is not supported by nf-core/funcprofiler. The column is accepted for compatibility with nf-core/taxprofiler samplesheets, but must be left empty." } }, - "required": ["sample", "fastq_1"] - } + "required": ["sample", "run_accession", "instrument_platform", "fastq_1"] + }, + "allOf": [ + { "uniqueEntries": ["fastq_1"] }, + { "uniqueEntries": ["fastq_2"] }, + { "uniqueEntries": ["fasta"] }, + { "uniqueEntries": ["sample", "run_accession"] } + ] } diff --git a/assets/slackreport.json b/assets/slackreport.json deleted file mode 100644 index db3564c..0000000 --- a/assets/slackreport.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "attachments": [ - { - "fallback": "Plain-text summary of the attachment.", - "color": "<% if (success) { %>good<% } else { %>danger<%} %>", - "author_name": "nf-core/funcprofiler ${version} - ${runName}", - "author_icon": "https://www.nextflow.io/docs/latest/_static/favicon.ico", - "text": "<% if (success) { %>Pipeline completed successfully!<% } else { %>Pipeline completed with errors<% } %>", - "fields": [ - { - "title": "Command used to launch the workflow", - "value": "```${commandLine}```", - "short": false - } - <% - if (!success) { %> - , - { - "title": "Full error message", - "value": "```${errorReport}```", - "short": false - }, - { - "title": "Pipeline configuration", - "value": "<% out << summary.collect{ k,v -> k == "hook_url" ? "_${k}_: (_hidden_)" : ( ( v.class.toString().contains('Path') || ( v.class.toString().contains('String') && v.contains('/') ) ) ? "_${k}_: `${v}`" : (v.class.toString().contains('DateTime') ? ("_${k}_: " + v.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM))) : "_${k}_: ${v}") ) }.join(",\n") %>", - "short": false - } - <% } - %> - ], - "footer": "Completed at <% out << dateComplete.format(java.time.format.DateTimeFormatter.ofLocalizedDateTime(java.time.format.FormatStyle.MEDIUM)) %> (duration: ${duration})" - } - ] -} diff --git a/conf/base.config b/conf/base.config index 05c9d05..49af73f 100644 --- a/conf/base.config +++ b/conf/base.config @@ -10,12 +10,11 @@ process { - // TODO nf-core: Check the defaults for all processes cpus = { 1 * task.attempt } memory = { 6.GB * task.attempt } time = { 4.h * task.attempt } - errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' } + errorStrategy = { task.exitStatus in ((130..145) + 104 + (175..177)) ? 'retry' : 'finish' } maxRetries = 1 maxErrors = '-1' @@ -24,7 +23,6 @@ process { // These labels are used and recognised by default in DSL2 files hosted on nf-core/modules. // If possible, it would be nice to keep the same label naming convention when // adding in your local modules too. - // TODO nf-core: Customise requirements for specific processes. // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors withLabel:process_single { cpus = { 1 } @@ -49,6 +47,9 @@ process { withLabel:process_long { time = { 20.h * task.attempt } } + withLabel:process_low_memory { + memory = { 1.GB * task.attempt } + } withLabel:process_high_memory { memory = { 200.GB * task.attempt } } diff --git a/conf/containers_conda_lock_files_amd64.config b/conf/containers_conda_lock_files_amd64.config new file mode 100644 index 0000000..dbe98ea --- /dev/null +++ b/conf/containers_conda_lock_files_amd64.config @@ -0,0 +1,2 @@ +process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt' } } +process { withName: 'RGI_BWT' { conda = 'modules/nf-core/rgi/bwt/.conda-lock/linux_amd64-bd-e905ecb8305e2609_1.txt' } } diff --git a/conf/containers_conda_lock_files_arm64.config b/conf/containers_conda_lock_files_arm64.config new file mode 100644 index 0000000..425f943 --- /dev/null +++ b/conf/containers_conda_lock_files_arm64.config @@ -0,0 +1,2 @@ +process { withName: 'MULTIQC' { conda = 'modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt' } } +process { withName: 'RGI_BWT' { conda = 'modules/nf-core/rgi/bwt/.conda-lock/linux_arm64-bd-fab5219836c1d880_1.txt' } } diff --git a/conf/containers_docker_amd64.config b/conf/containers_docker_amd64.config new file mode 100644 index 0000000..70e7784 --- /dev/null +++ b/conf/containers_docker_amd64.config @@ -0,0 +1,2 @@ +process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc' } } +process { withName: 'RGI_BWT' { container = 'community.wave.seqera.io/library/rgi_kma:e905ecb8305e2609' } } diff --git a/conf/containers_docker_arm64.config b/conf/containers_docker_arm64.config new file mode 100644 index 0000000..a3063f4 --- /dev/null +++ b/conf/containers_docker_arm64.config @@ -0,0 +1,2 @@ +process { withName: 'MULTIQC' { container = 'community.wave.seqera.io/library/multiqc:1.35--5c84a5000a226ab5' } } +process { withName: 'RGI_BWT' { container = 'community.wave.seqera.io/library/rgi_kma:fab5219836c1d880' } } diff --git a/conf/containers_singularity_https_amd64.config b/conf/containers_singularity_https_amd64.config new file mode 100644 index 0000000..86f4d30 --- /dev/null +++ b/conf/containers_singularity_https_amd64.config @@ -0,0 +1,2 @@ +process { withName: 'MULTIQC' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e346f4f6080eadf1253505e6ff09ef004454fc18e8d672006fd7b222cc412e/data' } } +process { withName: 'RGI_BWT' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/3f/3f452c8e124ee58ab6b26442d15401c57d471cb753f53921570dc484df4e7620/data' } } diff --git a/conf/containers_singularity_https_arm64.config b/conf/containers_singularity_https_arm64.config new file mode 100644 index 0000000..4e53bf6 --- /dev/null +++ b/conf/containers_singularity_https_arm64.config @@ -0,0 +1,2 @@ +process { withName: 'MULTIQC' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/e4/e48aa28aebc881254a499b24c3e1ce77b8df1b85a5432699ed6f72eb17ac7fb5/data' } } +process { withName: 'RGI_BWT' { container = 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e83b71b5dae10e1d771490c36f49d314718888c3cc8214350eb7f149090f0e/data' } } diff --git a/conf/containers_singularity_oras_amd64.config b/conf/containers_singularity_oras_amd64.config new file mode 100644 index 0000000..d2235d0 --- /dev/null +++ b/conf/containers_singularity_oras_amd64.config @@ -0,0 +1,2 @@ +process { withName: 'MULTIQC' { container = 'oras://community.wave.seqera.io/library/multiqc:1.35--c680f2aea25ccec2' } } +process { withName: 'RGI_BWT' { container = 'oras://community.wave.seqera.io/library/rgi_kma:06c9375141c15d16' } } diff --git a/conf/containers_singularity_oras_arm64.config b/conf/containers_singularity_oras_arm64.config new file mode 100644 index 0000000..9a0d1f1 --- /dev/null +++ b/conf/containers_singularity_oras_arm64.config @@ -0,0 +1,2 @@ +process { withName: 'MULTIQC' { container = 'oras://community.wave.seqera.io/library/multiqc:1.35--c0468833d65b2f81' } } +process { withName: 'RGI_BWT' { container = 'oras://community.wave.seqera.io/library/rgi_kma:a6eaadaaffbeaf85' } } diff --git a/conf/igenomes.config b/conf/igenomes.config index 3f11437..b8c8154 100644 --- a/conf/igenomes.config +++ b/conf/igenomes.config @@ -8,433 +8,431 @@ ---------------------------------------------------------------------------------------- */ -params { +params.genomes = [ // illumina iGenomes reference file paths - genomes { - 'GRCh37' { - fasta = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/GRCh37-blacklist.bed" - } - 'GRCh38' { - fasta = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/hg38-blacklist.bed" - } - 'CHM13' { - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAIndex/" - bwamem2 = "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAmem2Index/" - gtf = "${params.igenomes_base}/Homo_sapiens/NCBI/CHM13/Annotation/Genes/genes.gtf" - gff = "ftp://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0/GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz" - mito_name = "chrM" - } - 'GRCm38' { - fasta = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "1.87e9" - blacklist = "${projectDir}/assets/blacklists/GRCm38-blacklist.bed" - } - 'TAIR10' { - fasta = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/README.txt" - mito_name = "Mt" - } - 'EB2' { - fasta = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/README.txt" - } - 'UMD3.1' { - fasta = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/README.txt" - mito_name = "MT" - } - 'WBcel235' { - fasta = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.bed" - mito_name = "MtDNA" - macs_gsize = "9e7" - } - 'CanFam3.1' { - fasta = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/README.txt" - mito_name = "MT" - } - 'GRCz10' { - fasta = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'BDGP6' { - fasta = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.bed" - mito_name = "M" - macs_gsize = "1.2e8" - } - 'EquCab2' { - fasta = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/README.txt" - mito_name = "MT" - } - 'EB1' { - fasta = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/README.txt" - } - 'Galgal4' { - fasta = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'Gm01' { - fasta = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/README.txt" - } - 'Mmul_1' { - fasta = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/README.txt" - mito_name = "MT" - } - 'IRGSP-1.0' { - fasta = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.bed" - mito_name = "Mt" - } - 'CHIMP2.1.4' { - fasta = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/README.txt" - mito_name = "MT" - } - 'Rnor_5.0' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'Rnor_6.0' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.bed" - mito_name = "MT" - } - 'R64-1-1' { - fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.bed" - mito_name = "MT" - macs_gsize = "1.2e7" - } - 'EF2' { - fasta = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/README.txt" - mito_name = "MT" - macs_gsize = "1.21e7" - } - 'Sbi1' { - fasta = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/README.txt" - } - 'Sscrofa10.2' { - fasta = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/README.txt" - mito_name = "MT" - } - 'AGPv3' { - fasta = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.bed" - mito_name = "Mt" - } - 'hg38' { - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/hg38-blacklist.bed" - } - 'hg19' { - fasta = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "2.7e9" - blacklist = "${projectDir}/assets/blacklists/hg19-blacklist.bed" - } - 'mm10' { - fasta = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "1.87e9" - blacklist = "${projectDir}/assets/blacklists/mm10-blacklist.bed" - } - 'bosTau8' { - fasta = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.bed" - mito_name = "chrM" - } - 'ce10' { - fasta = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "9e7" - } - 'canFam3' { - fasta = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/README.txt" - mito_name = "chrM" - } - 'danRer10' { - fasta = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "1.37e9" - } - 'dm6' { - fasta = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.bed" - mito_name = "chrM" - macs_gsize = "1.2e8" - } - 'equCab2' { - fasta = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/README.txt" - mito_name = "chrM" - } - 'galGal4' { - fasta = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/README.txt" - mito_name = "chrM" - } - 'panTro4' { - fasta = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/README.txt" - mito_name = "chrM" - } - 'rn6' { - fasta = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.bed" - mito_name = "chrM" - } - 'sacCer3' { - fasta = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BismarkIndex/" - readme = "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Annotation/README.txt" - mito_name = "chrM" - macs_gsize = "1.2e7" - } - 'susScr3' { - fasta = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa" - bwa = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/version0.6.0/" - bowtie2 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/Bowtie2Index/" - star = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/STARIndex/" - bismark = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BismarkIndex/" - gtf = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.gtf" - bed12 = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.bed" - readme = "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/README.txt" - mito_name = "chrM" - } - } -} + 'GRCh37' : [ + fasta : "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Homo_sapiens/Ensembl/GRCh37/Annotation/README.txt", + mito_name : "MT", + macs_gsize : "2.7e9", + blacklist : "${projectDir}/assets/blacklists/GRCh37-blacklist.bed", + ], + 'GRCh38' : [ + fasta : "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Homo_sapiens/NCBI/GRCh38/Annotation/Genes/genes.bed", + mito_name : "chrM", + macs_gsize : "2.7e9", + blacklist : "${projectDir}/assets/blacklists/hg38-blacklist.bed", + ], + 'CHM13' : [ + fasta : "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAIndex/", + bwamem2 : "${params.igenomes_base}/Homo_sapiens/UCSC/CHM13/Sequence/BWAmem2Index/", + gtf : "${params.igenomes_base}/Homo_sapiens/NCBI/CHM13/Annotation/Genes/genes.gtf", + gff : "ftp://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0/GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz", + mito_name : "chrM", + ], + 'GRCm38' : [ + fasta : "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Mus_musculus/Ensembl/GRCm38/Annotation/README.txt", + mito_name : "MT", + macs_gsize : "1.87e9", + blacklist : "${projectDir}/assets/blacklists/GRCm38-blacklist.bed", + ], + 'TAIR10' : [ + fasta : "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Arabidopsis_thaliana/Ensembl/TAIR10/Annotation/README.txt", + mito_name : "Mt", + ], + 'EB2' : [ + fasta : "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Bacillus_subtilis_168/Ensembl/EB2/Annotation/README.txt", + ], + 'UMD3.1' : [ + fasta : "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Bos_taurus/Ensembl/UMD3.1/Annotation/README.txt", + mito_name : "MT", + ], + 'WBcel235' : [ + fasta : "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Caenorhabditis_elegans/Ensembl/WBcel235/Annotation/Genes/genes.bed", + mito_name : "MtDNA", + macs_gsize : "9e7", + ], + 'CanFam3.1' : [ + fasta : "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Canis_familiaris/Ensembl/CanFam3.1/Annotation/README.txt", + mito_name : "MT", + ], + 'GRCz10' : [ + fasta : "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Danio_rerio/Ensembl/GRCz10/Annotation/Genes/genes.bed", + mito_name : "MT", + ], + 'BDGP6' : [ + fasta : "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Drosophila_melanogaster/Ensembl/BDGP6/Annotation/Genes/genes.bed", + mito_name : "M", + macs_gsize : "1.2e8", + ], + 'EquCab2' : [ + fasta : "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Equus_caballus/Ensembl/EquCab2/Annotation/README.txt", + mito_name : "MT", + ], + 'EB1' : [ + fasta : "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Escherichia_coli_K_12_DH10B/Ensembl/EB1/Annotation/README.txt", + ], + 'Galgal4' : [ + fasta : "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Gallus_gallus/Ensembl/Galgal4/Annotation/Genes/genes.bed", + mito_name : "MT", + ], + 'Gm01' : [ + fasta : "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Glycine_max/Ensembl/Gm01/Annotation/README.txt", + ], + 'Mmul_1' : [ + fasta : "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Macaca_mulatta/Ensembl/Mmul_1/Annotation/README.txt", + mito_name : "MT", + ], + 'IRGSP-1.0' : [ + fasta : "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Oryza_sativa_japonica/Ensembl/IRGSP-1.0/Annotation/Genes/genes.bed", + mito_name : "Mt", + ], + 'CHIMP2.1.4' : [ + fasta : "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Pan_troglodytes/Ensembl/CHIMP2.1.4/Annotation/README.txt", + mito_name : "MT", + ], + 'Rnor_5.0' : [ + fasta : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_5.0/Annotation/Genes/genes.bed", + mito_name : "MT", + ], + 'Rnor_6.0' : [ + fasta : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Rattus_norvegicus/Ensembl/Rnor_6.0/Annotation/Genes/genes.bed", + mito_name : "MT", + ], + 'R64-1-1' : [ + fasta : "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Saccharomyces_cerevisiae/Ensembl/R64-1-1/Annotation/Genes/genes.bed", + mito_name : "MT", + macs_gsize : "1.2e7", + ], + 'EF2' : [ + fasta : "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Schizosaccharomyces_pombe/Ensembl/EF2/Annotation/README.txt", + mito_name : "MT", + macs_gsize : "1.21e7", + ], + 'Sbi1' : [ + fasta : "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Sorghum_bicolor/Ensembl/Sbi1/Annotation/README.txt", + ], + 'Sscrofa10.2' : [ + fasta : "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Sus_scrofa/Ensembl/Sscrofa10.2/Annotation/README.txt", + mito_name : "MT", + ], + 'AGPv3' : [ + fasta : "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Zea_mays/Ensembl/AGPv3/Annotation/Genes/genes.bed", + mito_name : "Mt", + ], + 'hg38' : [ + fasta : "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Homo_sapiens/UCSC/hg38/Annotation/Genes/genes.bed", + mito_name : "chrM", + macs_gsize : "2.7e9", + blacklist : "${projectDir}/assets/blacklists/hg38-blacklist.bed", + ], + 'hg19' : [ + fasta : "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Homo_sapiens/UCSC/hg19/Annotation/README.txt", + mito_name : "chrM", + macs_gsize : "2.7e9", + blacklist : "${projectDir}/assets/blacklists/hg19-blacklist.bed", + ], + 'mm10' : [ + fasta : "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Mus_musculus/UCSC/mm10/Annotation/README.txt", + mito_name : "chrM", + macs_gsize : "1.87e9", + blacklist : "${projectDir}/assets/blacklists/mm10-blacklist.bed", + ], + 'bosTau8' : [ + fasta : "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Bos_taurus/UCSC/bosTau8/Annotation/Genes/genes.bed", + mito_name : "chrM", + ], + 'ce10' : [ + fasta : "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Caenorhabditis_elegans/UCSC/ce10/Annotation/README.txt", + mito_name : "chrM", + macs_gsize : "9e7", + ], + 'canFam3' : [ + fasta : "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Canis_familiaris/UCSC/canFam3/Annotation/README.txt", + mito_name : "chrM", + ], + 'danRer10' : [ + fasta : "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Danio_rerio/UCSC/danRer10/Annotation/Genes/genes.bed", + mito_name : "chrM", + macs_gsize : "1.37e9", + ], + 'dm6' : [ + fasta : "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Drosophila_melanogaster/UCSC/dm6/Annotation/Genes/genes.bed", + mito_name : "chrM", + macs_gsize : "1.2e8", + ], + 'equCab2' : [ + fasta : "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Equus_caballus/UCSC/equCab2/Annotation/README.txt", + mito_name : "chrM", + ], + 'galGal4' : [ + fasta : "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Gallus_gallus/UCSC/galGal4/Annotation/README.txt", + mito_name : "chrM", + ], + 'panTro4' : [ + fasta : "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Pan_troglodytes/UCSC/panTro4/Annotation/README.txt", + mito_name : "chrM", + ], + 'rn6' : [ + fasta : "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Rattus_norvegicus/UCSC/rn6/Annotation/Genes/genes.bed", + mito_name : "chrM", + ], + 'sacCer3' : [ + fasta : "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Sequence/BismarkIndex/", + readme : "${params.igenomes_base}/Saccharomyces_cerevisiae/UCSC/sacCer3/Annotation/README.txt", + mito_name : "chrM", + macs_gsize : "1.2e7", + ], + 'susScr3' : [ + fasta : "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/WholeGenomeFasta/genome.fa", + bwa : "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BWAIndex/version0.6.0/", + bowtie2 : "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/Bowtie2Index/", + star : "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/STARIndex/", + bismark : "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Sequence/BismarkIndex/", + gtf : "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.gtf", + bed12 : "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/Genes/genes.bed", + readme : "${params.igenomes_base}/Sus_scrofa/UCSC/susScr3/Annotation/README.txt", + mito_name : "chrM", + ], +] diff --git a/conf/modules.config b/conf/modules.config index d203d2b..055e5dc 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -18,17 +18,72 @@ process { saveAs: { filename -> filename.equals('versions.yml') ? null : filename } ] - withName: FASTQC { - ext.args = '--quiet' + withName: UNTAR { + ext.prefix = { "${archive.simpleName}" } + publishDir = [ + path: { "${params.outdir}/untar/databases" }, + mode: params.publish_dir_mode, + enabled: params.save_untarred_databases, + ] + } + // humann4 requires a metaphlan profile with the extra columns provided by -t rel_ab_w_read_stats + withName: MPAHUMANN4 { + container = 'ghcr.io/vdblab/biobakery-profiler:4.0.6--4.0.0.alpha.1-final_smaller-pt2' + ext.args = '-t rel_ab_w_read_stats' + } + withName: HUMANN3_HUMANN { + publishDir = [ + path: { "${params.outdir}/humann3/" }, + mode: params.publish_dir_mode, + pattern: '*.{tsv.gz,log,.command.*}' + ] + } + withName: HUMANN4 { + publishDir = [ + path: { "${params.outdir}/humann4/" }, + mode: params.publish_dir_mode, + pattern: '*.{tsv.gz,log,.command.*}' + ] + } + withName: FMHFUNPROFILER { + ext.prefix = { "${meta.id}_${ko_sketch.baseName}.fmhfunprofiler" } + publishDir = [ + path: { "${params.outdir}/fmhfunprofiler/${ko_sketch}/" }, + mode: params.publish_dir_mode, + pattern: '*.{csv}' + ] + } + withName: RGI_BWT { + publishDir = [ + path: { "${params.outdir}/rgi/${meta.db_name}/" }, + mode: params.publish_dir_mode, + pattern: '*.{txt,json}' + ] + } + withName: DIAMOND_BLASTX { + // DBPREP stores '-' when a database row carries no db_params + ext.args = { meta.db_params && meta.db_params != '-' ? "${meta.db_params}" : '' } + ext.prefix = { "${meta.id}_${meta.db_name}.diamond" } + publishDir = [ + path: { "${params.outdir}/diamond/${meta.db_name}/" }, + mode: params.publish_dir_mode, + pattern: '*.{blast,xml,txt,daa,sam,tsv,paf,log}' + ] + } + withName: EGGNOGMAPPER { + ext.args = "--itype metagenome --genepred search --sensmode fast --pident 90 --query_cover 80" + // .emapper.hits is not published: several GB/sample, and reannotation uses the seed orthologs + publishDir = [ + path: { "${params.outdir}/eggnogmapper/" }, + mode: params.publish_dir_mode, + pattern: '*.{emapper.annotations,emapper.seed_orthologs}' + ] } - withName: 'MULTIQC' { ext.args = { params.multiqc_title ? "--title \"$params.multiqc_title\"" : '' } publishDir = [ path: { "${params.outdir}/multiqc" }, - mode: params.publish_dir_mode, - saveAs: { filename -> filename.equals('versions.yml') ? null : filename } + mode: params.publish_dir_mode ] } - } diff --git a/conf/test.config b/conf/test.config index 9f7ea72..ab28367 100644 --- a/conf/test.config +++ b/conf/test.config @@ -16,15 +16,42 @@ process { memory: '15.GB', time: '1.h' ] + + // MultiQC has no per-sample modules to report on here: the pipeline runs no read QC, so + // the report only carries the run summary and the software versions. + withName: 'MULTIQC' { + ext.when = false + } + + // The regroup steps add several minutes per sample for output the test does not check. + withName: 'HUMANN3_REGROUP' { + ext.when = false + } + withName: 'HUMANN4_REGROUP' { + ext.when = false + } + + // No read of the demo data proceeds to translated search against the demo UniRef database + withName: 'HUMANN3_HUMANN' { + ext.args = '--bypass-nucleotide-search' + } } +// rgi (505 MB) and metaphlan (976 MB) come from depot.galaxyproject.org, which is slow enough +// under CI concurrency that the 20 min default kills the pull mid-download. +apptainer.pullTimeout = '60m' +singularity.pullTimeout = '60m' + params { - config_profile_name = 'Test profile' - config_profile_description = 'Minimal test dataset to check pipeline function' - - // Input data - // TODO nf-core: Specify the paths to your test data on nf-core/test-datasets - // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_test_illumina_amplicon.csv'// Genome references - genome = 'R64-1-1' + config_profile_name = 'Test profile' + config_profile_description = 'Minimal test dataset to check pipeline function' + input = params.pipelines_testdata_base_path + 'funcprofiler/samplesheets/test.csv' + databases = params.pipelines_testdata_base_path + 'funcprofiler/database.csv' + run_fmhfunprofiler = true + run_humann_v3 = true + run_mifaser = true + run_diamond = false + run_humann_v4 = false + run_rgi = true + run_eggnogmapper = false } diff --git a/conf/test_full.config b/conf/test_full.config index 0568518..cb32d32 100644 --- a/conf/test_full.config +++ b/conf/test_full.config @@ -10,15 +10,23 @@ ---------------------------------------------------------------------------------------- */ -params { - config_profile_name = 'Full test profile' - config_profile_description = 'Full test dataset to check pipeline function' - - // Input data for full size test - // TODO nf-core: Specify the paths to your full test data ( on nf-core/test-datasets or directly in repositories, e.g. SRA) - // TODO nf-core: Give any required params for the test so that command line flags are not needed - input = params.pipelines_testdata_base_path + 'viralrecon/samplesheet/samplesheet_full_illumina_amplicon.csv' +// rgi and metaphlan come from depot.galaxyproject.org, which is slow enough that the 20 min +// default kills the pull mid-download. +apptainer.pullTimeout = '60m' +singularity.pullTimeout = '60m' - // Genome references - genome = 'R64-1-1' +params { + config_profile_name = 'Full test profile' + config_profile_description = 'Full test dataset to check pipeline function' + input = params.pipelines_testdata_base_path + 'funcprofiler/samplesheets/test_full.csv' + databases = params.pipelines_testdata_base_path + 'funcprofiler/database_full.csv' + run_fmhfunprofiler = true + run_humann_v3 = false // disabled until a good hosting solution can be found for indexed mpa database + run_rgi = true + run_mifaser = true + // DIAMOND and eggNOG-mapper are off because they are still beta and have no full-size + // database in `database_full.csv`; turn them on once one is staged on S3. + run_diamond = false + run_eggnogmapper = false + run_humann_v4 = false } diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..95b80c6 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,190 @@ +--- +title: Contributing +markdownPlugin: checklist +--- + +# `nf-core/funcprofiler`: Contributing guidelines + +Hi there! +Thanks for taking an interest in improving nf-core/funcprofiler. + +This page describes the recommended nf-core way to contribute to both nf-core/funcprofiler and nf-core pipelines in general, including: + +- [General contribution guidelines](#general-contribution-guidelines): common procedures or guides across all nf-core pipelines. +- [Pipeline-specific contribution guidelines](#pipeline-specific-contribution-guidelines): procedures or guides specific to the development conventions of nf-core/funcprofiler. + +> [!NOTE] +> If you need help using or modifying nf-core/funcprofiler, ask on the nf-core Slack [#funcprofiler](https://nfcore.slack.com/channels/funcprofiler) channel ([join our Slack here](https://nf-co.re/join/slack)). + +## General contribution guidelines + +### Contribution quick start + +To contribute code to any nf-core pipeline: + +- [ ] Ensure you have Nextflow, nf-core tools, and nf-test installed. See the [nf-core/tools repository](https://github.com/nf-core/tools) for instructions. +- [ ] Check whether a GitHub [issue](https://github.com/nf-core/funcprofiler/issues) about your idea already exists. If an issue does not exist, create one so that others are aware you are working on it. +- [ ] [Fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the [nf-core/funcprofiler repository](https://github.com/nf-core/funcprofiler) to your GitHub account. +- [ ] Create a branch on your forked repository and make your changes following [pipeline conventions](#pipeline-contribution-conventions) (if applicable). +- [ ] To fix major bugs, name your branch `patch` and follow the [patch release](#patch-release) process. +- [ ] Update relevant documentation within the `docs/` folder, use nf-core/tools to update `nextflow_schema.json`, and update `CITATIONS.md`. +- [ ] Run and/or update tests. See [Testing](#testing) for more information. +- [ ] [Lint](#lint-tests) your code with nf-core/tools. +- [ ] Submit a pull request (PR) against the `dev` branch and request a review. + +If you are not used to this workflow with Git, see the [GitHub documentation](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests) or [Git resources](https://try.github.io/) for more information. + +## Use of AI and LLMs + +The nf-core stance on the use of AI and LLMs is that humans are still ultimately responsible for their submitted code, regardless of the tools they use. + +If you’re using AI tools, try to stick by these guidelines: + +- Keep PRs as small and focused as possible +- Avoid any unnecessary changes, such as moving or refactoring code (unless that is the explicit intention of the PR) +- Review all generated code yourself before opening a PR, and ensure that you understand it +- Engage with the community review process and expect to make revisions + +For more detail, see the [blog post](https://nf-co.re/blog/2026/statement-on-ai) for a statement from the nf-core/core team. + +### Getting help + +For further information and help, see the [nf-core/funcprofiler documentation](https://nf-co.re/funcprofiler/usage) or ask on the nf-core [#funcprofiler](https://nfcore.slack.com/channels/funcprofiler) Slack channel ([join our Slack here](https://nf-co.re/join/slack)). + +### GitHub Codespaces + +You can contribute to nf-core/funcprofiler without installing a local development environment on your machine by using [GitHub Codespaces](https://github.com/codespaces). + +[GitHub Codespaces](https://github.com/codespaces) is an online developer environment that runs in your browser, complete with VS Code and a terminal. +Most nf-core repositories include a devcontainer configuration, which creates a GitHub Codespaces environment specifically for Nextflow development. +The environment includes pre-installed nf-core tools, Nextflow, and a few other helpful utilities via a Docker container. + +To get started, open the repository in [Codespaces](https://github.com/nf-core/funcprofiler/codespaces). + +### Testing + +Once you have made your changes, run the pipeline with nf-test to test them locally. +For additional information, use the `--verbose` flag to view the Nextflow console log output. + +```bash +nf-test test --tag test --profile +docker --verbose +``` + +If you have added new functionality, ensure you update the test assertions in the `.nf.test` files in the `tests/` directory. +Update the snapshots with the following command: + +```bash +nf-test test --tag test --profile +docker --verbose --update-snapshots +``` + +When you create a pull request with changes, GitHub Actions will run automatic tests. +Pull requests are typically reviewed when these tests are passing. + +Two types of tests are typically run: + +#### Lint tests + +nf-core has a [set of guidelines](https://nf-co.re/docs/specifications/overview) which all pipelines must follow. +To enforce these, run linting with nf-core/tools: + +```bash +nf-core pipelines lint +``` + +If you encounter failures or warnings, follow the linked documentation printed to screen. +For more information about linting tests, see [nf-core/tools API documentation](https://nf-co.re/docs/nf-core-tools/api_reference/latest/pipeline_lint_tests/actions_awsfulltest). + +#### Pipeline tests + +Each nf-core pipeline should be set up with a minimal set of test data. +GitHub Actions runs the pipeline on this data to ensure it runs through and exits successfully. +If there are any failures then the automated tests fail. +These tests are run with the latest available version of Nextflow and the minimum required version specified in the pipeline code. + +### Patch release + +> [!WARNING] +> Only in the unlikely event of a release that contains a critical bug. + +- [ ] Create a new branch `patch` on your fork based on `upstream/main` or `upstream/master`. +- [ ] Fix the bug and use nf-core/tools to bump the version to the next semantic version, for example, `1.2.3` → `1.2.4`. +- [ ] Open a Pull Request from `patch` directly to `main`/`master` with the changes. + +### Pipeline contribution conventions + +nf-core semi-standardises how you write code and other contributions to make the nf-core/funcprofiler code and processing logic more understandable for new contributors and to ensure quality. + +#### Add a new pipeline step + +To contribute a new step to the pipeline, follow the general nf-core coding procedure. +Please also refer to the [pipeline-specific contribution guidelines](#pipeline-specific-contribution-guidelines): + +- [ ] Define the corresponding [input channel](#channel-naming-schemes) into your new process from the expected previous process channel. +- [ ] Install a module with nf-core/tools, or write a local module (see [default processes resource requirements](#default-processes-resource-requirements)), and add it to the target `.nf`. +- [ ] Define the output channel if needed. Mix the version output channel into `ch_versions` and relevant files into `ch_multiqc`. +- [ ] Add new or updated parameters to `nextflow.config` with a [default value](#default-parameter-values). +- [ ] Add new or updated parameters and relevant help text to `nextflow_schema.json` with [nf-core/tools](#default-parameter-values). +- [ ] Add validation for relevant parameters to the pipeline utilisation section of `utils_nfcore_\_pipeline/main.nf` subworkflow. +- [ ] Perform local tests to validate that the new code works as expected. + - [ ] If applicable, add a new test in the `tests` directory. +- [ ] Update `usage.md`, `output.md`, and `citation.md` as appropriate. +- [ ] [Lint](#lint-tests) the code with nf-core/tools. +- [ ] Update any diagrams or pipeline images as necessary. +- [ ] Update MultiQC config `assets/multiqc_config.yml` so relevant suffixes, file name cleanup, and module plots are in the appropriate order. +- [ ] If applicable, create a [MultiQC](https://seqera.io/multiqc/) module. +- [ ] Add a description of the output files and, if relevant, images from the MultiQC report to `docs/output.md`. + +To update the minimum required Nextflow version, see the [Nextflow version bumping](#nextflow-version-bumping) section below. For more information about pipeline contributions, see [pipeline-specific contribution guidelines](#pipeline-specific-contribution-guidelines). + +#### Channel naming schemes + +Use the following naming schemes for channels to make the channel flow easier to understand: + +- Initial process channel: `ch_output_from_` +- Intermediate and terminal channels: `ch__for_` + +#### Default parameter values + +Parameters should be initialised and defined with default values within the `params` scope in `nextflow.config`. +They should also be documented in the pipeline JSON schema. + +To update `nextflow_schema.json`, run: + +```bash +nf-core pipelines schema build +``` + +The schema builder interface that loads in your browser should automatically update the defaults in the parameter documentation. + +#### Default processes resource requirements + +If you write a local module, specify a default set of resource requirements for the process. + +Sensible defaults for process resource requirements (CPUs, memory, time) should be defined in `conf/base.config`. +Specify these with generic `withLabel:` selectors, so they can be shared across multiple processes and steps of the pipeline. + +nf-core provides a set of standard labels that you should follow where possible, as seen in the [nf-core pipeline template](https://github.com/nf-core/tools/blob/main/nf_core/pipeline-template/conf/base.config). +These labels define resource defaults for single-core processes, modules that require a GPU, and different levels of multi-core configurations with increasing memory requirements. + +Values assigned within these labels can be dynamically passed to a tool using the `${task.cpus}` and `${task.memory}` Nextflow variables in the `script:` block of a module (see an example in the [modules repository](https://github.com/nf-core/modules/blob/bd1b6a40f55933d94b8c9ca94ec8c1ea0eaf4b82/modules/nf-core/samtools/bam2fq/main.nf#L30)). + +#### Nextflow version bumping + +If you use a new feature from core Nextflow, bump the minimum required Nextflow version in the pipeline with: + +```bash +nf-core pipelines bump-version --nextflow . +``` + +#### Images and figures guidelines + +If you update images or graphics, follow the nf-core [style guidelines](https://nf-co.re/docs/community/brand/workflow-schematics). + +## Pipeline specific contribution guidelines + +When adding a new profiler: + +- Add it to [nf-core/modules](https://github.com/nf-core/modules) rather than to `modules/local`. A local module is only a stopgap for tools that are not yet packaged on Bioconda. +- Gate it behind a `run_` parameter, and take its database from the database sheet so it is grouped by `dbprep` like every other tool. +- Add it to the `profile` subworkflow, to `docs/output.md`, and to `CITATIONS.md`. +- Cover it with an nf-test, and regenerate snapshots with `nf-test test --update-snapshot`. diff --git a/docs/images/nf-core-funcprofiler_logo_dark.png b/docs/images/nf-core-funcprofiler_logo_dark.png index 7e733e3..105ef36 100644 Binary files a/docs/images/nf-core-funcprofiler_logo_dark.png and b/docs/images/nf-core-funcprofiler_logo_dark.png differ diff --git a/docs/images/nf-core-funcprofiler_logo_light.png b/docs/images/nf-core-funcprofiler_logo_light.png index a67fe7a..2ce2a8d 100644 Binary files a/docs/images/nf-core-funcprofiler_logo_light.png and b/docs/images/nf-core-funcprofiler_logo_light.png differ diff --git a/docs/output.md b/docs/output.md index 5f1fbf1..4ff95ff 100644 --- a/docs/output.md +++ b/docs/output.md @@ -2,35 +2,130 @@ ## Introduction -This document describes the output produced by the pipeline. Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. +This document describes the output produced by the pipeline. +Most of the plots are taken from the MultiQC report, which summarises results at the end of the pipeline. -The directories listed below will be created in the results directory after the pipeline has finished. All paths are relative to the top-level results directory. - - +The directories listed below will be created in the results directory after the pipeline has finished. +All paths are relative to the top-level results directory. ## Pipeline overview The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes data using the following steps: -- [FastQC](#fastqc) - Raw read QC +- [HUMAnN v3 / v4](#humann-v3--v4) - Functional profiling via MetaPhlAn + HUMAnN +- [FMH FunProfiler](#fmh-funprofiler) - Sketch-based functional profiling +- [mi-faser](#mi-faser) - Read-level functional profiling +- [RGI BWT](#rgi-bwt) - Antimicrobial resistance gene identification +- [DIAMOND blastx](#diamond-blastx) - Translated alignment against a protein database (work in progress / beta) +- [eggNOG-mapper](#eggnog-mapper) - Functional annotation via orthology assignment (work in progress / beta) - [MultiQC](#multiqc) - Aggregate report describing results and QC from the whole pipeline - [Pipeline information](#pipeline-information) - Report metrics generated during the workflow execution -### FastQC +> [!NOTE] +> Other than MultiQC and pipeline information, all other steps (the profilers) are off by default, and must be switched on manually. The pipeline performs no read QC or preprocessing; see the [usage documentation](https://nf-co.re/funcprofiler/usage) for why. + +### HUMAnN v3 / v4 + +[HUMAnN](https://huttenhower.sph.harvard.edu/humann/) (HMP Unified Metabolic Analysis Network) is a method for efficiently and accurately profiling the presence/absence and abundance of microbial pathways in a community from metagenomic or metatranscriptomic sequencing data. +Enabled with `--run_humann_v3` or `--run_humann_v4`. HUMAnN 4 is in alpha status; it will become the default when fully released. +Each sample is first run through MetaPhlAn to generate a taxonomic profile, which guides HUMAnN functional profiling.
Output files -- `fastqc/` - - `*_fastqc.html`: FastQC report containing quality metrics. - - `*_fastqc.zip`: Zip archive containing the FastQC report, tab-delimited data file and plot images. +- `humann_v3//` or `humann_v4//` + - `*_genefamilies.tsv`: Gene family abundances in reads per kilobase (RPK), stratified by contributing species. + - `*_pathabundance.tsv`: Metabolic pathway abundances in RPK, stratified by species contribution. + - `*_pathcoverage.tsv`: Pathway coverage scores (0–1), indicating the fraction of reactions detected per pathway. +- `metaphlan//` + - `*_profile.txt`: Species-level taxonomic abundance profile used as input to HUMAnN.
-[FastQC](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/) gives general quality metrics about your sequenced reads. It provides information about the quality score distribution across your reads, per base sequence content (%A/T/G/C), adapter contamination and overrepresented sequences. For further reading and documentation see the [FastQC help pages](http://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/). +### FMH FunProfiler + +[FMH FunProfiler](https://github.com/KoslickiLab/fmh-funprofiler) uses FracMinHash sketching to rapidly assign reads to KEGG Orthology (KO) functional categories. +Enabled with `--run_fmhfunprofiler`. + +
+Output files + +- `fmhfunprofiler//` + - `*.fmhfunprofiler.ko`: KO (KEGG Orthology) abundance table for the sample. + +
+ +### mi-faser + +[mi-faser](https://bromberglab.org/project/mifaser/) maps reads to functional databases at the protein level to produce enzyme function profiles. +Enabled with `--run_mifaser`. + +
+Output files + +- `mifaser///` + - `analysis.tsv`: Tab-separated table of functional assignments with read counts per enzyme function (EC number). + - `analysis.log`: Log file with run statistics including number of reads processed and assigned. + +
+ +### RGI BWT + +[RGI](https://github.com/arpcard/rgi) (Resistance Gene Identifier) aligns reads against the CARD database using Bowtie2/BWA to identify antimicrobial resistance genes. +Enabled with `--run_rgi`. + +
+Output files + +- `rgi//` + - `*.txt`: Tab-separated AMR gene hit table with gene family, resistance mechanism, drug class, and read counts. + - `*.json`: Full RGI output in JSON format with detailed per-hit annotations. + +
+ +### DIAMOND blastx + +Enabled with `--run_diamond`. +Performs fast translated alignment of (meta)genomic reads against a protein reference database. +Each read is aligned in all six reading frames and only significant hits are reported. + +> [!WARNING] +> DIAMOND support is currently in beta and should be treated as work in progress. The module is still being validated in the full pipeline, including database handling, output behavior, and downstream reporting. Use with caution and independently review results before production use or interpretation. + +
+Output files + +- `diamond//` + - `*.tsv`: Tabular alignment results (BLAST tabular format 6) with one row per query-subject hit. + - `*.log`: DIAMOND run log containing alignment statistics (query count, alignment rate, etc.). + +
+ +### eggNOG-mapper + +Enabled with `--run_eggnogmapper`. +Assigns functional annotations to sequences by mapping them to orthologous groups in the eggNOG database. + +> [!WARNING] +> eggNOG-mapper support is currently in beta and should be treated as work in progress. The module is still being validated in the full pipeline, including database handling, output behavior, and downstream reporting. Use with caution and independently review results before production use or interpretation. + +
+Output files + +- `eggnogmapper//` + - `*.emapper.annotations`: TSV file with functional annotations per query sequence, including GO terms, KEGG pathways, COG categories, and more. + - `*.emapper.seed_orthologs`: TSV linking query sequences to their best seed orthologs _(optional, produced when search is performed)_. Pass this back to `emapper.py -m no_search --annotate_hits_table` to reannotate against a newer eggNOG release without repeating the search. + +
+ +The search phase also writes `*.emapper.hits`, the full hit table for every query. +It is a big file and not used very often, so it doesn't get published by default. ### MultiQC +[MultiQC](http://multiqc.info) is a visualization tool that generates a single HTML report summarising all samples in your project. +Most of the pipeline QC results are visualised in the report and further statistics are available in the report data directory. +
Output files @@ -41,12 +136,15 @@ The pipeline is built using [Nextflow](https://www.nextflow.io/) and processes d
-[MultiQC](http://multiqc.info) is a visualization tool that generates a single HTML report summarising all samples in your project. Most of the pipeline QC results are visualised in the report and further statistics are available in the report data directory. - -Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQC. The pipeline has special steps which also allow the software versions to be reported in the MultiQC output for future traceability. For more information about how to use MultiQC reports, see . +Because the pipeline runs no read QC, the report currently carries the run summary and the software versions rather than per-sample QC modules. +The pipeline has special steps which also allow the software versions to be reported in the MultiQC output for future traceability. +For more information about how to use MultiQC reports, see . ### Pipeline information +[Nextflow](https://www.nextflow.io/docs/latest/tracing.html) provides excellent functionality for generating various reports relevant to the running and execution of the pipeline. +This will allow you to troubleshoot errors with the running of the pipeline, and also provide you with other information such as launch commands, run times and resource usage. +
Output files @@ -57,5 +155,3 @@ Results generated by MultiQC collate pipeline QC from supported tools e.g. FastQ - Parameters used by the pipeline run: `params.json`.
- -[Nextflow](https://www.nextflow.io/docs/latest/tracing.html) provides excellent functionality for generating various reports relevant to the running and execution of the pipeline. This will allow you to troubleshoot errors with the running of the pipeline, and also provide you with other information such as launch commands, run times and resource usage. diff --git a/docs/usage.md b/docs/usage.md index 9c0d947..50a644c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -6,58 +6,290 @@ ## Introduction - +**nf-core/funcprofiler** performs read-based functional profiling of microbiome sequencing data. +It requires two input CSV files: a samplesheet describing your samples and a databases sheet describing the profiling databases to use. + +## Read preprocessing + +The pipeline does not perform read QC or preprocessing! +Reads are expected to arrive already trimmed, quality filtered and host decontaminated. + +We recommend users run nf-core/funcprofiler after running [nf-core/taxprofiler](https://nf-co.re/taxprofiler), which already covers short-read preprocessing, and provides complimentary information. +Adopting the nf-core [`fastq_shortreads_preprocess_qc`](https://nf-co.re/subworkflows/fastq_shortreads_preprocess_qc/) subworkflow is planned for a later release. ## Samplesheet input -You will need to create a samplesheet with information about the samples you would like to analyse before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 3 columns, and a header row as shown in the examples below. +You will need to create a samplesheet with information about the samples you would like to analyse before running the pipeline. +Use this parameter to specify its location. +It has to be a comma-separated file with a header row and the columns shown below. ```bash --input '[path to samplesheet file]' ``` -### Multiple runs of the same sample +| Column | Required | Description | +| --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `sample` | Yes | Sample name. Rows with the same `sample` name (and different `run_accession`) are merged before profiling. | +| `run_accession` | Yes | Unique run identifier (e.g. `RUN1`, `SRR12345`). Used to distinguish multiple sequencing runs of the same sample. | +| `instrument_platform` | Yes | Sequencing platform. Must be one of: `ABI_SOLID`, `BGISEQ`, `CAPILLARY`, `COMPLETE_GENOMICS`, `DNBSEQ`, `HELICOS`, `ILLUMINA`, `ION_TORRENT`, `LS454`. | +| `fastq_1` | Yes | Full path to gzipped already preprocessed FASTQ file for read 1. Must end in `.fastq.gz` or `.fq.gz`. | +| `fastq_2` | No | Full path to gzipped already preprocessed FASTQ file for read 2 (paired-end only). Leave empty for single-end reads. | +| `fasta` | No | Unused. The column is retained for compatibility with nf-core/taxprofiler samplesheets and must be left empty. | -The `sample` identifiers have to be the same when you have re-sequenced the same sample more than once e.g. to increase sequencing depth. The pipeline will concatenate the raw reads before performing any downstream analysis. Below is an example for the same sample sequenced across 3 lanes: +> [!NOTE] +> `fastq_1` must be provided for each row! We do **not** support `OXFORD_NANOPORE` or `PACBIO_SMRT` platforms, as long reads are incompatible (or at least, require nuanced interpretation) with most of these tools. Similarly, we do not support `fasta` input, as assembly-based pipelines like nf-core/funcscan would be more appropriate. + +### Example samplesheet -```csv title="samplesheet.csv" -sample,fastq_1,fastq_2 -CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz -CONTROL_REP1,AEG588A1_S1_L003_R1_001.fastq.gz,AEG588A1_S1_L003_R2_001.fastq.gz -CONTROL_REP1,AEG588A1_S1_L004_R1_001.fastq.gz,AEG588A1_S1_L004_R2_001.fastq.gz +```csv +sample,run_accession,instrument_platform,fastq_1,fastq_2,fasta +SAMPLE1,RUN1,ILLUMINA,/data/sample1_R1.fastq.gz,/data/sample1_R2.fastq.gz, +SAMPLE1,RUN2,ILLUMINA,/data/sample1_lane2_R1.fastq.gz,/data/sample1_lane2_R2.fastq.gz, +SAMPLE2,RUN1,ILLUMINA,/data/sample2_R1.fastq.gz,, ``` -### Full samplesheet +In this example, `SAMPLE1` has two runs which will be merged before profiling. `SAMPLE2` is single-end short reads. + +## Enabling profilers -The pipeline will auto-detect whether a sample is single- or paired-end using the information provided in the samplesheet. The samplesheet can have as many columns as you desire, however, there is a strict requirement for the first 3 columns to match those defined in the table below. +The pipeline will only run the profilers you explicitly turn on, and for which a database has been specified in your database samplesheet: + +| Flag | Profiler | Status | +| ---------------------- | --------------- | ----------------------- | +| `--run_humann_v3` | HUMAnN v3 | Available | +| `--run_humann_v4` | HUMAnN v4 | Available | +| `--run_fmhfunprofiler` | FMH FunProfiler | Available | +| `--run_mifaser` | mi-faser | Available | +| `--run_rgi` | RGI BWT | Available | +| `--run_diamond` | DIAMOND blastx | Work in progress / beta | +| `--run_eggnogmapper` | eggNOG-mapper | Work in progress / beta | + +> [!NOTE] +> Each `--run_` flag requires a matching database entry in the `--databases` CSV. Database rows for tools that are not enabled will be ignored. + +> [!WARNING] +> Beta means the profiler runs and produces output, but database handling and output behaviour have not been validated end to end, and neither is covered by the full-size test. +> Interpret the results with caution and check them independently before using them in an analysis. -A final samplesheet file consisting of both single- and paired-end data may look something like the one below. This is for 6 samples, where `TREATMENT_REP3` has been sequenced twice. +## Databases input -```csv title="samplesheet.csv" -sample,fastq_1,fastq_2 -CONTROL_REP1,AEG588A1_S1_L002_R1_001.fastq.gz,AEG588A1_S1_L002_R2_001.fastq.gz -CONTROL_REP2,AEG588A2_S2_L002_R1_001.fastq.gz,AEG588A2_S2_L002_R2_001.fastq.gz -CONTROL_REP3,AEG588A3_S3_L002_R1_001.fastq.gz,AEG588A3_S3_L002_R2_001.fastq.gz -TREATMENT_REP1,AEG588A4_S4_L003_R1_001.fastq.gz, -TREATMENT_REP2,AEG588A5_S5_L003_R1_001.fastq.gz, -TREATMENT_REP3,AEG588A6_S6_L003_R1_001.fastq.gz, -TREATMENT_REP3,AEG588A6_S6_L004_R1_001.fastq.gz, +```bash +--databases '[path to databases file]' ``` -| Column | Description | -| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sample` | Custom sample name. This entry will be identical for multiple sequencing libraries/runs from the same sample. Spaces in sample names are automatically converted to underscores (`_`). | -| `fastq_1` | Full path to FastQ file for Illumina short reads 1. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | -| `fastq_2` | Full path to FastQ file for Illumina short reads 2. File has to be gzipped and have the extension ".fastq.gz" or ".fq.gz". | +The databases sheet is a comma-separated file that specifies which databases to use for each profiler. +Only tools enabled via `--run_` flags will use the corresponding database entries. + +Use the `db_name` column to record the database release or version used for the run, for example `uniref90_v3`, `eggnog_v5`, `card_v3`, or `GS-24-all`. + +| Column | Required | Description | +| ----------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tool` | Yes | Profiler name. Must be one of: `humann_v3`, `humann_v4`, `fmhfunprofiler`, `mifaser`, `diamond`, `rgi`, `eggnogmapper`. | +| `db_name` | Yes | Name of the database as a whole, i.e. the release or version you want recorded in the results. All rows belonging to the same database must share this name. | +| `db_entity` | No | Name of an individual component of that database, for the tools that need more than one. Leave empty for tools that take a single database file or directory. | +| `db_params` | No | Additional parameters to pass to the profiler (no quotes allowed). | +| `db_path` | Yes | Absolute path to the database file or directory. Gzipped TAR archives (`.tar.gz`) are automatically decompressed. | + +> [!IMPORTANT] +> `db_name` and `db_entity` describe two different levels. `db_name` names the database, `db_entity` names one of its parts. +> HUMAnN and eggNOG-mapper need several parts, so they take **one row per part**, all sharing the same `db_name` and each naming a different `db_entity`: `humann_metaphlan`, `humann_nucleotide`, `humann_protein` and `humann_utility` for HUMAnN, and `eggnogmapper_db` and `eggnogmapper_data_dir` for eggNOG-mapper. +> FMH FunProfiler, mi-faser, DIAMOND and RGI take a single database, so they take one row with `db_entity` left empty. + +The pipeline checks the database sheet against the enabled profilers before it submits any job, so a missing component fails immediately rather than partway through a run. + +### Database versions and compatibility + +The pipeline passes `db_path` straight to the profiler and never checks it against the tool version, so pairing a database with a compatible tool release is up to you. +The versions a run actually used are recorded in `/pipeline_info/nf_core_funcprofiler_software_mqc_versions.yml`. + +These combinations were exercised on a human gut metagenome cohort during development; RGI, DIAMOND and HUMAnN v4 were only tested against the small CI databases. + +| Tool | Tool version | Database | +| --------------- | ------------ | ----------------------------------------------------------------------------------------------------------------- | +| HUMAnN v3 | 3.6.1 | ChocoPhlAn full `v201901_v31`, UniRef90 `201901b` full, `utility_mapping` full | +| MetaPhlAn | 4.0.6 | `mpa_vJan21_CHOCOPhlAnSGB_202103` | +| FMH FunProfiler | 1.1.1 | KO sketches from [Zenodo record 10045253](https://zenodo.org/records/10045253), scaled 1000 / k=11 and scaled 500 | +| mi-faser | 1.64 | `GS-24-all`, downloaded from the mi-faser website | +| eggNOG-mapper | 2.1.13 | eggNOG 5.0.2 data directory | + +### HUMAnN -An [example samplesheet](../assets/samplesheet.csv) has been provided with the pipeline. +[HUMAnN](https://huttenhower.sph.harvard.edu/humann/) profiles the abundance of microbial metabolic pathways and gene families, guided by a MetaPhlAn taxonomic profile. +Enable it with `--run_humann_v3` or `--run_humann_v4`. + +#### Database preparation + +HUMAnN requires four database components per named database, each as a separate row with the same `db_name`. +The ChocoPhlAn nucleotide database, the UniRef protein database and the utility mapping files are downloaded with `humann_databases`, which ships with HUMAnN; the MetaPhlAn marker database is downloaded with `metaphlan --install`. + +```bash +humann_databases --download chocophlan full /data/databases +humann_databases --download uniref uniref90_diamond /data/databases +humann_databases --download utility_mapping full /data/databases +metaphlan --install --bowtie2db /data/databases/metaphlan_db +``` + +See the [HUMAnN documentation](https://github.com/biobakery/humann#5-download-the-databases) for the full list of available releases. +The example below uses a HUMAnN v3-compatible UniRef90 database set; replace `uniref90_v3` with the exact release or version used in your analysis. + +```csv +tool,db_name,db_entity,db_params,db_path +humann_v3,uniref90_v3,humann_metaphlan,,/data/databases/metaphlan_db +humann_v3,uniref90_v3,humann_nucleotide,,/data/databases/chocophlan +humann_v3,uniref90_v3,humann_protein,,/data/databases/uniref90_diamond +humann_v3,uniref90_v3,humann_utility,,/data/databases/utility_mapping +``` + +### FMH FunProfiler + +[FMH FunProfiler](https://github.com/KoslickiLab/fmh-funprofiler) uses FracMinHash sketching to assign reads to KEGG Orthology (KO) categories. +Enable it with `--run_fmhfunprofiler`. + +#### Database preparation + +Download a pre-sketched KO database from [Zenodo record 10045253](https://zenodo.org/records/10045253), or build your own sketches with `sourmash sketch` as described in the [FMH FunProfiler README](https://github.com/KoslickiLab/fmh-funprofiler#usage). +`db_path` points at the `.sig.zip` sketch file. + +FMH FunProfiler is the one tool that needs its `db_params` filled in: it takes the k-mer size and the sketch scale of the database, in that order, separated by a space. +A sketch built at k=11 and scale 1000 therefore needs `11 1000`. + +```csv +tool,db_name,db_entity,db_params,db_path +fmhfunprofiler,kegg_v1,,11 1000,/data/databases/fmhfunprofiler_kegg.sig.zip +``` + +### mi-faser + +[mi-faser](https://bromberglab.org/project/mifaser/) performs functional profiling by mapping reads to functional databases at the protein level. +Enable it with `--run_mifaser`. + +#### Database preparation + +Download a pre-built mi-faser database (e.g. GS-21, GS-24-all, or GS-580) from the [mi-faser website](https://bromberglab.org/project/mifaser/). +`db_path` should point to the directory containing the database files, and `db_name` should record the downloaded database version. + +```csv +tool,db_name,db_entity,db_params,db_path +mifaser,GS-24-all,,,/data/databases/mifaser/GS-24-all +``` + +### RGI BWT + +[RGI](https://card.mcmaster.ca/about) (Resistance Gene Identifier) uses the Comprehensive Antibiotic Resistance Database (CARD) to identify AMR genes. +The `bwt` subcommand aligns reads directly to CARD using Bowtie2/BWA. +Enable it with `--run_rgi`. + +#### Database preparation + +Download the CARD database and extract it to a directory. +The example CSV below labels the database as `card_v3`; replace this with the exact CARD release used in your analysis. + +```bash +wget https://card.mcmaster.ca/latest/data +tar -xvf data ./card.json +rgi load --card_json card.json --local +``` + +The `db_path` in the databases CSV must point to the directory containing `card.json` and the pre-built CARD annotation files (`card_database_v*.fasta`). + +```csv +tool,db_name,db_entity,db_params,db_path +rgi,card_v3,,,/data/databases/card +``` + +> [!NOTE] +> Wildcard variant databases are not currently supported by the pipeline. Only the core CARD database is used. + +### eggNOG-mapper + +[eggNOG-mapper](https://github.com/eggnogdb/eggnog-mapper) assigns functional annotations by mapping sequences to orthologous groups in the eggNOG database. +Enable it with `--run_eggnogmapper`. + +> [!WARNING] +> eggNOG-mapper support is currently in beta and should be treated as work in progress. Database handling, output behavior, and downstream reporting are still being validated in the full pipeline, so use with caution and independently review results before production use or interpretation. + +#### Database preparation + +eggNOG-mapper requires two rows per named database: the search database (`eggnogmapper_db`) and the eggNOG data directory (`eggnogmapper_data_dir`). +Both are downloaded with `download_eggnog_data.py`, which ships with the eggnog-mapper package; see the [eggNOG-mapper wiki](https://github.com/eggnogdb/eggnog-mapper/wiki) for the available releases. + +```bash +download_eggnog_data.py --data_dir /data/databases/eggnog_mapper/data -P +create_dbs.py -m diamond --dbname eggnog_proteins --data_dir /data/databases/eggnog_mapper +``` + +The `db_params` field of the `eggnogmapper_db` row must specify the search mode (e.g. `diamond`, `mmseqs`, `hmmer`). +The example below uses an eggNOG v5 database label; replace `eggnog_v5` with the exact eggNOG database release used in your analysis. + +```csv +tool,db_name,db_entity,db_params,db_path +eggnogmapper,eggnog_v5,eggnogmapper_db,diamond,/data/databases/eggnog_mapper/eggnog_proteins.dmnd +eggnogmapper,eggnog_v5,eggnogmapper_data_dir,,/data/databases/eggnog_mapper/data +``` + +### DIAMOND blastx + +[DIAMOND](https://github.com/bbuchfink/diamond/wiki/) is a high-throughput sequence aligner for translated (nucleotide-vs-protein) alignment. +Enable it with `--run_diamond`. + +> [!WARNING] +> DIAMOND support is currently in beta and should be treated as work in progress. Database handling, output behavior, and downstream reporting are still being validated in the full pipeline, so use with caution and independently review results before production use or interpretation. + +#### Database preparation + +The database supplied in the `--databases` CSV must already be in DIAMOND binary format (`.dmnd`). +Build it from a versioned protein FASTA using `diamond makedb`, and use `db_name` to record the source database and release. + +```bash +diamond makedb --in proteins.faa --db proteins +# produces proteins.dmnd +``` + +See the [DIAMOND makedb documentation](https://github.com/bbuchfink/diamond/wiki/3.-Command-line-options#makedb-options) for all available options (e.g. adding taxonomy, setting block size). + +```csv +tool,db_name,db_entity,db_params,db_path +diamond,uniref90_v3,,,/data/databases/diamond +``` + +> [!WARNING] +> The path should point to the **directory** containing the `.dmnd` file, not the file itself. The pipeline will automatically locate the `.dmnd` file within that directory. + +### Full example databases sheet + +This example uses versioned database names to make the database releases traceable in the run outputs. +Replace these names and paths with the exact database releases you downloaded. + +```csv +tool,db_name,db_entity,db_params,db_path +humann_v3,uniref90_v3,humann_metaphlan,,/data/databases/metaphlan_db +humann_v3,uniref90_v3,humann_nucleotide,,/data/databases/chocophlan +humann_v3,uniref90_v3,humann_protein,,/data/databases/uniref90_diamond +humann_v3,uniref90_v3,humann_utility,,/data/databases/utility_mapping +humann_v4,uniref90_v4,humann_metaphlan,,/data/databases/metaphlan4_db +humann_v4,uniref90_v4,humann_nucleotide,,/data/databases/chocophlan_v4 +humann_v4,uniref90_v4,humann_protein,,/data/databases/uniref90_v4_diamond +humann_v4,uniref90_v4,humann_utility,,/data/databases/utility_mapping_v4 +fmhfunprofiler,kegg_v1,,11 1000,/data/databases/fmhfunprofiler_kegg.sig.zip +mifaser,GS-24-all,,,/data/databases/mifaser/GS-24-all +rgi,card_v3,,,/data/databases/card +eggnogmapper,eggnog_v5,eggnogmapper_db,diamond,/data/databases/eggnog_mapper/eggnog_proteins.dmnd +eggnogmapper,eggnog_v5,eggnogmapper_data_dir,,/data/databases/eggnog_mapper/data +diamond,uniref90_v3,,,/data/databases/diamond +``` ## Running the pipeline The typical command for running the pipeline is as follows: ```bash -nextflow run nf-core/funcprofiler --input ./samplesheet.csv --outdir ./results --genome GRCh37 -profile docker +nextflow run nf-core/funcprofiler \ + --input samplesheet.csv \ + --databases databases.csv \ + --outdir results \ + --run_humann_v3 \ + --run_fmhfunprofiler \ + -profile docker ``` This will launch the pipeline with the `docker` configuration profile. See below for more information about profiles. @@ -71,6 +303,8 @@ work # Directory containing the nextflow working files # Other nextflow hidden files, eg. history of pipeline runs and old logs. ``` +### Parameters + If you wish to repeatedly use the same parameters for multiple runs, rather than specifying each flag in the command, you can specify these in a params file. Pipeline settings can be provided in a `yaml` or `json` file via `-params-file `. @@ -87,10 +321,10 @@ nextflow run nf-core/funcprofiler -profile docker -params-file params.yaml with: ```yaml title="params.yaml" -input: './samplesheet.csv' -outdir: './results/' -genome: 'GRCh37' -<...> +input: "./samplesheet.csv" +databases: "./databases.csv" +outdir: "./results/" +run_humann_v3: true ``` You can also generate such `YAML`/`JSON` files via [nf-core/launch](https://nf-co.re/launch). @@ -127,7 +361,7 @@ Use this parameter to choose a configuration profile. Profiles can give configur Several generic profiles are bundled with the pipeline which instruct the pipeline to use software packaged using different methods (Docker, Singularity, Podman, Shifter, Charliecloud, Apptainer, Conda) - see below. -> [!IMPORTANT] +> [!WARNING] > We highly recommend the use of Docker or Singularity containers for full pipeline reproducibility, however when this is not possible, Conda is also supported. The pipeline also dynamically loads configurations from [https://github.com/nf-core/configs](https://github.com/nf-core/configs) when it runs, making multiple config profiles for various institutional clusters available at run time. For more information and to check if your system is supported, please see the [nf-core/configs documentation](https://github.com/nf-core/configs#documentation). @@ -149,11 +383,11 @@ If `-profile` is not specified, the pipeline will run locally and expect all sof - `shifter` - A generic configuration profile to be used with [Shifter](https://nersc.gitlab.io/development/shifter/how-to-use/) - `charliecloud` - - A generic configuration profile to be used with [Charliecloud](https://hpc.github.io/charliecloud/) + - A generic configuration profile to be used with [Charliecloud](https://charliecloud.io/) - `apptainer` - A generic configuration profile to be used with [Apptainer](https://apptainer.org/) - `wave` - - A generic configuration profile to enable [Wave](https://seqera.io/wave/) containers. Use together with one of the above (requires Nextflow ` 24.03.0-edge` or later). + - A generic configuration profile to enable [Wave](https://seqera.io/wave/) containers. Use together with one of the above (requires Nextflow `24.03.0-edge` or later). - `conda` - A generic configuration profile to be used with [Conda](https://conda.io/docs/). Please only use Conda as a last resort i.e. when it's not possible to run the pipeline with Docker, Singularity, Podman, Shifter, Charliecloud, or Apptainer. @@ -173,19 +407,19 @@ Specify the path to a specific config file (this is a core Nextflow command). Se Whilst the default requirements set within the pipeline will hopefully work for most people and with most input data, you may find that you want to customise the compute resources that the pipeline requests. Each step in the pipeline has a default set of requirements for number of CPUs, memory and time. For most of the pipeline steps, if the job exits with any of the error codes specified [here](https://github.com/nf-core/rnaseq/blob/4c27ef5610c87db00c3c5a3eed10b1d161abf575/conf/base.config#L18) it will automatically be resubmitted with higher resources request (2 x original, then 3 x original). If it still fails after the third attempt then the pipeline execution is stopped. -To change the resource requests, please see the [max resources](https://nf-co.re/docs/usage/configuration#max-resources) and [tuning workflow resources](https://nf-co.re/docs/usage/configuration#tuning-workflow-resources) section of the nf-core website. +To change the resource requests, please see the [max resources](https://nf-co.re/docs/running/configuration/nextflow-for-your-system#set-max-resources) and [customise process resources](https://nf-co.re/docs/running/configuration/nextflow-for-your-system#customize-process-resources) section of the nf-core website. ### Custom Containers In some cases, you may wish to change the container or conda environment used by a pipeline steps for a particular tool. By default, nf-core pipelines use containers and software from the [biocontainers](https://biocontainers.pro/) or [bioconda](https://bioconda.github.io/) projects. However, in some cases the pipeline specified version maybe out of date. -To use a different container from the default container or conda environment specified in a pipeline, please see the [updating tool versions](https://nf-co.re/docs/usage/configuration#updating-tool-versions) section of the nf-core website. +To use a different container from the default container or conda environment specified in a pipeline, please see the [updating tool versions](https://nf-co.re/docs/running/configuration/nextflow-for-your-system#update-tool-versions) section of the nf-core website. ### Custom Tool Arguments A pipeline might not always support every possible argument or option of a particular tool used in pipeline. Fortunately, nf-core pipelines provide some freedom to users to insert additional parameters that the pipeline does not include by default. -To learn how to provide additional arguments to a particular tool of the pipeline, please see the [customising tool arguments](https://nf-co.re/docs/usage/configuration#customising-tool-arguments) section of the nf-core website. +To learn how to provide additional arguments to a particular tool of the pipeline, please see the [customising tool arguments](https://nf-co.re/docs/running/configuration/nextflow-for-your-system#modifying-tool-arguments) section of the nf-core website. ### nf-core/configs diff --git a/main.nf b/main.nf index e16f51d..7a99a80 100644 --- a/main.nf +++ b/main.nf @@ -15,21 +15,9 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { FUNCPROFILER } from './workflows/funcprofiler' +include { FUNCPROFILER } from './workflows/funcprofiler' include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_funcprofiler_pipeline' -include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_funcprofiler_pipeline' -include { getGenomeAttribute } from './subworkflows/local/utils_nfcore_funcprofiler_pipeline' - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - GENOME PARAMETER VALUES -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ - -// TODO nf-core: Remove this line if you don't need a FASTA file -// This is an example of how to use getGenomeAttribute() to fetch parameters -// from igenomes.config using `--genome` -params.fasta = getGenomeAttribute('fasta') +include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_funcprofiler_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -41,18 +29,24 @@ params.fasta = getGenomeAttribute('fasta') // WORKFLOW: Run main analysis pipeline depending on type of input // workflow NFCORE_FUNCPROFILER { - take: - samplesheet // channel: samplesheet read in from --input + reads // channel: validated reads read in from --input + databases // channel: databases in from --databases main: // // WORKFLOW: Run pipeline // - FUNCPROFILER ( - samplesheet + FUNCPROFILER( + reads, + databases, + params.multiqc_config, + params.multiqc_logo, + params.multiqc_methods_description, + params.outdir, ) + emit: multiqc_report = FUNCPROFILER.out.multiqc_report // channel: /path/to/multiqc_report.html } @@ -63,42 +57,39 @@ workflow NFCORE_FUNCPROFILER { */ workflow { - - main: // // SUBWORKFLOW: Run initialisation tasks // - PIPELINE_INITIALISATION ( + PIPELINE_INITIALISATION( params.version, params.validate_params, params.monochrome_logs, args, params.outdir, - params.input + params.input, + params.databases, + params.help, + params.help_full, + params.show_hidden, ) // // WORKFLOW: Run main workflow // - NFCORE_FUNCPROFILER ( - PIPELINE_INITIALISATION.out.samplesheet + NFCORE_FUNCPROFILER( + PIPELINE_INITIALISATION.out.reads, + PIPELINE_INITIALISATION.out.databases, ) // // SUBWORKFLOW: Run completion tasks // - PIPELINE_COMPLETION ( + PIPELINE_COMPLETION( params.email, params.email_on_fail, params.plaintext_email, params.outdir, params.monochrome_logs, params.hook_url, - NFCORE_FUNCPROFILER.out.multiqc_report + NFCORE_FUNCPROFILER.out.multiqc_report, ) } - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - THE END -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/ diff --git a/modules.json b/modules.json index 0e7d944..54adb7c 100644 --- a/modules.json +++ b/modules.json @@ -5,14 +5,79 @@ "https://github.com/nf-core/modules.git": { "modules": { "nf-core": { - "fastqc": { + "cat/fastq": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "diamond/blastx": { + "branch": "master", + "git_sha": "83ce9b314157a24d9a92f17a07ed5d55f30b78f9", + "installed_by": ["modules"] + }, + "eggnogmapper": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "fmhfunprofiler": { + "branch": "master", + "git_sha": "da290c59a571dbc2fddcd9b87b69b7517cad6a94", + "installed_by": ["modules"] + }, + "gunzip": { + "branch": "master", + "git_sha": "0902eac3012baaf4f9ab6513c8c55acc9353c96c", + "installed_by": ["modules"] + }, + "humann3/humann": { + "branch": "master", + "git_sha": "7a2d8f7e1861c9c62472f1cd168d33cef918b108", + "installed_by": ["modules"] + }, + "humann3/regroup": { + "branch": "master", + "git_sha": "7a2d8f7e1861c9c62472f1cd168d33cef918b108", + "installed_by": ["modules"] + }, + "humann3/renorm": { + "branch": "master", + "git_sha": "7a2d8f7e1861c9c62472f1cd168d33cef918b108", + "installed_by": ["modules"] + }, + "metaphlan/metaphlan": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "mifaser": { + "branch": "master", + "git_sha": "522d0a5709833aaa28c58d4464b4348d03316a62", "installed_by": ["modules"] }, "multiqc": { "branch": "master", - "git_sha": "41dfa3f7c0ffabb96a6a813fe321c6d1cc5b6e46", + "git_sha": "98403d15b0e50edae1f3fec5eae5e24982f1fade", + "installed_by": ["modules"] + }, + "rgi/bwt": { + "branch": "master", + "git_sha": "0a93f68a28f5e07bb7ae82aeb005720faf8a3b35", + "installed_by": ["modules"] + }, + "rgi/cardannotation": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", + "installed_by": ["modules"] + }, + "seqkit/fq2fa": { + "branch": "master", + "git_sha": "d07a945f421a4a91ce4e5a22db63e0e7f8741607", + "installed_by": ["modules"] + }, + "untar": { + "branch": "master", + "git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120", "installed_by": ["modules"] } } @@ -21,17 +86,17 @@ "nf-core": { "utils_nextflow_pipeline": { "branch": "master", - "git_sha": "c2b22d85f30a706a3073387f30380704fcae013b", + "git_sha": "1a545fcbd762911c21a64ced3dbef99b2b51ac75", "installed_by": ["subworkflows"] }, "utils_nfcore_pipeline": { "branch": "master", - "git_sha": "51ae5406a030d4da1e49e4dab49756844fdd6c7a", + "git_sha": "a3fb7351b1fdb2b1de282b765816bbea190e86a8", "installed_by": ["subworkflows"] }, "utils_nfschema_plugin": { "branch": "master", - "git_sha": "2fd2cd6d0e7b273747f32e465fdc6bcc3ae0814e", + "git_sha": "a7b27fd25bfa8dcc07d299e88bd790585901a436", "installed_by": ["subworkflows"] } } diff --git a/modules/local/humann4/humann/environment.yml b/modules/local/humann4/humann/environment.yml new file mode 100644 index 0000000..fe49246 --- /dev/null +++ b/modules/local/humann4/humann/environment.yml @@ -0,0 +1,11 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - biobakery::humann==4.0.0a1 + - bioconda::metaphlan==4.0.0 + - pip + - pip: + - setuptools diff --git a/modules/local/humann4/humann/main.nf b/modules/local/humann4/humann/main.nf new file mode 100644 index 0000000..b877369 --- /dev/null +++ b/modules/local/humann4/humann/main.nf @@ -0,0 +1,70 @@ +// +// Local module: there is no nf-core/modules HUMAnN 4 module, because HUMAnN 4 is still an alpha +// release with no Bioconda package or Biocontainer of its own. The script follows the nf-core +// humann3 modules; the container is a community build carrying humann 4.0.0.alpha.1. +// +process HUMANN4 { + tag "${meta.id}" + label 'process_high' + + conda "${moduleDir}/environment.yml" + container 'ghcr.io/vdblab/biobakery-profiler:4.0.6--4.0.0.alpha.1-final_smaller-pt2' + + input: + tuple val(meta), path(input) + tuple val(_meta), path(profile) + path nucleotide_db + path protein_db + path utility_db + + output: + tuple val(meta), path("*_genefamilies.tsv.gz"), emit: genefamilies + tuple val(meta), path("*_pathabundance.tsv.gz"), emit: pathabundance + tuple val(meta), path("*_reactions.tsv.gz"), emit: reactions + tuple val(meta), path("*.log"), emit: log + tuple val("${task.process}"), val('HUMAnN'), eval("humann --version 2>&1 | sed 's/humann v//'"), emit: versions_humann, topic: versions + tuple val("${task.process}"), val('MetaPHLan'), eval("metaphlan --version 2>&1 | sed 's/metaphlan v//'"), emit: versions_metaphlan, topic: versions + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def nuc_ext = '*.fna.gz' + // TODO: I never got this to successfully run + // def pangenome_string = "--metaphlan-options \"-t rel_ab --bowtie2db ./${pangenome_db} --index ${pangenome_db_index_name} \"" + def pangenome_string = "--taxonomic-profile ${profile}" + """ + PROTS_DB=`find -L "${protein_db}" -name "*.dmnd" -exec dirname {} \\;` + nuclist=`find -L "${nucleotide_db}" -name "${nuc_ext}" -print -quit ` + NUCS_DB=\$(dirname \$nuclist) + + STATIC_CONFIG=`python -c "import humann; print(humann.__file__.replace('__init__.py', 'humann.cfg'))"` + cat \$STATIC_CONFIG | sed "s|utility_mapping = .*|utility_mapping = ${utility_db}|g" > humann.cfg + export HUMANN_CONFIG=humann.cfg + + humann \\ + ${args} \\ + --threads ${task.cpus} \\ + --input ${input} \\ + --protein-database \${PROTS_DB} \\ + --nucleotide-database \${NUCS_DB} \\ + --output-basename ${prefix} \\ + ${pangenome_string} \\ + --o-log ${prefix}.log \\ + --output . + + gzip -n *.tsv + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo ${args} + + for suf in genefamilies.tsv.gz pathabundance.tsv.gz reactions.tsv.gz + do + echo stub | gzip > ${prefix}_\$suf + done + touch ${prefix}.log + """ +} diff --git a/modules/local/humann4/humann/meta.yaml b/modules/local/humann4/humann/meta.yaml new file mode 100644 index 0000000..98a4c17 --- /dev/null +++ b/modules/local/humann4/humann/meta.yaml @@ -0,0 +1,68 @@ +name: humann4 +description: Functional analysis of metagenome or metatranscrtiptome data +keywords: + - function + - metagenomics + - metatranscriptomics + - profiling + - community +tools: + - humann: + description: "HUMAnN: The HMP Unified Metabolic Analysis Network, version 4" + homepage: http://huttenhower.sph.harvard.edu/humann + documentation: https://github.com/biobakery/biobakery/wiki/humann4 + tool_dev_url: https://github.com/biobakery/humann + doi: "10.7554/eLife.65088" + licence: ["MIT"] + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - input: + type: file + description: | + A metagenome (DNA reads) or metatranscriptome (RNA reads) [fastq,fastq.gz,fasta,fasta.gz] + - please note: no paired-end files are supported, concatenate paired and reads into one file! + OR Pre-computed mappings of reads to database sequences [sam,bam,blastm8] + OR Pre-computed (typically gene) abundance tables [tsv,biom] + pattern: "*.{fastq,fastq.gz,fasta,fasta.gz,sam,bam,blastm8,tsv,biom}" + - profile: + type: file + description: a taxonomic profile generated by Metaphlan + - nucleotide_db: + type: file + description: | + Can be a compressed tar archive (*.tar.gz) or a folder containing compressed fasta files (folder/*.gz) + See http://huttenhower.sph.harvard.edu/humann_data/chocophlan + - protein_db: + type: file + description: | + Can be a compressed tar archive (*.tar.gz) or a folder containing compressed fasta files (folder/*.gz) + See http://huttenhower.sph.harvard.edu/humann_data/uniprot + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - genefamilies: + type: file + description: Compressed tab separated text file + pattern: "*.{tsv.gz}" + - pathabundance: + type: file + description: Compressed tab separated text file + pattern: "*.{tsv.gz}" + - reactions: + type: file + description: Compressed tab separated text file + pattern: "*.{tsv.gz}" + +authors: + - "@d4straub" + - "@nickp60" + - "@vinisalazar" diff --git a/modules/local/humann4/humann/tests/main_v4.nf.test b/modules/local/humann4/humann/tests/main_v4.nf.test new file mode 100644 index 0000000..cce38e3 --- /dev/null +++ b/modules/local/humann4/humann/tests/main_v4.nf.test @@ -0,0 +1,115 @@ +nextflow_process { + + name "Test Process HUMANN_HUMANN as HUMANN4" + script "../main.nf" + process "HUMANN4" + tag "modules" + tag "modules_" + tag "humann" + + setup{ + run("UNTAR", alias: "UNTAR_v4_nuc") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v4/chocophlan_nfDEMO.tar.gz', checkIfExists: true ) + ]) + """ + } + } + run("UNTAR", alias: "UNTAR_v4_prot") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v4/uniref_nfDEMO.tar.gz', checkIfExists: true ) + ]) + """ + } + } + run("UNTAR", alias: "UNTAR_v4_util") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v4/utility_nfDEMO.tar.gz', checkIfExists: true ) + ]) + """ + } + } + } + test("humann_v4 sarscov2 - fastq") { + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0]= Channel.of([ + [ id:'test', single_end:false, run_accession:"abc" ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + ]) + input[1] = Channel.of([[], file("${moduleDir}/tests/mpa_test.txt")]) + input[2] = UNTAR_v4_nuc.out.untar.map{ it[1] } + input[3] = UNTAR_v4_prot.out.untar.map{ it[1] } + input[4] = UNTAR_v4_util.out.untar.map{ it[1] } + """ + } + } + + then { + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}', '**/*.log', '**/*.biom', 'humann3/*', 'untar/*']) + println(stable_name) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore', ignore: ['**/*.log', '**/*.biom']) + println(stable_path) + assertAll( + { assert workflow.success}, + { assert snapshot( + // Number of successful tasks + workflow.trace.succeeded().size(), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() + } + ) + } + } + + test("humann_v4 sarscov2 - fastq - stub") { + + options "-stub" + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0]= Channel.of([ + [ id:'test', single_end:false, run_accession:"abc" ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + ]) + input[1] = Channel.of([[], file("${moduleDir}/tests/mpa_test.txt")]) + input[2] = UNTAR_v4_nuc.out.untar.map{ it[1] } + input[3] = UNTAR_v4_prot.out.untar.map{ it[1] } + input[4] = UNTAR_v4_util.out.untar.map{ it[1] } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.genefamilies, process.out.pathabundance, process.out.pathcoverage, process.out.reactions).match() } + ) + } + + } +} diff --git a/modules/local/humann4/humann/tests/main_v4.nf.test.snap b/modules/local/humann4/humann/tests/main_v4.nf.test.snap new file mode 100644 index 0000000..9ea548c --- /dev/null +++ b/modules/local/humann4/humann/tests/main_v4.nf.test.snap @@ -0,0 +1,62 @@ +{ + "humann_v4 sarscov2 - fastq": { + "content": [ + 4, + [ + "humann4", + "humann4/test_2_genefamilies.tsv.gz", + "humann4/test_3_reactions.tsv.gz", + "humann4/test_4_pathabundance.tsv.gz", + "pipeline_info" + ], + [ + + ] + ], + "timestamp": "2026-08-04T11:59:37.715128", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "humann_v4 sarscov2 - fastq - stub": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false, + "run_accession": "abc" + }, + "test_genefamilies.tsv.gz:md5,f50b84b1db4b83ba62ec1deacc69c260" + ] + ], + [ + [ + { + "id": "test", + "single_end": false, + "run_accession": "abc" + }, + "test_pathabundance.tsv.gz:md5,f50b84b1db4b83ba62ec1deacc69c260" + ] + ], + null, + [ + [ + { + "id": "test", + "single_end": false, + "run_accession": "abc" + }, + "test_reactions.tsv.gz:md5,f50b84b1db4b83ba62ec1deacc69c260" + ] + ] + ], + "timestamp": "2026-06-11T09:26:56.574951", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + } +} \ No newline at end of file diff --git a/modules/local/humann4/humann/tests/mpa_test.txt b/modules/local/humann4/humann/tests/mpa_test.txt new file mode 100644 index 0000000..68b3769 --- /dev/null +++ b/modules/local/humann4/humann/tests/mpa_test.txt @@ -0,0 +1,7 @@ +#vOct22_CHOCOPhlAnSGB_202403 +#/opt/venv/bin/metaphlan --nproc 6 --input_type fastq test_1.fastq.gz -t rel_ab_w_read_stats --bowtie2out test.bowtie2out.txt --bowtie2db metaphlan4_database --index vOct22_CHOCOPhlAnSGB_202403 --biom test.biom --output_file test_profile.txt +#100 reads processed +#SampleID Metaphlan_Analysis +#estimated_reads_mapped_to_known_clades:0 +#clade_name clade_taxid relative_abundance coverage estimated_number_of_reads_from_the_clade +unclassified -1 100.0 0 0 diff --git a/modules/local/humann4/regroup/environment.yml b/modules/local/humann4/regroup/environment.yml new file mode 100644 index 0000000..fe49246 --- /dev/null +++ b/modules/local/humann4/regroup/environment.yml @@ -0,0 +1,11 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - biobakery::humann==4.0.0a1 + - bioconda::metaphlan==4.0.0 + - pip + - pip: + - setuptools diff --git a/modules/local/humann4/regroup/main.nf b/modules/local/humann4/regroup/main.nf new file mode 100644 index 0000000..dfe522d --- /dev/null +++ b/modules/local/humann4/regroup/main.nf @@ -0,0 +1,50 @@ +// +// Local module: there is no nf-core/modules HUMAnN 4 module, because HUMAnN 4 is still an alpha +// release with no Bioconda package or Biocontainer of its own. The script follows the nf-core +// humann3 modules; the container is a community build carrying humann 4.0.0.alpha.1. +// +process HUMANN4_REGROUP { + tag "${meta.id}" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container 'ghcr.io/vdblab/biobakery-profiler:4.0.6--4.0.0.alpha.1-final_smaller-pt2' + + input: + tuple val(meta), path(input) + val groups + path utility_db + + output: + tuple val(meta), path("*_regroup.tsv.gz"), emit: regroup + tuple val("${task.process}"), val('HUMAnN'), eval("humann --version 2>&1 | sed 's/humann v//'"), emit: versions_humann, topic: versions + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + if [[ ${input} == *.gz ]]; then + gunzip -c ${input} > input.tsv + else + mv ${input} input.tsv + fi + STATIC_CONFIG=`python -c "import humann; print(humann.__file__.replace('__init__.py', 'humann.cfg'))"` + cat \$STATIC_CONFIG | sed "s|utility_mapping = .*|utility_mapping = ${utility_db}|g" > humann.cfg + export HUMANN_CONFIG=humann.cfg + humann_config --print + humann_regroup_table \\ + --input input.tsv \\ + --output ${prefix}_regroup.tsv \\ + --groups ${groups} \\ + ${args} + + gzip -n ${prefix}_regroup.tsv + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "stub" | gzip > ${prefix}_regroup.tsv.gz + """ +} diff --git a/modules/local/humann4/regroup/meta.yaml b/modules/local/humann4/regroup/meta.yaml new file mode 100644 index 0000000..690ad6f --- /dev/null +++ b/modules/local/humann4/regroup/meta.yaml @@ -0,0 +1,47 @@ +name: humann_regroup +description: Regrouping genes to other functional categories +keywords: + - function + - metagenomics + - metatranscriptomics + - profiling + - community +tools: + - humann: + description: "HUMAnN: The HMP Unified Metabolic Analysis Network, version 4" + homepage: http://huttenhower.sph.harvard.edu/humann + documentation: https://github.com/biobakery/biobakery/wiki/humann3 + tool_dev_url: https://github.com/biobakery/humann + doi: "10.7554/eLife.65088" + licence: ["MIT"] + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - input: + type: file + description: Tab separated abundance file of HUMAnN3 + pattern: "*.{tsv.gz,tsv}" + - groups: + type: value + description: Regroup abundance values to MetaCyc reaction (RXN) abundances + pattern: "{uniref90_rxn,uniref50_rxn}" + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - regroup: + type: file + description: Re-grouped compressed tab separated text file + pattern: "*.{tsv.gz}" + +authors: + - "@d4straub" + - "@nickp60" + - "@vinisalazar" diff --git a/modules/local/humann4/regroup/tests/main.nf.test b/modules/local/humann4/regroup/tests/main.nf.test new file mode 100644 index 0000000..4248f32 --- /dev/null +++ b/modules/local/humann4/regroup/tests/main.nf.test @@ -0,0 +1,47 @@ +nextflow_process { + + name "Test Process HUMANN4_REGROUP" + script "../main.nf" + process "HUMANN4_REGROUP" + tag "modules" + tag "modules_" + tag "humann" + setup { + run("UNTAR", alias: "UNTAR_v3_util") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v3/utility_nfDEMO.tar.gz', checkIfExists: true ) + ]) + """ + } + } + } + test("humann_regroup sarscov2 - tsv - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ]) + input[1] = "uniref90_rxn" + input[2] = UNTAR_v3_util.out.untar.map{ it[1] } + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/local/humann4/regroup/tests/main.nf.test.snap b/modules/local/humann4/regroup/tests/main.nf.test.snap new file mode 100644 index 0000000..96e22d0 --- /dev/null +++ b/modules/local/humann4/regroup/tests/main.nf.test.snap @@ -0,0 +1,45 @@ +{ + "humann_regroup sarscov2 - tsv - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test_regroup.tsv.gz:md5,f50b84b1db4b83ba62ec1deacc69c260" + ] + ], + "1": [ + [ + "HUMANN4_REGROUP", + "HUMAnN", + "4.0.0.alpha.1" + ] + ], + "regroup": [ + [ + { + "id": "test", + "single_end": false + }, + "test_regroup.tsv.gz:md5,f50b84b1db4b83ba62ec1deacc69c260" + ] + ], + "versions_humann": [ + [ + "HUMANN4_REGROUP", + "HUMAnN", + "4.0.0.alpha.1" + ] + ] + } + ], + "timestamp": "2026-04-20T23:44:45.066062", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file diff --git a/modules/local/humann4/renorm/environment.yml b/modules/local/humann4/renorm/environment.yml new file mode 100644 index 0000000..fe49246 --- /dev/null +++ b/modules/local/humann4/renorm/environment.yml @@ -0,0 +1,11 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - biobakery::humann==4.0.0a1 + - bioconda::metaphlan==4.0.0 + - pip + - pip: + - setuptools diff --git a/modules/local/humann4/renorm/main.nf b/modules/local/humann4/renorm/main.nf new file mode 100644 index 0000000..d098a27 --- /dev/null +++ b/modules/local/humann4/renorm/main.nf @@ -0,0 +1,44 @@ +// +// Local module: there is no nf-core/modules HUMAnN 4 module, because HUMAnN 4 is still an alpha +// release with no Bioconda package or Biocontainer of its own. The script follows the nf-core +// humann3 modules; the container is a community build carrying humann 4.0.0.alpha.1. +// +process HUMANN4_RENORM { + tag "${meta.id}" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container 'ghcr.io/vdblab/biobakery-profiler:4.0.6--4.0.0.alpha.1-final_smaller-pt2' + + input: + tuple val(meta), path(input) + + output: + tuple val(meta), path("*_renorm.tsv.gz"), emit: renorm + tuple val("${task.process}"), val('HUMAnN'), eval("humann --version 2>&1 | sed 's/humann v//'"), emit: versions_humann, topic: versions + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + if [[ ${input} == *.gz ]]; then + gunzip -c ${input} > input.tsv + else + mv ${input} input.tsv + fi + + humann_renorm_table \\ + --input input.tsv \\ + --output ${prefix}_renorm.tsv \\ + ${args} + + gzip -n ${prefix}_renorm.tsv + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "stub" | gzip > ${prefix}_renorm.tsv.gz + """ +} diff --git a/modules/local/humann4/renorm/meta.yaml b/modules/local/humann4/renorm/meta.yaml new file mode 100644 index 0000000..4beb532 --- /dev/null +++ b/modules/local/humann4/renorm/meta.yaml @@ -0,0 +1,43 @@ +name: humann_renorm +description: Normalizing RPKs to relative abundance +keywords: + - function + - metagenomics + - metatranscriptomics + - profiling + - community +tools: + - humann: + description: "HUMAnN: The HMP Unified Metabolic Analysis Network, version 3" + homepage: http://huttenhower.sph.harvard.edu/humann + documentation: https://github.com/biobakery/biobakery/wiki/humann3 + tool_dev_url: https://github.com/biobakery/humann + doi: "10.7554/eLife.65088" + licence: ["MIT"] + +input: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - input: + type: file + description: Tab separated abundance file of HUMAnN3 + pattern: "*.{tsv.gz,tsv}" + +output: + - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - renorm: + type: file + description: Normalized compressed tab separated text file + pattern: "*.{tsv.gz}" + +authors: + - "@d4straub" + - "@nickp60" + - "@vinisalazar" diff --git a/modules/local/humann4/renorm/tests/main.nf.test b/modules/local/humann4/renorm/tests/main.nf.test new file mode 100644 index 0000000..62c03d0 --- /dev/null +++ b/modules/local/humann4/renorm/tests/main.nf.test @@ -0,0 +1,34 @@ +nextflow_process { + + name "Test Process HUMANN_RENORM" + script "../main.nf" + process "HUMANN4_RENORM" + tag "modules" + tag "modules_" + tag "humann" + + test("humann4_renorm sarscov2 - tsv - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/local/humann4/renorm/tests/main.nf.test.snap b/modules/local/humann4/renorm/tests/main.nf.test.snap new file mode 100644 index 0000000..730ece4 --- /dev/null +++ b/modules/local/humann4/renorm/tests/main.nf.test.snap @@ -0,0 +1,45 @@ +{ + "humann4_renorm sarscov2 - tsv - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test_renorm.tsv.gz:md5,f50b84b1db4b83ba62ec1deacc69c260" + ] + ], + "1": [ + [ + "HUMANN4_RENORM", + "HUMAnN", + "4.0.0.alpha.1" + ] + ], + "renorm": [ + [ + { + "id": "test", + "single_end": false + }, + "test_renorm.tsv.gz:md5,f50b84b1db4b83ba62ec1deacc69c260" + ] + ], + "versions_humann": [ + [ + "HUMANN4_RENORM", + "HUMAnN", + "4.0.0.alpha.1" + ] + ] + } + ], + "timestamp": "2026-04-21T11:51:26.626171", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/cat/fastq/environment.yml b/modules/nf-core/cat/fastq/environment.yml new file mode 100644 index 0000000..9b926b1 --- /dev/null +++ b/modules/nf-core/cat/fastq/environment.yml @@ -0,0 +1,12 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - conda-forge::coreutils=9.5 + - conda-forge::grep=3.11 + - conda-forge::gzip=1.13 + - conda-forge::lbzip2=2.5 + - conda-forge::sed=4.8 + - conda-forge::tar=1.34 diff --git a/modules/nf-core/cat/fastq/main.nf b/modules/nf-core/cat/fastq/main.nf new file mode 100644 index 0000000..8d12a78 --- /dev/null +++ b/modules/nf-core/cat/fastq/main.nf @@ -0,0 +1,69 @@ +process CAT_FASTQ { + tag "${meta.id}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/52ccce28d2ab928ab862e25aae26314d69c8e38bd41ca9431c67ef05221348aa/data' + : 'community.wave.seqera.io/library/coreutils_grep_gzip_lbzip2_pruned:838ba80435a629f8'}" + + input: + tuple val(meta), path(reads, stageAs: "input*/*") + + output: + tuple val(meta), path("*.merged.fastq.gz"), emit: reads + tuple val("${task.process}"), val("cat"), eval("cat --version 2>&1 | head -n 1 | sed 's/^.*coreutils) //; s/ .*\$//'"), emit: versions_cat, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def prefix = task.ext.prefix ?: "${meta.id}" + def readList = reads instanceof List ? reads.collect { item -> item.toString() } : [reads.toString()] + def compress = readList[0]?.endsWith('.gz') ? '' : '| gzip' + if (meta.single_end) { + if (readList.size >= 1) { + """ + cat ${readList.join(' ')} ${compress} > ${prefix}.merged.fastq.gz + """ + } else { + error("Could not find any FASTQ files to concatenate in the process input") + } + } + else { + if (readList.size >= 2) { + def read1 = [] + def read2 = [] + readList.eachWithIndex { v, ix -> (ix & 1 ? read2 : read1) << v } + """ + cat ${read1.join(' ')} ${compress} > ${prefix}_1.merged.fastq.gz + cat ${read2.join(' ')} ${compress} > ${prefix}_2.merged.fastq.gz + """ + } else { + error("Could not find any FASTQ file pairs to concatenate in the process input") + } + } + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + def readList = reads instanceof List ? reads.collect { item -> item.toString() } : [reads.toString()] + if (meta.single_end) { + if (readList.size >= 1) { + """ + echo '' | gzip > ${prefix}.merged.fastq.gz + """ + } else { + error("Could not find any FASTQ files to concatenate in the process input") + } + } + else { + if (readList.size >= 2) { + """ + echo '' | gzip > ${prefix}_1.merged.fastq.gz + echo '' | gzip > ${prefix}_2.merged.fastq.gz + """ + } else { + error("Could not find any FASTQ file pairs to concatenate in the process input") + } + } +} diff --git a/modules/nf-core/cat/fastq/meta.yml b/modules/nf-core/cat/fastq/meta.yml new file mode 100644 index 0000000..6fefd6e --- /dev/null +++ b/modules/nf-core/cat/fastq/meta.yml @@ -0,0 +1,67 @@ +name: cat_fastq +description: Concatenates fastq files. Supports both compressed (.gz) and uncompressed inputs; uncompressed files are automatically gzip-compressed during concatenation. +keywords: + - cat + - fastq + - concatenate + - compress +tools: + - cat: + description: | + The cat utility reads files sequentially, writing them to the standard output. + documentation: https://www.gnu.org/software/coreutils/manual/html_node/cat-invocation.html + licence: ["GPL-3.0-or-later"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: | + List of input FastQ files to be concatenated. + Accepts both gzip-compressed (.fastq.gz) and uncompressed (.fastq) files. + ontologies: [] +output: + reads: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.merged.fastq.gz": + type: file + description: Merged fastq file + pattern: "*.{merged.fastq.gz}" + ontologies: [] + versions_cat: + - - ${task.process}: + type: string + description: The process the versions were collected from + - cat: + type: string + description: The tool name + - cat --version 2>&1 | head -n 1 | sed 's/^.*coreutils) //; s/ .*\$//': + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - cat: + type: string + description: The tool name + - cat --version 2>&1 | head -n 1 | sed 's/^.*coreutils) //; s/ .*\$//': + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@joseespinosa" + - "@drpatelh" +maintainers: + - "@joseespinosa" + - "@drpatelh" diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test b/modules/nf-core/cat/fastq/tests/main.nf.test new file mode 100644 index 0000000..21052d9 --- /dev/null +++ b/modules/nf-core/cat/fastq/tests/main.nf.test @@ -0,0 +1,405 @@ +nextflow_process { + + name "Test Process CAT_FASTQ" + script "../main.nf" + process "CAT_FASTQ" + tag "modules" + tag "modules_nfcore" + tag "cat" + tag "cat/fastq" + tag "gunzip" + + test("test_cat_fastq_single_end") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_paired_end") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end_same_name") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_paired_end_same_name") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end_uncompressed") { + + setup { + run("GUNZIP") { + script "../../../gunzip/main.nf" + process { + """ + input[0] = Channel.of( + [[ id:'r1' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)], + [[ id:'r2' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ) + """ + } + } + } + + when { + process { + """ + input[0] = GUNZIP.out.gunzip + .toSortedList { a, b -> a[0].id <=> b[0].id } + .map { items -> [[ id: 'test', single_end: true ], items.collect { it[1] }] } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_paired_end_uncompressed") { + + setup { + run("GUNZIP") { + script "../../../gunzip/main.nf" + process { + """ + input[0] = Channel.of( + [[ id:'a' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)], + [[ id:'b' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)], + [[ id:'c' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true)], + [[ id:'d' ], file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true)] + ) + """ + } + } + } + + when { + process { + """ + input[0] = GUNZIP.out.gunzip + .toSortedList { a, b -> a[0].id <=> b[0].id } + .map { items -> [[ id: 'test', single_end: false ], items.collect { it[1] }] } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end_single_file") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_paired_end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end_same_name - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_paired_end_same_name - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end_single_file - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true)] + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("test_cat_fastq_single_end_no_files") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [] + ]) + """ + } + } + + then { + assertAll( + { assert process.failed }, + { assert snapshot(process.stdout.find { it.contains("-- Check script") }.split(" -- Check script")[0]).match() } + ) + } + } + + test("test_cat_fastq_paired_end_no_files") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [] + ]) + """ + } + } + + then { + assertAll( + { assert process.failed }, + { assert snapshot(process.stdout.find { it.contains("-- Check script") }.split(" -- Check script")[0]).match() } + ) + } + } + + test("test_cat_fastq_single_end_no_files - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + [] + ]) + """ + } + } + + then { + assertAll( + { assert process.failed }, + { assert snapshot(process.stdout.find { it.contains("-- Check script") }.split(" -- Check script")[0]).match() } + ) + } + } + + test("test_cat_fastq_paired_end_no_files - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [] + ]) + """ + } + } + + then { + assertAll( + { assert process.failed }, + { assert snapshot(process.stdout.find { it.contains("-- Check script") }.split(" -- Check script")[0]).match() } + ) + } + } +} diff --git a/modules/nf-core/cat/fastq/tests/main.nf.test.snap b/modules/nf-core/cat/fastq/tests/main.nf.test.snap new file mode 100644 index 0000000..6375b2a --- /dev/null +++ b/modules/nf-core/cat/fastq/tests/main.nf.test.snap @@ -0,0 +1,588 @@ +{ + "test_cat_fastq_paired_end_no_files - stub": { + "content": [ + " Could not find any FASTQ file pairs to concatenate in the process input" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-02-25T17:14:51.248685461" + }, + "test_cat_fastq_single_end_single_file": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:31:42.84401526" + }, + "test_cat_fastq_paired_end_same_name": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:31:36.820489323" + }, + "test_cat_fastq_paired_end_same_name - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:32:06.262192935" + }, + "test_cat_fastq_single_end_uncompressed": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,ee314a9bd568d06617171b0c85f508da" + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,ee314a9bd568d06617171b0c85f508da" + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-02-09T10:03:24.344628" + }, + "test_cat_fastq_paired_end_uncompressed": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-02-09T10:03:37.568053" + }, + "test_cat_fastq_single_end": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,ee314a9bd568d06617171b0c85f508da" + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,ee314a9bd568d06617171b0c85f508da" + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:31:18.859169785" + }, + "test_cat_fastq_single_end_same_name": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22" + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22" + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:31:30.942615287" + }, + "test_cat_fastq_single_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:31:48.827990633" + }, + "test_cat_fastq_paired_end_no_files": { + "content": [ + " Could not find any FASTQ file pairs to concatenate in the process input" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-02-25T17:14:40.806088747" + }, + "test_cat_fastq_single_end_no_files - stub": { + "content": [ + " Could not find any FASTQ files to concatenate in the process input" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-02-25T17:14:45.852365218" + }, + "test_cat_fastq_single_end_same_name - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:32:00.586584379" + }, + "test_cat_fastq_paired_end": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,3ad9406595fafec8172368f9cd0b6a22", + "test_2.merged.fastq.gz:md5,a52cab0b840c7178b0ea83df1fdbe8d5" + ] + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:31:25.159365603" + }, + "test_cat_fastq_single_end_no_files": { + "content": [ + " Could not find any FASTQ files to concatenate in the process input" + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "24.10.4" + }, + "timestamp": "2025-02-25T17:14:35.695192409" + }, + "test_cat_fastq_paired_end - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_1.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "test_2.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:31:54.850702874" + }, + "test_cat_fastq_single_end_single_file - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ], + "reads": [ + [ + { + "id": "test", + "single_end": true + }, + "test.merged.fastq.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions_cat": [ + [ + "CAT_FASTQ", + "cat", + "9.5" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2025-12-10T14:32:11.746498148" + } +} \ No newline at end of file diff --git a/modules/nf-core/fastqc/environment.yml b/modules/nf-core/diamond/blastx/environment.yml similarity index 86% rename from modules/nf-core/fastqc/environment.yml rename to modules/nf-core/diamond/blastx/environment.yml index f9f54ee..5dc13ad 100644 --- a/modules/nf-core/fastqc/environment.yml +++ b/modules/nf-core/diamond/blastx/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::fastqc=0.12.1 + - bioconda::diamond=2.2.1 diff --git a/modules/nf-core/diamond/blastx/main.nf b/modules/nf-core/diamond/blastx/main.nf new file mode 100644 index 0000000..453170c --- /dev/null +++ b/modules/nf-core/diamond/blastx/main.nf @@ -0,0 +1,117 @@ +process DIAMOND_BLASTX { + tag "${meta.id}" + label 'process_high' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://depot.galaxyproject.org/singularity/diamond:2.2.1--he361c42_0' + : 'quay.io/biocontainers/diamond:2.2.1--he361c42_0'}" + + input: + tuple val(meta), path(fasta) + tuple val(meta2), path(db) + val out_ext + val blast_columns + + output: + tuple val(meta), path('*.blast'), optional: true, emit: blast + tuple val(meta), path('*.xml'), optional: true, emit: xml + tuple val(meta), path('*.txt'), optional: true, emit: txt + tuple val(meta), path('*.daa'), optional: true, emit: daa + tuple val(meta), path('*.sam'), optional: true, emit: sam + tuple val(meta), path('*.tsv'), optional: true, emit: tsv + tuple val(meta), path('*.paf'), optional: true, emit: paf + tuple val(meta), path("*.log"), emit: log + tuple val("${task.process}"), val('diamond'), eval("diamond --version | sed 's/diamond version //g'"), emit: versions_diamond, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def is_compressed = fasta.getExtension() == "gz" ? true : false + def fasta_name = is_compressed ? fasta.getBaseName() : fasta + def columns = blast_columns ? "${blast_columns}" : '' + if (out_ext == 'blast') { + outfmt = 0 + } + else if (out_ext == 'xml') { + outfmt = 5 + } + else if (out_ext == 'txt') { + outfmt = 6 + } + else if (out_ext == 'daa') { + outfmt = 100 + } + else if (out_ext == 'sam') { + outfmt = 101 + } + else if (out_ext == 'tsv') { + outfmt = 102 + } + else if (out_ext == 'paf') { + outfmt = 103 + } + else { + outfmt = 6 + out_ext = 'txt' + log.warn("Unknown output file format provided (${out_ext}): selecting DIAMOND default of tabular BLAST output (txt)") + } + """ + if [ "${is_compressed}" == "true" ]; then + gzip -c -d ${fasta} > ${fasta_name} + fi + + DB=`find -L ./ -name "*.dmnd" | sed 's/\\.dmnd\$//'` + + diamond \\ + blastx \\ + --threads ${task.cpus} \\ + --db \$DB \\ + --query ${fasta_name} \\ + --outfmt ${outfmt} ${columns} \\ + ${args} \\ + --out ${prefix}.${out_ext} \\ + --log + + mv diamond.log ${prefix}.log + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + if (out_ext == 'blast') { + outfmt = 0 + } + else if (out_ext == 'xml') { + outfmt = 5 + } + else if (out_ext == 'txt') { + outfmt = 6 + } + else if (out_ext == 'daa') { + outfmt = 100 + } + else if (out_ext == 'sam') { + outfmt = 101 + } + else if (out_ext == 'tsv') { + outfmt = 102 + } + else if (out_ext == 'paf') { + outfmt = 103 + } + else { + outfmt = 6 + out_ext = 'txt' + log.warn("Unknown output file format provided (${out_ext}): selecting DIAMOND default of tabular BLAST output (txt)") + } + + """ + echo "${args}" + touch ${prefix}.${out_ext} + touch ${prefix}.log + """ +} diff --git a/modules/nf-core/diamond/blastx/meta.yml b/modules/nf-core/diamond/blastx/meta.yml new file mode 100644 index 0000000..019a3e9 --- /dev/null +++ b/modules/nf-core/diamond/blastx/meta.yml @@ -0,0 +1,179 @@ +name: diamond_blastx +description: Queries a DIAMOND database using blastx mode +keywords: + - fasta + - diamond + - blastx + - DNA sequence +tools: + - diamond: + description: Accelerated BLAST compatible local sequence aligner + homepage: https://github.com/bbuchfink/diamond + documentation: https://github.com/bbuchfink/diamond/wiki + tool_dev_url: https://github.com/bbuchfink/diamond + doi: "10.1038/s41592-021-01101-x" + licence: + - "GPL v3.0" + identifier: biotools:diamond +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - fasta: + type: file + description: Input fasta file containing query sequences + pattern: "*.{fa,fasta,fa.gz,fasta.gz}" + ontologies: + - edam: http://edamontology.org/format_1929 # FASTA + - - meta2: + type: map + description: | + Groovy Map containing db information + e.g. [ id:'test2', single_end:false ] + - db: + type: file + description: File of the indexed DIAMOND database + pattern: "*.dmnd" + ontologies: [] + - out_ext: + type: string + description: | + Specify the type of output file to be generated. `blast` corresponds to + BLAST pairwise format. `xml` corresponds to BLAST xml format. + `txt` corresponds to to BLAST tabular format. `tsv` corresponds to + taxonomic classification format. + pattern: "blast|xml|txt|daa|sam|tsv|paf" + - blast_columns: + type: string + description: | + Optional space separated list of DIAMOND tabular BLAST output keywords + used for in conjunction with the 'txt' out_ext option (--outfmt 6). Options: + qseqid sseqid pident length mismatch gapopen qstart qend sstart send evalue bitscore +output: + blast: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.blast": + type: file + description: File containing blastp hits + pattern: "*.{blast}" + ontologies: + - edam: http://edamontology.org/format_3836 # BLAST XML v2 results format + xml: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.xml": + type: file + description: File containing blastp hits + pattern: "*.{xml}" + ontologies: + - edam: http://edamontology.org/format_2332 # XML + txt: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.txt": + type: file + description: File containing hits in tabular BLAST format. + pattern: "*.{txt}" + ontologies: [] + daa: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.daa": + type: file + description: File containing hits DAA format + pattern: "*.{daa}" + ontologies: [] + sam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.sam": + type: file + description: File containing aligned reads in SAM format + pattern: "*.{sam}" + ontologies: + - edam: http://edamontology.org/format_2573 # SAM + tsv: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.tsv": + type: file + description: Tab separated file containing taxonomic classification of + hits + pattern: "*.{tsv}" + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + paf: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.paf": + type: file + description: File containing aligned reads in pairwise mapping format + format + pattern: "*.{paf}" + ontologies: [] + log: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.log": + type: file + description: Log file containing stdout information + pattern: "*.{log}" + ontologies: [] + versions_diamond: + - - ${task.process}: + type: string + description: The name of the process + - diamond: + type: string + description: The name of the tool + - diamond --version | sed 's/diamond version //g': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - diamond: + type: string + description: The name of the tool + - diamond --version | sed 's/diamond version //g': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@spficklin" + - "@jfy133" + - "@mjamy" +maintainers: + - "@spficklin" + - "@jfy133" + - "@mjamy" + - "@vagkaratzas" + - "@sofstam" diff --git a/modules/nf-core/diamond/blastx/tests/main.nf.test b/modules/nf-core/diamond/blastx/tests/main.nf.test new file mode 100644 index 0000000..87011ef --- /dev/null +++ b/modules/nf-core/diamond/blastx/tests/main.nf.test @@ -0,0 +1,82 @@ +nextflow_process { + + name "Test Process DIAMOND_BLASTX" + script "../main.nf" + process "DIAMOND_BLASTX" + tag "modules" + tag "modules_nfcore" + tag "diamond" + tag "diamond/makedb" + tag "diamond/blastx" + + setup { + run("DIAMOND_MAKEDB") { + script "../../makedb/main.nf" + process { + """ + input[0] = [ [id:'test2'], [ file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] ] + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + } + + test("Should search for transcriptome hits against a DIAMOND db and return the default tab separated output file of hits") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = [ [id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/transcriptome.fasta', checkIfExists: true) ] + input[1] = DIAMOND_MAKEDB.out.db + input[2] = 'tfdfdt' // Nonsense file extension to check default case. + input[3] = 'qseqid qlen' + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert path(process.out.log.get(0).get(1)).readLines().contains("11 queries aligned.") }, + { assert snapshot( + process.out.txt, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() + } + ) + } + + } + + test("Should search for transcriptome hits against a DIAMOND db and return the daa format output file of hits") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = [ [id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/transcriptome.fasta', checkIfExists: true) ] + input[1] = DIAMOND_MAKEDB.out.db + input[2] = 'daa' + input[3] = [] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.daa }, + { assert path(process.out.log.get(0).get(1)).readLines().contains("11 queries aligned.") }, + { assert snapshot(process.out.findAll { key, val -> key.startsWith('versions') }).match() } + ) + } + + } +} diff --git a/modules/nf-core/diamond/blastx/tests/main.nf.test.snap b/modules/nf-core/diamond/blastx/tests/main.nf.test.snap new file mode 100644 index 0000000..b3cf211 --- /dev/null +++ b/modules/nf-core/diamond/blastx/tests/main.nf.test.snap @@ -0,0 +1,46 @@ +{ + "Should search for transcriptome hits against a DIAMOND db and return the daa format output file of hits": { + "content": [ + { + "versions_diamond": [ + [ + "DIAMOND_BLASTX", + "diamond", + "2.2.1" + ] + ] + } + ], + "timestamp": "2026-06-09T15:06:53.562101168", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.3" + } + }, + "Should search for transcriptome hits against a DIAMOND db and return the default tab separated output file of hits": { + "content": [ + [ + [ + { + "id": "test" + }, + "test.txt:md5,33dc682dabfa44c7089abbc8fe8b84e4" + ] + ], + { + "versions_diamond": [ + [ + "DIAMOND_BLASTX", + "diamond", + "2.2.1" + ] + ] + } + ], + "timestamp": "2026-06-09T15:06:47.844654623", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.3" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/eggnogmapper/environment.yml b/modules/nf-core/eggnogmapper/environment.yml new file mode 100644 index 0000000..58acb20 --- /dev/null +++ b/modules/nf-core/eggnogmapper/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::eggnog-mapper=2.1.13 diff --git a/modules/nf-core/eggnogmapper/main.nf b/modules/nf-core/eggnogmapper/main.nf new file mode 100644 index 0000000..cff118e --- /dev/null +++ b/modules/nf-core/eggnogmapper/main.nf @@ -0,0 +1,58 @@ +process EGGNOGMAPPER { + tag "$meta.id" + label 'process_high' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/eggnog-mapper:2.1.13--pyhdfd78af_2': + 'quay.io/biocontainers/eggnog-mapper:2.1.13--pyhdfd78af_2' }" + + input: + tuple val(meta), path(fasta) + tuple val(search_mode), path(db) + path(eggnog_data_dir) + + output: + tuple val(meta), path("*.emapper.annotations") , emit: annotations + tuple val(meta), path("*.emapper.seed_orthologs"), emit: orthologs, optional: true + tuple val(meta), path("*.emapper.hits") , emit: hits , optional: true + tuple val("${task.process}"), val('eggnog-mapper'), eval("emapper.py --version 2>&1 | grep -o 'emapper-[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+' | sed 's/emapper-//'"), topic: versions, emit: versions_eggnogmapper + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def is_compressed = fasta.extension == '.gz' + def fasta_name = is_compressed ? fasta.baseName : "$fasta" + def db_flags = ['diamond': '--dmnd_db', 'novel_fams': '--dmnd_db', 'mmseqs': '--mmseqs_db', 'hmmer': '--database', 'no_search': '--annotate_hits_table', 'cache': '--cache'] + def db_path = (db instanceof Path && db.isDirectory()) ? "${db}/${db.name}" : "$db" + def db_arg = db && db_flags[search_mode] ? "${db_flags[search_mode]} ${db_path}" : '' + def dbmem = task.memory.toMega() > 40000 ? '--dbmem' : '' + """ + if [ "$is_compressed" == "true" ]; then + gzip -c -d $fasta > $fasta_name + fi + + emapper.py \\ + $args \\ + --cpu ${task.cpus} \\ + -i ${fasta_name} \\ + --data_dir ${eggnog_data_dir} \\ + -m ${search_mode} \\ + $db_arg \\ + ${dbmem} \\ + --output ${prefix} + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo $args + + touch ${prefix}.emapper.annotations + touch ${prefix}.emapper.seed_orthologs + touch ${prefix}.emapper.hits + """ +} diff --git a/modules/nf-core/eggnogmapper/meta.yml b/modules/nf-core/eggnogmapper/meta.yml new file mode 100644 index 0000000..7f04642 --- /dev/null +++ b/modules/nf-core/eggnogmapper/meta.yml @@ -0,0 +1,136 @@ +name: "eggnogmapper" +description: Fast genome-wide functional annotation through orthology assignment. +keywords: + - annotation + - functional annotation + - orthology + - genomics + - eggnog +tools: + - "eggnogmapper": + description: | + EggNOG-mapper is a tool for fast functional annotation of novel sequences. + It uses precomputed orthologous groups and phylogenies from the eggNOG database + to transfer functional information from fine-grained orthologs only. + homepage: "https://github.com/eggnogdb/eggnog-mapper" + documentation: "https://github.com/eggnogdb/eggnog-mapper/wiki" + tool_dev_url: "https://github.com/eggnogdb/eggnog-mapper" + doi: "10.1093/molbev/msab293" + licence: + - "AGPL v3" + identifier: "biotools:eggnog-mapper-v2" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - fasta: + type: file + description: Input sequences in FASTA format (plain or gzip-compressed) + pattern: "*.{fasta,faa,fa}(.gz)?" + ontologies: + - edam: http://edamontology.org/format_1929 # FASTA + - - search_mode: + type: string + description: | + Search mode passed to emapper.py via -m. Determines which backend + is used and which database flag is applied internally. + Supported modes: + - diamond: DIAMOND-based homology search (--dmnd_db) + - novel_fams: DIAMOND search against novel families (--dmnd_db) + - mmseqs: MMseqs2-based search (--mmseqs_db) + - hmmer: HMMER-based search (--database) + - no_search: Skip search step and annotate from a precomputed + *.emapper.seed_orthologs file (--annotate_hits_table) + - cache: Reuse a previously generated hits table (--cache) + enum: [diamond, novel_fams, mmseqs, hmmer, no_search, cache] + - db: + type: file + description: | + Database file, directory, or precomputed results file required by the + selected search_mode. The module automatically assigns the correct + flag depending on search_mode: + - diamond / novel_fams: DIAMOND database (*.dmnd) + - mmseqs: MMseqs2 database directory or prefix + - hmmer: HMM database (*.hmm, *.h3m) + - no_search: Precomputed *.emapper.seed_orthologs file + - cache: Previously generated *.emapper.hits file + This input is mandatory but its expected format depends on search_mode. + pattern: "*" + ontologies: + - edam: http://edamontology.org/format_1370 # HMMER format + - edam: http://edamontology.org/format_3475 # TSV + - eggnog_data_dir: + type: directory + description: | + Directory containing eggnog-mapper database files + (e.g. can be downloaded via download_eggnog_data.py, + found in the eggnog-mapper repository) + pattern: "*" +output: + annotations: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*.emapper.annotations": + type: file + description: TSV file with the results from the annotation phase, including + functional annotations, GO terms, KEGG pathways, and COG categories + pattern: "*.emapper.annotations" + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + orthologs: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*.emapper.seed_orthologs": + type: file + description: TSV file with the results from parsing the hits, linking queries + with their best seed orthologs (includes commented metadata header) + pattern: "*.emapper.seed_orthologs" + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + hits: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1' ]` + - "*.emapper.hits": + type: file + description: TSV file with the raw search hits from the Diamond/MMseqs2/HMMER + search phase before annotation + pattern: "*.emapper.hits" + ontologies: + - edam: http://edamontology.org/format_3475 # TSV + versions_eggnogmapper: + - - ${task.process}: + type: string + description: The name of the process + - eggnog-mapper: + type: string + description: The name of the tool + - emapper.py --version 2>&1 | grep -o 'emapper-[0-9]\+\.[0-9]\+\.[0-9]\+' | sed 's/emapper-//': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - eggnog-mapper: + type: string + description: The name of the tool + - emapper.py --version 2>&1 | grep -o 'emapper-[0-9]\+\.[0-9]\+\.[0-9]\+' | sed 's/emapper-//': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@vagkaratzas" +maintainers: + - "@vagkaratzas" + - "@gallvp" diff --git a/modules/nf-core/eggnogmapper/tests/main.nf.test b/modules/nf-core/eggnogmapper/tests/main.nf.test new file mode 100644 index 0000000..5b74a12 --- /dev/null +++ b/modules/nf-core/eggnogmapper/tests/main.nf.test @@ -0,0 +1,182 @@ +nextflow_process { + + name "Test Process EGGNOGMAPPER" + script "../main.nf" + process "EGGNOGMAPPER" + + tag "modules" + tag "modules_nfcore" + tag "eggnogmapper" + tag "diamond" + tag "diamond/makedb" + tag "mmseqs" + tag "mmseqs/createdb" + + test("sarscov2 - proteome - diamond") { + setup { + run("DIAMOND_MAKEDB") { + script "../../diamond/makedb/main.nf" + process { + """ + input[0] = [ [id:'dmnd_db'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + } + + when { + process { + """ + input[0] = [ [id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + input[1] = DIAMOND_MAKEDB.out.db.map { _meta, db -> [ 'diamond', db ] } + eggnog_db = file(params.modules_testdata_base_path + '/delete_me/eggnogmapper/eggnog.db', checkIfExists: true) + eggnog_db.copyTo("${workDir}/tmp/eggnog.db") + input[2] = "${workDir}/tmp/" + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.annotations[0][1]).readLines()[3..6], + file(process.out.orthologs[0][1]).readLines()[5..18], + process.out.hits[0][1], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + + } + + test("sarscov2 - proteome - mmseqs") { + setup { + run("MMSEQS_CREATEDB") { + script "../../mmseqs/createdb/main.nf" + process { + """ + input[0] = [ [id:'mmseqs_db'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + """ + } + } + } + + when { + process { + """ + input[0] = [ [id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + input[1] = MMSEQS_CREATEDB.out.db.map { _meta, db -> [ 'mmseqs', db ] } + eggnog_db = file(params.modules_testdata_base_path + '/delete_me/eggnogmapper/eggnog.db', checkIfExists: true) + eggnog_db.copyTo("${workDir}/tmp/eggnog.db") + input[2] = "${workDir}/tmp/" + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.annotations[0][1]).readLines()[3..6], + file(process.out.orthologs[0][1]).readLines().size(), + file(process.out.hits[0][1]).readLines().size(), + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + + } + + test("sarscov2 - proteome - no_search") { + setup { + run("DIAMOND_MAKEDB") { + script "../../diamond/makedb/main.nf" + process { + """ + input[0] = [ [id:'dmnd_db'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + run("EGGNOGMAPPER", alias: "EGGNOGMAPPER_SETUP") { + script "../main.nf" + process { + """ + input[0] = [ [id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + input[1] = DIAMOND_MAKEDB.out.db.map { _meta, db -> [ 'diamond', db ] } + eggnog_db = file(params.modules_testdata_base_path + '/delete_me/eggnogmapper/eggnog.db', checkIfExists: true) + eggnog_db.copyTo("${workDir}/tmp/eggnog.db") + input[2] = "${workDir}/tmp/" + """ + } + } + } + + when { + process { + """ + input[0] = [ [id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + input[1] = EGGNOGMAPPER_SETUP.out.orthologs.map { _meta, orthologs -> [ 'no_search', orthologs ] } + eggnog_db = file(params.modules_testdata_base_path + '/delete_me/eggnogmapper/eggnog.db', checkIfExists: true) + eggnog_db.copyTo("${workDir}/tmp/eggnog.db") + input[2] = "${workDir}/tmp/" + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot( + file(process.out.annotations[0][1]).readLines()[3..6], + process.out.findAll { key, val -> key.startsWith("versions")} + ).match() } + ) + } + + } + + test("sarscov2 - proteome - diamond - stub") { + options '-stub' + setup { + run("DIAMOND_MAKEDB") { + script "../../diamond/makedb/main.nf" + process { + """ + input[0] = [ [id:'dmnd_db'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + input[1] = [] + input[2] = [] + input[3] = [] + """ + } + } + } + + when { + process { + """ + input[0] = [ [id:'test'], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/proteome.fasta', checkIfExists: true) ] + input[1] = DIAMOND_MAKEDB.out.db.map { _meta, db -> [ 'diamond', db ] } + eggnog_db = file(params.modules_testdata_base_path + '/delete_me/eggnogmapper/eggnog.db', checkIfExists: true) + eggnog_db.copyTo("${workDir}/tmp/eggnog.db") + input[2] = "${workDir}/tmp/" + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + + } + +} diff --git a/modules/nf-core/eggnogmapper/tests/main.nf.test.snap b/modules/nf-core/eggnogmapper/tests/main.nf.test.snap new file mode 100644 index 0000000..f522e35 --- /dev/null +++ b/modules/nf-core/eggnogmapper/tests/main.nf.test.snap @@ -0,0 +1,135 @@ +{ + "sarscov2 - proteome - diamond": { + "content": [ + [ + "##", + "#query\tseed_ortholog\tevalue\tscore\teggNOG_OGs\tmax_annot_lvl\tCOG_category\tDescription\tPreferred_name\tGOs\tEC\tKEGG_ko\tKEGG_Pathway\tKEGG_Module\tKEGG_Reaction\tKEGG_rclass\tBRITE\tKEGG_TC\tCAZy\tBiGG_Reaction\tPFAMs", + "ENSSASP00005000002.1\tENSSASP00005000002.1\t0.0\t14179.0\tCOG0498@1|root,COG0498@2|Bacteria,1MUWQ@1224|Proteobacteria,2VHR6@28216|Betaproteobacteria,2KUMA@206389|Rhodocyclales\t1224|Proteobacteria\tE\tthreonine synthase\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-", + "## 12 queries scanned" + ], + [ + "#qseqid\tsseqid\tevalue\tbitscore\tqstart\tqend\tsstart\tsend\tpident\tqcov\tscov", + "ENSSASP00005000002.1\tENSSASP00005000002.1\t0.0\t14179.0\t1\t7096\t1\t7096\t100.0\t100.0\t100.0", + "ENSSASP00005000003.1\tENSSASP00005000003.1\t0.0\t8659.0\t1\t4405\t1\t4405\t100.0\t100.0\t100.0", + "ENSSASP00005000004.1\tENSSASP00005000004.1\t0.0\t2469.0\t1\t1273\t1\t1273\t100.0\t100.0\t100.0", + "ENSSASP00005000005.1\tENSSASP00005000005.1\t2.54e-286\t769.0\t1\t419\t1\t419\t100.0\t100.0\t100.0", + "ENSSASP00005000006.1\tENSSASP00005000006.1\t4.58e-205\t551.0\t1\t275\t1\t275\t100.0\t100.0\t100.0", + "ENSSASP00005000007.1\tENSSASP00005000007.1\t4.9e-160\t433.0\t1\t222\t1\t222\t100.0\t100.0\t100.0", + "ENSSASP00005000008.1\tENSSASP00005000008.1\t5.64e-94\t258.0\t1\t121\t1\t121\t100.0\t100.0\t100.0", + "ENSSASP00005000009.1\tENSSASP00005000009.1\t1.44e-87\t242.0\t1\t121\t1\t121\t100.0\t100.0\t100.0", + "ENSSASP00005000010.1\tENSSASP00005000010.1\t1.14e-47\t137.0\t1\t75\t1\t75\t100.0\t100.0\t100.0", + "ENSSASP00005000011.1\tENSSASP00005000011.1\t3.07e-39\t115.0\t1\t61\t1\t61\t100.0\t100.0\t100.0", + "ENSSASP00005000012.1\tENSSASP00005000012.1\t6.59e-20\t65.5\t1\t43\t1\t43\t100.0\t100.0\t100.0", + "ENSSASP00005000013.1\tENSSASP00005000013.1\t1.07e-25\t79.7\t1\t38\t1\t38\t100.0\t100.0\t100.0", + "## 12 queries scanned" + ], + "test.emapper.hits:md5,9ab2e1810b911f2e6c63f8c0f998ee83", + { + "versions_eggnogmapper": [ + [ + "EGGNOGMAPPER", + "eggnog-mapper", + "2.1.13" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-02-26T14:41:08.245249413" + }, + "sarscov2 - proteome - diamond - stub": { + "content": [ + { + "annotations": [ + [ + { + "id": "test" + }, + "test.emapper.annotations:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "hits": [ + [ + { + "id": "test" + }, + "test.emapper.hits:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "orthologs": [ + [ + { + "id": "test" + }, + "test.emapper.seed_orthologs:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_eggnogmapper": [ + [ + "EGGNOGMAPPER", + "eggnog-mapper", + "2.1.13" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.4" + }, + "timestamp": "2026-02-26T13:49:53.898972887" + }, + "sarscov2 - proteome - mmseqs": { + "content": [ + [ + "##", + "#query\tseed_ortholog\tevalue\tscore\teggNOG_OGs\tmax_annot_lvl\tCOG_category\tDescription\tPreferred_name\tGOs\tEC\tKEGG_ko\tKEGG_Pathway\tKEGG_Module\tKEGG_Reaction\tKEGG_rclass\tBRITE\tKEGG_TC\tCAZy\tBiGG_Reaction\tPFAMs", + "ENSSASP00005000002.1\tENSSASP00005000002.1\t0.0\t12938.0\tCOG0498@1|root,COG0498@2|Bacteria,1MUWQ@1224|Proteobacteria,2VHR6@28216|Betaproteobacteria,2KUMA@206389|Rhodocyclales\t1224|Proteobacteria\tE\tthreonine synthase\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-", + "## 12 queries scanned" + ], + 24, + 12, + { + "versions_eggnogmapper": [ + [ + "EGGNOGMAPPER", + "eggnog-mapper", + "2.1.13" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-02-27T09:49:08.050484472" + }, + "sarscov2 - proteome - no_search": { + "content": [ + [ + "##", + "#query\tseed_ortholog\tevalue\tscore\teggNOG_OGs\tmax_annot_lvl\tCOG_category\tDescription\tPreferred_name\tGOs\tEC\tKEGG_ko\tKEGG_Pathway\tKEGG_Module\tKEGG_Reaction\tKEGG_rclass\tBRITE\tKEGG_TC\tCAZy\tBiGG_Reaction\tPFAMs", + "ENSSASP00005000002.1\tENSSASP00005000002.1\t0.0\t14179.0\tCOG0498@1|root,COG0498@2|Bacteria,1MUWQ@1224|Proteobacteria,2VHR6@28216|Betaproteobacteria,2KUMA@206389|Rhodocyclales\t1224|Proteobacteria\tE\tthreonine synthase\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-\t-", + "## 12 queries scanned" + ], + { + "versions_eggnogmapper": [ + [ + "EGGNOGMAPPER", + "eggnog-mapper", + "2.1.13" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-02-27T10:49:12.14219149" + } +} \ No newline at end of file diff --git a/modules/nf-core/fastqc/main.nf b/modules/nf-core/fastqc/main.nf deleted file mode 100644 index 23e1663..0000000 --- a/modules/nf-core/fastqc/main.nf +++ /dev/null @@ -1,64 +0,0 @@ -process FASTQC { - tag "${meta.id}" - label 'process_medium' - - conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/fastqc:0.12.1--hdfd78af_0' : - 'biocontainers/fastqc:0.12.1--hdfd78af_0' }" - - input: - tuple val(meta), path(reads) - - output: - tuple val(meta), path("*.html"), emit: html - tuple val(meta), path("*.zip") , emit: zip - path "versions.yml" , emit: versions - - when: - task.ext.when == null || task.ext.when - - script: - def args = task.ext.args ?: '' - def prefix = task.ext.prefix ?: "${meta.id}" - // Make list of old name and new name pairs to use for renaming in the bash while loop - def old_new_pairs = reads instanceof Path || reads.size() == 1 ? [[ reads, "${prefix}.${reads.extension}" ]] : reads.withIndex().collect { entry, index -> [ entry, "${prefix}_${index + 1}.${entry.extension}" ] } - def rename_to = old_new_pairs*.join(' ').join(' ') - def renamed_files = old_new_pairs.collect{ _old_name, new_name -> new_name }.join(' ') - - // The total amount of allocated RAM by FastQC is equal to the number of threads defined (--threads) time the amount of RAM defined (--memory) - // https://github.com/s-andrews/FastQC/blob/1faeea0412093224d7f6a07f777fad60a5650795/fastqc#L211-L222 - // Dividing the task.memory by task.cpu allows to stick to requested amount of RAM in the label - def memory_in_mb = task.memory ? task.memory.toUnit('MB') / task.cpus : null - // FastQC memory value allowed range (100 - 10000) - def fastqc_memory = memory_in_mb > 10000 ? 10000 : (memory_in_mb < 100 ? 100 : memory_in_mb) - - """ - printf "%s %s\\n" ${rename_to} | while read old_name new_name; do - [ -f "\${new_name}" ] || ln -s \$old_name \$new_name - done - - fastqc \\ - ${args} \\ - --threads ${task.cpus} \\ - --memory ${fastqc_memory} \\ - ${renamed_files} - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) - END_VERSIONS - """ - - stub: - def prefix = task.ext.prefix ?: "${meta.id}" - """ - touch ${prefix}.html - touch ${prefix}.zip - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - fastqc: \$( fastqc --version | sed '/FastQC v/!d; s/.*v//' ) - END_VERSIONS - """ -} diff --git a/modules/nf-core/fastqc/meta.yml b/modules/nf-core/fastqc/meta.yml deleted file mode 100644 index c8d9d02..0000000 --- a/modules/nf-core/fastqc/meta.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: fastqc -description: Run FastQC on sequenced reads -keywords: - - quality control - - qc - - adapters - - fastq -tools: - - fastqc: - description: | - FastQC gives general quality metrics about your reads. - It provides information about the quality score distribution - across your reads, the per base sequence content (%A/C/G/T). - - You get information about adapter contamination and other - overrepresented sequences. - homepage: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/ - documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/ - licence: ["GPL-2.0-only"] - identifier: biotools:fastqc -input: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - reads: - type: file - description: | - List of input FastQ files of size 1 and 2 for single-end and paired-end data, - respectively. - ontologies: [] -output: - html: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.html": - type: file - description: FastQC report - pattern: "*_{fastqc.html}" - ontologies: [] - zip: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] - - "*.zip": - type: file - description: FastQC report archive - pattern: "*_{fastqc.zip}" - ontologies: [] - versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML -authors: - - "@drpatelh" - - "@grst" - - "@ewels" - - "@FelixKrueger" -maintainers: - - "@drpatelh" - - "@grst" - - "@ewels" - - "@FelixKrueger" diff --git a/modules/nf-core/fastqc/tests/main.nf.test b/modules/nf-core/fastqc/tests/main.nf.test deleted file mode 100644 index e9d79a0..0000000 --- a/modules/nf-core/fastqc/tests/main.nf.test +++ /dev/null @@ -1,309 +0,0 @@ -nextflow_process { - - name "Test Process FASTQC" - script "../main.nf" - process "FASTQC" - - tag "modules" - tag "modules_nfcore" - tag "fastqc" - - test("sarscov2 single-end [fastq]") { - - when { - process { - """ - input[0] = Channel.of([ - [ id: 'test', single_end:true ], - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - // NOTE The report contains the date inside it, which means that the md5sum is stable per day, but not longer than that. So you can't md5sum it. - // looks like this:
Mon 2 Oct 2023
test.gz
- // https://github.com/nf-core/modules/pull/3903#issuecomment-1743620039 - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 paired-end [fastq]") { - - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 interleaved [fastq]") { - - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 paired-end [bam]") { - - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/test_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/test_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 multiple [fastq]") { - - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1][0] ==~ ".*/test_1_fastqc.html" }, - { assert process.out.html[0][1][1] ==~ ".*/test_2_fastqc.html" }, - { assert process.out.html[0][1][2] ==~ ".*/test_3_fastqc.html" }, - { assert process.out.html[0][1][3] ==~ ".*/test_4_fastqc.html" }, - { assert process.out.zip[0][1][0] ==~ ".*/test_1_fastqc.zip" }, - { assert process.out.zip[0][1][1] ==~ ".*/test_2_fastqc.zip" }, - { assert process.out.zip[0][1][2] ==~ ".*/test_3_fastqc.zip" }, - { assert process.out.zip[0][1][3] ==~ ".*/test_4_fastqc.zip" }, - { assert path(process.out.html[0][1][0]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][1]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][2]).text.contains("File typeConventional base calls") }, - { assert path(process.out.html[0][1][3]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 custom_prefix") { - - when { - process { - """ - input[0] = Channel.of([ - [ id:'mysample', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert process.out.html[0][1] ==~ ".*/mysample_fastqc.html" }, - { assert process.out.zip[0][1] ==~ ".*/mysample_fastqc.zip" }, - { assert path(process.out.html[0][1]).text.contains("File typeConventional base calls") }, - { assert snapshot(process.out.versions).match() } - ) - } - } - - test("sarscov2 single-end [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [ id: 'test', single_end:true ], - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 paired-end [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 interleaved [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_interleaved.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 paired-end [bam] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 multiple [fastq] - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [id: 'test', single_end: false], // meta map - [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_1.fastq.gz', checkIfExists: true), - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test2_2.fastq.gz', checkIfExists: true) ] - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("sarscov2 custom_prefix - stub") { - - options "-stub" - when { - process { - """ - input[0] = Channel.of([ - [ id:'mysample', single_end:true ], // meta map - file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) - ]) - """ - } - } - - then { - assertAll ( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } -} diff --git a/modules/nf-core/fastqc/tests/main.nf.test.snap b/modules/nf-core/fastqc/tests/main.nf.test.snap deleted file mode 100644 index d5db309..0000000 --- a/modules/nf-core/fastqc/tests/main.nf.test.snap +++ /dev/null @@ -1,392 +0,0 @@ -{ - "sarscov2 custom_prefix": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:16.374038" - }, - "sarscov2 single-end [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": true - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": true - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": true - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": true - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:24.993809" - }, - "sarscov2 custom_prefix - stub": { - "content": [ - { - "0": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "mysample", - "single_end": true - }, - "mysample.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:03:10.93942" - }, - "sarscov2 interleaved [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:42.355718" - }, - "sarscov2 paired-end [bam]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:53.276274" - }, - "sarscov2 multiple [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:05.527626" - }, - "sarscov2 paired-end [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:31.188871" - }, - "sarscov2 paired-end [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:34.273566" - }, - "sarscov2 multiple [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:03:02.304411" - }, - "sarscov2 single-end [fastq]": { - "content": [ - [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:01:19.095607" - }, - "sarscov2 interleaved [fastq] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:44.640184" - }, - "sarscov2 paired-end [bam] - stub": { - "content": [ - { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "2": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "html": [ - [ - { - "id": "test", - "single_end": false - }, - "test.html:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,e1cc25ca8af856014824abd842e93978" - ], - "zip": [ - [ - { - "id": "test", - "single_end": false - }, - "test.zip:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.3" - }, - "timestamp": "2024-07-22T11:02:53.550742" - } -} \ No newline at end of file diff --git a/modules/nf-core/fmhfunprofiler/environment.yml b/modules/nf-core/fmhfunprofiler/environment.yml new file mode 100644 index 0000000..1a04b8b --- /dev/null +++ b/modules/nf-core/fmhfunprofiler/environment.yml @@ -0,0 +1,6 @@ +--- +channels: + - conda-forge + - bioconda +dependencies: + - "bioconda::fmh-funprofiler=1.1.1" diff --git a/modules/nf-core/fmhfunprofiler/main.nf b/modules/nf-core/fmhfunprofiler/main.nf new file mode 100644 index 0000000..ce698ac --- /dev/null +++ b/modules/nf-core/fmhfunprofiler/main.nf @@ -0,0 +1,41 @@ +process FMHFUNPROFILER { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/fmh-funprofiler:1.1.1--pyh106432d_0': + 'quay.io/biocontainers/fmh-funprofiler:1.1.1--pyh106432d_0' }" + + input: + tuple val(meta), path(reads) + path(ko_sketch) + val(ksize) + val(scaled) + + output: + tuple val(meta), path("*.csv"), emit: csv + tuple val("${task.process}"), val('fmh-funprofiler'), eval('python -c "import importlib.metadata; print(importlib.metadata.version(\'fmh-funprofiler\'))"'), topic: versions, emit: versions_fmhfunprofiler + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + funcprofiler \\ + $args \\ + $reads \\ + $ko_sketch \\ + $ksize \\ + $scaled \\ + ${prefix}.csv + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.csv + """ +} diff --git a/modules/nf-core/fmhfunprofiler/meta.yml b/modules/nf-core/fmhfunprofiler/meta.yml new file mode 100644 index 0000000..5de4107 --- /dev/null +++ b/modules/nf-core/fmhfunprofiler/meta.yml @@ -0,0 +1,85 @@ +name: "fmhfunprofiler" +description: Functionally profile metagenomic samples using FracMinHash sketches + against KEGG database references. +keywords: + - metagenomics + - functional profiling + - FracMinHash + - sourmash + - kegg +tools: + - "fmhfunprofiler": + description: "fmh-funprofiler is a pipeline that leverages FracMinHash (implemented + in sourmash) to functionally profile metagenomic samples, offering a faster + and more memory-efficient alternative to alignment-based methods." + homepage: "https://github.com/KoslickiLab/fmh-funprofiler" + documentation: "https://github.com/KoslickiLab/fmh-funprofiler" + tool_dev_url: "https://github.com/KoslickiLab/fmh-funprofiler" + doi: "10.1093/bioinformatics/btae397" + licence: + - "MIT" + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1', single_end:false ]` + - reads: + type: file + description: Input metagenomic sequences in FASTA or FASTQ format (can be + compressed) + pattern: "*.{fasta,fastq,fa,fq,fasta.gz,fastq.gz,fa.gz,fq.gz}" + ontologies: + - edam: http://edamontology.org/format_1930 + - ko_sketch: + type: file + description: Sourmash signature reference sketch or Sequence Bloom Tree + (SBT) of KEGG KOs + pattern: "*.{sig,sig.zip,sbt.zip}" + ontologies: [] + - ksize: + type: integer + description: The k-mer size to use for the sketch (typically 7, 11, or 15) + - scaled: + type: integer + description: The FracMinHash scale factor (e.g., 1000) +output: + csv: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1', single_end:false ]` + - "*.csv": + type: file + description: The main functional abundance profile matrix detailing KEGG + Orthology (KO) counts + pattern: "*.csv" + ontologies: + - edam: http://edamontology.org/format_3752 + versions_fmhfunprofiler: + - - ${task.process}: + type: string + description: The name of the process + - fmh-funprofiler: + type: string + description: The name of the tool + - 'python -c "import importlib.metadata; print(importlib.metadata.version(''fmh-funprofiler''))"': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - fmh-funprofiler: + type: string + description: The name of the tool + - 'python -c "import importlib.metadata; print(importlib.metadata.version(''fmh-funprofiler''))"': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@miraep8" +maintainers: + - "@miraep8" diff --git a/modules/nf-core/fmhfunprofiler/tests/main.nf.test b/modules/nf-core/fmhfunprofiler/tests/main.nf.test new file mode 100644 index 0000000..1f23e80 --- /dev/null +++ b/modules/nf-core/fmhfunprofiler/tests/main.nf.test @@ -0,0 +1,73 @@ +nextflow_process { + + name "Test Process FMHFUNPROFILER" + script "../main.nf" + process "FMHFUNPROFILER" + + tag "modules" + tag "modules_nfcore" + tag "fmhfunprofiler" + tag "sourmash" + tag "sourmash/sketch" + + setup { + run("SOURMASH_SKETCH") { + script "../../sourmash/sketch/main.nf" + process { + """ + input[0] = [ + [ id:'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/genome.fasta', checkIfExists: true) + ] + """ + } + } + } + + test("sarscov2 - fastq - single_end") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + input[1] = SOURMASH_SKETCH.out.signatures.map { meta, sig -> sig } + input[2] = 11 + input[3] = 1000 + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + test("sarscov2 - fastq - single_end - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [ id:'test', single_end:true ], [] ] + input[1] = [] + input[2] = 11 + input[3] = 1000 + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } +} diff --git a/modules/nf-core/fmhfunprofiler/tests/main.nf.test.snap b/modules/nf-core/fmhfunprofiler/tests/main.nf.test.snap new file mode 100644 index 0000000..18c4c53 --- /dev/null +++ b/modules/nf-core/fmhfunprofiler/tests/main.nf.test.snap @@ -0,0 +1,56 @@ +{ + "sarscov2 - fastq - single_end - stub": { + "content": [ + { + "csv": [ + [ + { + "id": "test", + "single_end": true + }, + "test.csv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_fmhfunprofiler": [ + [ + "FMHFUNPROFILER", + "fmh-funprofiler", + "1.1.1" + ] + ] + } + ], + "timestamp": "2026-07-09T10:52:24.354831448", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.4" + } + }, + "sarscov2 - fastq - single_end": { + "content": [ + { + "csv": [ + [ + { + "id": "test", + "single_end": true + }, + "test.csv:md5,16b7196a90c1d2fd3e3109c8d252cd08" + ] + ], + "versions_fmhfunprofiler": [ + [ + "FMHFUNPROFILER", + "fmh-funprofiler", + "1.1.1" + ] + ] + } + ], + "timestamp": "2026-07-09T10:52:11.971686709", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.4" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/gunzip/environment.yml b/modules/nf-core/gunzip/environment.yml new file mode 100644 index 0000000..9b926b1 --- /dev/null +++ b/modules/nf-core/gunzip/environment.yml @@ -0,0 +1,12 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - conda-forge::coreutils=9.5 + - conda-forge::grep=3.11 + - conda-forge::gzip=1.13 + - conda-forge::lbzip2=2.5 + - conda-forge::sed=4.8 + - conda-forge::tar=1.34 diff --git a/modules/nf-core/gunzip/main.nf b/modules/nf-core/gunzip/main.nf new file mode 100644 index 0000000..6edffc5 --- /dev/null +++ b/modules/nf-core/gunzip/main.nf @@ -0,0 +1,47 @@ +process GUNZIP { + tag "${archive}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/52ccce28d2ab928ab862e25aae26314d69c8e38bd41ca9431c67ef05221348aa/data' + : 'community.wave.seqera.io/library/coreutils_grep_gzip_lbzip2_pruned:838ba80435a629f8'}" + + input: + tuple val(meta), path(archive) + + output: + tuple val(meta), path("${gunzip}"), emit: gunzip + tuple val("${task.process}"), val('gunzip'), eval('gunzip --version 2>&1 | head -1 | sed "s/^.*(gzip) //; s/ Copyright.*//"'), topic: versions, emit: versions_gunzip + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def nameWithoutGz = archive.extension == 'gz' ? archive.baseName : archive.name + def extension = file(nameWithoutGz).extension + def name = file(nameWithoutGz).baseName + def prefix = task.ext.prefix ?: name + gunzip = prefix + ".${extension}" + """ + # Not calling gunzip itself because it creates files + # with the original group ownership rather than the + # default one for that user / the work directory + gzip \\ + -cd \\ + ${args} \\ + ${archive} \\ + > ${gunzip} + """ + + stub: + def nameWithoutGz = archive.extension == 'gz' ? archive.baseName : archive.name + def extension = file(nameWithoutGz).extension + def name = file(nameWithoutGz).baseName + def prefix = task.ext.prefix ?: name + gunzip = prefix + ".${extension}" + """ + touch ${gunzip} + """ +} diff --git a/modules/nf-core/gunzip/meta.yml b/modules/nf-core/gunzip/meta.yml new file mode 100644 index 0000000..bba6b3b --- /dev/null +++ b/modules/nf-core/gunzip/meta.yml @@ -0,0 +1,68 @@ +name: gunzip +description: Compresses and decompresses files. +keywords: + - gunzip + - compression + - decompression +tools: + - gunzip: + description: | + gzip is a file format and a software application used for file compression and decompression. + documentation: https://www.gnu.org/software/gzip/manual/gzip.html + licence: ["GPL-3.0-or-later"] + identifier: "" +input: + - - meta: + type: map + description: | + Optional groovy Map containing meta information + e.g. [ id:'test', single_end:false ] + - archive: + type: file + description: File to be compressed/uncompressed + pattern: "*.*" + ontologies: [] +output: + gunzip: + - - meta: + type: file + description: Compressed/uncompressed file + pattern: "*.*" + ontologies: [] + - ${gunzip}: + type: file + description: Compressed/uncompressed file + pattern: "*.*" + ontologies: [] + versions_gunzip: + - - ${task.process}: + type: string + description: The process the versions were collected from + - gunzip: + type: string + description: The tool name + - gunzip --version 2>&1 | head -1 | sed "s/^.*(gzip) //; s/ Copyright.*//": + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - gunzip: + type: string + description: The tool name + - gunzip --version 2>&1 | head -1 | sed "s/^.*(gzip) //; s/ Copyright.*//": + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@joseespinosa" + - "@drpatelh" + - "@jfy133" +maintainers: + - "@joseespinosa" + - "@drpatelh" + - "@jfy133" + - "@gallvp" diff --git a/modules/nf-core/gunzip/tests/main.nf.test b/modules/nf-core/gunzip/tests/main.nf.test new file mode 100644 index 0000000..33cb75a --- /dev/null +++ b/modules/nf-core/gunzip/tests/main.nf.test @@ -0,0 +1,175 @@ +nextflow_process { + + name "Test Process GUNZIP" + script "../main.nf" + process "GUNZIP" + tag "gunzip" + tag "modules_nfcore" + tag "modules" + + test("Should run without failures") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("Should run without failures - prefix") { + + config './nextflow.config' + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id: 'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("Should run without failures - stub") { + + options '-stub' + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("Should decompress file with extension appearing multiple times in filename") { + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true).copyTo('test.fa.v1.fa.gz') + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert file(process.out.gunzip[0][1]).name == 'test.fa.v1.fa' } + ) + } + + } + + test("Should decompress file with extension appearing multiple times in filename - prefix") { + + config './nextflow.config' + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id: 'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true).copyTo('test.fa.v1.fa.gz') + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("Should run without failures - prefix - stub") { + + options '-stub' + config './nextflow.config' + + when { + params { + outdir = "$outputDir" + } + process { + """ + input[0] = Channel.of([ + [ id: 'test' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + ) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/gunzip/tests/main.nf.test.snap b/modules/nf-core/gunzip/tests/main.nf.test.snap new file mode 100644 index 0000000..980e95a --- /dev/null +++ b/modules/nf-core/gunzip/tests/main.nf.test.snap @@ -0,0 +1,207 @@ +{ + "Should decompress file with extension appearing multiple times in filename - prefix": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.xyz.fa:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + { + "id": "test" + }, + "test.xyz.fa:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-04-15T15:20:52.59447", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "Should run without failures - prefix - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.xyz.fastq:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + { + "id": "test" + }, + "test.xyz.fastq:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-01-19T17:21:56.633550769", + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + } + }, + "Should run without failures - stub": { + "content": [ + { + "0": [ + [ + [ + + ], + "test_1.fastq:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + [ + + ], + "test_1.fastq:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-01-19T17:21:51.435621199", + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + } + }, + "Should run without failures": { + "content": [ + { + "0": [ + [ + [ + + ], + "test_1.fastq:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + [ + + ], + "test_1.fastq:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-01-19T17:21:40.613975821", + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + } + }, + "Should run without failures - prefix": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test.xyz.fastq:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "1": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ], + "gunzip": [ + [ + { + "id": "test" + }, + "test.xyz.fastq:md5,4161df271f9bfcd25d5845a1e220dbec" + ] + ], + "versions_gunzip": [ + [ + "GUNZIP", + "gunzip", + "1.13" + ] + ] + } + ], + "timestamp": "2026-01-19T17:21:46.086880414", + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/gunzip/tests/nextflow.config b/modules/nf-core/gunzip/tests/nextflow.config new file mode 100644 index 0000000..dec7764 --- /dev/null +++ b/modules/nf-core/gunzip/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: GUNZIP { + ext.prefix = { "${meta.id}.xyz" } + } +} diff --git a/modules/nf-core/humann3/humann/environment.yml b/modules/nf-core/humann3/humann/environment.yml new file mode 100644 index 0000000..3dc3f34 --- /dev/null +++ b/modules/nf-core/humann3/humann/environment.yml @@ -0,0 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::humann=3.6.1 + - bioconda::metaphlan=4.0.6 + - conda-forge::python=3.10.8 diff --git a/modules/nf-core/humann3/humann/main.nf b/modules/nf-core/humann3/humann/main.nf new file mode 100644 index 0000000..6063488 --- /dev/null +++ b/modules/nf-core/humann3/humann/main.nf @@ -0,0 +1,63 @@ + +process HUMANN3_HUMANN { + tag "$meta.id" + label 'process_high' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/humann:3.6.1--pyh7cba7a3_0' : + 'quay.io/biocontainers/humann:3.6.1--pyh7cba7a3_0' }" + + input: + tuple val(meta), path(input) + tuple val(meta2), path(profile) + path nucleotide_db + path protein_db + path utility_db + + output: + tuple val(meta), path("*_genefamilies.tsv.gz") , emit: genefamilies + tuple val(meta), path("*_pathabundance.tsv.gz"), emit: pathabundance + tuple val(meta), path("*_pathcoverage.tsv.gz") , emit: pathcoverage, optional: true + tuple val(meta), path("*_reactions.tsv.gz") , emit: reactions, optional: true + tuple val(meta), path("*.log") , emit: log + tuple val("${task.process}"), val('HUMAnN'), eval("humann --version 2>&1 | sed 's/humann v//'"), emit: versions_humann, topic: versions + tuple val("${task.process}"), val('MetaPhlAn'), eval("metaphlan --version 2>&1 | sed 's/MetaPhlAn version //'"), emit: versions_metaphlan, topic: versions + tuple val("${task.process}"), val('Python'), eval("python --version 2>&1 | sed 's/Python //'"), emit: versions_python, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def pangenome_string = "--taxonomic-profile ${profile}" + """ + PROTS_DB=`find -L "${protein_db}" -name "*.dmnd" -exec dirname {} \\;` + nuclist=`find -L "${nucleotide_db}" -name "*.ffn.gz" -print -quit ` + NUCS_DB=\$(dirname \$nuclist) + + humann \\ + $args \\ + --threads ${task.cpus} \\ + --input $input \\ + --protein-database \${PROTS_DB} \\ + --nucleotide-database \${NUCS_DB} \\ + --output-basename $prefix \\ + $pangenome_string \\ + --o-log ${prefix}.log \\ + --output . + + gzip -n *.tsv + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "" | gzip > ${prefix}_genefamilies.tsv.gz + echo "" | gzip > ${prefix}_pathabundance.tsv.gz + echo "" | gzip > ${prefix}_pathcoverage.tsv.gz + echo "" | gzip > ${prefix}_reactions.tsv.gz + touch ${prefix}.log + """ +} diff --git a/modules/nf-core/humann3/humann/meta.yml b/modules/nf-core/humann3/humann/meta.yml new file mode 100644 index 0000000..a7025fb --- /dev/null +++ b/modules/nf-core/humann3/humann/meta.yml @@ -0,0 +1,179 @@ +name: humann3_humann +description: Functional analysis of metagenome or metatranscriptome data +keywords: + - function + - metagenomics + - metatranscriptomics + - profiling + - community +tools: + - humann: + description: "HUMAnN: The HMP Unified Metabolic Analysis Network" + homepage: http://huttenhower.sph.harvard.edu/humann + documentation: https://github.com/biobakery/biobakery/wiki/humann3 + tool_dev_url: https://github.com/biobakery/humann + doi: "10.7554/eLife.65088" + licence: + - "MIT" + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - input: + type: file + description: | + A metagenome (DNA reads) or metatranscriptome (RNA reads) [fastq,fastq.gz,fasta,fasta.gz] + OR pre-computed mappings [sam,bam,blastm8] + OR pre-computed abundance tables [tsv,biom] + pattern: "*.{fastq,fastq.gz,fasta,fasta.gz,sam,bam,blastm8,tsv,biom}" + ontologies: + - edam: http://edamontology.org/format_1930 + - edam: http://edamontology.org/format_3475 + - edam: http://edamontology.org/format_3746 + - - meta2: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - profile: + type: file + description: Pre-computed MetaPhlAn taxonomic profile + pattern: "*.{txt}" + ontologies: [] + - nucleotide_db: + type: directory + description: | + ChocoPhlAn nucleotide database directory (v3: *.ffn.gz, v4: *.fna.gz) + - protein_db: + type: directory + description: | + UniRef protein database directory containing *.dmnd files + - utility_db: + type: directory + description: | + HUMAnN utility mapping database directory +output: + genefamilies: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*_genefamilies.tsv.gz": + type: file + description: Compressed gene families abundance table + pattern: "*.{tsv.gz}" + ontologies: [] + pathabundance: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*_pathabundance.tsv.gz": + type: file + description: Compressed pathway abundance table + pattern: "*.{tsv.gz}" + ontologies: [] + pathcoverage: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*_pathcoverage.tsv.gz": + type: file + description: Compressed pathway coverage table + pattern: "*.{tsv.gz}" + ontologies: [] + reactions: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*_reactions.tsv.gz": + type: file + description: Compressed reactions abundance table + pattern: "*.{tsv.gz}" + ontologies: [] + log: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*.log": + type: file + description: HUMAnN run log file + pattern: "*.{log}" + ontologies: [] + versions_humann: + - - ${task.process}: + type: string + description: The name of the process + - HUMAnN: + type: string + description: The name of the tool + - humann --version 2>&1 | sed 's/humann v//': + type: eval + description: The expression to obtain the version of the tool + versions_metaphlan: + - - ${task.process}: + type: string + description: The name of the process + - MetaPhlAn: + type: string + description: The name of the tool + - metaphlan --version 2>&1 | sed 's/MetaPhlAn version //': + type: eval + description: The expression to obtain the version of the tool + versions_python: + - - ${task.process}: + type: string + description: The name of the process + - Python: + type: string + description: The name of the tool + - python --version 2>&1 | sed 's/Python //': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - HUMAnN: + type: string + description: The name of the tool + - humann --version 2>&1 | sed 's/humann v//': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - MetaPhlAn: + type: string + description: The name of the tool + - metaphlan --version 2>&1 | sed 's/MetaPhlAn version //': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - Python: + type: string + description: The name of the tool + - python --version 2>&1 | sed 's/Python //': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@nickp60" + - "@d4straub" + - "@vinisalazar" +maintainers: + - "@nickp60" + - "@vinisalazar" diff --git a/modules/nf-core/humann3/humann/tests/main.nf.test b/modules/nf-core/humann3/humann/tests/main.nf.test new file mode 100644 index 0000000..280dc2a --- /dev/null +++ b/modules/nf-core/humann3/humann/tests/main.nf.test @@ -0,0 +1,124 @@ +nextflow_process { + + name "Test Process HUMANN3_HUMANN" + script "../main.nf" + process "HUMANN3_HUMANN" + config "./nextflow.config" + tag "modules" + tag "modules_nfcore" + tag "humann3" + tag "humann3/humann" + tag "metaphlan/metaphlan" + tag "untar" + setup{ + run("UNTAR") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.modules_testdata_base_path + 'delete_me/metaphlan4_database.tar.gz', checkIfExists: true ) + ]) + """ + } + } + run("UNTAR", alias: "UNTAR_v3_nuc") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.pipelines_testdata_base_path + 'data/database/humann/v3/chocophlan_nfDEMO.tar.gz', checkIfExists: true ) + ]) + """ + } + } + run("UNTAR", alias: "UNTAR_v3_prot") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.pipelines_testdata_base_path + 'data/database/humann/v3/uniref_nfDEMO.tar.gz', checkIfExists: true ) + ]) + """ + } + } + run("UNTAR", alias: "UNTAR_v3_util") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.pipelines_testdata_base_path + 'data/database/humann/v3/utility_nfDEMO.tar.gz', checkIfExists: true ) + ]) + """ + } + } + run("METAPHLAN_METAPHLAN", alias: "MPAHUMANN3") { + script "../../../../nf-core/metaphlan/metaphlan/main.nf" + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz',checkIfExists: true ) + ]) + input[1] = UNTAR.out.untar.map{ it[1] } + input[2] = false + """ + } + } + } + test("humann3 sarscov2 - fastq") { + when { + process { + """ + input[0]= Channel.of([ + [ id:'test', single_end:false, run_accession:"abc" ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + ]) + input[1] = MPAHUMANN3.out.profile + input[2] = UNTAR_v3_nuc.out.untar.map{ it[1] } + input[3] = UNTAR_v3_prot.out.untar.map{ it[1] } + input[4] = UNTAR_v3_util.out.untar.map{ it[1] } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.pathabundance, process.out.pathcoverage, process.out.reactions, process.out.findAll { key, val -> key.startsWith('versions') }).match() } + ) + } + + } + + test("humann3 sarscov2 - fastq - stub") { + + options "-stub" + + when { + process { + """ + input[0]= Channel.of([ + [ id:'test', single_end:false, run_accession:"abc" ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true), + ]) + input[1] = MPAHUMANN3.out.profile + input[2] = UNTAR_v3_nuc.out.untar.map{ it[1] } + input[3] = UNTAR_v3_prot.out.untar.map{ it[1] } + input[4] = UNTAR_v3_util.out.untar.map{ it[1] } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.pathabundance, process.out.pathcoverage, process.out.reactions, process.out.findAll { key, val -> key.startsWith('versions') }).match() } + ) + } + + } +} diff --git a/modules/nf-core/humann3/humann/tests/main.nf.test.snap b/modules/nf-core/humann3/humann/tests/main.nf.test.snap new file mode 100644 index 0000000..81ce7bf --- /dev/null +++ b/modules/nf-core/humann3/humann/tests/main.nf.test.snap @@ -0,0 +1,119 @@ +{ + "humann3 sarscov2 - fastq - stub": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false, + "run_accession": "abc" + }, + "test_pathabundance.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + [ + [ + { + "id": "test", + "single_end": false, + "run_accession": "abc" + }, + "test_pathcoverage.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + [ + [ + { + "id": "test", + "single_end": false, + "run_accession": "abc" + }, + "test_reactions.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + { + "versions_humann": [ + [ + "HUMANN3_HUMANN", + "HUMAnN", + "3.6.1" + ] + ], + "versions_metaphlan": [ + [ + "HUMANN3_HUMANN", + "MetaPhlAn", + "4.0.6 (1 Mar 2023)" + ] + ], + "versions_python": [ + [ + "HUMANN3_HUMANN", + "Python", + "3.10.8" + ] + ] + } + ], + "timestamp": "2026-05-19T18:08:28.27672", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "humann3 sarscov2 - fastq": { + "content": [ + [ + [ + { + "id": "test", + "single_end": false, + "run_accession": "abc" + }, + "test_pathabundance.tsv.gz:md5,65f73f474bdb2a7c8b278766ca789a3c" + ] + ], + [ + [ + { + "id": "test", + "single_end": false, + "run_accession": "abc" + }, + "test_pathcoverage.tsv.gz:md5,17c91a2581f34b55179aa4c79c242b1c" + ] + ], + [ + + ], + { + "versions_humann": [ + [ + "HUMANN3_HUMANN", + "HUMAnN", + "3.6.1" + ] + ], + "versions_metaphlan": [ + [ + "HUMANN3_HUMANN", + "MetaPhlAn", + "4.0.6 (1 Mar 2023)" + ] + ], + "versions_python": [ + [ + "HUMANN3_HUMANN", + "Python", + "3.10.8" + ] + ] + } + ], + "timestamp": "2026-05-19T18:08:05.120967", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/humann3/humann/tests/nextflow.config b/modules/nf-core/humann3/humann/tests/nextflow.config new file mode 100644 index 0000000..ff0dbb6 --- /dev/null +++ b/modules/nf-core/humann3/humann/tests/nextflow.config @@ -0,0 +1,3 @@ +params { + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/funcprofiler/' +} diff --git a/modules/nf-core/humann3/regroup/environment.yml b/modules/nf-core/humann3/regroup/environment.yml new file mode 100644 index 0000000..3dc3f34 --- /dev/null +++ b/modules/nf-core/humann3/regroup/environment.yml @@ -0,0 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::humann=3.6.1 + - bioconda::metaphlan=4.0.6 + - conda-forge::python=3.10.8 diff --git a/modules/nf-core/humann3/regroup/main.nf b/modules/nf-core/humann3/regroup/main.nf new file mode 100644 index 0000000..24e8116 --- /dev/null +++ b/modules/nf-core/humann3/regroup/main.nf @@ -0,0 +1,58 @@ +process HUMANN3_REGROUP { + tag "$meta.id" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/humann:3.6.1--pyh7cba7a3_0' : + 'quay.io/biocontainers/humann:3.6.1--pyh7cba7a3_0' }" + + input: + tuple val(meta), path(input) + val groups + path utility_db + + output: + tuple val(meta), path("*_regroup.tsv.gz"), emit: regroup + tuple val("${task.process}"), val('HUMAnN'), eval("humann --version 2>&1 | sed 's/humann v//'"), emit: versions_humann, topic: versions + tuple val("${task.process}"), val('MetaPhlAn'), eval("metaphlan --version 2>&1 | sed 's/MetaPhlAn version //'"), emit: versions_metaphlan, topic: versions + tuple val("${task.process}"), val('Python'), eval("python --version 2>&1 | sed 's/Python //'"), emit: versions_python, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + if [[ $input == *.gz ]]; then + gunzip -c $input > input.tsv + else + cp $input input.tsv + fi + + printf '%s\n' \\ + 'import os, sys' \\ + 'import humann.config as config' \\ + 'config.utility_mapping_database = os.environ["HUMANN_UTILITY_DB"]' \\ + 'from humann.tools.regroup_table import main' \\ + 'sys.exit(main())' \\ + > run_regroup.py + + export HUMANN_UTILITY_DB="${utility_db}" + + python run_regroup.py \\ + --input input.tsv \\ + --output ${prefix}_regroup.tsv \\ + --groups ${groups} \\ + ${args} + + gzip -n ${prefix}_regroup.tsv + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "" | gzip > ${prefix}_regroup.tsv.gz + """ +} diff --git a/modules/nf-core/humann3/regroup/meta.yml b/modules/nf-core/humann3/regroup/meta.yml new file mode 100644 index 0000000..417a34c --- /dev/null +++ b/modules/nf-core/humann3/regroup/meta.yml @@ -0,0 +1,116 @@ +name: humann3_regroup +description: Regrouping genes to other functional categories +keywords: + - function + - metagenomics + - metatranscriptomics + - profiling + - community +tools: + - humann: + description: "HUMAnN: The HMP Unified Metabolic Analysis Network, version 3" + homepage: http://huttenhower.sph.harvard.edu/humann + documentation: https://github.com/biobakery/biobakery/wiki/humann3 + tool_dev_url: https://github.com/biobakery/humann + doi: "10.7554/eLife.65088" + licence: + - "MIT" + identifier: "" + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - input: + type: file + description: Tab separated abundance file of HUMAnN3 + pattern: "*.{tsv.gz,tsv}" + - groups: + type: string + description: Regroup abundance values to a functional category (e.g. uniref90_rxn, uniref50_rxn) + pattern: "{uniref90_rxn,uniref50_rxn}" + - utility_db: + type: directory + description: HUMAnN utility mapping database directory + +output: + regroup: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*_regroup.tsv.gz": + type: file + description: Re-grouped compressed tab separated text file + pattern: "*.{tsv.gz}" + versions_humann: + - - ${task.process}: + type: string + description: The name of the process + - HUMAnN: + type: string + description: The name of the tool + - humann --version 2>&1 | sed 's/humann v//': + type: eval + description: The expression to obtain the version of the tool + versions_metaphlan: + - - ${task.process}: + type: string + description: The name of the process + - MetaPhlAn: + type: string + description: The name of the tool + - metaphlan --version 2>&1 | sed 's/MetaPhlAn version //': + type: eval + description: The expression to obtain the version of the tool + versions_python: + - - ${task.process}: + type: string + description: The name of the process + - Python: + type: string + description: The name of the tool + - python --version 2>&1 | sed 's/Python //': + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - HUMAnN: + type: string + description: The name of the tool + - humann --version 2>&1 | sed 's/humann v//': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - MetaPhlAn: + type: string + description: The name of the tool + - metaphlan --version 2>&1 | sed 's/MetaPhlAn version //': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - Python: + type: string + description: The name of the tool + - python --version 2>&1 | sed 's/Python //': + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@d4straub" + - "@nickp60" + - "@vinisalazar" +maintainers: + - "@nickp60" + - "@vinisalazar" diff --git a/modules/nf-core/humann3/regroup/tests/main.nf.test b/modules/nf-core/humann3/regroup/tests/main.nf.test new file mode 100644 index 0000000..d052638 --- /dev/null +++ b/modules/nf-core/humann3/regroup/tests/main.nf.test @@ -0,0 +1,73 @@ +nextflow_process { + + name "Test Process HUMANN3_REGROUP" + script "../main.nf" + process "HUMANN3_REGROUP" + config "./nextflow.config" + tag "modules" + tag "modules_nfcore" + tag "humann3" + tag "humann3/regroup" + tag "untar" + setup { + run("UNTAR", alias: "UNTAR_v3_util") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.pipelines_testdata_base_path + 'data/database/humann/v3/utility_nfDEMO.tar.gz', checkIfExists: true ) + ]) + """ + } + } + } + test("humann3_regroup - tsv") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file( params.modules_testdata_base_path + 'genomics/prokaryotes/metagenome/biobakery/test_genefamilies.tsv', checkIfExists: true ) + ]) + input[1] = "uniref90_level4ec" + input[2] = UNTAR_v3_util.out.untar.map{ it[1] } + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + + test("humann3_regroup - tsv - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file( params.modules_testdata_base_path + 'genomics/prokaryotes/metagenome/biobakery/test_genefamilies.tsv', checkIfExists: true ) + ]) + input[1] = "uniref90_level4ec" + input[2] = UNTAR_v3_util.out.untar.map{ it[1] } + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/humann3/regroup/tests/main.nf.test.snap b/modules/nf-core/humann3/regroup/tests/main.nf.test.snap new file mode 100644 index 0000000..187a94e --- /dev/null +++ b/modules/nf-core/humann3/regroup/tests/main.nf.test.snap @@ -0,0 +1,144 @@ +{ + "humann3_regroup - tsv - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test_regroup.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + "HUMANN3_REGROUP", + "HUMAnN", + "3.6.1" + ] + ], + "2": [ + [ + "HUMANN3_REGROUP", + "MetaPhlAn", + "4.0.6 (1 Mar 2023)" + ] + ], + "3": [ + [ + "HUMANN3_REGROUP", + "Python", + "3.10.8" + ] + ], + "regroup": [ + [ + { + "id": "test", + "single_end": false + }, + "test_regroup.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions_humann": [ + [ + "HUMANN3_REGROUP", + "HUMAnN", + "3.6.1" + ] + ], + "versions_metaphlan": [ + [ + "HUMANN3_REGROUP", + "MetaPhlAn", + "4.0.6 (1 Mar 2023)" + ] + ], + "versions_python": [ + [ + "HUMANN3_REGROUP", + "Python", + "3.10.8" + ] + ] + } + ], + "timestamp": "2026-05-19T18:33:38.31929", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "humann3_regroup - tsv": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test_regroup.tsv.gz:md5,7b00828cbce7a2aa5ece4db335d2fd28" + ] + ], + "1": [ + [ + "HUMANN3_REGROUP", + "HUMAnN", + "3.6.1" + ] + ], + "2": [ + [ + "HUMANN3_REGROUP", + "MetaPhlAn", + "4.0.6 (1 Mar 2023)" + ] + ], + "3": [ + [ + "HUMANN3_REGROUP", + "Python", + "3.10.8" + ] + ], + "regroup": [ + [ + { + "id": "test", + "single_end": false + }, + "test_regroup.tsv.gz:md5,7b00828cbce7a2aa5ece4db335d2fd28" + ] + ], + "versions_humann": [ + [ + "HUMANN3_REGROUP", + "HUMAnN", + "3.6.1" + ] + ], + "versions_metaphlan": [ + [ + "HUMANN3_REGROUP", + "MetaPhlAn", + "4.0.6 (1 Mar 2023)" + ] + ], + "versions_python": [ + [ + "HUMANN3_REGROUP", + "Python", + "3.10.8" + ] + ] + } + ], + "timestamp": "2026-05-19T18:33:27.694488", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/humann3/regroup/tests/nextflow.config b/modules/nf-core/humann3/regroup/tests/nextflow.config new file mode 100644 index 0000000..ff0dbb6 --- /dev/null +++ b/modules/nf-core/humann3/regroup/tests/nextflow.config @@ -0,0 +1,3 @@ +params { + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/funcprofiler/' +} diff --git a/modules/nf-core/humann3/renorm/environment.yml b/modules/nf-core/humann3/renorm/environment.yml new file mode 100644 index 0000000..3dc3f34 --- /dev/null +++ b/modules/nf-core/humann3/renorm/environment.yml @@ -0,0 +1,9 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::humann=3.6.1 + - bioconda::metaphlan=4.0.6 + - conda-forge::python=3.10.8 diff --git a/modules/nf-core/humann3/renorm/main.nf b/modules/nf-core/humann3/renorm/main.nf new file mode 100644 index 0000000..7611a17 --- /dev/null +++ b/modules/nf-core/humann3/renorm/main.nf @@ -0,0 +1,48 @@ +process HUMANN3_RENORM { + tag "$meta.id" + label 'process_low' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/humann:3.6.1--pyh7cba7a3_0' : + 'quay.io/biocontainers/humann:3.6.1--pyh7cba7a3_0' }" + + input: + tuple val(meta), path(input) + + output: + tuple val(meta), path("*_renorm.tsv.gz"), emit: renorm + tuple val("${task.process}"), val('HUMAnN'), eval("humann --version 2>&1 | sed 's/humann v//'"), emit: versions_humann, topic: versions + tuple val("${task.process}"), val('MetaPhlAn'), eval("metaphlan --version 2>&1 | sed 's/MetaPhlAn version //'"), emit: versions_metaphlan, topic: versions + tuple val("${task.process}"), val('Python'), eval("python --version 2>&1 | sed 's/Python //'"), emit: versions_python, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + if [[ $input == *.gz ]]; then + gunzip -c $input > input.tsv + else + mv $input input.tsv + fi + + humann_renorm_table \\ + --input input.tsv \\ + --output ${prefix}_renorm.tsv \\ + $args + + gzip -n ${prefix}_renorm.tsv + + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo "" | gzip > ${prefix}_renorm.tsv.gz + + """ +} diff --git a/modules/nf-core/humann3/renorm/meta.yml b/modules/nf-core/humann3/renorm/meta.yml new file mode 100644 index 0000000..465ed44 --- /dev/null +++ b/modules/nf-core/humann3/renorm/meta.yml @@ -0,0 +1,109 @@ +name: humann3_renorm +description: Normalizing RPKs to relative abundance +keywords: + - function + - metagenomics + - metatranscriptomics + - profiling + - community +tools: + - humann: + description: "HUMAnN: The HMP Unified Metabolic Analysis Network, version 3" + homepage: http://huttenhower.sph.harvard.edu/humann + documentation: https://github.com/biobakery/biobakery/wiki/humann3 + tool_dev_url: https://github.com/biobakery/humann + doi: "10.7554/eLife.65088" + licence: + - "MIT" + identifier: "" + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - input: + type: file + description: Tab separated abundance file of HUMAnN3 + pattern: "*.{tsv.gz,tsv}" + +output: + renorm: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test' ] + - "*_renorm.tsv.gz": + type: file + description: Normalized compressed tab separated text file + pattern: "*.{tsv.gz}" + versions_humann: + - - ${task.process}: + type: string + description: The name of the process + - HUMAnN: + type: string + description: The name of the tool + - humann --version 2>&1 | sed 's/humann v//': + type: eval + description: The expression to obtain the version of the tool + versions_metaphlan: + - - ${task.process}: + type: string + description: The name of the process + - MetaPhlAn: + type: string + description: The name of the tool + - metaphlan --version 2>&1 | sed 's/MetaPhlAn version //': + type: eval + description: The expression to obtain the version of the tool + versions_python: + - - ${task.process}: + type: string + description: The name of the process + - Python: + type: string + description: The name of the tool + - python --version 2>&1 | sed 's/Python //': + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - HUMAnN: + type: string + description: The name of the tool + - humann --version 2>&1 | sed 's/humann v//': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - MetaPhlAn: + type: string + description: The name of the tool + - metaphlan --version 2>&1 | sed 's/MetaPhlAn version //': + type: eval + description: The expression to obtain the version of the tool + - - ${task.process}: + type: string + description: The name of the process + - Python: + type: string + description: The name of the tool + - python --version 2>&1 | sed 's/Python //': + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@d4straub" + - "@nickp60" + - "@vinisalazar" +maintainers: + - "@nickp60" + - "@vinisalazar" diff --git a/modules/nf-core/humann3/renorm/tests/main.nf.test b/modules/nf-core/humann3/renorm/tests/main.nf.test new file mode 100644 index 0000000..5a00afa --- /dev/null +++ b/modules/nf-core/humann3/renorm/tests/main.nf.test @@ -0,0 +1,35 @@ +nextflow_process { + + name "Test Process HUMANN3_RENORM" + script "../main.nf" + process "HUMANN3_RENORM" + tag "modules" + tag "modules_nfcore" + tag "humann3" + tag "humann3/renorm" + + test("humann3_renorm sarscov2 - tsv - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ]) + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + + } + +} diff --git a/modules/nf-core/humann3/renorm/tests/main.nf.test.snap b/modules/nf-core/humann3/renorm/tests/main.nf.test.snap new file mode 100644 index 0000000..2f25059 --- /dev/null +++ b/modules/nf-core/humann3/renorm/tests/main.nf.test.snap @@ -0,0 +1,73 @@ +{ + "humann3_renorm sarscov2 - tsv - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test_renorm.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + "HUMANN3_RENORM", + "HUMAnN", + "3.6.1" + ] + ], + "2": [ + [ + "HUMANN3_RENORM", + "MetaPhlAn", + "4.0.6 (1 Mar 2023)" + ] + ], + "3": [ + [ + "HUMANN3_RENORM", + "Python", + "3.10.8" + ] + ], + "renorm": [ + [ + { + "id": "test", + "single_end": false + }, + "test_renorm.tsv.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions_humann": [ + [ + "HUMANN3_RENORM", + "HUMAnN", + "3.6.1" + ] + ], + "versions_metaphlan": [ + [ + "HUMANN3_RENORM", + "MetaPhlAn", + "4.0.6 (1 Mar 2023)" + ] + ], + "versions_python": [ + [ + "HUMANN3_RENORM", + "Python", + "3.10.8" + ] + ] + } + ], + "timestamp": "2026-05-19T18:07:13.55885", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/metaphlan/metaphlan/environment.yml b/modules/nf-core/metaphlan/metaphlan/environment.yml new file mode 100644 index 0000000..572f03f --- /dev/null +++ b/modules/nf-core/metaphlan/metaphlan/environment.yml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::metaphlan=4.1.1 + - pip + - pip: + - setuptools diff --git a/modules/nf-core/metaphlan/metaphlan/main.nf b/modules/nf-core/metaphlan/metaphlan/main.nf new file mode 100644 index 0000000..953abfc --- /dev/null +++ b/modules/nf-core/metaphlan/metaphlan/main.nf @@ -0,0 +1,74 @@ +process METAPHLAN_METAPHLAN { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://depot.galaxyproject.org/singularity/metaphlan:4.1.1--pyhdfd78af_0' + : 'quay.io/biocontainers/metaphlan:4.1.1--pyhdfd78af_0'}" + + input: + tuple val(meta), path(input) + path metaphlan_db_latest + val save_samfile + + output: + tuple val(meta), path("*_profile.txt"), emit: profile + tuple val(meta), path("*.biom"), emit: biom + tuple val(meta), path('*.bowtie2out.txt'), optional: true, emit: bt2out + tuple val(meta), path("*.sam"), optional: true, emit: sam + path "versions.yml", emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def input_type = "${input}" =~ /.*\.(fastq|fq)/ ? "--input_type fastq" : "${input}" =~ /.*\.(fasta|fna|fa)/ ? "--input_type fasta" : "${input}".endsWith(".bowtie2out.txt") ? "--input_type bowtie2out" : "--input_type sam" + def input_data = ("${input_type}".contains("fastq")) && !meta.single_end ? "${input[0]},${input[1]}" : "${input}" + def bowtie2_out = "${input_type}" == "--input_type bowtie2out" || "${input_type}" == "--input_type sam" ? '' : "--bowtie2out ${prefix}.bowtie2out.txt" + def samfile_out = save_samfile ? "-s ${prefix}.sam" : '' + """ + BT2_DB=`find -L "${metaphlan_db_latest}" -name "*rev.1.bt2*" -exec dirname {} \\;` + BT2_DB_INDEX=`find -L ${metaphlan_db_latest} -name "*.rev.1.bt2*" | sed 's/\\.rev.1.bt2.*\$//' | sed 's/.*\\///'` + + metaphlan \\ + --nproc ${task.cpus} \\ + ${input_type} \\ + ${input_data} \\ + ${args} \\ + ${bowtie2_out} \\ + ${samfile_out} \\ + --bowtie2db \$BT2_DB \\ + --index \$BT2_DB_INDEX \\ + --biom ${prefix}.biom \\ + --output_file ${prefix}_profile.txt + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + metaphlan: \$(metaphlan --version 2>&1 | awk '{print \$3}') + END_VERSIONS + """ + + stub: + def prefix = task.ext.prefix ?: "${meta.id}" + def samfile_cmd = save_samfile ? "touch ${prefix}.sam" : '' + def input_type = "${input}" =~ /.*\.(fastq|fq)/ ? "fastq" : + "${input}" =~ /.*\.(fasta|fna|fa)/? "fasta" : + "${input}".endsWith(".bowtie2out.txt") ? "bowtie2out" : + "sam" + def bowtie2_cmd = "${input_type}" == "bowtie2out" || "${input_type}" == "sam" ? '' : "touch ${prefix}.bowtie2out.txt" + + """ + touch ${prefix}.biom + touch ${prefix}_profile.txt + ${samfile_cmd} + ${bowtie2_cmd} + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + metaphlan: \$(metaphlan --version 2>&1 | awk '{print \$3}') + END_VERSIONS + """ +} diff --git a/modules/nf-core/metaphlan/metaphlan/meta.yml b/modules/nf-core/metaphlan/metaphlan/meta.yml new file mode 100644 index 0000000..8bc6c07 --- /dev/null +++ b/modules/nf-core/metaphlan/metaphlan/meta.yml @@ -0,0 +1,105 @@ +name: metaphlan_metaphlan +description: MetaPhlAn is a tool for profiling the composition of microbial communities + from metagenomic shotgun sequencing data. +keywords: + - metagenomics + - classification + - fastq + - fasta + - sam +tools: + - metaphlan: + description: Identify clades (phyla to species) present in the metagenome obtained + from a microbiome sample and their relative abundance + homepage: https://huttenhower.sph.harvard.edu/metaphlan/ + documentation: https://github.com/biobakery/MetaPhlAn + doi: "10.1038/s41587-023-01688-w" + licence: ["MIT License"] + identifier: biotools:metaphlan +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - input: + type: file + description: Metaphlan can classify the metagenome from a variety of input data + types, including FASTQ files (single-end and paired-end), FASTA, bowtie2-produced + SAM files (produced from alignments to the MetaPHlAn marker database) and + intermediate bowtie2 alignment files (bowtie2out) + pattern: "*.{fastq.gz, fasta, fasta.gz, sam, bowtie2out.txt}" + ontologies: [] + - metaphlan_db_latest: + type: file + description: | + Directory containing pre-downloaded and uncompressed MetaPhlAn database downloaded from: http://cmprod1.cibio.unitn.it/biobakery4/metaphlan_databases/. + Note that you will also need to specify `--index` and the database version name (e.g. 'mpa_vJan21_TOY_CHOCOPhlAnSGB_202103') in your module.conf ext.args for METAPHLAN_METAPHLAN! + pattern: "*/" + ontologies: [] + - save_samfile: + type: boolean + description: | + Whether to save the SAM file produced by MetaPhlAn of read alignments to MetaPhlAn database gene sequences +output: + profile: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*_profile.txt": + type: file + description: Tab-separated output file of the predicted taxon relative abundances + pattern: "*.{txt}" + ontologies: [] + biom: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.biom": + type: file + description: General-use format for representing biological sample by observation + contingency tables + pattern: "*.{biom}" + ontologies: + - edam: http://edamontology.org/format_3746 # BIOM format + bt2out: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.bowtie2out.txt": + type: file + description: Intermediate Bowtie2 output produced from mapping the metagenome + against the MetaPHlAn marker database ( not compatible with `bowtie2out` + files generated with MetaPhlAn versions below 3 ) + pattern: "*.{bowtie2out.txt}" + ontologies: [] + sam: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.sam": + type: file + description: SAM file produced by MetaPPhlAn of read alignments to MetaPhlAn database gene sequences + pattern: "*.{sam}" + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@MGordon09" + - "@LilyAnderssonLee" +maintainers: + - "@MGordon09" + - "@LilyAnderssonLee" diff --git a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test new file mode 100644 index 0000000..606f060 --- /dev/null +++ b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test @@ -0,0 +1,171 @@ +nextflow_process { + name "Test Process METAPHLAN_METAPHLAN" + script "../main.nf" + config "./nextflow.config" + + process "METAPHLAN_METAPHLAN" + tag "modules" + tag "modules_nfcore" + tag "untar" + tag "metaphlan" + tag "metaphlan/metaphlan" + + setup { + run("UNTAR") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( params.modules_testdata_base_path + 'delete_me/metaphlan4_database.tar.gz', checkIfExists: true ) + ]) + """ + } + } + } + + test("sarscov2 - illumina single end [fastq]") { + + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz',checkIfExists: true ) + ]) + input[1] = UNTAR.out.untar.map{ it[1] } + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.profile[0][1]).readLines()[2..5], + path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), + process.out.bt2out, + process.out.versions + ).match() + } + ) + } + } + + test("sarscov2 - illumina pair end [fastq]") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz',checkIfExists: true ), + file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz',checkIfExists: true ) ] + ]) + input[1] = UNTAR.out.untar.map{ it[1] } + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.profile[0][1]).readLines()[2..5], + path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), + process.out.bt2out, + process.out.versions + ).match() + } + ) + } + } + + test("sarscov2 - illumina single end [fasta]") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:true ], // meta map + file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fasta/contigs.fasta',checkIfExists: true ) + ]) + input[1] = UNTAR.out.untar.map{ it[1] } + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.profile[0][1]).readLines()[2..5], + path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), + process.out.bt2out, + process.out.versions + ).match() + } ) + } + } + + test("sarscov2 - illumina pair end [fastq] - save sam") { + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz',checkIfExists: true ), + file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz',checkIfExists: true )] + ]) + input[1] = UNTAR.out.untar.map{ it[1] } + input[2] = true + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( + path(process.out.profile[0][1]).readLines()[2..5], + path(process.out.biom[0][1]).readLines().last().contains('Biological Observation Matrix'), + process.out.bt2out, + sam(process.out.sam.get(0).get(1)).getFileType(), + process.out.versions + ).match() + } + ) + } + } + + test("sarscov2 - illumina pair end [fastq] - stub") { + + options "-stub" + + when { + process { + """ + input[0] = Channel.of([ + [ id:'test', single_end:false ], // meta map + [ file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz',checkIfExists: true ), + file( params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz',checkIfExists: true )] + ]) + input[1] = UNTAR.out.untar.map{ it[1] } + input[2] = false + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot( process.out ).match() } + ) + } + } +} diff --git a/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap new file mode 100644 index 0000000..a5b0f9a --- /dev/null +++ b/modules/nf-core/metaphlan/metaphlan/tests/main.nf.test.snap @@ -0,0 +1,192 @@ +{ + "sarscov2 - illumina pair end [fastq] - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test_profile.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test.biom:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bowtie2out.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + + ], + "4": [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ], + "biom": [ + [ + { + "id": "test", + "single_end": false + }, + "test.biom:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "bt2out": [ + [ + { + "id": "test", + "single_end": false + }, + "test.bowtie2out.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "profile": [ + [ + { + "id": "test", + "single_end": false + }, + "test_profile.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "sam": [ + + ], + "versions": [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] + } + ], + "timestamp": "2026-02-16T10:17:01.145927415", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "sarscov2 - illumina pair end [fastq] - save sam": { + "content": [ + [ + "#196 reads processed", + "#SampleID\tMetaphlan_Analysis", + "#clade_name\tNCBI_tax_id\trelative_abundance\tadditional_species", + "UNCLASSIFIED\t-1\t100.0\t" + ], + true, + [ + [ + { + "id": "test", + "single_end": false + }, + "test.bowtie2out.txt:md5,8c1bc21e1d8484b5551bf46331d61bd8" + ] + ], + "SAM", + [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] + ], + "timestamp": "2025-08-22T07:33:29.981757425", + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + } + }, + "sarscov2 - illumina single end [fastq]": { + "content": [ + [ + "#100 reads processed", + "#SampleID\tMetaphlan_Analysis", + "#clade_name\tNCBI_tax_id\trelative_abundance\tadditional_species", + "UNCLASSIFIED\t-1\t100.0\t" + ], + true, + [ + [ + { + "id": "test", + "single_end": true + }, + "test.bowtie2out.txt:md5,ef46a9c6a8ce9cae26fbfd5527116fd5" + ] + ], + [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] + ], + "timestamp": "2024-08-27T10:33:32.269571148", + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + } + }, + "sarscov2 - illumina single end [fasta]": { + "content": [ + [ + "#4 reads processed", + "#SampleID\tMetaphlan_Analysis", + "#clade_name\tNCBI_tax_id\trelative_abundance\tadditional_species", + "UNCLASSIFIED\t-1\t100.0\t" + ], + true, + [ + [ + { + "id": "test", + "single_end": true + }, + "test.bowtie2out.txt:md5,d99d05d6b011c647adf816f10fc6acbe" + ] + ], + [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] + ], + "timestamp": "2024-08-27T10:34:10.262604527", + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + } + }, + "sarscov2 - illumina pair end [fastq]": { + "content": [ + [ + "#196 reads processed", + "#SampleID\tMetaphlan_Analysis", + "#clade_name\tNCBI_tax_id\trelative_abundance\tadditional_species", + "UNCLASSIFIED\t-1\t100.0\t" + ], + true, + [ + [ + { + "id": "test", + "single_end": false + }, + "test.bowtie2out.txt:md5,8c1bc21e1d8484b5551bf46331d61bd8" + ] + ], + [ + "versions.yml:md5,db17780c9fc65bc70e9641101c47d0e0" + ] + ], + "timestamp": "2024-08-27T10:33:51.829732777", + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.04.4" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/metaphlan/metaphlan/tests/nextflow.config b/modules/nf-core/metaphlan/metaphlan/tests/nextflow.config new file mode 100644 index 0000000..e64f0f9 --- /dev/null +++ b/modules/nf-core/metaphlan/metaphlan/tests/nextflow.config @@ -0,0 +1,10 @@ +docker { + fixOwnership = true + runOptions = '--platform=linux/amd64' +} + +process { + withName: UNTAR { + ext.args2 = "--no-same-owner" + } +} diff --git a/modules/nf-core/mifaser/environment.yml b/modules/nf-core/mifaser/environment.yml new file mode 100644 index 0000000..62896ba --- /dev/null +++ b/modules/nf-core/mifaser/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::mifaser=1.64 diff --git a/modules/nf-core/mifaser/main.nf b/modules/nf-core/mifaser/main.nf new file mode 100644 index 0000000..ea54520 --- /dev/null +++ b/modules/nf-core/mifaser/main.nf @@ -0,0 +1,50 @@ +process MIFASER { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/mifaser:1.64--pyh106432d_0' : + 'quay.io/biocontainers/mifaser:1.64--pyh106432d_0' }" + + input: + tuple val(meta), path(reads) + path(db) + + output: + tuple val(meta), path("*multi_ec.tsv"), emit: multi_ec + tuple val(meta), path("*analysis.tsv"), emit: analysis + tuple val(meta), path("*ec_count.tsv"), emit: ec_counts + tuple val("${task.process}"), val('mi-faser'), eval("mifaser --version 2>&1 | sed 's/* v//'"), emit: versions_mifaser, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def input_flag = meta.single_end ? "-f" : "-l" + """ + mifaser \\ + ${args} \\ + ${input_flag} ${reads} \\ + --threads 1 \\ + --cpu ${task.cpus} \\ + --databasefolder \$PWD/${db} \\ + --outputfolder mifaser-${prefix}/ + + for suf in multi_ec.tsv analysis.tsv ec_count.tsv; do + mv mifaser-${prefix}/\${suf} ${prefix}_\${suf} + done + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo ${args} + for suf in multi_ec.tsv analysis.tsv ec_count.tsv; do + touch ${prefix}_\${suf} + done + """ +} diff --git a/modules/nf-core/mifaser/meta.yml b/modules/nf-core/mifaser/meta.yml new file mode 100644 index 0000000..932e416 --- /dev/null +++ b/modules/nf-core/mifaser/meta.yml @@ -0,0 +1,91 @@ +name: "mifaser" +description: Functional annotation of metagenomic reads by assigning enzyme + commission (EC) numbers +keywords: + - metagenomics + - functional annotation + - EC numbers + - fastq +tools: + - "mifaser": + description: "mi-faser: microsecond functional annotation of sequences, a massive + scalability upgrade" + homepage: "https://sourceforge.net/projects/mifaser/" + documentation: "https://sourceforge.net/projects/mifaser/" + tool_dev_url: "https://sourceforge.net/projects/mifaser/" + doi: "10.1093/nar/gkx1209" + licence: + - "NPOSL-3.0" + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'sample1', single_end:true ]` + - reads: + type: file + description: | + Single-end or paired-end FASTQ files. Use meta.single_end to indicate input type. + pattern: "*.{fastq,fastq.gz,fq,fq.gz}" + ontologies: + - edam: "http://edamontology.org/format_1930" + - db: + type: directory + description: Path to the mi-faser database folder +output: + multi_ec: + - - meta: + type: map + description: Groovy Map containing sample information + - "*multi_ec.tsv": + type: file + description: TSV file with multi-EC functional assignments per read + pattern: "*multi_ec.tsv" + ontologies: + - edam: http://edamontology.org/format_3475 + analysis: + - - meta: + type: map + description: Groovy Map containing sample information + - "*analysis.tsv": + type: file + description: TSV file with per-sample functional analysis summary + pattern: "*analysis.tsv" + ontologies: + - edam: http://edamontology.org/format_3475 + ec_counts: + - - meta: + type: map + description: Groovy Map containing sample information + - "*ec_count.tsv": + type: file + description: TSV file with EC number counts + pattern: "*ec_count.tsv" + ontologies: + - edam: http://edamontology.org/format_3475 + versions_mifaser: + - - "${task.process}": + type: string + description: Process name + - "mi-faser": + type: string + description: Tool name + - "mifaser --version 2>&1 | sed 's/* v//'": + type: eval + description: mifaser version string +topics: + versions: + - - "${task.process}": + type: string + description: Process name + - "mi-faser": + type: string + description: Tool name + - "mifaser --version 2>&1 | sed 's/* v//'": + type: eval + description: mifaser version string +authors: + - "@nickp60" +maintainers: + - "@nickp60" diff --git a/modules/nf-core/mifaser/tests/main.nf.test b/modules/nf-core/mifaser/tests/main.nf.test new file mode 100644 index 0000000..954ba2b --- /dev/null +++ b/modules/nf-core/mifaser/tests/main.nf.test @@ -0,0 +1,73 @@ +nextflow_process { + + name "Test Process MIFASER" + script "../main.nf" + process "MIFASER" + tag "modules" + tag "modules_nfcore" + tag "mifaser" + tag "untar" + + setup { + run("UNTAR") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = Channel.of([ + [], + file( + 'https://github.com/nf-core/test-datasets/raw/refs/heads/funcprofiler/data/database/mifaser/GS-24-all.tar.gz', + checkIfExists: true + ) + ]) + """ + } + } + } + + test("sarscov2 - single-end fastq") { + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ] + input[1] = UNTAR.out.untar.map { it[1] } + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot( + process.out.multi_ec, + process.out.analysis, + process.out.ec_counts, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() } + ) + } + } + + test("sarscov2 - single-end fastq - stub") { + options "-stub" + when { + process { + """ + input[0] = [ + [ id:'test', single_end:true ], + [ file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) ] + ] + input[1] = UNTAR.out.untar.map{ meta, dir -> dir.resolve("database/mifaser/GS-24-all") } + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/mifaser/tests/main.nf.test.snap b/modules/nf-core/mifaser/tests/main.nf.test.snap new file mode 100644 index 0000000..b14ab23 --- /dev/null +++ b/modules/nf-core/mifaser/tests/main.nf.test.snap @@ -0,0 +1,126 @@ +{ + "sarscov2 - single-end fastq - stub": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": true + }, + "test_multi_ec.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": true + }, + "test_analysis.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "2": [ + [ + { + "id": "test", + "single_end": true + }, + "test_ec_count.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "3": [ + [ + "MIFASER", + "mi-faser", + "mifaser 1.64 (07/21/25)" + ] + ], + "analysis": [ + [ + { + "id": "test", + "single_end": true + }, + "test_analysis.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "ec_counts": [ + [ + { + "id": "test", + "single_end": true + }, + "test_ec_count.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "multi_ec": [ + [ + { + "id": "test", + "single_end": true + }, + "test_multi_ec.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_mifaser": [ + [ + "MIFASER", + "mi-faser", + "mifaser 1.64 (07/21/25)" + ] + ] + } + ], + "timestamp": "2026-05-15T14:21:18.968578", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "sarscov2 - single-end fastq": { + "content": [ + [ + [ + { + "id": "test", + "single_end": true + }, + "test_multi_ec.tsv:md5,08ad0cac1771a190e63cd76a3b3ab686" + ] + ], + [ + [ + { + "id": "test", + "single_end": true + }, + "test_analysis.tsv:md5,722399e3bfd7af4273b36779a111db8a" + ] + ], + [ + [ + { + "id": "test", + "single_end": true + }, + "test_ec_count.tsv:md5,195e3e0db1dd8b603a7e8d91e85e480d" + ] + ], + { + "versions_mifaser": [ + [ + "MIFASER", + "mi-faser", + "mifaser 1.64 (07/21/25)" + ] + ] + } + ], + "timestamp": "2026-05-15T14:21:10.040918", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + } +} diff --git a/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt new file mode 100644 index 0000000..2a91c22 --- /dev/null +++ b/modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt @@ -0,0 +1,1526 @@ + +version: 6 +environments: +default: +channels: +- url: https://conda.anaconda.org/conda-forge/ +- url: https://conda.anaconda.org/bioconda/ +- url: https://conda.anaconda.org/bioconda/ +options: +pypi-prerelease-mode: if-necessary-or-explicit +packages: +linux-64: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.5.0-py314h680f03e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.5.20-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.0-pyhc90fa1f_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.5-py314hd8ed1ab_100.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.8.1-hecca717_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.0-h27c8c51_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.21.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py314h2b28147_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py314h8ec4b1a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.41.0-pyh58ad624_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.41.0-py310h49dadd8_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.41.0-py310hcbd6021_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py314h2e6c369_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.5-habeac84_100_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.5-h4df99d1_100.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/regex-2026.5.9-py314h5bd0f2a_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda +build_number: 20 +sha256: 1dd3fffd892081df9726d7eb7e0dea6198962ba775bd88842135a4ddb4deb3c9 +md5: a9f577daf3de00bca7c3c76c0ecbd1de +depends: +- __glibc >=2.17,<3.0.a0 +- libgomp >=7.5.0 +constrains: +- openmp_impl <0.0a0 +license: BSD-3-Clause +license_family: BSD +size: 28948 +timestamp: 1770939786096 +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661 +md5: aaa2a381ccc56eac91d63b6c1240312f +depends: +- cpython +- python-gil +license: MIT +license_family: MIT +size: 8191 +timestamp: 1744137672556 +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +sha256: e0ea1ba78fbb64f17062601edda82097fcf815012cf52bb704150a2668110d48 +md5: 2934f256a8acfe48f6ebb4fce6cde29c +depends: +- python >=3.9 +- typing-extensions >=4.0.0 +license: MIT +license_family: MIT +size: 18074 +timestamp: 1733247158254 +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +sha256: 1b6124230bb4e571b1b9401537ecff575b7b109cc3a21ee019f65e083b8399ab +md5: c6b0543676ecb1fb2d7643941fe375f2 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 64927 +timestamp: 1773935801332 +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.5.0-py314h680f03e_0.conda +noarch: generic +sha256: a1c97297e867776760489537bc5ae36fa83a154be30e3b79385a39ca4cb058fe +md5: 1133126d840e75287d83947be3fc3e71 +depends: +- python >=3.14 +license: BSD-3-Clause AND MIT AND EPL-2.0 +size: 7533 +timestamp: 1778594057496 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda +sha256: 3ad3500bff54a781c29f16ce1b288b36606e2189d0b0ef2f67036554f47f12b0 +md5: 8910d2c46f7e7b519129f486e0fe927a +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- libbrotlicommon 1.2.0 hb03c661_1 +license: MIT +license_family: MIT +size: 367376 +timestamp: 1764017265553 +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda +sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 +md5: d2ffd7602c02f2b316fd921d39876885 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: bzip2-1.0.6 +license_family: BSD +size: 260182 +timestamp: 1771350215188 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda +sha256: 9812a303a1395e1dafbd92e5bc8a1ff6013bcbba0a09c7f03a8d23e43560aa9b +md5: 489b8e97e666c93f68fdb35c3c9b957f +depends: +- __unix +license: ISC +size: 129868 +timestamp: 1779289852439 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.5.20-pyhd8ed1ab_0.conda +sha256: 645655a3510e38e625da136595f3f16f2130c3263630cc3bc8f60f619ddbe490 +md5: 9fefff2f745ea1cc2ef15211a20c054a +depends: +- python >=3.10 +license: ISC +size: 134201 +timestamp: 1779285131141 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda +sha256: 3f9483d62ce24ecd063f8a5a714448445dc8d9e201147c46699fc0033e824457 +md5: a9167b9571f3baa9d448faa2139d1089 +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 58872 +timestamp: 1775127203018 +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.0-pyhc90fa1f_0.conda +sha256: 99ab8ef815c4520cce3a7482c2513f377c14348206857661d84c76a55e030f97 +md5: 003767c47f1f0a474c4de268b57839c3 +depends: +- __unix +- python +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 104631 +timestamp: 1779108494556 +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +sha256: 8021c76eeadbdd5784b881b165242db9449783e12ce26d6234060026fd6a8680 +md5: b866ff7007b934d564961066c8195983 +depends: +- humanfriendly >=9.1 +- python >=3.9 +license: MIT +license_family: MIT +size: 43758 +timestamp: 1733928076798 +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +sha256: 59c9e29800b483b390467f90e82b0da3a4fbf0612efe1c90813fca232780e160 +md5: 071cf7b0ce333c81718b054066c15102 +depends: +- networkx >=2.0 +- numpy +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 39326 +timestamp: 1735759976140 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.5-py314hd8ed1ab_100.conda +noarch: generic +sha256: 777882d2685f368417f31bbe1b28f73687fc6c8f6a5768bda20ffeefa6b07f5b +md5: a749029ce5d0632a913db19d17f944ab +depends: +- python >=3.14,<3.15.0a0 +- python_abi * *_cp314 +license: Python-2.0 +size: 50212 +timestamp: 1779236682725 +- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.8.1-hecca717_0.conda +sha256: 29a10599d56d93bd750914888ebe6822d47722070762b4647b34d12df9f4476e +md5: d0757fd84af06f065eba49d39af6c546 +depends: +- __glibc >=2.17,<3.0.a0 +- libexpat 2.8.1 hecca717_0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 148238 +timestamp: 1779278694477 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b +md5: 0c96522c6bdaed4b1566d11387caaf45 +license: BSD-3-Clause +license_family: BSD +size: 397370 +timestamp: 1566932522327 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c +md5: 34893075a5c9e55cdafac56607368fc6 +license: OFL-1.1 +license_family: Other +size: 96530 +timestamp: 1620479909603 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 +md5: 4d59c254e01d9cde7957100457e2d5fb +license: OFL-1.1 +license_family: Other +size: 700814 +timestamp: 1620479612257 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14 +md5: 49023d73832ef61042f6a237cb2687e7 +license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 +license_family: Other +size: 1620504 +timestamp: 1727511233259 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.0-h27c8c51_0.conda +sha256: e798086d8a65d55dc4c51f5746705639c9a5f2eeb0b8fc50e6152cfc0d69a4e8 +md5: 06965b2f9854d0b15e0443ee81fe83dc +depends: +- __glibc >=2.17,<3.0.a0 +- libexpat >=2.8.1,<3.0a0 +- libfreetype >=2.14.3 +- libfreetype6 >=2.14.3 +- libgcc >=14 +- libuuid >=2.42.1,<3.0a0 +- libzlib >=1.3.2,<2.0a0 +license: MIT +license_family: MIT +size: 280882 +timestamp: 1779421631622 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333 +md5: a7970cd949a077b7cb9696379d338681 +depends: +- font-ttf-ubuntu +- font-ttf-inconsolata +- font-ttf-dejavu-sans-mono +- font-ttf-source-code-pro +license: BSD-3-Clause +license_family: BSD +size: 4059 +timestamp: 1762351264405 +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3 +md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9 +depends: +- python >=3.10 +- hyperframe >=6.1,<7 +- hpack >=4.1,<5 +- python +license: MIT +license_family: MIT +size: 95967 +timestamp: 1756364871835 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba +md5: 0a802cb9888dd14eeefc611f05c40b6e +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 30731 +timestamp: 1737618390337 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +sha256: fa2071da7fab758c669e78227e6094f6b3608228740808a6de5d6bce83d9e52d +md5: 7fe569c10905402ed47024fc481bb371 +depends: +- __unix +- python >=3.9 +license: MIT +license_family: MIT +size: 73563 +timestamp: 1733928021866 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +sha256: 6c4343b376d0b12a4c75ab992640970d36c933cad1fd924f6a1181fa91710e80 +md5: daddf757c3ecd6067b9af1df1f25d89e +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 67994 +timestamp: 1766267728652 +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8 +md5: 8e6923fc12f1fe8f8c4e5c9f343256ac +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 17397 +timestamp: 1737618427549 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda +sha256: 3d25f9f6f7ab3e1ce6429fc8c8aae0335cf446692e715068488536d220cc43de +md5: 1b9083b7f00609605d1483dbc6071a81 +depends: +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 62642 +timestamp: 1779294335905 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda +sha256: 43e2a5497cad1598ff88a3e69f69bc88b7b8f141fa63c60eab5db296317318b8 +md5: ffc17e785d64e12fc311af9184221839 +depends: +- python >=3.10 +- zipp >=3.20 +- python +license: Apache-2.0 +size: 34766 +timestamp: 1779714582554 +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +sha256: fc9ca7348a4f25fed2079f2153ecdcf5f9cf2a0bc36c4172420ca09e1849df7b +md5: 04558c96691bed63104678757beb4f8d +depends: +- markupsafe >=2.0 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 120685 +timestamp: 1764517220861 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +sha256: db973a37d75db8e19b5f44bbbdaead0c68dde745407f281e2a7fe4db74ec51d7 +md5: ada41c863af263cc4c5fcbaff7c3e4dc +depends: +- attrs >=22.2.0 +- jsonschema-specifications >=2023.3.6 +- python >=3.10 +- referencing >=0.28.4 +- rpds-py >=0.25.0 +- python +license: MIT +license_family: MIT +size: 82356 +timestamp: 1767839954256 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +sha256: 0a4f3b132f0faca10c89fdf3b60e15abb62ded6fa80aebfc007d05965192aa04 +md5: 439cd0f567d697b20a8f45cb70a1005a +depends: +- python >=3.10 +- referencing >=0.31.0 +- python +license: MIT +license_family: MIT +size: 19236 +timestamp: 1757335715225 +- conda: https://conda.anaconda.org/conda-forge/linux-64/kaleido-core-0.2.1-h3644ca4_0.tar.bz2 +sha256: 7f243680ca03eba7457b7a48f93a9440ba8181a8eac20a3eb5ef165ab6c96664 +md5: b3723b235b0758abaae8c82ce4d80146 +depends: +- __glibc >=2.17,<3.0.a0 +- expat >=2.2.10,<3.0.0a0 +- fontconfig +- fonts-conda-forge +- libgcc-ng >=9.3.0 +- mathjax 2.7.* +- nspr >=4.29,<5.0a0 +- nss >=3.62,<4.0a0 +- sqlite >=3.34.0,<4.0a0 +license: MIT +license_family: MIT +size: 62099926 +timestamp: 1615199463039 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_0.conda +sha256: eb89c6c39f2f6a93db55723dbb2f6bba8c8e63e6312bf1abf13e6e9ff45849c8 +md5: f92f984b558e6e6204014b16d212b271 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.4.1,<4.0a0 +- libtiff >=4.7.1,<4.8.0a0 +license: MIT +license_family: MIT +size: 251086 +timestamp: 1778079286384 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda +sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c +md5: 18335a698559cdbcd86150a48bf54ba6 +depends: +- __glibc >=2.17,<3.0.a0 +- zstd >=1.5.7,<1.6.0a0 +constrains: +- binutils_impl_linux-64 2.45.1 +license: GPL-3.0-only +license_family: GPL +size: 728002 +timestamp: 1774197446916 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda +sha256: f84cb54782f7e9cea95e810ea8fef186e0652d0fa73d3009914fa2c1262594e1 +md5: a752488c68f2e7c456bcbd8f16eec275 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: Apache-2.0 +license_family: Apache +size: 261513 +timestamp: 1773113328888 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-7_h4a7cf45_openblas.conda +build_number: 7 +sha256: 081c850f99bc355821fac9c6e3727d40b3f8ce3beb50a5437cf03726b611ff39 +md5: 955b44e8b00b7f7ef4ce0130cef12394 +depends: +- libopenblas >=0.3.33,<0.3.34.0a0 +- libopenblas >=0.3.33,<1.0a0 +constrains: +- libcblas 3.11.0 7*_openblas +- blas 2.307 openblas +- liblapack 3.11.0 7*_openblas +- liblapacke 3.11.0 7*_openblas +- mkl <2027 +license: BSD-3-Clause +license_family: BSD +size: 18716 +timestamp: 1778489854108 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-7_h0358290_openblas.conda +build_number: 7 +sha256: 956ae0bb1ec8b0c3663d75b151aceb0521b54e513bf97f621a035f9c87037970 +md5: 0675639dc24cb0032f199e7ff68e4633 +depends: +- libblas 3.11.0 7_h4a7cf45_openblas +constrains: +- liblapacke 3.11.0 7*_openblas +- blas 2.307 openblas +- liblapack 3.11.0 7*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18675 +timestamp: 1778489861559 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda +sha256: aa8e8c4be9a2e81610ddf574e05b64ee131fab5e0e3693210c9d6d2fba32c680 +md5: 6c77a605a7a689d17d4819c0f8ac9a00 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 73490 +timestamp: 1761979956660 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda +sha256: 363018b25fdb5534c79783d912bd4b685a3547f4fc5996357ad548899b0ee8e7 +md5: 93764a5ca80616e9c10106cdaec92f74 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- expat 2.8.1.* +license: MIT +license_family: MIT +size: 77294 +timestamp: 1779278686680 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda +sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 +md5: a360c33a5abe61c07959e449fa1453eb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 58592 +timestamp: 1769456073053 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda +sha256: 38f014a7129e644636e46064ecd6b1945e729c2140e21d75bb476af39e692db2 +md5: e289f3d17880e44b633ba911d57a321b +depends: +- libfreetype6 >=2.14.3 +license: GPL-2.0-only OR FTL +size: 8049 +timestamp: 1774298163029 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda +sha256: 16f020f96da79db1863fcdd8f2b8f4f7d52f177dd4c58601e38e9182e91adf1d +md5: fb16b4b69e3f1dcfe79d80db8fd0c55d +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libpng >=1.6.55,<1.7.0a0 +- libzlib >=1.3.2,<2.0a0 +constrains: +- freetype >=2.14.3 +license: GPL-2.0-only OR FTL +size: 384575 +timestamp: 1774298162622 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda +sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46 +md5: 57736f29cc2b0ec0b6c2952d3f101b6a +depends: +- __glibc >=2.17,<3.0.a0 +- _openmp_mutex >=4.5 +constrains: +- libgcc-ng ==15.2.0=*_19 +- libgomp 15.2.0 he0feb66_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 1041084 +timestamp: 1778269013026 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda +sha256: 9dcf54adfaa5e861123c2da4f2f0451a685464ea7e5a41ad91cf67b31d658d98 +md5: 331ee9b72b9dff570d56b1302c5ab37d +depends: +- libgcc 15.2.0 he0feb66_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27694 +timestamp: 1778269016987 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda +sha256: 561a42758ef25b9ce308c4e2cf56daee4f06138385a17e29a492cd928e00be6f +md5: 42bf7eca1a951735fa06c0e3c0d5c8e6 +depends: +- libgfortran5 15.2.0 h68bc16d_19 +constrains: +- libgfortran-ng ==15.2.0=*_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27655 +timestamp: 1778269042954 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda +sha256: 057978bb69fea29ed715a9b98adf71015c31baecc4aeb2bfc20d4fd5d83579d4 +md5: 85072b0ad177c966294f129b7c04a2d5 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=15.2.0 +constrains: +- libgfortran 15.2.0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 2483673 +timestamp: 1778269025089 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda +sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b +md5: faac990cb7aedc7f3a2224f2c9b0c26c +depends: +- __glibc >=2.17,<3.0.a0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 603817 +timestamp: 1778268942614 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda +sha256: 10056646c28115b174de81a44e23e3a0a3b95b5347d2e6c45cc6d49d35294256 +md5: 6178c6f2fb254558238ef4e6c56fb782 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- jpeg <0.0.0a +license: IJG AND BSD-3-Clause AND Zlib +size: 633831 +timestamp: 1775962768273 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-7_h47877c9_openblas.conda +build_number: 7 +sha256: 96962084921f197c9ad13fb7f8b324f2351d50ff3d8d962148751ad532f54a01 +md5: 6569b4f273740e25dc0dc7e3232c2a6c +depends: +- libblas 3.11.0 7_h4a7cf45_openblas +constrains: +- liblapacke 3.11.0 7*_openblas +- libcblas 3.11.0 7*_openblas +- blas 2.307 openblas +license: BSD-3-Clause +license_family: BSD +size: 18694 +timestamp: 1778489869038 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda +sha256: ec30e52a3c1bf7d0425380a189d209a52baa03f22fb66dd3eb587acaa765bd6d +md5: b88d90cad08e6bc8ad540cb310a761fb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- xz 5.8.3.* +license: 0BSD +size: 113478 +timestamp: 1775825492909 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda +sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843 +md5: 2c21e66f50753a083cbe6b80f38268fa +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: BSD-2-Clause +license_family: BSD +size: 92400 +timestamp: 1769482286018 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda +sha256: 3d9aa85648e5e18a6d66db98b8c4317cc426721ad7a220aa86330d1ccedc8903 +md5: 2d3278b721e40468295ca755c3b84070 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libgfortran +- libgfortran5 >=14.3.0 +constrains: +- openblas >=0.3.33,<0.3.34.0a0 +license: BSD-3-Clause +license_family: BSD +size: 5931919 +timestamp: 1776993658641 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda +sha256: 377cfe037f3eeb3b1bf3ad333f724a64d32f315ee1958581fc671891d63d3f89 +md5: eba48a68a1a2b9d3c0d9511548db85db +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libzlib >=1.3.2,<2.0a0 +license: zlib-acknowledgement +size: 317729 +timestamp: 1776315175087 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda +sha256: 54cdcd3214313b62c2a8ee277e6f42150d9b748264c1b70d958bf735e420ef8d +md5: 7dc38adcbf71e6b38748e919e16e0dce +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libzlib >=1.3.2,<2.0a0 +license: blessing +size: 954962 +timestamp: 1777986471789 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda +sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc +md5: 5794b3bdc38177caf969dabd3af08549 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc 15.2.0 he0feb66_19 +constrains: +- libstdcxx-ng ==15.2.0=*_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 5852044 +timestamp: 1778269036376 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda +sha256: e5f8c38625aa6d567809733ae04bb71c161a42e44a9fa8227abe61fa5c60ebe0 +md5: cd5a90476766d53e901500df9215e927 +depends: +- __glibc >=2.17,<3.0.a0 +- lerc >=4.0.0,<5.0a0 +- libdeflate >=1.25,<1.26.0a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.0,<4.0a0 +- liblzma >=5.8.1,<6.0a0 +- libstdcxx >=14 +- libwebp-base >=1.6.0,<2.0a0 +- libzlib >=1.3.1,<2.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: HPND +size: 435273 +timestamp: 1762022005702 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda +sha256: 3f0edf1280e2f6684a986f821eaa3e123d2694a00b31b96ca0d4a4c12c129231 +md5: 7d0a66598195ef00b6efc55aefc7453b +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: BSD-3-Clause +license_family: BSD +size: 40163 +timestamp: 1779118517630 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda +sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b +md5: aea31d2e5b1091feca96fcfe945c3cf9 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +constrains: +- libwebp 1.6.0 +license: BSD-3-Clause +license_family: BSD +size: 429011 +timestamp: 1752159441324 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda +sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa +md5: 92ed62436b625154323d40d5f2f11dd7 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +- pthread-stubs +- xorg-libxau >=1.0.11,<2.0a0 +- xorg-libxdmcp +license: MIT +license_family: MIT +size: 395888 +timestamp: 1727278577118 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda +sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 +md5: d87ff7921124eccd67248aa483c23fec +depends: +- __glibc >=2.17,<3.0.a0 +constrains: +- zlib 1.3.2 *_2 +license: Zlib +license_family: Other +size: 63629 +timestamp: 1774072609062 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +sha256: 20e0892592a3e7c683e3d66df704a9425d731486a97c34fc56af4da1106b2b6b +md5: ba0a9221ce1063f31692c07370d062f3 +depends: +- importlib-metadata >=4.4 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 85893 +timestamp: 1770694658918 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda +sha256: 0c4c35376fe920714390d46e4b8d31c876d65f18e1655899e0763ec25f2a902f +md5: 6d03368f2b2b0a5fb6839df53b2eb5e0 +depends: +- mdurl >=0.1,<1 +- python >=3.10 +license: MIT +license_family: MIT +size: 69017 +timestamp: 1778169663339 +- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py314h67df5f8_1.conda +sha256: c279be85b59a62d5c52f5dd9a4cd43ebd08933809a8416c22c3131595607d4cf +md5: 9a17c4307d23318476d7fbf0fedc0cde +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- jinja2 >=3.0.0 +license: BSD-3-Clause +license_family: BSD +size: 27424 +timestamp: 1772445227915 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mathjax-2.7.7-ha770c72_3.tar.bz2 +sha256: 02fef69bde69db264a12f21386612262f545b6e3e68d8f1ccec19f3eaae58edf +md5: 86e69bd82c2a2c6fd29f5ab7e02b3691 +license: Apache-2.0 +license_family: Apache +size: 22281629 +timestamp: 1662784498331 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +sha256: 78c1bbe1723449c52b7a9df1af2ee5f005209f67e40b6e1d3c7619127c43b1c7 +md5: 592132998493b3ff25fd7479396e8351 +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 14465 +timestamp: 1733255681319 +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda +sha256: e86033aa55a9e915e2d0957e770bdb81e3feb26a227d1adb17f9d6c528da6a71 +md5: cdb20309681ba3ce8f52c110e214d4f3 +depends: +- click +- coloredlogs +- humanize +- importlib-metadata +- jinja2 >=3.0.0 +- jsonschema +- markdown +- natsort +- numpy +- packaging +- pillow >=10.2.0 +- plotly >=5.18 +- polars >=1.34.0 +- polars-runtime-compat >=1.34.0 +- pyaml-env +- pydantic >=2.7.1 +- python >=3.9,!=3.14.1 +- python-dotenv +- python-kaleido 0.2.1 +- pyyaml >=4 +- requests +- rich >=10 +- rich-click +- spectra >=0.0.10 +- tiktoken +- tqdm +- typeguard >=4 +license: GPL-3.0-or-later +license_family: GPL3 +size: 4282188 +timestamp: 1779465338806 +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.21.2-pyhcf101f3_0.conda +sha256: 70f43d62450927d51673eecd8823e14f5b3cfebdb43cda1d502eba97162bab42 +md5: 6687827c332121727ce383919e1ec8c2 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 284323 +timestamp: 1778929680962 +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +sha256: aeb1548eb72e4f198e72f19d242fb695b35add2ac7b2c00e0d83687052867680 +md5: e941e85e273121222580723010bd4fa2 +depends: +- python >=3.9 +- python +license: MIT +license_family: MIT +size: 39262 +timestamp: 1770905275632 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda +sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3 +md5: fc21868a1a5aacc937e7a18747acb8a5 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: X11 AND BSD-3-Clause +size: 918956 +timestamp: 1777422145199 +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +sha256: f6a82172afc50e54741f6f84527ef10424326611503c64e359e25a19a8e4c1c6 +md5: a2c1eeadae7a309daed9d62c96012a2b +depends: +- python >=3.11 +- python +constrains: +- numpy >=1.25 +- scipy >=1.11.2 +- matplotlib-base >=3.8 +- pandas >=2.0 +license: BSD-3-Clause +license_family: BSD +size: 1587439 +timestamp: 1765215107045 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda +sha256: e3664264bd936c357523b55c71ed5a30263c6ba278d726a75b1eb112e6fb0b64 +md5: e235d5566c9cc8970eb2798dd4ecf62f +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: MPL-2.0 +license_family: MOZILLA +size: 228588 +timestamp: 1762348634537 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda +sha256: 44dd98ffeac859d84a6dcba79a2096193a42fc10b29b28a5115687a680dd6aea +md5: 567fbeed956c200c1db5782a424e58ee +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libsqlite >=3.51.0,<4.0a0 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +- nspr >=4.38,<5.0a0 +license: MPL-2.0 +license_family: MOZILLA +size: 2057773 +timestamp: 1763485556350 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py314h2b28147_0.conda +sha256: bc61ae892973751a6b0e6ecea57ed6d7053224bddcb007165d6ceb1d7344ad47 +md5: f49b5f950379e0b97c35ca97682f7c6a +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- liblapack >=3.9.0,<4.0a0 +- python_abi 3.14.* *_cp314 +- libblas >=3.9.0,<4.0a0 +- libcblas >=3.9.0,<4.0a0 +constrains: +- numpy-base <0a0 +license: BSD-3-Clause +license_family: BSD +size: 8928909 +timestamp: 1779169198391 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda +sha256: 3900f9f2dbbf4129cf3ad6acf4e4b6f7101390b53843591c53b00f034343bc4d +md5: 11b3379b191f63139e29c0d19dee24cd +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libpng >=1.6.50,<1.7.0a0 +- libstdcxx >=14 +- libtiff >=4.7.1,<4.8.0a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-2-Clause +license_family: BSD +size: 355400 +timestamp: 1758489294972 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda +sha256: c0ef482280e38c71a08ad6d71448194b719630345b0c9c60744a2010e8a8e0cb +md5: da1b85b6a87e141f5140bb9924cecab0 +depends: +- __glibc >=2.17,<3.0.a0 +- ca-certificates +- libgcc >=14 +license: Apache-2.0 +license_family: Apache +size: 3167099 +timestamp: 1775587756857 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda +sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890 +md5: 4c06a92e74452cfa53623a81592e8934 +depends: +- python >=3.8 +- python +license: Apache-2.0 +license_family: APACHE +size: 91574 +timestamp: 1777103621679 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py314h8ec4b1a_0.conda +sha256: 123d8a7c16c88658b4f29e9f115a047598c941708dade74fbaff373a32dbec5e +md5: 76c4757c0ec9d11f969e8eb44899307b +depends: +- python +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- libtiff >=4.7.1,<4.8.0a0 +- openjpeg >=2.5.4,<3.0a0 +- libxcb >=1.17.0,<2.0a0 +- libwebp-base >=1.6.0,<2.0a0 +- zlib-ng >=2.3.3,<2.4.0a0 +- libjpeg-turbo >=3.1.2,<4.0a0 +- python_abi 3.14.* *_cp314 +- libfreetype >=2.14.3 +- libfreetype6 >=2.14.3 +- lcms2 >=2.18,<3.0a0 +- tk >=8.6.13,<8.7.0a0 +license: HPND +size: 1082797 +timestamp: 1775060059882 +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +sha256: c418d325359fc7a0074cea7f081ef1bce26e114d2da8a0154c5d27ecc87a08e7 +md5: 3e9427ee186846052e81fadde8ebe96a +depends: +- narwhals >=1.15.1 +- packaging +- python >=3.10 +constrains: +- ipywidgets >=7.6 +license: MIT +license_family: MIT +size: 5251872 +timestamp: 1772628857717 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.41.0-pyh58ad624_0.conda +sha256: 70fc56877c4a095ee658d61924d8019768fbae4a48437058d181fc94b0a7c4d8 +md5: 25a883fed9f1f3f21ff317a3e7c92ac4 +depends: +- polars-runtime-32 ==1.41.0 +- python >=3.10 +- python +constrains: +- numpy >=1.16.0 +- pyarrow >=7.0.0 +- fastexcel >=0.9 +- openpyxl >=3.0.0 +- xlsx2csv >=0.8.0 +- connectorx >=0.3.2 +- deltalake >=1.0.0 +- pyiceberg >=0.7.1 +- altair >=5.4.0 +- great_tables >=0.8.0 +- polars-runtime-32 ==1.41.0 +- polars-runtime-64 ==1.41.0 +- polars-runtime-compat ==1.41.0 +license: MIT +size: 539656 +timestamp: 1779630790562 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-32-1.41.0-py310h49dadd8_0.conda +noarch: python +sha256: e51ee3fe5259f2e115b2f78f8fbe3554e419c7c82b0c110878e12a5ff95ce3ab +md5: 7682765a1588e5ac887c99736d297c93 +depends: +- python +- __glibc >=2.17,<3.0.a0 +- libstdcxx >=14 +- libgcc >=14 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +size: 42578921 +timestamp: 1779630790562 +- conda: https://conda.anaconda.org/conda-forge/linux-64/polars-runtime-compat-1.41.0-py310hcbd6021_0.conda +noarch: python +sha256: 29c3831c92394af11d9f7d04882dda9479ffbb76a3d36ba155d52159d67805fa +md5: cb0b620c9914a07a9022cb8b183ea9ee +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +size: 41864944 +timestamp: 1779630722548 +- conda: https://conda.anaconda.org/conda-forge/linux-64/procps-ng-4.0.6-h18c060e_0.conda +sha256: 4ce2e1ee31a6217998f78c31ce7dc0a3e0557d9238b51d49dd20c52d467a126d +md5: f2c23a77b25efcad57d377b34bd84941 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-2.0-or-later AND LGPL-2.0-or-later +license_family: GPL +size: 593603 +timestamp: 1769710381284 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda +sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973 +md5: b3c17d95b5a10c6e64a21fa17573e70e +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=13 +license: MIT +license_family: MIT +size: 8252 +timestamp: 1726802366959 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +sha256: 58994e0d2ea8584cb399546e6f6896d771995e6121d1a7b6a2c9948388358932 +md5: e17be1016bcc3516827b836cd3e4d9dc +depends: +- python >=3.9 +- pyyaml >=5.0,<=7.0 +license: MIT +license_family: MIT +size: 14645 +timestamp: 1736766960536 +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda +sha256: 69700e31165df070e9716315e042196aa92525dae5deb5107785847ab9f4189f +md5: 729843edafc0899b3348bd3f19525b9d +depends: +- typing-inspection >=0.4.2 +- typing_extensions >=4.14.1 +- python >=3.10 +- annotated-types >=0.6.0 +- pydantic-core ==2.46.4 +- python +license: MIT +license_family: MIT +size: 346511 +timestamp: 1778103405862 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py314h2e6c369_0.conda +sha256: 802e216c39f1359aed60823b6e11d8ccd812b0ae1c81ae5ac1c81f99446409ab +md5: 0c96993dbeadf3a277cf757b9f1c9412 +depends: +- python +- typing-extensions >=4.6.0,!=4.7.0 +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 1895020 +timestamp: 1778084229247 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda +sha256: cf70b2f5ad9ae472b71235e5c8a736c9316df3705746de419b59d442e8348e86 +md5: 16c18772b340887160c79a6acc022db0 +depends: +- python >=3.10 +license: BSD-2-Clause +license_family: BSD +size: 893031 +timestamp: 1774796815820 +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 +md5: 461219d1a5bd61342293efa2c0c90eac +depends: +- __unix +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 21085 +timestamp: 1733217331982 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.5-habeac84_100_cp314.conda +build_number: 100 +sha256: 55eed9bf2a3f6e90311276f0834737fe7c2d9ec3e5e2e557507858df4c7521e6 +md5: da92e59ff92f2d5ede4f612af20f583f +depends: +- __glibc >=2.17,<3.0.a0 +- bzip2 >=1.0.8,<2.0a0 +- ld_impl_linux-64 >=2.36.1 +- libexpat >=2.8.0,<3.0a0 +- libffi >=3.5.2,<3.6.0a0 +- libgcc >=14 +- liblzma >=5.8.3,<6.0a0 +- libmpdec >=4.0.0,<5.0a0 +- libsqlite >=3.53.1,<4.0a0 +- libuuid >=2.42.1,<3.0a0 +- libzlib >=1.3.2,<2.0a0 +- ncurses >=6.6,<7.0a0 +- openssl >=3.5.6,<4.0a0 +- python_abi 3.14.* *_cp314 +- readline >=8.3,<9.0a0 +- tk >=8.6.13,<8.7.0a0 +- tzdata +- zstd >=1.5.7,<1.6.0a0 +license: Python-2.0 +size: 36745188 +timestamp: 1779236923603 +python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5 +md5: 130584ad9f3a513cdd71b1fdc1244e9c +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 27848 +timestamp: 1772388605021 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.5-h4df99d1_100.conda +sha256: 41dd7da285d71d519257fa7dacb1cae060d5ebfaa5f92cba5994899d2978e943 +md5: 41954747ba952ec4b01e16c2c9e8d8ff +depends: +- cpython 3.14.5.* +- python_abi * *_cp314 +license: Python-2.0 +size: 50212 +timestamp: 1779236703009 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +sha256: e17bf63a30aec33432f1ead86e15e9febde9fc40a7f869c0e766be8d2db44170 +md5: 310259a5b03ff02289d7705f39e2b1d2 +depends: +- kaleido-core 0.2.1.* +- python >=3.5 +license: MIT +license_family: MIT +size: 18320 +timestamp: 1615204747600 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +build_number: 8 +sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 +md5: 0539938c55b6b1a59b560e843ad864a4 +constrains: +- python 3.14.* *_cp314 +license: BSD-3-Clause +license_family: BSD +size: 6989 +timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda +sha256: b318fb070c7a1f89980ef124b80a0b5ccf3928143708a85e0053cde0169c699d +md5: 2035f68f96be30dc60a5dfd7452c7941 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- yaml >=0.2.5,<0.3.0a0 +license: MIT +license_family: MIT +size: 202391 +timestamp: 1770223462836 +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda +sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 +md5: d7d95fc8287ea7bf33e0e7116d2b95ec +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-3.0-only +license_family: GPL +size: 345073 +timestamp: 1765813471974 +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +sha256: 0577eedfb347ff94d0f2fa6c052c502989b028216996b45c7f21236f25864414 +md5: 870293df500ca7e18bedefa5838a22ab +depends: +- attrs >=22.2.0 +- python >=3.10 +- rpds-py >=0.7.0 +- typing_extensions >=4.4.0 +- python +license: MIT +license_family: MIT +size: 51788 +timestamp: 1760379115194 +- conda: https://conda.anaconda.org/conda-forge/linux-64/regex-2026.5.9-py314h5bd0f2a_0.conda +sha256: c7a4aca4977c15c82d053b06cbc676460974c1b25757cfeea8a9a2497ac911f8 +md5: 9dd235b6ac69a0198080dac39f9891aa +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +license: Apache-2.0 AND CNRI-Python +license_family: PSF +size: 413611 +timestamp: 1778374155646 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda +sha256: 1715246b19c9f85ee022933b4845f2fc14ac9184981b7b7d9b728bec8e9588da +md5: 4a85203c1d80c1059086ae860836ffb9 +depends: +- python >=3.10 +- certifi >=2023.5.7 +- charset-normalizer >=2,<4 +- idna >=2.5,<4 +- urllib3 >=1.26,<3 +- python +constrains: +- chardet >=3.0.2,<8 +license: Apache-2.0 +license_family: APACHE +size: 68709 +timestamp: 1778851103479 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda +sha256: 3d6ba2c0fcdac3196ba2f0615b4104e532525ffa1335b50a2878be5ff488814a +md5: 0242025a3c804966bf71aa04eee82f66 +depends: +- markdown-it-py >=2.2.0 +- pygments >=2.13.0,<3.0.0 +- python >=3.10 +- typing_extensions >=4.0.0,<5.0.0 +- python +license: MIT +license_family: MIT +size: 208577 +timestamp: 1775991661559 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +sha256: aa3fcb167321bae51998de2e94d199109c9024f25a5a063cb1c28d8f1af33436 +md5: 0c20a8ebcddb24a45da89d5e917e6cb9 +depends: +- python >=3.10 +- rich >=12 +- click >=8 +- typing-extensions >=4 +- __unix +- python +license: MIT +license_family: MIT +size: 64356 +timestamp: 1769850479089 +- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py314h2e6c369_0.conda +sha256: e53b0cbf3b324eaa03ca1fe1a688fdf4ab42cea9c25270b0a7307d8aaaa4f446 +md5: c1c368b5437b0d1a68f372ccf01cb133 +depends: +- python +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 376121 +timestamp: 1764543122774 +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +sha256: 7c65782d2511738e62c70462e89d65da4fa54d5a7e47c46667bcd27a59f81876 +md5: 472239e4eb7b5a84bb96b3ed7e3a596a +depends: +- colormath >=3.0.0 +- python >=3.9 +license: MIT +license_family: MIT +size: 22284 +timestamp: 1735770589188 +- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda +sha256: d167fa92781bcdcd3b9aaa6bb1cd50c5b108f6190c170098a118b5cf5df2f881 +md5: 8e0b8654ead18e50af552e54b5a08a61 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libsqlite 3.53.1 h0c1763c_0 +- libzlib >=1.3.2,<2.0a0 +- ncurses >=6.6,<7.0a0 +- readline >=8.3,<9.0a0 +license: blessing +size: 205399 +timestamp: 1777986477546 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tiktoken-0.12.0-py314h67fec18_3.conda +sha256: 7e395d67fd249d901beb1ae269057763c0d8c3ee5f7a348694bdb16d158a37d9 +md5: d705f9d8a1185a2b01cced191177a028 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- regex >=2022.1.18 +- requests >=2.26.0 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 939648 +timestamp: 1764028306357 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda +sha256: cafeec44494f842ffeca27e9c8b0c27ed714f93ac77ddadc6aaf726b5554ebac +md5: cffd3bdd58090148f4cfcd831f4b26ab +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +constrains: +- xorg-libx11 >=1.8.12,<2.0a0 +license: TCL +license_family: BSD +size: 3301196 +timestamp: 1769460227866 +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6 +md5: e5ce43272193b38c2e9037446c1d9206 +depends: +- python >=3.10 +- __unix +- python +license: MPL-2.0 and MIT +size: 94132 +timestamp: 1770153424136 +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda +sha256: 59d7851d32fddb5b510272e6557aa982edeb927d349648dac27f5bf01d18bb26 +md5: 4460f039b7dedf15f7df086446ca75ae +depends: +- typing_extensions >=4.14.0 +- python >=3.10 +- importlib-metadata >=3.6 +- python +constrains: +- pytest >=7 +license: MIT +license_family: MIT +size: 38297 +timestamp: 1778779291237 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c +md5: edd329d7d3a4ab45dcf905899a7a6115 +depends: +- typing_extensions ==4.15.0 pyhcf101f3_0 +license: PSF-2.0 +license_family: PSF +size: 91383 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda +sha256: 8b90d2f19f9458b8c58a55e1fcdc1d90c1603a847a47654d8a454549413ba60a +md5: 53f5409c5cfd6c5a66417d68e3f0a864 +depends: +- python >=3.10 +- typing_extensions >=4.12.0 +- python +license: MIT +license_family: MIT +size: 20935 +timestamp: 1777105465795 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 +md5: 0caa1af407ecff61170c9437a808404d +depends: +- python >=3.10 +- python +license: PSF-2.0 +license_family: PSF +size: 51692 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c +md5: ad659d0a2b3e47e38d829aa8cad2d610 +license: LicenseRef-Public-Domain +size: 119135 +timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda +sha256: feff959a816f7988a0893201aa9727bbb7ee1e9cec2c4f0428269b489eb93fb4 +md5: cbb88288f74dbe6ada1c6c7d0a97223e +depends: +- backports.zstd >=1.0.0 +- brotli-python >=1.2.0 +- h2 >=4,<5 +- pysocks >=1.5.6,<2.0,!=1.5.7 +- python >=3.10 +license: MIT +license_family: MIT +size: 103560 +timestamp: 1778188657149 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda +sha256: 6bc6ab7a90a5d8ac94c7e300cc10beb0500eeba4b99822768ca2f2ef356f731b +md5: b2895afaf55bf96a8c8282a2e47a5de0 +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 15321 +timestamp: 1762976464266 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda +sha256: 25d255fb2eef929d21ff660a0c687d38a6d2ccfbcbf0cc6aa738b12af6e9d142 +md5: 1dafce8548e38671bea82e3f5c6ce22f +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 20591 +timestamp: 1762976546182 +- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda +sha256: 6d9ea2f731e284e9316d95fa61869fe7bbba33df7929f82693c121022810f4ad +md5: a77f85f77be52ff59391544bfe73390a +depends: +- libgcc >=14 +- __glibc >=2.17,<3.0.a0 +license: MIT +license_family: MIT +size: 85189 +timestamp: 1753484064210 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda +sha256: 210bd31c22bb88f5e2a167df24c95bb5f152b2ada7502f9b8c49d1f5366db423 +md5: ba3dcdc8584155c97c648ae9c044b7a3 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 24190 +timestamp: 1779159948016 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda +sha256: ea4e50c465d70236408cb0bfe0115609fd14db1adcd8bd30d8918e0291f8a75f +md5: 2aadb0d17215603a82a2a6b0afd9a4cb +depends: +- __glibc >=2.17,<3.0.a0 +- libgcc >=14 +- libstdcxx >=14 +license: Zlib +license_family: Other +size: 122618 +timestamp: 1770167931827 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda +sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 +md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 +depends: +- __glibc >=2.17,<3.0.a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-3-Clause +license_family: BSD +size: 601375 +timestamp: 1764777111296 diff --git a/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt new file mode 100644 index 0000000..3d5b93d --- /dev/null +++ b/modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt @@ -0,0 +1,1476 @@ + +version: 6 +environments: +default: +channels: +- url: https://conda.anaconda.org/conda-forge/ +- url: https://conda.anaconda.org/bioconda/ +- url: https://conda.anaconda.org/bioconda/ +options: +pypi-prerelease-mode: if-necessary-or-explicit +packages: +linux-aarch64: +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.5.0-py314h680f03e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.5.20-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.0-pyhc90fa1f_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.5-py314hd8ed1ab_100.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.8.1-hfae3067_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.18.0-hba86a56_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.19.1-h9d5b58d_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-7_haddc8a3_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-7_hd72aa62_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.4.1-he30d5cf_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-7_h88aeb00_openblas.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.33-pthreads_h9d3fd7e_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.58-h1abf092_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.53.1-h022381a_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_19.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.1-h1022ec0_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.21.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.6-py314he1698a1_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.2-h546c87b_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.2.0-py314hac3e5ec_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.41.0-pyh58ad624_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.41.0-py310h32c7c23_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.41.0-py310hc0e61be_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.46.4-py314h451b6cc_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.5-hfd9ac0a_100_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.5-h4df99d1_100.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.5.9-py314h51f160d_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.53.1-he8854b5_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda +build_number: 20 +sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068 +md5: 468fd3bb9e1f671d36c2cbc677e56f1d +depends: +- libgomp >=7.5.0 +constrains: +- openmp_impl <0.0a0 +license: BSD-3-Clause +license_family: BSD +size: 28926 +timestamp: 1770939656741 +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda +sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661 +md5: aaa2a381ccc56eac91d63b6c1240312f +depends: +- cpython +- python-gil +license: MIT +license_family: MIT +size: 8191 +timestamp: 1744137672556 +- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda +sha256: e0ea1ba78fbb64f17062601edda82097fcf815012cf52bb704150a2668110d48 +md5: 2934f256a8acfe48f6ebb4fce6cde29c +depends: +- python >=3.9 +- typing-extensions >=4.0.0 +license: MIT +license_family: MIT +size: 18074 +timestamp: 1733247158254 +- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda +sha256: 1b6124230bb4e571b1b9401537ecff575b7b109cc3a21ee019f65e083b8399ab +md5: c6b0543676ecb1fb2d7643941fe375f2 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 64927 +timestamp: 1773935801332 +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.5.0-py314h680f03e_0.conda +noarch: generic +sha256: a1c97297e867776760489537bc5ae36fa83a154be30e3b79385a39ca4cb058fe +md5: 1133126d840e75287d83947be3fc3e71 +depends: +- python >=3.14 +license: BSD-3-Clause AND MIT AND EPL-2.0 +size: 7533 +timestamp: 1778594057496 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda +sha256: 5a5b0cdcd7ed89c6a8fb830924967f6314a2b71944bc1ebc2c105781ba97aa75 +md5: a1b5c571a0923a205d663d8678df4792 +depends: +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +constrains: +- libbrotlicommon 1.2.0 he30d5cf_1 +license: MIT +license_family: MIT +size: 373193 +timestamp: 1764017486851 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda +sha256: b3495077889dde6bb370938e7db82be545c73e8589696ad0843a32221520ad4c +md5: 840d8fc0d7b3209be93080bc20e07f2d +depends: +- libgcc >=14 +license: bzip2-1.0.6 +license_family: BSD +size: 192412 +timestamp: 1771350241232 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda +sha256: 9812a303a1395e1dafbd92e5bc8a1ff6013bcbba0a09c7f03a8d23e43560aa9b +md5: 489b8e97e666c93f68fdb35c3c9b957f +depends: +- __unix +license: ISC +size: 129868 +timestamp: 1779289852439 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.5.20-pyhd8ed1ab_0.conda +sha256: 645655a3510e38e625da136595f3f16f2130c3263630cc3bc8f60f619ddbe490 +md5: 9fefff2f745ea1cc2ef15211a20c054a +depends: +- python >=3.10 +license: ISC +size: 134201 +timestamp: 1779285131141 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda +sha256: 3f9483d62ce24ecd063f8a5a714448445dc8d9e201147c46699fc0033e824457 +md5: a9167b9571f3baa9d448faa2139d1089 +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 58872 +timestamp: 1775127203018 +- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.0-pyhc90fa1f_0.conda +sha256: 99ab8ef815c4520cce3a7482c2513f377c14348206857661d84c76a55e030f97 +md5: 003767c47f1f0a474c4de268b57839c3 +depends: +- __unix +- python +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 104631 +timestamp: 1779108494556 +- conda: https://conda.anaconda.org/conda-forge/noarch/coloredlogs-15.0.1-pyhd8ed1ab_4.conda +sha256: 8021c76eeadbdd5784b881b165242db9449783e12ce26d6234060026fd6a8680 +md5: b866ff7007b934d564961066c8195983 +depends: +- humanfriendly >=9.1 +- python >=3.9 +license: MIT +license_family: MIT +size: 43758 +timestamp: 1733928076798 +- conda: https://conda.anaconda.org/conda-forge/noarch/colormath-3.0.0-pyhd8ed1ab_4.conda +sha256: 59c9e29800b483b390467f90e82b0da3a4fbf0612efe1c90813fca232780e160 +md5: 071cf7b0ce333c81718b054066c15102 +depends: +- networkx >=2.0 +- numpy +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 39326 +timestamp: 1735759976140 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.5-py314hd8ed1ab_100.conda +noarch: generic +sha256: 777882d2685f368417f31bbe1b28f73687fc6c8f6a5768bda20ffeefa6b07f5b +md5: a749029ce5d0632a913db19d17f944ab +depends: +- python >=3.14,<3.15.0a0 +- python_abi * *_cp314 +license: Python-2.0 +size: 50212 +timestamp: 1779236682725 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.8.1-hfae3067_0.conda +sha256: a9cd5eb1700e11cc39acc36630a2d72a4e317943bd7c5695cd8804419f04ff42 +md5: 89f0247b3cea528d8ad1a6664a313153 +depends: +- libexpat 2.8.1 hfae3067_0 +- libgcc >=14 +license: MIT +license_family: MIT +size: 140114 +timestamp: 1779278679081 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 +sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b +md5: 0c96522c6bdaed4b1566d11387caaf45 +license: BSD-3-Clause +license_family: BSD +size: 397370 +timestamp: 1566932522327 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 +sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c +md5: 34893075a5c9e55cdafac56607368fc6 +license: OFL-1.1 +license_family: Other +size: 96530 +timestamp: 1620479909603 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 +sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 +md5: 4d59c254e01d9cde7957100457e2d5fb +license: OFL-1.1 +license_family: Other +size: 700814 +timestamp: 1620479612257 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda +sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14 +md5: 49023d73832ef61042f6a237cb2687e7 +license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 +license_family: Other +size: 1620504 +timestamp: 1727511233259 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.18.0-hba86a56_0.conda +sha256: 1805f4ab3d9e1734a5a17abccc2cb0fdade51d4d5f29bdc410600ea0115ec050 +md5: b660d59a9d0fb3297327418624acaec3 +depends: +- libexpat >=2.8.1,<3.0a0 +- libfreetype >=2.14.3 +- libfreetype6 >=2.14.3 +- libgcc >=14 +- libuuid >=2.42.1,<3.0a0 +- libzlib >=1.3.2,<2.0a0 +license: MIT +license_family: MIT +size: 293348 +timestamp: 1779421661332 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda +sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333 +md5: a7970cd949a077b7cb9696379d338681 +depends: +- font-ttf-ubuntu +- font-ttf-inconsolata +- font-ttf-dejavu-sans-mono +- font-ttf-source-code-pro +license: BSD-3-Clause +license_family: BSD +size: 4059 +timestamp: 1762351264405 +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda +sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3 +md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9 +depends: +- python >=3.10 +- hyperframe >=6.1,<7 +- hpack >=4.1,<5 +- python +license: MIT +license_family: MIT +size: 95967 +timestamp: 1756364871835 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda +sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba +md5: 0a802cb9888dd14eeefc611f05c40b6e +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 30731 +timestamp: 1737618390337 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanfriendly-10.0-pyh707e725_8.conda +sha256: fa2071da7fab758c669e78227e6094f6b3608228740808a6de5d6bce83d9e52d +md5: 7fe569c10905402ed47024fc481bb371 +depends: +- __unix +- python >=3.9 +license: MIT +license_family: MIT +size: 73563 +timestamp: 1733928021866 +- conda: https://conda.anaconda.org/conda-forge/noarch/humanize-4.15.0-pyhd8ed1ab_0.conda +sha256: 6c4343b376d0b12a4c75ab992640970d36c933cad1fd924f6a1181fa91710e80 +md5: daddf757c3ecd6067b9af1df1f25d89e +depends: +- python >=3.10 +license: MIT +license_family: MIT +size: 67994 +timestamp: 1766267728652 +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda +sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8 +md5: 8e6923fc12f1fe8f8c4e5c9f343256ac +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 17397 +timestamp: 1737618427549 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda +sha256: 3d25f9f6f7ab3e1ce6429fc8c8aae0335cf446692e715068488536d220cc43de +md5: 1b9083b7f00609605d1483dbc6071a81 +depends: +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 62642 +timestamp: 1779294335905 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda +sha256: 43e2a5497cad1598ff88a3e69f69bc88b7b8f141fa63c60eab5db296317318b8 +md5: ffc17e785d64e12fc311af9184221839 +depends: +- python >=3.10 +- zipp >=3.20 +- python +license: Apache-2.0 +size: 34766 +timestamp: 1779714582554 +- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda +sha256: fc9ca7348a4f25fed2079f2153ecdcf5f9cf2a0bc36c4172420ca09e1849df7b +md5: 04558c96691bed63104678757beb4f8d +depends: +- markupsafe >=2.0 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 120685 +timestamp: 1764517220861 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda +sha256: db973a37d75db8e19b5f44bbbdaead0c68dde745407f281e2a7fe4db74ec51d7 +md5: ada41c863af263cc4c5fcbaff7c3e4dc +depends: +- attrs >=22.2.0 +- jsonschema-specifications >=2023.3.6 +- python >=3.10 +- referencing >=0.28.4 +- rpds-py >=0.25.0 +- python +license: MIT +license_family: MIT +size: 82356 +timestamp: 1767839954256 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda +sha256: 0a4f3b132f0faca10c89fdf3b60e15abb62ded6fa80aebfc007d05965192aa04 +md5: 439cd0f567d697b20a8f45cb70a1005a +depends: +- python >=3.10 +- referencing >=0.31.0 +- python +license: MIT +license_family: MIT +size: 19236 +timestamp: 1757335715225 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/kaleido-core-0.2.1-he5a581e_0.tar.bz2 +sha256: d3c7f4797566e6f983d16c2a87063a18e4b2d819a66230190a21584d70042755 +md5: 4f0d284f5d11e04277b552eb1c172c7f +depends: +- __glibc >=2.17,<3.0.a0 +- expat >=2.2.10,<3.0.0a0 +- fontconfig +- fonts-conda-forge +- libgcc-ng >=9.3.0 +- mathjax 2.7.* +- nspr >=4.29,<5.0a0 +- nss >=3.62,<4.0a0 +- sqlite >=3.34.0,<4.0a0 +license: MIT +license_family: MIT +size: 65750397 +timestamp: 1615199465742 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.19.1-h9d5b58d_0.conda +sha256: 1e5f68e4b36a0e1a278c6dc026bc3d7775518a15832cbc9d7fc1c0e4c47784b1 +md5: b1f8bee3c53a6d2c103fb4a1ae44f5c4 +depends: +- libgcc >=14 +- libjpeg-turbo >=3.1.4.1,<4.0a0 +- libtiff >=4.7.1,<4.8.0a0 +license: MIT +license_family: MIT +size: 296899 +timestamp: 1778079402392 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda +sha256: 7abd913d81a9bf00abb699e8987966baa2065f5132e37e815f92d90fc6bba530 +md5: a21644fc4a83da26452a718dc9468d5f +depends: +- zstd >=1.5.7,<1.6.0a0 +constrains: +- binutils_impl_linux-aarch64 2.45.1 +license: GPL-3.0-only +license_family: GPL +size: 875596 +timestamp: 1774197520746 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.1.0-h52b7260_0.conda +sha256: 8957fd460c1c132c8031f65fd5f56ec3807fd71b7cab2c5e2b0937b13404ab36 +md5: d13423b06447113a90b5b1366d4da171 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: Apache-2.0 +license_family: Apache +size: 240444 +timestamp: 1773114901155 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-7_haddc8a3_openblas.conda +build_number: 7 +sha256: f27ba323c2f1e1731b5e880fe520f178f55047f25be94f77e649605b2343c066 +md5: e8d07b777f6ff1fab69665336561910b +depends: +- libopenblas >=0.3.33,<0.3.34.0a0 +- libopenblas >=0.3.33,<1.0a0 +constrains: +- liblapack 3.11.0 7*_openblas +- libcblas 3.11.0 7*_openblas +- mkl <2027 +- blas 2.307 openblas +- liblapacke 3.11.0 7*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18696 +timestamp: 1778489796402 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-7_hd72aa62_openblas.conda +build_number: 7 +sha256: c8f0192362966df0828419f042d6f94c079e5df00ad6bd05b5e84c12b42f8cc7 +md5: 90ac57b82c055faa9be25031864b7d8f +depends: +- libblas 3.11.0 7_haddc8a3_openblas +constrains: +- liblapack 3.11.0 7*_openblas +- blas 2.307 openblas +- liblapacke 3.11.0 7*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18664 +timestamp: 1778489802790 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.25-h1af38f5_0.conda +sha256: 48814b73bd462da6eed2e697e30c060ae16af21e9fbed30d64feaf0aad9da392 +md5: a9138815598fe6b91a1d6782ca657b0c +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 71117 +timestamp: 1761979776756 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_0.conda +sha256: 1fc392b997c6ee2bd3226a7cd870d0edbcbb367e25f9f18dd4a7025fced6efc0 +md5: 513dd884361dfb8a554298ed69b58823 +depends: +- libgcc >=14 +constrains: +- expat 2.8.1.* +license: MIT +license_family: MIT +size: 77140 +timestamp: 1779278671302 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda +sha256: 3df4c539449aabc3443bbe8c492c01d401eea894603087fca2917aa4e1c2dea9 +md5: 2f364feefb6a7c00423e80dcb12db62a +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 55952 +timestamp: 1769456078358 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype-2.14.3-h8af1aa0_0.conda +sha256: 752e4f66283d7deb4c6fd47d88df644d8daa2aaa825a54f3bf350a625190192a +md5: a229e22d4d8814a07702b0919d8e6701 +depends: +- libfreetype6 >=2.14.3 +license: GPL-2.0-only OR FTL +size: 8125 +timestamp: 1774301094057 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libfreetype6-2.14.3-hdae7a39_0.conda +sha256: 8e6b27fe4eec4c2fa7b7769a21973734c8dba1de80086fb0213e58375ac09f4c +md5: b99ed99e42dafb27889483b3098cace7 +depends: +- libgcc >=14 +- libpng >=1.6.55,<1.7.0a0 +- libzlib >=1.3.2,<2.0a0 +constrains: +- freetype >=2.14.3 +license: GPL-2.0-only OR FTL +size: 422941 +timestamp: 1774301093473 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_19.conda +sha256: 4592b096e553f67799ae70d4b6167eeda3ec74587d68c7aecbf4e7b1df136681 +md5: f35b3f52d0a2ec4ffe3c89ba135cdb9a +depends: +- _openmp_mutex >=4.5 +constrains: +- libgomp 15.2.0 h8acb6b2_19 +- libgcc-ng ==15.2.0=*_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 622462 +timestamp: 1778268755949 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_19.conda +sha256: 1137f93f477f56199ded24117430045a0c02cbe8b10031beac3b9ad2138539d3 +md5: 770cf892e5530f43e63cadc673e85653 +depends: +- libgcc 15.2.0 h8acb6b2_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27738 +timestamp: 1778268759211 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_19.conda +sha256: e5ad94be72634233510b33ba792a3339921bd468f0b8bc6961ea05eded251d9b +md5: c7a5b5decf969ead5ecada83654164cf +depends: +- libgfortran5 15.2.0 h1b7bec0_19 +constrains: +- libgfortran-ng ==15.2.0=*_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 27728 +timestamp: 1778268784621 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_19.conda +sha256: af8e9bdcaa77f133a8ee4c1ef57ef564d9c45aa262abf9f5ef9b50eb99d96407 +md5: 779dbb494de6d3d6477cab52eb34285a +depends: +- libgcc >=15.2.0 +constrains: +- libgfortran 15.2.0 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 1487244 +timestamp: 1778268767295 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_19.conda +sha256: 2370ef0ffcbae5bede3c4bf136add4abc257245eb91f724c99bb4a43116c5a83 +md5: c5e8a379c4a2ec2aea4ba22758c001d9 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 587387 +timestamp: 1778268674393 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libjpeg-turbo-3.1.4.1-he30d5cf_0.conda +sha256: e97ec2af5f09f8f6ea8ecd550055c95ae80fae22015fcfadaa94eafe025c9ccc +md5: a85ba48648f6868016f2741fd9170250 +depends: +- libgcc >=14 +constrains: +- jpeg <0.0.0a +license: IJG AND BSD-3-Clause AND Zlib +size: 693143 +timestamp: 1775962625956 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-7_h88aeb00_openblas.conda +build_number: 7 +sha256: 20b38a0156200ac65f597bf0a93914c565435f2cc58b1042581854231a99ac35 +md5: 5899cbd743cc74fd655c1ed2af7120f3 +depends: +- libblas 3.11.0 7_haddc8a3_openblas +constrains: +- libcblas 3.11.0 7*_openblas +- blas 2.307 openblas +- liblapacke 3.11.0 7*_openblas +license: BSD-3-Clause +license_family: BSD +size: 18685 +timestamp: 1778489809140 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_0.conda +sha256: d61962b9cd54c3554361550203c64d5b65b71e3058a285b66e4b04b9769f0a5c +md5: 76298a9e6d71ee6e832a8d0d7373b261 +depends: +- libgcc >=14 +constrains: +- xz 5.8.3.* +license: 0BSD +size: 126102 +timestamp: 1775828008518 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda +sha256: 57c0dd12d506e84541c4e877898bd2a59cca141df493d34036f18b2751e0a453 +md5: 7b9813e885482e3ccb1fa212b86d7fd0 +depends: +- libgcc >=14 +license: BSD-2-Clause +license_family: BSD +size: 114056 +timestamp: 1769482343003 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.33-pthreads_h9d3fd7e_0.conda +sha256: b018ecfb05e75a8eea3f21f6b5c5c2a54b5178bdcf19e2e2df2735740214a8c8 +md5: 58a66cd95e9692f08abe89f55a6f3f12 +depends: +- libgcc >=14 +- libgfortran +- libgfortran5 >=14.3.0 +constrains: +- openblas >=0.3.33,<0.3.34.0a0 +license: BSD-3-Clause +license_family: BSD +size: 5121336 +timestamp: 1776993423004 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.58-h1abf092_0.conda +sha256: 483eaa53da40a6a3e558709d9f7b1ca388735364ae21a1ba58cf942514649c92 +md5: f51503ac45a4888bce71af9027a2ecc9 +depends: +- libgcc >=14 +- libzlib >=1.3.2,<2.0a0 +license: zlib-acknowledgement +size: 341202 +timestamp: 1776315188425 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.53.1-h022381a_0.conda +sha256: ad03b7d8e4d08001f0df88ee7a56108bb35bae4795a42b9a04cc1abfa822bd07 +md5: 2ec1119217d8f0d086e9a62f3cb0e5ea +depends: +- libgcc >=14 +- libzlib >=1.3.2,<2.0a0 +license: blessing +size: 955361 +timestamp: 1777986487553 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_19.conda +sha256: 1dadc45e599f510dd5f97141dddcdbb9844d9f1430c1f3a38075cf1c58f87b4e +md5: 543fbc8d71f2a0baf04cf88ce96cb8bb +depends: +- libgcc 15.2.0 h8acb6b2_19 +constrains: +- libstdcxx-ng ==15.2.0=*_19 +license: GPL-3.0-only WITH GCC-exception-3.1 +license_family: GPL +size: 5546559 +timestamp: 1778268777463 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.1-hdb009f0_1.conda +sha256: 7ff79470db39e803e21b8185bc8f19c460666d5557b1378d1b1e857d929c6b39 +md5: 8c6fd84f9c87ac00636007c6131e457d +depends: +- lerc >=4.0.0,<5.0a0 +- libdeflate >=1.25,<1.26.0a0 +- libgcc >=14 +- libjpeg-turbo >=3.1.0,<4.0a0 +- liblzma >=5.8.1,<6.0a0 +- libstdcxx >=14 +- libwebp-base >=1.6.0,<2.0a0 +- libzlib >=1.3.1,<2.0a0 +- zstd >=1.5.7,<1.6.0a0 +license: HPND +size: 488407 +timestamp: 1762022048105 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.1-h1022ec0_0.conda +sha256: 1628839b062e98b2192857d4da8496ac9ac6b0dbb77aa040c34efc9192c440ee +md5: 0f42f9fedd2a32d798de95a7f65c456f +depends: +- libgcc >=14 +license: BSD-3-Clause +license_family: BSD +size: 43453 +timestamp: 1779118526838 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.6.0-ha2e29f5_0.conda +sha256: b03700a1f741554e8e5712f9b06dd67e76f5301292958cd3cb1ac8c6fdd9ed25 +md5: 24e92d0942c799db387f5c9d7b81f1af +depends: +- libgcc >=14 +constrains: +- libwebp 1.6.0 +license: BSD-3-Clause +license_family: BSD +size: 359496 +timestamp: 1752160685488 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda +sha256: 461cab3d5650ac6db73a367de5c8eca50363966e862dcf60181d693236b1ae7b +md5: cd14ee5cca2464a425b1dbfc24d90db2 +depends: +- libgcc >=13 +- pthread-stubs +- xorg-libxau >=1.0.11,<2.0a0 +- xorg-libxdmcp +license: MIT +license_family: MIT +size: 397493 +timestamp: 1727280745441 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda +sha256: eb111e32e5a7313a5bf799c7fb2419051fa2fe7eff74769fac8d5a448b309f7f +md5: 502006882cf5461adced436e410046d1 +constrains: +- zlib 1.3.2 *_2 +license: Zlib +license_family: Other +size: 69833 +timestamp: 1774072605429 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-3.10.2-pyhcf101f3_0.conda +sha256: 20e0892592a3e7c683e3d66df704a9425d731486a97c34fc56af4da1106b2b6b +md5: ba0a9221ce1063f31692c07370d062f3 +depends: +- importlib-metadata >=4.4 +- python >=3.10 +- python +license: BSD-3-Clause +license_family: BSD +size: 85893 +timestamp: 1770694658918 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda +sha256: 0c4c35376fe920714390d46e4b8d31c876d65f18e1655899e0763ec25f2a902f +md5: 6d03368f2b2b0a5fb6839df53b2eb5e0 +depends: +- mdurl >=0.1,<1 +- python >=3.10 +license: MIT +license_family: MIT +size: 69017 +timestamp: 1778169663339 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/markupsafe-3.0.3-py314hb76de3f_1.conda +sha256: 383c188496d13a55658c06e61e7d4cdff2c9f9d5a0648769fca8250bece7e0ef +md5: e5de3c36dd548b35ff2a8aa49208dcb3 +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +constrains: +- jinja2 >=3.0.0 +license: BSD-3-Clause +license_family: BSD +size: 27913 +timestamp: 1772446407659 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/mathjax-2.7.7-h8af1aa0_3.tar.bz2 +sha256: 8fd4c79d6eda3d4cba73783114305a53a154ada4d1e334d4e02cb3521429599b +md5: 7b08314a6867a9d5648a1c3265e9eb8e +license: Apache-2.0 +license_family: Apache +size: 22257008 +timestamp: 1662784555011 +- conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda +sha256: 78c1bbe1723449c52b7a9df1af2ee5f005209f67e40b6e1d3c7619127c43b1c7 +md5: 592132998493b3ff25fd7479396e8351 +depends: +- python >=3.9 +license: MIT +license_family: MIT +size: 14465 +timestamp: 1733255681319 +- conda: https://conda.anaconda.org/bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda +sha256: e86033aa55a9e915e2d0957e770bdb81e3feb26a227d1adb17f9d6c528da6a71 +md5: cdb20309681ba3ce8f52c110e214d4f3 +depends: +- click +- coloredlogs +- humanize +- importlib-metadata +- jinja2 >=3.0.0 +- jsonschema +- markdown +- natsort +- numpy +- packaging +- pillow >=10.2.0 +- plotly >=5.18 +- polars >=1.34.0 +- polars-runtime-compat >=1.34.0 +- pyaml-env +- pydantic >=2.7.1 +- python >=3.9,!=3.14.1 +- python-dotenv +- python-kaleido 0.2.1 +- pyyaml >=4 +- requests +- rich >=10 +- rich-click +- spectra >=0.0.10 +- tiktoken +- tqdm +- typeguard >=4 +license: GPL-3.0-or-later +license_family: GPL3 +size: 4282188 +timestamp: 1779465338806 +- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.21.2-pyhcf101f3_0.conda +sha256: 70f43d62450927d51673eecd8823e14f5b3cfebdb43cda1d502eba97162bab42 +md5: 6687827c332121727ce383919e1ec8c2 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 284323 +timestamp: 1778929680962 +- conda: https://conda.anaconda.org/conda-forge/noarch/natsort-8.4.0-pyhcf101f3_2.conda +sha256: aeb1548eb72e4f198e72f19d242fb695b35add2ac7b2c00e0d83687052867680 +md5: e941e85e273121222580723010bd4fa2 +depends: +- python >=3.9 +- python +license: MIT +license_family: MIT +size: 39262 +timestamp: 1770905275632 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda +sha256: 369db85c5cd8d99dde364ce70725d76511d9c8199e5b820c740414091bf5bcca +md5: b2a43456aa56fe80c2477a5094899eff +depends: +- libgcc >=14 +license: X11 AND BSD-3-Clause +size: 960036 +timestamp: 1777422174534 +- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda +sha256: f6a82172afc50e54741f6f84527ef10424326611503c64e359e25a19a8e4c1c6 +md5: a2c1eeadae7a309daed9d62c96012a2b +depends: +- python >=3.11 +- python +constrains: +- numpy >=1.25 +- scipy >=1.11.2 +- matplotlib-base >=3.8 +- pandas >=2.0 +license: BSD-3-Clause +license_family: BSD +size: 1587439 +timestamp: 1765215107045 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nspr-4.38-h3ad9384_0.conda +sha256: 78a06e89285fef242e272998b292c1e621e3ee3dd4fba62ec014e503c7ec118f +md5: 6dd4f07147774bf720075a210f8026b9 +depends: +- libgcc >=14 +- libstdcxx >=14 +license: MPL-2.0 +license_family: MOZILLA +size: 235140 +timestamp: 1762350120355 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nss-3.118-h544fa81_0.conda +sha256: 48942696889367ffd448f8dccfc080fb7e130b9938a4a3b6b20ef8e6af856463 +md5: 4540f9570d12db2150f42ba036154552 +depends: +- libgcc >=14 +- libsqlite >=3.51.0,<4.0a0 +- libstdcxx >=14 +- libzlib >=1.3.1,<2.0a0 +- nspr >=4.38,<5.0a0 +license: MPL-2.0 +license_family: MOZILLA +size: 2061869 +timestamp: 1763490303490 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.6-py314he1698a1_0.conda +sha256: 04af718b911f8a3a0095481c7e283aa081a175fe626eccbc2c5644bcb2aba9a1 +md5: 8b173772deea177b45d2a133b509b3f7 +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- python_abi 3.14.* *_cp314 +- libblas >=3.9.0,<4.0a0 +- liblapack >=3.9.0,<4.0a0 +- libcblas >=3.9.0,<4.0a0 +constrains: +- numpy-base <0a0 +license: BSD-3-Clause +license_family: BSD +size: 8002900 +timestamp: 1779169206742 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.4-h5da879a_0.conda +sha256: bd1bc8bdde5e6c5cbac42d462b939694e40b59be6d0698f668515908640c77b8 +md5: cea962410e327262346d48d01f05936c +depends: +- libgcc >=14 +- libpng >=1.6.50,<1.7.0a0 +- libstdcxx >=14 +- libtiff >=4.7.1,<4.8.0a0 +- libzlib >=1.3.1,<2.0a0 +license: BSD-2-Clause +license_family: BSD +size: 392636 +timestamp: 1758489353577 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.2-h546c87b_0.conda +sha256: 348cb74c1530ac241215d047ef65d134cf797af935c97a68655319362b7e6a01 +md5: 3b129669089e4d6a5c6871dbb4669b99 +depends: +- ca-certificates +- libgcc >=14 +license: Apache-2.0 +license_family: Apache +size: 3706406 +timestamp: 1775589602258 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda +sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890 +md5: 4c06a92e74452cfa53623a81592e8934 +depends: +- python >=3.8 +- python +license: Apache-2.0 +license_family: APACHE +size: 91574 +timestamp: 1777103621679 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-12.2.0-py314hac3e5ec_0.conda +sha256: 96b26c2657275ffe84ab510edf0865e21999d791485d12794edd4a71b837beb6 +md5: 87d58d103b47c4a8567b3d7666647684 +depends: +- python +- libgcc >=14 +- python 3.14.* *_cp314 +- openjpeg >=2.5.4,<3.0a0 +- libxcb >=1.17.0,<2.0a0 +- libwebp-base >=1.6.0,<2.0a0 +- zlib-ng >=2.3.3,<2.4.0a0 +- python_abi 3.14.* *_cp314 +- lcms2 >=2.18,<3.0a0 +- tk >=8.6.13,<8.7.0a0 +- libtiff >=4.7.1,<4.8.0a0 +- libjpeg-turbo >=3.1.2,<4.0a0 +- libfreetype >=2.14.3 +- libfreetype6 >=2.14.3 +license: HPND +size: 1062080 +timestamp: 1775060067775 +- conda: https://conda.anaconda.org/conda-forge/noarch/plotly-6.6.0-pyhd8ed1ab_0.conda +sha256: c418d325359fc7a0074cea7f081ef1bce26e114d2da8a0154c5d27ecc87a08e7 +md5: 3e9427ee186846052e81fadde8ebe96a +depends: +- narwhals >=1.15.1 +- packaging +- python >=3.10 +constrains: +- ipywidgets >=7.6 +license: MIT +license_family: MIT +size: 5251872 +timestamp: 1772628857717 +- conda: https://conda.anaconda.org/conda-forge/noarch/polars-1.41.0-pyh58ad624_0.conda +sha256: 70fc56877c4a095ee658d61924d8019768fbae4a48437058d181fc94b0a7c4d8 +md5: 25a883fed9f1f3f21ff317a3e7c92ac4 +depends: +- polars-runtime-32 ==1.41.0 +- python >=3.10 +- python +constrains: +- numpy >=1.16.0 +- pyarrow >=7.0.0 +- fastexcel >=0.9 +- openpyxl >=3.0.0 +- xlsx2csv >=0.8.0 +- connectorx >=0.3.2 +- deltalake >=1.0.0 +- pyiceberg >=0.7.1 +- altair >=5.4.0 +- great_tables >=0.8.0 +- polars-runtime-32 ==1.41.0 +- polars-runtime-64 ==1.41.0 +- polars-runtime-compat ==1.41.0 +license: MIT +size: 539656 +timestamp: 1779630790562 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-32-1.41.0-py310h32c7c23_0.conda +noarch: python +sha256: d903b774ec09189e164207328aac157eee82fed8cc5c9ace46aeb5d1c15cb5b3 +md5: 8c08c506ed1ea8ce0ca37af5e918c58d +depends: +- python +- libgcc >=14 +- libstdcxx >=14 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +size: 38704429 +timestamp: 1779630794932 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/polars-runtime-compat-1.41.0-py310hc0e61be_0.conda +noarch: python +sha256: 101696adff43a654146376c62ef9611bf7946b95fa46f604fe247d77eefc6267 +md5: 65b73e4260677ee5162bdbb252e28e06 +depends: +- python +- libstdcxx >=14 +- libgcc >=14 +- _python_abi3_support 1.* +- cpython >=3.10 +constrains: +- __glibc >=2.17 +license: MIT +size: 38651498 +timestamp: 1779630714016 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/procps-ng-4.0.6-h1779866_0.conda +sha256: e9cbcbc94e151ada3d6dc365380aaaf591f65012c16d9a2abaea4b9b90adc402 +md5: ab7288cc39545556d1bc5e71ab2df9a9 +depends: +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-2.0-or-later AND LGPL-2.0-or-later +license_family: GPL +size: 636733 +timestamp: 1769712412683 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda +sha256: 977dfb0cb3935d748521dd80262fe7169ab82920afd38ed14b7fee2ea5ec01ba +md5: bb5a90c93e3bac3d5690acf76b4a6386 +depends: +- libgcc >=13 +license: MIT +license_family: MIT +size: 8342 +timestamp: 1726803319942 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-env-1.2.2-pyhd8ed1ab_0.conda +sha256: 58994e0d2ea8584cb399546e6f6896d771995e6121d1a7b6a2c9948388358932 +md5: e17be1016bcc3516827b836cd3e4d9dc +depends: +- python >=3.9 +- pyyaml >=5.0,<=7.0 +license: MIT +license_family: MIT +size: 14645 +timestamp: 1736766960536 +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda +sha256: 69700e31165df070e9716315e042196aa92525dae5deb5107785847ab9f4189f +md5: 729843edafc0899b3348bd3f19525b9d +depends: +- typing-inspection >=0.4.2 +- typing_extensions >=4.14.1 +- python >=3.10 +- annotated-types >=0.6.0 +- pydantic-core ==2.46.4 +- python +license: MIT +license_family: MIT +size: 346511 +timestamp: 1778103405862 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pydantic-core-2.46.4-py314h451b6cc_0.conda +sha256: 1a7c6b18e404c13c4d959888ecb48a9ed9de0e41be2872932b83a35278088df0 +md5: 9c3ace6aba6df14b943256095ac1281e +depends: +- python +- typing-extensions >=4.6.0,!=4.7.0 +- libgcc >=14 +- python 3.14.* *_cp314 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 1780773 +timestamp: 1778084251775 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda +sha256: cf70b2f5ad9ae472b71235e5c8a736c9316df3705746de419b59d442e8348e86 +md5: 16c18772b340887160c79a6acc022db0 +depends: +- python >=3.10 +license: BSD-2-Clause +license_family: BSD +size: 893031 +timestamp: 1774796815820 +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda +sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 +md5: 461219d1a5bd61342293efa2c0c90eac +depends: +- __unix +- python >=3.9 +license: BSD-3-Clause +license_family: BSD +size: 21085 +timestamp: 1733217331982 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.5-hfd9ac0a_100_cp314.conda +build_number: 100 +sha256: d37bad5447365346166c72950ea8f49689aa49cecc1b0623d00458427627b8df +md5: d956e09feb806f5974675ce92ad81d45 +depends: +- bzip2 >=1.0.8,<2.0a0 +- ld_impl_linux-aarch64 >=2.36.1 +- libexpat >=2.8.0,<3.0a0 +- libffi >=3.5.2,<3.6.0a0 +- libgcc >=14 +- liblzma >=5.8.3,<6.0a0 +- libmpdec >=4.0.0,<5.0a0 +- libsqlite >=3.53.1,<4.0a0 +- libuuid >=2.42.1,<3.0a0 +- libzlib >=1.3.2,<2.0a0 +- ncurses >=6.6,<7.0a0 +- openssl >=3.5.6,<4.0a0 +- python_abi 3.14.* *_cp314 +- readline >=8.3,<9.0a0 +- tk >=8.6.13,<8.7.0a0 +- tzdata +- zstd >=1.5.7,<1.6.0a0 +license: Python-2.0 +size: 37510439 +timestamp: 1779236267040 +python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dotenv-1.2.2-pyhcf101f3_0.conda +sha256: 74e417a768f59f02a242c25e7db0aa796627b5bc8c818863b57786072aeb85e5 +md5: 130584ad9f3a513cdd71b1fdc1244e9c +depends: +- python >=3.10 +license: BSD-3-Clause +license_family: BSD +size: 27848 +timestamp: 1772388605021 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.5-h4df99d1_100.conda +sha256: 41dd7da285d71d519257fa7dacb1cae060d5ebfaa5f92cba5994899d2978e943 +md5: 41954747ba952ec4b01e16c2c9e8d8ff +depends: +- cpython 3.14.5.* +- python_abi * *_cp314 +license: Python-2.0 +size: 50212 +timestamp: 1779236703009 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-kaleido-0.2.1-pyhd8ed1ab_0.tar.bz2 +sha256: e17bf63a30aec33432f1ead86e15e9febde9fc40a7f869c0e766be8d2db44170 +md5: 310259a5b03ff02289d7705f39e2b1d2 +depends: +- kaleido-core 0.2.1.* +- python >=3.5 +license: MIT +license_family: MIT +size: 18320 +timestamp: 1615204747600 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda +build_number: 8 +sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 +md5: 0539938c55b6b1a59b560e843ad864a4 +constrains: +- python 3.14.* *_cp314 +license: BSD-3-Clause +license_family: BSD +size: 6989 +timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda +sha256: 496b5e65dfdd0aaaaa5de0dcaaf3bceea00fcb4398acf152f89e567c82ec1046 +md5: 9ae2c92975118058bd720e9ba2bb7c58 +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +- yaml >=0.2.5,<0.3.0a0 +license: MIT +license_family: MIT +size: 195678 +timestamp: 1770223441816 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda +sha256: fe695f9d215e9a2e3dd0ca7f56435ab4df24f5504b83865e3d295df36e88d216 +md5: 3d49cad61f829f4f0e0611547a9cda12 +depends: +- libgcc >=14 +- ncurses >=6.5,<7.0a0 +license: GPL-3.0-only +license_family: GPL +size: 357597 +timestamp: 1765815673644 +- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda +sha256: 0577eedfb347ff94d0f2fa6c052c502989b028216996b45c7f21236f25864414 +md5: 870293df500ca7e18bedefa5838a22ab +depends: +- attrs >=22.2.0 +- python >=3.10 +- rpds-py >=0.7.0 +- typing_extensions >=4.4.0 +- python +license: MIT +license_family: MIT +size: 51788 +timestamp: 1760379115194 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/regex-2026.5.9-py314h51f160d_0.conda +sha256: 05ef55f09f31eabd0a205f6b065e13fc746675f41924620977692ef0ffe5aad8 +md5: 34ed7bc9febeca70f55b757ca09c354d +depends: +- libgcc >=14 +- python >=3.14,<3.15.0a0 +- python >=3.14,<3.15.0a0 *_cp314 +- python_abi 3.14.* *_cp314 +license: Apache-2.0 AND CNRI-Python +license_family: PSF +size: 409780 +timestamp: 1778374195988 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda +sha256: 1715246b19c9f85ee022933b4845f2fc14ac9184981b7b7d9b728bec8e9588da +md5: 4a85203c1d80c1059086ae860836ffb9 +depends: +- python >=3.10 +- certifi >=2023.5.7 +- charset-normalizer >=2,<4 +- idna >=2.5,<4 +- urllib3 >=1.26,<3 +- python +constrains: +- chardet >=3.0.2,<8 +license: Apache-2.0 +license_family: APACHE +size: 68709 +timestamp: 1778851103479 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda +sha256: 3d6ba2c0fcdac3196ba2f0615b4104e532525ffa1335b50a2878be5ff488814a +md5: 0242025a3c804966bf71aa04eee82f66 +depends: +- markdown-it-py >=2.2.0 +- pygments >=2.13.0,<3.0.0 +- python >=3.10 +- typing_extensions >=4.0.0,<5.0.0 +- python +license: MIT +license_family: MIT +size: 208577 +timestamp: 1775991661559 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-click-1.9.7-pyh8f84b5b_0.conda +sha256: aa3fcb167321bae51998de2e94d199109c9024f25a5a063cb1c28d8f1af33436 +md5: 0c20a8ebcddb24a45da89d5e917e6cb9 +depends: +- python >=3.10 +- rich >=12 +- click >=8 +- typing-extensions >=4 +- __unix +- python +license: MIT +license_family: MIT +size: 64356 +timestamp: 1769850479089 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rpds-py-0.30.0-py314h02b7a91_0.conda +sha256: a587240f16eac7c6a80f9585cef679cd1cb9a287b8dfcdd36dcef1f7e7db15dc +md5: e7f6ed9e60043bb5cbcc527764897f0d +depends: +- python +- libgcc >=14 +- python_abi 3.14.* *_cp314 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 376332 +timestamp: 1764543345455 +- conda: https://conda.anaconda.org/conda-forge/noarch/spectra-0.0.11-pyhd8ed1ab_2.conda +sha256: 7c65782d2511738e62c70462e89d65da4fa54d5a7e47c46667bcd27a59f81876 +md5: 472239e4eb7b5a84bb96b3ed7e3a596a +depends: +- colormath >=3.0.0 +- python >=3.9 +license: MIT +license_family: MIT +size: 22284 +timestamp: 1735770589188 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/sqlite-3.53.1-he8854b5_0.conda +sha256: 27467e4bfb0681546f149718c33b806fec078185fbaa6a4d17d440bc8f56185c +md5: 46009bdca2315a99e0a3a7d0ba1af3b9 +depends: +- libgcc >=14 +- libsqlite 3.53.1 h022381a_0 +- libzlib >=1.3.2,<2.0a0 +- ncurses >=6.6,<7.0a0 +- readline >=8.3,<9.0a0 +license: blessing +size: 209964 +timestamp: 1777986493350 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tiktoken-0.12.0-py314h6a36e60_3.conda +sha256: c1da41c79262b27efa168407cfecc47b20270e5fc071a8307f95a2c85fb94170 +md5: 55bf7b559202236157b14323b40f19e6 +depends: +- libgcc >=14 +- libstdcxx >=14 +- python >=3.14,<3.15.0a0 +- python_abi 3.14.* *_cp314 +- regex >=2022.1.18 +- requests >=2.26.0 +constrains: +- __glibc >=2.17 +license: MIT +license_family: MIT +size: 914402 +timestamp: 1764030357702 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda +sha256: e25c314b52764219f842b41aea2c98a059f06437392268f09b03561e4f6e5309 +md5: 7fc6affb9b01e567d2ef1d05b84aa6ed +depends: +- libgcc >=14 +- libzlib >=1.3.1,<2.0a0 +constrains: +- xorg-libx11 >=1.8.12,<2.0a0 +license: TCL +license_family: BSD +size: 3368666 +timestamp: 1769464148928 +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda +sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6 +md5: e5ce43272193b38c2e9037446c1d9206 +depends: +- python >=3.10 +- __unix +- python +license: MPL-2.0 and MIT +size: 94132 +timestamp: 1770153424136 +- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda +sha256: 59d7851d32fddb5b510272e6557aa982edeb927d349648dac27f5bf01d18bb26 +md5: 4460f039b7dedf15f7df086446ca75ae +depends: +- typing_extensions >=4.14.0 +- python >=3.10 +- importlib-metadata >=3.6 +- python +constrains: +- pytest >=7 +license: MIT +license_family: MIT +size: 38297 +timestamp: 1778779291237 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda +sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c +md5: edd329d7d3a4ab45dcf905899a7a6115 +depends: +- typing_extensions ==4.15.0 pyhcf101f3_0 +license: PSF-2.0 +license_family: PSF +size: 91383 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda +sha256: 8b90d2f19f9458b8c58a55e1fcdc1d90c1603a847a47654d8a454549413ba60a +md5: 53f5409c5cfd6c5a66417d68e3f0a864 +depends: +- python >=3.10 +- typing_extensions >=4.12.0 +- python +license: MIT +license_family: MIT +size: 20935 +timestamp: 1777105465795 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda +sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 +md5: 0caa1af407ecff61170c9437a808404d +depends: +- python >=3.10 +- python +license: PSF-2.0 +license_family: PSF +size: 51692 +timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda +sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c +md5: ad659d0a2b3e47e38d829aa8cad2d610 +license: LicenseRef-Public-Domain +size: 119135 +timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda +sha256: feff959a816f7988a0893201aa9727bbb7ee1e9cec2c4f0428269b489eb93fb4 +md5: cbb88288f74dbe6ada1c6c7d0a97223e +depends: +- backports.zstd >=1.0.0 +- brotli-python >=1.2.0 +- h2 >=4,<5 +- pysocks >=1.5.6,<2.0,!=1.5.7 +- python >=3.10 +license: MIT +license_family: MIT +size: 103560 +timestamp: 1778188657149 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-he30d5cf_1.conda +sha256: e9f6e931feeb2f40e1fdbafe41d3b665f1ab6cb39c5880a1fcf9f79a3f3c84a5 +md5: 1c246e1105000c3660558459e2fd6d43 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 16317 +timestamp: 1762977521691 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-he30d5cf_1.conda +sha256: 128d72f36bcc8d2b4cdbec07507542e437c7d67f677b7d77b71ed9eeac7d6df1 +md5: bff06dcde4a707339d66d45d96ceb2e2 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 21039 +timestamp: 1762979038025 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda +sha256: 66265e943f32ce02396ad214e27cb35f5b0490b3bd4f064446390f9d67fa5d88 +md5: 032d8030e4a24fe1f72c74423a46fb88 +depends: +- libgcc >=14 +license: MIT +license_family: MIT +size: 88088 +timestamp: 1753484092643 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda +sha256: 210bd31c22bb88f5e2a167df24c95bb5f152b2ada7502f9b8c49d1f5366db423 +md5: ba3dcdc8584155c97c648ae9c044b7a3 +depends: +- python >=3.10 +- python +license: MIT +license_family: MIT +size: 24190 +timestamp: 1779159948016 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-ng-2.3.3-ha7cb516_1.conda +sha256: 638a3a41a4fbfed52d3c60c8ef5a3693b3f12a5b1a3f58fa29f5698d0a0702e2 +md5: f731af71c723065d91b4c01bb822641b +depends: +- libgcc >=14 +- libstdcxx >=14 +license: Zlib +license_family: Other +size: 121046 +timestamp: 1770167944449 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda +sha256: 569990cf12e46f9df540275146da567d9c618c1e9c7a0bc9d9cfefadaed20b75 +md5: c3655f82dcea2aa179b291e7099c1fcc +depends: +- libzlib >=1.3.1,<2.0a0 +license: BSD-3-Clause +license_family: BSD +size: 614429 +timestamp: 1764777145593 diff --git a/modules/nf-core/multiqc/environment.yml b/modules/nf-core/multiqc/environment.yml index 812fc4c..7a970e2 100644 --- a/modules/nf-core/multiqc/environment.yml +++ b/modules/nf-core/multiqc/environment.yml @@ -4,4 +4,4 @@ channels: - conda-forge - bioconda dependencies: - - bioconda::multiqc=1.29 + - bioconda::multiqc=1.35 diff --git a/modules/nf-core/multiqc/main.nf b/modules/nf-core/multiqc/main.nf index 0ac3c36..c4bc715 100644 --- a/modules/nf-core/multiqc/main.nf +++ b/modules/nf-core/multiqc/main.nf @@ -1,24 +1,21 @@ process MULTIQC { + tag "${meta.id}" label 'process_single' conda "${moduleDir}/environment.yml" - container "${ workflow.containerEngine == 'singularity' && !task.ext.singularity_pull_docker_container ? - 'https://depot.galaxyproject.org/singularity/multiqc:1.29--pyhdfd78af_0' : - 'biocontainers/multiqc:1.29--pyhdfd78af_0' }" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e346f4f6080eadf1253505e6ff09ef004454fc18e8d672006fd7b222cc412e/data' + : 'community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc'}" input: - path multiqc_files, stageAs: "?/*" - path(multiqc_config) - path(extra_multiqc_config) - path(multiqc_logo) - path(replace_names) - path(sample_names) + tuple val(meta), path(multiqc_files, stageAs: "?/*"), path(multiqc_config, stageAs: "?/*"), path(multiqc_logo), path(replace_names), path(sample_names) output: - path "*multiqc_report.html", emit: report - path "*_data" , emit: data - path "*_plots" , optional:true, emit: plots - path "versions.yml" , emit: versions + tuple val(meta), path("*.html"), emit: report + tuple val(meta), path("*_data"), emit: data + tuple val(meta), path("*_plots"), emit: plots, optional: true + // MultiQC should not push its versions to the `versions` topic. Its input depends on the versions topic to be resolved thus outputting to the topic will let the pipeline hang forever + tuple val("${task.process}"), val('multiqc'), eval('multiqc --version | sed "s/.* //g"'), emit: versions when: task.ext.when == null || task.ext.when @@ -26,38 +23,28 @@ process MULTIQC { script: def args = task.ext.args ?: '' def prefix = task.ext.prefix ? "--filename ${task.ext.prefix}.html" : '' - def config = multiqc_config ? "--config $multiqc_config" : '' - def extra_config = extra_multiqc_config ? "--config $extra_multiqc_config" : '' + def config = multiqc_config ? multiqc_config instanceof List ? "--config ${multiqc_config.join(' --config ')}" : "--config ${multiqc_config}" : "" def logo = multiqc_logo ? "--cl-config 'custom_logo: \"${multiqc_logo}\"'" : '' def replace = replace_names ? "--replace-names ${replace_names}" : '' def samples = sample_names ? "--sample-names ${sample_names}" : '' """ multiqc \\ --force \\ - $args \\ - $config \\ - $prefix \\ - $extra_config \\ - $logo \\ - $replace \\ - $samples \\ + ${args} \\ + ${config} \\ + ${prefix} \\ + ${logo} \\ + ${replace} \\ + ${samples} \\ . - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS """ stub: """ mkdir multiqc_data + touch multiqc_data/.stub mkdir multiqc_plots + touch multiqc_plots/.stub touch multiqc_report.html - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - multiqc: \$( multiqc --version | sed -e "s/multiqc, version //g" ) - END_VERSIONS """ } diff --git a/modules/nf-core/multiqc/meta.yml b/modules/nf-core/multiqc/meta.yml index ce30eb7..27ce18d 100644 --- a/modules/nf-core/multiqc/meta.yml +++ b/modules/nf-core/multiqc/meta.yml @@ -1,6 +1,6 @@ name: multiqc -description: Aggregate results from bioinformatics analyses across many samples into - a single report +description: Aggregate results from bioinformatics analyses across many samples + into a single report keywords: - QC - bioinformatics tools @@ -12,74 +12,91 @@ tools: It's a general use tool, perfect for summarising the output from numerous bioinformatics tools. homepage: https://multiqc.info/ documentation: https://multiqc.info/docs/ - licence: ["GPL-3.0-or-later"] + licence: + - "GPL-3.0-or-later" identifier: biotools:multiqc input: - - multiqc_files: - type: file - description: | - List of reports / files recognised by MultiQC, for example the html and zip output of FastQC - ontologies: [] - - multiqc_config: - type: file - description: Optional config yml for MultiQC - pattern: "*.{yml,yaml}" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML - - extra_multiqc_config: - type: file - description: Second optional config yml for MultiQC. Will override common sections - in multiqc_config. - pattern: "*.{yml,yaml}" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML - - multiqc_logo: - type: file - description: Optional logo file for MultiQC - pattern: "*.{png}" - ontologies: [] - - replace_names: - type: file - description: | - Optional two-column sample renaming file. First column a set of - patterns, second column a set of corresponding replacements. Passed via - MultiQC's `--replace-names` option. - pattern: "*.{tsv}" - ontologies: - - edam: http://edamontology.org/format_3475 # TSV - - sample_names: - type: file - description: | - Optional TSV file with headers, passed to the MultiQC --sample_names - argument. - pattern: "*.{tsv}" - ontologies: - - edam: http://edamontology.org/format_3475 # TSV -output: - report: - - "*multiqc_report.html": + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - multiqc_files: type: file - description: MultiQC report file - pattern: "multiqc_report.html" + description: | + List of reports / files recognised by MultiQC, for example the html and zip output of FastQC ontologies: [] - data: - - "*_data": - type: directory - description: MultiQC data dir - pattern: "multiqc_data" - plots: - - "*_plots": + - multiqc_config: + type: file + description: Optional config yml for MultiQC + pattern: "*.{yml,yaml}" + ontologies: + - edam: http://edamontology.org/format_3750 + - multiqc_logo: type: file - description: Plots created by MultiQC - pattern: "*_data" + description: Optional logo file for MultiQC + pattern: "*.{png}" ontologies: [] - versions: - - versions.yml: + - replace_names: + type: file + description: | + Optional two-column sample renaming file. First column a set of + patterns, second column a set of corresponding replacements. Passed via + MultiQC's `--replace-names` option. + pattern: "*.{tsv}" + ontologies: + - edam: http://edamontology.org/format_3475 + - sample_names: type: file - description: File containing software versions - pattern: "versions.yml" + description: | + Optional TSV file with headers, passed to the MultiQC --sample_names + argument. + pattern: "*.{tsv}" ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - edam: http://edamontology.org/format_3475 +output: + report: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*.html": + type: file + description: MultiQC report file + pattern: ".html" + ontologies: [] + data: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_data": + type: directory + description: MultiQC data dir + pattern: "multiqc_data" + plots: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'sample1', single_end:false ] + - "*_plots": + type: file + description: Plots created by MultiQC + pattern: "*_plots" + ontologies: [] + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - multiqc: + type: string + description: The tool name + - multiqc --version | sed "s/.* //g": + type: eval + description: The expression to obtain the version of the tool authors: - "@abhi18av" - "@bunop" @@ -90,3 +107,27 @@ maintainers: - "@bunop" - "@drpatelh" - "@jfy133" +containers: + conda: + linux/amd64: + lock_file: modules/nf-core/multiqc/.conda-lock/linux_amd64-bd-c17fb751507e9dfc_1.txt + linux/arm64: + lock_file: modules/nf-core/multiqc/.conda-lock/linux_arm64-bd-5c84a5000a226ab5_1.txt + docker: + linux/amd64: + name: community.wave.seqera.io/library/multiqc:1.35--c17fb751507e9dfc + build_id: bd-c17fb751507e9dfc_1 + scan_id: sc-3b1b3932f9846892_1 + linux/arm64: + name: community.wave.seqera.io/library/multiqc:1.35--5c84a5000a226ab5 + build_id: bd-5c84a5000a226ab5_1 + scan_id: sc-0d39df41e9737bbd_1 + singularity: + linux/amd64: + name: oras://community.wave.seqera.io/library/multiqc:1.35--c680f2aea25ccec2 + build_id: bd-c680f2aea25ccec2_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e346f4f6080eadf1253505e6ff09ef004454fc18e8d672006fd7b222cc412e/data + linux/arm64: + name: oras://community.wave.seqera.io/library/multiqc:1.35--c0468833d65b2f81 + build_id: bd-c0468833d65b2f81_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/e4/e48aa28aebc881254a499b24c3e1ce77b8df1b85a5432699ed6f72eb17ac7fb5/data diff --git a/modules/nf-core/multiqc/tests/custom_prefix.config b/modules/nf-core/multiqc/tests/custom_prefix.config new file mode 100644 index 0000000..b30b135 --- /dev/null +++ b/modules/nf-core/multiqc/tests/custom_prefix.config @@ -0,0 +1,5 @@ +process { + withName: 'MULTIQC' { + ext.prefix = "custom_prefix" + } +} diff --git a/modules/nf-core/multiqc/tests/main.nf.test b/modules/nf-core/multiqc/tests/main.nf.test index 33316a7..4cbdb95 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test +++ b/modules/nf-core/multiqc/tests/main.nf.test @@ -15,25 +15,84 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_single") } - ) + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() + } + } + + test("sarscov2 single-end [fastqc] - custom prefix") { + config "./custom_prefix.config" + + when { + process { + """ + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) + """ + } } + then { + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() + } } test("sarscov2 single-end [fastqc] [config]") { @@ -41,23 +100,85 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = Channel.of(file("https://github.com/nf-core/tools/raw/dev/nf_core/pipeline-template/assets/multiqc_config.yml", checkIfExists: true)) - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true), + [], + [], + [] + ]) """ } } then { - assertAll( - { assert process.success }, - { assert process.out.report[0] ==~ ".*/multiqc_report.html" }, - { assert process.out.data[0] ==~ ".*/multiqc_data" }, - { assert snapshot(process.out.versions).match("multiqc_versions_config") } - ) + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() + } + } + + test("sarscov2 single-end [fastqc] [multiple configs]") { + + when { + process { + """ + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [ + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true), + file("https://raw.githubusercontent.com/nf-core/seqinspector/1.0.0/assets/multiqc_config.yml", checkIfExists: true) + ], + [], + [], + [] + ]) + """ + } + } + + then { + assert process.success + assert snapshot( + sanitizeOutput(process.out).collectEntries { key, val -> + if (key == "data") { + return [key, val.collect { [path(it[1]).list().collect { file(it.toString()).name }] }] + } + else if (key == "plots") { + return [key, val.collect { [ + "pdf", + path("${it[1]}/pdf").list().collect { file(it.toString()).name }, + "png", + path("${it[1]}/png").list().collect { file(it.toString()).name }, + "svg", + path("${it[1]}/svg").list().collect { file(it.toString()).name }] }] + } + else if (key == "report") { + return [key, file(val[0][1].toString()).name] + } + return [key, val] + } + ).match() } } @@ -68,25 +189,23 @@ nextflow_process { when { process { """ - input[0] = Channel.of(file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true)) - input[1] = [] - input[2] = [] - input[3] = [] - input[4] = [] - input[5] = [] + input[0] = channel.of([ + [ id: 'FASTQC' ], + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastqc/test_fastqc.zip', checkIfExists: true), + [], + [], + [], + [] + ]) """ } } then { + assert process.success assertAll( - { assert process.success }, - { assert snapshot(process.out.report.collect { file(it).getName() } + - process.out.data.collect { file(it).getName() } + - process.out.plots.collect { file(it).getName() } + - process.out.versions ).match("multiqc_stub") } + { assert snapshot(sanitizeOutput(process.out)).match() } ) } - } } diff --git a/modules/nf-core/multiqc/tests/main.nf.test.snap b/modules/nf-core/multiqc/tests/main.nf.test.snap index 88e9057..4489921 100644 --- a/modules/nf-core/multiqc/tests/main.nf.test.snap +++ b/modules/nf-core/multiqc/tests/main.nf.test.snap @@ -1,41 +1,422 @@ { - "multiqc_versions_single": { + "sarscov2 single-end [fastqc] [multiple configs]": { "content": [ - [ - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" - ] + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.35" + ] + ] + } ], + "timestamp": "2026-03-17T16:15:42.577775492", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.2" - }, - "timestamp": "2025-05-22T11:50:41.182332996" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, - "multiqc_stub": { + "sarscov2 single-end [fastqc]": { "content": [ - [ - "multiqc_report.html", - "multiqc_data", - "multiqc_plots", - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" - ] + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_software_versions.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.35" + ] + ] + } ], + "timestamp": "2026-03-17T16:21:17.072841555", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.2" - }, - "timestamp": "2025-05-22T11:51:22.448739369" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } }, - "multiqc_versions_config": { + "sarscov2 single-end [fastqc] - stub": { "content": [ - [ - "versions.yml:md5,c1fe644a37468f6dae548d98bc72c2c1" - ] + { + "data": [ + [ + { + "id": "FASTQC" + }, + [ + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "plots": [ + [ + { + "id": "FASTQC" + }, + [ + ".stub:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "report": [ + [ + { + "id": "FASTQC" + }, + "multiqc_report.html:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.35" + ] + ] + } ], + "timestamp": "2026-02-26T15:14:39.789193051", "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.2" - }, - "timestamp": "2025-05-22T11:51:06.198928424" + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "sarscov2 single-end [fastqc] [config]": { + "content": [ + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "multiqc_report.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.35" + ] + ] + } + ], + "timestamp": "2026-03-17T16:15:30.372239611", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } + }, + "sarscov2 single-end [fastqc] - custom prefix": { + "content": [ + { + "data": [ + [ + [ + "fastqc-status-check-heatmap.txt", + "fastqc_overrepresented_sequences_plot.txt", + "fastqc_per_base_n_content_plot.txt", + "fastqc_per_base_sequence_quality_plot.txt", + "fastqc_per_sequence_gc_content_plot_Counts.txt", + "fastqc_per_sequence_gc_content_plot_Percentages.txt", + "fastqc_per_sequence_quality_scores_plot.txt", + "fastqc_sequence_counts_plot.txt", + "fastqc_sequence_duplication_levels_plot.txt", + "fastqc_sequence_length_distribution_plot.txt", + "fastqc_top_overrepresented_sequences_table.txt", + "llms-full.txt", + "multiqc.log", + "multiqc.parquet", + "multiqc_citations.txt", + "multiqc_data.json", + "multiqc_fastqc.txt", + "multiqc_general_stats.txt", + "multiqc_software_versions.txt", + "multiqc_sources.txt" + ] + ] + ], + "plots": [ + [ + "pdf", + [ + "fastqc-status-check-heatmap.pdf", + "fastqc_overrepresented_sequences_plot.pdf", + "fastqc_per_base_n_content_plot.pdf", + "fastqc_per_base_sequence_quality_plot.pdf", + "fastqc_per_sequence_gc_content_plot_Counts.pdf", + "fastqc_per_sequence_gc_content_plot_Percentages.pdf", + "fastqc_per_sequence_quality_scores_plot.pdf", + "fastqc_sequence_counts_plot-cnt.pdf", + "fastqc_sequence_counts_plot-pct.pdf", + "fastqc_sequence_duplication_levels_plot.pdf", + "fastqc_sequence_length_distribution_plot.pdf", + "fastqc_top_overrepresented_sequences_table.pdf" + ], + "png", + [ + "fastqc-status-check-heatmap.png", + "fastqc_overrepresented_sequences_plot.png", + "fastqc_per_base_n_content_plot.png", + "fastqc_per_base_sequence_quality_plot.png", + "fastqc_per_sequence_gc_content_plot_Counts.png", + "fastqc_per_sequence_gc_content_plot_Percentages.png", + "fastqc_per_sequence_quality_scores_plot.png", + "fastqc_sequence_counts_plot-cnt.png", + "fastqc_sequence_counts_plot-pct.png", + "fastqc_sequence_duplication_levels_plot.png", + "fastqc_sequence_length_distribution_plot.png", + "fastqc_top_overrepresented_sequences_table.png" + ], + "svg", + [ + "fastqc-status-check-heatmap.svg", + "fastqc_overrepresented_sequences_plot.svg", + "fastqc_per_base_n_content_plot.svg", + "fastqc_per_base_sequence_quality_plot.svg", + "fastqc_per_sequence_gc_content_plot_Counts.svg", + "fastqc_per_sequence_gc_content_plot_Percentages.svg", + "fastqc_per_sequence_quality_scores_plot.svg", + "fastqc_sequence_counts_plot-cnt.svg", + "fastqc_sequence_counts_plot-pct.svg", + "fastqc_sequence_duplication_levels_plot.svg", + "fastqc_sequence_length_distribution_plot.svg", + "fastqc_top_overrepresented_sequences_table.svg" + ] + ] + ], + "report": "custom_prefix.html", + "versions": [ + [ + "MULTIQC", + "multiqc", + "1.35" + ] + ] + } + ], + "timestamp": "2026-03-17T16:15:18.189023981", + "meta": { + "nf-test": "0.9.4", + "nextflow": "25.10.4" + } } } \ No newline at end of file diff --git a/modules/nf-core/multiqc/tests/nextflow.config b/modules/nf-core/multiqc/tests/nextflow.config index c537a6a..374dfef 100644 --- a/modules/nf-core/multiqc/tests/nextflow.config +++ b/modules/nf-core/multiqc/tests/nextflow.config @@ -1,5 +1,6 @@ process { withName: 'MULTIQC' { ext.prefix = null + ext.args = '-p' } } diff --git a/modules/nf-core/multiqc/tests/tags.yml b/modules/nf-core/multiqc/tests/tags.yml deleted file mode 100644 index bea6c0d..0000000 --- a/modules/nf-core/multiqc/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -multiqc: - - modules/nf-core/multiqc/** diff --git a/modules/nf-core/rgi/bwt/environment.yml b/modules/nf-core/rgi/bwt/environment.yml new file mode 100644 index 0000000..58b301d --- /dev/null +++ b/modules/nf-core/rgi/bwt/environment.yml @@ -0,0 +1,8 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::kma=1.6.11 + - bioconda::rgi=6.0.8 diff --git a/modules/nf-core/rgi/bwt/main.nf b/modules/nf-core/rgi/bwt/main.nf new file mode 100644 index 0000000..b92b667 --- /dev/null +++ b/modules/nf-core/rgi/bwt/main.nf @@ -0,0 +1,82 @@ +process RGI_BWT { + tag "${meta.id}" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/3f/3f452c8e124ee58ab6b26442d15401c57d471cb753f53921570dc484df4e7620/data' + : 'community.wave.seqera.io/library/rgi_kma:e905ecb8305e2609' }" + + input: + tuple val(meta), path(reads, arity: '1..2') + path card + path wildcard + + output: + tuple val(meta), path("*.json"), emit: json + tuple val(meta), path("*.txt"), emit: tsv + tuple val(meta), path("temp/"), emit: tmp + tuple val("${task.process}"), val('rgi'), eval("rgi main --version"), emit: versions_rgi, topic: versions + tuple val("${task.process}"), val('rgi-database'), eval("echo \$DB_VERSION"), emit: versions_db , topic: versions + tuple val("${task.process}"), val('kma'), eval("kma -v | sed 's/KMA-//'"), emit: versions_kma, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + // This customizes the command: rgi load + def args = task.ext.args ?: '' + // This customizes the command: rgi main + def args2 = task.ext.args2 ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def read_one = reads[0] + def read_two_cmd = reads.size() > 1 ? "--read_two ${reads[1]}" : "" + def load_wildcard = "" + + if (wildcard) { + load_wildcard = """ \\ + --wildcard_annotation ${wildcard}/wildcard_database_v\$DB_VERSION.fasta \\ + --wildcard_annotation_all_models ${wildcard}/wildcard_database_v\$DB_VERSION\\_all.fasta \\ + --wildcard_index ${wildcard}/wildcard/index-for-model-sequences.txt \\ + --amr_kmers ${wildcard}/wildcard/all_amr_61mers.txt \\ + --kmer_database ${wildcard}/wildcard/61_kmer_db.json \\ + --kmer_size 61 + """ + } + + """ + DB_VERSION=\$(ls ${card}/card_database_*_all.fasta | sed "s/${card}\\/card_database_v\\([0-9].*[0-9]\\).*/\\1/") + + rgi \\ + load \\ + ${args} \\ + --local \\ + --card_json ${card}/card.json \\ + --debug \\ + --card_annotation ${card}/card_database_v\$DB_VERSION.fasta \\ + --card_annotation_all_models ${card}/card_database_v\$DB_VERSION\\_all.fasta \\ + ${load_wildcard} + + rgi \\ + bwt \\ + ${args2} \\ + --local \\ + --threads ${task.cpus} \\ + --output_file ${prefix} \\ + --read_one ${read_one} \\ + ${read_two_cmd} + + mkdir temp/ + for FILE in *.xml *.fsa *.{nhr,nin,nsq} *.draft *.potentialGenes *{variant,rrna,protein,predictedGenes,overexpression,homolog}.json; do [[ -e \$FILE ]] && mv \$FILE temp/; done + + """ + + stub: + """ + mkdir -p temp + touch test.json + touch test.txt + + DB_VERSION=stub_version + """ +} diff --git a/modules/nf-core/rgi/bwt/meta.yml b/modules/nf-core/rgi/bwt/meta.yml new file mode 100644 index 0000000..f18ccd2 --- /dev/null +++ b/modules/nf-core/rgi/bwt/meta.yml @@ -0,0 +1,160 @@ +name: rgi_bwt +description: Predict antibiotic resistance from protein or nucleotide data +keywords: + - bacteria + - fasta + - antibiotic resistance +tools: + - rgi: + description: This tool provides a preliminary annotation of your DNA sequence(s) based upon the data available in The Comprehensive Antibiotic Resistance Database (CARD). Hits to genes tagged with Antibiotic Resistance ontology terms will be highlighted. As CARD expands to include more pathogens, genomes, plasmids, and ontology terms this tool will grow increasingly powerful in providing first-pass detection of antibiotic resistance associated genes. See license at CARD website. + homepage: https://card.mcmaster.ca + documentation: https://github.com/arpcard/rgi + tool_dev_url: https://github.com/arpcard/rgi + doi: "10.1093/nar/gkz935" + licence: + - "https://card.mcmaster.ca/about" + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - reads: + type: file + description: Single-end or paired-end nucleotide sequences in FASTQ or FASTA format + pattern: "*.{fastq,fastq.gz,fq,fq.gz,fasta,fasta.gz,fa,fa.gz,fna,fna.gz,faa,faa.gz}" + ontologies: + - edam: http://edamontology.org/format_1930 # FASTQ + - card: + type: directory + description: Directory containing the CARD database. This is expected to be the unarchived but otherwise unaltered download folder (see RGI documentation for download instructions). + pattern: "*/" + - wildcard: + type: directory + description: Directory containing the WildCARD database (optional). This is expected to be the unarchived but otherwise unaltered download folder (see RGI documentation for download instructions). + pattern: "*/" +output: + json: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.json": + type: file + description: JSON formatted file with RGI results + pattern: "*.{json}" + ontologies: + - edam: http://edamontology.org/format_3464 # JSON + tsv: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - "*.txt": + type: file + description: Tab-delimited file with RGI results + pattern: "*.{txt}" + ontologies: [] + tmp: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - temp/: + type: directory + description: Directory containing various intermediate files + pattern: "temp/" + versions_rgi: + - - ${task.process}: + type: string + description: The process the versions were collected from + - rgi: + type: string + description: The tool name + - rgi main --version: + type: eval + description: The version string returned by the command + versions_db: + - - ${task.process}: + type: string + description: The process the versions were collected from + - rgi-database: + type: string + description: The tool name + - echo \$DB_VERSION: + type: eval + description: The CARD database version string + versions_kma: + - - ${task.process}: + type: string + description: The process the versions were collected from + - kma: + type: string + description: The name of the tool + - kma -v | sed 's/KMA-//': + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The process the versions were collected from + - rgi: + type: string + description: The tool name + - rgi main --version: + type: eval + description: The version string returned by the command + - - ${task.process}: + type: string + description: The process the versions were collected from + - rgi-database: + type: string + description: The tool name + - echo \$DB_VERSION: + type: eval + description: The CARD database version string + - - ${task.process}: + type: string + description: The process the versions were collected from + - kma: + type: string + description: The name of the tool + - kma -v | sed 's/KMA-//': + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@vinisalazar" +maintainers: + - "@nickp60" + - "@vinisalazar" +containers: + docker: + linux/amd64: + name: community.wave.seqera.io/library/rgi_kma:e905ecb8305e2609 + build_id: bd-e905ecb8305e2609_1 + scan_id: sc-99ef62328a33452b_1 + linux/arm64: + name: community.wave.seqera.io/library/rgi_kma:fab5219836c1d880 + build_id: bd-fab5219836c1d880_1 + scan_id: sc-721854d12f10e7f7_1 + singularity: + linux/amd64: + name: oras://community.wave.seqera.io/library/rgi_kma:06c9375141c15d16 + build_id: bd-06c9375141c15d16_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/3f/3f452c8e124ee58ab6b26442d15401c57d471cb753f53921570dc484df4e7620/data + linux/arm64: + name: oras://community.wave.seqera.io/library/rgi_kma:a6eaadaaffbeaf85 + build_id: bd-a6eaadaaffbeaf85_1 + https: https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/c8/c8e83b71b5dae10e1d771490c36f49d314718888c3cc8214350eb7f149090f0e/data + conda: + linux/amd64: + lock_file: modules/nf-core/rgi/bwt/.conda-lock/linux_amd64-bd-e905ecb8305e2609_1.txt + linux/arm64: + lock_file: modules/nf-core/rgi/bwt/.conda-lock/linux_arm64-bd-fab5219836c1d880_1.txt diff --git a/modules/nf-core/rgi/bwt/tests/main.nf.test b/modules/nf-core/rgi/bwt/tests/main.nf.test new file mode 100644 index 0000000..a31672c --- /dev/null +++ b/modules/nf-core/rgi/bwt/tests/main.nf.test @@ -0,0 +1,98 @@ +nextflow_process { + + name "Test Process RGI_BWT" + script "../main.nf" + process "RGI_BWT" + topics "versions" + tag "modules" + tag "modules_nfcore" + tag "rgi" + tag "rgi/bwt" + tag "rgi/cardannotation" + tag "untar" + + setup { + run("UNTAR") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = [ + [ ], + file(params.modules_testdata_base_path + 'genomics/prokaryotes/metagenome/rgi/card-data.tar.bz2', checkIfExists: true) + ] + """ + } + } + + run("RGI_CARDANNOTATION") { + script "modules/nf-core/rgi/cardannotation" + process { + """ + input[0] = UNTAR.out.untar.map{ it[1] } + """ + } + } + } + + test("rgi/bwt - minigut - test_fastq_gz") { + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], + [ + file(params.modules_testdata_base_path + '../../mag/test_data/test_minigut_R1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + '../../mag/test_data/test_minigut_R2.fastq.gz', checkIfExists: true), + ] + ] + input[1] = RGI_CARDANNOTATION.out.db + input[2] = [] + """ + } + } + + then { + def outDir = file(process.out.tsv[0][1][0]).parentFile + def mappingFile = outDir.listFiles().find { + it.name.endsWith(".gene_mapping_data.txt") + } + + assert process.success + assertAll( + { assert snapshot( + sanitizeOutput(process.out, unstableKeys: ["tsv", "json"]), + mappingFile.readLines().sort() + ).match() }, + ) + } + } + + test("rgi/bwt - minigut - test_fastq_gz - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], + [ + file(params.modules_testdata_base_path + '../../mag/test_data/test_minigut_R1.fastq.gz', checkIfExists: true), + file(params.modules_testdata_base_path + '../../mag/test_data/test_minigut_R2.fastq.gz', checkIfExists: true), + ] + ] + input[1] = RGI_CARDANNOTATION.out.db + input[2] = [] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } +} diff --git a/modules/nf-core/rgi/bwt/tests/main.nf.test.snap b/modules/nf-core/rgi/bwt/tests/main.nf.test.snap new file mode 100644 index 0000000..01c0c63 --- /dev/null +++ b/modules/nf-core/rgi/bwt/tests/main.nf.test.snap @@ -0,0 +1,146 @@ +{ + "rgi/bwt - minigut - test_fastq_gz - stub": { + "content": [ + { + "json": [ + [ + { + "id": "test", + "single_end": false + }, + "test.json:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "tmp": [ + [ + { + "id": "test", + "single_end": false + }, + [ + + ] + ] + ], + "tsv": [ + [ + { + "id": "test", + "single_end": false + }, + "test.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "versions_db": [ + [ + "RGI_BWT", + "rgi-database", + "stub_version" + ] + ], + "versions_kma": [ + [ + "RGI_BWT", + "kma", + "1.6.11" + ] + ], + "versions_rgi": [ + [ + "RGI_BWT", + "rgi", + "6.0.8" + ] + ] + } + ], + "timestamp": "2026-08-17T08:23:55.264483205", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "rgi/bwt - minigut - test_fastq_gz": { + "content": [ + { + "json": [ + [ + { + "id": "test", + "single_end": false + }, + "test.allele_mapping_data.json" + ] + ], + "tmp": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.temp.sam.temp.fsa:md5,bd47f4f8e6eefb9f9e70deb5cd42e7f9" + ] + ] + ], + "tsv": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test.allele_mapping_data.txt", + "test.artifacts_mapping_stats.txt", + "test.coverage.temp.txt", + "test.coverage_all_positions.summary.temp.txt", + "test.coverage_all_positions.temp.txt", + "test.gene_mapping_data.txt", + "test.overall_mapping_stats.txt", + "test.reference_mapping_stats.txt", + "test.seqs.temp.txt", + "test.temp.txt" + ] + ] + ], + "versions_db": [ + [ + "RGI_BWT", + "rgi-database", + "4.0.1" + ] + ], + "versions_kma": [ + [ + "RGI_BWT", + "kma", + "1.6.11" + ] + ], + "versions_rgi": [ + [ + "RGI_BWT", + "rgi", + "6.0.8" + ] + ] + }, + [ + "ARO Term\tARO Accession\tReference Model Type\tReference DB\tAlleles with Mapped Reads\tReference Allele(s) Identity to CARD Reference Protein (%)\tResistomes & Variants: Observed in Genome(s)\tResistomes & Variants: Observed in Plasmid(s)\tResistomes & Variants: Observed Pathogen(s)\tCompletely Mapped Reads\tMapped Reads with Flanking Sequence\tAll Mapped Reads\tAverage Percent Coverage\tAverage Length Coverage (bp)\tAverage MAPQ (Completely Mapped Reads)\tNumber of Mapped Baits\tNumber of Mapped Baits with Reads\tAverage Number of reads per Bait\tNumber of reads per Bait Coefficient of Variation (%)\tNumber of reads mapping to baits and mapping to complete gene\tNumber of reads mapping to baits and mapping to complete gene (%)\tMate Pair Linkage (# reads)\tReference Length\tAMR Gene Family\tDrug Class\tResistance Mechanism", + "Escherichia coli acrA\t3004043\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t51.00\t0.00\t51.00\t100.00\t1194.00\t188.71\t0\t0\t0\t0\tN/A\tN/A\t\t1194\tresistance-nodulation-cell division (RND) antibiotic efflux pump\tfluoroquinolone antibiotic; cephalosporin; glycylcycline; penicillin beta-lactam; tetracycline antibiotic; rifamycin antibiotic; phenicol antibiotic; disinfecting agents and antiseptics\tantibiotic efflux", + "Escherichia coli emrE\t3004039\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t23.00\t0.00\t23.00\t100.00\t333.00\t175.96\t0\t0\t0\t0\tN/A\tN/A\t\t333\tsmall multidrug resistance (SMR) antibiotic efflux pump\tmacrolide antibiotic\tantibiotic efflux", + "LptD\t3005059\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tKlebsiella pneumoniae\t38.00\t0.00\t38.00\t44.57\t1047.00\t131.34\t0\t0\t0\t0\tN/A\tN/A\t\t2349\tATP-binding cassette (ABC) antibiotic efflux pump\tcarbapenem; peptide antibiotic; aminocoumarin antibiotic; rifamycin antibiotic\tantibiotic efflux", + "acrB\t3000216\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t133.00\t0.00\t133.00\t100.00\t3150.00\t191.36\t0\t0\t0\t0\tN/A\tN/A\t\t3150\tresistance-nodulation-cell division (RND) antibiotic efflux pump\tfluoroquinolone antibiotic; cephalosporin; glycylcycline; penicillin beta-lactam; tetracycline antibiotic; rifamycin antibiotic; phenicol antibiotic; disinfecting agents and antiseptics\tantibiotic efflux", + "kdpE\t3003841\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t45.00\t0.00\t45.00\t100.00\t678.00\t175.80\t0\t0\t0\t0\tN/A\tN/A\t\t678\tkdpDE\taminoglycoside antibiotic\tantibiotic efflux", + "leuO\t3003843\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t55.00\t0.00\t55.00\t100.00\t945.00\t173.55\t0\t0\t0\t0\tN/A\tN/A\t\t945\tmajor facilitator superfamily (MFS) antibiotic efflux pump\tnucleoside antibiotic; disinfecting agents and antiseptics\tantibiotic efflux", + "rmtH\t3003198\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tKlebsiella pneumoniae\t4.00\t0.00\t4.00\t6.59\t50.00\t79.00\t0\t0\t0\t0\tN/A\tN/A\t\t759\t16S rRNA methyltransferase (G1405)\taminoglycoside antibiotic\tantibiotic target alteration", + "tet(Q)\t3000191\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tBacteroides fragilis\t138.00\t0.00\t138.00\t100.00\t1974.00\t179.62\t0\t0\t0\t0\tN/A\tN/A\t\t1974\ttetracycline-resistant ribosomal protection protein\ttetracycline antibiotic\tantibiotic target protection" + ] + ], + "timestamp": "2026-08-17T12:30:32.794546461", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/rgi/cardannotation/environment.yml b/modules/nf-core/rgi/cardannotation/environment.yml new file mode 100644 index 0000000..b6b2d34 --- /dev/null +++ b/modules/nf-core/rgi/cardannotation/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::rgi=6.0.5 diff --git a/modules/nf-core/rgi/cardannotation/main.nf b/modules/nf-core/rgi/cardannotation/main.nf new file mode 100644 index 0000000..776f3c2 --- /dev/null +++ b/modules/nf-core/rgi/cardannotation/main.nf @@ -0,0 +1,61 @@ +process RGI_CARDANNOTATION { + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://depot.galaxyproject.org/singularity/rgi:6.0.5--pyh05cac1d_0' + : 'quay.io/biocontainers/rgi:6.0.5--pyh05cac1d_0'}" + + input: + path card + + output: + path ("card_database_processed"), emit: db + env 'RGI_VERSION', emit: tool_version + env 'DB_VERSION', emit: db_version + path "versions.yml", emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + + """ + rgi card_annotation \\ + -i ${card}/card.json \\ + ${args} + + DB_VERSION=\$(ls card_database_*_all.fasta | sed "s/card_database_v\\([0-9].*[0-9]\\).*/\\1/") + + mkdir card_database_processed + mv card*.fasta card_database_processed + cp ${card}/* card_database_processed + + RGI_VERSION=\$(rgi main --version) + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + rgi: \$(echo \$RGI_VERSION) + rgi-database: \$(echo \$DB_VERSION) + END_VERSIONS + """ + + stub: + """ + touch card.fasta + touch card_all.fasta + + mkdir card_database_processed + mv card*.fasta card_database_processed + + RGI_VERSION=\$(rgi main --version) + DB_VERSION=stub_version + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + rgi: \$(echo \$RGI_VERSION) + rgi-database: \$(echo \$DB_VERSION) + END_VERSIONS + """ +} diff --git a/modules/nf-core/rgi/cardannotation/meta.yml b/modules/nf-core/rgi/cardannotation/meta.yml new file mode 100644 index 0000000..6810661 --- /dev/null +++ b/modules/nf-core/rgi/cardannotation/meta.yml @@ -0,0 +1,53 @@ +name: rgi_cardannotation +description: Preprocess the CARD database for RGI to predict antibiotic resistance + from protein or nucleotide data +keywords: + - bacteria + - fasta + - antibiotic resistance +tools: + - rgi: + description: This module preprocesses the downloaded Comprehensive Antibiotic + Resistance Database (CARD) which can then be used as input for RGI. + homepage: https://card.mcmaster.ca + documentation: https://github.com/arpcard/rgi + tool_dev_url: https://github.com/arpcard/rgi + doi: "10.1093/nar/gkz935" + licence: ["https://card.mcmaster.ca/about"] + identifier: "" +input: + - card: + type: directory + description: Directory containing the CARD database + pattern: "*/" +output: + db: + - card_database_processed: + type: directory + description: Directory containing the processed CARD database files + pattern: "*/" + tool_version: + - RGI_VERSION: + type: string + description: The version of the tool in string format (useful for downstream + tools such as hAMRronization) + db_version: + - DB_VERSION: + type: string + description: The version of the used database in string format (useful for downstream + tools such as hAMRronization) + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: "versions.yml" + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@rpetit3" + - "@jfy133" + - "@jasmezz" +maintainers: + - "@rpetit3" + - "@jfy133" + - "@jasmezz" diff --git a/modules/nf-core/rgi/cardannotation/tests/main.nf.test b/modules/nf-core/rgi/cardannotation/tests/main.nf.test new file mode 100644 index 0000000..fa51142 --- /dev/null +++ b/modules/nf-core/rgi/cardannotation/tests/main.nf.test @@ -0,0 +1,66 @@ +nextflow_process { + + name "Test Process RGI_CARDANNOTATION" + script "../main.nf" + process "RGI_CARDANNOTATION" + + tag "modules" + tag "modules_nfcore" + tag "rgi" + tag "rgi/cardannotation" + tag "untar" + + setup { + run("UNTAR") { + script "modules/nf-core/untar/main.nf" + process { + """ + file('https://card.mcmaster.ca/latest/data', checkIfExists: true).copyTo('data.tar.gz') + + input[0] = [ + [ ], + file("data.tar.gz") + ] + """ + } + } + } + + test("rgi/cardannotation") { + + when { + process { + """ + input[0] = UNTAR.out.untar.map{ it[1] } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("rgi/cardannotation - stub") { + + options "-stub" + + when { + process { + """ + input[0] = UNTAR.out.untar.map{ it[1] } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } +} diff --git a/modules/nf-core/rgi/cardannotation/tests/main.nf.test.snap b/modules/nf-core/rgi/cardannotation/tests/main.nf.test.snap new file mode 100644 index 0000000..2d1391b --- /dev/null +++ b/modules/nf-core/rgi/cardannotation/tests/main.nf.test.snap @@ -0,0 +1,120 @@ +{ + "rgi/cardannotation - stub": { + "content": [ + { + "0": [ + [ + "card.fasta:md5,d41d8cd98f00b204e9800998ecf8427e", + "card_all.fasta:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "1": [ + "6.0.5" + ], + "2": [ + "stub_version" + ], + "3": [ + "versions.yml:md5,c42c7e6566b41df0310a5a4c1fd8f949" + ], + "db": [ + [ + "card.fasta:md5,d41d8cd98f00b204e9800998ecf8427e", + "card_all.fasta:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ], + "db_version": [ + "stub_version" + ], + "tool_version": [ + "6.0.5" + ], + "versions": [ + "versions.yml:md5,c42c7e6566b41df0310a5a4c1fd8f949" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-03T10:10:40.229702375" + }, + "rgi/cardannotation": { + "content": [ + { + "0": [ + [ + "CARD-Download-README.txt:md5,b57364cc1a5fab0541e13a01fabe5dea", + "PMID.tsv:md5,e3ce79c4b5dcf0a9e3117ed683f96e54", + "aro_categories.tsv:md5,6f9c4b0410b9e2b3cf5867a2a3f1db07", + "aro_categories_index.tsv:md5,d5fbc673c0de6601b07c8016b3909f8e", + "aro_index.tsv:md5,0f183c7869876fa32c8f86aade0df7b5", + "card.json:md5,72156d00155f69e637664bfb5d3b5395", + "card_database_v4.0.1.fasta:md5,5ead0b239c312ebb068a3b5aa9676b2d", + "card_database_v4.0.1_all.fasta:md5,f389ce15fac30e9ab394ca8a49f6451f", + "nucleotide_fasta_protein_homolog_model.fasta:md5,696d1aa4f04bd08fc4bdeea33ab9db43", + "nucleotide_fasta_protein_knockout_model.fasta:md5,d8224ce019ad69a041d83ccf7877b4e0", + "nucleotide_fasta_protein_overexpression_model.fasta:md5,80a1e7957c79d311446e06c6dd49db8e", + "nucleotide_fasta_protein_variant_model.fasta:md5,7450e559045c9d1d8f13c73054c64f4c", + "nucleotide_fasta_rRNA_gene_variant_model.fasta:md5,bd53f46d630f652c9f6b7584c2126e1f", + "protein_fasta_protein_homolog_model.fasta:md5,36ea300133fd7c5a45de2fee4c5050bf", + "protein_fasta_protein_knockout_model.fasta:md5,f16667df70d1a5f910d3ae45f5250c3d", + "protein_fasta_protein_overexpression_model.fasta:md5,723e8762be5c96aed8c379a6499cecee", + "protein_fasta_protein_variant_model.fasta:md5,8c02d8fc84c9a90953f8534355244019", + "shortname_antibiotics.tsv:md5,9a4ba742fd8a3a49c7f50744001a4129", + "shortname_pathogens.tsv:md5,5211712be4f4c3306cbe4052cafae1d7", + "snps.txt:md5,529d4fdb74c8940c0930ec1a7a6d4980" + ] + ], + "1": [ + "6.0.5" + ], + "2": [ + "4.0.1" + ], + "3": [ + "versions.yml:md5,bbd7b05923d280ece1cc3c426aa98ea9" + ], + "db": [ + [ + "CARD-Download-README.txt:md5,b57364cc1a5fab0541e13a01fabe5dea", + "PMID.tsv:md5,e3ce79c4b5dcf0a9e3117ed683f96e54", + "aro_categories.tsv:md5,6f9c4b0410b9e2b3cf5867a2a3f1db07", + "aro_categories_index.tsv:md5,d5fbc673c0de6601b07c8016b3909f8e", + "aro_index.tsv:md5,0f183c7869876fa32c8f86aade0df7b5", + "card.json:md5,72156d00155f69e637664bfb5d3b5395", + "card_database_v4.0.1.fasta:md5,5ead0b239c312ebb068a3b5aa9676b2d", + "card_database_v4.0.1_all.fasta:md5,f389ce15fac30e9ab394ca8a49f6451f", + "nucleotide_fasta_protein_homolog_model.fasta:md5,696d1aa4f04bd08fc4bdeea33ab9db43", + "nucleotide_fasta_protein_knockout_model.fasta:md5,d8224ce019ad69a041d83ccf7877b4e0", + "nucleotide_fasta_protein_overexpression_model.fasta:md5,80a1e7957c79d311446e06c6dd49db8e", + "nucleotide_fasta_protein_variant_model.fasta:md5,7450e559045c9d1d8f13c73054c64f4c", + "nucleotide_fasta_rRNA_gene_variant_model.fasta:md5,bd53f46d630f652c9f6b7584c2126e1f", + "protein_fasta_protein_homolog_model.fasta:md5,36ea300133fd7c5a45de2fee4c5050bf", + "protein_fasta_protein_knockout_model.fasta:md5,f16667df70d1a5f910d3ae45f5250c3d", + "protein_fasta_protein_overexpression_model.fasta:md5,723e8762be5c96aed8c379a6499cecee", + "protein_fasta_protein_variant_model.fasta:md5,8c02d8fc84c9a90953f8534355244019", + "shortname_antibiotics.tsv:md5,9a4ba742fd8a3a49c7f50744001a4129", + "shortname_pathogens.tsv:md5,5211712be4f4c3306cbe4052cafae1d7", + "snps.txt:md5,529d4fdb74c8940c0930ec1a7a6d4980" + ] + ], + "db_version": [ + "4.0.1" + ], + "tool_version": [ + "6.0.5" + ], + "versions": [ + "versions.yml:md5,bbd7b05923d280ece1cc3c426aa98ea9" + ] + } + ], + "meta": { + "nf-test": "0.9.2", + "nextflow": "25.04.6" + }, + "timestamp": "2025-09-03T10:10:17.719519729" + } +} \ No newline at end of file diff --git a/modules/nf-core/seqkit/fq2fa/environment.yml b/modules/nf-core/seqkit/fq2fa/environment.yml new file mode 100644 index 0000000..09abb79 --- /dev/null +++ b/modules/nf-core/seqkit/fq2fa/environment.yml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::seqkit=2.13.0 diff --git a/modules/nf-core/seqkit/fq2fa/main.nf b/modules/nf-core/seqkit/fq2fa/main.nf new file mode 100644 index 0000000..0722455 --- /dev/null +++ b/modules/nf-core/seqkit/fq2fa/main.nf @@ -0,0 +1,40 @@ +process SEQKIT_FQ2FA { + tag "${meta.id}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/4f/4fe272ab9a519cf418160471a485b5ef50ea3f571a8e4555a826f70a4d8243ae/data' + : 'community.wave.seqera.io/library/seqkit:2.13.0--05c0a96bf9fb2751'}" + + input: + tuple val(meta), path(fastq) + + output: + tuple val(meta), path("*.fa.gz"), emit: fasta + tuple val("${task.process}"), val('seqkit'), eval("seqkit version | sed 's/^.*v//'"), emit: versions_seqkit, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + seqkit \\ + fq2fa \\ + ${args} \\ + -j ${task.cpus} \\ + -o ${prefix}.fa.gz \\ + ${fastq} + """ + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + echo ${args} + + echo "" | gzip > ${prefix}.fa.gz + """ +} diff --git a/modules/nf-core/seqkit/fq2fa/meta.yml b/modules/nf-core/seqkit/fq2fa/meta.yml new file mode 100644 index 0000000..92bf7cd --- /dev/null +++ b/modules/nf-core/seqkit/fq2fa/meta.yml @@ -0,0 +1,63 @@ +name: "seqkit_fq2fa" +description: Convert FASTQ to FASTA format +keywords: + - fastq + - fasta + - convert +tools: + - "seqkit": + description: "Cross-platform and ultrafast toolkit for FASTA/Q file manipulation, + written by Wei Shen." + homepage: "https://github.com/shenwei356/seqkit" + documentation: "https://bioinf.shenwei.me/seqkit/" + doi: "10.1371/journal.pone.0163962" + licence: ["MIT"] + identifier: biotools:seqkit + +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - fastq: + type: file + description: Sequence file in fastq format + pattern: "*.{fastq,fq}.gz" + ontologies: + - edam: http://edamontology.org/format_1930 # FASTQ +output: + fasta: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*.fa.gz": + type: file + description: Sequence file in fasta format + pattern: "*.{fasta,fa}.gz" + ontologies: [] + versions_seqkit: + - - ${task.process}: + type: string + description: The name of the process + - seqkit: + type: string + description: The name of the tool + - seqkit version | sed 's/^.*v//': + type: eval + description: The expression to obtain the version of the tool +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - seqkit: + type: string + description: The name of the tool + - seqkit version | sed 's/^.*v//': + type: eval + description: The expression to obtain the version of the tool +authors: + - "@d-jch" diff --git a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test new file mode 100644 index 0000000..b20ac23 --- /dev/null +++ b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test @@ -0,0 +1,53 @@ +nextflow_process { + + name "Test Process SEQKIT_FQ2FA" + script "../main.nf" + process "SEQKIT_FQ2FA" + + tag "modules" + tag "modules_nfcore" + tag "seqkit" + tag "seqkit/fq2fa" + + test("sarscov2 - bam") { + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + test("sarscov2 - bam - stub") { + options '-stub' + + when { + process { + """ + input[0] = [ + [ id:'test', single_end:false ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz', checkIfExists: true) + ] + """ + } + } + + then { + assert process.success + assertAll( + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } +} diff --git a/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap new file mode 100644 index 0000000..ea4763d --- /dev/null +++ b/modules/nf-core/seqkit/fq2fa/tests/main.nf.test.snap @@ -0,0 +1,56 @@ +{ + "sarscov2 - bam - stub": { + "content": [ + { + "fasta": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fa.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions_seqkit": [ + [ + "SEQKIT_FQ2FA", + "seqkit", + "2.13.0" + ] + ] + } + ], + "timestamp": "2026-06-15T10:19:21.836507096", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.3" + } + }, + "sarscov2 - bam": { + "content": [ + { + "fasta": [ + [ + { + "id": "test", + "single_end": false + }, + "test.fa.gz:md5,f0c5c9110ce19e9ebbc9a6b6baf9e105" + ] + ], + "versions_seqkit": [ + [ + "SEQKIT_FQ2FA", + "seqkit", + "2.13.0" + ] + ] + } + ], + "timestamp": "2026-06-12T17:24:20.019577498", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.3" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/untar/environment.yml b/modules/nf-core/untar/environment.yml new file mode 100644 index 0000000..9b926b1 --- /dev/null +++ b/modules/nf-core/untar/environment.yml @@ -0,0 +1,12 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - conda-forge::coreutils=9.5 + - conda-forge::grep=3.11 + - conda-forge::gzip=1.13 + - conda-forge::lbzip2=2.5 + - conda-forge::sed=4.8 + - conda-forge::tar=1.34 diff --git a/modules/nf-core/untar/main.nf b/modules/nf-core/untar/main.nf new file mode 100644 index 0000000..bf2c056 --- /dev/null +++ b/modules/nf-core/untar/main.nf @@ -0,0 +1,75 @@ +process UNTAR { + tag "${archive}" + label 'process_single' + + conda "${moduleDir}/environment.yml" + container "${workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container + ? 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/52/52ccce28d2ab928ab862e25aae26314d69c8e38bd41ca9431c67ef05221348aa/data' + : 'community.wave.seqera.io/library/coreutils_grep_gzip_lbzip2_pruned:838ba80435a629f8'}" + + input: + tuple val(meta), path(archive) + + output: + tuple val(meta), path("${prefix}"), emit: untar + tuple val("${task.process}"), val('untar'), eval('tar --version 2>&1 | head -1 | sed "s/tar (GNU tar) //; s/ Copyright.*//"'), emit: versions_untar, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def args2 = task.ext.args2 ?: '' + prefix = task.ext.prefix ?: (meta.id ? "${meta.id}" : archive.baseName.toString().replaceFirst(/\.tar$/, "")) + + """ + mkdir ${prefix} + + ## Ensures --strip-components only applied when top level of tar contents is a directory + ## If just files or multiple directories, place all in prefix + if [[ \$(tar -taf ${archive} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then + tar \\ + -C ${prefix} --strip-components 1 \\ + -xavf \\ + ${args} \\ + ${archive} \\ + ${args2} + else + tar \\ + -C ${prefix} \\ + -xavf \\ + ${args} \\ + ${archive} \\ + ${args2} + fi + + """ + + stub: + prefix = task.ext.prefix ?: (meta.id ? "${meta.id}" : archive.toString().replaceFirst(/\.[^\.]+(.gz)?$/, "")) + """ + mkdir ${prefix} + ## Dry-run untaring the archive to get the files and place all in prefix + if [[ \$(tar -taf ${archive} | grep -o -P "^.*?\\/" | uniq | wc -l) -eq 1 ]]; then + for i in `tar -tf ${archive}`; + do + if [[ \$(echo "\${i}" | grep -E "/\$") == "" ]]; + then + touch \${i} + else + mkdir -p \${i} + fi + done + else + for i in `tar -tf ${archive}`; + do + if [[ \$(echo "\${i}" | grep -E "/\$") == "" ]]; + then + touch ${prefix}/\${i} + else + mkdir -p ${prefix}/\${i} + fi + done + fi + """ +} diff --git a/modules/nf-core/untar/meta.yml b/modules/nf-core/untar/meta.yml new file mode 100644 index 0000000..571d807 --- /dev/null +++ b/modules/nf-core/untar/meta.yml @@ -0,0 +1,73 @@ +name: untar +description: Extract files from tar, tar.gz, tar.bz2, tar.xz archives +keywords: + - untar + - uncompress + - extract +tools: + - untar: + description: | + Extract tar, tar.gz, tar.bz2, tar.xz files. + documentation: https://www.gnu.org/software/tar/manual/ + licence: ["GPL-3.0-or-later"] + identifier: "" +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - archive: + type: file + description: File to be untarred + pattern: "*.{tar,tar.gz,tar.bz2,tar.xz}" + ontologies: + - edam: http://edamontology.org/format_3981 # TAR format + - edam: http://edamontology.org/format_3989 # GZIP format +output: + untar: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + pattern: "*/" + - ${prefix}: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + pattern: "*/" + versions_untar: + - - ${task.process}: + type: string + description: The name of the process + - untar: + type: string + description: The name of the tool + - tar --version 2>&1 | head -1 | sed "s/tar (GNU tar) //; s/ Copyright.*//": + type: eval + description: The expression to obtain the version of the tool + +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - untar: + type: string + description: The name of the tool + - tar --version 2>&1 | head -1 | sed "s/tar (GNU tar) //; s/ Copyright.*//": + type: eval + description: The expression to obtain the version of the tool + +authors: + - "@joseespinosa" + - "@drpatelh" + - "@matthdsm" + - "@jfy133" +maintainers: + - "@joseespinosa" + - "@drpatelh" + - "@matthdsm" + - "@jfy133" diff --git a/modules/nf-core/untar/tests/main.nf.test b/modules/nf-core/untar/tests/main.nf.test new file mode 100644 index 0000000..fde8db1 --- /dev/null +++ b/modules/nf-core/untar/tests/main.nf.test @@ -0,0 +1,97 @@ +nextflow_process { + + name "Test Process UNTAR" + script "../main.nf" + process "UNTAR" + tag "modules" + tag "modules_nfcore" + tag "untar" + + test("test_untar") { + + when { + process { + """ + input[0] = [ [], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/db/kraken2.tar.gz', checkIfExists: true) ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.untar, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() }, + ) + } + } + + test("test_untar_onlyfiles") { + + when { + process { + """ + input[0] = [ [], file(params.modules_testdata_base_path + 'generic/tar/hello.tar.gz', checkIfExists: true) ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.untar, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() }, + ) + } + } + + test("test_untar - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [], file(params.modules_testdata_base_path + 'genomics/sarscov2/genome/db/kraken2.tar.gz', checkIfExists: true) ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.untar, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() }, + ) + } + } + + test("test_untar_onlyfiles - stub") { + + options "-stub" + + when { + process { + """ + input[0] = [ [], file(params.modules_testdata_base_path + 'generic/tar/hello.tar.gz', checkIfExists: true) ] + """ + } + } + + then { + assertAll ( + { assert process.success }, + { assert snapshot( + process.out.untar, + process.out.findAll { key, val -> key.startsWith('versions') } + ).match() }, + ) + } + } +} diff --git a/modules/nf-core/untar/tests/main.nf.test.snap b/modules/nf-core/untar/tests/main.nf.test.snap new file mode 100644 index 0000000..51a414d --- /dev/null +++ b/modules/nf-core/untar/tests/main.nf.test.snap @@ -0,0 +1,118 @@ +{ + "test_untar_onlyfiles": { + "content": [ + [ + [ + [ + + ], + [ + "hello.txt:md5,e59ff97941044f85df5297e1c302d260" + ] + ] + ], + { + "versions_untar": [ + [ + "UNTAR", + "untar", + "1.34" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-28T17:49:32.000491" + }, + "test_untar_onlyfiles - stub": { + "content": [ + [ + [ + [ + + ], + [ + "hello.txt:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + { + "versions_untar": [ + [ + "UNTAR", + "untar", + "1.34" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-28T17:49:58.812479" + }, + "test_untar - stub": { + "content": [ + [ + [ + [ + + ], + [ + "hash.k2d:md5,d41d8cd98f00b204e9800998ecf8427e", + "opts.k2d:md5,d41d8cd98f00b204e9800998ecf8427e", + "taxo.k2d:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + { + "versions_untar": [ + [ + "UNTAR", + "untar", + "1.34" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-28T17:49:48.119456" + }, + "test_untar": { + "content": [ + [ + [ + [ + + ], + [ + "hash.k2d:md5,8b8598468f54a7087c203ad0190555d9", + "opts.k2d:md5,a033d00cf6759407010b21700938f543", + "taxo.k2d:md5,094d5891cdccf2f1468088855c214b2c" + ] + ] + ], + { + "versions_untar": [ + [ + "UNTAR", + "untar", + "1.34" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.2" + }, + "timestamp": "2026-01-28T17:49:17.252494" + } +} \ No newline at end of file diff --git a/nextflow.config b/nextflow.config index db43105..154f6cf 100644 --- a/nextflow.config +++ b/nextflow.config @@ -1,4 +1,5 @@ /* +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nf-core/funcprofiler Nextflow config file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -9,15 +10,9 @@ // Global default params, used in configs params { - // TODO nf-core: Specify your pipeline's command line flags // Input options input = null - // References - genome = null - igenomes_base = 's3://ngi-igenomes/igenomes/' - igenomes_ignore = false - // MultiQC options multiqc_config = null multiqc_title = null @@ -32,7 +27,6 @@ params { email_on_fail = null plaintext_email = false monochrome_logs = false - hook_url = null help = false help_full = false show_hidden = false @@ -49,8 +43,29 @@ params { // Schema validation default options validate_params = true + // Databases + databases = null + save_untarred_databases = false + + // RGI + run_rgi = false + // Humann + run_humann_v3 = false + run_humann_v4 = false + // fmhfunprofiler + run_fmhfunprofiler = false + // mi-faser + run_mifaser = false + run_diamond = false + // eggnogmapper + run_eggnogmapper = false + } +// Backwards compatibility for publishDir syntax +outputDir = params.outdir +workflow.output.mode = params.publish_dir_mode + // Load base.config by default for all pipelines includeConfig 'conf/base.config' @@ -89,9 +104,20 @@ profiles { shifter.enabled = false charliecloud.enabled = false apptainer.enabled = false - docker.runOptions = '-u $(id -u):$(id -g)' + docker.runOptions = '-u $(id -u):$(id -g) --platform linux/x86_64' } - arm { + arm64 { + process.arch = 'arm64' + // TODO https://github.com/nf-core/modules/issues/6694 + // For now if you're using arm64 you have to use wave for the sake of the maintainers + // wave profile + apptainer.ociAutoPull = true + singularity.ociAutoPull = true + wave.enabled = true + wave.freeze = true + wave.strategy = 'conda,container' + } + emulate_amd64 { docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' } singularity { @@ -148,18 +174,6 @@ profiles { wave.freeze = true wave.strategy = 'conda,container' } - gitpod { - executor.name = 'local' - executor.cpus = 4 - executor.memory = 8.GB - process { - resourceLimits = [ - memory: 8.GB, - cpus : 4, - time : 1.h - ] - } - } gpu { docker.runOptions = '-u $(id -u):$(id -g) --gpus all' apptainer.runOptions = '--nv' @@ -177,8 +191,7 @@ includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !pa // Load nf-core/funcprofiler custom profiles from different institutions. -// TODO nf-core: Optionally, you can add a pipeline-specific nf-core config at https://github.com/nf-core/configs -// includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/funcprofiler.config" : "/dev/null" +includeConfig params.custom_config_base && (!System.getenv('NXF_OFFLINE') || !params.custom_config_base.startsWith('http')) ? "${params.custom_config_base}/pipeline/funcprofiler.config" : "/dev/null" // Set default registry for Apptainer, Docker, Podman, Charliecloud and Singularity independent of -profile // Will not be used unless Apptainer / Docker / Podman / Charliecloud / Singularity are enabled @@ -189,9 +202,6 @@ podman.registry = 'quay.io' singularity.registry = 'quay.io' charliecloud.registry = 'quay.io' -// Load igenomes.config if required -includeConfig !params.igenomes_ignore ? 'conf/igenomes.config' : 'conf/igenomes_ignored.config' - // Export these variables to prevent local Python/R libraries from conflicting with those in the container // The JULIA depot path has been adjusted to a fixed path `/usr/local/share/julia` that needs to be used for packages in the container. // See https://apeltzer.github.io/post/03-julia-lang-nextflow/ for details on that. Once we have a common agreement on where to keep Julia packages, this is adjustable. @@ -236,61 +246,57 @@ dag { manifest { name = 'nf-core/funcprofiler' contributors = [ - // TODO nf-core: Update the field with the details of the contributors to your pipeline. New with Nextflow version 24.10.0 [ name: 'Nick Waters', - affiliation: '', + affiliation: 'MSKCC', email: '', - github: '', - contribution: [], // List of contribution types ('author', 'maintainer' or 'contributor') + github: 'nickp60', + contribution: ['author', 'maintainer'], // List of contribution types ('author', 'maintainer' or 'contributor') orcid: '' ], + [ + + name: 'Vini Salazar', + affiliation: 'University of Melbourne', + email: '', + github: 'vinisalazar', + contribution: ['author', 'maintainer'], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '' + ], + [ + name: 'Mirae B', + affiliation: 'MSKCC', + email: '', + github: 'miraep8', + contribution: ['author', 'maintainer'], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '' + ], + [ + name: 'Yixuan Yang', + affiliation: 'NC State', + email: '', + github: 'Yixuan39', + contribution: ['author', 'maintainer'], // List of contribution types ('author', 'maintainer' or 'contributor') + orcid: '' + ] ] homePage = 'https://github.com/nf-core/funcprofiler' description = """Read-based functional profiling of microbiome sequencing data""" mainScript = 'main.nf' defaultBranch = 'main' - nextflowVersion = '!>=24.10.5' - version = '1.0.0dev' + nextflowVersion = '!>=25.10.4' + version = '1.0.0' doi = '' } // Nextflow plugins plugins { - id 'nf-schema@2.4.2' // Validation of pipeline parameters and creation of an input channel from a sample sheet + id 'nf-schema@2.5.1' // Validation of pipeline parameters and creation of an input channel from a sample sheet } validation { defaultIgnoreParams = ["genomes"] monochromeLogs = params.monochrome_logs - help { - enabled = true - command = "nextflow run nf-core/funcprofiler -profile --input samplesheet.csv --outdir " - fullParameter = "help_full" - showHiddenParameter = "show_hidden" - beforeText = """ --\033[2m----------------------------------------------------\033[0m- - \033[0;32m,--.\033[0;30m/\033[0;32m,-.\033[0m -\033[0;34m ___ __ __ __ ___ \033[0;32m/,-._.--~\'\033[0m -\033[0;34m |\\ | |__ __ / ` / \\ |__) |__ \033[0;33m} {\033[0m -\033[0;34m | \\| | \\__, \\__/ | \\ |___ \033[0;32m\\`-._,-`-,\033[0m - \033[0;32m`._,._,\'\033[0m -\033[0;35m nf-core/funcprofiler ${manifest.version}\033[0m --\033[2m----------------------------------------------------\033[0m- -""" - afterText = """${manifest.doi ? "\n* The pipeline\n" : ""}${manifest.doi.tokenize(",").collect { " https://doi.org/${it.trim().replace('https://doi.org/','')}"}.join("\n")}${manifest.doi ? "\n" : ""} -* The nf-core framework - https://doi.org/10.1038/s41587-020-0439-x - -* Software dependencies - https://github.com/nf-core/funcprofiler/blob/main/CITATIONS.md -""" - } - summary { - beforeText = validation.help.beforeText - afterText = validation.help.afterText - } } - // Load modules.config for DSL2 module specific options includeConfig 'conf/modules.config' diff --git a/nextflow_schema.json b/nextflow_schema.json index 5c45ecf..44e40e0 100644 --- a/nextflow_schema.json +++ b/nextflow_schema.json @@ -10,7 +10,7 @@ "type": "object", "fa_icon": "fas fa-terminal", "description": "Define where the pipeline should find input data and save output data.", - "required": ["input", "outdir"], + "required": ["input", "databases", "outdir"], "properties": { "input": { "type": "string", @@ -20,9 +20,26 @@ "mimetype": "text/csv", "pattern": "^\\S+\\.csv$", "description": "Path to comma-separated file containing information about the samples in the experiment.", - "help_text": "You will need to create a design file with information about the samples in your experiment before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 3 columns, and a header row. See [usage docs](https://nf-co.re/funcprofiler/usage#samplesheet-input).", + "help_text": "You will need to create a design file with information about the samples in your experiment before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 6 columns (`sample`, `run_accession`, `instrument_platform`, `fastq_1`, `fastq_2`, `fasta`), and a header row. We utilise the same input style as nf-core/taxprofiler, with 2 main differences: long-read platforms are not supported, nor is `fasta` input. See [usage docs](https://nf-co.re/funcprofiler/usage#samplesheet-input).", "fa_icon": "fas fa-file-csv" }, + "databases": { + "type": "string", + "mimetype": "text/csv", + "format": "file-path", + "exists": true, + "schema": "assets/schema_database.json", + "pattern": "^\\S+\\.csv$", + "fa_icon": "fas fa-database", + "description": "Path to comma-separated file containing information about databases and profiling parameters for each taxonomic profiler", + "help_text": "You will need to create a design file with information about the samples in your experiment before running the pipeline. Use this parameter to specify its location. It has to be a comma-separated file with 5 columns (`tool`, `db_name`, `db_entity`, `db_params`, `db_path`), and a header row. See [usage docs](https://nf-co.re/funcprofiler/dev/usage#full-database-sheet).\n\nProfilers will only be executed if a corresponding database are supplied. \n\n As with taxprofiler, we recommend storing this database sheet somewhere centrally and accessible by others members of your lab/institutions, as this file will likely be regularly reused." + }, + "save_untarred_databases": { + "type": "boolean", + "fa_icon": "fas fa-database", + "description": "Specify to save decompressed user-supplied TAR archives of databases", + "help_text": "If input databases are supplied as gzipped TAR archives, in some cases you may want to move and re-use these for future runs. Specifying this parameter will save these to `--outdir results/` under a directory called `untar`." + }, "outdir": { "type": "string", "format": "directory-path", @@ -43,42 +60,46 @@ } } }, - "reference_genome_options": { - "title": "Reference genome options", + "profiling_options": { + "title": "Profiling options", "type": "object", - "fa_icon": "fas fa-dna", - "description": "Reference genome related files and options required for the workflow.", + "description": "", + "default": "", "properties": { - "genome": { - "type": "string", - "description": "Name of iGenomes reference.", - "fa_icon": "fas fa-book", - "help_text": "If using a reference genome configured in the pipeline using iGenomes, use this parameter to give the ID for the reference. This is then used to build the full paths for all required reference genome files e.g. `--genome GRCh38`. \n\nSee the [nf-core website docs](https://nf-co.re/usage/reference_genomes) for more details." + "run_fmhfunprofiler": { + "type": "boolean", + "fa_icon": "fas fa-toggle-on", + "description": "Turn on profiling with FMH FunProfiler. Requires a `fmhfunprofiler`-tagged database to be present in the CSV file passed to --databases" }, - "fasta": { - "type": "string", - "format": "file-path", - "exists": true, - "mimetype": "text/plain", - "pattern": "^\\S+\\.fn?a(sta)?(\\.gz)?$", - "description": "Path to FASTA genome file.", - "help_text": "This parameter is *mandatory* if `--genome` is not specified. If you don't have a BWA index available this will be generated for you automatically. Combine with `--save_reference` to save BWA index for future runs.", - "fa_icon": "far fa-file-code" + "run_humann_v3": { + "type": "boolean", + "fa_icon": "fas fa-toggle-on", + "description": "Turn on profiling with HUMAnN3. Requires a `humann_v3`-tagged database to be present in the CSV file passed to --databases" }, - "igenomes_ignore": { + "run_humann_v4": { "type": "boolean", - "description": "Do not load the iGenomes reference config.", - "fa_icon": "fas fa-ban", - "hidden": true, - "help_text": "Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`." + "fa_icon": "fas fa-toggle-on", + "description": "Turn on profiling with HUMAnN4. Requires a `humann_v4`-tagged database to be present in the CSV file passed to --databases" }, - "igenomes_base": { - "type": "string", - "format": "directory-path", - "description": "The base path to the igenomes reference files", - "fa_icon": "fas fa-ban", - "hidden": true, - "default": "s3://ngi-igenomes/igenomes/" + "run_diamond": { + "type": "boolean", + "fa_icon": "fas fa-toggle-on", + "description": "Turn on translated alignment with DIAMOND blastx. Requires a `diamond`-tagged database to be present in the CSV file passed to --databases" + }, + "run_rgi": { + "type": "boolean", + "fa_icon": "fas fa-toggle-on", + "description": "Turn on profiling with RGI. Requires a `rgi`-tagged database to be present in the CSV file passed to --databases" + }, + "run_mifaser": { + "type": "boolean", + "fa_icon": "fas fa-toggle-on", + "description": "Turn on profiling with mi-faser. Requires a `mifaser`-tagged database to be present in the CSV file passed to --databases" + }, + "run_eggnogmapper": { + "type": "boolean", + "fa_icon": "fas fa-toggle-on", + "description": "Turn on functional annotation with eggNOG-mapper. Requires `eggnogmapper`-tagged database entries to be present in the CSV file passed to --databases" } } }, @@ -180,13 +201,6 @@ "fa_icon": "fas fa-palette", "hidden": true }, - "hook_url": { - "type": "string", - "description": "Incoming hook URL for messaging service", - "fa_icon": "fas fa-people-group", - "help_text": "Incoming hook URL for messaging service. Currently, MS Teams and Slack are supported.", - "hidden": true - }, "multiqc_config": { "type": "string", "format": "file-path", @@ -224,6 +238,18 @@ "fa_icon": "far calendar", "description": "Suffix to add to the trace report filename. Default is the date and time in the format yyyy-MM-dd_HH-mm-ss.", "hidden": true + }, + "help": { + "type": ["boolean", "string"], + "description": "Display the help message." + }, + "help_full": { + "type": "boolean", + "description": "Display the full detailed help message." + }, + "show_hidden": { + "type": "boolean", + "description": "Display hidden parameters in the help message (only works when --help or --help_full are provided)." } } } @@ -233,7 +259,7 @@ "$ref": "#/$defs/input_output_options" }, { - "$ref": "#/$defs/reference_genome_options" + "$ref": "#/$defs/profiling_options" }, { "$ref": "#/$defs/institutional_config_options" diff --git a/nf-test.config b/nf-test.config index 3a1fff5..d712a84 100644 --- a/nf-test.config +++ b/nf-test.config @@ -1,20 +1,23 @@ config { // location for all nf-test tests - testsDir "." + testsDir = "." // nf-test directory including temporary files for each test - workDir System.getenv("NFT_WORKDIR") ?: ".nf-test" + workDir = System.getenv("NFT_WORKDIR") ?: ".nf-test" // location of an optional nextflow.config file specific for executing tests - configFile "tests/nextflow.config" + configFile = "tests/nextflow.config" // ignore tests coming from the nf-core/modules repo - ignore 'modules/nf-core/**/tests/*', 'subworkflows/nf-core/**/tests/*' + ignore = [ + 'modules/nf-core/**/tests/*', + 'subworkflows/nf-core/**/tests/*', + ] // run all test with defined profile(s) from the main nextflow.config - profile "test" + profile = "test" - // list of filenames or patterns that should be trigger a full test run + // list of filenames or patterns that should be trigger a full test run triggers 'nextflow.config', 'nf-test.config', 'conf/test.config', 'tests/nextflow.config', 'tests/.nftignore' // load the necessary plugins diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index 41333a3..1845fa5 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -1,6 +1,6 @@ { "@context": [ - "https://w3id.org/ro/crate/1.1/context", + "https://w3id.org/ro/crate/1.2/context", { "GithubService": "https://w3id.org/ro/terms/test#GithubService", "JenkinsService": "https://w3id.org/ro/terms/test#JenkinsService", @@ -21,9 +21,9 @@ { "@id": "./", "@type": "Dataset", - "creativeWorkStatus": "InProgress", - "datePublished": "2025-08-13T15:15:55+00:00", - "description": "

\n \n \n \"nf-core/funcprofiler\"\n \n

\n\n[![GitHub Actions CI Status](https://github.com/nf-core/funcprofiler/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/funcprofiler/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/funcprofiler/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/funcprofiler/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/funcprofiler/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A524.10.5-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.3.2-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.3.2)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/funcprofiler)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23funcprofiler-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/funcprofiler)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**nf-core/funcprofiler** is a bioinformatics pipeline that ...\n\n\n\n\n1. Read QC ([`FastQC`](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/))2. Present QC for raw reads ([`MultiQC`](http://multiqc.info/))\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/usage/installation) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/usage/introduction#how-to-run-a-pipeline) with `-profile test` before running the workflow on actual data.\n\n\n\nNow, you can run the pipeline using:\n\n\n\n```bash\nnextflow run nf-core/funcprofiler \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/funcprofiler/usage) and the [parameter documentation](https://nf-co.re/funcprofiler/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/funcprofiler/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/funcprofiler/output).\n\n## Credits\n\nnf-core/funcprofiler was originally written by Nick Waters.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#funcprofiler` channel](https://nfcore.slack.com/channels/funcprofiler) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "creativeWorkStatus": "Stable", + "datePublished": "2026-09-01T12:58:14+00:00", + "description": "

\n \n \n \"nf-core/funcprofiler\"\n \n

\n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/funcprofiler)\n[![GitHub Actions CI Status](https://github.com/nf-core/funcprofiler/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/funcprofiler/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/funcprofiler/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/funcprofiler/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/funcprofiler/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.10.4-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-4.1.0-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/4.1.0)\n[![run with conda](http://img.shields.io/badge/run%20with-conda-3EB049?labelColor=000000&logo=anaconda)](https://docs.conda.io/en/latest/)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/funcprofiler)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23funcprofiler-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/funcprofiler)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**nf-core/funcprofiler** is a bioinformatics pipeline for read-based functional profiling of microbiome sequencing data. It accepts already preprocessed short-read FASTQ files and runs one or more functional profilers against user-supplied databases, producing gene family abundances, pathway abundances, pathway coverages, and antimicrobial resistance profiles. Long-read platforms are not supported in this release.\n\n### Pipeline Summary\n\n![](./assets/pipeline_light.svg)\n\nSupported profilers and current status:\n\n1. [**HUMANn v3**](https://huttenhower.sph.harvard.edu/humann/) \u2014 functional profiling via MetaPhlAn + HUMANn 3 (`--run_humann_v3`)\n2. [**HUMANn v4**](https://docs.google.com/document/d/1rCx5JkuO7wCKWrL8_-UJx_FkopJAfcDFtZktgPspak0/edit?tab=t.0#heading=h.i5hn0zprhwld) \u2014 functional profiling via MetaPhlAn + HUMANn 4 (`--run_humann_v4`)\n3. [**FMH FunProfiler**](https://github.com/KoslickiLab/fmh-funprofiler) \u2014 sketch-based functional profiling (`--run_fmhfunprofiler`)\n4. [**RGI**](https://github.com/arpcard/rgi) \u2014 antimicrobial resistance gene identification (`--run_rgi`, available)\n5. [**mifaser**](https://bromberglab.org/project/mifaser/) \u2014 functional profiling via mifaser (`--run_mifaser`, available)\n6. [**DIAMOND**](https://github.com/bbuchfink/diamond) \u2014 alignment with DIAMOND blastx (`--run_diamond`, work in progress / beta)\n7. [**eggNOG-mapper**](https://github.com/eggnogdb/eggnog-mapper) \u2014 functional annotation, orthology assignments and domain prediction (`--run_eggnogmapper`, work in progress / beta)\n\n> [!WARNING]\n> DIAMOND and eggNOG-mapper support is currently in beta and should be treated as work in progress. These modules are still being validated in the full pipeline, including database handling, output behavior, and downstream reporting. Use them with caution, expect potential issues, and independently review results before using them for production analyses or interpretation.\n\n## Usage\n\n> [!NOTE]\n> If you are new to Nextflow and nf-core, please refer to [this page](https://nf-co.re/docs/get_started/environment_setup/overview) on how to set-up Nextflow. Make sure to [test your setup](https://nf-co.re/docs/get_started/run-your-first-pipeline) with `-profile test` before running the workflow on actual data.\n\nFirst, prepare a samplesheet with your input data:\n\n`samplesheet.csv`:\n\n```csv\nsample,run_accession,instrument_platform,fastq_1,fastq_2,fasta\nSAMPLE1,RUN1,ILLUMINA,/path/to/sample1_R1.fastq.gz,/path/to/sample1_R2.fastq.gz,\nSAMPLE2,RUN1,ILLUMINA,/path/to/sample2.fastq.gz,,\n```\n\nEach row represents a sequencing run. Multiple rows with the same `sample` and different `run_accession` values will be merged before profiling. Reads are expected to arrive already preprocessed: the pipeline performs no read QC, trimming or host decontamination.\n\nThen prepare a databases sheet \u2014 see [docs/usage.md](docs/usage.md) for the full format. Here is an abbreviated example for running HUMANn (which requires 4 databases):\n\n`databases.csv`\n\n```csv\ntool,db_name,db_entity,db_params,db_path\nhumann_v3,uniref90_v3,humann_metaphlan,,/data/databases/metaphlan_db\nhumann_v3,uniref90_v3,humann_nucleotide,,/data/databases/chocophlan\nhumann_v3,uniref90_v3,humann_protein,,/data/databases/uniref90_diamond\nhumann_v3,uniref90_v3,humann_utility,,/data/databases/utility_mapping\n```\n\nNow, you can run the pipeline using:\n\n```bash\nnextflow run nf-core/funcprofiler \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --databases databases.csv \\\n --run_humann_v3\n```\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/running/run-pipelines#using-parameter-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/funcprofiler/usage) and the [parameter documentation](https://nf-co.re/funcprofiler/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/funcprofiler/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/funcprofiler/output).\n\n## Credits\n\nnf-core/funcprofiler was originally written by Nick Waters, Vini Salazar, Yixuan Yang, Mirae Baichoo.\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n- Matthias H\u00f6rtenhuber\n- James Fellows Yates\n- Jonas Scheid\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](docs/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#funcprofiler` channel](https://nfcore.slack.com/channels/funcprofiler) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" @@ -43,6 +43,9 @@ { "@id": "modules/" }, + { + "@id": "modules/local/" + }, { "@id": "modules/nf-core/" }, @@ -99,7 +102,7 @@ }, "mentions": [ { - "@id": "#43d93482-10b4-4a4a-9aae-56cf094b0489" + "@id": "#dad319cd-1b41-40c8-92bd-dd52d8c1eda4" } ], "name": "nf-core/funcprofiler" @@ -112,7 +115,7 @@ }, "conformsTo": [ { - "@id": "https://w3id.org/ro/crate/1.1" + "@id": "https://w3id.org/ro/crate/1.2" }, { "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0" @@ -126,13 +129,31 @@ "SoftwareSourceCode", "ComputationalWorkflow" ], - "creator": [ + "author": [ + { + "@id": "#02abcbb1-966b-4c2b-9848-c2ef3c65726e" + }, + { + "@id": "#865c248f-67f4-474a-9f1e-8f4ff51cffab" + }, + { + "@id": "#f74f489b-c4bb-4bb1-8e43-fdde330df31c" + }, { - "@id": "#nickp60@users.noreply.github.com" + "@id": "#7afafb31-7939-4b51-8cca-c73ca161e3e7" + }, + { + "@id": "#c7756996-91be-4b50-92a0-394343896060" + }, + { + "@id": "#66641cd0-9bcf-4871-bb16-e25bd870088a" + }, + { + "@id": "https://orcid.org/0000-0002-4219-9076" } ], "dateCreated": "", - "dateModified": "2025-08-13T11:15:55Z", + "dateModified": "2026-09-01T12:58:14Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", "keywords": [ "nf-core", @@ -143,7 +164,16 @@ ], "maintainer": [ { - "@id": "#nickp60@users.noreply.github.com" + "@id": "#02abcbb1-966b-4c2b-9848-c2ef3c65726e" + }, + { + "@id": "#865c248f-67f4-474a-9f1e-8f4ff51cffab" + }, + { + "@id": "#f74f489b-c4bb-4bb1-8e43-fdde330df31c" + }, + { + "@id": "#3f3b690c-5064-46b9-82c3-50d9a35a4502" } ], "name": [ @@ -157,10 +187,10 @@ }, "url": [ "https://github.com/nf-core/funcprofiler", - "https://nf-co.re/funcprofiler/dev/" + "https://nf-co.re/funcprofiler/1.0.0/" ], "version": [ - "1.0.0dev" + "1.0.0" ] }, { @@ -173,14 +203,14 @@ "url": { "@id": "https://www.nextflow.io/" }, - "version": "!>=24.10.5" + "version": "!>=25.10.4" }, { - "@id": "#43d93482-10b4-4a4a-9aae-56cf094b0489", + "@id": "#dad319cd-1b41-40c8-92bd-dd52d8c1eda4", "@type": "TestSuite", "instance": [ { - "@id": "#d1cf13a7-6e4d-4a5b-9196-57c7109be07f" + "@id": "#3a318617-b78c-4c00-b17f-e97e9560adea" } ], "mainEntity": { @@ -189,7 +219,7 @@ "name": "Test suite for nf-core/funcprofiler" }, { - "@id": "#d1cf13a7-6e4d-4a5b-9196-57c7109be07f", + "@id": "#3a318617-b78c-4c00-b17f-e97e9560adea", "@type": "TestInstance", "name": "GitHub Actions workflow for testing nf-core/funcprofiler", "resource": "repos/nf-core/funcprofiler/actions/workflows/nf-test.yml", @@ -231,6 +261,11 @@ "@type": "Dataset", "description": "Modules used by the pipeline" }, + { + "@id": "modules/local/", + "@type": "Dataset", + "description": "Pipeline-specific modules" + }, { "@id": "modules/nf-core/", "@type": "Dataset", @@ -318,10 +353,36 @@ "url": "https://nf-co.re/" }, { - "@id": "#nickp60@users.noreply.github.com", + "@id": "#02abcbb1-966b-4c2b-9848-c2ef3c65726e", + "@type": "Person", + "affiliation": "MSKCC", + "email": "nickp60@gmail.com", + "name": "Nick Waters", + "url": "https://github.com/nickp60" + }, + { + "@id": "#865c248f-67f4-474a-9f1e-8f4ff51cffab", + "@type": "Person", + "affiliation": "University of Melbourne", + "email": "17276653+vinisalazar@users.noreply.github.com", + "name": "Vini Salazar", + "url": "https://github.com/vinisalazar" + }, + { + "@id": "#f74f489b-c4bb-4bb1-8e43-fdde330df31c", + "@type": "Person", + "affiliation": "MSKCC", + "email": "miraep8@gmail.com", + "name": "Mirae B", + "url": "https://github.com/miraep8" + }, + { + "@id": "#3f3b690c-5064-46b9-82c3-50d9a35a4502", "@type": "Person", - "email": "nickp60@users.noreply.github.com", - "name": "Nick Waters" + "affiliation": "NC State", + "email": "yyang55@ncsu.edu", + "name": "Yixuan Yang", + "url": "https://github.com/Yixuan39" } ] } \ No newline at end of file diff --git a/subworkflows/local/dataprep/main.nf b/subworkflows/local/dataprep/main.nf new file mode 100644 index 0000000..c7912b8 --- /dev/null +++ b/subworkflows/local/dataprep/main.nf @@ -0,0 +1,74 @@ +// +// Prepare the reads for profiling. +// +// Takes the validated samplesheet channel from PIPELINE_INITIALISATION, merges the sequencing +// runs belonging to the same sample, and emits the two read layouts the profilers need: +// +// reads - 1 file for single-end samples, 2 for paired-end, real endedness preserved. +// reads_concat - always exactly 1 file, R1 and R2 concatenated, `meta.single_end` forced to +// true so that single-FASTQ tools see a single-end sample. +// +include { CAT_FASTQ as MERGE_RUNS } from '../../../modules/nf-core/cat/fastq/main' +include { CAT_FASTQ } from '../../../modules/nf-core/cat/fastq/main' + +workflow DATAPREP { + take: + reads // channel: [ val(meta), [ path(reads) ] ] + + main: + + // Step 1: Group by meta.id and merge runs if needed + ch_grouped = reads + .map { meta, fastqs -> + // Create grouping key and new meta without run_accession for grouping + def group_key = meta.id + [group_key, meta, fastqs] + } + .groupTuple(by: 0) + .map { _group_key, meta_list, reads_list -> + // Take the first meta as template (they should all have same id) + def meta = meta_list[0] + // Remove run_accession since we're merging runs + meta = meta - meta.subMap('run_accession') + + // Flatten all reads into a single list + def all_reads = reads_list.flatten() + + [meta, all_reads] + } + .branch { meta, fastqs -> + merge: (meta.single_end && fastqs.size() > 1) || (!meta.single_end && fastqs.size() > 2) + skip: true + } + + // Merge reads for samples that need it + ch_merged = MERGE_RUNS(ch_grouped.merge).reads + + // Combine merged and non-merged samples + ch_reads = ch_merged.mix(ch_grouped.skip) + + // Step 2: Create concatenated single-file version for tools that need it + ch_for_concat = ch_reads + .map { meta, fastqs -> + // Mark as single_end for CAT_FASTQ to concatenate R1 and R2 into one file + def meta_concat = meta.clone() + meta_concat.single_end = true + [meta_concat, fastqs] + } + .branch { _meta, fastqs -> + concat: fastqs.size() > 1 + skip: true + } + + // Concatenate all reads into single file per sample + ch_concatenated = CAT_FASTQ(ch_for_concat.concat).reads + .mix(ch_for_concat.skip) + .map { meta, fastqs -> + // Ensure reads is always a list + [meta, [fastqs].flatten()] + } + + emit: + reads = ch_reads // Paired-end reads (R1, R2) or single-end + reads_concat = ch_concatenated // All reads concatenated into single file +} diff --git a/subworkflows/local/dataprep/meta.yml b/subworkflows/local/dataprep/meta.yml new file mode 100644 index 0000000..915faa4 --- /dev/null +++ b/subworkflows/local/dataprep/meta.yml @@ -0,0 +1,43 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "dataprep" +description: | + Validate the input samplesheet and prepare read channels for profiling. Sets + `single_end`, `run_accession` and `instrument_platform` on the meta map, merges + multiple runs belonging to the same sample, and produces an additional channel + in which read pairs are concatenated into a single file for tools that cannot + take paired input. +keywords: + - samplesheet + - fastq + - merging + - concatenation + - metagenome +components: + - cat/fastq +input: + - samplesheet: + type: file + description: | + Channel of validated samplesheet rows. Long-read (`OXFORD_NANOPORE`) + platforms and FASTA input are rejected, and `fastq_1` is required. + Structure: [ val(meta), val(run_accession), val(instrument_platform), path(fastq_1), path(fastq_2), path(fasta) ] + pattern: "*.{fq,fastq}{,.gz}" +output: + - reads: + type: file + description: | + Channel of reads per sample, with runs merged where a sample has more + than one. Paired-end samples carry two files, single-end samples one. + Structure: [ val(meta), [ path(reads) ] ] + pattern: "*.{fq,fastq}{,.gz}" + - reads_concat: + type: file + description: | + Channel of the same reads concatenated into a single file per sample, + with `single_end` forced to `true`, for tools that accept only one FASTQ. + Structure: [ val(meta), [ path(reads) ] ] + pattern: "*.{fq,fastq}{,.gz}" +authors: + - "@nickp60" +maintainers: + - "@nickp60" diff --git a/subworkflows/local/dataprep/tests/main.nf.test b/subworkflows/local/dataprep/tests/main.nf.test new file mode 100644 index 0000000..7a46688 --- /dev/null +++ b/subworkflows/local/dataprep/tests/main.nf.test @@ -0,0 +1,68 @@ +nextflow_workflow { + + name "Test Subworkflow DATAPREP" + script "../main.nf" + workflow "DATAPREP" + + tag "subworkflows" + tag "subworkflows_" + tag "subworkflows/dataprep" + tag "cat_fastq" + + test("paired-end runmerged") { + + when { + workflow { + """ + input[0] = Channel.fromList([ + [ + [id: '2612', single_end: false, run_accession: 'ERR5766176', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'taxprofiler/data/fastq/ERX5474932_ERR5766176_1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'taxprofiler/data/fastq/ERX5474932_ERR5766176_2.fastq.gz') + ] + ], + [ + [id: '2612', single_end: false, run_accession: 'ERR5766176_B', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'taxprofiler/data/fastq/ERX5474932_ERR5766176_B_1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'taxprofiler/data/fastq/ERX5474932_ERR5766176_B_2.fastq.gz') + ] + ], + [ + [id: 'minigut', single_end: false, run_accession: '1', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R2.fastq.gz') + ] + ] + ]) + """ + } + } + then { + assert workflow.success + + def items = workflow.out.reads_concat.toList() + assert items.size() == 2, "run merging appears to have failed" + + items.each { meta, reads -> + // Check exactly 1 file per sample for concat channel + def fileList = reads instanceof List ? reads : [reads] + assert fileList.size() == 1, "Expected exactly 1 fastq file for ${meta.id}, got ${fileList}" + } + + def pe_items = workflow.out.reads.toList() + + pe_items.each { meta, reads -> + // Check exactly 2 files per sample for the paired channel + def fileList = reads instanceof List ? reads : [reads] + assert fileList.size() == 2, "Expected exactly 2 fastq files for ${meta.id}, got ${fileList}" + } + + assertAll( + { assert snapshot(workflow.out).match() } + ) + } + } +} diff --git a/subworkflows/local/dataprep/tests/main.nf.test.snap b/subworkflows/local/dataprep/tests/main.nf.test.snap new file mode 100644 index 0000000..8b9fa61 --- /dev/null +++ b/subworkflows/local/dataprep/tests/main.nf.test.snap @@ -0,0 +1,105 @@ +{ + "paired-end runmerged": { + "content": [ + { + "0": [ + [ + { + "id": "2612", + "single_end": false, + "instrument_platform": "ILLUMINA" + }, + [ + "2612_1.merged.fastq.gz:md5,e38f6e7ad98fc7b848b4967bde945d13", + "2612_2.merged.fastq.gz:md5,5f40e29533a8f88521954301b836dbd8" + ] + ], + [ + { + "id": "minigut", + "single_end": false, + "instrument_platform": "ILLUMINA" + }, + [ + "/nf-core/test-datasets/mag/test_data/test_minigut_R1.fastq.gz", + "/nf-core/test-datasets/mag/test_data/test_minigut_R2.fastq.gz" + ] + ] + ], + "1": [ + [ + { + "id": "2612", + "single_end": true, + "instrument_platform": "ILLUMINA" + }, + [ + "2612.merged.fastq.gz:md5,270bf4c4d9707c6afc970fe5622cc673" + ] + ], + [ + { + "id": "minigut", + "single_end": true, + "instrument_platform": "ILLUMINA" + }, + [ + "minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129" + ] + ] + ], + "reads": [ + [ + { + "id": "2612", + "single_end": false, + "instrument_platform": "ILLUMINA" + }, + [ + "2612_1.merged.fastq.gz:md5,e38f6e7ad98fc7b848b4967bde945d13", + "2612_2.merged.fastq.gz:md5,5f40e29533a8f88521954301b836dbd8" + ] + ], + [ + { + "id": "minigut", + "single_end": false, + "instrument_platform": "ILLUMINA" + }, + [ + "/nf-core/test-datasets/mag/test_data/test_minigut_R1.fastq.gz", + "/nf-core/test-datasets/mag/test_data/test_minigut_R2.fastq.gz" + ] + ] + ], + "reads_concat": [ + [ + { + "id": "2612", + "single_end": true, + "instrument_platform": "ILLUMINA" + }, + [ + "2612.merged.fastq.gz:md5,270bf4c4d9707c6afc970fe5622cc673" + ] + ], + [ + { + "id": "minigut", + "single_end": true, + "instrument_platform": "ILLUMINA" + }, + [ + "minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129" + ] + ] + ] + } + ], + "timestamp": "2026-04-18T00:05:15.049339", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file diff --git a/subworkflows/local/dbprep/main.nf b/subworkflows/local/dbprep/main.nf new file mode 100644 index 0000000..0a7ef07 --- /dev/null +++ b/subworkflows/local/dbprep/main.nf @@ -0,0 +1,68 @@ +// +// Prepare the databases for profiling. +// +// Takes the validated database sheet from PIPELINE_INITIALISATION, drops the rows belonging to +// profilers that are not enabled, decompresses the TAR archives among the rest, and groups the +// remaining paths by [ tool, db_name, db_params ] into a Map of `db_entity -> path`. Tools that +// take a single database leave `db_entity` empty in the sheet and are stored under 'main'. +// +include { UNTAR } from '../../../modules/nf-core/untar/main' + +workflow DBPREP { + take: + databases + + main: + + // Validate and decompress databases + ch_dbs_for_untar = databases.branch { db_meta, db_path -> + untar: db_path.name.endsWith(".tar.gz") | db_path.name.endsWith(".tar.bz2") | db_path.name.endsWith(".tar") | db_path.name.endsWith(".tar.xz") + skip: true + } + // Filter the channel to untar only those databases for tools that are selected to be run by the user. + // Also, to ensure only untar once per file, group together all databases of one file + ch_inputdb_untar = ch_dbs_for_untar.untar + .filter { db_meta, db_path -> + params["run_${db_meta.tool}"] + } + .groupTuple(by: 1) + .map { meta, dbfile -> + def new_meta = ['id': dbfile.baseName] + ['meta': meta] + [new_meta, dbfile] + } + + // Untar the databases + UNTAR(ch_inputdb_untar) + // Spread out the untarred and shared databases + ch_outputdb_from_untar = UNTAR.out.untar + .map { meta, db -> + [meta.meta, db] + } + .transpose(by: 0) + + ch_semifinal_dbs = ch_dbs_for_untar.skip + .mix(ch_outputdb_from_untar) + .map { db_meta, db -> + def corrected_db_params = db_meta.db_params ? [db_params: db_meta.db_params] : [db_params: '-'] + [db_meta + corrected_db_params, db] + } + + ch_grouped_dbs = ch_semifinal_dbs + .map { meta, path -> + def entity = meta.db_entity ?: 'main' + [[tool: meta.tool, db_name: meta.db_name, db_params: meta.db_params], [entity, path]] + } + .groupTuple() + .map { groupKey, groupTuples -> + def grouped_dbs = groupTuples.collect { tuple -> + [ + db_entity: tuple[0], + db_path: tuple[1], + ] + } + return [groupKey, grouped_dbs] + } + + emit: + dbs = ch_grouped_dbs +} diff --git a/subworkflows/local/dbprep/meta.yml b/subworkflows/local/dbprep/meta.yml new file mode 100644 index 0000000..89e987e --- /dev/null +++ b/subworkflows/local/dbprep/meta.yml @@ -0,0 +1,36 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "dbprep" +description: | + Prepare the databases declared in the database sheet. Archives are decompressed + once per file and only for tools the user has enabled, then all entities + belonging to the same database are grouped so that each profiler receives a + single entry per database name and parameter combination. +keywords: + - database + - untar + - decompression + - metagenome +components: + - untar +input: + - databases: + type: file + description: | + Channel of database entries from the database sheet. `meta.tool` selects + which profiler the database belongs to, `meta.db_entity` names the part + of a multi-file database, and `meta.db_params` carries tool-specific + arguments. Entries ending in `.tar`, `.tar.gz`, `.tar.bz2` or `.tar.xz` + are decompressed, the rest are passed through untouched. + Structure: [ val(meta), path(database) ] + pattern: "*.{tar,tar.gz,tar.bz2,tar.xz}" +output: + - dbs: + type: file + description: | + Channel of databases grouped by tool, name and parameters. The second + element is a list of maps, each holding the entity name and its path. + Structure: [ val(meta), [ [ db_entity: val(entity), db_path: path(db) ] ] ] +authors: + - "@nickp60" +maintainers: + - "@nickp60" diff --git a/subworkflows/local/dbprep/tests/main.nf.test b/subworkflows/local/dbprep/tests/main.nf.test new file mode 100644 index 0000000..76adb84 --- /dev/null +++ b/subworkflows/local/dbprep/tests/main.nf.test @@ -0,0 +1,59 @@ +nextflow_workflow { + + name "Test Subworkflow DBPREP" + script "../main.nf" + workflow "DBPREP" + + tag "subworkflows" + tag "subworkflows_" + tag "subworkflows/dbprep" + test("leave untarred alone") { + + when { + workflow { + """ + // Test that non-taredfiles don't get mutilated + input[0] = Channel.of([ + [ tool:'test', db_name:'test_dontuntar' ], // meta map + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true), + ]) + """ + } + } + then { + assert workflow.success + assertAll( + { assert snapshot( + workflow.out + ).match() } + ) + } + } + test("untar test db") { + + when { + workflow { + """ + input[0] = Channel.of( + [ + [id: 'testfmh', + tool: 'fmhfunprofiler', + db_name: 'fmhfunprofiler1000', + db_entity: '', + db_params: '11 1000' + ], + file(params.modules_testdata_base_path + 'funcprofiler/data/database/fmhfunprofiler/KOs_sketched_scaled_1000_demo.sig.zip') + ]) + """ + } + } + then { + assert workflow.success + assertAll( + { assert snapshot( + workflow.out + ).match() } + ) + } + } +} diff --git a/subworkflows/local/dbprep/tests/main.nf.test.snap b/subworkflows/local/dbprep/tests/main.nf.test.snap new file mode 100644 index 0000000..c4ada7d --- /dev/null +++ b/subworkflows/local/dbprep/tests/main.nf.test.snap @@ -0,0 +1,84 @@ +{ + "untar test db": { + "content": [ + { + "0": [ + [ + { + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "11 1000" + }, + [ + { + "db_entity": "main", + "db_path": "/nf-core/test-datasets/modules/data/funcprofiler/data/database/fmhfunprofiler/KOs_sketched_scaled_1000_demo.sig.zip" + } + ] + ] + ], + "dbs": [ + [ + { + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "11 1000" + }, + [ + { + "db_entity": "main", + "db_path": "/nf-core/test-datasets/modules/data/funcprofiler/data/database/fmhfunprofiler/KOs_sketched_scaled_1000_demo.sig.zip" + } + ] + ] + ] + } + ], + "timestamp": "2026-04-17T14:42:38.677532", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "leave untarred alone": { + "content": [ + { + "0": [ + [ + { + "tool": "test", + "db_name": "test_dontuntar", + "db_params": "-" + }, + [ + { + "db_entity": "main", + "db_path": "/nf-core/test-datasets/modules/data/genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam" + } + ] + ] + ], + "dbs": [ + [ + { + "tool": "test", + "db_name": "test_dontuntar", + "db_params": "-" + }, + [ + { + "db_entity": "main", + "db_path": "/nf-core/test-datasets/modules/data/genomics/sarscov2/illumina/bam/test.paired_end.sorted.bam" + } + ] + ] + ] + } + ], + "timestamp": "2026-04-17T14:42:33.150258", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + } +} \ No newline at end of file diff --git a/subworkflows/local/profile/main.nf b/subworkflows/local/profile/main.nf new file mode 100644 index 0000000..467e861 --- /dev/null +++ b/subworkflows/local/profile/main.nf @@ -0,0 +1,295 @@ +// +// Run profiling +// + +include { MIFASER } from '../../../modules/nf-core/mifaser/main' +include { HUMANN3_HUMANN } from '../../../modules/nf-core/humann3/humann/main' +include { HUMANN4 } from '../../../modules/local/humann4/humann/main' +include { HUMANN3_REGROUP } from '../../../modules/nf-core/humann3/regroup/main' +include { HUMANN4_REGROUP } from '../../../modules/local/humann4/regroup/main' +include { FMHFUNPROFILER } from '../../../modules/nf-core/fmhfunprofiler/main' +include { + METAPHLAN_METAPHLAN as MPAHUMANN3 ; + METAPHLAN_METAPHLAN as MPAHUMANN4 +} from '../../../modules/nf-core/metaphlan/metaphlan/main' +include { DIAMOND_BLASTX } from '../../../modules/nf-core/diamond/blastx/main' +include { RGI_BWT } from '../../../modules/nf-core/rgi/bwt/main' +include { RGI_CARDANNOTATION } from '../../../modules/nf-core/rgi/cardannotation/main' +include { EGGNOGMAPPER } from '../../../modules/nf-core/eggnogmapper/main' +include { SEQKIT_FQ2FA } from '../../../modules/nf-core/seqkit/fq2fa/main' +include { GUNZIP } from '../../../modules/nf-core/gunzip/main' + +workflow PROFILE { + take: + reads // [ [ meta ], [ reads ] ] + reads_concat // [ [ meta ], [ reads ] ] + databases // [ [ meta ], path ] + + main: + // These are count tables + ch_raw_profiles = channel.empty() + + /* + COMBINE READS WITH POSSIBLE DATABASES + */ + // Each tool as a slightly different input structure and generally separate + // input channels for reads vs databases. We restructure the channel tuple + // for each tool and make liberal use of multiMap to keep reads/databases + // channel element order in sync with each other + + // PAIRED-END READ TOOLS + ch_input_for_rgi = prepareInputs(reads, databases, 'rgi', false) + ch_input_for_eggnogmapper = prepareInputs(reads_concat, databases, 'eggnogmapper', true) + + // CONCAT READ TOOLS + ch_input_for_fmhfunprofiler = prepareInputs(reads_concat, databases, 'fmhfunprofiler', true) + ch_input_for_diamond = prepareInputs(reads_concat, databases, 'diamond', true) + ch_input_for_humann_v3 = prepareInputs(reads_concat, databases, 'humann_v3', true) + ch_input_for_humann_v4 = prepareInputs(reads_concat, databases, 'humann_v4', true) + ch_input_for_mifaser = prepareInputs(reads_concat, databases, 'mifaser', true) + + if (params.run_fmhfunprofiler) { + // this tool needs the db_params at runtime, so it takes a [[meta], path] tuple instead of just a path. + // db_params is checked for its two integers by validateProfilerDatabases() at pipeline initialisation. + fmh_db = getDbPath(ch_input_for_fmhfunprofiler.db, "main", true) + .multiMap { db_meta, db_path -> + def args = db_meta.db_params.split(" ") + db_path: db_path + kmer: args[0] + sketch: args[1] + } + FMHFUNPROFILER( + ch_input_for_fmhfunprofiler.reads, + fmh_db.db_path, + fmh_db.kmer, + fmh_db.sketch, + ) + ch_raw_profiles = ch_raw_profiles.mix(FMHFUNPROFILER.out.csv) + } + if (params.run_mifaser) { + MIFASER(ch_input_for_mifaser.reads, getDbPath(ch_input_for_mifaser.db, 'main')) + ch_raw_profiles = ch_raw_profiles.mix(MIFASER.out.ec_counts) + } + + if (params.run_humann_v3) { + MPAHUMANN3( + ch_input_for_humann_v3.reads, + getDbPath(ch_input_for_humann_v3.db, 'humann_metaphlan'), + false, + ) + // JOIN the original reads with the profile output + ch_humann3_input = ch_input_for_humann_v3.reads.join(MPAHUMANN3.out.profile, by: 0) + // Join on meta map + HUMANN3_HUMANN( + ch_humann3_input.map { it -> [it[0], it[1]] }, + ch_humann3_input.map { it -> [it[0], it[2]] }, + getDbPath(ch_input_for_humann_v3.db, 'humann_nucleotide'), + getDbPath(ch_input_for_humann_v3.db, 'humann_protein'), + getDbPath(ch_input_for_humann_v3.db, 'humann_utility'), + ) + HUMANN3_REGROUP(HUMANN3_HUMANN.out.genefamilies, "uniref90_level4ec", getDbPath(ch_input_for_humann_v3.db, 'humann_utility')) + ch_raw_profiles = ch_raw_profiles.mix(MPAHUMANN3.out.profile) + ch_raw_profiles = ch_raw_profiles + .mix(HUMANN3_HUMANN.out.pathabundance) + .mix(HUMANN3_HUMANN.out.genefamilies) + .mix(HUMANN3_HUMANN.out.pathcoverage) + .mix(HUMANN3_REGROUP.out.regroup) + } + if (params.run_humann_v4) { + MPAHUMANN4( + ch_input_for_humann_v4.reads, + getDbPath(ch_input_for_humann_v4.db, 'humann_metaphlan'), + false, + ) + // Join on meta map + ch_humann4_input = ch_input_for_humann_v4.reads.join(MPAHUMANN4.out.profile, by: 0) + HUMANN4( + ch_humann4_input.map { it -> [it[0], it[1]] }, + ch_humann4_input.map { it -> [it[0], it[2]] }, + getDbPath(ch_input_for_humann_v4.db, 'humann_nucleotide'), + getDbPath(ch_input_for_humann_v4.db, 'humann_protein'), + getDbPath(ch_input_for_humann_v4.db, 'humann_utility'), + ) + HUMANN4_REGROUP(HUMANN4.out.genefamilies, "uniclust90_level4ec", getDbPath(ch_input_for_humann_v4.db, 'humann_utility')) + ch_raw_profiles = ch_raw_profiles + .mix(HUMANN4.out.pathabundance) + .mix(HUMANN4.out.genefamilies) + .mix(HUMANN4.out.reactions) + .mix(HUMANN4_REGROUP.out.regroup) + } + + if (params.run_diamond) { + // 'txt' selects --outfmt 6 (tabular alignments). Do not use 'tsv': that is + // --outfmt 102, DIAMOND's taxonomic classification format, which requires a + // database built with --taxonmap/--taxonnodes and reports taxa rather than hits. + DIAMOND_BLASTX(ch_input_for_diamond.reads, getDbPath(ch_input_for_diamond.db, "main", true), 'txt', '') + ch_raw_profiles = ch_raw_profiles.mix(DIAMOND_BLASTX.out.txt) + } + + if (params.run_rgi) { + RGI_CARDANNOTATION(getDbPath(ch_input_for_rgi.db, "main")) + RGI_BWT(ch_input_for_rgi.reads, RGI_CARDANNOTATION.out.db, []) + ch_raw_profiles = ch_raw_profiles.mix(RGI_BWT.out.tsv) + } + if (params.run_eggnogmapper) { + SEQKIT_FQ2FA(ch_input_for_eggnogmapper.reads) + GUNZIP(SEQKIT_FQ2FA.out.fasta) + // EGGNOGMAPPER takes the search database as [ search_mode, db ]: the mode picks the + // flag emapper.py is given, and 'diamond' is what a .dmnd database needs. + EGGNOGMAPPER( + GUNZIP.out.gunzip, + getDbPath(ch_input_for_eggnogmapper.db, "eggnogmapper_db").map { db -> ['diamond', db] }, + getDbPath(ch_input_for_eggnogmapper.db, "eggnogmapper_data_dir"), + ) + ch_raw_profiles = ch_raw_profiles.mix(EGGNOGMAPPER.out.annotations) + } + + emit: + profiles = ch_raw_profiles // channel: [ val(meta), path(profile) ] + // Software versions are published to the `versions` topic by each module +} + + +// due to https://github.com/askimed/nf-test/issues/309 +workflow TEST_PREPAREINPUTS_WRAPPER { + take: + reads + databases + tool_name + singleFqTool + + main: + testresult = prepareInputs(reads, databases, tool_name, singleFqTool) + + emit: + reads = testresult.reads + db = testresult.db +} + + +// Custom Functions + +// +// Make a string safe to use as a channel element id: underscores and whitespace to hyphens, +// anything else that is not a word character or a dot dropped, runs of hyphens collapsed. +// +def sanitizeId(str) { + return str + .toString() + // underscores to hyphens, spaces to hyphens, drop special chars, collapse hyphens + .replaceAll(/_/, '-') + .replaceAll(/\s+/, '-') + .replaceAll(/[^\w\-.]/, '') + .replaceAll(/-+/, '-') +} + +/** +* Combine a reads channel with the databases of one tool, and split the result into the two +* channels a profiler module takes, keeping their element order in sync. +* +* @param pairedreads A channel of [ meta, [ reads ] ] +* @param databases A channel of [ db_meta, [ db_file ] ], as emitted by DBPREP +* @param tool_name Only databases with this `tool` are used +* @param singleFqTool True for tools that take a single FASTQ, i.e. that are fed reads_concat +* @return A multiMap'ed channel with a `.reads` and a `.db` sub-channel +*/ +def prepareInputs(pairedreads, databases, tool_name, singleFqTool = false) { + // Step 1: Filter databases to only the requested tool, then group by db_name and db_params + def ch_dbs_grouped = databases + .flatMap { meta_db, file_list -> + // Flatten: emit one tuple per file object + file_list.collect { file_obj -> + // Merge the file object's db_entity into the metadata + def meta_with_entity = meta_db + [db_entity: file_obj.db_entity] + [meta_with_entity, file_obj] + } + } + .filter { meta_db, file -> + meta_db.tool == tool_name + } + .map { meta_db, file -> + // Create grouping key: [tool, db_name, db_params] + def group_key = [meta_db.tool, meta_db.db_name ?: '', meta_db.db_params ?: ''] + [group_key, meta_db, file] + } + // Group all files for same tool+db_name+db_params + .groupTuple() + .map { group_key, meta_db_list, files -> + def tool = group_key[0] + def db_name = group_key[1] + def db_params = group_key[2] + + // Convert files list to Map keyed by db_entity for deterministic snapshots + // Map structure: entity_name -> db_path (entity is already in the key) + def files_map = [:] + [meta_db_list, files] + .transpose() + .each { meta_db, file -> + // Store only the path + files_map[meta_db.db_entity] = file.db_path + } + + // Create consolidated metadata with db_entities as a Set + def meta_db_grouped = [id: sanitizeId("${tool}--${db_name}--${db_params}"), tool: tool, db_name: db_name, db_params: db_params, db_entities: files_map.keySet() as Set, num_files: files_map.size()] + + // Return files as map + [meta_db_grouped, files_map.toSorted()] + } + // Step 2: Combine reads with ALL grouped databases (cartesian product) + // Each sample will get one entry per unique db_name+db_params combination for this tool + def reads_with_dbs = pairedreads + .combine(ch_dbs_grouped) + .map { meta_sample, reads, meta_db, db_files_map -> + // Flatten reads to ensure consistent list format + def flat_reads = [reads].flatten() + + // Return: [meta_sample, reads_list, meta_db, db_files_map] + [meta_sample, flat_reads, meta_db, db_files_map] + } + + // Step 3: Validate and add metadata based on tool type + def result = reads_with_dbs + .map { meta, reads, db_meta, db_files -> + def expected = meta.single_end | singleFqTool ? 1 : 2 + if (reads.size() != expected) { + error("PE-aware tool (${!singleFqTool}) '${db_meta.tool}': expected ${expected} read file(s) for sample ${meta.id} (single_end=${meta.single_end}), got ${reads.size()}") + } + [meta, reads, db_meta, db_files] + } + .multiMap { it -> + // Carry the database identity into the read meta so that ext.args, ext.prefix + // and publishDir can key on it, as nf-core/taxprofiler does. Only a subset is + // merged: meta_db also holds an id, which must not overwrite the sample id. + reads: [it[0] + it[2].subMap('tool', 'db_name', 'db_params'), it[1]] + db: [it[2], it[3]] + } + return result +} + +/** +* Pull one component out of a grouped database. +* +* DBPREP hands each tool its database as a Map of `db_entity -> path`, keyed by the `db_entity` +* column of the database sheet. Tools that take a single database file or directory leave that +* column empty and DBPREP stores it under 'main'; HUMAnN and eggNOG-mapper need several +* components and address them by name. +* +* Which components each profiler requires is checked by validateProfilerDatabases() at pipeline +* initialisation. The error below is only a backstop, so that a missing entity fails loudly here +* rather than reaching the module as a null path. +* +* @param groupeddb A channel of [ db_meta, Map[db_entity -> path] ], as emitted by DBPREP +* @param entity The db_entity to look up +* @param asTuple Return [ db_meta, path ] instead of just the path, for tools that need db_params +* @return A channel of the requested database path, or of [ db_meta, path ] +*/ +def getDbPath(groupeddb, entity = 'main', asTuple = false) { + return groupeddb.map { meta_db, files_map -> + if (!files_map.containsKey(entity)) { + error("No entity '${entity}' file found in database ${meta_db.id}") + } + + def db_path = files_map[entity] + asTuple ? [meta_db, db_path] : db_path + } +} diff --git a/subworkflows/local/profile/meta.yml b/subworkflows/local/profile/meta.yml new file mode 100644 index 0000000..d69de4d --- /dev/null +++ b/subworkflows/local/profile/meta.yml @@ -0,0 +1,61 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/subworkflows/yaml-schema.json +name: "profile" +description: | + Run the enabled read-based functional profilers. Reads are combined with every + database matching the tool, so a sample is profiled once per database name and + parameter combination. Tools that take paired input read from `reads`, tools + that take a single FASTQ read from `reads_concat`, and each profiler runs only + when its `run_` parameter is set. +keywords: + - microbiome + - metagenome + - fastq + - functional profiling +components: + - fmhfunprofiler + - mifaser + - humann3/humann + - humann3/regroup + - humann4 + - humann4/regroup + - metaphlan/metaphlan + - diamond/blastx + - rgi/bwt + - rgi/cardannotation + - eggnogmapper + - seqkit/fq2fa + - gunzip +input: + - reads: + type: file + description: | + Channel of paired-end (or single-end) reads, used by the profilers that + accept a read pair. + Structure: [ val(meta), [ path(reads) ] ] + pattern: "*.{fq,fastq}{,.gz}" + - reads_concat: + type: file + description: | + Channel of reads concatenated into a single file per sample, used by the + profilers that accept only one FASTQ. + Structure: [ val(meta), [ path(reads) ] ] + pattern: "*.{fq,fastq}{,.gz}" + - databases: + type: file + description: | + Channel of grouped databases as emitted by the `dbprep` subworkflow. + Structure: [ val(meta), [ [ db_entity: val(entity), db_path: path(db) ] ] ] +output: + - profiles: + type: file + description: | + Channel of the tabular profiles produced by each enabled tool. The meta + map identifies the sample, the tool and the database used. + Structure: [ val(meta), path(profile) ] + pattern: "*.{tsv,csv,txt}" +# Software versions are published to the `versions` topic by each module rather +# than emitted as a channel. +authors: + - "@nickp60" +maintainers: + - "@nickp60" diff --git a/subworkflows/local/profile/tests/main.nf.test b/subworkflows/local/profile/tests/main.nf.test new file mode 100644 index 0000000..8234c8a --- /dev/null +++ b/subworkflows/local/profile/tests/main.nf.test @@ -0,0 +1,356 @@ +nextflow_workflow { + + topics 'versions' + name "Test profile" + script "../main.nf" + workflow "PROFILE" + + tag "subworkflows" + tag "subworkflows/profile" + + test("run multisampleinputs - grouped databases (humann_v3)") { + tag 'humann' + setup { + run("DATAPREP") { + script "subworkflows/local/dataprep/main.nf" + process { + """ + input[0] = Channel.fromList([ + [ + [id: 'minigut', single_end: false, run_accession: '1', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R2.fastq.gz') + ] + ] + ]) + """ + } + } + + run("DBPREP") { + script "subworkflows/local/dbprep/main.nf" + process { + """ + input[0] = Channel.of( + [ + [id: 'fmh', tool: 'fmhfunprofiler', db_name: 'demo_1000', db_entity: '', db_params: '11 1000'], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/fmhfunprofiler/KOs_sketched_scaled_1000_demo.sig.zip') + ], + [ + [id: 'humann_v3_demo_v3_humann_nucleotide', tool: 'humann_v3', db_name: 'demo_v3', db_entity: 'humann_nucleotide', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v3/chocophlan_nfDEMO.tar.gz') + ], + [ + [id: 'humann_v3_demo_v3_humann_protein', tool: 'humann_v3', db_name: 'demo_v3', db_entity: 'humann_protein', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v3/uniref_nfDEMO.tar.gz') + ], + [ + [id: 'humann_v3_demo_v3_humann_metaphlan', tool: 'humann_v3', db_name: 'demo_v3', db_entity: 'humann_metaphlan', db_params: ''], + file('https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/delete_me/metaphlan4_database.tar.gz') + ], + [ + [id: 'humann_v3_demo_v3_humann_utility', tool: 'humann_v3', db_name: 'demo_v3', db_entity: 'humann_utility', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v3/utility_nfDEMO.tar.gz') + ] + ) + """ + } + } + } + when { + params { + run_humann_v3 = true + run_fmhfunprofiler = true + outdir = "$outputDir" + } + workflow { + """ + input[0] = DATAPREP.out.reads + input[1] = DATAPREP.out.reads_concat + input[2] = DBPREP.out.dbs + """ + } + } + then { + assert workflow.success + + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assert snapshot(stable_path).match() + } + } + + test("run fmh") { + tag 'fmh' + setup { + run("DATAPREP") { + script "subworkflows/local/dataprep/main.nf" + process { + """ + input[0] = Channel.fromList([ + [ + [id: 'minigut', single_end: false, run_accession: '1', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R2.fastq.gz') + ] + ] + ]) + """ + } + } + + run("DBPREP") { + script "subworkflows/local/dbprep/main.nf" + process { + """ + input[0] = Channel.of( + [ + [id: 'fmh', tool: 'fmhfunprofiler', db_name: 'demo_1000', db_entity: '', db_params: '11 1000'], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/fmhfunprofiler/KOs_sketched_scaled_1000_demo.sig.zip') + ] + ) + """ + } + } + } + when { + params { + run_humann_v3 = false + run_fmhfunprofiler = true + outdir = "$outputDir" + } + workflow { + """ + input[0] = DATAPREP.out.reads + input[1] = DATAPREP.out.reads_concat + input[2] = DBPREP.out.dbs + """ + } + } + then { + assert workflow.success + + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assert snapshot(stable_path).match() + } + } + + test("run RGI") { + tag 'rgi' + setup { + run("DATAPREP") { + script "subworkflows/local/dataprep/main.nf" + process { + """ + input[0] = Channel.fromList([ + [ + [id: 'minigut', single_end: false, run_accession: '1', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R2.fastq.gz') + ] + ] + ]) + """ + } + } + + run("DBPREP") { + script "subworkflows/local/dbprep/main.nf" + process { + """ + input[0] = Channel.of( + [ + [id: 'rgi', tool: 'rgi', db_name: 'fullv4', db_entity: '', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/rgi/broadstreet-v4.0.1.tar.bz2') + ] + ) + """ + } + } + } + when { + params { + run_humann_v3 = false + run_rgi = true + run_fmhfunprofiler = false + outdir = "$outputDir" + } + workflow { + """ + input[0] = DATAPREP.out.reads + input[1] = DATAPREP.out.reads_concat + input[2] = DBPREP.out.dbs + """ + } + } + then { + assert workflow.success + + def rgi_paths = getAllFilesFromDir(params.outdir, include: ["rgi/**"], ignore: ["rgi/card_database_processed/**"]) + def outDir = rgi_paths[0].parentFile + + def mappingFile = outDir.listFiles().find { it.name.endsWith(".gene_mapping_data.txt") } + assert mappingFile != null : "No .gene_mapping_data.txt file found in ${outDir}" + + def sortedLines = mappingFile.readLines().sort() + + assert snapshot(sortedLines + topics.versions).match() + } + } + + test("run eggnogmapper") { + tag 'eggnogmapper' + setup { + run("DATAPREP") { + script "subworkflows/local/dataprep/main.nf" + process { + """ + // sarscov2 reads rather than minigut: the demo eggnog.db only carries + // annotations for the proteins in the demo proteome.dmnd, so a gut + // metagenome snapshots an annotation file with nothing but the header + input[0] = Channel.fromList([ + [ + [id: 'sarscov2', single_end: false, run_accession: '1', instrument_platform: 'ILLUMINA'], + [ + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_1.fastq.gz'), + file(params.modules_testdata_base_path + 'genomics/sarscov2/illumina/fastq/test_2.fastq.gz') + ] + ] + ]) + """ + } + } + + run("DBPREP") { + script "subworkflows/local/dbprep/main.nf" + process { + """ + // emapper.py's --data_dir must be a directory, but the demo eggnog.db is a bare file, + // so put it in one here + def eggnog_db = file(params.modules_testdata_base_path + 'delete_me/eggnogmapper/eggnog.db') + eggnog_db.copyTo("${workDir}/eggnog_data_dir/eggnog.db") + + input[0] = Channel.of( + [ + [id: 'eggnogmapper_demo_eggnogmapper_db', tool: 'eggnogmapper', db_name: 'demo', db_entity: 'eggnogmapper_db', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/eggnog-mapper/proteome.dmnd') + ], + [ + [id: 'eggnogmapper_demo_eggnogmapper_data_dir', tool: 'eggnogmapper', db_name: 'demo', db_entity: 'eggnogmapper_data_dir', db_params: ''], + file("${workDir}/eggnog_data_dir") + ] + ) + """ + } + } + } + when { + params { + run_eggnogmapper = true + outdir = "$outputDir" + } + workflow { + """ + input[0] = DATAPREP.out.reads + input[1] = DATAPREP.out.reads_concat + input[2] = DBPREP.out.dbs + """ + } + } + then { + assert workflow.success + + def eggnog_paths = getAllFilesFromDir(params.outdir, include: ["eggnogmapper/**"]) + def annotationFile = eggnog_paths.find { it.name.endsWith(".emapper.annotations") } + assert annotationFile != null : "No .emapper.annotations file found in ${params.outdir}/eggnogmapper" + + // the ## lines carry the emapper version, the full command line and a runtime, so drop them + def stableLines = annotationFile.readLines().findAll { !it.startsWith("##") } + def header = stableLines.head() + def annotations = stableLines.tail().collect { it.split("\t", -1) } + + // guard the snapshot: a run that annotates nothing still writes the header, so + // without this an empty result would snapshot cleanly and hide a broken search + assert annotations : "No annotations in ${annotationFile}, only the header" + + // one row per annotated read is neither small nor guaranteed to be ordered the same + // way twice, so snapshot what the annotation is rather than which reads carried it: + // columns 2, 5 and 8 are seed_ortholog, eggNOG_OGs and Description + def annotated = annotations.collect { [it[1], it[4], it[7]] }.unique().sort() + + assert snapshot(header, annotated, eggnog_paths*.name.sort(), topics.versions).match() + } + } + + test("run diamond") { + tag 'diamond' + setup { + run("DATAPREP") { + script "subworkflows/local/dataprep/main.nf" + process { + """ + input[0] = Channel.fromList([ + [ + [id: 'minigut', single_end: false, run_accession: '1', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R2.fastq.gz') + ] + ] + ]) + """ + } + } + + run("DBPREP") { + script "subworkflows/local/dbprep/main.nf" + process { + """ + // B. fragilis is one of the genomes behind the minigut fixture, so blastx + // has something to find; the SARS-CoV-2 proteome the eggNOG-mapper test + // uses returns a single hit on these reads + input[0] = Channel.of( + [ + [id: 'diamond_bfragilis', tool: 'diamond', db_name: 'bfragilis', db_entity: '', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/diamond/bfragilis_proteome.dmnd') + ] + ) + """ + } + } + } + when { + params { + run_diamond = true + outdir = "$outputDir" + } + workflow { + """ + input[0] = DATAPREP.out.reads + input[1] = DATAPREP.out.reads_concat + input[2] = DBPREP.out.dbs + """ + } + } + then { + assert workflow.success + + def diamond_paths = getAllFilesFromDir(params.outdir, include: ["diamond/**"]) + def alignments = diamond_paths.find { it.name.endsWith(".txt") } + assert alignments != null : "No DIAMOND alignment table found in ${params.outdir}/diamond" + + // --outfmt 6 writes no header, so an empty file is a silently failed search + def hits = alignments.readLines().collect { it.split("\t", -1) } + assert hits : "No alignments in ${alignments}" + + // as for eggNOG-mapper, snapshot which subjects were hit rather than which reads + // hit them. minigut hits 1201 of the 4170 proteins in the database, which is + // more than belongs in a snapshot file, so record how many and name the first few + def subjects = hits.collect { it[1] }.unique().sort() + + assert snapshot(subjects.size(), subjects.take(10), diamond_paths*.name.sort(), topics.versions).match() + } + } +} diff --git a/subworkflows/local/profile/tests/main.nf.test.snap b/subworkflows/local/profile/tests/main.nf.test.snap new file mode 100644 index 0000000..bf7ec56 --- /dev/null +++ b/subworkflows/local/profile/tests/main.nf.test.snap @@ -0,0 +1,154 @@ +{ + "run RGI": { + "content": [ + [ + "ARO Term\tARO Accession\tReference Model Type\tReference DB\tAlleles with Mapped Reads\tReference Allele(s) Identity to CARD Reference Protein (%)\tResistomes & Variants: Observed in Genome(s)\tResistomes & Variants: Observed in Plasmid(s)\tResistomes & Variants: Observed Pathogen(s)\tCompletely Mapped Reads\tMapped Reads with Flanking Sequence\tAll Mapped Reads\tAverage Percent Coverage\tAverage Length Coverage (bp)\tAverage MAPQ (Completely Mapped Reads)\tNumber of Mapped Baits\tNumber of Mapped Baits with Reads\tAverage Number of reads per Bait\tNumber of reads per Bait Coefficient of Variation (%)\tNumber of reads mapping to baits and mapping to complete gene\tNumber of reads mapping to baits and mapping to complete gene (%)\tMate Pair Linkage (# reads)\tReference Length\tAMR Gene Family\tDrug Class\tResistance Mechanism", + "Escherichia coli acrA\t3004043\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t51.00\t0.00\t51.00\t100.00\t1194.00\t188.71\t0\t0\t0\t0\tN/A\tN/A\t\t1194\tresistance-nodulation-cell division (RND) antibiotic efflux pump\tfluoroquinolone antibiotic; cephalosporin; glycylcycline; penicillin beta-lactam; tetracycline antibiotic; rifamycin antibiotic; phenicol antibiotic; disinfecting agents and antiseptics\tantibiotic efflux", + "Escherichia coli emrE\t3004039\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t23.00\t0.00\t23.00\t100.00\t333.00\t175.96\t0\t0\t0\t0\tN/A\tN/A\t\t333\tsmall multidrug resistance (SMR) antibiotic efflux pump\tmacrolide antibiotic\tantibiotic efflux", + "LptD\t3005059\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tKlebsiella pneumoniae\t38.00\t0.00\t38.00\t44.57\t1047.00\t131.34\t0\t0\t0\t0\tN/A\tN/A\t\t2349\tATP-binding cassette (ABC) antibiotic efflux pump\tcarbapenem; peptide antibiotic; aminocoumarin antibiotic; rifamycin antibiotic\tantibiotic efflux", + "acrB\t3000216\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t133.00\t0.00\t133.00\t100.00\t3150.00\t191.36\t0\t0\t0\t0\tN/A\tN/A\t\t3150\tresistance-nodulation-cell division (RND) antibiotic efflux pump\tfluoroquinolone antibiotic; cephalosporin; glycylcycline; penicillin beta-lactam; tetracycline antibiotic; rifamycin antibiotic; phenicol antibiotic; disinfecting agents and antiseptics\tantibiotic efflux", + "kdpE\t3003841\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t45.00\t0.00\t45.00\t100.00\t678.00\t175.80\t0\t0\t0\t0\tN/A\tN/A\t\t678\tkdpDE\taminoglycoside antibiotic\tantibiotic efflux", + "leuO\t3003843\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tEscherichia coli\t55.00\t0.00\t55.00\t100.00\t945.00\t173.55\t0\t0\t0\t0\tN/A\tN/A\t\t945\tmajor facilitator superfamily (MFS) antibiotic efflux pump\tnucleoside antibiotic; disinfecting agents and antiseptics\tantibiotic efflux", + "rmtH\t3003198\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tKlebsiella pneumoniae\t4.00\t0.00\t4.00\t6.59\t50.00\t79.00\t0\t0\t0\t0\tN/A\tN/A\t\t759\t16S rRNA methyltransferase (G1405)\taminoglycoside antibiotic\tantibiotic target alteration", + "tet(Q)\t3000191\tprotein homolog model\tCARD\t1\t100.0\tno data\tno data\tBacteroides fragilis\t138.00\t0.00\t138.00\t100.00\t1974.00\t179.62\t0\t0\t0\t0\tN/A\tN/A\t\t1974\ttetracycline-resistant ribosomal protection protein\ttetracycline antibiotic\tantibiotic target protection", + [ + "DATAPREP:CAT_FASTQ", + "cat", + "9.5" + ], + [ + "DBPREP:UNTAR", + "untar", + "1.34" + ], + [ + "PROFILE:RGI_BWT", + "kma", + "1.6.11" + ], + [ + "PROFILE:RGI_BWT", + "rgi", + "6.0.8" + ], + [ + "PROFILE:RGI_BWT", + "rgi-database", + "4.0.1" + ] + ] + ], + "timestamp": "2026-09-02T16:52:53.96173", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "run diamond": { + "content": [ + 1201, + [ + "WP_002558051.1", + "WP_002560983.1", + "WP_004291423.1", + "WP_004291424.1", + "WP_004291426.1", + "WP_004291454.1", + "WP_004291455.1", + "WP_004291456.1", + "WP_004291466.1", + "WP_004291467.1" + ], + [ + "minigut_bfragilis.diamond.log", + "minigut_bfragilis.diamond.txt" + ], + [ + [ + "DATAPREP:CAT_FASTQ", + "cat", + "9.5" + ], + [ + "PROFILE:DIAMOND_BLASTX", + "diamond", + "2.2.1" + ] + ] + ], + "timestamp": "2026-08-04T15:23:43.891346", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "run fmh": { + "content": [ + [ + "minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129", + "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,1081039ab9e9b378d2dfd3206e96e917" + ] + ], + "timestamp": "2026-07-29T16:20:47.621463", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "run multisampleinputs - grouped databases (humann_v3)": { + "content": [ + [ + "minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129", + "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,1081039ab9e9b378d2dfd3206e96e917" + ] + ], + "timestamp": "2026-07-29T16:20:29.367839", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "run eggnogmapper": { + "content": [ + "#query\tseed_ortholog\tevalue\tscore\teggNOG_OGs\tmax_annot_lvl\tCOG_category\tDescription\tPreferred_name\tGOs\tEC\tKEGG_ko\tKEGG_Pathway\tKEGG_Module\tKEGG_Reaction\tKEGG_rclass\tBRITE\tKEGG_TC\tCAZy\tBiGG_Reaction\tPFAMs", + [ + [ + "ENSSASP00005000002.1", + "COG0498@1|root,COG0498@2|Bacteria,1MUWQ@1224|Proteobacteria,2VHR6@28216|Betaproteobacteria,2KUMA@206389|Rhodocyclales", + "threonine synthase" + ] + ], + [ + "sarscov2.emapper.annotations", + "sarscov2.emapper.seed_orthologs" + ], + [ + [ + "DATAPREP:CAT_FASTQ", + "cat", + "9.5" + ], + [ + "PROFILE:EGGNOGMAPPER", + "eggnog-mapper", + "2.1.13" + ], + [ + "PROFILE:GUNZIP", + "gunzip", + "1.13" + ], + [ + "PROFILE:SEQKIT_FQ2FA", + "seqkit", + "2.13.0" + ] + ] + ], + "timestamp": "2026-08-04T15:14:00.583844", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + } +} \ No newline at end of file diff --git a/subworkflows/local/profile/tests/prepareInput.nf.test b/subworkflows/local/profile/tests/prepareInput.nf.test new file mode 100644 index 0000000..3491492 --- /dev/null +++ b/subworkflows/local/profile/tests/prepareInput.nf.test @@ -0,0 +1,241 @@ +nextflow_workflow { + + name "Test prepareInputs via wrapper workflow" + script "../main.nf" + workflow "TEST_PREPAREINPUTS_WRAPPER" + + tag "subworkflows" + tag "subworkflows/profile" + + test("prep inputs - single FQ tool -- fail when given paired data") { + when { + workflow { + """ + input[0] = Channel.fromList([ + [ + [id: '2612', sample: '2612', run_accession: 'ERR5766176', instrument_platform: 'ILLUMINA', single_end: false], + ['ERX5474932_ERR5766176_r1.fastq.gz', 'ERX5474932_ERR5766176_r2.fastq.gz'] + ], + [ + [id: 'sample2', sample: 'sample2', run_accession: 'abc', instrument_platform: 'ILLUMINA', single_end: false], + ['sample2_r1.fastq.gz', 'sample2_r2.fastq.gz'] + ] + ]) + + input[1] = Channel.fromList([ + [ + [tool: 'fmhfunprofiler', db_name: 'fmhfunprofiler1000', params: '11 1000'], + [[db_entity: 'main', db_path: "./KOs_sketched_scaled_1000_demo.sig.zip"]] + ] + ]) + + input[2] = 'fmhfunprofiler' + input[3] = true + """ + } + } + then { + assert workflow.failed + assert snapshot(workflow.out).match() + } + } + + test("prep inputs - single FQ tool ") { + when { + workflow { + """ + input[0] = Channel.fromList([ + [ + [id: '2612', sample: '2612', run_accession: 'ERR5766176', instrument_platform: 'ILLUMINA', single_end: false], + ['ERX5474932_ERR5766176_merged.fastq.gz'] + ], + [ + [id: 'sample2', sample: 'sample2', run_accession: 'abc', instrument_platform: 'ILLUMINA', single_end: false], + ['sample2_merged.fastq.gz'] + ] + ]) + + input[1] = Channel.fromList([ + [ + [tool: 'fmhfunprofiler', db_name: 'fmhfunprofiler1000', params: '11 1000'], + [[db_entity: 'main', db_path: "./KOs_sketched_scaled_1000_demo.sig.zip"]] + ] + ]) + + input[2] = 'fmhfunprofiler' + input[3] = true + """ + } + } + then { + assert workflow.success + assert snapshot(workflow.out).match() + } + } + + test("prep inputs - PE aware tool (rgi)") { + when { + workflow { + """ + input[0] = Channel.fromList([ + [ + [id: '2612', sample: '2612', run_accession: 'ERR5766176', instrument_platform: 'ILLUMINA', single_end: false], + ['ERX5474932_ERR5766176_r1.fastq.gz', 'ERX5474932_ERR5766176_r2.fastq.gz'] + ], + [ + [id: 'sample2', sample: 'sample2', run_accession: 'abc', instrument_platform: 'ILLUMINA', single_end: false], + ['sample2_r1.fastq.gz', 'sample2_r2.fastq.gz'] + ] + ]) + + input[1] = Channel.fromList([ + [ + [tool: 'rgi', db_name: '4.0.1', params: ''], + [[db_entity: 'main', db_path: 'broadstreet-v4.0.1.tar.bz2']] + ] + ]) + + input[2] = 'rgi' // tool_name + input[3] = false // singleFqTool + """ + } + } + then { + assert workflow.success + assert snapshot(workflow.out).match() + } + } + + test("prep inputs - grouped databases (humann_v3)") { + when { + workflow { + """ + input[0] = Channel.of([ + [id: '2612', sample: '2612', run_accession: 'ERR5766176', instrument_platform: 'ILLUMINA', single_end: false], + ['ERX5474932_ERR5766176_merged.fastq.gz'] + ]) + + input[1] = Channel.fromList([ + [ + [ + id: 'humann_v3_demo_v3_humann_nucleotide', + tool: 'humann_v3', + db_name: 'demo_v3', + db_entity: 'humann_nucleotide', + db_params: '' + ], + [ + [db_entity: 'humann_nucleotide', db_path: 'chocophlan_nfDEMO.tar.gz'], + [db_entity: 'humann_protein', db_path: 'uniref_nfDEMO.tar.gz'], + [db_entity: 'humann_utility', db_path: 'utility_nfDEMO.tar.gz'] + ] + ] + ]) + + input[2] = 'humann_v3' // tool_name + input[3] = true // singleFqTool + """ + } + } + then { + assert workflow.success + assert snapshot(workflow.out).match() + } + } + + test("prep multisampleinputs - grouped databases (humann_v3)") { + setup { + run("DATAPREP") { + script "subworkflows/local/dataprep/main.nf" + process { + """ + input[0] = Channel.fromList([ + [ + [id: '2612', single_end: false, run_accession: 'ERR5766176', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'taxprofiler/data/fastq/ERX5474932_ERR5766176_1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'taxprofiler/data/fastq/ERX5474932_ERR5766176_2.fastq.gz') + ] + ], + [ + [id: '2612', single_end: false, run_accession: 'ERR5766176_B', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'taxprofiler/data/fastq/ERX5474932_ERR5766176_B_1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'taxprofiler/data/fastq/ERX5474932_ERR5766176_B_2.fastq.gz') + ] + ], + [ + [id: 'minigut', single_end: false, run_accession: '1', instrument_platform: 'ILLUMINA'], + [ + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R1.fastq.gz'), + file(params.pipelines_testdata_base_path + 'mag/test_data/test_minigut_R2.fastq.gz') + ] + ] + ]) + """ + } + } + + run("DBPREP") { + script "subworkflows/local/dbprep/main.nf" + process { + """ + input[0] = Channel.of( + [ + [id: 'humann_v3_demo_v3_humann_nucleotide', tool: 'humann_v3', db_name: 'demo_v3', db_entity: 'humann_nucleotide', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v3/chocophlan_nfDEMO.tar.gz') + ], + [ + [id: 'humann_v3_demo_v3_humann_protein', tool: 'humann_v3', db_name: 'demo_v3', db_entity: 'humann_protein', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v3/uniref_nfDEMO.tar.gz') + ], + [ + [id: 'humann_v3_demo_v3_humann_metaphlan', tool: 'humann_v3', db_name: 'demo_v3', db_entity: 'humann_metaphlan', db_params: ''], + file('https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/delete_me/metaphlan4_database.tar.gz') + ], + [ + [id: 'humann_v3_demo_v3_humann_utility', tool: 'humann_v3', db_name: 'demo_v3', db_entity: 'humann_utility', db_params: ''], + file(params.pipelines_testdata_base_path + 'funcprofiler/data/database/humann/v3/utility_nfDEMO.tar.gz') + ] + ) + """ + } + } + } + when { + workflow { + """ + input[0] = DATAPREP.out.reads_concat + input[1] = DBPREP.out.dbs + input[2] = 'humann_v3' // tool_name + input[3] = true // singleFqTool + """ + } + } + then { + assert workflow.success + assert snapshot( + workflow.out.reads + .sort { it[0].toString() }, + workflow.out.db + .sort { it[0].toString() } + .collect { item -> + item.collect { element -> + if (element instanceof Map) { + // Sort map by keys AND sort any list values + return element.sort().collectEntries { key, value -> + if (value instanceof List) { + [(key): value.sort()] + } + else { + [(key): value] + } + } + } + return element + } + } + ).match() + } + } +} diff --git a/subworkflows/local/profile/tests/prepareInput.nf.test.snap b/subworkflows/local/profile/tests/prepareInput.nf.test.snap new file mode 100644 index 0000000..13c4852 --- /dev/null +++ b/subworkflows/local/profile/tests/prepareInput.nf.test.snap @@ -0,0 +1,545 @@ +{ + "prep inputs - single FQ tool ": { + "content": [ + { + "0": [ + [ + { + "id": "2612", + "sample": "2612", + "run_accession": "ERR5766176", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "" + }, + [ + "ERX5474932_ERR5766176_merged.fastq.gz" + ] + ], + [ + { + "id": "sample2", + "sample": "sample2", + "run_accession": "abc", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "" + }, + [ + "sample2_merged.fastq.gz" + ] + ] + ], + "1": [ + [ + { + "id": "fmhfunprofiler-fmhfunprofiler1000-", + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "", + "db_entities": [ + "main" + ], + "num_files": 1 + }, + { + "main": "./KOs_sketched_scaled_1000_demo.sig.zip" + } + ], + [ + { + "id": "fmhfunprofiler-fmhfunprofiler1000-", + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "", + "db_entities": [ + "main" + ], + "num_files": 1 + }, + { + "main": "./KOs_sketched_scaled_1000_demo.sig.zip" + } + ] + ], + "db": [ + [ + { + "id": "fmhfunprofiler-fmhfunprofiler1000-", + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "", + "db_entities": [ + "main" + ], + "num_files": 1 + }, + { + "main": "./KOs_sketched_scaled_1000_demo.sig.zip" + } + ], + [ + { + "id": "fmhfunprofiler-fmhfunprofiler1000-", + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "", + "db_entities": [ + "main" + ], + "num_files": 1 + }, + { + "main": "./KOs_sketched_scaled_1000_demo.sig.zip" + } + ] + ], + "reads": [ + [ + { + "id": "2612", + "sample": "2612", + "run_accession": "ERR5766176", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "" + }, + [ + "ERX5474932_ERR5766176_merged.fastq.gz" + ] + ], + [ + { + "id": "sample2", + "sample": "sample2", + "run_accession": "abc", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "fmhfunprofiler", + "db_name": "fmhfunprofiler1000", + "db_params": "" + }, + [ + "sample2_merged.fastq.gz" + ] + ] + ] + } + ], + "timestamp": "2026-08-04T12:26:37.701915", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "prep inputs - grouped databases (humann_v3)": { + "content": [ + { + "0": [ + [ + { + "id": "2612", + "sample": "2612", + "run_accession": "ERR5766176", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "humann_v3", + "db_name": "demo_v3", + "db_params": "" + }, + [ + "ERX5474932_ERR5766176_merged.fastq.gz" + ] + ] + ], + "1": [ + [ + { + "id": "humann-v3-demo-v3-", + "tool": "humann_v3", + "db_name": "demo_v3", + "db_params": "", + "db_entities": [ + "humann_nucleotide", + "humann_protein", + "humann_utility" + ], + "num_files": 3 + }, + { + "humann_nucleotide": "chocophlan_nfDEMO.tar.gz", + "humann_protein": "uniref_nfDEMO.tar.gz", + "humann_utility": "utility_nfDEMO.tar.gz" + } + ] + ], + "db": [ + [ + { + "id": "humann-v3-demo-v3-", + "tool": "humann_v3", + "db_name": "demo_v3", + "db_params": "", + "db_entities": [ + "humann_nucleotide", + "humann_protein", + "humann_utility" + ], + "num_files": 3 + }, + { + "humann_nucleotide": "chocophlan_nfDEMO.tar.gz", + "humann_protein": "uniref_nfDEMO.tar.gz", + "humann_utility": "utility_nfDEMO.tar.gz" + } + ] + ], + "reads": [ + [ + { + "id": "2612", + "sample": "2612", + "run_accession": "ERR5766176", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "humann_v3", + "db_name": "demo_v3", + "db_params": "" + }, + [ + "ERX5474932_ERR5766176_merged.fastq.gz" + ] + ] + ] + } + ], + "timestamp": "2026-08-04T12:26:48.134987", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "prep inputs - single FQ tool -- fail when given paired data": { + "content": [ + { + "0": [ + + ], + "1": [ + + ], + "db": [ + + ], + "reads": [ + + ] + } + ], + "timestamp": "2026-04-17T01:27:47.151296", + "meta": { + "nf-test": "0.9.5", + "nextflow": "25.10.4" + } + }, + "prep inputs - PE aware tool (rgi)": { + "content": [ + { + "0": [ + [ + { + "id": "2612", + "sample": "2612", + "run_accession": "ERR5766176", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "rgi", + "db_name": "4.0.1", + "db_params": "" + }, + [ + "ERX5474932_ERR5766176_r1.fastq.gz", + "ERX5474932_ERR5766176_r2.fastq.gz" + ] + ], + [ + { + "id": "sample2", + "sample": "sample2", + "run_accession": "abc", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "rgi", + "db_name": "4.0.1", + "db_params": "" + }, + [ + "sample2_r1.fastq.gz", + "sample2_r2.fastq.gz" + ] + ] + ], + "1": [ + [ + { + "id": "rgi-4.0.1-", + "tool": "rgi", + "db_name": "4.0.1", + "db_params": "", + "db_entities": [ + "main" + ], + "num_files": 1 + }, + { + "main": "broadstreet-v4.0.1.tar.bz2" + } + ], + [ + { + "id": "rgi-4.0.1-", + "tool": "rgi", + "db_name": "4.0.1", + "db_params": "", + "db_entities": [ + "main" + ], + "num_files": 1 + }, + { + "main": "broadstreet-v4.0.1.tar.bz2" + } + ] + ], + "db": [ + [ + { + "id": "rgi-4.0.1-", + "tool": "rgi", + "db_name": "4.0.1", + "db_params": "", + "db_entities": [ + "main" + ], + "num_files": 1 + }, + { + "main": "broadstreet-v4.0.1.tar.bz2" + } + ], + [ + { + "id": "rgi-4.0.1-", + "tool": "rgi", + "db_name": "4.0.1", + "db_params": "", + "db_entities": [ + "main" + ], + "num_files": 1 + }, + { + "main": "broadstreet-v4.0.1.tar.bz2" + } + ] + ], + "reads": [ + [ + { + "id": "2612", + "sample": "2612", + "run_accession": "ERR5766176", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "rgi", + "db_name": "4.0.1", + "db_params": "" + }, + [ + "ERX5474932_ERR5766176_r1.fastq.gz", + "ERX5474932_ERR5766176_r2.fastq.gz" + ] + ], + [ + { + "id": "sample2", + "sample": "sample2", + "run_accession": "abc", + "instrument_platform": "ILLUMINA", + "single_end": false, + "tool": "rgi", + "db_name": "4.0.1", + "db_params": "" + }, + [ + "sample2_r1.fastq.gz", + "sample2_r2.fastq.gz" + ] + ] + ] + } + ], + "timestamp": "2026-08-04T12:26:43.049758", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "prep multisampleinputs - grouped databases (humann_v3)": { + "content": [ + [ + [ + { + "id": "2612", + "single_end": true, + "instrument_platform": "ILLUMINA", + "tool": "humann_v3", + "db_name": "demo_v3", + "db_params": "-" + }, + [ + "2612.merged.fastq.gz:md5,270bf4c4d9707c6afc970fe5622cc673" + ] + ], + [ + { + "id": "minigut", + "single_end": true, + "instrument_platform": "ILLUMINA", + "tool": "humann_v3", + "db_name": "demo_v3", + "db_params": "-" + }, + [ + "minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129" + ] + ] + ], + [ + [ + { + "db_entities": [ + "humann_metaphlan", + "humann_nucleotide", + "humann_protein", + "humann_utility" + ], + "db_name": "demo_v3", + "db_params": "-", + "id": "humann-v3-demo-v3-", + "num_files": 4, + "tool": "humann_v3" + }, + { + "humann_metaphlan": [ + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.1.bt2l:md5,f560f1878d407cad746b40e19c137b2f", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.2.bt2l:md5,ada1fa4dbfa0bbd00fd9541458d0caab", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.3.bt2l:md5,1b5ec794c2f0c456ea60deb5898f4840", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.4.bt2l:md5,fe7bbac658aece93db332255910e3f4f", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.fna.bz2:md5,43dd63a3263c01105af26b701a9b5562", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.pkl:md5,005453b7c66c85f3e01218653d09e266", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.rev.1.bt2l:md5,7b23ad55748937a1b21f8ed735fe0d73", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.rev.2.bt2l:md5,acc38a28f2e590d5ce12a9defe4c8c87" + ], + "humann_nucleotide": [ + "g__Bacteroides.s__Bacteroides_dorei.centroids.v201901_v31.ffn.gz:md5,c23ab47a3f0a34abd20f0b1826482c6d", + "g__Bacteroides.s__Bacteroides_vulgatus.centroids.v201901_v31.ffn.gz:md5,61a2c5aa5ff04e400147974852e5bcc2" + ], + "humann_protein": [ + "uniref90_demo_prots_v201901b.dmnd:md5,1d2f8df48a349d72436425aafa29a6b1", + "uniref90_demo_prots_v201901b.fna:md5,10699776b9428fdf673030dba1f818a7" + ], + "humann_utility": [ + "README.txt:md5,9d3db20d44df2404c41064a815d14e35", + "map_eggnog_name.txt.gz:md5,b23ae8c34c86b1f160d66b1e218d1c8a", + "map_eggnog_uniref50.txt.gz:md5,50bd690aecd716cdacee47ecaf405d56", + "map_eggnog_uniref90.txt.gz:md5,4dac1a34d5557565afd964f44e0dab2e", + "map_go_name.txt.gz:md5,9e437e5000ce203b74cd16b42acca0f2", + "map_go_uniref50.txt.gz:md5,efa82fad21970c4b6f8695aeed44f56f", + "map_go_uniref90.txt.gz:md5,cc12d3d1d8a9493b5eb1637004d4de02", + "map_kegg-mdl_name.txt.gz:md5,ce28c1ae107325b12a328644f70f724d", + "map_ko_name.txt.gz:md5,093ceb058735a98e2e68d178f791ed36", + "map_ko_uniref50.txt.gz:md5,628aa13e990777760f822d347cb0b1ad", + "map_ko_uniref90.txt.gz:md5,420f8ec15e77c18da8069465f679cde7", + "map_level4ec_name.txt.gz:md5,2e201c4d860789795dd7c8acb36ab595", + "map_level4ec_uniref50.txt.gz:md5,c6988287fd4bdda511110e18915eeea9", + "map_level4ec_uniref90.txt.gz:md5,b14904213f3e3c010a8b3fdbdc9cd7ef", + "map_pfam_name.txt.gz:md5,cdd6c73f7fb4bc0284d9e6769124854b", + "map_pfam_uniref50.txt.gz:md5,b9f128f4b337c83a652c9926e6c292e4", + "map_pfam_uniref90.txt.gz:md5,5d03d39e5305a541b6017fd308e2154b", + "map_uniref50_name.txt.bz2:md5,62ea0afa60ad7ad1ba7aa2af43ed7d23", + "map_uniref90_name.txt.bz2:md5,988f3ce65a432bbe2c8fd3354cad99fa" + ] + } + ], + [ + { + "db_entities": [ + "humann_metaphlan", + "humann_nucleotide", + "humann_protein", + "humann_utility" + ], + "db_name": "demo_v3", + "db_params": "-", + "id": "humann-v3-demo-v3-", + "num_files": 4, + "tool": "humann_v3" + }, + { + "humann_metaphlan": [ + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.1.bt2l:md5,f560f1878d407cad746b40e19c137b2f", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.2.bt2l:md5,ada1fa4dbfa0bbd00fd9541458d0caab", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.3.bt2l:md5,1b5ec794c2f0c456ea60deb5898f4840", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.4.bt2l:md5,fe7bbac658aece93db332255910e3f4f", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.fna.bz2:md5,43dd63a3263c01105af26b701a9b5562", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.pkl:md5,005453b7c66c85f3e01218653d09e266", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.rev.1.bt2l:md5,7b23ad55748937a1b21f8ed735fe0d73", + "mpa_vJan21_TOY_CHOCOPhlAnSGB_202103.rev.2.bt2l:md5,acc38a28f2e590d5ce12a9defe4c8c87" + ], + "humann_nucleotide": [ + "g__Bacteroides.s__Bacteroides_dorei.centroids.v201901_v31.ffn.gz:md5,c23ab47a3f0a34abd20f0b1826482c6d", + "g__Bacteroides.s__Bacteroides_vulgatus.centroids.v201901_v31.ffn.gz:md5,61a2c5aa5ff04e400147974852e5bcc2" + ], + "humann_protein": [ + "uniref90_demo_prots_v201901b.dmnd:md5,1d2f8df48a349d72436425aafa29a6b1", + "uniref90_demo_prots_v201901b.fna:md5,10699776b9428fdf673030dba1f818a7" + ], + "humann_utility": [ + "README.txt:md5,9d3db20d44df2404c41064a815d14e35", + "map_eggnog_name.txt.gz:md5,b23ae8c34c86b1f160d66b1e218d1c8a", + "map_eggnog_uniref50.txt.gz:md5,50bd690aecd716cdacee47ecaf405d56", + "map_eggnog_uniref90.txt.gz:md5,4dac1a34d5557565afd964f44e0dab2e", + "map_go_name.txt.gz:md5,9e437e5000ce203b74cd16b42acca0f2", + "map_go_uniref50.txt.gz:md5,efa82fad21970c4b6f8695aeed44f56f", + "map_go_uniref90.txt.gz:md5,cc12d3d1d8a9493b5eb1637004d4de02", + "map_kegg-mdl_name.txt.gz:md5,ce28c1ae107325b12a328644f70f724d", + "map_ko_name.txt.gz:md5,093ceb058735a98e2e68d178f791ed36", + "map_ko_uniref50.txt.gz:md5,628aa13e990777760f822d347cb0b1ad", + "map_ko_uniref90.txt.gz:md5,420f8ec15e77c18da8069465f679cde7", + "map_level4ec_name.txt.gz:md5,2e201c4d860789795dd7c8acb36ab595", + "map_level4ec_uniref50.txt.gz:md5,c6988287fd4bdda511110e18915eeea9", + "map_level4ec_uniref90.txt.gz:md5,b14904213f3e3c010a8b3fdbdc9cd7ef", + "map_pfam_name.txt.gz:md5,cdd6c73f7fb4bc0284d9e6769124854b", + "map_pfam_uniref50.txt.gz:md5,b9f128f4b337c83a652c9926e6c292e4", + "map_pfam_uniref90.txt.gz:md5,5d03d39e5305a541b6017fd308e2154b", + "map_uniref50_name.txt.bz2:md5,62ea0afa60ad7ad1ba7aa2af43ed7d23", + "map_uniref90_name.txt.bz2:md5,988f3ce65a432bbe2c8fd3354cad99fa" + ] + } + ] + ] + ], + "timestamp": "2026-08-04T14:42:06.880276", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + } +} \ No newline at end of file diff --git a/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf b/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf index c042558..3f4a9b3 100644 --- a/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_funcprofiler_pipeline/main.nf @@ -8,14 +8,14 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { samplesheetToList } from 'plugin/nf-schema' -include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' -include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { imNotification } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' +include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' +include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' +include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -24,77 +24,103 @@ include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipelin */ workflow PIPELINE_INITIALISATION { - take: - version // boolean: Display version and exit - validate_params // boolean: Boolean whether to validate parameters against the schema at runtime - monochrome_logs // boolean: Do not use coloured log outputs + version // boolean: Display version and exit + validate_params // boolean: Boolean whether to validate parameters against the schema at runtime + monochrome_logs // boolean: Do not use coloured log outputs nextflow_cli_args // array: List of positional nextflow CLI args - outdir // string: The output directory where the results will be saved - input // string: Path to input samplesheet + outdir // string: The output directory where the results will be saved + input // string: Path to input samplesheet + databases // string: Path to databases + help // boolean: Display help message and exit + help_full // boolean: Show the full help message + show_hidden // boolean: Show hidden parameters in the help message main: - ch_versions = Channel.empty() + ch_versions = channel.empty() // // Print version and exit if required and dump pipeline parameters to JSON file // - UTILS_NEXTFLOW_PIPELINE ( + UTILS_NEXTFLOW_PIPELINE( version, true, outdir, - workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1 + workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1, ) // // Validate parameters and generate parameter summary to stdout // - UTILS_NFSCHEMA_PLUGIN ( + before_text = """ +-\033[2m----------------------------------------------------\033[0m- + \033[0;32m,--.\033[0;30m/\033[0;32m,-.\033[0m +\033[0;34m ___ __ __ __ ___ \033[0;32m/,-._.--~\'\033[0m +\033[0;34m |\\ | |__ __ / ` / \\ |__) |__ \033[0;33m} {\033[0m +\033[0;34m | \\| | \\__, \\__/ | \\ |___ \033[0;32m\\`-._,-`-,\033[0m + \033[0;32m`._,._,\'\033[0m +\033[0;35m nf-core/funcprofiler ${workflow.manifest.version}\033[0m +-\033[2m----------------------------------------------------\033[0m- +""" + after_text = """${workflow.manifest.doi ? "\n* The pipeline\n" : ""}${workflow.manifest.doi.tokenize(",").collect { doi -> " https://doi.org/${doi.trim().replace('https://doi.org/', '')}" }.join("\n")}${workflow.manifest.doi ? "\n" : ""} +* The nf-core framework + https://doi.org/10.1038/s41587-020-0439-x + +* Software dependencies + https://github.com/nf-core/funcprofiler/blob/main/CITATIONS.md +""" + command = "nextflow run ${workflow.manifest.name} -profile --input samplesheet.csv --outdir " + // + // Validate parameters and generate parameter summary to stdout + // + UTILS_NFSCHEMA_PLUGIN( workflow, validate_params, - null + null, + help, + help_full, + show_hidden, + before_text, + after_text, + command, + false ) // // Check config provided to the pipeline // - UTILS_NFCORE_PIPELINE ( + UTILS_NFCORE_PIPELINE( nextflow_cli_args ) // - // Custom validation for pipeline parameters + // Create channel from input file provided through params.input + // + // Rows are validated and turned into their final [ meta, [ reads ] ] form here, so that + // a malformed samplesheet aborts the run before any task is submitted. // - validateInputParameters() + def samplesheet_list = samplesheetToList(params.input, "assets/schema_input.json") + .collect { meta, run_accession, instrument_platform, fastq_1, fastq_2, fasta -> + validateInputSamplesheet(meta, run_accession, instrument_platform, fastq_1, fastq_2, fasta) + } + validateRunEndedness(samplesheet_list) + ch_samplesheet = channel.fromList(samplesheet_list) // - // Create channel from input file provided through params.input + // Create channel from databases file provided through params.databases // - - Channel - .fromList(samplesheetToList(params.input, "${projectDir}/assets/schema_input.json")) - .map { - meta, fastq_1, fastq_2 -> - if (!fastq_2) { - return [ meta.id, meta + [ single_end:true ], [ fastq_1 ] ] - } else { - return [ meta.id, meta + [ single_end:false ], [ fastq_1, fastq_2 ] ] - } - } - .groupTuple() - .map { samplesheet -> - validateInputSamplesheet(samplesheet) - } - .map { - meta, fastqs -> - return [ meta, fastqs.flatten() ] - } - .set { ch_samplesheet } + // The list is materialised before it becomes a channel so that the database sheet can be + // checked against the enabled profilers up front rather than partway through the run. + // + def databases_list = samplesheetToList(params.databases, "assets/schema_database.json") + validateProfilerDatabases(databases_list) + ch_databases = channel.fromList(databases_list) emit: - samplesheet = ch_samplesheet - versions = ch_versions + reads = ch_samplesheet + databases = ch_databases + versions = ch_versions } /* @@ -104,15 +130,14 @@ workflow PIPELINE_INITIALISATION { */ workflow PIPELINE_COMPLETION { - take: - email // string: email address - email_on_fail // string: email address sent on pipeline failure + email // string: email address + email_on_fail // string: email address sent on pipeline failure plaintext_email // boolean: Send plain-text email instead of HTML - outdir // path: Path to output directory where results will be published + outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output - hook_url // string: hook URL for notifications - multiqc_report // string: Path to MultiQC report + hook_url // string: hook URL for notifications + multiqc_report // string: Path to MultiQC report main: summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") @@ -135,13 +160,10 @@ workflow PIPELINE_COMPLETION { } completionSummary(monochrome_logs) - if (hook_url) { - imNotification(summary_params, hook_url) - } } workflow.onError { - log.error "Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting" + log.error("Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting") } } @@ -150,77 +172,165 @@ workflow PIPELINE_COMPLETION { FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +// Validate one samplesheet row and build the meta map the rest of the pipeline uses. // -// Check and validate pipeline parameters +// The sample name, run accession, instrument platform and FASTQ paths are already checked by +// `assets/schema_input.json`, which also rejects the long-read platforms the profilers cannot +// handle. Only the FastA column needs checking here, because JSON schema cannot express +// "this column exists for nf-core/taxprofiler compatibility but must be left empty". // -def validateInputParameters() { - genomeExistsError() -} +def validateInputSamplesheet(meta, run_accession, instrument_platform, fastq_1, fastq_2, fasta) { + if (fasta) { + error("Please check input samplesheet: FastA input is not supported, supply FastQ reads instead (sample: ${meta.id}).") + } -// -// Validate channels from input samplesheet -// -def validateInputSamplesheet(input) { - def (metas, fastqs) = input[1..2] + meta.single_end = !fastq_2 + meta.run_accession = run_accession + meta.instrument_platform = instrument_platform - // Check that multiple runs of the same sample are of the same datatype i.e. single-end / paired-end - def endedness_ok = metas.collect{ meta -> meta.single_end }.unique().size == 1 - if (!endedness_ok) { - error("Please check input samplesheet -> Multiple runs of a sample must be of the same datatype i.e. single-end or paired-end: ${metas[0].id}") - } + return [meta, fastq_2 ? [fastq_1, fastq_2] : [fastq_1]] +} - return [ metas[0], fastqs ] +// Runs of the same sample must all be single-end or all paired-end, otherwise DATAPREP cannot +// interpret the read list it merges them into. +// +def validateRunEndedness(samplesheet_list) { + samplesheet_list + .groupBy { meta, _reads -> meta.id } + .each { id, rows -> + if (rows.collect { meta, _reads -> meta.single_end }.unique().size() != 1) { + error("Please check input samplesheet: multiple runs of a sample must all be single-end or all paired-end (sample: ${id}).") + } + } } + // -// Get attribute from genome config file e.g. fasta +// The database components each profiler needs, as `db_entity` names. Tools that take a single +// database file or directory leave `db_entity` empty, which DBPREP stores as the 'main' entity. // -def getGenomeAttribute(attribute) { - if (params.genomes && params.genome && params.genomes.containsKey(params.genome)) { - if (params.genomes[ params.genome ].containsKey(attribute)) { - return params.genomes[ params.genome ][ attribute ] - } - } - return null +def profilerDatabaseEntities() { + return [ + 'humann_v3': ['humann_metaphlan', 'humann_nucleotide', 'humann_protein', 'humann_utility'], + 'humann_v4': ['humann_metaphlan', 'humann_nucleotide', 'humann_protein', 'humann_utility'], + 'eggnogmapper': ['eggnogmapper_db', 'eggnogmapper_data_dir'], + 'fmhfunprofiler': ['main'], + 'mifaser': ['main'], + 'diamond': ['main'], + 'rgi': ['main'], + ] } // -// Exit pipeline if incorrect --genome key provided +// Check that every enabled profiler has a complete database in the database sheet. // -def genomeExistsError() { - if (params.genomes && params.genome && !params.genomes.containsKey(params.genome)) { - def error_string = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + - " Genome '${params.genome}' not found in any config files provided to the pipeline.\n" + - " Currently, the available genome keys are:\n" + - " ${params.genomes.keySet().join(", ")}\n" + - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - error(error_string) +// Without this the pipeline starts, runs whatever else is enabled, and only fails once the +// incomplete database reaches the profiler, so it is done here before any task is submitted. +// +def validateProfilerDatabases(databases) { + def entities_by_db = [:] + databases.each { db_meta, _db_path -> + def key = [db_meta.tool, db_meta.db_name] + entities_by_db[key] = (entities_by_db[key] ?: [] as Set) + [db_meta.db_entity ?: 'main'] + } + + profilerDatabaseEntities().each { tool, required_entities -> + if (!params["run_${tool}"]) { + return + } + + def dbs_for_tool = entities_by_db.findAll { key, _entities -> key[0] == tool } + if (!dbs_for_tool) { + error("--run_${tool} is set but the database sheet '${params.databases}' has no row with tool '${tool}'.") + } + + dbs_for_tool.each { key, entities -> + def missing = required_entities - entities + if (missing) { + error("Database '${key[1]}' for --run_${tool} is missing required db_entity row(s): ${missing.join(', ')}.") + } + } + } + + // fmh-funprofiler reads its k-mer size and sketch scale out of db_params at runtime + if (params.run_fmhfunprofiler) { + databases + .findAll { db_meta, _db_path -> db_meta.tool == 'fmhfunprofiler' } + .each { db_meta, _db_path -> + def db_params = (db_meta.db_params ?: '').trim().split(/\s+/).findAll { arg -> arg } + if (db_params.size() != 2) { + error("fmhfunprofiler database '${db_meta.db_name}' must set db_params to two integers (k-mer size and sketch scale), but got '${db_meta.db_params}'.") + } + } } } + // // Generate methods description for MultiQC // def toolCitationText() { - // TODO nf-core: Optionally add in-text citation tools to this list. - // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", - // Uncomment function in methodsDescriptionText to render in MultiQC report + def text_humann = [ + "Functional profiling was performed with", + params.run_humann_v3 && params.run_humann_v4 + ? "HUMAnN v3 and HUMAnN v4 (Beghini et al. 2021)" + : params.run_humann_v3 + ? "HUMAnN v3 (Beghini et al. 2021)" + : "HUMAnN v4 (Beghini et al. 2021)", + "using MetaPhlAn (Blanco-Míguez et al. 2023) for taxonomic marker-based profiling.", + ].join(' ').trim() + + def text_diamond = ["Protein-level sequence alignment was performed with DIAMOND (Buchfink et al. 2021)."].join(' ').trim() + + def text_fmhfunprofiler = ["Functional profiling was additionally performed with fmhfunprofiler (Hera et al. 2024)."].join(' ').trim() + + def text_mifaser = ["Enzyme function annotation was performed with mi-faser (Zhu et al. 2017)."].join(' ').trim() + + def text_eggnogmapper = ["Functional Annotation, Orthology Assignments, and Domain Prediction was performed with eggNOG-mapper v2 (Cantalapiedra et. al 2021)"].join(' ').trim() + + def text_rgi = ["Resistome prediction was performed using RGI (Alcock et. al 2023)"].join(' ').trim() + def citation_text = [ - "Tools used in the workflow included:", - "FastQC (Andrews 2010),", - "MultiQC (Ewels et al. 2016)", - "." - ].join(' ').trim() + "Tools used in the workflow included:", + params.run_humann_v3 || params.run_humann_v4 ? text_humann : "", + params.run_diamond ? text_diamond : "", + params.run_fmhfunprofiler ? text_fmhfunprofiler : "", + params.run_mifaser ? text_mifaser : "", + params.run_eggnogmapper ? text_eggnogmapper : "", + params.run_rgi ? text_rgi : "", + "Pipeline results statistics were summarised with MultiQC (Ewels et al. 2016).", + ].join(' ').trim().replaceAll("[,|.] +\\.", ".") return citation_text } def toolBibliographyText() { - // TODO nf-core: Optionally add bibliographic entries to this list. - // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", - // Uncomment function in methodsDescriptionText to render in MultiQC report + def text_humann = [ + params.run_humann_v3 || params.run_humann_v4 ? "
  • Beghini, F., McIver, L. J., Blanco-M\u00edguez, A., Dubois, L., Asnicar, F., Maharjan, S., Mailyan, A., Thomas, A. M., Manghi, P., Valles-Colomer, M., Weingart, G., Zhang, Y., Zolfo, M., Huttenhower, C., Franzosa, E. A., & Segata, N. (2021). Integrating taxonomic, functional, and strain-level profiling of diverse microbial communities with bioBakery 3. eLife, 10, e65088. 10.7554/eLife.65088
  • " : "", + params.run_humann_v3 || params.run_humann_v4 ? "
  • Blanco-M\u00edguez, A., Beghini, F., Cumbo, F., McIver, L. J., Thompson, K. N., Zolfo, M., Manghi, P., Dubois, L., Huang, K. D., Thomas, A. M., Nickols, W. A., Piccinno, G., Piperni, E., Pun\u010doch\u00e1\u0159, M., Valles-Colomer, M., Tett, A., Giordano, F., Davies, R., Wolf, J., \u2026 Segata, N. (2023). Extending and improving metagenomic taxonomic profiling with uncharacterized species using MetaPhlAn 4. Nature Biotechnology, 41, 1633\u20131645. 10.1038/s41587-023-01688-w
  • " : "", + ].join(' ').trim() + + def text_diamond = [params.run_diamond ? "
  • Buchfink, B., Reuter, K., & Drost, H.-G. (2021). Sensitive protein alignments at tree-of-life scale using DIAMOND. Nature Methods, 18(4), 366–368. 10.1038/s41592-021-01101-x
  • " : ""].join(' ').trim() + + def text_fmhfunprofiler = [params.run_fmhfunprofiler ? "
  • Hera, M. R., Liu, S., Wei, W., Rodriguez, J. S., Ma, C., & Koslicki, D. (2024). Metagenomic functional profiling: to sketch or not to sketch? Bioinformatics, 40(Suppl 2), ii165–ii173. 10.1093/bioinformatics/btae397
  • " : ""].join(' ').trim() + + def text_mifaser = [ + params.run_mifaser ? "
  • Zhu, C., Miller, M., Marpaka, S., Vaysberg, P., R\u00fchlemann, M. C., Wu, G., Heinsen, F.-A., Tempel, M., Woodhouse, L., Burkhardt, L., Tams, R., Knecht, C., Heinig, M., Franke, A., Huser, T., & Bromberg, Y. (2017). Functional sequencing read annotation for high precision microbiome analysis. Nucleic Acids Research, 46(4), e23. 10.1093/nar/gkx1209
  • " : "", + params.run_mifaser ? "
  • Mahlich, Y., Zhu, C., Chung, H., Velaga, P. K., De Paolis Kaluza, M. C., Radivojac, P., Bromberg, Y. (2023). Learning from the unknown: exploring the range of bacterial functionality. Nucleic Acids Research. 10.1093/nar/gkad757
  • " : "", + params.run_mifaser ? "
  • Zhu, C., Delmont, T. O., Vogel, T. M., & Bromberg, Y. (2015). Functional basis of microorganism classification. PLoS Computational Biology, 11(8), e1004472. 10.1371/journal.pcbi.1004472
  • " : "", + ].join(' ').trim() + + def text_eggnggmapper = [params.run_eggnogmapper ? "
  • Carlos P Cantalapiedra, Ana Hernández-Plaza, Ivica Letunic, Peer Bork, Jaime Huerta-Cepas, eggNOG-mapper v2: Functional Annotation, Orthology Assignments, and Domain Prediction at the Metagenomic Scale, Molecular Biology and Evolution, Volume 38, Issue 12, December 2021, 0.1093/molbev/msab293
  • " : ""].join(' ').trim() + + def text_rgi = [params.run_rgi ? "
  • Alcock et al. 2023. CARD 2023: expanded curation, support for machine learning, and resistome prediction at the Comprehensive Antibiotic Resistance Database. Nucleic Acids Researchpubmed.ncbi.nlm.nih.gov/36263822
  • " : ""].join(' ').trim() + def reference_text = [ - "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", - "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " - ].join(' ').trim() + text_humann, + text_eggnggmapper, + text_rgi, + text_diamond, + text_fmhfunprofiler, + text_mifaser, + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics, 32(19), 3047–3048. 10.1093/bioinformatics/btw354
  • ", + ].join(' ').trim() return reference_text } @@ -228,6 +338,7 @@ def toolBibliographyText() { def methodsDescriptionText(mqc_methods_yaml) { // Convert to a named map so can be used as with familiar NXF ${workflow} variable syntax in the MultiQC YML file def meta = [:] + meta.workflow = workflow.toMap() meta["manifest_map"] = workflow.manifest.toMap() @@ -242,21 +353,21 @@ def methodsDescriptionText(mqc_methods_yaml) { temp_doi_ref += "(doi: ${doi_ref.replace("https://doi.org/", "").replace(" ", "")}), " } meta["doi_text"] = temp_doi_ref.substring(0, temp_doi_ref.length() - 2) - } else meta["doi_text"] = "" + } + else { + meta["doi_text"] = "" + } meta["nodoi_text"] = meta.manifest_map.doi ? "" : "
  • If available, make sure to update the text to include the Zenodo DOI of version of the pipeline used.
  • " - // Tool references - meta["tool_citations"] = "" - meta["tool_bibliography"] = "" - - // TODO nf-core: Only uncomment below if logic in toolCitationText/toolBibliographyText has been filled! - // meta["tool_citations"] = toolCitationText().replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") - // meta["tool_bibliography"] = toolBibliographyText() + // meta["tool_citations"] = "" + // meta["tool_bibliography"] = "" + meta["tool_citations"] = toolCitationText().replaceAll(", \\.", ".").replaceAll("\\. \\.", ".").replaceAll(", \\.", ".") + meta["tool_bibliography"] = toolBibliographyText() def methods_text = mqc_methods_yaml.text - def engine = new groovy.text.SimpleTemplateEngine() + def engine = new groovy.text.SimpleTemplateEngine() def description_html = engine.createTemplate(methods_text).make(meta) return description_html.toString() diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf index d6e593e..37939ac 100644 --- a/subworkflows/nf-core/utils_nextflow_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nextflow_pipeline/main.nf @@ -73,11 +73,23 @@ def getWorkflowVersion() { def dumpParametersToJSON(outdir) { def timestamp = new java.util.Date().format('yyyy-MM-dd_HH-mm-ss') def filename = "params_${timestamp}.json" - def temp_pf = new File(workflow.launchDir.toString(), ".${filename}") - def jsonStr = groovy.json.JsonOutput.toJson(params) + def temp_pf = workflow.launchDir.resolve(".${filename}") + def jsonGenerator = new groovy.json.JsonGenerator.Options() + .excludeNulls() + .addConverter(Path) { Path path -> path.toUriString() } + .addConverter(Duration) { Duration duration -> duration.toMillis() } + .addConverter(MemoryUnit) { MemoryUnit memory -> memory.toBytes() } + .addConverter(nextflow.script.types.VersionNumber) { nextflow.script.types.VersionNumber version -> version.toString() } + .build() + def jsonStr = jsonGenerator.toJson(params) temp_pf.text = groovy.json.JsonOutput.prettyPrint(jsonStr) - - nextflow.extension.FilesEx.copyTo(temp_pf.toPath(), "${outdir}/pipeline_info/params_${timestamp}.json") + if (outdir instanceof Path) { + temp_pf.copyTo(outdir.resolve("pipeline_info/${filename}")) + } else if (outdir instanceof String) { + temp_pf.copyTo("${outdir}/pipeline_info/params_${timestamp}.json") + } else { + log.warn("Could not determine type of outdir, parameters JSON file will not be copied to output directory!") + } temp_pf.delete() } diff --git a/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml deleted file mode 100644 index f847611..0000000 --- a/subworkflows/nf-core/utils_nextflow_pipeline/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -subworkflows/utils_nextflow_pipeline: - - subworkflows/nf-core/utils_nextflow_pipeline/** diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf index bfd2587..afca543 100644 --- a/subworkflows/nf-core/utils_nfcore_pipeline/main.nf +++ b/subworkflows/nf-core/utils_nfcore_pipeline/main.nf @@ -17,7 +17,7 @@ workflow UTILS_NFCORE_PIPELINE { checkProfileProvided(nextflow_cli_args) emit: - valid_config + valid_config = valid_config } /* @@ -98,7 +98,7 @@ def workflowVersionToYAML() { // Get channel of software versions used in pipeline in YAML format // def softwareVersionsToYAML(ch_versions) { - return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(Channel.of(workflowVersionToYAML())) + return ch_versions.unique().map { version -> processVersionsFromYAML(version) }.unique().mix(channel.of(workflowVersionToYAML())) } // @@ -353,67 +353,3 @@ def completionSummary(monochrome_logs=true) { log.info("-${colors.purple}[${workflow.manifest.name}]${colors.red} Pipeline completed with errors${colors.reset}-") } } - -// -// Construct and send a notification to a web server as JSON e.g. Microsoft Teams and Slack -// -def imNotification(summary_params, hook_url) { - def summary = [:] - summary_params - .keySet() - .sort() - .each { group -> - summary << summary_params[group] - } - - def misc_fields = [:] - misc_fields['start'] = workflow.start - misc_fields['complete'] = workflow.complete - misc_fields['scriptfile'] = workflow.scriptFile - misc_fields['scriptid'] = workflow.scriptId - if (workflow.repository) { - misc_fields['repository'] = workflow.repository - } - if (workflow.commitId) { - misc_fields['commitid'] = workflow.commitId - } - if (workflow.revision) { - misc_fields['revision'] = workflow.revision - } - misc_fields['nxf_version'] = workflow.nextflow.version - misc_fields['nxf_build'] = workflow.nextflow.build - misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp - - def msg_fields = [:] - msg_fields['version'] = getWorkflowVersion() - msg_fields['runName'] = workflow.runName - msg_fields['success'] = workflow.success - msg_fields['dateComplete'] = workflow.complete - msg_fields['duration'] = workflow.duration - msg_fields['exitStatus'] = workflow.exitStatus - msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None') - msg_fields['errorReport'] = (workflow.errorReport ?: 'None') - msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "") - msg_fields['projectDir'] = workflow.projectDir - msg_fields['summary'] = summary << misc_fields - - // Render the JSON template - def engine = new groovy.text.GStringTemplateEngine() - // Different JSON depending on the service provider - // Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format - def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json" - def hf = new File("${workflow.projectDir}/assets/${json_path}") - def json_template = engine.createTemplate(hf).make(msg_fields) - def json_message = json_template.toString() - - // POST - def post = new URL(hook_url).openConnection() - post.setRequestMethod("POST") - post.setDoOutput(true) - post.setRequestProperty("Content-Type", "application/json") - post.getOutputStream().write(json_message.getBytes("UTF-8")) - def postRC = post.getResponseCode() - if (!postRC.equals(200)) { - log.warn(post.getErrorStream().getText()) - } -} diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test similarity index 100% rename from subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test rename to subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap b/subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap similarity index 100% rename from subworkflows/nf-core/utils_nfcore_pipeline/tests/main.workflow.nf.test.snap rename to subworkflows/nf-core/utils_nfcore_pipeline/tests/main.nf.test.snap diff --git a/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml b/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml deleted file mode 100644 index ac8523c..0000000 --- a/subworkflows/nf-core/utils_nfcore_pipeline/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -subworkflows/utils_nfcore_pipeline: - - subworkflows/nf-core/utils_nfcore_pipeline/** diff --git a/subworkflows/nf-core/utils_nfschema_plugin/main.nf b/subworkflows/nf-core/utils_nfschema_plugin/main.nf index 4994303..9ff0681 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/main.nf +++ b/subworkflows/nf-core/utils_nfschema_plugin/main.nf @@ -4,6 +4,7 @@ include { paramsSummaryLog } from 'plugin/nf-schema' include { validateParameters } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' workflow UTILS_NFSCHEMA_PLUGIN { @@ -15,32 +16,62 @@ workflow UTILS_NFSCHEMA_PLUGIN { // when this input is empty it will automatically use the configured schema or // "${projectDir}/nextflow_schema.json" as default. This input should not be empty // for meta pipelines + help // boolean: show help message + help_full // boolean: show full help message + show_hidden // boolean: show hidden parameters in help message + before_text // string: text to show before the help message and parameters summary + after_text // string: text to show after the help message and parameters summary + command // string: an example command of the pipeline + cli_typecast // boolean: whether to perform typecasting of CLI parameters. Set this to `null` to use the default behaviour main: + if(help || help_full) { + help_options = [ + beforeText: before_text, + afterText: after_text, + command: command, + showHidden: show_hidden, + fullHelp: help_full, + ] + if(parameters_schema) { + help_options << [parameters_schema: parameters_schema] + } + log.info paramsHelp( + help_options, + (help instanceof String && help != "true") ? help : "", + ) + exit 0 + } + // // Print parameter summary to stdout. This will display the parameters // that differ from the default given in the JSON schema // + + summary_options = [:] if(parameters_schema) { - log.info paramsSummaryLog(input_workflow, parameters_schema:parameters_schema) - } else { - log.info paramsSummaryLog(input_workflow) + summary_options << [parameters_schema: parameters_schema] } + log.info before_text + log.info paramsSummaryLog(summary_options, input_workflow) + log.info after_text // // Validate the parameters using nextflow_schema.json or the schema // given via the validation.parametersSchema configuration option // if(validate_params) { + validateOptions = [:] if(parameters_schema) { - validateParameters(parameters_schema:parameters_schema) - } else { - validateParameters() + validateOptions << [parameters_schema: parameters_schema] + } + if(cli_typecast != null) { + validateOptions << [cast_cli_params: cli_typecast] } + validateParameters(validateOptions) } emit: dummy_emit = true } - diff --git a/subworkflows/nf-core/utils_nfschema_plugin/meta.yml b/subworkflows/nf-core/utils_nfschema_plugin/meta.yml index f7d9f02..1d8c75a 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/meta.yml +++ b/subworkflows/nf-core/utils_nfschema_plugin/meta.yml @@ -25,6 +25,30 @@ input: option. When this input is empty it will automatically use the configured schema or "${projectDir}/nextflow_schema.json" as default. The schema should not be given in this way for meta pipelines. + - help: + type: boolean, string + description: | + Show the help message and exit. When a parameter name is given, show the help message for that parameter instead of the general help message. + - help_full: + type: boolean + description: Show the full help message and exit. + - show_hidden: + type: boolean + description: Show hidden parameters in the help message. + - before_text: + type: string + description: Text to show before the parameters summary and help message. + - after_text: + type: string + description: Text to show after the parameters summary and help message. + - command: + type: string + description: An example command to run the pipeline, to show in the help message and the summary. + - cli_typecast: + type: boolean + description: | + Whether to apply typecasting to the parameters given via the CLI before validation. + Set this to `null` to use the default behavior. output: - dummy_emit: type: boolean diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test index 8fb3016..1fd1eac 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/main.nf.test @@ -25,6 +25,13 @@ nextflow_workflow { input[0] = workflow input[1] = validate_params input[2] = "" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" + input[9] = null """ } } @@ -51,6 +58,13 @@ nextflow_workflow { input[0] = workflow input[1] = validate_params input[2] = "" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" + input[9] = null """ } } @@ -77,6 +91,13 @@ nextflow_workflow { input[0] = workflow input[1] = validate_params input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" + input[9] = null """ } } @@ -103,6 +124,13 @@ nextflow_workflow { input[0] = workflow input[1] = validate_params input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + input[3] = false + input[4] = false + input[5] = false + input[6] = "" + input[7] = "" + input[8] = "" + input[9] = null """ } } @@ -114,4 +142,37 @@ nextflow_workflow { ) } } + + test("Should create a help message") { + + when { + + params { + test_data = '' + outdir = null + } + + workflow { + """ + validate_params = true + input[0] = workflow + input[1] = validate_params + input[2] = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" + input[3] = true + input[4] = false + input[5] = false + input[6] = "Before" + input[7] = "After" + input[8] = "nextflow run test/test" + input[9] = null + """ + } + } + + then { + assertAll( + { assert workflow.success } + ) + } + } } diff --git a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config index 09ef842..fd71cb8 100644 --- a/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config +++ b/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow.config @@ -1,8 +1,8 @@ plugins { - id "nf-schema@2.4.2" + id "nf-schema@2.7.2" } validation { parametersSchema = "${projectDir}/subworkflows/nf-core/utils_nfschema_plugin/tests/nextflow_schema.json" monochromeLogs = true -} \ No newline at end of file +} diff --git a/tests/.nftignore b/tests/.nftignore index 158c83c..968874a 100644 --- a/tests/.nftignore +++ b/tests/.nftignore @@ -1,11 +1,27 @@ .DS_Store -multiqc/multiqc_data/fastqc_top_overrepresented_sequences_table.txt -multiqc/multiqc_data/BETA-multiqc.parquet +multiqc/multiqc_data/multiqc.parquet multiqc/multiqc_data/multiqc.log multiqc/multiqc_data/multiqc_data.json multiqc/multiqc_data/multiqc_sources.txt multiqc/multiqc_data/multiqc_software_versions.txt +multiqc/multiqc_data/llms-full.txt multiqc/multiqc_plots/{svg,pdf,png}/*.{svg,pdf,png} multiqc/multiqc_report.html -fastqc/*_fastqc.{html,zip} +multiqc/multiqc_data/llms-full.txt +multiqc/multiqc_data/multiqc.parquet pipeline_info/*.{html,json,txt,yml} +**/*.log +**/*.biom +**/*_profile.txt +**/*_genefamilies.tsv.gz +**/*_pathcoverage.tsv.gz +**/*_pathabundance.tsv.gz +**/*_reactions.tsv.gz +**/*bowtie2out.txt +**/*_mapping_data.json +**/*_mapping_data.txt +**/*.seqs.temp.txt +**/*.allele_mapping_data.json +**/*.allele_mapping_data.txt +**/*.gene_mapping_data.json +**/*.gene_mapping_data.txt diff --git a/tests/default.nf.test b/tests/default.nf.test index 637443a..e28fd20 100644 --- a/tests/default.nf.test +++ b/tests/default.nf.test @@ -3,6 +3,7 @@ nextflow_pipeline { name "Test pipeline" script "../main.nf" tag "pipeline" + profile "test" test("-profile test") { @@ -13,21 +14,19 @@ nextflow_pipeline { } then { - // stable_name: All files + folders in ${params.outdir}/ with a stable name - def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) - // stable_path: All files in ${params.outdir}/ with stable content - def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + // stable_path: All files + folders in ${params.outdir}/ with a stable path (including file name) + def stable_path = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: ['pipeline_info/*.{html,json,txt}']) + // stable_content: All files in ${params.outdir}/ with stable content + def stable_content = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assert workflow.success assertAll( - { assert workflow.success}, { assert snapshot( - // Number of successful tasks - workflow.trace.succeeded().size(), // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions - removeNextflowVersion("$outputDir/pipeline_info/nf_core_funcprofiler_software_mqc_versions.yml"), + //removeNextflowVersion("$outputDir/pipeline_info/nf_core_funcprofiler_software_mqc_versions.yml"), // All stable path name, with a relative path - stable_name, + stable_path, // All files with stable contents - stable_path + stable_content ).match() } ) } diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap new file mode 100644 index 0000000..34c585e --- /dev/null +++ b/tests/default.nf.test.snap @@ -0,0 +1,101 @@ +{ + "-profile test": { + "content": [ + [ + "cat", + "cat/minigut.merged.fastq.gz", + "fmhfunprofiler", + "fmhfunprofiler/KOs_sketched_scaled_1000_demo.sig.zip", + "fmhfunprofiler/KOs_sketched_scaled_1000_demo.sig.zip/minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv", + "humann3", + "humann3/minigut.log", + "humann3/minigut_genefamilies.tsv.gz", + "humann3/minigut_pathabundance.tsv.gz", + "humann3/minigut_pathcoverage.tsv.gz", + "mifaser", + "mifaser/minigut_analysis.tsv", + "mifaser/minigut_ec_count.tsv", + "mifaser/minigut_multi_ec.tsv", + "mpahumann3", + "mpahumann3/minigut.biom", + "mpahumann3/minigut.bowtie2out.txt", + "mpahumann3/minigut_profile.txt", + "pipeline_info", + "pipeline_info/nf_core_funcprofiler_software_mqc_versions.yml", + "rgi", + "rgi/4.0.1", + "rgi/4.0.1/minigut.allele_mapping_data.json", + "rgi/4.0.1/minigut.allele_mapping_data.txt", + "rgi/4.0.1/minigut.artifacts_mapping_stats.txt", + "rgi/4.0.1/minigut.coverage.temp.txt", + "rgi/4.0.1/minigut.coverage_all_positions.summary.temp.txt", + "rgi/4.0.1/minigut.coverage_all_positions.temp.txt", + "rgi/4.0.1/minigut.gene_mapping_data.txt", + "rgi/4.0.1/minigut.overall_mapping_stats.txt", + "rgi/4.0.1/minigut.reference_mapping_stats.txt", + "rgi/4.0.1/minigut.seqs.temp.txt", + "rgi/4.0.1/minigut.temp.txt", + "rgi/card_database_processed", + "rgi/card_database_processed/CARD-Download-README.txt", + "rgi/card_database_processed/PMID.tsv", + "rgi/card_database_processed/aro_categories.tsv", + "rgi/card_database_processed/aro_categories_index.tsv", + "rgi/card_database_processed/aro_index.tsv", + "rgi/card_database_processed/card.json", + "rgi/card_database_processed/card_database_v4.0.1.fasta", + "rgi/card_database_processed/card_database_v4.0.1_all.fasta", + "rgi/card_database_processed/nucleotide_fasta_protein_homolog_model.fasta", + "rgi/card_database_processed/nucleotide_fasta_protein_knockout_model.fasta", + "rgi/card_database_processed/nucleotide_fasta_protein_overexpression_model.fasta", + "rgi/card_database_processed/nucleotide_fasta_protein_variant_model.fasta", + "rgi/card_database_processed/nucleotide_fasta_rRNA_gene_variant_model.fasta", + "rgi/card_database_processed/protein_fasta_protein_homolog_model.fasta", + "rgi/card_database_processed/protein_fasta_protein_knockout_model.fasta", + "rgi/card_database_processed/protein_fasta_protein_overexpression_model.fasta", + "rgi/card_database_processed/protein_fasta_protein_variant_model.fasta", + "rgi/card_database_processed/shortname_antibiotics.tsv", + "rgi/card_database_processed/shortname_pathogens.tsv", + "rgi/card_database_processed/snps.txt" + ], + [ + "minigut.merged.fastq.gz:md5,1fbae8f5fe6fdfa6552cfca32d9c3129", + "minigut_KOs_sketched_scaled_1000_demo.sig.fmhfunprofiler.csv:md5,1081039ab9e9b378d2dfd3206e96e917", + "minigut_analysis.tsv:md5,1cda8e4b88a34f56539d04cc2dac0914", + "minigut_ec_count.tsv:md5,5c2306e908a487f57d70da9b4f131217", + "minigut_multi_ec.tsv:md5,915713718d7b6fabc3fbc3a1286999e0", + "minigut.artifacts_mapping_stats.txt:md5,26b4346ac5367d575ab67f9246e8ca08", + "minigut.coverage.temp.txt:md5,8fa9ceb6c1f02bdcd89472c2523a775a", + "minigut.coverage_all_positions.summary.temp.txt:md5,9d93d7e96faf94c18f637a02ef1cebf2", + "minigut.coverage_all_positions.temp.txt:md5,fd6083d850435153d3678aa5c387fdc2", + "minigut.overall_mapping_stats.txt:md5,7a66e3f185702925bef3873f356072ff", + "minigut.reference_mapping_stats.txt:md5,986084fa8f72769b0e8a8827ce84f138", + "minigut.temp.txt:md5,e8510289eeb0be3d0e25faaef0c43116", + "CARD-Download-README.txt:md5,b57364cc1a5fab0541e13a01fabe5dea", + "PMID.tsv:md5,e3ce79c4b5dcf0a9e3117ed683f96e54", + "aro_categories.tsv:md5,6f9c4b0410b9e2b3cf5867a2a3f1db07", + "aro_categories_index.tsv:md5,d5fbc673c0de6601b07c8016b3909f8e", + "aro_index.tsv:md5,0f183c7869876fa32c8f86aade0df7b5", + "card.json:md5,72156d00155f69e637664bfb5d3b5395", + "card_database_v4.0.1.fasta:md5,5ead0b239c312ebb068a3b5aa9676b2d", + "card_database_v4.0.1_all.fasta:md5,f389ce15fac30e9ab394ca8a49f6451f", + "nucleotide_fasta_protein_homolog_model.fasta:md5,696d1aa4f04bd08fc4bdeea33ab9db43", + "nucleotide_fasta_protein_knockout_model.fasta:md5,d8224ce019ad69a041d83ccf7877b4e0", + "nucleotide_fasta_protein_overexpression_model.fasta:md5,80a1e7957c79d311446e06c6dd49db8e", + "nucleotide_fasta_protein_variant_model.fasta:md5,7450e559045c9d1d8f13c73054c64f4c", + "nucleotide_fasta_rRNA_gene_variant_model.fasta:md5,bd53f46d630f652c9f6b7584c2126e1f", + "protein_fasta_protein_homolog_model.fasta:md5,36ea300133fd7c5a45de2fee4c5050bf", + "protein_fasta_protein_knockout_model.fasta:md5,f16667df70d1a5f910d3ae45f5250c3d", + "protein_fasta_protein_overexpression_model.fasta:md5,723e8762be5c96aed8c379a6499cecee", + "protein_fasta_protein_variant_model.fasta:md5,8c02d8fc84c9a90953f8534355244019", + "shortname_antibiotics.tsv:md5,9a4ba742fd8a3a49c7f50744001a4129", + "shortname_pathogens.tsv:md5,5211712be4f4c3306cbe4052cafae1d7", + "snps.txt:md5,529d4fdb74c8940c0930ec1a7a6d4980" + ] + ], + "timestamp": "2026-07-31T09:50:44.24986845", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + } +} \ No newline at end of file diff --git a/tests/nextflow.config b/tests/nextflow.config index 73e92d1..6e088f1 100644 --- a/tests/nextflow.config +++ b/tests/nextflow.config @@ -4,11 +4,10 @@ ======================================================================================== */ -// TODO nf-core: Specify any additional parameters here -// Or any resources requirements params { modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/' - pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/refs/heads/funcprofiler' + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/' } -aws.client.anonymous = true // fixes S3 access issues on self-hosted runners +// Fixes S3 access issues on self-hosted runners +aws.client.anonymous = true diff --git a/workflows/funcprofiler.nf b/workflows/funcprofiler.nf index 18a9ad8..226845a 100644 --- a/workflows/funcprofiler.nf +++ b/workflows/funcprofiler.nf @@ -3,12 +3,14 @@ IMPORT MODULES / SUBWORKFLOWS / FUNCTIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { FASTQC } from '../modules/nf-core/fastqc/main' -include { MULTIQC } from '../modules/nf-core/multiqc/main' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' +include { MULTIQC } from '../modules/nf-core/multiqc/main' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { paramsSummaryMultiqc } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { softwareVersionsToYAML } from '../subworkflows/nf-core/utils_nfcore_pipeline' include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_funcprofiler_pipeline' +include { DATAPREP } from '../subworkflows/local/dataprep/main' +include { DBPREP } from '../subworkflows/local/dbprep/main' +include { PROFILE } from '../subworkflows/local/profile/main' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -17,81 +19,90 @@ include { methodsDescriptionText } from '../subworkflows/local/utils_nfcore_func */ workflow FUNCPROFILER { - take: - ch_samplesheet // channel: samplesheet read in from --input + reads // channel: validated reads read in from --input + databases // channel: databases from --databases + multiqc_config + multiqc_logo + multiqc_methods_description + outdir + main: ch_versions = Channel.empty() ch_multiqc_files = Channel.empty() - // - // MODULE: Run FastQC - // - FASTQC ( - ch_samplesheet + + DATAPREP( + reads + ) + + DBPREP( + databases + ) + PROFILE( + DATAPREP.out.reads, + DATAPREP.out.reads_concat, + DBPREP.out.dbs, ) - ch_multiqc_files = ch_multiqc_files.mix(FASTQC.out.zip.collect{it[1]}) - ch_versions = ch_versions.mix(FASTQC.out.versions.first()) // // Collate and save software versions // - softwareVersionsToYAML(ch_versions) + def topic_versions = channel + .topic("versions") + .distinct() + .branch { entry -> + versions_file: entry instanceof Path + versions_tuple: true + } + + def topic_versions_string = topic_versions.versions_tuple + .map { process, tool, version -> + [process[process.lastIndexOf(':') + 1..-1], " ${tool}: ${version}"] + } + .groupTuple(by: 0) + .map { process, tool_versions -> + tool_versions.unique().sort() + "${process}:\n${tool_versions.join('\n')}" + } + + def ch_collated_versions = softwareVersionsToYAML(ch_versions.mix(topic_versions.versions_file)) + .mix(topic_versions_string) .collectFile( - storeDir: "${params.outdir}/pipeline_info", - name: 'nf_core_' + 'funcprofiler_software_' + 'mqc_' + 'versions.yml', + storeDir: "${outdir}/pipeline_info", + name: 'nf_core_' + 'funcprofiler_software_' + 'mqc_' + 'versions.yml', sort: true, - newLine: true - ).set { ch_collated_versions } - + newLine: true, + ) // // MODULE: MultiQC // - ch_multiqc_config = Channel.fromPath( - "$projectDir/assets/multiqc_config.yml", checkIfExists: true) - ch_multiqc_custom_config = params.multiqc_config ? - Channel.fromPath(params.multiqc_config, checkIfExists: true) : - Channel.empty() - ch_multiqc_logo = params.multiqc_logo ? - Channel.fromPath(params.multiqc_logo, checkIfExists: true) : - Channel.empty() - - summary_params = paramsSummaryMap( - workflow, parameters_schema: "nextflow_schema.json") - ch_workflow_summary = Channel.value(paramsSummaryMultiqc(summary_params)) - ch_multiqc_files = ch_multiqc_files.mix( - ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) - ch_multiqc_custom_methods_description = params.multiqc_methods_description ? - file(params.multiqc_methods_description, checkIfExists: true) : - file("$projectDir/assets/methods_description_template.yml", checkIfExists: true) - ch_methods_description = Channel.value( - methodsDescriptionText(ch_multiqc_custom_methods_description)) - ch_multiqc_files = ch_multiqc_files.mix(ch_collated_versions) - ch_multiqc_files = ch_multiqc_files.mix( - ch_methods_description.collectFile( - name: 'methods_description_mqc.yaml', - sort: true - ) + def ch_summary_params = paramsSummaryMap(workflow, parameters_schema: "nextflow_schema.json") + def ch_workflow_summary = channel.value(paramsSummaryMultiqc(ch_summary_params)) + ch_multiqc_files = ch_multiqc_files.mix(ch_workflow_summary.collectFile(name: 'workflow_summary_mqc.yaml')) + def ch_multiqc_custom_methods_description = multiqc_methods_description + ? file(multiqc_methods_description, checkIfExists: true) + : file("${projectDir}/assets/methods_description_template.yml", checkIfExists: true) + def ch_methods_description = channel.value(methodsDescriptionText(ch_multiqc_custom_methods_description)) + ch_multiqc_files = ch_multiqc_files.mix(ch_methods_description.collectFile(name: 'methods_description_mqc.yaml', sort: true)) + MULTIQC( + ch_multiqc_files.flatten().collect().map { files -> + [ + [id: 'funcprofiler'], + files, + multiqc_config + ? file(multiqc_config, checkIfExists: true) + : file("${projectDir}/assets/multiqc_config.yml", checkIfExists: true), + multiqc_logo ? file(multiqc_logo, checkIfExists: true) : [], + [], + [], + ] + } ) - MULTIQC ( - ch_multiqc_files.collect(), - ch_multiqc_config.toList(), - ch_multiqc_custom_config.toList(), - ch_multiqc_logo.toList(), - [], - [] - ) - - emit:multiqc_report = MULTIQC.out.report.toList() // channel: /path/to/multiqc_report.html - versions = ch_versions // channel: [ path(versions.yml) ] - + emit: + multiqc_report = MULTIQC.out.report.map { _meta, report -> [report] }.toList() // channel: /path/to/multiqc_report.html + versions = ch_versions // channel: [ path(versions.yml) ] } - -/* -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - THE END -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*/