DevLog
Opened this issue ยท 18 comments
Implement a set-based record?
import registrate
record = registrate.SetBasedRecord() # rename
record(1)
record(2)
record(3)
record(1)
>>> record
{1, 2, 3}
Note: Support others (e.g. deque
)?
Implement decorators:
import roster
@roster.record
def numbers(number: int) -> int:
return number
@roster.roster(key=True)
def functions(func) -> str:
return func.__name__
@roster.register(key=True)
def routes(path: str, method: str = 'GET') -> Route:
return Route(path, method=method)
Draw inspiration from annotate
Ability to change the underlying store? E.g., set
instead of list
, Namespace
instead of dict
record: Record[Set[int]] = Record(set())
class Namespace(Record[T]):
store: SimpleNamespace[T]
def record(self, item: T, /) -> T:
self.store[...] = ...
return item
def value_register(hook):
@register
def r(func: Callable, *args, **kwargs) -> Tuple[Callable, Any]:
return (func, hook(*args, **kwargs))
return r
def key_register(hook):
@register
def r(func: Callable, *args, **kwargs) -> Tuple[Callable, Any]:
return (hook(*args, **kwargs), func)
return r
Make Register
accept a single item
, have to subclass to 'flatten', e.g:
class BasicRegister(Register):
def __init__(self, factory):
super(lambda k, v: (k, v))
self._factory = factory
def __call__(self, *args, **kwargs):
return super().__call__(self._factory(*args, **kwargs))
Consider:
@routes('/', method='GET')
def root(): pass
>>> routes
[Route(path='/', method='GET', target=<function root>)]
Hence, all containers should support an entrypoint
Maybe the decorators get you to provide the entrypoint, and you can choose to specify a resolver?
E.g:
@register(resolve=lambda k, v: (v, k))
def routes(path: str, method: str='GET') -> Route:
return Route(path=path, method=method)
store = {}
def func(func):
store[func] = 'FUNCTION'
return func
def cls(cls):
store[cls] = 'CLASS'
return cls
@func
def foo(): pass
@cls
class Bar: pass
routes = MapStore()
@routes.key
def route(path: str, method: str='GET') -> Route:
return Route(path=path, method=method)
class Record(Generic[V], ABC):
@abstractmethod
def record(self, value: V, /) -> None:
...
def __call__(self, value: V, /) -> V:
self.record(value)
return value
def item(self, func: Callable[[T], V], /) -> Callable[[T], T]:
def proxy(item: T, /) -> T:
self.record(func(item))
return item
return proxy
class ListRecord(Record[V], List[V]):
def record(self, value: V, /) -> None:
self.append(value)
class SetRecord(Record[V], Set[V]):
def record(self, value: V, /) -> None:
self.add(value)
class Register(Generic[K, V], ABC):
@abstractmethod
def register(self, key: K, value: V, /) -> None:
...
def __call__(self, key: K, /) -> Callable[[V], V]:
def proxy(value: V, /) -> V:
self.register(key, value)
return value
return proxy
def key(self, func: Callable[..., K], /) -> Callable[..., Callable[[V], V]]:
def proxy(*args: Any, **kwargs: Any) -> Callable[[V], V]:
key: K = func(*args, **kwargs)
def decorator(value: V, /) -> V:
self.register(key, value)
return value
return decorator
return proxy
def value(self, func: Callable[..., V], /) -> Callable[..., Callable[[K], K]]:
def proxy(*args: Any, **kwargs: Any) -> Callable[[K], K]:
value: V = func(*args, **kwargs)
def decorator(key: K, /) -> K:
self.register(key, value)
return key
return decorator
return proxy
def entry(self, func: Callable[[T], Tuple[K, V]], /) -> Callable[[T], T]:
def proxy(item: T, /) -> T:
self.register(*func(item))
return item
return proxy
class DictRegister(Register[K, V], Dict[K, V]):
def register(self, key: K, value: V, /) -> None:
self[key] = value
Implement decorators:
import roster @roster.record def numbers(number: int) -> int: return number @roster.roster(key=True) def functions(func) -> str: return func.__name__ @roster.register(key=True) def routes(path: str, method: str = 'GET') -> Route: return Route(path, method=method)Draw inspiration from
annotate
Not a fan of this idea as it becomes unclear.
record: Record[Set[int]] = Record(set())
This can't be done because a set
is a Collection
, whereas a list
is a Sequence
. Handy ref: https://docs.python.org/3/library/collections.abc.html#collections.abc.AsyncIterable
Consider:
@routes('/', method='GET') def root(): pass>>> routes [Route(path='/', method='GET', target=<function root>)]Hence, all containers should support an entrypoint
^^^ TODO. Currently RecordABC.item
expects a func that returns its first parameter - I assume the value would need to be returned instead?
Add PyPI link to GitHub repo
TODO: Improve typing - use param specs