python: Support application factories
Adds support for the app factory pattern to the Python language module. A factory is a callable that returns a WSGI or ASGI application object. Unit does not support passing arguments to factories. Setting the `factory` option to `true` instructs Unit to treat the configured `callable` as a factory. For example: "my-app": { "type": "python", "path": "/srv/www/", "module": "hello", "callable": "create_app", "factory": true } This is similar to other WSGI / ASGI servers. E.g., $ uvicorn --factory hello:create_app $ gunicorn 'hello:create_app()' The factory setting defaults to false. Closes: https://github.com/nginx/unit/issues/1106 Link: <https://github.com/nginx/unit/pull/1336#issuecomment-2179381605> [ Commit message - Dan / Minor code tweaks - Andrew ] Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
This commit is contained in:
parent
d62a5e2c37
commit
a9aa9e76db
2 changed files with 37 additions and 1 deletions
|
@ -841,6 +841,11 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = {
|
|||
.type = NXT_CONF_VLDT_STRING,
|
||||
.validator = nxt_conf_vldt_targets_exclusive,
|
||||
.u.string = "callable",
|
||||
}, {
|
||||
.name = nxt_string("factory"),
|
||||
.type = NXT_CONF_VLDT_BOOLEAN,
|
||||
.validator = nxt_conf_vldt_targets_exclusive,
|
||||
.u.string = "factory",
|
||||
}, {
|
||||
.name = nxt_string("prefix"),
|
||||
.type = NXT_CONF_VLDT_STRING,
|
||||
|
@ -865,6 +870,9 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_target_members[] = {
|
|||
}, {
|
||||
.name = nxt_string("callable"),
|
||||
.type = NXT_CONF_VLDT_STRING,
|
||||
}, {
|
||||
.name = nxt_string("factory"),
|
||||
.type = NXT_CONF_VLDT_BOOLEAN,
|
||||
}, {
|
||||
.name = nxt_string("prefix"),
|
||||
.type = NXT_CONF_VLDT_STRING,
|
||||
|
@ -883,6 +891,9 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_notargets_members[] = {
|
|||
}, {
|
||||
.name = nxt_string("callable"),
|
||||
.type = NXT_CONF_VLDT_STRING,
|
||||
}, {
|
||||
.name = nxt_string("factory"),
|
||||
.type = NXT_CONF_VLDT_BOOLEAN,
|
||||
}, {
|
||||
.name = nxt_string("prefix"),
|
||||
.type = NXT_CONF_VLDT_STRING,
|
||||
|
|
|
@ -403,11 +403,13 @@ nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target,
|
|||
char *callable, *module_name;
|
||||
PyObject *module, *obj;
|
||||
nxt_str_t str;
|
||||
nxt_bool_t is_factory = 0;
|
||||
nxt_conf_value_t *value;
|
||||
|
||||
static nxt_str_t module_str = nxt_string("module");
|
||||
static nxt_str_t callable_str = nxt_string("callable");
|
||||
static nxt_str_t prefix_str = nxt_string("prefix");
|
||||
static nxt_str_t factory_flag_str = nxt_string("factory");
|
||||
|
||||
module = obj = NULL;
|
||||
|
||||
|
@ -449,7 +451,30 @@ nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
value = nxt_conf_get_object_member(conf, &factory_flag_str, NULL);
|
||||
if (value != NULL) {
|
||||
is_factory = nxt_conf_get_boolean(value);
|
||||
}
|
||||
|
||||
if (is_factory) {
|
||||
if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
|
||||
nxt_alert(task,
|
||||
"factory \"%s\" in module \"%s\" "
|
||||
"can not be called to fetch callable",
|
||||
callable, module_name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
obj = PyObject_CallObject(obj, NULL);
|
||||
if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
|
||||
nxt_alert(task,
|
||||
"factory \"%s\" in module \"%s\" "
|
||||
"did not return callable object",
|
||||
callable, module_name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
} else if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
|
||||
nxt_alert(task, "\"%s\" in module \"%s\" is not a callable object",
|
||||
callable, module_name);
|
||||
goto fail;
|
||||
|
|
Loading…
Reference in a new issue