2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2010-09-01 14:13:48 +00:00
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
2011-10-23 17:52:20 +00:00
|
|
|
*/
|
2010-09-01 14:13:48 +00:00
|
|
|
|
2011-02-27 20:10:08 +00:00
|
|
|
/** \file blender/python/generic/py_capi_utils.c
|
|
|
|
* \ingroup pygen
|
2011-11-05 08:40:07 +00:00
|
|
|
*
|
|
|
|
* Extend upon CPython's API, filling in some gaps, these functions use PyC_
|
|
|
|
* prefix to distinguish them apart from CPython.
|
|
|
|
*
|
|
|
|
* \note
|
|
|
|
* This module should only depend on CPython, however it currently uses
|
|
|
|
* BLI_string_utf8() for unicode conversion.
|
2011-02-27 20:10:08 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
#include <Python.h>
|
2011-02-22 07:57:18 +00:00
|
|
|
#include <frameobject.h>
|
2011-02-14 04:15:25 +00:00
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
#include "py_capi_utils.h"
|
|
|
|
|
2012-02-05 02:04:26 +00:00
|
|
|
/* only for BLI_strncpy_wchar_from_utf8, should replace with py funcs but too late in release now */
|
|
|
|
#include "BLI_string_utf8.h"
|
2011-04-18 08:27:50 +00:00
|
|
|
|
2011-04-18 10:18:35 +00:00
|
|
|
#ifdef _WIN32 /* BLI_setenv */
|
|
|
|
#include "BLI_path_util.h"
|
|
|
|
#endif
|
|
|
|
|
2011-06-17 05:45:46 +00:00
|
|
|
/* array utility function */
|
2012-02-05 02:04:26 +00:00
|
|
|
int PyC_AsArray(void *array, PyObject *value, const Py_ssize_t length,
|
|
|
|
const PyTypeObject *type, const short is_double, const char *error_prefix)
|
2011-06-17 05:45:46 +00:00
|
|
|
{
|
|
|
|
PyObject *value_fast;
|
2012-02-05 02:04:26 +00:00
|
|
|
Py_ssize_t value_len;
|
|
|
|
Py_ssize_t i;
|
2011-06-17 05:45:46 +00:00
|
|
|
|
2012-03-03 22:07:58 +00:00
|
|
|
if (!(value_fast = PySequence_Fast(value, error_prefix))) {
|
2011-06-17 05:45:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-03 22:07:58 +00:00
|
|
|
value_len = PySequence_Fast_GET_SIZE(value_fast);
|
2011-06-17 05:45:46 +00:00
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (value_len != length) {
|
2011-06-17 05:45:46 +00:00
|
|
|
Py_DECREF(value);
|
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
"%.200s: invalid sequence length. expected %d, got %d",
|
|
|
|
error_prefix, length, value_len);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for each type */
|
2011-10-13 01:29:08 +00:00
|
|
|
if (type == &PyFloat_Type) {
|
|
|
|
if (is_double) {
|
2012-03-16 21:39:56 +00:00
|
|
|
double *array_double = array;
|
|
|
|
for (i = 0; i < length; i++) {
|
2012-03-03 22:07:58 +00:00
|
|
|
array_double[i] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value_fast, i));
|
2011-06-17 05:45:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-03-16 21:39:56 +00:00
|
|
|
float *array_float = array;
|
|
|
|
for (i = 0; i < length; i++) {
|
2012-03-03 22:07:58 +00:00
|
|
|
array_float[i] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value_fast, i));
|
2011-06-17 05:45:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-10-13 01:29:08 +00:00
|
|
|
else if (type == &PyLong_Type) {
|
2011-06-17 05:45:46 +00:00
|
|
|
/* could use is_double for 'long int' but no use now */
|
2012-03-16 21:39:56 +00:00
|
|
|
int *array_int = array;
|
|
|
|
for (i = 0; i < length; i++) {
|
2012-03-03 22:07:58 +00:00
|
|
|
array_int[i] = PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value_fast, i));
|
2011-06-17 05:45:46 +00:00
|
|
|
}
|
|
|
|
}
|
2011-10-13 01:29:08 +00:00
|
|
|
else if (type == &PyBool_Type) {
|
2012-03-16 21:39:56 +00:00
|
|
|
int *array_bool = array;
|
|
|
|
for (i = 0; i < length; i++) {
|
2012-03-03 22:07:58 +00:00
|
|
|
array_bool[i] = (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value_fast, i)) != 0);
|
2011-06-17 05:45:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Py_DECREF(value_fast);
|
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
"%s: internal error %s is invalid",
|
|
|
|
error_prefix, type->tp_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_DECREF(value_fast);
|
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (PyErr_Occurred()) {
|
2011-06-17 05:45:46 +00:00
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
"%s: one or more items could not be used as a %s",
|
|
|
|
error_prefix, type->tp_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
/* for debugging */
|
2011-09-28 05:53:40 +00:00
|
|
|
void PyC_ObSpit(const char *name, PyObject *var)
|
|
|
|
{
|
2010-09-01 14:13:48 +00:00
|
|
|
fprintf(stderr, "<%s> : ", name);
|
2012-03-16 21:39:56 +00:00
|
|
|
if (var == NULL) {
|
2010-09-01 14:13:48 +00:00
|
|
|
fprintf(stderr, "<NIL>");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PyObject_Print(var, stderr, 0);
|
|
|
|
fprintf(stderr, " ref:%d ", (int)var->ob_refcnt);
|
|
|
|
fprintf(stderr, " ptr:%p", (void *)var);
|
|
|
|
|
|
|
|
fprintf(stderr, " type:");
|
2011-10-13 01:29:08 +00:00
|
|
|
if (Py_TYPE(var))
|
2010-09-01 14:13:48 +00:00
|
|
|
fprintf(stderr, "%s", Py_TYPE(var)->tp_name);
|
|
|
|
else
|
|
|
|
fprintf(stderr, "<NIL>");
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
2011-09-28 05:53:40 +00:00
|
|
|
void PyC_LineSpit(void)
|
|
|
|
{
|
2011-03-25 04:36:10 +00:00
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
const char *filename;
|
|
|
|
int lineno;
|
|
|
|
|
2011-03-25 04:36:10 +00:00
|
|
|
/* Note, allow calling from outside python (RNA) */
|
2011-10-13 01:29:08 +00:00
|
|
|
if (!PYC_INTERPRETER_ACTIVE) {
|
2011-03-25 04:36:10 +00:00
|
|
|
fprintf(stderr, "python line lookup failed, interpreter inactive\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
PyErr_Clear();
|
|
|
|
PyC_FileAndNum(&filename, &lineno);
|
|
|
|
|
|
|
|
fprintf(stderr, "%s:%d\n", filename, lineno);
|
|
|
|
}
|
|
|
|
|
2012-07-19 09:55:49 +00:00
|
|
|
void PyC_StackSpit(void)
|
|
|
|
{
|
|
|
|
/* Note, allow calling from outside python (RNA) */
|
|
|
|
if (!PYC_INTERPRETER_ACTIVE) {
|
|
|
|
fprintf(stderr, "python line lookup failed, interpreter inactive\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* lame but handy */
|
|
|
|
PyGILState_STATE gilstate = PyGILState_Ensure();
|
|
|
|
PyRun_SimpleString("__import__('traceback').print_stack()");
|
|
|
|
PyGILState_Release(gilstate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
void PyC_FileAndNum(const char **filename, int *lineno)
|
|
|
|
{
|
2011-02-22 07:57:18 +00:00
|
|
|
PyFrameObject *frame;
|
2010-09-01 14:13:48 +00:00
|
|
|
|
2012-03-26 06:55:09 +00:00
|
|
|
if (filename) *filename = NULL;
|
|
|
|
if (lineno) *lineno = -1;
|
2011-02-22 07:57:18 +00:00
|
|
|
|
2012-03-16 21:39:56 +00:00
|
|
|
if (!(frame = PyThreadState_GET()->frame)) {
|
2010-09-01 14:13:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-02-22 07:57:18 +00:00
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
/* when executing a script */
|
|
|
|
if (filename) {
|
2011-02-22 07:57:18 +00:00
|
|
|
*filename = _PyUnicode_AsString(frame->f_code->co_filename);
|
2010-09-01 14:13:48 +00:00
|
|
|
}
|
2011-02-22 07:57:18 +00:00
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
/* when executing a module */
|
2011-10-13 01:29:08 +00:00
|
|
|
if (filename && *filename == NULL) {
|
2010-09-01 14:13:48 +00:00
|
|
|
/* try an alternative method to get the filename - module based
|
|
|
|
* references below are all borrowed (double checked) */
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *mod_name = PyDict_GetItemString(PyEval_GetGlobals(), "__name__");
|
2011-10-13 01:29:08 +00:00
|
|
|
if (mod_name) {
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *mod = PyDict_GetItem(PyImport_GetModuleDict(), mod_name);
|
2011-10-13 01:29:08 +00:00
|
|
|
if (mod) {
|
2012-03-16 21:39:56 +00:00
|
|
|
*filename = PyModule_GetFilename(mod);
|
2010-09-01 14:13:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* unlikely, fallback */
|
2011-10-13 01:29:08 +00:00
|
|
|
if (*filename == NULL) {
|
2012-03-16 21:39:56 +00:00
|
|
|
*filename = _PyUnicode_AsString(mod_name);
|
2010-09-01 14:13:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-22 07:57:18 +00:00
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
if (lineno) {
|
2011-02-22 07:57:18 +00:00
|
|
|
*lineno = PyFrame_GetLineNumber(frame);
|
2010-09-01 14:13:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-20 00:48:00 +00:00
|
|
|
void PyC_FileAndNum_Safe(const char **filename, int *lineno)
|
|
|
|
{
|
2011-12-18 08:50:06 +00:00
|
|
|
if (!PYC_INTERPRETER_ACTIVE) {
|
2011-10-20 00:48:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyC_FileAndNum(filename, lineno);
|
|
|
|
}
|
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
/* Would be nice if python had this built in */
|
|
|
|
PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...)
|
|
|
|
{
|
|
|
|
Py_ssize_t i;
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *item = o;
|
2010-09-01 14:13:48 +00:00
|
|
|
char *attr;
|
|
|
|
|
|
|
|
va_list vargs;
|
|
|
|
|
|
|
|
va_start(vargs, n);
|
2012-03-16 21:39:56 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2010-09-01 14:13:48 +00:00
|
|
|
attr = va_arg(vargs, char *);
|
|
|
|
item = PyObject_GetAttrString(item, attr);
|
|
|
|
|
|
|
|
if (item)
|
|
|
|
Py_DECREF(item);
|
|
|
|
else /* python will set the error value here */
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
va_end(vargs);
|
|
|
|
|
|
|
|
Py_XINCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
2011-09-15 10:43:55 +00:00
|
|
|
/* similar to PyErr_Format(),
|
|
|
|
*
|
2012-02-25 16:49:59 +00:00
|
|
|
* implementation - we cant actually preprend the existing exception,
|
2012-07-16 23:23:33 +00:00
|
|
|
* because it could have _any_ arguments given to it, so instead we get its
|
2011-09-15 10:43:55 +00:00
|
|
|
* __str__ output and raise our own exception including it.
|
|
|
|
*/
|
|
|
|
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...)
|
|
|
|
{
|
|
|
|
PyObject *error_value_prefix;
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, format);
|
2012-03-16 21:39:56 +00:00
|
|
|
error_value_prefix = PyUnicode_FromFormatV(format, args); /* can fail and be NULL */
|
2011-09-15 10:43:55 +00:00
|
|
|
va_end(args);
|
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (PyErr_Occurred()) {
|
2011-09-15 10:43:55 +00:00
|
|
|
PyObject *error_type, *error_value, *error_traceback;
|
|
|
|
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
|
|
|
PyErr_Format(exception_type_prefix,
|
|
|
|
"%S, %.200s(%S)",
|
|
|
|
error_value_prefix,
|
|
|
|
Py_TYPE(error_value)->tp_name,
|
|
|
|
error_value
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PyErr_SetObject(exception_type_prefix,
|
|
|
|
error_value_prefix
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_XDECREF(error_value_prefix);
|
|
|
|
|
|
|
|
/* dumb to always return NULL but matches PyErr_Format */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-03 06:46:31 +00:00
|
|
|
/* returns the exception string as a new PyUnicode object, depends on external traceback module */
|
2011-09-08 02:14:24 +00:00
|
|
|
#if 0
|
|
|
|
|
|
|
|
/* this version uses traceback module but somehow fails on UI errors */
|
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
PyObject *PyC_ExceptionBuffer(void)
|
|
|
|
{
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *traceback_mod = NULL;
|
|
|
|
PyObject *format_tb_func = NULL;
|
|
|
|
PyObject *ret = NULL;
|
2011-09-03 06:46:31 +00:00
|
|
|
|
2012-03-16 21:39:56 +00:00
|
|
|
if (!(traceback_mod = PyImport_ImportModule("traceback"))) {
|
2010-09-01 14:13:48 +00:00
|
|
|
goto error_cleanup;
|
2011-03-19 11:12:48 +00:00
|
|
|
}
|
2012-03-16 21:39:56 +00:00
|
|
|
else if (!(format_tb_func = PyObject_GetAttrString(traceback_mod, "format_exc"))) {
|
2010-09-01 14:13:48 +00:00
|
|
|
goto error_cleanup;
|
2011-03-19 11:12:48 +00:00
|
|
|
}
|
2011-09-03 06:46:31 +00:00
|
|
|
|
2012-03-16 21:39:56 +00:00
|
|
|
ret = PyObject_CallObject(format_tb_func, NULL);
|
2011-09-03 06:46:31 +00:00
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (ret == Py_None) {
|
2011-09-03 06:46:31 +00:00
|
|
|
Py_DECREF(ret);
|
2012-03-16 21:39:56 +00:00
|
|
|
ret = NULL;
|
2010-09-01 14:13:48 +00:00
|
|
|
}
|
2011-09-03 06:46:31 +00:00
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
error_cleanup:
|
|
|
|
/* could not import the module so print the error and close */
|
2011-09-03 06:46:31 +00:00
|
|
|
Py_XDECREF(traceback_mod);
|
|
|
|
Py_XDECREF(format_tb_func);
|
2010-09-01 14:13:48 +00:00
|
|
|
|
2011-09-03 06:46:31 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2011-09-08 02:14:24 +00:00
|
|
|
#else /* verbose, non-threadsafe version */
|
|
|
|
PyObject *PyC_ExceptionBuffer(void)
|
|
|
|
{
|
|
|
|
PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */
|
|
|
|
PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */
|
|
|
|
PyObject *string_io = NULL;
|
|
|
|
PyObject *string_io_buf = NULL;
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *string_io_mod = NULL;
|
|
|
|
PyObject *string_io_getvalue = NULL;
|
2011-09-08 02:14:24 +00:00
|
|
|
|
|
|
|
PyObject *error_type, *error_value, *error_traceback;
|
|
|
|
|
|
|
|
if (!PyErr_Occurred())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
|
|
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
|
|
|
/* import io
|
|
|
|
* string_io = io.StringIO()
|
|
|
|
*/
|
|
|
|
|
2012-03-16 21:39:56 +00:00
|
|
|
if (!(string_io_mod = PyImport_ImportModule("io"))) {
|
2011-09-08 02:14:24 +00:00
|
|
|
goto error_cleanup;
|
|
|
|
}
|
2012-03-16 21:39:56 +00:00
|
|
|
else if (!(string_io = PyObject_CallMethod(string_io_mod, (char *)"StringIO", NULL))) {
|
2011-09-08 02:14:24 +00:00
|
|
|
goto error_cleanup;
|
|
|
|
}
|
2012-03-16 21:39:56 +00:00
|
|
|
else if (!(string_io_getvalue = PyObject_GetAttrString(string_io, "getvalue"))) {
|
2011-09-08 02:14:24 +00:00
|
|
|
goto error_cleanup;
|
|
|
|
}
|
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
Py_INCREF(stdout_backup); // since these were borrowed we don't want them freed when replaced.
|
2011-09-08 02:14:24 +00:00
|
|
|
Py_INCREF(stderr_backup);
|
|
|
|
|
2012-03-09 00:41:09 +00:00
|
|
|
PySys_SetObject("stdout", string_io); // both of these are freed when restoring
|
2011-09-08 02:14:24 +00:00
|
|
|
PySys_SetObject("stderr", string_io);
|
|
|
|
|
|
|
|
PyErr_Restore(error_type, error_value, error_traceback);
|
|
|
|
PyErr_Print(); /* print the error */
|
|
|
|
PyErr_Clear();
|
|
|
|
|
|
|
|
string_io_buf = PyObject_CallObject(string_io_getvalue, NULL);
|
|
|
|
|
|
|
|
PySys_SetObject("stdout", stdout_backup);
|
|
|
|
PySys_SetObject("stderr", stderr_backup);
|
|
|
|
|
|
|
|
Py_DECREF(stdout_backup); /* now sys owns the ref again */
|
|
|
|
Py_DECREF(stderr_backup);
|
|
|
|
|
|
|
|
Py_DECREF(string_io_mod);
|
|
|
|
Py_DECREF(string_io_getvalue);
|
|
|
|
Py_DECREF(string_io); /* free the original reference */
|
|
|
|
|
|
|
|
PyErr_Clear();
|
|
|
|
return string_io_buf;
|
|
|
|
|
|
|
|
|
|
|
|
error_cleanup:
|
|
|
|
/* could not import the module so print the error and close */
|
|
|
|
Py_XDECREF(string_io_mod);
|
|
|
|
Py_XDECREF(string_io);
|
|
|
|
|
|
|
|
PyErr_Restore(error_type, error_value, error_traceback);
|
|
|
|
PyErr_Print(); /* print the error */
|
|
|
|
PyErr_Clear();
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-09-01 14:13:48 +00:00
|
|
|
|
|
|
|
/* string conversion, escape non-unicode chars, coerce must be set to NULL */
|
2010-10-03 23:29:43 +00:00
|
|
|
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
|
2010-09-01 14:13:48 +00:00
|
|
|
{
|
2011-11-03 14:09:18 +00:00
|
|
|
const char *result;
|
2010-09-01 14:13:48 +00:00
|
|
|
|
2012-03-16 21:39:56 +00:00
|
|
|
result = _PyUnicode_AsString(py_str);
|
2010-09-01 14:13:48 +00:00
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (result) {
|
2010-09-01 14:13:48 +00:00
|
|
|
/* 99% of the time this is enough but we better support non unicode
|
|
|
|
* chars since blender doesnt limit this */
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else {
|
2011-09-27 04:07:48 +00:00
|
|
|
PyErr_Clear();
|
|
|
|
|
2012-06-18 13:46:57 +00:00
|
|
|
if (PyBytes_Check(py_str)) {
|
2011-09-27 04:07:48 +00:00
|
|
|
return PyBytes_AS_STRING(py_str);
|
|
|
|
}
|
2012-03-16 21:39:56 +00:00
|
|
|
else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
|
2011-11-22 14:05:08 +00:00
|
|
|
return PyBytes_AS_STRING(*coerce);
|
|
|
|
}
|
2011-09-27 04:07:48 +00:00
|
|
|
else {
|
2011-11-22 14:05:08 +00:00
|
|
|
/* leave error raised from EncodeFS */
|
|
|
|
return NULL;
|
2011-09-27 04:07:48 +00:00
|
|
|
}
|
2010-09-01 14:13:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-22 10:49:35 +00:00
|
|
|
PyObject *PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size)
|
2010-09-01 14:13:48 +00:00
|
|
|
{
|
2012-03-24 07:36:32 +00:00
|
|
|
PyObject *result = PyUnicode_FromStringAndSize(str, size);
|
2011-10-13 01:29:08 +00:00
|
|
|
if (result) {
|
2010-09-01 14:13:48 +00:00
|
|
|
/* 99% of the time this is enough but we better support non unicode
|
|
|
|
* chars since blender doesnt limit this */
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PyErr_Clear();
|
2010-12-05 09:20:18 +00:00
|
|
|
/* this means paths will always be accessible once converted, on all OS's */
|
2012-03-16 21:39:56 +00:00
|
|
|
result = PyUnicode_DecodeFSDefaultAndSize(str, size);
|
2010-09-01 14:13:48 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
2010-09-18 15:30:03 +00:00
|
|
|
|
2011-10-22 10:49:35 +00:00
|
|
|
PyObject *PyC_UnicodeFromByte(const char *str)
|
|
|
|
{
|
|
|
|
return PyC_UnicodeFromByteAndSize(str, strlen(str));
|
|
|
|
}
|
|
|
|
|
2010-09-18 15:30:03 +00:00
|
|
|
/*****************************************************************************
|
2012-03-03 20:36:09 +00:00
|
|
|
* Description: This function creates a new Python dictionary object.
|
|
|
|
* note: dict is owned by sys.modules["__main__"] module, reference is borrowed
|
|
|
|
* note: important we use the dict from __main__, this is what python expects
|
|
|
|
* for 'pickle' to work as well as strings like this...
|
|
|
|
* >> foo = 10
|
|
|
|
* >> print(__import__("__main__").foo)
|
|
|
|
*
|
|
|
|
* note: this overwrites __main__ which gives problems with nested calles.
|
|
|
|
* be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
|
|
|
|
* any chance that python is in the call stack.
|
2012-03-09 18:28:30 +00:00
|
|
|
****************************************************************************/
|
2010-09-18 15:30:03 +00:00
|
|
|
PyObject *PyC_DefaultNameSpace(const char *filename)
|
|
|
|
{
|
2012-03-16 21:39:56 +00:00
|
|
|
PyInterpreterState *interp = PyThreadState_GET()->interp;
|
|
|
|
PyObject *mod_main = PyModule_New("__main__");
|
2010-09-18 15:30:03 +00:00
|
|
|
PyDict_SetItemString(interp->modules, "__main__", mod_main);
|
|
|
|
Py_DECREF(mod_main); /* sys.modules owns now */
|
|
|
|
PyModule_AddStringConstant(mod_main, "__name__", "__main__");
|
2012-03-21 22:29:49 +00:00
|
|
|
if (filename) {
|
|
|
|
/* __file__ mainly for nice UI'ness */
|
|
|
|
PyModule_AddObject(mod_main, "__file__", PyUnicode_DecodeFSDefault(filename));
|
|
|
|
}
|
2010-09-18 15:30:03 +00:00
|
|
|
PyModule_AddObject(mod_main, "__builtins__", interp->builtins);
|
|
|
|
Py_INCREF(interp->builtins); /* AddObject steals a reference */
|
|
|
|
return PyModule_GetDict(mod_main);
|
|
|
|
}
|
2010-09-19 14:02:45 +00:00
|
|
|
|
2011-02-01 12:37:53 +00:00
|
|
|
/* restore MUST be called after this */
|
|
|
|
void PyC_MainModule_Backup(PyObject **main_mod)
|
|
|
|
{
|
2012-03-16 21:39:56 +00:00
|
|
|
PyInterpreterState *interp = PyThreadState_GET()->interp;
|
|
|
|
*main_mod = PyDict_GetItemString(interp->modules, "__main__");
|
2012-03-18 07:38:51 +00:00
|
|
|
Py_XINCREF(*main_mod); /* don't free */
|
2011-02-01 12:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PyC_MainModule_Restore(PyObject *main_mod)
|
|
|
|
{
|
2012-03-16 21:39:56 +00:00
|
|
|
PyInterpreterState *interp = PyThreadState_GET()->interp;
|
2011-02-01 12:37:53 +00:00
|
|
|
PyDict_SetItemString(interp->modules, "__main__", main_mod);
|
|
|
|
Py_XDECREF(main_mod);
|
|
|
|
}
|
2010-09-19 14:02:45 +00:00
|
|
|
|
2011-04-18 08:27:50 +00:00
|
|
|
/* must be called before Py_Initialize, expects output of BLI_get_folder(BLENDER_PYTHON, NULL) */
|
|
|
|
void PyC_SetHomePath(const char *py_path_bundle)
|
|
|
|
{
|
2012-03-16 21:39:56 +00:00
|
|
|
if (py_path_bundle == NULL) {
|
2011-04-18 08:27:50 +00:00
|
|
|
/* Common enough to have bundled *nix python but complain on OSX/Win */
|
|
|
|
#if defined(__APPLE__) || defined(_WIN32)
|
2012-02-05 02:04:26 +00:00
|
|
|
fprintf(stderr, "Warning! bundled python not found and is expected on this platform. "
|
|
|
|
"(if you built with CMake: 'install' target may have not been built)\n");
|
2011-04-18 08:27:50 +00:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* set the environment path */
|
|
|
|
printf("found bundled python: %s\n", py_path_bundle);
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
/* OSX allow file/directory names to contain : character (represented as / in the Finder)
|
2012-03-03 20:36:09 +00:00
|
|
|
* but current Python lib (release 3.1.1) doesn't handle these correctly */
|
2011-10-13 01:29:08 +00:00
|
|
|
if (strchr(py_path_bundle, ':'))
|
2011-04-18 08:27:50 +00:00
|
|
|
printf("Warning : Blender application is located in a path containing : or / chars\
|
|
|
|
\nThis may make python import function fail\n");
|
|
|
|
#endif
|
|
|
|
|
2012-05-19 10:10:49 +00:00
|
|
|
|
|
|
|
#if 0 /* disable for now [#31506] - campbell */
|
2011-04-18 08:27:50 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
/* cmake/MSVC debug build crashes without this, why only
|
2012-03-03 20:36:09 +00:00
|
|
|
* in this case is unknown.. */
|
2011-04-18 08:27:50 +00:00
|
|
|
{
|
2012-05-28 21:36:29 +00:00
|
|
|
/*BLI_setenv("PYTHONPATH", py_path_bundle)*/;
|
2011-04-18 08:27:50 +00:00
|
|
|
}
|
2012-05-19 10:10:49 +00:00
|
|
|
#endif
|
2011-04-18 08:27:50 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
{
|
|
|
|
static wchar_t py_path_bundle_wchar[1024];
|
|
|
|
|
|
|
|
/* cant use this, on linux gives bug: #23018, TODO: try LANG="en_US.UTF-8" /usr/bin/blender, suggested 22008 */
|
|
|
|
/* mbstowcs(py_path_bundle_wchar, py_path_bundle, FILE_MAXDIR); */
|
|
|
|
|
2012-02-05 02:04:26 +00:00
|
|
|
BLI_strncpy_wchar_from_utf8(py_path_bundle_wchar, py_path_bundle,
|
|
|
|
sizeof(py_path_bundle_wchar) / sizeof(wchar_t));
|
2011-04-18 08:27:50 +00:00
|
|
|
|
|
|
|
Py_SetPythonHome(py_path_bundle_wchar);
|
|
|
|
// printf("found python (wchar_t) '%ls'\n", py_path_bundle_wchar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-19 14:02:45 +00:00
|
|
|
/* Would be nice if python had this built in */
|
|
|
|
void PyC_RunQuicky(const char *filepath, int n, ...)
|
|
|
|
{
|
2012-03-16 21:39:56 +00:00
|
|
|
FILE *fp = fopen(filepath, "r");
|
2010-09-19 14:02:45 +00:00
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (fp) {
|
2012-03-16 21:39:56 +00:00
|
|
|
PyGILState_STATE gilstate = PyGILState_Ensure();
|
2010-09-19 14:02:45 +00:00
|
|
|
|
|
|
|
va_list vargs;
|
|
|
|
|
2012-03-16 21:39:56 +00:00
|
|
|
int *sizes = PyMem_MALLOC(sizeof(int) * (n / 2));
|
2010-09-19 14:02:45 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
PyObject *py_dict = PyC_DefaultNameSpace(filepath);
|
2012-03-18 07:38:51 +00:00
|
|
|
PyObject *values = PyList_New(n / 2); /* namespace owns this, don't free */
|
2010-09-19 14:02:45 +00:00
|
|
|
|
|
|
|
PyObject *py_result, *ret;
|
|
|
|
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *struct_mod = PyImport_ImportModule("struct");
|
|
|
|
PyObject *calcsize = PyObject_GetAttrString(struct_mod, "calcsize"); /* struct.calcsize */
|
|
|
|
PyObject *pack = PyObject_GetAttrString(struct_mod, "pack"); /* struct.pack */
|
|
|
|
PyObject *unpack = PyObject_GetAttrString(struct_mod, "unpack"); /* struct.unpack */
|
2010-09-19 14:02:45 +00:00
|
|
|
|
|
|
|
Py_DECREF(struct_mod);
|
|
|
|
|
|
|
|
va_start(vargs, n);
|
2012-03-16 21:39:56 +00:00
|
|
|
for (i = 0; i * 2 < n; i++) {
|
2010-09-19 14:02:45 +00:00
|
|
|
char *format = va_arg(vargs, char *);
|
|
|
|
void *ptr = va_arg(vargs, void *);
|
|
|
|
|
2012-03-16 21:39:56 +00:00
|
|
|
ret = PyObject_CallFunction(calcsize, (char *)"s", format);
|
2010-09-19 14:02:45 +00:00
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (ret) {
|
2012-03-26 06:55:09 +00:00
|
|
|
sizes[i] = PyLong_AsSsize_t(ret);
|
2010-09-19 14:02:45 +00:00
|
|
|
Py_DECREF(ret);
|
2010-12-03 17:05:21 +00:00
|
|
|
ret = PyObject_CallFunction(unpack, (char *)"sy#", format, (char *)ptr, sizes[i]);
|
2010-09-19 14:02:45 +00:00
|
|
|
}
|
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (ret == NULL) {
|
2010-09-19 14:02:45 +00:00
|
|
|
printf("PyC_InlineRun error, line:%d\n", __LINE__);
|
|
|
|
PyErr_Print();
|
|
|
|
PyErr_Clear();
|
|
|
|
|
|
|
|
PyList_SET_ITEM(values, i, Py_None); /* hold user */
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
|
2012-03-26 06:55:09 +00:00
|
|
|
sizes[i] = 0;
|
2010-09-19 14:02:45 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-10-13 01:29:08 +00:00
|
|
|
if (PyTuple_GET_SIZE(ret) == 1) {
|
2010-09-19 14:02:45 +00:00
|
|
|
/* convenience, convert single tuples into single values */
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *tmp = PyTuple_GET_ITEM(ret, 0);
|
2010-09-19 14:02:45 +00:00
|
|
|
Py_INCREF(tmp);
|
|
|
|
Py_DECREF(ret);
|
|
|
|
ret = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyList_SET_ITEM(values, i, ret); /* hold user */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
va_end(vargs);
|
|
|
|
|
|
|
|
/* set the value so we can access it */
|
|
|
|
PyDict_SetItemString(py_dict, "values", values);
|
|
|
|
|
|
|
|
py_result = PyRun_File(fp, filepath, Py_file_input, py_dict, py_dict);
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (py_result) {
|
2010-09-19 14:02:45 +00:00
|
|
|
|
|
|
|
/* we could skip this but then only slice assignment would work
|
|
|
|
* better not be so strict */
|
2012-03-16 21:39:56 +00:00
|
|
|
values = PyDict_GetItemString(py_dict, "values");
|
2010-09-19 14:02:45 +00:00
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (values && PyList_Check(values)) {
|
2010-09-19 14:02:45 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* don't use the result */
|
2010-09-19 14:02:45 +00:00
|
|
|
Py_DECREF(py_result);
|
2012-03-16 21:39:56 +00:00
|
|
|
py_result = NULL;
|
2010-09-19 14:02:45 +00:00
|
|
|
|
|
|
|
/* now get the values back */
|
|
|
|
va_start(vargs, n);
|
2012-03-16 21:39:56 +00:00
|
|
|
for (i = 0; i * 2 < n; i++) {
|
2010-09-19 14:02:45 +00:00
|
|
|
char *format = va_arg(vargs, char *);
|
|
|
|
void *ptr = va_arg(vargs, void *);
|
|
|
|
|
|
|
|
PyObject *item;
|
|
|
|
PyObject *item_new;
|
|
|
|
/* prepend the string formatting and remake the tuple */
|
2012-03-16 21:39:56 +00:00
|
|
|
item = PyList_GET_ITEM(values, i);
|
2011-10-13 01:29:08 +00:00
|
|
|
if (PyTuple_CheckExact(item)) {
|
2012-03-16 21:39:56 +00:00
|
|
|
int ofs = PyTuple_GET_SIZE(item);
|
|
|
|
item_new = PyTuple_New(ofs + 1);
|
2011-10-13 01:29:08 +00:00
|
|
|
while (ofs--) {
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *member = PyTuple_GET_ITEM(item, ofs);
|
2010-09-19 14:02:45 +00:00
|
|
|
PyTuple_SET_ITEM(item_new, ofs + 1, member);
|
|
|
|
Py_INCREF(member);
|
|
|
|
}
|
|
|
|
|
|
|
|
PyTuple_SET_ITEM(item_new, 0, PyUnicode_FromString(format));
|
|
|
|
}
|
|
|
|
else {
|
2012-03-16 21:39:56 +00:00
|
|
|
item_new = Py_BuildValue("sO", format, item);
|
2010-09-19 14:02:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = PyObject_Call(pack, item_new, NULL);
|
|
|
|
|
2011-10-13 01:29:08 +00:00
|
|
|
if (ret) {
|
2010-09-19 14:02:45 +00:00
|
|
|
/* copy the bytes back into memory */
|
|
|
|
memcpy(ptr, PyBytes_AS_STRING(ret), sizes[i]);
|
|
|
|
Py_DECREF(ret);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("PyC_InlineRun error on arg '%d', line:%d\n", i, __LINE__);
|
|
|
|
PyC_ObSpit("failed converting:", item_new);
|
|
|
|
PyErr_Print();
|
|
|
|
PyErr_Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_DECREF(item_new);
|
|
|
|
}
|
|
|
|
va_end(vargs);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("PyC_InlineRun error, 'values' not a list, line:%d\n", __LINE__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("PyC_InlineRun error line:%d\n", __LINE__);
|
|
|
|
PyErr_Print();
|
|
|
|
PyErr_Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_DECREF(calcsize);
|
|
|
|
Py_DECREF(pack);
|
|
|
|
Py_DECREF(unpack);
|
|
|
|
|
|
|
|
PyMem_FREE(sizes);
|
|
|
|
|
|
|
|
PyGILState_Release(gilstate);
|
|
|
|
}
|
|
|
|
}
|
2012-02-20 22:04:29 +00:00
|
|
|
|
|
|
|
/* generic function to avoid depending on RNA */
|
|
|
|
void *PyC_RNA_AsPointer(PyObject *value, const char *type_name)
|
|
|
|
{
|
2012-03-16 21:39:56 +00:00
|
|
|
PyObject *as_pointer;
|
|
|
|
PyObject *pointer;
|
2012-02-20 22:04:29 +00:00
|
|
|
|
|
|
|
if (!strcmp(Py_TYPE(value)->tp_name, type_name) &&
|
|
|
|
(as_pointer = PyObject_GetAttrString(value, "as_pointer")) != NULL &&
|
|
|
|
PyCallable_Check(as_pointer))
|
|
|
|
{
|
|
|
|
void *result = NULL;
|
|
|
|
|
|
|
|
/* must be a 'type_name' object */
|
|
|
|
pointer = PyObject_CallObject(as_pointer, NULL);
|
|
|
|
Py_DECREF(as_pointer);
|
|
|
|
|
|
|
|
if (!pointer) {
|
|
|
|
PyErr_SetString(PyExc_SystemError, "value.as_pointer() failed");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
result = PyLong_AsVoidPtr(pointer);
|
|
|
|
Py_DECREF(pointer);
|
|
|
|
if (!result) {
|
|
|
|
PyErr_SetString(PyExc_SystemError, "value.as_pointer() failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
"expected '%.200s' type found '%.200s' instead",
|
|
|
|
type_name, Py_TYPE(value)->tp_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2012-02-22 09:15:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* PyC_FlagSet_* functions - so flags/sets can be interchanged in a generic way */
|
|
|
|
#include "BLI_dynstr.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
char *PyC_FlagSet_AsString(PyC_FlagSet *item)
|
|
|
|
{
|
|
|
|
DynStr *dynstr = BLI_dynstr_new();
|
|
|
|
PyC_FlagSet *e;
|
|
|
|
char *cstring;
|
|
|
|
|
|
|
|
for (e = item; item->identifier; item++) {
|
|
|
|
BLI_dynstr_appendf(dynstr, (e == item) ? "'%s'" : ", '%s'", item->identifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
cstring = BLI_dynstr_get_cstring(dynstr);
|
|
|
|
BLI_dynstr_free(dynstr);
|
|
|
|
return cstring;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PyC_FlagSet_ValueFromID_int(PyC_FlagSet *item, const char *identifier, int *value)
|
|
|
|
{
|
2012-03-24 06:24:53 +00:00
|
|
|
for ( ; item->identifier; item++) {
|
2012-03-16 21:39:56 +00:00
|
|
|
if (strcmp(item->identifier, identifier) == 0) {
|
2012-02-22 09:15:46 +00:00
|
|
|
*value = item->value;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *value, const char *error_prefix)
|
|
|
|
{
|
|
|
|
if (PyC_FlagSet_ValueFromID_int(item, identifier, value) == 0) {
|
|
|
|
const char *enum_str = PyC_FlagSet_AsString(item);
|
|
|
|
PyErr_Format(PyExc_ValueError,
|
|
|
|
"%s: '%.200s' not found in (%s)",
|
|
|
|
error_prefix, identifier, enum_str);
|
|
|
|
MEM_freeN((void *)enum_str);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 'value' _must_ be a set type, error check before calling */
|
|
|
|
int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix)
|
|
|
|
{
|
|
|
|
/* set of enum items, concatenate all values with OR */
|
|
|
|
int ret, flag = 0;
|
|
|
|
|
|
|
|
/* set looping */
|
|
|
|
Py_ssize_t pos = 0;
|
|
|
|
Py_ssize_t hash = 0;
|
|
|
|
PyObject *key;
|
|
|
|
|
|
|
|
*r_value = 0;
|
|
|
|
|
|
|
|
while (_PySet_NextEntry(value, &pos, &key, &hash)) {
|
|
|
|
const char *param = _PyUnicode_AsString(key);
|
|
|
|
|
|
|
|
if (param == NULL) {
|
|
|
|
PyErr_Format(PyExc_TypeError,
|
|
|
|
"%.200s expected a string, not %.200s",
|
|
|
|
error_prefix, Py_TYPE(key)->tp_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PyC_FlagSet_ValueFromID(items, param, &ret, error_prefix) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
flag |= ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
*r_value = flag;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
|
|
|
|
{
|
|
|
|
PyObject *ret = PySet_New(NULL);
|
|
|
|
PyObject *pystr;
|
|
|
|
|
|
|
|
for ( ; items->identifier; items++) {
|
|
|
|
if (items->value & flag) {
|
|
|
|
pystr = PyUnicode_FromString(items->identifier);
|
|
|
|
PySet_Add(ret, pystr);
|
|
|
|
Py_DECREF(pystr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|