Running Commands

Contree SDK provides multiple ways to execute commands in containers, from simple shell commands to complex workflows with file handling and custom I/O.

Basic Command Execution

You can run commands using shell syntax or by specifying command and arguments separately:

 1image = await client.images.pull("busybox:latest")
 2print(f"Pulled {image=}")
 3
 4result = await image.run(shell="echo 'Hello World'")
 5print(f"Simple echo: {result.stdout=}, {result.stderr=}, {result.exit_code=}")
 6
 7result = await image.run(shell="pwd")
 8print(f"Current directory: {result.stdout=}, {result.exit_code=}")
 9
10result = await image.run(shell="ls -la")
11print(f"Directory listing: {result.stdout=}, {result.exit_code=}")
12
13result = await image.run(shell="cat -", stdin="Hello from stdin\n")
14print(f"Cat with stdin: {result.stdout=}, {result.exit_code=}")
15
16result = await image.run(shell="echo 'Error message' >&2; exit 1")
17print(f"Error command: {result.stdout=}, {result.stderr=}, {result.exit_code=}")

See ContreeImage.run() and ContreeSession.run() for all options.

 1image = client.images.pull("busybox:latest")
 2print(f"Pulled {image=}")
 3
 4result = image.run(shell="echo 'Hello World'").wait()
 5print(f"Simple echo: {result.stdout=}, {result.stderr=}, {result.exit_code=}")
 6
 7result = image.run(shell="pwd").wait()
 8print(f"Current directory: {result.stdout=}, {result.exit_code=}")
 9
10result = image.run(shell="ls -la").wait()
11print(f"Directory listing: {result.stdout=}, {result.exit_code=}")
12
13result = image.run(shell="cat -", stdin="Hello from stdin\n").wait()
14print(f"Cat with stdin: {result.stdout=}, {result.exit_code=}")
15
16result = image.run(shell="echo 'Error message' >&2; exit 1").wait()
17print(f"Error command: {result.stdout=}, {result.stderr=}, {result.exit_code=}")

See ContreeImageSync.run() and ContreeSessionSync.run() for all options.

Working with Files

You can upload and use files in your commands by specifying local file paths or pre-uploaded file objects:

 1image = await client.images.pull("busybox:latest")
 2print(f"Pulled {image=}")
 3
 4print("\nExample 1: Local file upload to image")
 5with NamedTemporaryFile(mode="w", suffix=".txt") as test_file:
 6    test_file.write("some txt file\nsecond line\n\nlast line\n")
 7    test_file.flush()
 8
 9    result = await image.run(shell=f"cat /{test_file.name.split('/')[-1]} | grep line", files=[test_file.name])
10    print(f"Run with local file: {result.stdout=}, {result.exit_code=}")
11
12print("\nExample 2: Upload file via contree.files and use in image")
13with NamedTemporaryFile(mode="w", suffix=".sh") as script_file:
14    script_file.write("#!/bin/sh\necho 'Hello from uploaded script'\necho 'Working directory:'\npwd\n")
15    script_file.flush()
16
17    uploaded_file = await client.files.upload(script_file.name)
18    print(f"Uploaded file: {uploaded_file=}")
19
20    result = await image.run(shell="sh /file.sh", files={"file.sh": uploaded_file})
21    print(f"Run with uploaded file: {result.stdout=}, {result.stderr=}, {result.exit_code=}")
22
23print("\nExample 3: Multiple files working together")
24with (
25    NamedTemporaryFile(mode="w", suffix=".txt") as data_file,
26    NamedTemporaryFile(mode="w", suffix=".sh") as script_file,
27):
28    data_file.write("apple\nbanana\ncherry\ndate\n")
29    data_file.flush()
30
31    script_file.write(
32        "#!/bin/bash\necho 'Processing data:'\ncat /data.txt | grep -E '^[ab]'"
33        "\necho 'Found items starting with a or b'"
34    )
35    script_file.flush()
36
37    result = await image.run(
38        shell="chmod +x /script.sh && sh /script.sh",
39        files={"data.txt": data_file.name, "script.sh": script_file.name},
40    )
41    print(f"Multiple files result: {result.stdout=}, {result.stderr=}, {result.exit_code=}")
 1image = client.images.pull("busybox:latest")
 2print(f"Pulled {image=}")
 3
 4print("\nExample 1: Local file upload to image")
 5with NamedTemporaryFile(mode="w", suffix=".txt") as test_file:
 6    test_file.write("some txt file\nsecond line\n\nlast line\n")
 7    test_file.flush()
 8
 9    result = image.run(shell=f"cat /{test_file.name.split('/')[-1]} | grep line", files=[test_file.name]).wait()
10    print(f"Run with local file: {result.stdout=}, {result.exit_code=}")
11
12print("\nExample 2: Upload file via contree.files and use in image")
13with NamedTemporaryFile(mode="w", suffix=".sh") as script_file:
14    script_file.write("#!/bin/sh\necho 'Hello from uploaded script'\necho 'Working directory:'\npwd\n")
15    script_file.flush()
16
17    uploaded_file = client.files.upload(script_file.name)
18    print(f"Uploaded file: {uploaded_file=}")
19
20    result = image.run(shell="sh /file.sh", files={"file.sh": uploaded_file}).wait()
21    print(f"Run with uploaded file: {result.stdout=}, {result.stderr=}, {result.exit_code=}")
22
23print("\nExample 3: Multiple files working together")
24with (
25    NamedTemporaryFile(mode="w", suffix=".txt") as data_file,
26    NamedTemporaryFile(mode="w", suffix=".sh") as script_file,
27):
28    data_file.write("apple\nbanana\ncherry\ndate\n")
29    data_file.flush()
30
31    script_file.write(
32        "#!/bin/bash\necho 'Processing data:'\ncat /data.txt | grep -E '^[ab]'"
33        "\necho 'Found items starting with a or b'"
34    )
35    script_file.flush()
36
37    result = image.run(
38        shell="chmod +x /script.sh && sh /script.sh",
39        files={"data.txt": data_file.name, "script.sh": script_file.name},
40    ).wait()
41    print(f"Multiple files result: {result.stdout=}, {result.stderr=}, {result.exit_code=}")

File Upload Methods

You can provide files to commands in several ways:

  • Local file paths: files=["/path/to/local/file.txt"] - Upload files directly

  • File mapping: files={"dest.txt": "/local/source.txt"} - Upload with custom names

  • Pre-uploaded files: files={"script.sh": uploaded_file_object} - Use files uploaded via client.files.upload()

Advanced I/O Handling

You can use Python I/O objects for more sophisticated input/output handling:

 1image = await client.images.pull("busybox:latest")
 2print(f"Pulled {image=}")
 3
 4print("\nExample 1: StringIO for stdin and stdout")
 5stdin_io = StringIO("apple\nbanana\ncherry\ndate\n")
 6stdout_io = StringIO()
 7
 8result = await image.run(shell="grep 'a' | sort", stdin=stdin_io, stdout=stdout_io)
 9print(f"StringIO result: exit_code={result.exit_code}")
10print(f"Output in StringIO: {stdout_io.getvalue()=}")
11print(f"result.stdout is the StringIO object: {result.stdout is stdout_io}")
12
13print("\nExample 2: PIPE for stderr capture")
14result = await image.run(shell="echo 'to stdout'; echo 'to stderr' >&2; exit 0", stderr=PIPE)
15print(f"PIPE stderr: {result.stdout=}")
16print(f"Stderr content: {result.stderr.read().decode()=}")
17print(f"Stderr type: {type(result.stderr).__name__}")
18
19print("\nExample 3: Output to bytes")
20result = await image.run(shell="echo 'Hello bytes world'", stdout=bytes)
21print(f"Bytes output: {result.stdout=}")
22print(f"Output type: {type(result.stdout).__name__}")
23
24print("\nExample 4: open() file object for input")
25with NamedTemporaryFile(mode="w", suffix=".txt") as temp_file:
26    temp_file.write("line1\nline2\nline3\n")
27    temp_file.flush()
28
29    with open(temp_file.name) as file_obj:
30        result = await image.run(shell="wc -l", stdin=file_obj)
31        print(f"File object input: {result.stdout=}, {result.exit_code=}")
32
33print("\nExample 5: BytesIO for binary data")
34binary_data = BytesIO(b"binary\ndata\nlines\n")
35
36result = await image.run(shell="wc -l", stdin=binary_data)
37print(f"BytesIO input: {result.stdout=}, {result.exit_code=}")

See run() for I/O parameter details.

 1image = client.images.pull("busybox:latest")
 2print(f"Pulled {image=}")
 3
 4print("\nExample 1: StringIO for stdin and stdout")
 5stdin_io = StringIO("apple\nbanana\ncherry\ndate\n")
 6stdout_io = StringIO()
 7
 8result = image.run(shell="grep 'a' | sort", stdin=stdin_io, stdout=stdout_io).wait()
 9print(f"StringIO result: exit_code={result.exit_code}")
10print(f"Output in StringIO: {stdout_io.getvalue()=}")
11print(f"result.stdout is the StringIO object: {result.stdout is stdout_io}")
12
13print("\nExample 2: PIPE for stderr capture")
14result = image.run(shell="echo 'to stdout'; echo 'to stderr' >&2; exit 0", stderr=PIPE).wait()
15print(f"PIPE stderr: {result.stdout=}")
16print(f"Stderr content: {result.stderr.read().decode()=}")
17print(f"Stderr type: {type(result.stderr).__name__}")
18
19print("\nExample 3: Output to bytes")
20result = image.run(shell="echo 'Hello bytes world'", stdout=bytes).wait()
21print(f"Bytes output: {result.stdout=}")
22print(f"Output type: {type(result.stdout).__name__}")
23
24print("\nExample 4: open() file object for input")
25with NamedTemporaryFile(mode="w", suffix=".txt") as temp_file:
26    temp_file.write("line1\nline2\nline3\n")
27    temp_file.flush()
28
29    with open(temp_file.name) as file_obj:
30        result = image.run(shell="wc -l", stdin=file_obj).wait()
31        print(f"File object input: {result.stdout=}, {result.exit_code=}")
32
33print("\nExample 5: BytesIO for binary data")
34binary_data = BytesIO(b"binary\ndata\nlines\n")
35
36result = image.run(shell="wc -l", stdin=binary_data).wait()
37print(f"BytesIO input: {result.stdout=}, {result.exit_code=}")

See run() for I/O parameter details.

Supported I/O Types

  • StringIO: For text-based input/output

  • BytesIO: For binary data handling

  • File objects: Use open() file handles directly

  • PIPE: Capture stderr/stdout as byte streams

  • bytes type: Get output as bytes instead of strings

Subprocess-like Interface (Sync Only)

You can use a subprocess-like interface for more control over process execution:

 1image = client.images.pull("busybox:latest")
 2print(f"Pulled {image=}")
 3
 4print("\nExample 1: Basic popen with wait()")
 5process = image.popen(["/bin/ls", "-la"], cwd="/bin")
 6process.wait()
 7print(f"Process completed: returncode={process.returncode}")
 8print(f"Output: {process.stdout[:100]}...")
 9
10print("\nExample 2: Shell command with stdout and stderr")
11process = image.popen("echo 'Hello stdout' && echo 'Hello stderr' >&2", shell=True)
12process.wait()
13print(f"Stdout: {process.stdout=}")
14print(f"Stderr: {process.stderr=}")
15
16print("\nExample 3: Using communicate() for input/output")
17process = image.popen(["/bin/grep", "apple"])
18stdout, stderr = process.communicate(input="apple\nbanana\ncherry\napple pie\n")
19print(f"Grep results: {stdout=}")
20print(f"Return code: {process.returncode=}")
21
22print("\nExample 4: Environment variables")
23process = image.popen(
24    "echo $MY_VAR && echo $ANOTHER_VAR", shell=True, env={"MY_VAR": "hello_world", "ANOTHER_VAR": "test_value"}
25)
26process.wait()
27print(f"Environment output: {process.stdout=}")
28
29print("\nExample 5: Error handling")
30process = image.popen(["/bin/ls", "/nonexistent"])
31process.wait()
32print(f"Error case: returncode={process.returncode}")
33print(f"Error output: {process.stderr=}")

See ContreeProcessSync for the full subprocess API.

Popen Features

  • Process control: Use wait(), communicate(), and check returncode

  • Environment variables: Pass custom env dictionary

  • Working directory: Set cwd parameter

  • Shell commands: Enable with shell=True

  • Error handling: Check returncode and stderr for failures

Command Parameters

Core Parameters

  • shell: Execute as shell command (e.g., "ls -la | grep txt")

  • command: Executable path (e.g., "/bin/ls")

  • args: Command arguments as tuple (e.g., ("-la", "/tmp"))

  • stdin: Input data (string, bytes, or I/O object)

  • env: Environment variables as dictionary

I/O Parameters

  • stdout: Redirect stdout (StringIO, BytesIO, file path, or bytes)

  • stderr: Redirect stderr (StringIO, BytesIO, PIPE, or bytes)

  • files: Upload files (list of paths or dict mapping)

Execution Parameters

  • cwd: Working directory inside container

  • disposable: Whether to persist changes (default: True for runs, False for sessions)

Result Objects

Command execution returns result objects with:

  • stdout: Command output as string (or specified type)

  • stderr: Error output as string (or specified type)

  • exit_code: Process exit code (0 = success)

  • uuid: UUID of the resulting image state