Welcome to mirror list, hosted at ThFree Co, Russian Federation.

py_capi_utils.h « generic « python « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: ecb6db2b82caaa85a25aa73ab3955be965e6828f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/* SPDX-License-Identifier: GPL-2.0-or-later */

/** \file
 * \ingroup pygen
 */

/* Use a define instead of `#pragma once` because of `bmesh_py_types.h` */
#ifndef __PY_CAPI_UTILS_H__
#define __PY_CAPI_UTILS_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "BLI_sys_types.h"
#include "BLI_utildefines_variadic.h"

void PyC_ObSpit(const char *name, PyObject *var);
/**
 * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument).
 * Use for logging.
 */
void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
PyObject *PyC_ExceptionBuffer(void);
PyObject *PyC_ExceptionBuffer_Simple(void);
PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
PyObject *PyC_FrozenSetFromStrings(const char **strings);

/**
 * Similar to #PyErr_Format(),
 *
 * Implementation - we can't actually prepend the existing exception,
 * because it could have _any_ arguments given to it, so instead we get its
 * `__str__` output and raise our own exception including it.
 */
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *str);

/**
 * Use for Python callbacks run directly from C,
 * when we can't use normal methods of raising exceptions.
 */
void PyC_Err_PrintWithFunc(PyObject *py_func);

void PyC_FileAndNum(const char **r_filename, int *r_lineno);
void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno); /* checks python is running */
int PyC_AsArray_FAST(void *array,
                     size_t array_item_size,
                     PyObject *value_fast,
                     Py_ssize_t length,
                     const PyTypeObject *type,
                     const char *error_prefix);
int PyC_AsArray(void *array,
                size_t array_item_size,
                PyObject *value,
                Py_ssize_t length,
                const PyTypeObject *type,
                const char *error_prefix);

int PyC_AsArray_Multi_FAST(void *array,
                           size_t array_item_size,
                           PyObject *value_fast,
                           const int *dims,
                           int dims_len,
                           const PyTypeObject *type,
                           const char *error_prefix);

int PyC_AsArray_Multi(void *array,
                      size_t array_item_size,
                      PyObject *value,
                      const int *dims,
                      int dims_len,
                      const PyTypeObject *type,
                      const char *error_prefix);

PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len);
PyObject *PyC_Tuple_PackArray_F64(const double *array, uint len);
PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len);
PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len);
PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len);

#define PyC_Tuple_Pack_F32(...) \
  PyC_Tuple_PackArray_F32(((const float[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_F64(...) \
  PyC_Tuple_PackArray_F64(((const double[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_I32(...) \
  PyC_Tuple_PackArray_I32(((const int[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_I32FromBool(...) \
  PyC_Tuple_PackArray_I32FromBool(((const int[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_Bool(...) \
  PyC_Tuple_PackArray_Bool(((const bool[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))

PyObject *PyC_Tuple_PackArray_Multi_F32(const float *array, const int dims[], int dims_len);
PyObject *PyC_Tuple_PackArray_Multi_F64(const double *array, const int dims[], int dims_len);
PyObject *PyC_Tuple_PackArray_Multi_I32(const int *array, const int dims[], int dims_len);
PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], int dims_len);

/**
 * Caller needs to ensure tuple is uninitialized.
 * Handy for filling a tuple with None for eg.
 */
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value);
void PyC_List_Fill(PyObject *list, PyObject *value);

/* follow http://www.python.org/dev/peps/pep-0383/ */
PyObject *PyC_UnicodeFromByte(const char *str);
PyObject *PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size);
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
/**
 * String conversion, escape non-unicode chars
 * \param coerce: must be set to NULL.
 */
const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce);

/**
 * 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 calls.
 * be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
 * any chance that python is in the call stack.
 */
PyObject *PyC_DefaultNameSpace(const char *filename);
void PyC_RunQuicky(const char *filepath, int n, ...);
/**
 * Import `imports` into `py_dict`.
 *
 * \param py_dict: A Python dictionary, typically used as a name-space for script execution.
 * \param imports: A NULL terminated array of strings.
 * \return true when all modules import without errors, otherwise return false.
 * The caller is expected to handle the exception.
 */
bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[]);

/**
 * #PyC_MainModule_Restore MUST be called after #PyC_MainModule_Backup.
 */
void PyC_MainModule_Backup(PyObject **r_main_mod);
void PyC_MainModule_Restore(PyObject *main_mod);

bool PyC_IsInterpreterActive(void);

void *PyC_RNA_AsPointer(PyObject *value, const char *type_name);

/* flag / set --- interchange */
typedef struct PyC_FlagSet {
  int value;
  const char *identifier;
} PyC_FlagSet;

PyObject *PyC_FlagSet_AsString(const PyC_FlagSet *item);
int PyC_FlagSet_ValueFromID_int(const PyC_FlagSet *item, const char *identifier, int *r_value);
int PyC_FlagSet_ValueFromID(const PyC_FlagSet *item,
                            const char *identifier,
                            int *r_value,
                            const char *error_prefix);
int PyC_FlagSet_ToBitfield(const PyC_FlagSet *items,
                           PyObject *value,
                           int *r_value,
                           const char *error_prefix);
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);

/**
 * \return success
 *
 * \note it is caller's responsibility to acquire & release GIL!
 */
bool PyC_RunString_AsNumber(const char **imports,
                            const char *expr,
                            const char *filename,
                            double *r_value);
bool PyC_RunString_AsIntPtr(const char **imports,
                            const char *expr,
                            const char *filename,
                            intptr_t *r_value);
bool PyC_RunString_AsStringAndSize(const char **imports,
                                   const char *expr,
                                   const char *filename,
                                   char **r_value,
                                   size_t *r_value_size);
bool PyC_RunString_AsString(const char **imports,
                            const char *expr,
                            const char *filename,
                            char **r_value);

/**
 * Use with PyArg_ParseTuple's "O&" formatting.
 *
 * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
 */
int PyC_ParseBool(PyObject *o, void *p);

struct PyC_StringEnumItems {
  int value;
  const char *id;
};
struct PyC_StringEnum {
  const struct PyC_StringEnumItems *items;
  int value_found;
};

/**
 * Use with PyArg_ParseTuple's "O&" formatting.
 */
int PyC_ParseStringEnum(PyObject *o, void *p);
const char *PyC_StringEnum_FindIDFromValue(const struct PyC_StringEnumItems *items, int value);

int PyC_CheckArgs_DeepCopy(PyObject *args);

/* Integer parsing (with overflow checks), -1 on error. */
/**
 *
 * Comparison with #PyObject_IsTrue
 * ================================
 *
 * Even though Python provides a way to retrieve the boolean value for an object,
 * in many cases it's far too relaxed, with the following examples coercing values.
 *
 * \code{.py}
 * data.value = "Text"    # True.
 * data.value = ""        # False.
 * data.value = {1, 2}    # True
 * data.value = {}        # False.
 * data.value = None      # False.
 * \endcode
 *
 * In practice this is often a mistake by the script author that doesn't behave as they expect.
 * So it's better to be more strict for attribute assignment and function arguments,
 * only accepting True/False 0/1.
 *
 * If coercing a value is desired, it can be done explicitly: `data.value = bool(value)`
 *
 * \see #PyC_ParseBool for use with #PyArg_ParseTuple and related functions.
 *
 * \note Don't use `bool` return type, so -1 can be used as an error value.
 */
int PyC_Long_AsBool(PyObject *value);
int8_t PyC_Long_AsI8(PyObject *value);
int16_t PyC_Long_AsI16(PyObject *value);
#if 0 /* inline */
int32_t PyC_Long_AsI32(PyObject *value);
int64_t PyC_Long_AsI64(PyObject *value);
#endif

uint8_t PyC_Long_AsU8(PyObject *value);
uint16_t PyC_Long_AsU16(PyObject *value);
uint32_t PyC_Long_AsU32(PyObject *value);
#if 0 /* inline */
uint64_t PyC_Long_AsU64(PyObject *value);
#endif

/* inline so type signatures match as expected */
Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value)
{
  return (int32_t)_PyLong_AsInt(value);
}
Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value)
{
  return (int64_t)PyLong_AsLongLong(value);
}
Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value)
{
  return (uint64_t)PyLong_AsUnsignedLongLong(value);
}

/* utils for format string in `struct` module style syntax */
char PyC_StructFmt_type_from_str(const char *typestr);
bool PyC_StructFmt_type_is_float_any(char format);
bool PyC_StructFmt_type_is_int_any(char format);
bool PyC_StructFmt_type_is_byte(char format);
bool PyC_StructFmt_type_is_bool(char format);

#endif /* __PY_CAPI_UTILS_H__ */

#ifdef __cplusplus
}
#endif