Python: multiple values in the "path" option.
This commit is contained in:
@@ -9,6 +9,12 @@
|
|||||||
date="" time=""
|
date="" time=""
|
||||||
packager="Andrei Belov <defan@nginx.com>">
|
packager="Andrei Belov <defan@nginx.com>">
|
||||||
|
|
||||||
|
<change type="feature">
|
||||||
|
<para>
|
||||||
|
ability to specify multiple directories in the "path" option of Python apps.
|
||||||
|
</para>
|
||||||
|
</change>
|
||||||
|
|
||||||
<change type="bugfix">
|
<change type="bugfix">
|
||||||
<para>
|
<para>
|
||||||
invalid HTTP responses were generated for some unusual status codes.
|
invalid HTTP responses were generated for some unusual status codes.
|
||||||
|
|||||||
@@ -47,13 +47,13 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *home;
|
char *home;
|
||||||
nxt_str_t path;
|
nxt_conf_value_t *path;
|
||||||
nxt_str_t module;
|
nxt_str_t module;
|
||||||
char *callable;
|
char *callable;
|
||||||
nxt_str_t protocol;
|
nxt_str_t protocol;
|
||||||
uint32_t threads;
|
uint32_t threads;
|
||||||
uint32_t thread_stack_size;
|
uint32_t thread_stack_size;
|
||||||
} nxt_python_app_conf_t;
|
} nxt_python_app_conf_t;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,10 @@ static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt,
|
|||||||
nxt_conf_value_t *value, void *data);
|
nxt_conf_value_t *value, void *data);
|
||||||
static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt,
|
static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt,
|
||||||
nxt_conf_value_t *value, void *data);
|
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,
|
static nxt_int_t nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
|
||||||
nxt_conf_value_t *value, void *data);
|
nxt_conf_value_t *value, void *data);
|
||||||
static nxt_int_t nxt_conf_vldt_threads(nxt_conf_validation_t *vldt,
|
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,
|
.type = NXT_CONF_VLDT_STRING,
|
||||||
}, {
|
}, {
|
||||||
.name = nxt_string("path"),
|
.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"),
|
.name = nxt_string("module"),
|
||||||
.type = NXT_CONF_VLDT_STRING,
|
.type = NXT_CONF_VLDT_STRING,
|
||||||
@@ -1376,6 +1381,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
|
static nxt_int_t
|
||||||
nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
|
nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt,
|
||||||
nxt_conf_value_t *value, void *data)
|
nxt_conf_value_t *value, void *data)
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ static nxt_conf_map_t nxt_python_app_conf[] = {
|
|||||||
|
|
||||||
{
|
{
|
||||||
nxt_string("path"),
|
nxt_string("path"),
|
||||||
NXT_CONF_MAP_STR,
|
NXT_CONF_MAP_PTR,
|
||||||
offsetof(nxt_common_app_conf_t, u.python.path),
|
offsetof(nxt_common_app_conf_t, u.python.path),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ typedef struct {
|
|||||||
|
|
||||||
static nxt_int_t nxt_python_start(nxt_task_t *task,
|
static nxt_int_t nxt_python_start(nxt_task_t *task,
|
||||||
nxt_process_data_t *data);
|
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_init_threads(nxt_python_app_conf_t *c);
|
||||||
static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx);
|
static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx);
|
||||||
static void *nxt_python_thread_func(void *main_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;
|
int rc;
|
||||||
char *nxt_py_module;
|
char *nxt_py_module;
|
||||||
size_t len;
|
size_t len;
|
||||||
PyObject *obj, *pypath, *module;
|
PyObject *obj, *module;
|
||||||
nxt_str_t proto;
|
nxt_str_t proto;
|
||||||
const char *callable;
|
const char *callable;
|
||||||
nxt_unit_ctx_t *unit_ctx;
|
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");
|
nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush");
|
||||||
|
|
||||||
|
/* obj is a Borrowed reference. */
|
||||||
|
obj = NULL;
|
||||||
|
|
||||||
if (nxt_slow_path(nxt_py_stderr_flush == NULL)) {
|
if (nxt_slow_path(nxt_py_stderr_flush == NULL)) {
|
||||||
nxt_alert(task, "Python failed to get \"flush\" attribute of "
|
nxt_alert(task, "Python failed to get \"flush\" attribute of "
|
||||||
"\"sys.stderr\" object");
|
"\"sys.stderr\" object");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obj is a Borrowed reference. */
|
if (nxt_slow_path(nxt_python_set_path(task, c->path) != NXT_OK)) {
|
||||||
|
goto fail;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = Py_BuildValue("[s]", "unit");
|
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
|
static int
|
||||||
nxt_python_init_threads(nxt_python_app_conf_t *c)
|
nxt_python_init_threads(nxt_python_app_conf_t *c)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user