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 directlyFile mapping:
files={"dest.txt": "/local/source.txt"}- Upload with custom namesPre-uploaded files:
files={"script.sh": uploaded_file_object}- Use files uploaded viaclient.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 directlyPIPE: 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 checkreturncodeEnvironment variables: Pass custom
envdictionaryWorking directory: Set
cwdparameterShell commands: Enable with
shell=TrueError handling: Check
returncodeandstderrfor 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, orbytes)stderr: Redirect stderr (StringIO, BytesIO, PIPE, orbytes)files: Upload files (list of paths or dict mapping)
Execution Parameters¶
cwd: Working directory inside containerdisposable: 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