Skip to main content

iisi-app-core

iisi-app-core is a small Python library for two things:

  • bootstrapping ports-and-adapters applications with decorators, autoload, and punq
  • lightweight role-based authorization with an explicit Principal

Requirements

  • Python >=3.14,<4

Installation

pip install iisi-app-core

Bootstrap Quickstart

1. Mark ports and implementations

from dataclasses import dataclass
from iisi_app_core import (
    ContainerBuilder,
    application,
    driven_adapter,
    driven_port,
    driving_adapter,
    driving_port,
)


@driven_port
class UserRepository:
    def get(self, user_id: str) -> dict[str, str]:
        raise NotImplementedError


@driven_adapter(port=UserRepository)
class DynamoUserRepository(UserRepository):
    def get(self, user_id: str) -> dict[str, str]:
        return {"id": user_id, "name": "Ada"}


@driving_port
class GetUserProfilePort:
    def get_user_profile(self, user_id: str) -> dict[str, str]:
        raise NotImplementedError

@dataclass(frozen=True, slots=True)
@application(port=GetUserProfilePort)
class GetUserProfile(GetUserProfilePort):
    
    repo: UserRepository

    def get_user_profile(self, user_id: str) -> dict[str, str]:
        return self.repo.get(user_id)

@dataclass(frozen=True, slots=True)
@driving_adapter
class GetUserProfileHandler:

    app: GetUserProfilePort

    def handle(self, user_id: str) -> dict[str, str]:
        return self.app.get_user_profile(user_id)

ContainerBuilder.build() validates the boundaries:

  • driving adapters may depend only on @driving_port ports
  • applications may depend only on @driven_port ports
  • depending on a decorated implementation directly raises PortsAndAdaptersViolationError

2. Autoload modules

import app.users

from iisi_app_core import autoload


modules = autoload(app.users)

autoload(...) expects an imported package object and recursively imports all Python modules under it, excluding __init__.py.

3. Build the container

from iisi_app_core import ComponentRegistry, ContainerBuilder


registry = ComponentRegistry.from_modules(modules)
container = ContainerBuilder(registry).build()

handler = container.resolve(GetUserProfileHandler)
result = handler.handle("123")

Both the declared port and the concrete implementation are registered in punq.

4. Optional FastAPI + Mangum bootstrap

Install the framework extra when you want a web bootstrap path:

pip install "iisi-app-core[fastapi]"
from typing import Annotated

import app.users
from fastapi import APIRouter, FastAPI

from iisi_app_core.integrations.fastapi import FastApiMangumBuilder, from_container


def create_app(ctx) -> FastAPI:
    from app.users.ports import GetUserProfilePort

    router = APIRouter()

    @router.get("/users/{user_id}")
    def get_user_profile(
        user_id: str,
        use_case: Annotated[GetUserProfilePort, from_container(GetUserProfilePort)],
    ) -> dict[str, str]:
        return use_case.get_user_profile(user_id)

    app = FastAPI()
    app.include_router(router)
    return app


built = (
    FastApiMangumBuilder()
    .autoload(app.users)
    .app(create_app)
    .enable_mangum(lifespan="off")
    .build()
)

app = built.app
handler = built.handler

FastApiMangumBuilder reuses the existing autoload(...) and ContainerBuilder.build() logic, then exposes the built container, registry, and modules through app.state.

Standalone Authz

authz is explicit and does not use request-local global state.

from iisi_app_core import Principal, Role, require_role


@require_role(Role.READER)
def view_profile(*, principal: Principal, user_id: str) -> str:
    return f"{principal.name}:{user_id}"


principal = Principal.of(name="alice", role=Role.READER, tenant_id="tenant")
result = view_profile(principal=principal, user_id="123")

If your callable does not receive principal= directly, provide principal_getter=...:

from iisi_app_core import Role, require_role


@require_role(Role.ADMIN, principal_getter=lambda args, kwargs: args[0].principal)
def run(command) -> str:
    return "ok"

Available authz helpers:

  • Principal, Role
  • authorize, ensure_at_least, at_least, has_role
  • require_role
  • DomainValidationError, ForbiddenError

Public API

Top-level exports are intentionally small:

  • bootstrap: autoload, ModuleAutoloadError, decorators, metadata types, ComponentRegistry, ContainerBuilder
  • authz: Principal, Role, require_role, helper functions, DomainValidationError, ForbiddenError

Everything else from earlier versions is out of scope for this library.

Metadata

Release files for iisi-app-core 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for iisi-app-core 0.2.2
File Size Uploaded Provenance Actions
iisi_app_core-0.2.2.tar.gz 17.0 kB Without provenance Details for iisi_app_core-0.2.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for iisi-app-core 0.2.2
File Interpreter ABI Platform Actions
iisi_app_core-0.2.2-py3-none-any.whl Python 3 none any Details for iisi_app_core-0.2.2-py3-none-any.whl

Total release size: 30.3 kB

Release files / iisi_app_core-0.2.2.tar.gz

Download URL iisi_app_core-0.2.2.tar.gz
Size 17.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ea27e9adac796b29198871ccec694e2d9eac32a606e603ec61ac73984bd47837
BLAKE2b-256 checksum
How to use checksums
6ab3b7c6d7bcddea9d0bb1a7a67a6664cb291335ee15e6edb01189f891b0fefa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Release files / iisi_app_core-0.2.2-py3-none-any.whl

Download URL iisi_app_core-0.2.2-py3-none-any.whl
Size 13.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0912dcf3c6937a523290b683b3b77f9d6e795d1de66558feede651e2bf9dca90
BLAKE2b-256 checksum
How to use checksums
903312518f1a1c20ca09056beb9ac99bddeed0d7fea8f9917ad5be16363aeaac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Security for iisi-app-core 0.2.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page