def register_component2(registry: ServiceRegistry, target: Callable, context: Type[Resource] = IResource): """ Imperative form of the component decorator """ # This is one using a hypothetical fork of wired.dataclasses.injector # while Michael and I discuss props component_name = target.__name__ def component_factory(container: ServiceContainer): def construct_component(**kwargs): """ A partial-partial, used to collect kwargs during calling """ # Let's use copied version of Injector, one that supports props from wired_components.injector2 import Injector injector = Injector(target) component_instance = injector(container=container, props=kwargs) return component_instance return construct_component # Use the name of the class, e.g. Breadcrumb, as the name argument # during registration registry.register_factory(component_factory, IComponent, context=context, name=component_name) # Next, add a zope.interface "subscription" to allow later reading of # all registered components adapter_registry: AdapterRegistry = registry._factories adapter_registry.subscribe([IResource], IComponent, target)
def register_dataclass(registry: ServiceRegistry, target, for_=None, context=None): """ Generic injectory factory for dataclasses """ # Note: This function could be a decorator which already knows # the registry, has all the targets, and can do them in one # container that it makes. For example: # from wired.decorators import factory # @factory(for_=Greeter, context=FrenchCustomer) # @datclass # class FrenchGreeter(Greeter): # pass # The common case, for default registrations we can omit # the "for_" as it is the same as the class implementing it if for_ is None: for_ = target if getattr(target, 'factory', None): # This class wants to control its factory, use that one dataclass_factory = target.factory else: # Use a generic dataclass factory def dataclass_factory(c: ServiceContainer): instance = injector_construction(c, target) return instance registry.register_factory(dataclass_factory, for_, context=context)
def setup(settings: Settings) -> ServiceRegistry: # Make the registry registry = ServiceRegistry() # Make the greeter factories, using punctuation from settings punctuation = settings.punctuation # First the default greeter, no context def default_greeter_factory(container) -> Greeter: # Use the dataclass default for greeting return Greeter(punctuation=punctuation) # Register it as a factory using its class for the "key" registry.register_factory(default_greeter_factory, Greeter) # Now the French greeter, using context of FrenchCustomer def french_greeter_factory(container) -> Greeter: # Use the dataclass default for greeting return FrenchGreeter(punctuation=punctuation) # Register it as a factory using its class for the "key", but # this time register with a "context" registry.register_factory( french_greeter_factory, Greeter, context=FrenchCustomer ) return registry
def setup(registry: ServiceRegistry, settings: Settings): # The French greeter, using context of FrenchCustomer punctuation = settings.punctuation def french_greeter_factory(container) -> Greeter: return FrenchGreeter(punctuation=punctuation) # Register it as a factory using its class for the "key", but # this time register with a "context" registry.register_factory( french_greeter_factory, Greeter, context=FrenchCustomer ) # *** OVERRIDE !!! This add-on replaces the core, built-in Greeter # with a different implementation. def override_greeter_factory(container) -> Greeter: return OverrideGreeter(punctuation=punctuation) # Register it as a factory using its class for the "key", but # this time register with a "context" registry.register_factory( override_greeter_factory, Greeter, context=Customer ) # Grab the Datastore and add a FrenchCustomer container: ServiceContainer = registry.create_container() datastore: Datastore = container.get(Datastore) customer1 = FrenchCustomer(name='Henri') datastore.customers.append(customer1)
def register_view(registry: ServiceRegistry, target: Type, context: Optional[Type[Resource]] = IResource): """ Imperative form of the decorator """ def view_factory(container: ServiceContainer): injector = Injector(container) view_instance = injector(target) return view_instance registry.register_factory(view_factory, IView, context=context)
def app(): # Do this once at startup registry = ServiceRegistry() registry.register_factory(greeter_factory, Greeter) registry.register_factory(Greeting, Greeting) # Do this for every "request" or operation container = registry.create_container() greeting: Greeting = container.get(Greeting) assert 'Hello from Marie' == greeting.greet()
def test(): registry = ServiceRegistry() registry.register_factory(view_factory, View) # Per "request" container = registry.create_container() view: View = container.get(View) result = view.name expected = 'View' return expected, result
def setup() -> ServiceRegistry: # Make the registry registry = ServiceRegistry() # Make the greeter factory def greeter_factory(container) -> Greeter: return Greeter(greeting='Hello') # Register it as a factory using its class for the "key" registry.register_factory(greeter_factory, Greeter) return registry
def register_autowire(registry: ServiceRegistry, cls: Type[Any], iface: Type[Any] = Interface, *, context: Optional[Type[Any]] = None, name: Text = "", cls_args: Optional[Iterable[Any]] = None, cls_kwargs: Optional[Mapping[Text, Any]] = None, namespace: Optional[Mapping[Text, Any]] = None, lazy: bool = False) -> None: factory = factory_factory(cls, cls_args, cls_kwargs, namespace, lazy) registry.register_factory(factory, iface, context=context, name=name)
def setup(registry: ServiceRegistry, settings: Settings): # The French greeter, using context of FrenchCustomer punctuation = settings.punctuation def french_greeter_factory(container) -> Greeter: # Use the dataclass default for greeting return FrenchGreeter(punctuation=punctuation) # Register it as a factory using its class for the "key", but # this time register with a "context" registry.register_factory(french_greeter_factory, Greeter, context=FrenchCustomer)
def setup(registry: ServiceRegistry, datastore: Datastore): """ Initialize the features in the core application """ # Register factories for target in (Resource, Request, View): registry.register_factory(target.factory, target) # Register dataclass factories (automated sniffing) register_dataclass(registry, Greeter, Greeter) # During bootstrap, make some Customers mary = Customer(name='mary', title='Mary') datastore.customers['mary'] = mary
class _RegistrarBase: """Represents the base class for classes able to register and manage services and function as an IoC object. This is an internal class and not meant for directy use in code. It was provided as a base class to aid unit testing. """ def __init__(self): self._registry = ServiceRegistry() @property def services(self): key = '_container' if not hasattr(self, key): container = self._registry.create_container() setattr(self, key, container) return getattr(self, key) def register_service(self, service, iface=Interface, context=None, name=''): service_factory = SingletonServiceWrapper(service) self.register_service_factory(service_factory, iface, context=context, name=name) def register_service_factory(self, service_factory, iface=Interface, context=None, name=''): self._registry.register_factory(ProxyFactory(service_factory), iface, context=context, name=name) def find_service_factory(self, iface, context=None, name=''): factory = self._registry.find_factory(iface, context=context, name=name) if not factory: raise LookupError('could not find registered service') if isinstance(factory, ProxyFactory): return factory.factory return factory def find_service(self, iface, context=None, name=''): return self.services.get(iface, context=context, name=name)
def setup(settings: Settings) -> ServiceRegistry: # Make the registry registry = ServiceRegistry() # Make the greeter factory, using punctuation from settings punctuation = settings.punctuation def greeter_factory(container) -> Greeter: return Greeter(greeting='Hello', punctuation=punctuation) # Register it as a factory using its class for the "key" registry.register_factory(greeter_factory, Greeter) return registry
def register_dataclass(registry: ServiceRegistry, target, for_=None, context=None, name=''): """ Register a factory for a dataclass that can sniff dependencies. .. code-block:: python from sqlalchemy.orm import Session @dataclass class LoginService: db: Session registry = ServiceRegistry() register_dataclass(registry, LoginService) # ... later container = registry.create_container() svc = container.get(LoginService) :param for_: By default, ``target`` is used as the service type. This can be used to override the ``iface_or_type`` argument in :meth:`wired.ServiceRegistry.register_factory` to some other type. :param context: The ``context`` argument in :meth:`wired.ServiceRegistry.register_factory`. :param str name: The ``name`` argument in :meth:`wired.ServiceRegistry.register_factory`. .. seealso:: - :func:`wired.dataclasses.factory` - :func:`wired.dataclasses.injected` """ # The common case, for default registrations we can omit # the "for_" as it is the same as the class implementing it if for_ is None: for_ = target injector = Injector(target) registry.register_factory(injector, for_, context=context, name=name)
def app(): # Do this once at startup registry = ServiceRegistry() scanner = Scanner(registry=registry) # Point the scanner at a package/module and scan scanner.scan(decorators.basic_class) registry.register_factory(greeter_factory, Greeter) # No longer need this line # registry.register_factory(Greeting, Greeting) # Do this for every "request" or operation container = registry.create_container() greeting: Greeting = container.get(Greeting) assert 'Hello from Marie' == greeting.greet()
def make_registry( root: Optional[Root] = None, root_factory: Optional[Callable] = None, scannables: Union[Iterable[Scannable], Scannable] = tuple(), plugins: Union[Iterable[Plugin], Plugin] = tuple(), theme_config: Optional[ThemeConfig] = None, ) -> ServiceRegistry: """ Construct a Themester registry with some defaults """ registry = ServiceRegistry() # Handle the venusian scanner scanner = Scanner(registry=registry) registry.register_singleton(scanner, Scanner) # Handle the root if root is not None: registry.register_singleton(root, Root) # Handle a root factory if root_factory is not None: registry.register_factory(root_factory, Root) # Handle the theme config if theme_config is not None: registry.register_singleton(theme_config, ThemeConfig) # Scan themester factories _scan_target(scanner, factories) # Handle anything that needs to be scanned if isinstance(scannables, Sequence): for scannable in scannables: _scan_target(scanner, scannable) else: _scan_target(scanner, scannables) # Handle any plugins if isinstance(plugins, Sequence): for plugin in plugins: _setup_target(registry, scanner, plugin) else: _setup_target(registry, scanner, plugins) return registry
def setup(registry: ServiceRegistry, settings: Settings): # The French greeter, using context of FrenchCustomer punctuation = settings.punctuation def french_greeter_factory(container) -> Greeter: return FrenchGreeter(punctuation=punctuation) # Register it as a factory using its class for the "key", but # this time register with a "context" registry.register_factory(french_greeter_factory, Greeter, context=FrenchCustomer) # Grab the Datastore and add a FrenchCustomer container: ServiceContainer = registry.create_container() datastore: Datastore = container.get(Datastore) henri = FrenchCustomer(name='henri', title='Henri') datastore.customers['henri'] = henri
def setup(settings: Settings) -> ServiceRegistry: # Make the registry registry = ServiceRegistry() # Make the greeter factory, using punctuation from settings punctuation = settings.punctuation # First the default greeter, no context def default_greeter_factory(container) -> Greeter: # Use the dataclass default for greeting return Greeter(punctuation=punctuation) # Register it as a factory using its class for the "key" registry.register_factory(default_greeter_factory, Greeter) # Import the add-on and initialize it from .custom import setup setup(registry, settings) return registry
def register_view( registry: ServiceRegistry, target: Callable = None, context: Optional[Type] = None, name: Optional[str] = None, ): """ Imperative form of the view decorator """ def view_factory(container: ServiceContainer): injector = Injector(container) view_instance = injector(target) return view_instance if name is None: registry.register_factory( view_factory, View, context=context ) else: registry.register_factory( view_factory, View, context=context, name=name )
def setup(registry: ServiceRegistry, settings: Settings): """ Initialize the features in the core application """ # Make and register the Datastore datastore = Datastore() registry.register_singleton(datastore, Datastore) # **** Default Greeter # Make the greeter factory, using punctuation from settings punctuation = settings.punctuation def default_greeter_factory(container) -> Greeter: # Use the dataclass default for greeting return Greeter(punctuation=punctuation) # Register it as a factory using its class for the "key" registry.register_factory(default_greeter_factory, Greeter) # During bootstrap, make some Customers customer1 = Customer(name='Mary') datastore.customers.append(customer1)
def register_dataclass(registry: ServiceRegistry, target, for_=None, context=None): """ Generic injectory factory for dataclasses """ # The common case, for default registrations we can omit # the "for_" as it is the same as the class implementing it if for_ is None: for_ = target if getattr(target, 'wired_factory', None): # This class wants to control its factory, use that one dataclass_factory = target.wired_factory else: # Use a generic dataclass factory def dataclass_factory(c: ServiceContainer): instance = injector_construction(c, target) return instance registry.register_factory(dataclass_factory, for_, context=context)
def register_component(registry: ServiceRegistry, target: Callable, context: Type[Resource] = IResource): """ Imperative form of the component decorator """ component_name = target.__name__ def component_factory(container: ServiceContainer): def construct_component(**props): """ A partial-partial, used to collect kwargs during calling """ all_args = props.copy() # TODO Would be nice to replace this with DI once wired # supports props. # Only pass resource or view if the dataclass wants it fields = get_type_hints(target) if 'request' in fields: request: Request = container.get(Request) all_args['request'] = request if 'context' in fields: all_args['context'] = container.context if 'view' in fields: view: View = container.get(View) all_args['view'] = view component_instance = target(**all_args) return component_instance return construct_component # Use the name of the class, e.g. Breadcrumb, as the name argument # during registration registry.register_factory(component_factory, IComponent, context=context, name=component_name) # Next, add a zope.interface "subscription" to allow later reading of # all registered components adapter_registry: AdapterRegistry = registry._factories adapter_registry.subscribe([IResource], IComponent, target)
def setup(registry: ServiceRegistry, settings: Settings): """ Initialize the features in the core application """ # Make and register the Datastore singleton datastore = Datastore() registry.register_singleton(datastore, Datastore) # Context factory def context_factory(container) -> Resource: # Presumes that "url" is in the container ds: Datastore = container.get(Datastore) url: str = container.get(Url) context: Resource = ds.customers.get(url) return context registry.register_factory(context_factory, Resource) # Request factory def request_factory(container) -> Request: url: str = container.get(Url) request = Request(url=url, container=container) return request registry.register_factory(request_factory, Request) # **** Default View def view_factory(container) -> View: request: Request = container.get(Request) context: Resource = container.get(Resource) greeter: Greeter = container.get(Greeter, context=context) view = View(request=request, context=context, greeter=greeter) return view registry.register_factory(view_factory, View) # **** Default Greeter def default_greeter_factory(container) -> Greeter: # Use the dataclass default for greeting return Greeter(punctuation=settings.punctuation) # Register it as a factory using its class for the "key" registry.register_factory(default_greeter_factory, Greeter) # During bootstrap, make some Customers mary = Customer(name='mary', title='Mary') datastore.customers['mary'] = mary
def wired_setup( registry: ServiceRegistry, scanner: Scanner, ): registry.register_factory(resource_factory, Resource) scanner.scan(themester.sphinx)
def wired_setup(registry: ServiceRegistry): registry.register_factory(context_parents, IParents)
def wired_setup(registry: ServiceRegistry) -> None: registry.register_factory(all_components, IAllComponents) registry.register_factory(wrap_components, IWrapComponents)