Skip to main content

The Python port of Node in Layers Core.

Project description

In Layers Core

Python port of the Node-in-Layers core framework. Supports Domains, config and layers loading, and cross-layer logging.

Key points:

  • Domains explicitly provided in config (no convention discovery)
  • Layers are loaded in configured order (supports composite layers)
  • Cross-layer logging with automatic id propagation and function wraps

Pecularities, Limitations, and Recommendations

No Keyword Arguments for Layer level Functions

For the public functions for a given layer, the arguments cannot use kwargs. The reason behind this is it creates a consistent interface to allow the framework and other tools to work.

We recommend making arguments an object (class instance, dict), and making the last argument a "cross_layer_props" object, that can pass along across layers.

Contributing

Running Unit Tests

poetry run pytest --cov=. --cov-report=term-missing --cov-report=html -q

Auto-Cleaning / Checking Tools

./bin/lint.sh

Publishing

./bin/deploy.sh

Models and Persistence Backends

Overview

  • Models are standard Pydantic classes decorated with @model(domain=..., plural_name=...).
  • When a domain’s services layer is loaded, the framework discovers the domain’s models and exposes them as SimpleModel wrappers under:
    • context.models.<domain>.get_models() -> Box, keyed by the model’s plural name
    • Example access: context.models.mydomain.get_models().MyModels
  • Each entry in this mapping is a SimpleModel wrapper with:
    • instance(data | **kwargs) to wrap raw data
    • create(data | **kwargs) to persist through a backend
    • retrieve(id), update(id, **kwargs), delete(id), search(query)
    • get_model_definition(), get_primary_key_name(), get_primary_key(data)
  • A SimpleModel instance supports zero-arg getters for its data via instance.get.<field>().

Important: Persistence uses a backend returned by a model backend provider living in the services of the domain named by in_layers_core.models.model_backend. If none is provided, a core fallback uses a no-op backend (CRUD operations will raise NotImplemented).

Declaring a Model

from pydantic import BaseModel, Field
from in_layers.core.models.libs import model

@model(domain="pipeline", plural_name="PipelineJobs")
class PipelineJob(BaseModel):
    id: str = Field(...)
    name: str = Field(...)

Providing a Model Backend (via a Domain’s Services)

You must provide, in the configured domain’s services layer, a method that returns a backend for each model. The service needs a method:

  • get_model_backend(model_definition) -> BackendProtocol

For example:

# services.py

class MyDomainServices:
    def __init__(self, ctx):
        self._ctx = ctx

    def get_model_backend(self, model_definition):
        # you can check the domain, the name of the model (if it is model/domain specific)
        # return your BackendProtocol implementation (e.g., Mongo, SQL, etc.)
        return MyConcreteBackend(...)


Then tell the framework which backend provider to use via config:
```python
config = Box(
    system_name="test",
    environment="test",
    in_layers_core=Box(
        logging=Box(...),
        layer_order=["services", "features"],
        domains=[...],
        models=Box(
            # Choose your model backend by telling the framework which domain it lives in.
            # The framework will call mydomain.services.get_model_backend(model_definition)
            model_backend="mydomain",
            # Optional: surface CRUD wrappers in services/features
            model_services_cruds=True,
            model_features_cruds=False,
        ),
    ),
)

Notes:

  • Ensure the configured domain’s services are loaded before domains whose models you want to wrap (via domain ordering and layer_order).
  • If not provided, the framework falls back to a core default provider, which uses a no-op backend (CRUD is not implemented).
  • If model_features_cruds is true, model_services_cruds is implicitly treated as true and both layers expose cruds.<Plural> wrappers.

Using Models in Services

from pydantic import BaseModel
from in_layers.core.models.libs import model
# ./mydomain/models.py
@model(domain="mydomain", plural_name="MyModels")
class MyModel(BaseModel):
    id: str
    name: str
# ./mydomain/services.py
from types import SimpleNamespace

class MyServices:
    def __init__(self, ctx):
        self._ctx = ctx

    def return_a_model_instance(self):
        models = self._ctx.models.mydomain.get_models()
        MyModels = models.MyModels
        # Create a non-persisted instance via kwargs (or Mapping)
        inst = MyModels.instance(id="123", name="John Doe")
        # Access fields
        assert inst.get.id() == "123"
        assert inst.get.name() == "John Doe"
        return inst
# ./mydomain/__init__.py
from . import services, models
name = "mydomain"
__all__ = ['name', 'services', 'models']

Backends

Backends implement BackendProtocol:

  • create(model, data) -> Mapping
  • retrieve(model, id) -> Mapping | None
  • update(model, id, data) -> Mapping
  • delete(model, id) -> None
  • search(model, query) -> ModelSearchResult

Your persistence factory decides which backend to return per model class (e.g., route different models to different datastores).

Instance Creation Options

  • Mapping:
    • MyModels.instance({"id": "123", "name": "John"})
    • MyModels.create({"id": "123", "name": "John"})
  • Keywords:
    • MyModels.instance(id="123", name="John")
    • MyModels.create(id="123", name="John")

When both are provided, keyword arguments override keys in the mapping.

Project details


Download files

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

Source Distribution

in_layers_core-0.4.24.tar.gz (33.6 kB view details)

Uploaded Source

Built Distribution

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

in_layers_core-0.4.24-py3-none-any.whl (38.9 kB view details)

Uploaded Python 3

File details

Details for the file in_layers_core-0.4.24.tar.gz.

File metadata

  • Download URL: in_layers_core-0.4.24.tar.gz
  • Upload date:
  • Size: 33.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for in_layers_core-0.4.24.tar.gz
Algorithm Hash digest
SHA256 967ec1a94139c4f5bc63d5ecc41c3f3c17de1888fc996ef16ece07d836efca9a
MD5 1f55477a93db899c81a83f46078ba9cd
BLAKE2b-256 f0fe394230aa7806e10c964737a6fde4a60bc6f2bee5c6c3967fc5a34e74de6a

See more details on using hashes here.

File details

Details for the file in_layers_core-0.4.24-py3-none-any.whl.

File metadata

File hashes

Hashes for in_layers_core-0.4.24-py3-none-any.whl
Algorithm Hash digest
SHA256 a4a03aa9d3789c0404edb6542b5688d7484ba74f23bb54cf7a3e3fe90141f07f
MD5 4ba1508e96a9fbdcf428e0e6358d8e91
BLAKE2b-256 222eee644d155d24b515d84c296e6c5e60f447e8a4461f7e819007abe76eb553

See more details on using hashes here.

Supported by

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