Skip to main content

WARNING: this project is still undergoing some heavy changes and is still quite poorly documented so if you're interested in using it, well do that at your own risk.

Lily - microservices by humans for humans

Lily is built around:

  • DDD (Domain Driven Design) = Commands + Events
  • TDD+ (Test Driven Development / Documentation)

Foundations

Lily was inspired by various existing tools and methodologies. In order to understand the philosophy of Lily one must udnerstand two basic concepts:

  • COMMAND - is a thing one can perform
  • EVENT - is a consequence of executing COMMAND (one COMMAND can lead to many events).

In lily we define commands that are raising (python's raise) various events that are captured by the main events loop (do not confuse with node.js event loop).

Creating HTTP commands

Lily enable very simple and semantic creation of commands using various transport mechanism (HTTP, Websockets, Async) in a one unified way.

Each HTTP command is build around the same skeleton:

from lily import (
    command,
    Meta,
    name,
    Input,
    Output,
    serializers,
    Access,
    HTTPCommands,
)

class SampleCommands(HTTPCommands):
    @command(
        name=<NAME>,

        meta=Meta(
            title=<META_TITLE>,
            description=<META_DESCRIPTION>,
            domain=<META_DOMAIN>),

        access=Access(access_list=<ACCESS_LIST>),

        input=Input(body_parser=<BODY_PARSER>),

        output=Output(serializer=<SERIALIZER>),
    )
    def <HTTP_VERB>(self, request):

        raise self.event.<EXPECTED_EVENT>({'some': 'thing'})

The simplest are HTTP commands that can be defined in the following way:

from lily import (
    command,
    Meta,
    name,
    Input,
    Output,
    serializers,
    Access,
    HTTPCommands,
)

class SampleCommands(HTTPCommands):
    @command(
        name=name.Read(CatalogueItem),

        meta=Meta(
            title='Bulk Read Catalogue Items',
            domain=CATALOGUE),

        access=Access(access_list=['ADMIN']),

        input=Input(body_parser=CatalogueItemParser),

        output=Output(serializer=serializers.EmptySerializer),
    )
    def get(self, request):

        raise self.event.Read({'some': 'thing'})

Names

FIXME: add it ...

Creating Authorizer class

Each command created in Lily can be protected from viewers who should not be able to access it. Currently one can pass to the @command decorator access_list which is passed to the Authorizer class.

from lily.base.events import EventFactory


class BaseAuthorizer(EventFactory):
    """Minimal Authorizer Class."""

    def __init__(self, access_list):
        self.access_list = access_list

    def authorize(self, request):
        try:
            return {
                'user_id': request.META['HTTP_X_CS_USER_ID'],
                'account_type': request.META['HTTP_X_CS_ACCOUNT_TYPE'],
            }

        except KeyError:
            raise self.AccessDenied('ACCESS_DENIED', context=request)

    def log(self, authorize_data):
        return authorize_data

But naturally it can take any form you wish. For example:

  • it could expect Authorization header and perform Bearer token decoding
  • it could leverage the existence of access_list allowing one to apply some sophisticated authorization policy.

An example of fairly classical (jwt token based Authorizer would be):

from lily import BaseAuthorizer
from .token import AuthToken


class Authorizer(BaseAuthorizer):

    def __init__(self, access_list):
        self.access_list = access_list

    def authorize(self, request):

        try:
            type_, token = request.META['HTTP_AUTHORIZATION'].split()

        except KeyError:
            raise self.AuthError('COULD_NOT_FIND_AUTH_TOKEN')

        else:
            if type_.lower().strip() != 'bearer':
                raise self.AuthError('COULD_NOT_FIND_AUTH_TOKEN')

        account = AuthToken.decode(token)

        if account.type not in self.access_list:
            raise self.AccessDenied('ACCESS_DENIED')

        # -- return the enrichment that should be available as
        # -- `request.access` attribute
        return {'account': account}

    def log(self, authorize_data):
        return {
            'account_id': authorize_data['account'].id
        }

Notice how above custom Authorizer class inherits from BaseAuthorizer. In order to enable custom Authorizer class one must set in the settings.py:

LILY_AUTHORIZER_CLASS = 'account.authorizer.Authorizer'

where naturally the module path would depend on a specific project set up.

Finally in order to use Authorization at the command level one must set in the @command definition:

from lily import (
    command,
    Meta,
    name,
    Output,
    serializers,
    Access,
    HTTPCommands,
)

class SampleCommands(HTTPCommands):
    @command(
        name=name.Read(CatalogueItem),

        meta=Meta(
            title='Bulk Read Catalogue Items',
            domain=CATALOGUE),

        access=Access(access_list=['ADMIN']),

        output=Output(serializer=serializers.EmptySerializer),
    )
    def get(self, request):

        raise self.event.Read({'some': 'thing'})

where access entry explicitly specifies who can access a particular command, that list will be injected to the Authorizer on each request to the server.

Metadata

Release files for lily 3.0.1

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

Source distribution (sdist)

Source distribution for lily 3.0.1
File Size Uploaded
lily-3.0.1.tar.gz 1.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for lily 3.0.1
File Interpreter ABI Platform
lily-3.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 2.5 MB

Release files / lily-3.0.1.tar.gz

Download URL lily-3.0.1.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
1fe925c2d689c2c8efaea30a4d05763bae65a34baf95b4877136e00b93b635ca
BLAKE2b-256 checksum
How to use checksums
7f559be3f5ed5b4e43caee7f28ee91c0c23b99b712b46dc0f42dc9cb694d31a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.1.13 CPython/3.9.13 Linux/5.13.0-1031-azure

Release files / lily-3.0.1-py3-none-any.whl

Download URL lily-3.0.1-py3-none-any.whl
Size 1.3 MB
Tags Python 3
SHA-256 checksum
How to use checksums
a4c7401d25951d24371f12dec9cb107961dd710a9d048635a55b09a687b56229
BLAKE2b-256 checksum
How to use checksums
273e2a5d10cec660a9e47fa5ff8cd530440c46d8e46b0847dea56fc9bd75dc58
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.1.13 CPython/3.9.13 Linux/5.13.0-1031-azure

Release history Release notifications | RSS feed

This release

3.0.1 This release

2 release files

3.0.0

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.2

1 release file

2.2.13

1 release file

2.2.11

1 release file

2.2.10

1 release file

2.2.6

1 release file

2.2.4

1 release file

2.2.3

1 release file

2.2.2

1 release file

2.2.1

1 release file

2.2.0

1 release file

2.1.3

1 release file

2.1.1

1 release file

2.1.0

1 release file

2.0.6

1 release file

2.0.5

1 release file

2.0.4

1 release file

2.0.2

1 release file

2.0.1

1 release file

2.0.0

1 release file

1.3.3

1 release file

1.3.2

1 release file

1.3.1

1 release file

1.3.0

1 release file

1.2.24

1 release file

1.2.23

1 release file

1.2.22

1 release file

1.2.21

1 release file

1.2.20

1 release file

1.2.19

1 release file

1.2.18

1 release file

1.2.17

1 release file

1.2.16

1 release file

1.2.15

1 release file

1.2.14

1 release file

1.2.13

1 release file

1.2.12

1 release file

1.2.11

1 release file

1.2.10

1 release file

1.2.9

1 release file

1.2.8

1 release file

1.2.7

1 release file

1.2.6

1 release file

1.2.5

1 release file

1.2.4

1 release file

1.2.3

1 release file

1.2.2

1 release file

1.2.0

1 release file

1.1.31

1 release file

1.1.30

1 release file

1.1.28

1 release file

1.1.27

1 release file

1.1.26

1 release file

1.1.25

1 release file

1.1.24

1 release file

1.1.23

1 release file

1.1.21

1 release file

1.1.20

1 release file

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