Source code for snake._meta
"""Meta Class Voodoo magic."""
from __future__ import annotations
import os
import dataclasses
import itertools
import logging
import sys
from collections import defaultdict
from collections.abc import Callable, Iterator, Iterable
from enum import Enum, EnumMeta
from functools import wraps
from typing import Any, TypeVar
from functools import partial
from typing_extensions import dataclass_transform
T = TypeVar("T")
ThreeInts = tuple[int, int, int]
ThreeFloats = tuple[float, float, float]
[docs]
def make_log_property(dunder_name: str) -> Callable:
"""Create a property logger."""
def log(self: Any) -> logging.Logger:
"""Get a logger."""
return logging.getLogger(f"{dunder_name}.{self.__class__.__name__}")
return log
[docs]
class LogMixin:
"""A Mixin to add a logger to a class."""
@property
def log(self) -> logging.Logger:
"""Logger."""
return logging.getLogger(f"{self.__class__.__name__}")
[docs]
class NoCaseEnum(Enum, metaclass=EnumMeta):
"""Base Class for Enum to be case insensitive."""
pass
[docs]
class MethodRegister:
"""
A Decorator to register methods of the same type in dictionaries.
Parameters
----------
name: str
The register
"""
registry: dict = defaultdict(dict)
def __init__(self, register_name: str):
self.register_name = register_name
[docs]
def __call__(
self,
method_name: str | Callable,
) -> Callable:
"""Register the function in the registry."""
def decorator(func: Callable[..., T], method_name: str) -> Callable[..., T]:
self.registry[self.register_name][method_name] = func
if func.__name__ != method_name:
func.__name__ += "__" + method_name
@wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> T:
return func(*args, **kwargs)
return wrapper
# allow for direct name.
if callable(method_name):
func = method_name
method_name = func.__name__
return decorator(func, method_name)
else:
return partial(decorator, method_name=method_name)
if sys.version_info <= (3, 12):
def batched(iterable: Iterable, n: int) -> Iterator[tuple[int]]:
# batched('ABCDEFG', 3) --> ABC DEF G
if n < 1:
raise ValueError("n must be at least one")
it = iter(iterable)
while batch := tuple(itertools.islice(it, n)):
yield batch
else:
batched = itertools.batched
[docs]
class Singleton(type):
_instances: dict[type, object] = {}
[docs]
def __call__(cls, *args: Any, **kwargs: Any):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
[docs]
class ENVCONFIG(metaclass=Singleton):
"""Environment Configuration."""
SNAKE_TMP_DIR = "/tmp"
SNAKE_HDF5_CHUNK_SIZE = 1024**2
SNAKE_HDF5_CHUNK_WRITE_SIZE = 4 * 1024**3
[docs]
@classmethod
def __getitem__(cls, key: str) -> Any:
if key in os.environ:
return os.environ[key]
return getattr(cls, key)
EnvConfig = ENVCONFIG()