This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/python/generic/py_capi_rna.c
Campbell Barton c434782e3a File headers: SPDX License migration
Use a shorter/simpler license convention, stops the header taking so
much space.

Follow the SPDX license specification: https://spdx.org/licenses

- C/C++/objc/objc++
- Python
- Shell Scripts
- CMake, GNUmakefile

While most of the source tree has been included

- `./extern/` was left out.
- `./intern/cycles` & `./intern/atomic` are also excluded because they
  use different header conventions.

doc/license/SPDX-license-identifiers.txt has been added to list SPDX all
used identifiers.

See P2788 for the script that automated these edits.

Reviewed By: brecht, mont29, sergey

Ref D14069
2022-02-11 09:14:36 +11:00

230 lines
5.7 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup pygen
*
* Python/RNA utilities.
*
* RNA functions that aren't part of the `bpy_rna.c` API.
*/
/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdbool.h>
#include "py_capi_rna.h"
#include "BLI_bitmap.h"
#include "BLI_dynstr.h"
#include "RNA_access.h"
#include "MEM_guardedalloc.h"
/* -------------------------------------------------------------------- */
/** \name Enum Utilities
* \{ */
char *pyrna_enum_repr(const EnumPropertyItem *item)
{
DynStr *dynstr = BLI_dynstr_new();
/* We can't compare with the first element in the array
* since it may be a category (without an identifier). */
for (bool is_first = true; item->identifier; item++) {
if (item->identifier[0]) {
BLI_dynstr_appendf(dynstr, is_first ? "'%s'" : ", '%s'", item->identifier);
is_first = false;
}
}
char *cstring = BLI_dynstr_get_cstring(dynstr);
BLI_dynstr_free(dynstr);
return cstring;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Enum Conversion Utilities
* \{ */
int pyrna_enum_value_from_id(const EnumPropertyItem *item,
const char *identifier,
int *r_value,
const char *error_prefix)
{
if (RNA_enum_value_from_id(item, identifier, r_value) == 0) {
const char *enum_str = pyrna_enum_repr(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;
}
BLI_bitmap *pyrna_enum_bitmap_from_set(const EnumPropertyItem *items,
PyObject *value,
int type_size,
bool type_convert_sign,
int bitmap_size,
const char *error_prefix)
{
/* Set looping. */
Py_ssize_t pos = 0;
Py_ssize_t hash = 0;
PyObject *key;
BLI_bitmap *bitmap = BLI_BITMAP_NEW(bitmap_size, __func__);
while (_PySet_NextEntry(value, &pos, &key, &hash)) {
const char *param = PyUnicode_AsUTF8(key);
if (param == NULL) {
PyErr_Format(PyExc_TypeError,
"%.200s expected a string, not %.200s",
error_prefix,
Py_TYPE(key)->tp_name);
goto error;
}
int ret;
if (pyrna_enum_value_from_id(items, param, &ret, error_prefix) == -1) {
goto error;
}
int index = ret;
if (type_convert_sign) {
if (type_size == 2) {
union {
signed short as_signed;
ushort as_unsigned;
} ret_convert;
ret_convert.as_signed = (signed short)ret;
index = (int)ret_convert.as_unsigned;
}
else if (type_size == 1) {
union {
signed char as_signed;
uchar as_unsigned;
} ret_convert;
ret_convert.as_signed = (signed char)ret;
index = (int)ret_convert.as_unsigned;
}
else {
BLI_assert_unreachable();
}
}
BLI_assert(index < bitmap_size);
BLI_BITMAP_ENABLE(bitmap, index);
}
return bitmap;
error:
MEM_freeN(bitmap);
return NULL;
}
int pyrna_enum_bitfield_from_set(const EnumPropertyItem *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_AsUTF8(key);
if (param == NULL) {
PyErr_Format(PyExc_TypeError,
"%.200s expected a string, not %.200s",
error_prefix,
Py_TYPE(key)->tp_name);
return -1;
}
if (pyrna_enum_value_from_id(items, param, &ret, error_prefix) == -1) {
return -1;
}
flag |= ret;
}
*r_value = flag;
return 0;
}
PyObject *pyrna_enum_bitfield_as_set(const EnumPropertyItem *items, int value)
{
PyObject *ret = PySet_New(NULL);
const char *identifier[RNA_ENUM_BITFLAG_SIZE + 1];
if (RNA_enum_bitflag_identifiers(items, value, identifier)) {
PyObject *item;
int index;
for (index = 0; identifier[index]; index++) {
item = PyUnicode_FromString(identifier[index]);
PySet_Add(ret, item);
Py_DECREF(item);
}
}
return ret;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Argument Parsing Helpers
* \{ */
int pyrna_enum_value_parse_string(PyObject *o, void *p)
{
const char *identifier = PyUnicode_AsUTF8(o);
if (identifier == NULL) {
PyErr_Format(PyExc_TypeError, "expected a string enum, not %.200s", Py_TYPE(o)->tp_name);
return 0;
}
struct BPy_EnumProperty_Parse *parse_data = p;
if (pyrna_enum_value_from_id(
parse_data->items, identifier, &parse_data->value, "enum identifier") == -1) {
return 0;
}
parse_data->value_orig = o;
parse_data->is_set = true;
return 1;
}
int pyrna_enum_bitfield_parse_set(PyObject *o, void *p)
{
if (!PySet_Check(o)) {
PyErr_Format(PyExc_TypeError, "expected a set, not %.200s", Py_TYPE(o)->tp_name);
return 0;
}
struct BPy_EnumProperty_Parse *parse_data = p;
if (pyrna_enum_bitfield_from_set(
parse_data->items, o, &parse_data->value, "enum identifier set") == -1) {
return 0;
}
parse_data->value_orig = o;
parse_data->is_set = true;
return 1;
}
/** \} */