Wsgi

Connect your application to a WSGI server.

  1. Overview
  2. application
  3. classes
  4. modules
  5. bindings
  6. additional_configs
  7. class_overrides
  8. overrides
  9. now
  10. utcnow

Overview

The Wsgi context is used to connect a clearskies application to a WSGI server of your choice. As with all contexts, you first create it and pass in the application (a callable, endpoint, or endpoint group) as well as any dependency injection parameters. Then, you call the context from inside of the function invoked by your WSGI server, passing along the environment and start_response variables, and returning the response from the context. Here’s a simple example:

import clearskies

def hello_world():
    return "Hello World!"

wsgi = clearskies.contexts.Wsgi(hello_world)

def application(environment, start_response):
    return wsgi(environment, start_response)

You would then launch your WSGI server. For instance, here’s how to launch it with uwsgi, which automatically looks for a function called application and treats that as the WSGI starting point:

uwsgi --http :9090 --wsgi-file test.py

You could then:

curl 'http://localhost:9090'

And see the response from this “hello world” app. Note than in the above example I create the context outside of the application function. Of course, you can do the opposite:

import clearskies

def hello_world():
    return "Hello World!"

def application(environment, start_response):
    wsgi = clearskies.contexts.Wsgi(hello_world)
    return wsgi(environment, start_response)

The difference is that most wsgi servers will cache any objects created outside of the handler function (e.g. application in this case). When you first create the context clearskies will configure and validate any endpoints attached. Also, it will create an instance of the dependency injection container and cache it. If the context object is created outside of the handler, and the server caches objects in this csae, then this validation will only happen once and the DI cache will store objects in between HTTP calls. If you create your context inside the handler function, then you’ll end up with an empty cache everytime and you’ll have slower responses because of clearskies checking the application configuration everytime. Note that the DI system for clearskies grants you full cache control, so by and large it’s normal and expected that you’ll persist the cache between requests by creating the context outside of any handler functions.

application

Required

The application to execute.

This can be a callable, an endpoint, or an endpoint group. If passed a callable, the callable can request any standard or defined dependencies and should return the desired response. It can also raise any exception from clearskies.exceptions.

classes

Optional

Record any class that should be made available for injection.

All classes that come in here become available via their injection name, which is calculated by converting the class name from TitleCase to snake_case. e.g. the following class:

class MyClass:
    pass

gets an injection name of my_class. Also, clearskies will only resolve and reject based on type hints if those classes are first added via add_classes. See the following example:

from clearskies.di import Di

class MyClass:
    name = "Simple Demo"

di = Di(classes=[MyClass])
# equivalent: di.add_classes(MyClass), di.add_classes([MyClass])

def my_function(my_class):
    print(my_class.name)

def my_function_with_type_hinting(the_name_no_longer_matters: MyClass):
    print(my-class.name)

# both print 'Simple Demo'
di.call_function(my_function)
di.call_function(my_function_with_type_hinting)

modules

Optional

Add a module to the dependency injection container.

clearskies will iterate through the module, adding all imported classes into the dependency injection container.

So, consider the following file structure inside a module:

my_module/
    __init__.py
    my_sub_module/
        __init__.py
        my_class.py

Assuming that the submodule and class are imported at each level (e.g. my_module/init.py imports my_sub_module, and my_sub_module/init.py imports my_class.py) then you can:

from clearksies.di import Di
import my_module

di = Di()
di.add_modules([
    my_module
])  # also equivalent: di.add_modules(my_module), or Di(modules=[my_module])


def my_function(my_class):
    pass


di.call_function(my_function)

my_function will be called and my_class will automatically be populated with an instance of my_module.sub_module.my_class.MyClass.

Note that MyClass will be able to declare its own dependencies per normal dependency injection rules. See the main docblock in the clearskies.di.Di class for more details about how all the pieces work together.

bindings

Optional

Provide a specific value for name-based injection.

This method attaches a value to a specific dependency injection name.

import clearskies.di

di = clearskies.di.Di()
di.add_binding("my_name", 12345)
# equivalent:
# di = clearskies.di.Di(bindings={"my_name": 12345})


def my_function(my_name):
    print(my_name)  # prints 12345


di.call_function(my_function)

additional_configs

Optional

Add an additional config instance to the dependency injection container.

Additional config class provide an additional way to provide dependencies into the dependency injection system. For more details about how to use them, see both base classes:

  1. clearskies.di.additional_config.AdditionalConfig
  2. clearskies.di.additional_config_auto_import.AdditionalConfigAutoImport

To use this method:

import clearskies.di


class MyConfig(clearskies.di.AdditionalConfig):
    def provide_some_value(self):
        return 2

    def provide_another_value(self, some_value):
        return some_value * 2


di = clearskies.di.Di()
di.add_additional_configs([MyConfig()])
# equivalents:
# di.add_additional_configs(MyConfig())
# di = clearskies.di.Di(additional_configs=[MyConfig()])


def my_function(another_value):
    print(another_value)  # prints 4


di.call_function(my_function)

class_overrides

Optional

Override a class for type-based injection.

This function allows you to replace/mock class provided when relying on type hinting for injection. This is most often (but not exclusively) used for mocking out classes during texting. Note that this only overrides that specific class - not classes that extend it.

Example:

from clearskies.import Di

class TypeHintedClass:
    my_value = 5

class ReplacementClass:
    my_value = 10

di = Di()
di.add_classes(TypeHintedClass)
di.add_class_override(TypeHintedClass, ReplacementClass)
# also di = Di(class_overrides={TypeHintedClass: ReplacementClass})

def my_function(some_value: TypeHintedClass):
    print(some_value.my_value) # prints 10

di.call_function(my_function)

overrides

Optional

now

Optional

Set the current time which will be passed along to any dependency arguments named now.

utcnow

Optional