Planemo, docker, python: issue with getting args passed to the script

Hi all,

I am working on my first galaxy tool release (private tool, so I made some minimal code that reproduces my issue), and I am struggling with passing python args; when I print the sys.argv content before parsing args, the issue is obvious (see below). What’s interesting is that as a starting point, I used a tool that is deployed on our Galaxy server, and it works… But maybe there is a config somewhere that I do not know about that changes how args are passed?

The screenshot above was generated using planemo:

planemo docker_build --no_docker_sudo galaxy_minimal.xml
planemo serve --docker --no_cleanup galaxy_minimal.xml

I have tested the docker image and it works as intended:

So the issue is definitely somewhere else, but I have not been able to figure it out after a couple days of trying things out. I would love to share all files in a zip but did not see a way to upload?

In case there is something obvious, I copy pasted my Dockerfile and my xml below.

Dockerfile:

# Use a Python image with uv pre-installed
# https://docs.astral.sh/uv/guides/integration/docker/#installing-uv
# - uv v7.2.0 installed
# - python 3.12 (slim)
FROM ghcr.io/astral-sh/uv:0.7.2-python3.12-bookworm-slim

# Enable uv bytecode compilation
ENV UV_COMPILE_BYTECODE=1
# Have uv copy from the cache instead of creating symlinks since it's a mounted volume
ENV UV_LINK_MODE=copy

# Define the working directory
WORKDIR /workdir

# Copy dependencies code in workdir
COPY uv.lock pyproject.toml ./

# Build the environment --> in .venv
RUN uv sync --frozen --no-dev

# Copy files from the directory where the Dockerfile is located code in WORKDIR inside image
# In case existing .venv in repo, .venv is in the .dockerignore to avoid overriding
COPY --chmod=0755 . .

# Place current env at the front of the path
# This ensures the container will use the right Python interpreter and dependencies
ENV PATH="/workdir/.venv/bin:$PATH"

# use sh script to pass the args
ENTRYPOINT [ "python", "/workdir/src/galaxy_minimal.py" ]

python script:

import argparse
import sys

def main():

    print("All command-line arguments (raw):", sys.argv)

    parser = argparse.ArgumentParser()
    parser.add_argument("--input", action="store", required=True, type=str, help="Any text file")
    parser.add_argument("--output", action="store", required=True, type=str, help="Output file name")
    args=parser.parse_args()

    success_message = f"Successfully processed args:\n --input {args.input}\n --output {args.output}"

    with open(args.output, 'w') as fho:
        fho.write(success_message)

    # Add in standard out
    print(success_message)

# Excute main; command line or galaxy docker entrypoint
main()

xml file:

<tool
    id="galaxy_minimal"
    name="Galaxy Debug"
    version="1.0.0"
    profile="22.01">
    <description>Debug Galaxy xml/deployment</description>

    <requirements>
        <container type="docker">galaxydebug:1.0.0</container>
    </requirements>

    <command><![CDATA[
        python /debug/galaxy_minimal.py --input '$input' --output DebugGalaxy.log
    ]]></command>

    <inputs>
        <param name="input" label="Input File" type="data" help="Upload any file" />
    </inputs>

    <outputs>
        <data name="output_file" format="txt" from_work_dir="DebugGalaxy.log" ></data>
    </outputs>

    <help> <![CDATA[
        .. class:: infomark
        Reproduce issue with minimal code
    ]]></help>

</tool>


The way Galaxy executes the command you’re assembling in the <command>section works differently from what you’re thinking:

The command gets written together with other boilerplate stuff into a tool_script.sh file, which is then passed to the environment’s /bin/sh, which is supposed to execute it.

Now because of the way you configured the docker image, that /bin/sh tool_script.shcommand doesn’t reach a shell, but gets passed directly to the python script.

1 Like

In other words, you’re not supposed to create a docker container that acts as your script, but one that merely provides a shell environment, from which your script can get executed.

1 Like

Thank you, that is very helpful!

@wm75 Thanks again for putting me on the right path.

I changed the Dockerfile entrypoint to, well, nothing:

# Galaxy will provide the command
ENTRYPOINT [ ]

And now it works:

Hopefully this is what you meant!

1 Like

Yes, the entry point would have been the problem.

Thanks for reporting back!