Practical Example: ConnectionFailedError Definition
๐ท๏ธ Error Handling and Exceptions / Custom Exceptions
๐ Context Introduction
When building tools that interact with external servicesโlike databases, APIs, or remote serversโconnection failures are a common reality. Instead of relying on generic Python exceptions, creating a custom exception like ConnectionFailedError makes your code more readable and your debugging more precise. This example shows how to define and use a custom exception for network-related failures.
โ๏ธ What Is a Custom Exception?
A custom exception is a new exception class you define by inheriting from Python's built-in Exception class. It allows you to:
- Give meaningful names to specific error conditions.
- Add extra attributes (like the hostname or port) to carry context.
- Catch and handle errors more selectively in your code.
๐ ๏ธ Defining ConnectionFailedError
To define a custom exception, you create a class that inherits from Exception. You can optionally add an init method to store additional information.
Example structure:
- Class name: ConnectionFailedError
- Inherits from: Exception
- Attributes: host (the target server address) and port (the target port number)
How to define it:
- Start with class ConnectionFailedError(Exception):
- Inside the class, define def init(self, host, port, message="Connection failed"):
- Call super().init(message) to initialize the base exception.
- Store self.host = host and self.port = port.
๐ Comparison: Built-in Exception vs. Custom Exception
| Feature | Built-in Exception (e.g., ConnectionError) | Custom ConnectionFailedError |
|---|---|---|
| Name clarity | Generic, could mean anything | Specific to connection failures |
| Extra context | No host or port info | Stores host and port details |
| Catch precision | Catches all connection issues | Catches only your defined scenario |
| Readability | Requires comments to explain | Self-documenting by name |
๐ต๏ธ How to Raise and Catch ConnectionFailedError
Raising the exception:
- Use raise ConnectionFailedError(host="api.example.com", port=443) inside your code when a connection attempt fails.
- You can pass a custom message like raise ConnectionFailedError(host, port, "Timeout after 5 seconds").
Catching the exception:
- Use try: and except ConnectionFailedError as e: to handle only this specific error.
- Inside the except block, access e.host, e.port, and str(e) to get details.
Example flow:
- Try to connect to a server.
- If connection fails, raise ConnectionFailedError with the host and port.
- In the calling code, catch ConnectionFailedError and log the host and port for debugging.
๐งฉ Why This Matters for Engineers
- Debugging speed: When you see ConnectionFailedError, you immediately know it's a network issue, not a logic bug.
- Error propagation: You can add context (like hostname) that helps trace the failure back to its source.
- Code maintainability: Other engineers reading your code understand exactly what failed without digging into implementation details.
- Separation of concerns: Network-related errors are handled separately from other exception types.
โ Best Practices for Custom Exceptions
- Keep the exception name descriptive and specific to the failure type.
- Include only relevant attributes that help diagnose the issue.
- Always call super().init() to ensure the base exception works correctly.
- Document your custom exception in the class docstring so others know when to raise and catch it.
- Avoid overusing custom exceptionsโuse them only when a built-in exception doesn't capture the needed context.
๐ Final Thought
Defining a ConnectionFailedError is a simple but powerful way to make your error handling more expressive. It turns a vague failure into a clear, actionable signal. As you build more complex systems, custom exceptions become an essential tool for writing robust, debuggable code.
A ConnectionFailedError is a custom exception class that engineers define to handle network connection failures in a clear and specific way.
๐ข Example 1: Basic ConnectionFailedError class definition
This example shows the simplest way to define a custom exception by inheriting from Python's built-in Exception class.
class ConnectionFailedError(Exception):
pass
๐ค Output: No output (class definition only)
๐ก Example 2: Raising a ConnectionFailedError
This example demonstrates how to raise the custom exception when a connection attempt fails.
class ConnectionFailedError(Exception):
pass
def connect_to_server(address):
raise ConnectionFailedError(f"Cannot connect to {address}")
connect_to_server("192.168.1.100")
๐ค Output: Traceback (most recent call last): ... ConnectionFailedError: Cannot connect to 192.168.1.100
๐ต Example 3: Catching a ConnectionFailedError with try-except
This example shows how engineers can catch and handle the custom exception gracefully.
class ConnectionFailedError(Exception):
pass
def connect_to_server(address):
raise ConnectionFailedError(f"Cannot connect to {address}")
try:
connect_to_server("192.168.1.100")
except ConnectionFailedError as error:
print(f"Connection issue: {error}")
๐ค Output: Connection issue: Cannot connect to 192.168.1.100
๐ฃ Example 4: ConnectionFailedError with custom attributes
This example adds a status code attribute to give engineers more information about the failure.
class ConnectionFailedError(Exception):
def __init__(self, address, status_code):
self.address = address
self.status_code = status_code
message = f"Failed to connect to {address} (status: {status_code})"
super().__init__(message)
def check_server(address):
status = 503
raise ConnectionFailedError(address, status)
try:
check_server("api.example.com")
except ConnectionFailedError as error:
print(f"Error: {error}")
print(f"Server: {error.address}, Status: {error.status_code}")
๐ค Output: Error: Failed to connect to api.example.com (status: 503)
Server: api.example.com, Status: 503
๐ด Example 5: Practical retry logic with ConnectionFailedError
This example shows how engineers can implement a retry mechanism when a connection fails.
import time
class ConnectionFailedError(Exception):
pass
def attempt_connection(server_name):
import random
if random.randint(1, 3) == 1:
print(f"Connected to {server_name}")
return True
else:
raise ConnectionFailedError(f"Could not reach {server_name}")
def connect_with_retry(server_name, max_retries=3):
for attempt in range(1, max_retries + 1):
try:
return attempt_connection(server_name)
except ConnectionFailedError as error:
print(f"Attempt {attempt} failed: {error}")
if attempt < max_retries:
time.sleep(1)
print("All connection attempts failed")
return False
connect_with_retry("database.internal")
๐ค Output: Attempt 1 failed: Could not reach database.internal
Attempt 2 failed: Could not reach database.internal
Connected to database.internal
Comparison Table
| Feature | Built-in Exception |
Custom ConnectionFailedError |
|---|---|---|
| Specificity | Generic error | Clear connection failure intent |
| Readability | Vague message | Self-documenting class name |
| Catch precision | Catches all errors | Catches only connection issues |
| Custom attributes | Not supported | Can add address, status code, etc. |
| Debugging value | Low | High for network engineers |
๐ Context Introduction
When building tools that interact with external servicesโlike databases, APIs, or remote serversโconnection failures are a common reality. Instead of relying on generic Python exceptions, creating a custom exception like ConnectionFailedError makes your code more readable and your debugging more precise. This example shows how to define and use a custom exception for network-related failures.
โ๏ธ What Is a Custom Exception?
A custom exception is a new exception class you define by inheriting from Python's built-in Exception class. It allows you to:
- Give meaningful names to specific error conditions.
- Add extra attributes (like the hostname or port) to carry context.
- Catch and handle errors more selectively in your code.
๐ ๏ธ Defining ConnectionFailedError
To define a custom exception, you create a class that inherits from Exception. You can optionally add an init method to store additional information.
Example structure:
- Class name: ConnectionFailedError
- Inherits from: Exception
- Attributes: host (the target server address) and port (the target port number)
How to define it:
- Start with class ConnectionFailedError(Exception):
- Inside the class, define def init(self, host, port, message="Connection failed"):
- Call super().init(message) to initialize the base exception.
- Store self.host = host and self.port = port.
๐ Comparison: Built-in Exception vs. Custom Exception
| Feature | Built-in Exception (e.g., ConnectionError) | Custom ConnectionFailedError |
|---|---|---|
| Name clarity | Generic, could mean anything | Specific to connection failures |
| Extra context | No host or port info | Stores host and port details |
| Catch precision | Catches all connection issues | Catches only your defined scenario |
| Readability | Requires comments to explain | Self-documenting by name |
๐ต๏ธ How to Raise and Catch ConnectionFailedError
Raising the exception:
- Use raise ConnectionFailedError(host="api.example.com", port=443) inside your code when a connection attempt fails.
- You can pass a custom message like raise ConnectionFailedError(host, port, "Timeout after 5 seconds").
Catching the exception:
- Use try: and except ConnectionFailedError as e: to handle only this specific error.
- Inside the except block, access e.host, e.port, and str(e) to get details.
Example flow:
- Try to connect to a server.
- If connection fails, raise ConnectionFailedError with the host and port.
- In the calling code, catch ConnectionFailedError and log the host and port for debugging.
๐งฉ Why This Matters for Engineers
- Debugging speed: When you see ConnectionFailedError, you immediately know it's a network issue, not a logic bug.
- Error propagation: You can add context (like hostname) that helps trace the failure back to its source.
- Code maintainability: Other engineers reading your code understand exactly what failed without digging into implementation details.
- Separation of concerns: Network-related errors are handled separately from other exception types.
โ Best Practices for Custom Exceptions
- Keep the exception name descriptive and specific to the failure type.
- Include only relevant attributes that help diagnose the issue.
- Always call super().init() to ensure the base exception works correctly.
- Document your custom exception in the class docstring so others know when to raise and catch it.
- Avoid overusing custom exceptionsโuse them only when a built-in exception doesn't capture the needed context.
๐ Final Thought
Defining a ConnectionFailedError is a simple but powerful way to make your error handling more expressive. It turns a vague failure into a clear, actionable signal. As you build more complex systems, custom exceptions become an essential tool for writing robust, debuggable code.
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.
A ConnectionFailedError is a custom exception class that engineers define to handle network connection failures in a clear and specific way.
๐ข Example 1: Basic ConnectionFailedError class definition
This example shows the simplest way to define a custom exception by inheriting from Python's built-in Exception class.
class ConnectionFailedError(Exception):
pass
๐ค Output: No output (class definition only)
๐ก Example 2: Raising a ConnectionFailedError
This example demonstrates how to raise the custom exception when a connection attempt fails.
class ConnectionFailedError(Exception):
pass
def connect_to_server(address):
raise ConnectionFailedError(f"Cannot connect to {address}")
connect_to_server("192.168.1.100")
๐ค Output: Traceback (most recent call last): ... ConnectionFailedError: Cannot connect to 192.168.1.100
๐ต Example 3: Catching a ConnectionFailedError with try-except
This example shows how engineers can catch and handle the custom exception gracefully.
class ConnectionFailedError(Exception):
pass
def connect_to_server(address):
raise ConnectionFailedError(f"Cannot connect to {address}")
try:
connect_to_server("192.168.1.100")
except ConnectionFailedError as error:
print(f"Connection issue: {error}")
๐ค Output: Connection issue: Cannot connect to 192.168.1.100
๐ฃ Example 4: ConnectionFailedError with custom attributes
This example adds a status code attribute to give engineers more information about the failure.
class ConnectionFailedError(Exception):
def __init__(self, address, status_code):
self.address = address
self.status_code = status_code
message = f"Failed to connect to {address} (status: {status_code})"
super().__init__(message)
def check_server(address):
status = 503
raise ConnectionFailedError(address, status)
try:
check_server("api.example.com")
except ConnectionFailedError as error:
print(f"Error: {error}")
print(f"Server: {error.address}, Status: {error.status_code}")
๐ค Output: Error: Failed to connect to api.example.com (status: 503)
Server: api.example.com, Status: 503
๐ด Example 5: Practical retry logic with ConnectionFailedError
This example shows how engineers can implement a retry mechanism when a connection fails.
import time
class ConnectionFailedError(Exception):
pass
def attempt_connection(server_name):
import random
if random.randint(1, 3) == 1:
print(f"Connected to {server_name}")
return True
else:
raise ConnectionFailedError(f"Could not reach {server_name}")
def connect_with_retry(server_name, max_retries=3):
for attempt in range(1, max_retries + 1):
try:
return attempt_connection(server_name)
except ConnectionFailedError as error:
print(f"Attempt {attempt} failed: {error}")
if attempt < max_retries:
time.sleep(1)
print("All connection attempts failed")
return False
connect_with_retry("database.internal")
๐ค Output: Attempt 1 failed: Could not reach database.internal
Attempt 2 failed: Could not reach database.internal
Connected to database.internal
Comparison Table
| Feature | Built-in Exception |
Custom ConnectionFailedError |
|---|---|---|
| Specificity | Generic error | Clear connection failure intent |
| Readability | Vague message | Self-documenting class name |
| Catch precision | Catches all errors | Catches only connection issues |
| Custom attributes | Not supported | Can add address, status code, etc. |
| Debugging value | Low | High for network engineers |