Skip to content

Commit a9aa9e7

Browse files
gourav-kandoriaac000
authored andcommitted
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: #1106 Link: <#1336 (comment)> [ Commit message - Dan / Minor code tweaks - Andrew ] Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
1 parent d62a5e2 commit a9aa9e7

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

src/nxt_conf_validation.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,11 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = {
841841
.type = NXT_CONF_VLDT_STRING,
842842
.validator = nxt_conf_vldt_targets_exclusive,
843843
.u.string = "callable",
844+
}, {
845+
.name = nxt_string("factory"),
846+
.type = NXT_CONF_VLDT_BOOLEAN,
847+
.validator = nxt_conf_vldt_targets_exclusive,
848+
.u.string = "factory",
844849
}, {
845850
.name = nxt_string("prefix"),
846851
.type = NXT_CONF_VLDT_STRING,
@@ -865,6 +870,9 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_target_members[] = {
865870
}, {
866871
.name = nxt_string("callable"),
867872
.type = NXT_CONF_VLDT_STRING,
873+
}, {
874+
.name = nxt_string("factory"),
875+
.type = NXT_CONF_VLDT_BOOLEAN,
868876
}, {
869877
.name = nxt_string("prefix"),
870878
.type = NXT_CONF_VLDT_STRING,
@@ -883,6 +891,9 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_notargets_members[] = {
883891
}, {
884892
.name = nxt_string("callable"),
885893
.type = NXT_CONF_VLDT_STRING,
894+
}, {
895+
.name = nxt_string("factory"),
896+
.type = NXT_CONF_VLDT_BOOLEAN,
886897
}, {
887898
.name = nxt_string("prefix"),
888899
.type = NXT_CONF_VLDT_STRING,

src/python/nxt_python.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,11 +403,13 @@ nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target,
403403
char *callable, *module_name;
404404
PyObject *module, *obj;
405405
nxt_str_t str;
406+
nxt_bool_t is_factory = 0;
406407
nxt_conf_value_t *value;
407408

408409
static nxt_str_t module_str = nxt_string("module");
409410
static nxt_str_t callable_str = nxt_string("callable");
410411
static nxt_str_t prefix_str = nxt_string("prefix");
412+
static nxt_str_t factory_flag_str = nxt_string("factory");
411413

412414
module = obj = NULL;
413415

@@ -449,7 +451,30 @@ nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target,
449451
goto fail;
450452
}
451453

452-
if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
454+
value = nxt_conf_get_object_member(conf, &factory_flag_str, NULL);
455+
if (value != NULL) {
456+
is_factory = nxt_conf_get_boolean(value);
457+
}
458+
459+
if (is_factory) {
460+
if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
461+
nxt_alert(task,
462+
"factory \"%s\" in module \"%s\" "
463+
"can not be called to fetch callable",
464+
callable, module_name);
465+
goto fail;
466+
}
467+
468+
obj = PyObject_CallObject(obj, NULL);
469+
if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
470+
nxt_alert(task,
471+
"factory \"%s\" in module \"%s\" "
472+
"did not return callable object",
473+
callable, module_name);
474+
goto fail;
475+
}
476+
477+
} else if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
453478
nxt_alert(task, "\"%s\" in module \"%s\" is not a callable object",
454479
callable, module_name);
455480
goto fail;

0 commit comments

Comments
 (0)