summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2020-12-22 17:53:41 +0300
committerValentin Bartenev <vbart@nginx.com>2020-12-22 17:53:41 +0300
commitcac762ab7ef22798d0f1d0813201c0018bd589a1 (patch)
treead094a56c7018f230ab8b83dd40085e41adb2280
parent65295c81413cff75eddef2845f09159711e553df (diff)
downloadunit-cac762ab7ef22798d0f1d0813201c0018bd589a1.tar.gz
unit-cac762ab7ef22798d0f1d0813201c0018bd589a1.tar.bz2
Python: multiple values in the "path" option.
-rw-r--r--docs/changes.xml6
-rw-r--r--src/nxt_application.h14
-rw-r--r--src/nxt_conf_validation.c35
-rw-r--r--src/nxt_main_process.c2
-rw-r--r--src/python/nxt_python.c103
5 files changed, 124 insertions, 36 deletions
diff --git a/docs/changes.xml b/docs/changes.xml
index 6bd30cab..db7a2799 100644
--- a/docs/changes.xml
+++ b/docs/changes.xml
@@ -9,6 +9,12 @@
date="" time=""
packager="Andrei Belov &lt;defan@nginx.com&gt;">
+<change type="feature">
+<para>
+ability to specify multiple directories in the "path" option of Python apps.
+</para>
+</change>
+
<change type="bugfix">
<para>
invalid HTTP responses were generated for some unusual status codes.
diff --git a/src/nxt_application.h b/src/nxt_application.h
index 5632f56f..632c5632 100644
--- a/src/nxt_application.h
+++ b/src/nxt_application.h
@@ -47,13 +47,13 @@ typedef struct {
typedef struct {
- char *home;
- nxt_str_t path;
- nxt_str_t module;
- char *callable;
- nxt_str_t protocol;
- uint32_t threads;
- uint32_t thread_stack_size;
+ char *home;
+ nxt_conf_value_t *path;
+ nxt_str_t module;
+ char *callable;
+ nxt_str_t protocol;
+ uint32_t threads;
+ uint32_t thread_stack_size;
} nxt_python_app_conf_t;
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index acb2e3de..67fa3095 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -96,6 +96,10 @@ static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
+static nxt_int_t nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data);
+static nxt_int_t nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_threads(nxt_conf_validation_t *vldt,
@@ -491,7 +495,8 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = {
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("path"),
- .type = NXT_CONF_VLDT_STRING,
+ .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
+ .validator = nxt_conf_vldt_python_path,
}, {
.name = nxt_string("module"),
.type = NXT_CONF_VLDT_STRING,
@@ -1377,6 +1382,34 @@ nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
static nxt_int_t
+nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data)
+{
+ if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
+ return nxt_conf_vldt_array_iterator(vldt, value,
+ &nxt_conf_vldt_python_path_element);
+ }
+
+ /* NXT_CONF_STRING */
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
+nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value)
+{
+ if (nxt_conf_type(value) != NXT_CONF_STRING) {
+ return nxt_conf_vldt_error(vldt, "The \"path\" array must contain "
+ "only string values.");
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data)
{
diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c
index 0cde435b..2916f0ab 100644
--- a/src/nxt_main_process.c
+++ b/src/nxt_main_process.c
@@ -182,7 +182,7 @@ static nxt_conf_map_t nxt_python_app_conf[] = {
{
nxt_string("path"),
- NXT_CONF_MAP_STR,
+ NXT_CONF_MAP_PTR,
offsetof(nxt_common_app_conf_t, u.python.path),
},
diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c
index faf0c0e1..d8204937 100644
--- a/src/python/nxt_python.c
+++ b/src/python/nxt_python.c
@@ -24,6 +24,7 @@ typedef struct {
static nxt_int_t nxt_python_start(nxt_task_t *task,
nxt_process_data_t *data);
+static nxt_int_t nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value);
static int nxt_python_init_threads(nxt_python_app_conf_t *c);
static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx);
static void *nxt_python_thread_func(void *main_ctx);
@@ -67,7 +68,7 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
int rc;
char *nxt_py_module;
size_t len;
- PyObject *obj, *pypath, *module;
+ PyObject *obj, *module;
nxt_str_t proto;
const char *callable;
nxt_unit_ctx_t *unit_ctx;
@@ -162,38 +163,18 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
}
nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush");
+
+ /* obj is a Borrowed reference. */
+ obj = NULL;
+
if (nxt_slow_path(nxt_py_stderr_flush == NULL)) {
nxt_alert(task, "Python failed to get \"flush\" attribute of "
"\"sys.stderr\" object");
goto fail;
}
- /* obj is a Borrowed reference. */
-
- if (c->path.length > 0) {
- obj = PyString_FromStringAndSize((char *) c->path.start,
- c->path.length);
-
- if (nxt_slow_path(obj == NULL)) {
- nxt_alert(task, "Python failed to create string object \"%V\"",
- &c->path);
- goto fail;
- }
-
- pypath = PySys_GetObject((char *) "path");
-
- if (nxt_slow_path(pypath == NULL)) {
- nxt_alert(task, "Python failed to get \"sys.path\" list");
- goto fail;
- }
-
- if (nxt_slow_path(PyList_Insert(pypath, 0, obj) != 0)) {
- nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"",
- &c->path);
- goto fail;
- }
-
- Py_DECREF(obj);
+ if (nxt_slow_path(nxt_python_set_path(task, c->path) != NXT_OK)) {
+ goto fail;
}
obj = Py_BuildValue("[s]", "unit");
@@ -317,6 +298,74 @@ fail:
}
+static nxt_int_t
+nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value)
+{
+ int ret;
+ PyObject *path, *sys;
+ nxt_str_t str;
+ nxt_uint_t n;
+ nxt_conf_value_t *array;
+
+ if (value == NULL) {
+ return NXT_OK;
+ }
+
+ sys = PySys_GetObject((char *) "path");
+ if (nxt_slow_path(sys == NULL)) {
+ nxt_alert(task, "Python failed to get \"sys.path\" list");
+ return NXT_ERROR;
+ }
+
+ /* sys is a Borrowed reference. */
+
+ if (nxt_conf_type(value) == NXT_CONF_STRING) {
+ n = 0;
+ goto value_is_string;
+ }
+
+ /* NXT_CONF_ARRAY */
+ array = value;
+
+ n = nxt_conf_array_elements_count(array);
+
+ while (n != 0) {
+ n--;
+
+ /*
+ * Insertion in front of existing paths starting from the last element
+ * to preserve original order while giving priority to the values
+ * specified in the "path" option.
+ */
+
+ value = nxt_conf_get_array_element(array, n);
+
+ value_is_string:
+
+ nxt_conf_get_string(value, &str);
+
+ path = PyString_FromStringAndSize((char *) str.start, str.length);
+ if (nxt_slow_path(path == NULL)) {
+ nxt_alert(task, "Python failed to create string object \"%V\"",
+ &str);
+ return NXT_ERROR;
+ }
+
+ ret = PyList_Insert(sys, 0, path);
+
+ Py_DECREF(path);
+
+ if (nxt_slow_path(ret != 0)) {
+ nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"",
+ &str);
+ return NXT_ERROR;
+ }
+ }
+
+ return NXT_OK;
+}
+
+
static int
nxt_python_init_threads(nxt_python_app_conf_t *c)
{