# Ganicas Utils
[](https://www.python.org/downloads/)
[](LICENSE)
[](https://github.com/ganicas/ganicas_utils)
**Ganicas Utils** is an internal Python package providing structured logging utilities and middleware for Flask and FastAPI applications. Built on top of [structlog](https://www.structlog.org/), it enables production-ready, context-aware logging with minimal configuration.
---
## 📋 Table of Contents
- [Features](#-features)
- [Installation](#-installation)
- [Quick Start](#-quick-start)
- [Structured Logging](#-structured-logging)
- [Basic Configuration](#basic-configuration)
- [Production Configuration](#production-configuration)
- [Middleware](#-middleware)
- [Flask Middleware](#flask-middleware)
- [FastAPI Middleware](#fastapi-middleware)
- [Request Logging Middleware](#request-logging-middleware)
- [Why Structured Logging?](#-why-structured-logging)
- [Development](#-development)
- [License](#-license)
---
## ✨ Features
- **Structured Logging**: JSON-formatted logs for easy parsing by log aggregation tools (ELK, Datadog, Grafana Loki)
- **Context Management**: Automatic request context binding (request_id, IP, user_agent, etc.)
- **Flask & FastAPI Support**: Ready-to-use middleware for both frameworks
- **Advanced Request Logging**: Comprehensive ASGI middleware with:
- Automatic request/response logging
- Sensitive header sanitization
- Slow request detection
- Sampling for high-traffic endpoints
- Exception tracking with full context
- Distributed tracing support (traceparent header)
- **Production Ready**: Battle-tested with 99% code coverage
---
## 📦 Installation
```bash
pip install ganicas-package
```
Or with Poetry:
```bash
poetry add ganicas-package
```
---
## 🚀 Quick Start
### Basic Configuration
Replace `logger = logging.getLogger(__name__)` with `logger = structlog.get_logger(__name__)`:
```python
from ganicas_utils.logging import LoggingConfigurator
from ganicas_utils.config import Config
import structlog
config = Config()
LoggingConfigurator(
service_name=config.APP_NAME,
log_level='INFO',
setup_logging_dict=True
).configure_structlog(
formatter='plain_console',
formatter_std_lib='plain_console'
)
logger = structlog.get_logger(__name__)
logger.info("Application started", version="1.0.0", environment="production")
```

---
## 📊 Structured Logging
### Production Configuration
For production environments, use JSON formatting for machine-readable logs:
```python
from ganicas_utils.logging import LoggingConfigurator
from ganicas_utils.config import Config
import structlog
config = Config()
LoggingConfigurator(
service_name=config.APP_NAME,
log_level='INFO',
setup_logging_dict=True
).configure_structlog(
formatter='json_formatter',
formatter_std_lib='json_formatter'
)
logger = structlog.get_logger(__name__)
logger.info("User login", user_id=12345, ip_address="192.168.1.1")
logger.warning("High memory usage", memory_percent=85.5, threshold=80)
logger.error("Database connection failed", db_host="localhost", error_code="CONN_REFUSED")
try:
result = 1 / 0
except ZeroDivisionError:
logger.exception("Division by zero error", operation="calculate_ratio")
```

---
## 🔧 Middleware
### Flask Middleware
The `FlaskRequestContextMiddleware` automatically adds request context to all logs:
```python
import uuid
from flask import Flask
from ganicas_utils.logging import LoggingConfigurator
from ganicas_utils.logging.middlewares import FlaskRequestContextMiddleware
from ganicas_utils.config import Config
import structlog
config = Config()
LoggingConfigurator(
service_name=config.APP_NAME,
log_level="INFO",
setup_logging_dict=True,
).configure_structlog(formatter='json_formatter', formatter_std_lib='json_formatter')
logger = structlog.get_logger(__name__)
app = Flask(__name__)
app.wsgi_app = FlaskRequestContextMiddleware(app.wsgi_app)
@app.route("/")
def home():
logger.info("Processing request") # Automatically includes request_id, method, path
return "Hello, World!"
if __name__ == "__main__":
app.run()
```

**Automatic context injection:**
- `request_id` - Unique identifier for each request
- `request_method` - HTTP method (GET, POST, etc.)
- `request_path` - Request URL path
---
### FastAPI Middleware
#### Basic Context Middleware
For simple request context binding, use `FastAPIRequestContextMiddleware`:
```python
from fastapi import FastAPI
from ganicas_utils.logging import LoggingConfigurator
from ganicas_utils.logging.middlewares import FastAPIRequestContextMiddleware
from ganicas_utils.config import Config
import structlog
config = Config()
LoggingConfigurator(
service_name=config.APP_NAME,
log_level="INFO",
setup_logging_dict=True,
).configure_structlog(formatter='json_formatter', formatter_std_lib='json_formatter')
logger = structlog.get_logger(__name__)
app = FastAPI()
app.add_middleware(FastAPIRequestContextMiddleware)
@app.get("/")
async def root():
logger.info("Processing request") # Automatically includes request context
return {"message": "Hello World"}
```

---
### Request Logging Middleware
For production-grade request/response logging with advanced features, use `RequestLoggingMiddleware`:
```python
from fastapi import FastAPI
from ganicas_utils.logging import LoggingConfigurator
from ganicas_utils.logging.middlewares import RequestLoggingMiddleware
import structlog
LoggingConfigurator(
service_name="my-api",
log_level="INFO",
setup_logging_dict=True,
).configure_structlog(formatter='json_formatter', formatter_std_lib='json_formatter')
app = FastAPI()
# Add comprehensive request logging
app.add_middleware(
RequestLoggingMiddleware,
slow_request_threshold_ms=1000, # Warn on requests > 1s
propagate_request_id=True, # Add request_id to response headers
skip_paths={"/healthz", "/metrics"}, # Don't log health checks
sample_2xx_rate=0.1, # Sample 10% of successful requests
)
@app.get("/api/users/{user_id}")
async def get_user(user_id: int):
return {"user_id": user_id, "name": "John Doe"}
```
#### Features
**Automatic Logging:**
- `request.start` - Logs when request begins
- `request.end` - Logs when request completes (with status, duration, size)
- `request.exception` - Logs unhandled exceptions with full traceback
**Logged Information:**
- Request: method, path, query params, client IP, user agent, content type/length
- Response: status code, size, content type, duration
- Headers: Sanitized request/response headers (for 4xx/5xx errors)
- Performance: Request duration, slow request detection
**Security:**
- Automatic sanitization of sensitive headers (`Authorization`, `Cookie`, `X-API-Key`)
- Authorization header preserves scheme: `Bearer ***` instead of exposing tokens
- No request/response body logging (only sizes)
**Performance Optimization:**
- Skip logging for health checks and metrics endpoints
- Sample successful requests to reduce log volume
- Skip OPTIONS requests
- Configurable path prefixes to skip
**Distributed Tracing:**
- Supports W3C `traceparent` header
- Falls back to `x-request-id` or `x-amzn-trace-id`
- Propagates request_id to response headers
#### Configuration Options
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `logger` | `structlog.BoundLoggerBase` | `structlog.get_logger("http")` | Custom logger instance |
| `slow_request_threshold_ms` | `int` | `None` | Threshold in ms to flag slow requests |
| `propagate_request_id` | `bool` | `True` | Add `x-request-id` to response headers |
| `skip_paths` | `set[str]` | `{"/healthz", "/metrics"}` | Exact paths to skip logging |
| `skip_prefixes` | `tuple[str, ...]` | `("/metrics",)` | Path prefixes to skip logging |
| `sample_2xx_rate` | `float` | `None` | Sample rate for 2xx/3xx responses (0.0-1.0) |
#### Example Logs
**Successful Request:**
```json
{
"event": "request.end",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"method": "GET",
"path": "/api/users/123",
"status_code": 200,
"duration_ms": 45,
"response_size": 256,
"client_ip": "192.168.1.100",
"user_agent": "Mozilla/5.0...",
"level": "info"
}
```
**Slow Request Warning:**
```json
{
"event": "request.end",
"request_id": "550e8400-e29b-41d4-a716-446655440001",
"method": "POST",
"path": "/api/process",
"status_code": 200,
"duration_ms": 1523,
"slow_request": true,
"slow_threshold_ms": 1000,
"level": "warning"
}
```
**Error with Sanitized Headers:**
```json
{
"event": "request.end",
"request_id": "550e8400-e29b-41d4-a716-446655440002",
"method": "POST",
"path": "/api/login",
"status_code": 401,
"duration_ms": 12,
"request_headers": {
"authorization": "Bearer ***",
"content-type": "application/json"
},
"level": "warning"
}
```
---
## 🎯 Why Structured Logging?
**Traditional logging challenges:**
- Plain text logs are hard to parse programmatically
- Difficult to filter and search in log aggregation tools
- Missing context makes debugging distributed systems challenging
**Structured logging benefits:**
- **Machine-readable**: JSON format for easy parsing by ELK, Datadog, Grafana Loki
- **Rich context**: Automatic correlation with request_id, user_id, transaction_id
- **Better filtering**: Query logs by any field (status_code, duration, user_id, etc.)
- **Observability**: Enhanced monitoring and alerting capabilities
- **Debugging**: Trace requests across microservices with distributed tracing support
**This package uses [structlog](https://www.structlog.org/)** - a powerful library that enhances Python's standard logging with better context management and flexible log formatting.
---
## 🛠️ Development
### Prerequisites
Install [Poetry](https://python-poetry.org/docs/#installation) for dependency management:
```bash
curl -sSL https://install.python-poetry.org | python3 -
```
### Setup
```bash
# Install dependencies
poetry install --with dev
# Run tests with coverage
poetry run pytest -v --cov=ganicas_utils
# Run tests with detailed output
poetry run pytest -rs --cov=ganicas_utils -s
# Run pre-commit hooks
poetry run pre-commit run --all-files
```
### Running Tests
```bash
# Run all tests
poetry run pytest
# Run specific test file
poetry run pytest tests/test_request_logging_middleware.py
# Run with coverage report
poetry run pytest --cov=ganicas_utils --cov-report=html
```
### Code Quality
This project uses:
- **pytest** for testing (99% coverage)
- **ruff** for linting and formatting
- **pre-commit** for automated checks
---
## 📄 License
Proprietary - Internal use only for Ganicas projects.
---
## 🤝 Contributing
This is an internal package. For questions or contributions, please contact the Ganicas development team.
---
## 📚 Additional Resources
- [structlog Documentation](https://www.structlog.org/en/stable/)
- [FastAPI Middleware Guide](https://fastapi.tiangolo.com/tutorial/middleware/)
- [Flask Middleware Guide](https://flask.palletsprojects.com/en/latest/api/#flask.Flask.wsgi_app)
---
**Made with ❤️ by Ganicas Team**
Raw data
{
"_id": null,
"home_page": null,
"name": "ganicas-package",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.11",
"maintainer_email": null,
"keywords": "logging, utilities, internal-package, structlog, middleware, fastapi, flask",
"author": "Ganicas",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/ce/4f/bf7aaf04d8385a1399cebd1b2d5b7769d9508312dc7ae1155b76974a9045/ganicas_package-0.2.0.tar.gz",
"platform": null,
"description": "# Ganicas Utils\n\n[](https://www.python.org/downloads/)\n[](LICENSE)\n[](https://github.com/ganicas/ganicas_utils)\n\n**Ganicas Utils** is an internal Python package providing structured logging utilities and middleware for Flask and FastAPI applications. Built on top of [structlog](https://www.structlog.org/), it enables production-ready, context-aware logging with minimal configuration.\n\n---\n\n## \ud83d\udccb Table of Contents\n\n- [Features](#-features)\n- [Installation](#-installation)\n- [Quick Start](#-quick-start)\n- [Structured Logging](#-structured-logging)\n - [Basic Configuration](#basic-configuration)\n - [Production Configuration](#production-configuration)\n- [Middleware](#-middleware)\n - [Flask Middleware](#flask-middleware)\n - [FastAPI Middleware](#fastapi-middleware)\n - [Request Logging Middleware](#request-logging-middleware)\n- [Why Structured Logging?](#-why-structured-logging)\n- [Development](#-development)\n- [License](#-license)\n\n---\n\n## \u2728 Features\n\n- **Structured Logging**: JSON-formatted logs for easy parsing by log aggregation tools (ELK, Datadog, Grafana Loki)\n- **Context Management**: Automatic request context binding (request_id, IP, user_agent, etc.)\n- **Flask & FastAPI Support**: Ready-to-use middleware for both frameworks\n- **Advanced Request Logging**: Comprehensive ASGI middleware with:\n - Automatic request/response logging\n - Sensitive header sanitization\n - Slow request detection\n - Sampling for high-traffic endpoints\n - Exception tracking with full context\n - Distributed tracing support (traceparent header)\n- **Production Ready**: Battle-tested with 99% code coverage\n\n---\n\n## \ud83d\udce6 Installation\n\n```bash\npip install ganicas-package\n```\n\nOr with Poetry:\n\n```bash\npoetry add ganicas-package\n```\n\n---\n\n## \ud83d\ude80 Quick Start\n\n### Basic Configuration\n\nReplace `logger = logging.getLogger(__name__)` with `logger = structlog.get_logger(__name__)`:\n\n```python\nfrom ganicas_utils.logging import LoggingConfigurator\nfrom ganicas_utils.config import Config\nimport structlog\n\nconfig = Config()\n\nLoggingConfigurator(\n service_name=config.APP_NAME,\n log_level='INFO',\n setup_logging_dict=True\n).configure_structlog(\n formatter='plain_console',\n formatter_std_lib='plain_console'\n)\n\nlogger = structlog.get_logger(__name__)\nlogger.info(\"Application started\", version=\"1.0.0\", environment=\"production\")\n```\n\n\n\n---\n\n## \ud83d\udcca Structured Logging\n\n### Production Configuration\n\nFor production environments, use JSON formatting for machine-readable logs:\n\n```python\nfrom ganicas_utils.logging import LoggingConfigurator\nfrom ganicas_utils.config import Config\nimport structlog\n\nconfig = Config()\n\nLoggingConfigurator(\n service_name=config.APP_NAME,\n log_level='INFO',\n setup_logging_dict=True\n).configure_structlog(\n formatter='json_formatter',\n formatter_std_lib='json_formatter'\n)\n\nlogger = structlog.get_logger(__name__)\nlogger.info(\"User login\", user_id=12345, ip_address=\"192.168.1.1\")\nlogger.warning(\"High memory usage\", memory_percent=85.5, threshold=80)\nlogger.error(\"Database connection failed\", db_host=\"localhost\", error_code=\"CONN_REFUSED\")\n\ntry:\n result = 1 / 0\nexcept ZeroDivisionError:\n logger.exception(\"Division by zero error\", operation=\"calculate_ratio\")\n```\n\n\n\n\n---\n\n## \ud83d\udd27 Middleware\n\n### Flask Middleware\n\nThe `FlaskRequestContextMiddleware` automatically adds request context to all logs:\n\n```python\nimport uuid\nfrom flask import Flask\nfrom ganicas_utils.logging import LoggingConfigurator\nfrom ganicas_utils.logging.middlewares import FlaskRequestContextMiddleware\nfrom ganicas_utils.config import Config\nimport structlog\n\nconfig = Config()\n\nLoggingConfigurator(\n service_name=config.APP_NAME,\n log_level=\"INFO\",\n setup_logging_dict=True,\n).configure_structlog(formatter='json_formatter', formatter_std_lib='json_formatter')\n\nlogger = structlog.get_logger(__name__)\n\napp = Flask(__name__)\napp.wsgi_app = FlaskRequestContextMiddleware(app.wsgi_app)\n\n@app.route(\"/\")\ndef home():\n logger.info(\"Processing request\") # Automatically includes request_id, method, path\n return \"Hello, World!\"\n\nif __name__ == \"__main__\":\n app.run()\n```\n\n\n\n**Automatic context injection:**\n- `request_id` - Unique identifier for each request\n- `request_method` - HTTP method (GET, POST, etc.)\n- `request_path` - Request URL path\n\n---\n\n### FastAPI Middleware\n\n#### Basic Context Middleware\n\nFor simple request context binding, use `FastAPIRequestContextMiddleware`:\n\n```python\nfrom fastapi import FastAPI\nfrom ganicas_utils.logging import LoggingConfigurator\nfrom ganicas_utils.logging.middlewares import FastAPIRequestContextMiddleware\nfrom ganicas_utils.config import Config\nimport structlog\n\nconfig = Config()\n\nLoggingConfigurator(\n service_name=config.APP_NAME,\n log_level=\"INFO\",\n setup_logging_dict=True,\n).configure_structlog(formatter='json_formatter', formatter_std_lib='json_formatter')\n\nlogger = structlog.get_logger(__name__)\napp = FastAPI()\napp.add_middleware(FastAPIRequestContextMiddleware)\n\n@app.get(\"/\")\nasync def root():\n logger.info(\"Processing request\") # Automatically includes request context\n return {\"message\": \"Hello World\"}\n```\n\n\n\n---\n\n### Request Logging Middleware\n\nFor production-grade request/response logging with advanced features, use `RequestLoggingMiddleware`:\n\n```python\nfrom fastapi import FastAPI\nfrom ganicas_utils.logging import LoggingConfigurator\nfrom ganicas_utils.logging.middlewares import RequestLoggingMiddleware\nimport structlog\n\nLoggingConfigurator(\n service_name=\"my-api\",\n log_level=\"INFO\",\n setup_logging_dict=True,\n).configure_structlog(formatter='json_formatter', formatter_std_lib='json_formatter')\n\napp = FastAPI()\n\n# Add comprehensive request logging\napp.add_middleware(\n RequestLoggingMiddleware,\n slow_request_threshold_ms=1000, # Warn on requests > 1s\n propagate_request_id=True, # Add request_id to response headers\n skip_paths={\"/healthz\", \"/metrics\"}, # Don't log health checks\n sample_2xx_rate=0.1, # Sample 10% of successful requests\n)\n\n@app.get(\"/api/users/{user_id}\")\nasync def get_user(user_id: int):\n return {\"user_id\": user_id, \"name\": \"John Doe\"}\n```\n\n#### Features\n\n**Automatic Logging:**\n- `request.start` - Logs when request begins\n- `request.end` - Logs when request completes (with status, duration, size)\n- `request.exception` - Logs unhandled exceptions with full traceback\n\n**Logged Information:**\n- Request: method, path, query params, client IP, user agent, content type/length\n- Response: status code, size, content type, duration\n- Headers: Sanitized request/response headers (for 4xx/5xx errors)\n- Performance: Request duration, slow request detection\n\n**Security:**\n- Automatic sanitization of sensitive headers (`Authorization`, `Cookie`, `X-API-Key`)\n- Authorization header preserves scheme: `Bearer ***` instead of exposing tokens\n- No request/response body logging (only sizes)\n\n**Performance Optimization:**\n- Skip logging for health checks and metrics endpoints\n- Sample successful requests to reduce log volume\n- Skip OPTIONS requests\n- Configurable path prefixes to skip\n\n**Distributed Tracing:**\n- Supports W3C `traceparent` header\n- Falls back to `x-request-id` or `x-amzn-trace-id`\n- Propagates request_id to response headers\n\n#### Configuration Options\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `logger` | `structlog.BoundLoggerBase` | `structlog.get_logger(\"http\")` | Custom logger instance |\n| `slow_request_threshold_ms` | `int` | `None` | Threshold in ms to flag slow requests |\n| `propagate_request_id` | `bool` | `True` | Add `x-request-id` to response headers |\n| `skip_paths` | `set[str]` | `{\"/healthz\", \"/metrics\"}` | Exact paths to skip logging |\n| `skip_prefixes` | `tuple[str, ...]` | `(\"/metrics\",)` | Path prefixes to skip logging |\n| `sample_2xx_rate` | `float` | `None` | Sample rate for 2xx/3xx responses (0.0-1.0) |\n\n#### Example Logs\n\n**Successful Request:**\n```json\n{\n \"event\": \"request.end\",\n \"request_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"method\": \"GET\",\n \"path\": \"/api/users/123\",\n \"status_code\": 200,\n \"duration_ms\": 45,\n \"response_size\": 256,\n \"client_ip\": \"192.168.1.100\",\n \"user_agent\": \"Mozilla/5.0...\",\n \"level\": \"info\"\n}\n```\n\n**Slow Request Warning:**\n```json\n{\n \"event\": \"request.end\",\n \"request_id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"method\": \"POST\",\n \"path\": \"/api/process\",\n \"status_code\": 200,\n \"duration_ms\": 1523,\n \"slow_request\": true,\n \"slow_threshold_ms\": 1000,\n \"level\": \"warning\"\n}\n```\n\n**Error with Sanitized Headers:**\n```json\n{\n \"event\": \"request.end\",\n \"request_id\": \"550e8400-e29b-41d4-a716-446655440002\",\n \"method\": \"POST\",\n \"path\": \"/api/login\",\n \"status_code\": 401,\n \"duration_ms\": 12,\n \"request_headers\": {\n \"authorization\": \"Bearer ***\",\n \"content-type\": \"application/json\"\n },\n \"level\": \"warning\"\n}\n```\n\n---\n\n## \ud83c\udfaf Why Structured Logging?\n\n**Traditional logging challenges:**\n- Plain text logs are hard to parse programmatically\n- Difficult to filter and search in log aggregation tools\n- Missing context makes debugging distributed systems challenging\n\n**Structured logging benefits:**\n- **Machine-readable**: JSON format for easy parsing by ELK, Datadog, Grafana Loki\n- **Rich context**: Automatic correlation with request_id, user_id, transaction_id\n- **Better filtering**: Query logs by any field (status_code, duration, user_id, etc.)\n- **Observability**: Enhanced monitoring and alerting capabilities\n- **Debugging**: Trace requests across microservices with distributed tracing support\n\n**This package uses [structlog](https://www.structlog.org/)** - a powerful library that enhances Python's standard logging with better context management and flexible log formatting.\n\n\n---\n\n## \ud83d\udee0\ufe0f Development\n\n### Prerequisites\n\nInstall [Poetry](https://python-poetry.org/docs/#installation) for dependency management:\n\n```bash\ncurl -sSL https://install.python-poetry.org | python3 -\n```\n\n### Setup\n\n```bash\n# Install dependencies\npoetry install --with dev\n\n# Run tests with coverage\npoetry run pytest -v --cov=ganicas_utils\n\n# Run tests with detailed output\npoetry run pytest -rs --cov=ganicas_utils -s\n\n# Run pre-commit hooks\npoetry run pre-commit run --all-files\n```\n\n### Running Tests\n\n```bash\n# Run all tests\npoetry run pytest\n\n# Run specific test file\npoetry run pytest tests/test_request_logging_middleware.py\n\n# Run with coverage report\npoetry run pytest --cov=ganicas_utils --cov-report=html\n```\n\n### Code Quality\n\nThis project uses:\n- **pytest** for testing (99% coverage)\n- **ruff** for linting and formatting\n- **pre-commit** for automated checks\n\n---\n\n## \ud83d\udcc4 License\n\nProprietary - Internal use only for Ganicas projects.\n\n---\n\n## \ud83e\udd1d Contributing\n\nThis is an internal package. For questions or contributions, please contact the Ganicas development team.\n\n---\n\n## \ud83d\udcda Additional Resources\n\n- [structlog Documentation](https://www.structlog.org/en/stable/)\n- [FastAPI Middleware Guide](https://fastapi.tiangolo.com/tutorial/middleware/)\n- [Flask Middleware Guide](https://flask.palletsprojects.com/en/latest/api/#flask.Flask.wsgi_app)\n\n---\n\n**Made with \u2764\ufe0f by Ganicas Team**\n",
"bugtrack_url": null,
"license": null,
"summary": "Ganicas internal Python package for structured logging and utilities.",
"version": "0.2.0",
"project_urls": null,
"split_keywords": [
"logging",
" utilities",
" internal-package",
" structlog",
" middleware",
" fastapi",
" flask"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "48a660b54bfd632666dc4b85cc59b53c2d517355f2cc6ff755b153bb0497713a",
"md5": "c7227631b22a86db4970ab1a51cbb977",
"sha256": "6a879efd18a1a02aa0527ba1e203a438f713b77a34cda5b87911ac38942f4096"
},
"downloads": -1,
"filename": "ganicas_package-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c7227631b22a86db4970ab1a51cbb977",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.11",
"size": 11540,
"upload_time": "2025-10-11T18:47:53",
"upload_time_iso_8601": "2025-10-11T18:47:53.122058Z",
"url": "https://files.pythonhosted.org/packages/48/a6/60b54bfd632666dc4b85cc59b53c2d517355f2cc6ff755b153bb0497713a/ganicas_package-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "ce4fbf7aaf04d8385a1399cebd1b2d5b7769d9508312dc7ae1155b76974a9045",
"md5": "d8675d7bd7956db97bc73e42b1b490a1",
"sha256": "f0b17347f4825df5450a9bf11118b551be00b14b8a8bfd284c2175f97c7153b2"
},
"downloads": -1,
"filename": "ganicas_package-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "d8675d7bd7956db97bc73e42b1b490a1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.11",
"size": 13720,
"upload_time": "2025-10-11T18:47:54",
"upload_time_iso_8601": "2025-10-11T18:47:54.144532Z",
"url": "https://files.pythonhosted.org/packages/ce/4f/bf7aaf04d8385a1399cebd1b2d5b7769d9508312dc7ae1155b76974a9045/ganicas_package-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-11 18:47:54",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "ganicas-package"
}