Python library to keep secrets out of logs
Project description
printsafe
A Python library that prevents accidental exposure of sensitive data in logs, debug output, and string representations.
Overview
printsafe provides a Secret class that wraps sensitive values (passwords, API keys, tokens, etc.) and prevents them from being accidentally exposed through:
- String representation (
str(),print()) - Debug output (
repr()) - Logging statements
- Iteration (prevents character-by-character exposure)
The wrapped value remains fully accessible when explicitly requested, but is protected from accidental disclosure.
The library also includes an EnvVar class that extends Secret to automatically load sensitive values from environment variables.
Installation
pip install printsafe
Quick Start
from printsafe import Secret
# Wrap a sensitive value
api_key = Secret("sk-1234567890abcdef")
# Safe operations - won't expose the secret
print(api_key) # Output: [REDACTED]
print(f"API Key: {api_key}") # Output: API Key: [REDACTED]
str(api_key) # Returns: "[REDACTED]"
repr(api_key) # Returns: "[REDACTED]"
# Access the actual value when needed
actual_key = api_key.value # Returns: "sk-1234567890abcdef"
Usage Examples
Basic Usage
from printsafe import Secret
# Create a secret with default placeholder
password = Secret("my_super_secret_password")
print(password) # [REDACTED]
# Create a secret with custom placeholder
token = Secret("abc123xyz", placeholder="<HIDDEN>")
print(token) # <HIDDEN>
Environment Variables
from printsafe import EnvVar
# Load from environment variable with automatic placeholder
# Assuming API_KEY environment variable is set to "sk-12345"
api_key = EnvVar("API_KEY")
print(api_key) # [API_KEY] - uses env var name as placeholder
# With default value if environment variable is not set
debug_mode = EnvVar("DEBUG_MODE", default="false")
print(debug_mode) # [DEBUG_MODE]
print(debug_mode.value) # "false" if DEBUG_MODE not set
# With custom placeholder - overrides the default behavior
secret_token = EnvVar("SECRET_TOKEN", placeholder="<ENV_SECRET>")
print(secret_token) # <ENV_SECRET>
# Access the environment variable name
print(api_key.name) # API_KEY
Working with Different Data Types
# String secrets
api_key = Secret("sk-1234567890")
# Numeric secrets
secret_number = Secret(42)
print(secret_number) # [REDACTED]
print(secret_number.value) # 42
# Dictionary secrets
config = Secret({"database_url": "postgresql://user:pass@host/db"})
print(config) # [REDACTED]
print(config.value["database_url"]) # Access nested values
Method Delegation
The Secret class delegates method calls to the wrapped value:
secret_text = Secret("hello world")
# These methods are delegated to the wrapped string
print(secret_text.upper()) # Raises AttributeError or returns delegated result
print(secret_text.value.upper()) # "HELLO WORLD" - safe explicit access
Callable Secrets
If the wrapped value is callable, the Secret can be called directly:
def secret_function(x):
return x * 2
secret_func = Secret(secret_function)
result = secret_func(5) # Calls the wrapped function, returns 10
Comparison and Hashing
secret1 = Secret("password123")
secret2 = Secret("password123")
secret3 = Secret("different")
# Equality comparison
print(secret1 == secret2) # True
print(secret1 == secret3) # False
print(secret1 == "password123") # True
# Can be used in sets and as dict keys
secrets = {secret1, secret2} # Set with one unique secret
secret_dict = {secret1: "user1"}
Prevented Operations
secret = Secret("sensitive")
# These operations are blocked to prevent exposure:
try:
for char in secret: # Iteration blocked
print(char)
except TypeError as e:
print(e) # 'Secret' object is not iterable
API Reference
Secret(value, placeholder="[REDACTED]")
Parameters
value: The sensitive value to wrap (any type)placeholder(str, optional): Text to display instead of the actual value. Defaults to"[REDACTED]"
Attributes
value: Access the wrapped sensitive valueplaceholder: The placeholder text used for string representation
Methods
__str__(): Returns the placeholder string__repr__(): Returns the placeholder string__eq__(other): Compare with another Secret or value__hash__(): Returns hash of the wrapped value__call__(*args, **kwargs): Call the wrapped value if it's callable__getattr__(name): Delegate attribute access to wrapped value
Blocked Operations
__iter__(): RaisesTypeErrorto prevent iteration
EnvVar(name, default=None, placeholder=None)
A Secret subclass that automatically loads its value from an environment variable.
Parameters
name(str): The name of the environment variable to readdefault: Default value if environment variable is not set (default:None)placeholder(str, optional): Text to display instead of the actual value. IfNone(default), automatically uses"[{name}]"where{name}is the environment variable name. Can be explicitly set to any string to override this behavior.
Attributes
value: Access the wrapped sensitive value from the environment variableplaceholder: The placeholder text used for string representationname: The name of the environment variable
Methods
Inherits all methods from Secret class:
__str__(): Returns the placeholder string__repr__(): Returns the placeholder string__eq__(other): Compare with another Secret or value__hash__(): Returns hash of the wrapped value__call__(*args, **kwargs): Call the wrapped value if it's callable__getattr__(name): Delegate attribute access to wrapped value
Blocked Operations
__iter__(): RaisesTypeErrorto prevent iteration
Security Considerations
- The actual value is stored in memory and can be accessed via the
valueattribute - This library protects against accidental exposure, not malicious access
- Memory dumps or debugging tools may still reveal the sensitive data
- Consider additional security measures for highly sensitive applications
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file printsafe-0.2.0.tar.gz.
File metadata
- Download URL: printsafe-0.2.0.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bfe4c7d6df8c7470a25162161f4a0ed59cea30e1d4b29a137e10c95f1727424b
|
|
| MD5 |
5cf18f0757c87dd90089b7cb753dc692
|
|
| BLAKE2b-256 |
aba1afa4c9f2a2ff4cdce8328a539eba697a7b5c08dae3c98bd6a3fbeadcdc72
|
File details
Details for the file printsafe-0.2.0-py3-none-any.whl.
File metadata
- Download URL: printsafe-0.2.0-py3-none-any.whl
- Upload date:
- Size: 6.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
600c7abab9ac7d03dcc6335c9aaed014c7ce9624c460c569f469657e49fef725
|
|
| MD5 |
598b4265de13edde9ff0bbc840aca7e5
|
|
| BLAKE2b-256 |
89a753f56c690124875addf823ec19de9d93fae0a1f777ab445a7c09df6eaf2f
|