Python metaprogramming

python #metaprogramming

Examples from my codebases https://github.com/barisozmen/python-cookbook/blob/main/metaclasses.py

from cli_support import graceful_keyboard_interrupt, debugger_on_error


class SingletonMetaclass(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]


class GracefulInterruptMetaclass(type):
    def __new__(cls, name, bases, attrs):
        # Wrap all public methods with graceful_keyboard_interrupt
        for key, value in attrs.items():
            if callable(value) and not key.startswith('_'):
                attrs[key] = graceful_keyboard_interrupt(value)
        return super().__new__(cls, name, bases, attrs)


class DebuggerOnErrorMetaclass(type):
    def __new__(cls, name, bases, attrs):
        for key, value in attrs.items():
            if callable(value) and not key.startswith('_'):
                attrs[key] = debugger_on_error(value)
        return super().__new__(cls, name, bases, attrs)




class LoggedMetaclass(type):
    """Metaclass that logs all method calls for a class"""
    def __new__(cls, name, bases, attrs):
        # Wrap callable methods with logging
        for key, value in attrs.items():
            if callable(value) and not key.startswith('_'):
                attrs[key] = cls.log_call(value)
        return super().__new__(cls, name, bases, attrs)

    @staticmethod
    def log_call(func):
        def wrapper(*args, **kwargs):
            print(f'Calling: {func.__name__}')
            result = func(*args, **kwargs)
            print(f'Finished: {func.__name__}')
            return result
        return wrapper


class StaticMethodsByDefault(type):
    def __new__(cls, name, bases, attrs):
        # Make all methods static by default, except special methods
        for key, value in attrs.items():
            if callable(value) and not key.startswith('__'):
                attrs[key] = staticmethod(value)
        return super().__new__(cls, name, bases, attrs)

https://github.com/barisozmen/python-cookbook/blob/main/cli_support.py

import os
import sys
from functools import wraps


def graceful_keyboard_interrupt(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except KeyboardInterrupt:
            print("\n\nKeyboard interrupt detected. Exiting...")
            print("\nGoodbye! 👋\n")
            sys.exit(1)
    return wrapper


def debugger_on_error(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            import pdb; pdb.set_trace()
            raise e
    return wrapper

https://github.com/barisozmen/python-cookbook/blob/main/singletons.py

from metaclasses import SingletonMetaclass

class Counter(metaclass=SingletonMetaclass):
    def __init__(self):
        self.count = 0

    @property
    def next_id(self):
        self.count += 1
        return self.count


class Config(metaclass=SingletonMetaclass):
    def __init__(self):
        self._settings = {}

    def set(self, key, value):
        self._settings[key] = value

    def get(self, key, default=None):
        return self._settings.get(key, default) 
Linked from