Return Code Evaluations and Assertions
๐ท๏ธ Operating System and System Operations / Shell Commands with Subprocess
When your scripts run shell commands or external programs, the operating system always sends back a return code (also called exit code or status code). This small number tells you whether the command succeeded or failed. Learning to evaluate these codes properly is essential for building reliable automation that can react to failures, retry operations, or stop execution when something goes wrong.
โ๏ธ What Is a Return Code?
Every command or program you run finishes with a numeric exit status:
- 0 means the command completed successfully
- Any non-zero value (1, 2, 127, etc.) indicates an error or abnormal termination
Python captures this return code automatically when you use the subprocess module. You can inspect it to decide what your script should do next.
๐ Checking Return Codes with subprocess
When you run a command using subprocess.run(), the result object contains a returncode attribute:
- Access it directly as result.returncode
- Compare it to 0 to check for success
- Use conditional logic to handle failures differently
A typical pattern looks like this:
- Run the command and store the result
- Check if result.returncode != 0
- If non-zero, log the error or exit the script with a message
- If zero, continue with the next step
๐ ๏ธ Using check=True for Automatic Validation
Instead of manually checking return codes every time, you can let Python do the work by passing check=True to subprocess.run():
- With check=True, Python raises a CalledProcessError if the return code is non-zero
- This stops your script immediately unless you catch the exception
- It is ideal for commands that must succeed before proceeding
Without check=True, your script continues running even if the command fails, which can lead to unpredictable behavior downstream.
๐ต๏ธ Understanding Common Return Codes
Different return codes give you clues about what went wrong:
| Return Code | Meaning | Typical Cause |
|---|---|---|
| 0 | Success | Command completed without errors |
| 1 | General error | Command failed for a generic reason |
| 2 | Misuse of shell builtins | Invalid syntax or wrong arguments |
| 126 | Command not executable | Permission denied or file is not executable |
| 127 | Command not found | The program does not exist in the system PATH |
| 130 | Script terminated by Ctrl+C | User interrupted the process |
| 137 | Killed by SIGKILL | Process was forcefully terminated |
| 255 | Exit status out of range | Command returned a value outside 0โ255 |
โ Introduction to Assertions
Assertions are a lightweight way to enforce conditions in your code. The assert statement checks if a condition is True, and if it is False, it raises an AssertionError and stops execution.
Use assertions for:
- Validating that a return code is zero
- Confirming that a file exists before reading it
- Checking that variables have expected values
- Testing assumptions during development
The syntax is simple: assert condition, "optional error message"
๐งช Combining Return Codes with Assertions
You can combine both concepts to create self-checking scripts:
- Run a command and capture the result
- Use assert result.returncode == 0, "Command failed with code: {result.returncode}"
- If the command fails, the script stops with a clear message
- If it succeeds, execution continues normally
This approach is especially useful for:
- Deployment scripts where every step must succeed
- Testing pipelines that verify system states
- Automation tasks that should not proceed after a failure
โ ๏ธ When to Use Assertions vs. Exceptions
Both techniques help you handle failures, but they serve different purposes:
| Feature | Assertions | Exceptions (try/except) |
|---|---|---|
| Primary use | Development and debugging | Production error handling |
| Can be disabled | Yes, with -O flag | No, always active |
| Error message | Custom message in assert | Full exception object with traceback |
| Recovery | Not intended for recovery | Can catch and continue |
| Best for | Checking invariants and assumptions | Handling expected runtime errors |
Use assertions for conditions that should never happen if your code is correct. Use exceptions for errors you anticipate and want to handle gracefully.
๐ Best Practices for Return Code Evaluation
Follow these guidelines to write robust scripts:
- Always check return codes after running external commands
- Use check=True for commands that are critical to your workflow
- Log the return code and command output when a failure occurs
- Do not assume a command succeeded just because no exception was raised
- Use meaningful exit codes in your own scripts (0 for success, 1 for general errors)
- Document what each non-zero return code means in your code comments
๐ง Summary
Return codes are the operating system's way of telling you whether a command worked. Python's subprocess module gives you full access to these codes, and you can evaluate them manually or automatically with check=True. Assertions provide a simple way to enforce conditions and catch problems early during development. Together, these tools help you build scripts that fail fast, fail clearly, and never silently ignore errors.
Return code evaluations and assertions check whether a shell command succeeded or failed by examining its exit status.
โ Example 1: Checking a successful command's return code
This example runs a simple command and prints its return code to show that success equals zero.
import subprocess
result = subprocess.run(["echo", "hello"])
print(result.returncode)
๐ค Output: 0
โ Example 2: Checking a failed command's return code
This example runs a command that does not exist and prints the non-zero return code.
import subprocess
result = subprocess.run(["nonexistent_command"], capture_output=True)
print(result.returncode)
๐ค Output: 127
โ Example 3: Using check=True to raise an exception on failure
This example shows how to let Python automatically raise an error when a command fails.
import subprocess
try:
subprocess.run(["false"], check=True)
except subprocess.CalledProcessError as error:
print("Command failed with return code:", error.returncode)
๐ค Output: Command failed with return code: 1
โ Example 4: Using assert to validate a command succeeded
This example uses an assertion to verify that a command ran successfully before continuing.
import subprocess
result = subprocess.run(["ls", "/tmp"], capture_output=True)
assert result.returncode == 0, "ls command failed"
print("Command succeeded")
๐ค Output: Command succeeded
โ Example 5: Practical pattern โ run command and assert success
This example runs a real-world command and uses assert to confirm it completed without errors.
import subprocess
result = subprocess.run(["mkdir", "-p", "/tmp/test_folder"], capture_output=True)
assert result.returncode == 0, f"mkdir failed with code {result.returncode}"
print("Folder created successfully")
๐ค Output: Folder created successfully
Comparison Table
| Method | Behavior on Success | Behavior on Failure | Use Case |
|---|---|---|---|
result.returncode |
Returns 0 | Returns non-zero integer | Manual checking |
check=True |
Continues execution | Raises CalledProcessError |
Automatic error handling |
assert result.returncode == 0 |
Continues execution | Raises AssertionError |
Validation in tests or scripts |
When your scripts run shell commands or external programs, the operating system always sends back a return code (also called exit code or status code). This small number tells you whether the command succeeded or failed. Learning to evaluate these codes properly is essential for building reliable automation that can react to failures, retry operations, or stop execution when something goes wrong.
โ๏ธ What Is a Return Code?
Every command or program you run finishes with a numeric exit status:
- 0 means the command completed successfully
- Any non-zero value (1, 2, 127, etc.) indicates an error or abnormal termination
Python captures this return code automatically when you use the subprocess module. You can inspect it to decide what your script should do next.
๐ Checking Return Codes with subprocess
When you run a command using subprocess.run(), the result object contains a returncode attribute:
- Access it directly as result.returncode
- Compare it to 0 to check for success
- Use conditional logic to handle failures differently
A typical pattern looks like this:
- Run the command and store the result
- Check if result.returncode != 0
- If non-zero, log the error or exit the script with a message
- If zero, continue with the next step
๐ ๏ธ Using check=True for Automatic Validation
Instead of manually checking return codes every time, you can let Python do the work by passing check=True to subprocess.run():
- With check=True, Python raises a CalledProcessError if the return code is non-zero
- This stops your script immediately unless you catch the exception
- It is ideal for commands that must succeed before proceeding
Without check=True, your script continues running even if the command fails, which can lead to unpredictable behavior downstream.
๐ต๏ธ Understanding Common Return Codes
Different return codes give you clues about what went wrong:
| Return Code | Meaning | Typical Cause |
|---|---|---|
| 0 | Success | Command completed without errors |
| 1 | General error | Command failed for a generic reason |
| 2 | Misuse of shell builtins | Invalid syntax or wrong arguments |
| 126 | Command not executable | Permission denied or file is not executable |
| 127 | Command not found | The program does not exist in the system PATH |
| 130 | Script terminated by Ctrl+C | User interrupted the process |
| 137 | Killed by SIGKILL | Process was forcefully terminated |
| 255 | Exit status out of range | Command returned a value outside 0โ255 |
โ Introduction to Assertions
Assertions are a lightweight way to enforce conditions in your code. The assert statement checks if a condition is True, and if it is False, it raises an AssertionError and stops execution.
Use assertions for:
- Validating that a return code is zero
- Confirming that a file exists before reading it
- Checking that variables have expected values
- Testing assumptions during development
The syntax is simple: assert condition, "optional error message"
๐งช Combining Return Codes with Assertions
You can combine both concepts to create self-checking scripts:
- Run a command and capture the result
- Use assert result.returncode == 0, "Command failed with code: {result.returncode}"
- If the command fails, the script stops with a clear message
- If it succeeds, execution continues normally
This approach is especially useful for:
- Deployment scripts where every step must succeed
- Testing pipelines that verify system states
- Automation tasks that should not proceed after a failure
โ ๏ธ When to Use Assertions vs. Exceptions
Both techniques help you handle failures, but they serve different purposes:
| Feature | Assertions | Exceptions (try/except) |
|---|---|---|
| Primary use | Development and debugging | Production error handling |
| Can be disabled | Yes, with -O flag | No, always active |
| Error message | Custom message in assert | Full exception object with traceback |
| Recovery | Not intended for recovery | Can catch and continue |
| Best for | Checking invariants and assumptions | Handling expected runtime errors |
Use assertions for conditions that should never happen if your code is correct. Use exceptions for errors you anticipate and want to handle gracefully.
๐ Best Practices for Return Code Evaluation
Follow these guidelines to write robust scripts:
- Always check return codes after running external commands
- Use check=True for commands that are critical to your workflow
- Log the return code and command output when a failure occurs
- Do not assume a command succeeded just because no exception was raised
- Use meaningful exit codes in your own scripts (0 for success, 1 for general errors)
- Document what each non-zero return code means in your code comments
๐ง Summary
Return codes are the operating system's way of telling you whether a command worked. Python's subprocess module gives you full access to these codes, and you can evaluate them manually or automatically with check=True. Assertions provide a simple way to enforce conditions and catch problems early during development. Together, these tools help you build scripts that fail fast, fail clearly, and never silently ignore errors.
Interactive Views
You are currently in ๐ All-in-One mode. Use the tabs at the top to switch to ๐ Theory Only or ๐ป Code Only views.
Return code evaluations and assertions check whether a shell command succeeded or failed by examining its exit status.
โ Example 1: Checking a successful command's return code
This example runs a simple command and prints its return code to show that success equals zero.
import subprocess
result = subprocess.run(["echo", "hello"])
print(result.returncode)
๐ค Output: 0
โ Example 2: Checking a failed command's return code
This example runs a command that does not exist and prints the non-zero return code.
import subprocess
result = subprocess.run(["nonexistent_command"], capture_output=True)
print(result.returncode)
๐ค Output: 127
โ Example 3: Using check=True to raise an exception on failure
This example shows how to let Python automatically raise an error when a command fails.
import subprocess
try:
subprocess.run(["false"], check=True)
except subprocess.CalledProcessError as error:
print("Command failed with return code:", error.returncode)
๐ค Output: Command failed with return code: 1
โ Example 4: Using assert to validate a command succeeded
This example uses an assertion to verify that a command ran successfully before continuing.
import subprocess
result = subprocess.run(["ls", "/tmp"], capture_output=True)
assert result.returncode == 0, "ls command failed"
print("Command succeeded")
๐ค Output: Command succeeded
โ Example 5: Practical pattern โ run command and assert success
This example runs a real-world command and uses assert to confirm it completed without errors.
import subprocess
result = subprocess.run(["mkdir", "-p", "/tmp/test_folder"], capture_output=True)
assert result.returncode == 0, f"mkdir failed with code {result.returncode}"
print("Folder created successfully")
๐ค Output: Folder created successfully
Comparison Table
| Method | Behavior on Success | Behavior on Failure | Use Case |
|---|---|---|---|
result.returncode |
Returns 0 | Returns non-zero integer | Manual checking |
check=True |
Continues execution | Raises CalledProcessError |
Automatic error handling |
assert result.returncode == 0 |
Continues execution | Raises AssertionError |
Validation in tests or scripts |