Skip to main content

mousse

Project description

Mousse

Collections of my most used functions, classes and patterns. I was craving for a delicious mousse as I was comming up with the name.

Installation


pip install -U mousse

Components


Dataclass

This is a self-implement, minimal version of pydantic, with some minor changes.

from typing import *
from mousse import Dataclass, asdict, asclass, Field

class Foo(Dataclass):
    name: str
    number: float
    items: List[str] = []


class Bar(Dataclass):
    foo: Foo
    index: int = Field(..., alias="id")


foo = Foo(
    name="foo", 
    number=42.0, 
    items=["banana", "egg"]
)
bar = Bar(id=1, foo=foo)
print(bar.foo)
# Foo(name="foo", number=42.0, items=['banana', 'egg'])

#convert back to dictionary
bar_dict = asdict(bar)
print(bar_dict)
# {'foo': {'name': 'foo', 'number': 42.0, 'items': ['banana', 'egg']}, 'id': 1}

#conver back to dataclass
bar = asclass(Bar, bar_dict)
print(bar)
# Bar(foo=Foo(name="foo", number=42.0, items=['banana', 'egg']), index=1)

# load from file (.json, .yaml)
bar = asclass(Bar, path="bar.json")
print(bar)
# Bar(foo=Foo(name="foo", number=42.0, items=['banana', 'egg']), index=1)

Some helper functions are:

  • validate: Check data type of variable
from typing import *
from mousse import validate, Dataclass

class Foo(Dataclass):
    name: str
    number: float
    items: List[str] = []

Number = Union[int, float]

validate(int, 1) # True
validate(int, 1.0) # False

validate(Number, 1) # True
validate(Number, 1.0) # True

validate(Dict[str, Any], {
    "a": 1,
    "b": "a"
}) # True

validate(Dict[str, int], {
    "a": 1,
    "b": "a"
}) # False

validate(Tuple[int, float], (1, 1.2)) # True
validate(Tuple[int, float], (1.0, 1.2)) # False
validate(Tuple[Number, Number], (1, 1.2)) # True

foo = Foo(
    name="foo", 
    number=42.0, 
    items=["banana", "egg"]
)
validate(Foo, foo) # True
validate(List[Foo], [foo]) # True
validate(List[Foo], (foo,)) # False
validate(Sequence[Foo], (foo,)) # True
  • parse: Attempt to parse data
from typing import *
from mousse import parse, Dataclass

class Foo(Dataclass):
    name: str
    number: float
    items: List[str] = []

parse(float, 1) # 1.0
parse(Union[int, float], 1) # 1
parse(Union[float, int], 1) # 1.0

parse(Dict[str, Any], {
    1: 2,
    2: 3
}) # {'1': 2, '2': 3}

parse(Dict[str, float], {
    1: 2,
    2: 3
}) # {'1': 2.0, '2': 3.0}

parse(Foo, {
    "name": "foo",
    "number": 42.2,
    "items": [1, 2, 3]
}) # Foo(name="foo", number=42.2, items=['1', '2', '3'])

Config

This is how I manage the configuration of my application. By creating a Config object that can be loaded once and refered everywhere. Of course, by default, the Config object cannot be changed by convention means. A changing config during runtime is evil.

# entry_point.py

from mousse import load_config

load_config(
    "foo", # to identified a key for the configuration,
    path="config.yaml" # also support json
)

# config.yaml
# foo:
#   name: foo
#   number: 42.0
#   items:
#     - name: banana
#       price: 12
#     - name: egg
#       price: 10
# id: 1
# anywhere.py

from typing import *
from mousse import get_config, asdict, asclass, Dataclass

# This can be called anytime
config = get_config("foo")

# before load_config
print(config)
# Config()

# after load_config
print(config)
# Config(foo=Config(items=[Config(price=12), Config(price=10)]), id=1)

print(config.foo)
# Config(items=[Config(price=12), Config(price=10)])

print(config.foo.items[0].price)
# 12

# reassignment is forbidden 
config.foo = "bar"
# AssertionError: Permission denied

# compatible with asdict
config_data = asdict(config)
print(config_data)
# {
#     "foo": {
#         "name": "foo",
#         "number": 42.0,
#         "items": [
#             {
#                 "name": "banana",
#                 "price": 12
#             },
#             {
#                 "name": "egg",
#                 "price": 10
#             }
#         ]
#     },
#     "id": 1
# }

class Item(Dataclass):
    name: str
    price: int

class Foo(Dataclass):
    name: str
    number: float
    items: List[Item]


class Bar(Dataclass):
    foo: Foo
    id: int


# compatible with asclass
bar = asclass(Bar, config)
print(bar)
# Bar(foo=Foo(name="foo", number=42.0, items=[Item(name="banana", price=12), Item(name="egg", price=10)]), id=1)

Logger


This module is for managing logging process, with pre-defined logging format and both file logging and stdout logging.

# entry_point.py

from mousse import get_logger

logger = get_logger(
    "foo", # key to identify logger,
)
logger.add_handler("RotatingFileHandler", path="logs/foo.out")
# anywhere.py

from mousse import get_logger

logger = get_logger("foo")
logger.info("This is", "my", "logger number:", 1)
# [2022-05-09 20:28:04] [43050 4345906560] [INFO] [anywhere:.<module>:1] This is my logger number: 1

The format of the log is:

[{date} {time}] [{process_id} {thread_id}] [{level}] [{file}:{caller}:{lineno}] {msg}

Pattern


A collection of my most used design patterns

Registry pattern

# registry.py
from mousse import Registry

pokedex = Registry()


class Pokemon:
    def __init__(self, name:str):
        self.name = name
# kanto.py
from .registry import pokedex, Pokemon


@pokedex.register
class Pikachu(Pokemon):
    def sound(self):
        return "pika pika chu"



@pokedex.register
class Charmander(Pokemon):
    def sound(self):
        return "charman charman der"
# johto.py
from .registry import pokedex, Pokemon


@pokedex.register
class Chikorita(Pokemon):
    def sound(self):
        return "chiko chiko"
from . import kanto, johto
from .registry import pokedex


pikachu = pokedex("Pikachu", "1st")
print(pikachu.name, pikachu.sound())

charmander = pokedex("Charmander", "2nd")
print(charmander.name, charmander.sound())

chikorita = pokedex("Chikorita", "3rd")
print(chikorita.name, chikorita.sound())

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

mousse-0.1.41.tar.gz (25.5 kB view details)

Uploaded Source

Built Distribution

mousse-0.1.41-py3-none-any.whl (30.8 kB view details)

Uploaded Python 3

File details

Details for the file mousse-0.1.41.tar.gz.

File metadata

  • Download URL: mousse-0.1.41.tar.gz
  • Upload date:
  • Size: 25.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.7

File hashes

Hashes for mousse-0.1.41.tar.gz
Algorithm Hash digest
SHA256 10b258b36a55b453bd04e6502e1288b5b8d0165a0115d88ff7abed4bbda28c2b
MD5 3635d2d6246bccc5a10638ed25b8f3fa
BLAKE2b-256 5971fba8698a2b078218a3bd5782b3b05331c4a741d0f16b92b7be44e415d348

See more details on using hashes here.

File details

Details for the file mousse-0.1.41-py3-none-any.whl.

File metadata

  • Download URL: mousse-0.1.41-py3-none-any.whl
  • Upload date:
  • Size: 30.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.7

File hashes

Hashes for mousse-0.1.41-py3-none-any.whl
Algorithm Hash digest
SHA256 5d17b1d195129076007ddca48c15d4bbc1be7ea2834e038f854ff8a46e5068a0
MD5 db1f755738f892cd90be0b84915af367
BLAKE2b-256 a4b49de12f920cadb7ddd21ad63f0cd00d8edfef35a8d2401cb3cbea73cd17c0

See more details on using hashes here.

Supported by

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