Python Default Type Dict

Есть ли в Python возможность создать класс наподобие TypedDict который будет поддерживать значения по умолчанию. Я реализовал такой класс, назвал его DefTypeDict, он вернет словарь, а ключи которые не были переданы возьмёт из атрибута. Но проблема в том что тут нет предупреждений о неверном типе передаваемых аргументов, хотя в TypeDict есть подсветка.

import sys
# pip install typing-extensions
from typing import _type_check

from typing_extensions import _TypedDictMeta


class _DefTypeDictMeta(_TypedDictMeta):
    def __new__(cls, name, bases, ns, total=True):
        """Create new typed dict class object.

        This method is called when TypedDict is subclassed,
        or when TypedDict is instantiated. This way
        TypedDict supports all three syntax forms described in its docstring.
        Subclasses and instances of TypedDict return actual dictionaries.
        """
        for base in bases:
            if type(base) is not _DefTypeDictMeta:
                raise TypeError('cannot inherit from both a DefTypeDict type '
                                'and a non-TypedDict base class')
        tp_dict = type.__new__(_DefTypeDictMeta, name, (dict,), ns)

        annotations = {}
        own_annotations = ns.get('__annotations__', {})
        own_annotation_keys = set(own_annotations.keys())
        msg = "DefTypeDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
        own_annotations = {
            n: _type_check(tp, msg, module=tp_dict.__module__)
            for n, tp in own_annotations.items()
        }
        required_keys = set()
        optional_keys = set()

        for base in bases:
            annotations.update(base.__dict__.get('__annotations__', {}))
            required_keys.update(base.__dict__.get('__required_keys__', ()))
            optional_keys.update(base.__dict__.get('__optional_keys__', ()))

        annotations.update(own_annotations)
        if total:
            required_keys.update(own_annotation_keys)
        else:
            optional_keys.update(own_annotation_keys)

        tp_dict.__annotations__ = annotations
        tp_dict.__required_keys__ = frozenset(required_keys)
        tp_dict.__optional_keys__ = frozenset(optional_keys)
        if not hasattr(tp_dict, '__total__'):
            tp_dict.__total__ = total
        return tp_dict

    def default_dit(self, **kwargs):
        return {_k: _v for _k, _v
                in self.__dict__.items() if
                not _k.startswith("__") and
                not _k.endswith("__") and
                _k not in kwargs} | kwargs

    __call__ = default_dit  # dict  # static method


def DefTypeDict(typename, fields=None, /, *, total=True, **kwargs):
    """
    Словарь поддерживающий значения по умолчанию

    >>> class Settings(DefTypeDict):
    >>>    port: int = 7070
    >>>    host: str = "0.0.0.0"
    >>> Settings(port=8080)
    {"port":8080, host="0.0.0.0"}

    @param typename:
    @param fields:
    @param total:
    @param kwargs:
    @return:
    """

    if fields is None:
        fields = kwargs
    elif kwargs:
        raise TypeError("DefTypeDict takes either a dict or keyword arguments,"
                        " but not both")

    ns = {'__annotations__': dict(fields)}
    try:
        # Setting correct module is necessary to make typed dict classes pickleable.
        ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass

    return _DefTypeDictMeta(typename, (), ns, total=total)


_DefTypeDict = type.__new__(_DefTypeDictMeta, 'DefTypeDict', (), {})
DefTypeDict.__mro_entries__ = lambda bases: (_DefTypeDict,)

Использование

class Settings(DefTypeDict):
   port: int = 7070
   host: str = "0.0.0.0"

class Settings_2(TypeDict):
   port: int 
   host: str

Settings(port='8080') # Должно быть предупреждене о неверном типе аргуметна
# {"port":'8080', host="0.0.0.0"}

Settings_2(port='8080',host='0.0.0.0') # аргумент port выделяться как неверный тип
# {"port":'8080', host="0.0.0.0"}

Ответы (0 шт):