1#!/usr/bin/env python3
2"""
3
4
5"""
6# Imports:
7from __future__ import annotations
8
9# ##-- stdlib imports
10import datetime
11import enum
12import functools as ftz
13import itertools as itz
14import logging as logmod
15import pathlib as pl
16import re
17import time
18import collections
19import contextlib
20import hashlib
21from copy import deepcopy
22from uuid import UUID, uuid1
23from weakref import ref
24import atexit # for @atexit.register
25import faulthandler
26# ##-- end stdlib imports
27
28from . import _interface as API # noqa: N812
29from .annotate import SubAnnotate_m
30
31# ##-- types
32# isort: off
33# General
34import abc
35import collections.abc
36import typing
37import types
38from typing import cast, assert_type, assert_never
39from typing import Generic, NewType, Never
40from typing import no_type_check, final, override, overload
41# Protocols and Interfaces:
42from typing import Protocol, runtime_checkable
43if typing.TYPE_CHECKING:
44 from typing import Final, ClassVar, Any, Self
45 from typing import Literal, LiteralString
46 from typing import TypeGuard
47 from collections.abc import Iterable, Iterator, Callable, Generator
48 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
49
50 from jgdv import Maybe
51
52# isort: on
53# ##-- end types
54
55##-- logging
56logging = logmod.getLogger(__name__)
57##-- end logging
58
59# Vars:
60
61# Body:
62
[docs]
63class SubRegistry_m(SubAnnotate_m):
64 """ Create Subclasses in a registry
65
66 By doing:
67
68 class MyReg(SubRegistry_m):
69 _registry : dict[str, type] = {}
70
71 class MyClass(MyReg['blah']: ...
72
73 MyClass is created as a subclass of MyReg, with a parameter set to 'blah'.
74 This is added into MyReg._registry
75 """
76 _registry : ClassVar[dict] = {}
77
78 @classmethod
79 def __init_subclass__(cls, *args:Any, **kwargs:Any) -> None: # noqa: ANN401
80 logging.debug("Registry Subclass: %s : %s : %s", cls, args, kwargs)
81 super().__init_subclass__(*args, **kwargs)
82 match getattr(cls, "_registry", None):
83 case None:
84 logging.debug("Creating Registry: %s : %s : %s", cls.__name__, args, kwargs)
85 cls._registry = {}
86 case _:
87 pass
88 match cls.cls_annotation():
89 case None:
90 logging.debug("No Annotation")
91 pass
92 case x if x in cls._registry and issubclass(cls, (current:=cls._registry[x])):
93 logging.debug("Overriding : %s : %s : %s : (%s) : %s", cls.__name__, args, kwargs, x, current)
94 cls._registry[x] = cls
95 case x if x not in cls._registry:
96 logging.debug("Registering: %s : %s : %s : (%s)", cls.__name__, args, kwargs, x)
97 cls._registry.setdefault(x, cls)
98
99 @classmethod
100 def __class_getitem__(cls:type, *params:Any) -> type: # type:ignore # noqa: ANN401
101 match cls._registry.get(params[0], None): # type: ignore[attr-defined]
102 case None:
103 logging.debug("No Registered annotation class: %s :%s", cls, params)
104 return super().__class_getitem__(*params) # type: ignore[misc]
105 case x:
106 return x
107
[docs]
108 @classmethod
109 def get_registered(cls, *, param:Maybe=None) -> Self:
110 param = param or cls.cls_annotation()
111 return cls._registry.get(param, cls)
112
[docs]
113 @classmethod
114 def maybe_subclass(cls, *, param:Maybe=None) -> Maybe[Self]:
115 param = param or cls.cls_annotation()
116 return cls._registry.get(param, None)