示例#1
0
def test_basic(registry: ServiceRegistry, container: ServiceContainer):
    register_dataclass(registry, DummyGreeter)
    register_dataclass(registry, DummyCustomer)
    greeter: DummyGreeter = container.get(DummyGreeter)
    customer: DummyCustomer = container.get(DummyCustomer)
    assert 'dummy_greeter' == greeter.name
    assert 'dummy_customer' == customer.name
def make_context(
        container: ServiceContainer,
        component_name: str,
        **kwargs
) -> Dict[str, Any]:
    """ Make component fields, other info into dict for template context """

    from wired_components.component import IWrapComponents, IComponent

    # Start with all the wrapped components
    context: Dict[str, Any] = container.get(IWrapComponents)

    # We get the component again in case there are multiple components
    # registered with the same name, but for more specific contexts.
    component_factory = container.get(IComponent, name=component_name)

    # TODO Try to replace this part with DI+props in wired.components
    #   (see above in component_factory)
    component_instance = component_factory(**kwargs)

    # Copy all the fields into the context dict
    for field in dataclasses.fields(component_instance):
        context[field.name] = getattr(component_instance, field.name)

    return context
示例#3
0
 def wired_factory(container: ServiceContainer) -> Resource:
     """ Custom factory that gets a Datastore instance """
     # Presumes that "url" is in the container
     ds: Datastore = container.get(Datastore)
     url: Url = container.get(Url)
     context: Resource = ds.customers.get(url.value)
     return context
示例#4
0
def resource_factory(container: ServiceContainer) -> Resource:
    # Get dependencies
    root: Root = container.get(Root)
    page_context: PageContext = container.get(PageContext)

    # Extract what's needed and make a resource
    document_metadata: Dict[str, Any] = page_context.meta
    this_rtype = document_metadata.get('type', 'document')
    resource = root if this_rtype == 'homepage' else Document(
        name=page_context.pagename, parent=root, title=page_context.title)
    return resource
示例#5
0
 def resolved(
     self,
     container: ServiceContainer,
     obj: Any = None,
     namespace: Optional[Mapping[Text, Any]] = None,
 ) -> Any:
     params = {}
     if self.context:
         if self.context is FROM_SELF:
             assert obj
             params["context"] = obj
         elif isinstance(self.context, FromNamespace):
             assert namespace
             params["context"] = namespace[self.context.name]
         elif isinstance(self.context, FromProperty):
             assert obj
             params["context"] = getattr(obj, self.context.name)
     if self.name:
         if isinstance(self.name, FromNamespace):
             assert namespace
             params["name"] = namespace[self.name.name]
         elif isinstance(self.name, FromProperty):
             assert obj
             params["name"] = getattr(obj, self.name.name)
         else:
             params["name"] = self.name
     return container.get(self.iface_or_type, **params)
def test_view_decorator_function(
    registry: ServiceRegistry,
    view_container: ServiceContainer,
    simple_root,
    interface,
):
    # Test a view registered for all resources
    from wired_components.view import IView, View, register_view

    @dataclass
    class SomeView(View):
        flag: int = 99

    if interface == 'ignore':
        # Simulate omitting the ``context=`` argument
        register_view(registry, SomeView)
    else:
        register_view(registry, SomeView, context=interface)

    # Get the view from the container
    view: SomeView = view_container.get(IView)

    # Assert some things
    assert isinstance(view, View)
    assert view.flag == 99
示例#7
0
 def injectable_factory(container: ServiceContainer):
     if use_props:
         # Just return the target, it will be
         # constructed when the props are available
         return target
     else:
         injector = container.get(Injector)
         instance = injector(target)
         return instance
示例#8
0
def customer_interaction(container: ServiceContainer,
                         customer: Customer) -> str:
    """ Customer comes in, handle the steps in greeting them """

    # Get a Greeter using the customer as context. Use the Customer when
    # generating the greeting.
    greeter: Greeter = container.get(Greeter, context=customer)
    greeting = greeter(customer)

    return greeting
示例#9
0
    def __call__(self, previous: Paths, container: ServiceContainer) -> Paths:
        # Get the pathto service from the PageContext
        page_context = container.get(PageContext)
        pathto: Callable[[str, int], str] = getattr(page_context, 'pathto')

        # Handle a single item differently than a list
        if type(previous) in [list, tuple]:
            return tuple(
                [pathto(this_previous, 1) for this_previous in previous])
        else:
            return pathto(previous, 1)
示例#10
0
def injector_construction(container: ServiceContainer, target):
    """ Introspect dataclass and get arguments from container """

    # Make the args dict that we will construct dataclass with
    args = {}

    # Iterate through the dataclass fields
    for field_name, field_type in get_type_hints(target).items():
        if field_type != str:
            args[field_name] = container.get(field_type)

    # Now construct an instance of the target dataclass
    return target(**args)
示例#11
0
    def __call__(self, previous: Type, container: ServiceContainer):
        try:
            service = container.get(self.lookup_type)
            if isclass(service):
                # This "service" is actually injectable, instead of
                # a plain factory. At the moment, we just have a class.
                # Use this injector instance to turn it into an instance.
                from wired_injector import Injector

                injector = container.get(Injector)
                service = injector(service)
            if self.attr is None:
                return service
            else:
                return getattr(service, self.attr)
        except LookupError:
            # We don't want to just crash with a LookupError, as the
            # field might have a default. Thus, bail out of processing
            # the pipeline.
            from wired_injector.injector import SkipField

            raise SkipField()
示例#12
0
def render_component(container: ServiceContainer, component_name: str,
                     **kwargs) -> Markup:
    # Get the context for the template
    context = make_context(container, component_name, **kwargs)

    # Get the template
    template_name = f'{component_name.lower()}.jinja2'

    # Get the renderer
    renderer: JinjaRenderer = container.get(IJinjaRenderer)

    # Render and return
    m = renderer.render(context, template_name, container=container)
    return m
示例#13
0
    def render(self, context: Dict, template_name: str,
               container: ServiceContainer) -> Markup:
        """ Given a dataclass, flatten it and render with jinja2 template """

        # Always put the wrapped components into the template context
        from ..component import IWrapComponents
        wrapped_components: Dict[str, Type] = container.get(IWrapComponents)

        context.update(wrapped_components)

        template: Template = self.environment.get_or_select_template(
            template_name)
        result = template.render(**context)
        m = Markup(result)
        return m
def wrap_components(container: ServiceContainer, ) -> Dict[str, Callable]:
    """ Wrap component rendering with a partial to gain access to container

    """

    # Get all the components, from the container
    components: Dict[str, Any] = container.get(IAllComponents)

    # For each, wrap them in a partial that contains the container
    return {
        component_name: partial(
            render_component,
            component_name=component_name,
            container=container,
        )
        for component_name, component in components.items()
    }
示例#15
0
def copy_theme_resources(container: ServiceContainer, app: Sphinx):
    ctr: CopyThemeResources = container.get(CopyThemeResources)
    static_outdir = Path(app.outdir) / '_static'
    ctr(copy_asset, static_outdir)
示例#16
0
def injector_construction(container: ServiceContainer, target):
    """ Introspect dataclass and get arguments from container """

    from .models import Resource, Url, Settings

    if target in (Url, Settings):
        # Don't need to construct this one from a dataclass,
        # it's a singleton the container
        instance = container.get(target)
        return instance

    # Make the args dict that we will construct dataclass with
    args = {}

    # Get the context from the container
    context: Resource = container.get(Resource)

    # Iterate through the dataclass fields
    # Because fields() gives a string for the type, instead of the
    # actual type, let's get a mapping of field name -> field type
    fields_mapping = {f.name: f for f in fields(target)}

    # Now we can iterate over the fields using type hints
    for field_name, field_type in get_type_hints(target).items():

        # Do some special cases first
        if field_type == ServiceContainer:
            # Doing this style of bailing out quickly for performance
            # reasons. Don't want to keep doing "if", though it
            # means some repetitions.
            args[field_name] = container
            continue

        # See if this field is using the injectable field, e.g.
        # url: str = injected(Url, attr='value')
        full_field: Field = fields_mapping[field_name]
        if full_field.metadata.get('injected', False):
            injected_info = full_field.metadata['injected']
            injected_attr = injected_info['attr']
            injected_type = injected_info['type_']
            # Ask the registry for one of these
            injected_target = container.get(injected_type, context=context)
            # Get the specified attribute off that instance
            field_value = getattr(injected_target, injected_attr)
            args[field_name] = field_value
            continue

        # Now the general case, something like url: Url
        try:
            field_value = container.get(field_type, context=context)
            args[field_name] = field_value
        except TypeError:
            # Seems that wired, when looking up str, gives:
            # TypeError: can't set attributes of built-in/extension type 'str'
            # We will use that to our advantage to look for a dataclass
            # field default value.
            field_default = getattr(full_field, 'default', None)
            if field_default:
                args[field_name] = field_default
                continue
            else:
                raise LookupError()
        except LookupError:
            # Give up and work around ``wired`` unhelpful exception
            # by adding some context information.
            msg = f'Injector failed for {field_name} on {target.__name__}'
            raise LookupError(msg)

    # Now construct an instance of the target dataclass
    return target(**args)
示例#17
0
def context_parents(container: ServiceContainer) -> Parents:
    context: Resource = container.get(Context)
    p = parents(context)
    return p
示例#18
0
 def factory(container: ServiceContainer) -> 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
示例#19
0
 def factory(container: ServiceContainer) -> Request:
     url: str = container.get(Url)
     request = Request(url=url, container=container)
     return request
示例#20
0
 def factory(container: ServiceContainer) -> 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
示例#21
0
 def __init__(self, container: ServiceContainer):
     self.greeter = container.get(Greeter)
示例#22
0
 def __call__(self, previous: DC, container: ServiceContainer) -> Dict:
     # Either use the value to the left, or if provided an argument,
     # look it up
     if self.lookup_type is not None:
         previous = container.get(self.lookup_type)
     return asdict(previous)
示例#23
0
def greeting_factory(container: ServiceContainer):
    greeter = container.get(Greeter)
    return Greeting(greeter)
 def target(container: ServiceContainer):
     view = container.get(View)
     return view