Skip to main content

OxUtils

Production-ready utilities for Django applications in the Oxiliere ecosystem.

PyPI version Python 3.12+ Django 5.0+ Tests License Code style: ruff

Features

  • 🔐 JWT Authentication - RS256 with JWKS caching
  • 📝 Structured Logging - JSON logs with automatic request tracking
  • 🔍 Audit System - Change tracking with S3 export
  • ⚙️ Celery Integration - Pre-configured task processing
  • 🛠️ Django Mixins - UUID, timestamps, user tracking
  • Custom Exceptions - Standardized API errors
  • 🎨 Context Processors - Site name and domain for templates
  • 💱 Currency Module - Multi-source exchange rates (BCC/OXR)
  • 📄 PDF Generation - WeasyPrint integration for Django
  • 🏢 Multi-Tenant - PostgreSQL schema-based isolation
  • 🔑 Permissions — Domain-oriented RBAC with named actions, AND/OR logic, groups & grants, translatable labels

Installation

pip install oxutils
uv add oxutils

Quick Start

1. Configure Django Settings

# settings.py
from oxutils.conf import UTILS_APPS, AUDIT_MIDDLEWARE

INSTALLED_APPS = [
    *UTILS_APPS,  # structlog, auditlog, celery_results
    # your apps...
]

MIDDLEWARE = [
    *AUDIT_MIDDLEWARE,  # RequestMiddleware, Auditlog
    # your middleware...
]

2. Environment Variables

OXI_SERVICE_NAME=my-service
OXI_JWT_JWKS_URL=https://auth.example.com/.well-known/jwks.json

3. Usage Examples

# JWT Authentication
from oxutils.jwt.client import verify_token
payload = verify_token(token)

# Structured Logging
import structlog
logger = structlog.get_logger(__name__)
logger.info("user_action", user_id=user_id)


# Model Mixins
from oxutils.models.base import BaseModelMixin
class Product(BaseModelMixin):  # UUID + timestamps + is_active
    name = models.CharField(max_length=255)

# Custom Exceptions
from oxutils.exceptions import NotFoundException
raise NotFoundException(detail="User not found")

# Context Processors
# settings.py
TEMPLATES = [{
    'OPTIONS': {
        'context_processors': [
            'oxutils.context.site_name_processor.site_name',
        ],
    },
}]
# Now {{ site_name }} and {{ site_domain }} are available in templates

Documentation

Core Modules

Additional Modules

  • Currency - Exchange rates management
  • PDF - PDF generation with WeasyPrint
  • Oxiliere - Multi-tenant architecture
  • Permissions - RBAC with named actions

Requirements

  • Python 3.12+
  • Django 5.0+
  • PostgreSQL (recommended)

Development

git clone https://github.com/oxiliere/oxutils.git
cd oxutils
uv sync
uv run pytest  # 201 tests passing, 4 skipped

Creating Migrations

To generate Django migrations for the audit module:

make migrations
# or
uv run make_migrations.py

See MIGRATIONS.md for detailed documentation.

Optional Dependencies

# Multi-tenant support
uv add oxutils[oxiliere]

# PDF generation
uv add oxutils[pdf]

# Development tools
uv add oxutils[dev]

Advanced Examples

JWT with Django Ninja

from ninja import NinjaAPI
from ninja.security import HttpBearer
from oxutils.jwt.client import verify_token

class JWTAuth(HttpBearer):
    def authenticate(self, request, token):
        try:
            return verify_token(token)
        except:
            return None

api = NinjaAPI(auth=JWTAuth())

@api.get("/protected")
def protected(request):
    return {"user_id": request.auth['sub']}

Audit Log Export

from oxutils.audit.export import export_logs_from_date
from datetime import datetime, timedelta

from_date = datetime.now() - timedelta(days=7)
export = export_logs_from_date(from_date=from_date)
print(f"Exported to {export.data.url}")

Currency Exchange Rates

from oxutils.currency.models import CurrencyState

# Sync rates from BCC (with OXR fallback)
state = CurrencyState.sync()

# Get latest rates
latest = CurrencyState.objects.latest()
usd_rate = latest.currencies.get(code='USD').rate
eur_rate = latest.currencies.get(code='EUR').rate

PDF Generation

from oxutils.pdf.printer import Printer
from oxutils.pdf.views import WeasyTemplateView

# Standalone PDF generation
printer = Printer(
    template_name='invoice.html',
    context={'invoice': invoice},
    stylesheets=['css/invoice.css']
)
pdf_bytes = printer.write_pdf()

# Class-based view
class InvoicePDFView(WeasyTemplateView):
    template_name = 'invoice.html'
    pdf_filename = 'invoice.pdf'
    pdf_stylesheets = ['css/invoice.css']

Multi-Tenant Setup

# settings.py
TENANT_MODEL = "oxiliere.Tenant"
MIDDLEWARE = [
    'oxutils.oxiliere.middleware.TenantMainMiddleware',
    # ...
]

Permissions (v0.5.0)

# settings.py — define named actions & scopes with translatable labels
from django.utils.translation import gettext_lazy as _

PERMISSION_PRESET = {
    "actions": {
        "orders": {
            "create":  {"implies": [],          "label": _("Create")},
            "approve": {"implies": ["create"],  "label": _("Approve")},
            "cancel":  {"implies": [],          "label": _("Cancel")},
        },
        "articles": {
            "read":    {"implies": [],          "label": _("Read")},
            "write":   {"implies": ["read"],    "label": _("Write")},
            "publish": {"implies": ["write"],   "label": _("Publish")},
        },
    },
    "roles": [{"name": "Editor", "slug": "editor"}],
    "groups": [],
    "role_grants": [
        {"role": "editor", "scope": "articles", "actions": ["write"], "context": {}},
    ],
}

# Scopes — strings or dicts with labels (recommended for frontend i18n)
ACCESS_SCOPES = [
    "articles",
    {"key": "orders", "label": _("Orders")},
]

# Controller — AND (/) and OR (|) operators
from oxutils.permissions.perms import ScopePermission

@api_controller('/orders', permissions=[ScopePermission('orders:create/approve')])
class OrderController:  # user needs create AND approve
    ...

# Frontend endpoint — translated action labels
# GET /api/access/scopes/orders/actions
# → {"scope": "orders", "actions": [
#     {"key": "create",  "label": "Créer"},
#     {"key": "approve", "label": "Approuver"},
#   ]}

# Frontend endpoint — translated scope labels
# GET /api/access/scopes
# → [
#     {"key": "articles", "label": "Articles"},
#     {"key": "orders",   "label": "Commandes"},
#   ]

License

LGPL 3.0 License - see LICENSE

Support


Made with ❤️ by Oxiliere

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oxutils-0.5.1.tar.gz (121.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

oxutils-0.5.1-py3-none-any.whl (190.1 kB view details)

Uploaded Python 3

File details

Details for the file oxutils-0.5.1.tar.gz.

File metadata

  • Download URL: oxutils-0.5.1.tar.gz
  • Upload date:
  • Size: 121.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for oxutils-0.5.1.tar.gz
Algorithm Hash digest
SHA256 7c7da4ba1d1480b3377d0a4e1306ca998c92cf7e3ee5b2bcd6c1941558393385
MD5 e15481867aea0c915906293735977ee8
BLAKE2b-256 b2c70a1a1d6349d7cfc80dd1b2e826670e1b055a9884b6c5f026611b4d5fcbb2

See more details on using hashes here.

Provenance

The following attestation bundles were made for oxutils-0.5.1.tar.gz:

Publisher: publish.yml on oxiliere/oxutils

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oxutils-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: oxutils-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 190.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for oxutils-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 78c4fed522836d9b6b577f380d1639fdfd5ee58429d375134e5ffb46022a4630
MD5 b5b3f8acfab8cb6206b7b799b02d7917
BLAKE2b-256 7f3867cbee0dd31d0e7c4f2359dd52ac11cea778af4a4821d4e25f3482fce432

See more details on using hashes here.

Provenance

The following attestation bundles were made for oxutils-0.5.1-py3-none-any.whl:

Publisher: publish.yml on oxiliere/oxutils

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page