# auditry
A clean, framework-agnostic observability middleware for FastAPI and Quart that provides comprehensive request/response logging, correlation ID tracking, business event extraction, and sensitive data redaction.
[](https://badge.fury.io/py/auditry)
[](https://pypi.org/project/auditry/)
[](https://opensource.org/licenses/MIT)
## Installation
### For FastAPI
```bash
pip install auditry[fastapi]
```
### For Quart
```bash
pip install auditry[quart]
```
### For both frameworks
```bash
pip install auditry[all]
```
## Quick Start
### FastAPI
```python
from fastapi import FastAPI
from auditry import configure_logging, ObservabilityConfig, get_logger
from auditry.fastapi import create_middleware
# Configure structured logging at startup
configure_logging(level="INFO")
app = FastAPI()
# Add observability middleware (single line!)
app = create_middleware(
app,
config=ObservabilityConfig(service_name="my-service")
)
logger = get_logger(__name__)
@app.get("/")
async def root():
logger.info("Hello World")
return {"message": "Hello World"}
```
### Quart
```python
from quart import Quart
from auditry import configure_logging, ObservabilityConfig, get_logger
from auditry.quart import create_middleware
# Configure structured logging at startup
configure_logging(level="INFO")
app = Quart(__name__)
# Add observability middleware (single line!)
app = create_middleware(
app,
config=ObservabilityConfig(service_name="my-service")
)
logger = get_logger(__name__)
@app.route("/")
async def root():
logger.info("Hello World")
return {"message": "Hello World"}
```
## Configuration
### Required Configuration
```python
config = ObservabilityConfig(
service_name="your-service-name", # REQUIRED
)
```
**Note:** The `service_name` is required and must be provided. This ensures all services have meaningful names in logs rather than generic defaults.
### Full Configuration Options
```python
config = ObservabilityConfig(
# REQUIRED: Service name for log filtering (no default)
service_name="my-service-name",
# Correlation ID header name (default: X-Correlation-ID)
# Use this if your org uses a different header, such as X-Request-ID
correlation_id_header="X-Correlation-ID",
# Maximum request/response body size to log (default: 10KB)
payload_size_limit=10_240,
# Additional sensitive field patterns to redact
additional_redaction_patterns=["internal_id", "employee_ssn"],
# Whether to log request headers (default: True)
log_request_headers=True,
# Whether to log response headers (default: False)
log_response_headers=False,
# Whether to log query parameters (default: True)
log_query_params=True,
# Whether to log request bodies for all endpoints (default: True)
# Set to False for applications handling sensitive data
log_request_body=True,
# Whether to log response bodies for all endpoints (default: True)
# Set to False for applications returning sensitive data
log_response_body=True,
)
# For FastAPI:
from auditry.fastapi import create_middleware
app = create_middleware(app, config)
# For Quart:
from auditry.quart import create_middleware
app = create_middleware(app, config)
```
## Correlation IDs
Correlation IDs are automatically handled:
- **Incoming requests**: Extracts from `X-Correlation-ID` header (or your custom header)
- **Generated if missing**: Creates a new UUID if no correlation ID provided
- **Added to response**: Returns the correlation ID in the response header
- **Included in logs**: Automatically included in all structured logs
### Using Correlation IDs in Your Code
```python
from auditry import get_logger, get_correlation_id
logger = get_logger(__name__)
@app.get("/users/{user_id}")
async def get_user(user_id: str):
# Correlation ID is automatically available
correlation_id = get_correlation_id()
# All logs automatically include the correlation ID
logger.info(f"Fetching user {user_id}")
return {"user_id": user_id, "correlation_id": correlation_id}
```
### Propagating to Downstream Services
```python
import httpx
from auditry import get_correlation_id
@app.get("/proxy")
async def proxy_request():
# Get the current correlation ID
correlation_id = get_correlation_id()
# Pass it to downstream services
async with httpx.AsyncClient() as client:
response = await client.get(
"https://downstream-service.com/api/data",
headers={"X-Correlation-ID": correlation_id} # Use your org's header name
)
return response.json()
```
## User Tracking
The middleware automatically extracts user IDs from your authentication system and includes them in logs.
### FastAPI User Tracking
```python
from fastapi import Request, Depends
async def get_current_user(request: Request):
# Your authentication logic here
user_id = "user-123"
# Set user_id in request state for auditry to capture
request.state.user_id = user_id
# OR if you have a user object:
# request.state.user = user_object # Must have .id or .user_id attribute
return user_id
@app.get("/protected")
async def protected_route(user_id: str = Depends(get_current_user)):
return {"message": "Protected content"}
```
### Quart User Tracking
```python
from quart import request
@app.before_request
async def authenticate():
# Your authentication logic here
# Set user on request for auditry to capture
request.current_user = AuthenticatedUser(id="user-123")
# OR use g.user or g.user_id
# from quart import g
# g.user_id = "user-123"
```
The middleware automatically finds the user ID from these locations:
- **FastAPI**: `request.state.user_id` or `request.state.user.id`
- **Quart**: `request.current_user.id`, `g.user.id`, or `g.user_id`
## Business Event Tagging (For Analytics)
Tag specific endpoints as "business events" to make analytics queries easier for your sales/product teams.
### Configuration
Tag endpoints in your middleware config - zero code changes needed in your actual endpoints:
```python
from auditry import ObservabilityConfig, BusinessEventConfig
config = ObservabilityConfig(
service_name="my-service-name",
# Define which endpoints to tag for analytics
business_events={
"POST /workflows": BusinessEventConfig(
event_type="workflow.created",
extract_from_request=["file_id"], # Pull file_id from request body
extract_from_response=["id"], # Pull workflow id from response
),
"DELETE /workflows/{workflow_id}": BusinessEventConfig(
event_type="workflow.deleted",
extract_from_path=["workflow_id"], # Pull workflow_id from URL path
),
},
)
# Apply to your framework
from auditry.fastapi import create_middleware # or auditry.quart
app = create_middleware(app, config)
```
### Log Output with Event Tags
Regular log (no tagging):
```json
{
"service": "my-service-name",
"message": "Request completed: POST /workflows - Status: 201",
"request": {...},
"response": {...}
}
```
Tagged business event log:
```json
{
"service": "my-service-name",
"message": "Request completed: POST /workflows - Status: 201",
"event_type": "workflow.created", // ← Filterable in log platform
"business_context": {
"file_id": "file_123", // ← From request body
"id": "workflow_789" // ← From response body
},
"request": {...},
"response": {...}
}
```
### Supported Extract Locations
- `extract_from_request`: Fields from request JSON body
- `extract_from_response`: Fields from response JSON body
- `extract_from_path`: Parameters from URL path (e.g., `/workflows/{workflow_id}`)
## Log Output
All logs are structured JSON, ready for log aggregators:
```json
{
"timestamp": "2025-10-28T12:34:56.789012+00:00",
"level": "INFO",
"service": "my-service-name",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "Request completed: POST /workflows - Status: 201 - Duration: 45.23ms",
"request": {
"method": "POST",
"path": "/workflows",
"query_params": {},
"headers": {"user-agent": "curl/7.64.1", "authorization": "[REDACTED]"},
"body": {"name": "My Workflow", "password": "[REDACTED]"},
"user_id": "user_12345"
},
"response": {
"status_code": 201,
"duration_ms": 45.23,
"body": {"id": "workflow_789", "name": "My Workflow"}
}
}
```
## Sensitive Data Handling
### Automatic Redaction
Automatically redacts these sensitive field patterns in all logged requests/responses:
- `password`
- `token`
- `api_key` / `apikey`
- `secret`
- `authorization`
- `ssn` / `social_security_number`
- `credit_card` / `creditcard`
- `x-api-key`
Add custom patterns via configuration:
```python
config = ObservabilityConfig(
service_name="my-service-name",
additional_redaction_patterns=["internal_token", "employee_id"],
)
```
### Disabling Body Logging (Application-Wide)
For applications handling sensitive data, you can disable logging of request and/or response bodies across the entire application:
```python
config = ObservabilityConfig(
service_name="my-service-name",
# Disable request body logging for all endpoints
log_request_body=False,
# Disable response body logging for all endpoints
log_response_body=False,
)
```
When body logging is disabled, logs will show `[BODY_LOGGING_DISABLED]` instead of the actual content, while still logging metadata like headers, status codes, and timing information.
## Best Practices
### 1. Configure Logging Early
Call `configure_logging()` at application startup, before any other code:
```python
from auditry import configure_logging
# First thing in your app
configure_logging(level="INFO")
app = FastAPI()
# ... rest of your app
```
### 2. Use Structured Logging
Always use `get_logger(__name__)` instead of standard Python logging:
```python
from auditry import get_logger
logger = get_logger(__name__)
# Good - structured with correlation ID
logger.info("Processing payment", amount=100.50, currency="USD")
# Bad - loses structured data
import logging
logging.info("Processing payment")
```
### 3. Propagate Correlation IDs
When calling downstream services, always pass the correlation ID:
```python
from auditry import get_correlation_id
correlation_id = get_correlation_id()
headers = {"X-Correlation-ID": correlation_id} # Use your org's header name
response = await client.get(url, headers=headers)
```
### 4. Customize for Your Organization
Match your org's conventions:
```python
config = ObservabilityConfig(
service_name="my-service-name",
correlation_id_header="X-Request-ID", # If your org uses this header instead
additional_redaction_patterns=["ssn", "tax_id"], # Your sensitive fields
)
```
## Example Output: Success vs Failure
### Successful Request
```json
{
"level": "INFO",
"service": "my-service-name",
"correlation_id": "abc-123",
"message": "Request completed: POST /workflows - Status: 201 - Duration: 45ms",
"request": {...},
"response": {...}
}
```
### Failed Request
```json
{
"level": "ERROR",
"service": "my-service-name",
"correlation_id": "abc-123",
"message": "Request failed: POST /workflows - Error: ValueError: Invalid name",
"request": {...},
"exception_type": "ValueError",
"exception_message": "Invalid name",
"execution_duration_ms": 12.34
}
```
## License
MIT License - see [LICENSE](LICENSE) file for details.
## Contributing
Contributions welcome! Please submit a Pull Request.
## Support
For issues and questions: [GitHub Issues](https://github.com/lst4rk/auditry/issues)
## Author
**Liv Stark** - [livstark.work@gmail.com](mailto:livstark.work@gmail.com)
Raw data
{
"_id": null,
"home_page": null,
"name": "auditry",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "fastapi, quart, observability, logging, middleware, correlation-id, redaction",
"author": null,
"author_email": "Liv Stark <livstark.work@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/1e/0f/f64c0922dfbd5dbf7289fd4afbb37650bc9fba0d04ee6fbfd318b6f4c7d4/auditry-0.2.1.tar.gz",
"platform": null,
"description": "# auditry\n\nA clean, framework-agnostic observability middleware for FastAPI and Quart that provides comprehensive request/response logging, correlation ID tracking, business event extraction, and sensitive data redaction.\n\n[](https://badge.fury.io/py/auditry)\n[](https://pypi.org/project/auditry/)\n[](https://opensource.org/licenses/MIT)\n\n## Installation\n\n### For FastAPI\n\n```bash\npip install auditry[fastapi]\n```\n\n### For Quart\n\n```bash\npip install auditry[quart]\n```\n\n### For both frameworks\n\n```bash\npip install auditry[all]\n```\n\n## Quick Start\n\n### FastAPI\n\n```python\nfrom fastapi import FastAPI\nfrom auditry import configure_logging, ObservabilityConfig, get_logger\nfrom auditry.fastapi import create_middleware\n\n# Configure structured logging at startup\nconfigure_logging(level=\"INFO\")\n\napp = FastAPI()\n\n# Add observability middleware (single line!)\napp = create_middleware(\n app,\n config=ObservabilityConfig(service_name=\"my-service\")\n)\n\nlogger = get_logger(__name__)\n\n@app.get(\"/\")\nasync def root():\n logger.info(\"Hello World\")\n return {\"message\": \"Hello World\"}\n```\n\n### Quart\n\n```python\nfrom quart import Quart\nfrom auditry import configure_logging, ObservabilityConfig, get_logger\nfrom auditry.quart import create_middleware\n\n# Configure structured logging at startup\nconfigure_logging(level=\"INFO\")\n\napp = Quart(__name__)\n\n# Add observability middleware (single line!)\napp = create_middleware(\n app,\n config=ObservabilityConfig(service_name=\"my-service\")\n)\n\nlogger = get_logger(__name__)\n\n@app.route(\"/\")\nasync def root():\n logger.info(\"Hello World\")\n return {\"message\": \"Hello World\"}\n```\n\n## Configuration\n\n### Required Configuration\n\n```python\nconfig = ObservabilityConfig(\n service_name=\"your-service-name\", # REQUIRED\n)\n```\n\n**Note:** The `service_name` is required and must be provided. This ensures all services have meaningful names in logs rather than generic defaults.\n\n### Full Configuration Options\n\n```python\nconfig = ObservabilityConfig(\n # REQUIRED: Service name for log filtering (no default)\n service_name=\"my-service-name\",\n\n # Correlation ID header name (default: X-Correlation-ID)\n # Use this if your org uses a different header, such as X-Request-ID\n correlation_id_header=\"X-Correlation-ID\",\n\n # Maximum request/response body size to log (default: 10KB)\n payload_size_limit=10_240,\n\n # Additional sensitive field patterns to redact\n additional_redaction_patterns=[\"internal_id\", \"employee_ssn\"],\n\n # Whether to log request headers (default: True)\n log_request_headers=True,\n\n # Whether to log response headers (default: False)\n log_response_headers=False,\n\n # Whether to log query parameters (default: True)\n log_query_params=True,\n\n # Whether to log request bodies for all endpoints (default: True)\n # Set to False for applications handling sensitive data\n log_request_body=True,\n\n # Whether to log response bodies for all endpoints (default: True)\n # Set to False for applications returning sensitive data\n log_response_body=True,\n)\n\n# For FastAPI:\nfrom auditry.fastapi import create_middleware\napp = create_middleware(app, config)\n\n# For Quart:\nfrom auditry.quart import create_middleware\napp = create_middleware(app, config)\n```\n\n## Correlation IDs\n\nCorrelation IDs are automatically handled:\n\n- **Incoming requests**: Extracts from `X-Correlation-ID` header (or your custom header)\n- **Generated if missing**: Creates a new UUID if no correlation ID provided\n- **Added to response**: Returns the correlation ID in the response header\n- **Included in logs**: Automatically included in all structured logs\n\n### Using Correlation IDs in Your Code\n\n```python\nfrom auditry import get_logger, get_correlation_id\n\nlogger = get_logger(__name__)\n\n@app.get(\"/users/{user_id}\")\nasync def get_user(user_id: str):\n # Correlation ID is automatically available\n correlation_id = get_correlation_id()\n\n # All logs automatically include the correlation ID\n logger.info(f\"Fetching user {user_id}\")\n\n return {\"user_id\": user_id, \"correlation_id\": correlation_id}\n```\n\n### Propagating to Downstream Services\n\n```python\nimport httpx\nfrom auditry import get_correlation_id\n\n@app.get(\"/proxy\")\nasync def proxy_request():\n # Get the current correlation ID\n correlation_id = get_correlation_id()\n\n # Pass it to downstream services\n async with httpx.AsyncClient() as client:\n response = await client.get(\n \"https://downstream-service.com/api/data\",\n headers={\"X-Correlation-ID\": correlation_id} # Use your org's header name\n )\n\n return response.json()\n```\n\n## User Tracking\n\nThe middleware automatically extracts user IDs from your authentication system and includes them in logs.\n\n### FastAPI User Tracking\n\n```python\nfrom fastapi import Request, Depends\n\nasync def get_current_user(request: Request):\n # Your authentication logic here\n user_id = \"user-123\"\n\n # Set user_id in request state for auditry to capture\n request.state.user_id = user_id\n # OR if you have a user object:\n # request.state.user = user_object # Must have .id or .user_id attribute\n\n return user_id\n\n@app.get(\"/protected\")\nasync def protected_route(user_id: str = Depends(get_current_user)):\n return {\"message\": \"Protected content\"}\n```\n\n### Quart User Tracking\n\n```python\nfrom quart import request\n\n@app.before_request\nasync def authenticate():\n # Your authentication logic here\n\n # Set user on request for auditry to capture\n request.current_user = AuthenticatedUser(id=\"user-123\")\n # OR use g.user or g.user_id\n # from quart import g\n # g.user_id = \"user-123\"\n```\n\nThe middleware automatically finds the user ID from these locations:\n- **FastAPI**: `request.state.user_id` or `request.state.user.id`\n- **Quart**: `request.current_user.id`, `g.user.id`, or `g.user_id`\n\n## Business Event Tagging (For Analytics)\n\nTag specific endpoints as \"business events\" to make analytics queries easier for your sales/product teams.\n\n### Configuration\n\nTag endpoints in your middleware config - zero code changes needed in your actual endpoints:\n\n```python\nfrom auditry import ObservabilityConfig, BusinessEventConfig\n\nconfig = ObservabilityConfig(\n service_name=\"my-service-name\",\n\n # Define which endpoints to tag for analytics\n business_events={\n \"POST /workflows\": BusinessEventConfig(\n event_type=\"workflow.created\",\n extract_from_request=[\"file_id\"], # Pull file_id from request body\n extract_from_response=[\"id\"], # Pull workflow id from response\n ),\n \"DELETE /workflows/{workflow_id}\": BusinessEventConfig(\n event_type=\"workflow.deleted\",\n extract_from_path=[\"workflow_id\"], # Pull workflow_id from URL path\n ),\n },\n)\n\n# Apply to your framework\nfrom auditry.fastapi import create_middleware # or auditry.quart\napp = create_middleware(app, config)\n```\n\n### Log Output with Event Tags\n\nRegular log (no tagging):\n```json\n{\n \"service\": \"my-service-name\",\n \"message\": \"Request completed: POST /workflows - Status: 201\",\n \"request\": {...},\n \"response\": {...}\n}\n```\n\nTagged business event log:\n```json\n{\n \"service\": \"my-service-name\",\n \"message\": \"Request completed: POST /workflows - Status: 201\",\n \"event_type\": \"workflow.created\", // \u2190 Filterable in log platform\n \"business_context\": {\n \"file_id\": \"file_123\", // \u2190 From request body\n \"id\": \"workflow_789\" // \u2190 From response body\n },\n \"request\": {...},\n \"response\": {...}\n}\n```\n\n### Supported Extract Locations\n\n- `extract_from_request`: Fields from request JSON body\n- `extract_from_response`: Fields from response JSON body \n- `extract_from_path`: Parameters from URL path (e.g., `/workflows/{workflow_id}`)\n\n## Log Output\n\nAll logs are structured JSON, ready for log aggregators:\n\n```json\n{\n \"timestamp\": \"2025-10-28T12:34:56.789012+00:00\",\n \"level\": \"INFO\",\n \"service\": \"my-service-name\",\n \"correlation_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"message\": \"Request completed: POST /workflows - Status: 201 - Duration: 45.23ms\",\n \"request\": {\n \"method\": \"POST\",\n \"path\": \"/workflows\",\n \"query_params\": {},\n \"headers\": {\"user-agent\": \"curl/7.64.1\", \"authorization\": \"[REDACTED]\"},\n \"body\": {\"name\": \"My Workflow\", \"password\": \"[REDACTED]\"},\n \"user_id\": \"user_12345\"\n },\n \"response\": {\n \"status_code\": 201,\n \"duration_ms\": 45.23,\n \"body\": {\"id\": \"workflow_789\", \"name\": \"My Workflow\"}\n }\n}\n```\n\n## Sensitive Data Handling\n\n### Automatic Redaction\n\nAutomatically redacts these sensitive field patterns in all logged requests/responses:\n\n- `password`\n- `token`\n- `api_key` / `apikey`\n- `secret`\n- `authorization`\n- `ssn` / `social_security_number`\n- `credit_card` / `creditcard`\n- `x-api-key`\n\nAdd custom patterns via configuration:\n\n```python\nconfig = ObservabilityConfig(\n service_name=\"my-service-name\",\n additional_redaction_patterns=[\"internal_token\", \"employee_id\"],\n)\n```\n\n### Disabling Body Logging (Application-Wide)\n\nFor applications handling sensitive data, you can disable logging of request and/or response bodies across the entire application:\n\n```python\nconfig = ObservabilityConfig(\n service_name=\"my-service-name\",\n\n # Disable request body logging for all endpoints\n log_request_body=False,\n\n # Disable response body logging for all endpoints\n log_response_body=False,\n)\n```\n\nWhen body logging is disabled, logs will show `[BODY_LOGGING_DISABLED]` instead of the actual content, while still logging metadata like headers, status codes, and timing information.\n## Best Practices\n\n### 1. Configure Logging Early\n\nCall `configure_logging()` at application startup, before any other code:\n\n```python\nfrom auditry import configure_logging\n\n# First thing in your app\nconfigure_logging(level=\"INFO\")\n\napp = FastAPI()\n# ... rest of your app\n```\n\n### 2. Use Structured Logging\n\nAlways use `get_logger(__name__)` instead of standard Python logging:\n\n```python\nfrom auditry import get_logger\n\nlogger = get_logger(__name__)\n\n# Good - structured with correlation ID\nlogger.info(\"Processing payment\", amount=100.50, currency=\"USD\")\n\n# Bad - loses structured data\nimport logging\nlogging.info(\"Processing payment\")\n```\n\n### 3. Propagate Correlation IDs\n\nWhen calling downstream services, always pass the correlation ID:\n\n```python\nfrom auditry import get_correlation_id\n\ncorrelation_id = get_correlation_id()\nheaders = {\"X-Correlation-ID\": correlation_id} # Use your org's header name\nresponse = await client.get(url, headers=headers)\n```\n\n### 4. Customize for Your Organization\n\nMatch your org's conventions:\n\n```python\nconfig = ObservabilityConfig(\n service_name=\"my-service-name\",\n correlation_id_header=\"X-Request-ID\", # If your org uses this header instead\n additional_redaction_patterns=[\"ssn\", \"tax_id\"], # Your sensitive fields\n)\n```\n\n## Example Output: Success vs Failure\n\n### Successful Request\n\n```json\n{\n \"level\": \"INFO\",\n \"service\": \"my-service-name\",\n \"correlation_id\": \"abc-123\",\n \"message\": \"Request completed: POST /workflows - Status: 201 - Duration: 45ms\",\n \"request\": {...},\n \"response\": {...}\n}\n```\n\n### Failed Request\n\n```json\n{\n \"level\": \"ERROR\",\n \"service\": \"my-service-name\",\n \"correlation_id\": \"abc-123\",\n \"message\": \"Request failed: POST /workflows - Error: ValueError: Invalid name\",\n \"request\": {...},\n \"exception_type\": \"ValueError\",\n \"exception_message\": \"Invalid name\",\n \"execution_duration_ms\": 12.34\n}\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions welcome! Please submit a Pull Request.\n\n## Support\n\nFor issues and questions: [GitHub Issues](https://github.com/lst4rk/auditry/issues)\n\n## Author\n\n**Liv Stark** - [livstark.work@gmail.com](mailto:livstark.work@gmail.com)\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Observability middleware for FastAPI and Quart with request/response logging, correlation IDs, and sensitive data redaction",
"version": "0.2.1",
"project_urls": {
"Homepage": "https://github.com/lst4rk/auditry",
"Issues": "https://github.com/lst4rk/auditry/issues",
"Repository": "https://github.com/lst4rk/auditry"
},
"split_keywords": [
"fastapi",
" quart",
" observability",
" logging",
" middleware",
" correlation-id",
" redaction"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "c3279244ca078c1b14e0176b799784701aa59121728f7fb1e9f333a68b628cc8",
"md5": "2fee2e3ce590226fca247a4e55679db9",
"sha256": "37afc35caa99e311af29b2a59e04bcad611ae4bf8ffb6c32f16104b2fde0f8e4"
},
"downloads": -1,
"filename": "auditry-0.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2fee2e3ce590226fca247a4e55679db9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 22635,
"upload_time": "2025-10-30T15:10:28",
"upload_time_iso_8601": "2025-10-30T15:10:28.271615Z",
"url": "https://files.pythonhosted.org/packages/c3/27/9244ca078c1b14e0176b799784701aa59121728f7fb1e9f333a68b628cc8/auditry-0.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "1e0ff64c0922dfbd5dbf7289fd4afbb37650bc9fba0d04ee6fbfd318b6f4c7d4",
"md5": "f3ccd6bc767512a87cf84975406d9034",
"sha256": "be1be17f1c84773db484a08cfe1a92d681488e03b338a05acba9e72350fcd382"
},
"downloads": -1,
"filename": "auditry-0.2.1.tar.gz",
"has_sig": false,
"md5_digest": "f3ccd6bc767512a87cf84975406d9034",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 23613,
"upload_time": "2025-10-30T15:10:29",
"upload_time_iso_8601": "2025-10-30T15:10:29.602026Z",
"url": "https://files.pythonhosted.org/packages/1e/0f/f64c0922dfbd5dbf7289fd4afbb37650bc9fba0d04ee6fbfd318b6f4c7d4/auditry-0.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-30 15:10:29",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "lst4rk",
"github_project": "auditry",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "auditry"
}