PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args) { const char *path, *path_full; int index = -1; PYRNA_STRUCT_CHECK_OBJ(self); if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index)) return NULL; if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) == -1) { return NULL; } else { short result; ReportList reports; BKE_reports_init(&reports, RPT_STORE); result = ANIM_remove_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0); MEM_freeN((void *)path_full); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) return NULL; WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION | ND_FCURVES_ORDER, NULL); return PyBool_FromLong(result); } }
PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) { const char *path, *path_full; int index = -1; PYRNA_STRUCT_CHECK_OBJ(self); if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index)) return NULL; if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) == -1) { return NULL; } else { PyObject *ret = NULL; ReportList reports; int result; BKE_reports_init(&reports, RPT_STORE); result = ANIM_add_driver(&reports, (ID *)self->ptr.id.data, path_full, index, CREATEDRIVER_WITH_FMODIFIER, DRIVER_TYPE_PYTHON); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) return NULL; if (result) { ID *id = self->ptr.id.data; AnimData *adt = BKE_animdata_from_id(id); FCurve *fcu; PointerRNA tptr; if (index == -1) { /* all, use a list */ int i = 0; ret = PyList_New(0); while ((fcu = list_find_fcurve(&adt->drivers, path_full, i++))) { RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr); PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr)); } } else { fcu = list_find_fcurve(&adt->drivers, path_full, index); RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr); ret = pyrna_struct_CreatePyObject(&tptr); } WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION | ND_FCURVES_ORDER, NULL); } else { /* XXX, should be handled by reports, */ PyErr_SetString(PyExc_TypeError, "bpy_struct.driver_add(): failed because of an internal error"); return NULL; } MEM_freeN((void *)path_full); return ret; } }
PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw) { /* args, pyrna_struct_keyframe_parse handles these */ const char *path_full = NULL; int index = -1; float cfra = FLT_MAX; const char *group_name = NULL; PYRNA_STRUCT_CHECK_OBJ(self); if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, "s|ifsO!:bpy_struct.keyframe_delete()", "bpy_struct.keyframe_insert()", &path_full, &index, &cfra, &group_name, NULL) == -1) { return NULL; } else { short result; ReportList reports; BKE_reports_init(&reports, RPT_STORE); result = delete_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0); MEM_freeN((void *)path_full); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) return NULL; return PyBool_FromLong(result); } }
PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw) { /* args, pyrna_struct_keyframe_parse handles these */ const char *path_full = NULL; int index = -1; float cfra = FLT_MAX; const char *group_name = NULL; char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */ int options = 0; PYRNA_STRUCT_CHECK_OBJ(self); if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, "s|ifsO!:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", &path_full, &index, &cfra, &group_name, &options) == -1) { return NULL; } else { short result; ReportList reports; BKE_reports_init(&reports, RPT_STORE); result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, keytype, options); MEM_freeN((void *)path_full); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) return NULL; return PyBool_FromLong(result); } }
static PyObject *bpy_lib_enter(BPy_Library *self) { PyObject *ret; BPy_Library *self_from; PyObject *from_dict = _PyDict_NewPresized(MAX_LIBARRAY); ReportList reports; BKE_reports_init(&reports, RPT_STORE); self->blo_handle = BLO_blendhandle_from_file(self->abspath, &reports); if (self->blo_handle == NULL) { if (BPy_reports_to_error(&reports, PyExc_IOError, true) != -1) { PyErr_Format(PyExc_IOError, "load: %s failed to open blend file", self->abspath); } return NULL; } else { int i = 0, code; while ((code = BKE_idcode_iter_step(&i))) { if (BKE_idcode_is_linkable(code)) { const char *name_plural = BKE_idcode_to_name_plural(code); PyObject *str = PyUnicode_FromString(name_plural); PyObject *item; PyDict_SetItem(self->dict, str, item = PyList_New(0)); Py_DECREF(item); PyDict_SetItem(from_dict, str, item = _bpy_names(self, code)); Py_DECREF(item); Py_DECREF(str); } } } /* create a dummy */ self_from = PyObject_New(BPy_Library, &bpy_lib_Type); BLI_strncpy(self_from->relpath, self->relpath, sizeof(self_from->relpath)); BLI_strncpy(self_from->abspath, self->abspath, sizeof(self_from->abspath)); self_from->blo_handle = NULL; self_from->flag = 0; self_from->dict = from_dict; /* owns the dict */ /* return pair */ ret = PyTuple_New(2); PyTuple_SET_ITEMS(ret, (PyObject *)self_from, (PyObject *)self); Py_INCREF(self); BKE_reports_clear(&reports); return ret; }
static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) { static const char *kwlist[] = { "filepath", "datablocks", /* optional */ "relative_remap", "fake_user", "compress", NULL, }; /* args */ const char *filepath; char filepath_abs[FILE_MAX]; PyObject *datablocks = NULL; bool use_relative_remap = false, use_fake_user = false, use_compress = false; if (!PyArg_ParseTupleAndKeywords( args, kwds, "sO!|$O&O&O&:write", (char **)kwlist, &filepath, &PySet_Type, &datablocks, PyC_ParseBool, &use_relative_remap, PyC_ParseBool, &use_fake_user, PyC_ParseBool, &use_compress)) { return NULL; } Main *bmain_src = G.main; int write_flags = 0; if (use_relative_remap) { write_flags |= G_FILE_RELATIVE_REMAP; } if (use_compress) { write_flags |= G_FILE_COMPRESS; } BLI_strncpy(filepath_abs, filepath, FILE_MAX); BLI_path_abs(filepath_abs, G.main->name); BKE_blendfile_write_partial_begin(bmain_src); /* array of ID's and backup any data we modify */ struct { ID *id; /* original values */ short id_flag; short id_us; } *id_store_array, *id_store; int id_store_len = 0; PyObject *ret; /* collect all id data from the set and store in 'id_store_array' */ { Py_ssize_t pos, hash; PyObject *key; id_store_array = MEM_mallocN(sizeof(*id_store_array) * PySet_Size(datablocks), __func__); id_store = id_store_array; pos = hash = 0; while (_PySet_NextEntry(datablocks, &pos, &key, &hash)) { if (!pyrna_id_FromPyObject(key, &id_store->id)) { PyErr_Format(PyExc_TypeError, "Expected and ID type, not %.200s", Py_TYPE(key)->tp_name); ret = NULL; goto finally; } else { id_store->id_flag = id_store->id->flag; id_store->id_us = id_store->id->us; if (use_fake_user) { id_store->id->flag |= LIB_FAKEUSER; } id_store->id->us = 1; BKE_blendfile_write_partial_tag_ID(id_store->id, true); id_store_len += 1; id_store++; } } } /* write blend */ int retval = 0; ReportList reports; BKE_reports_init(&reports, RPT_STORE); retval = BKE_blendfile_write_partial(bmain_src, filepath_abs, write_flags, &reports); /* cleanup state */ BKE_blendfile_write_partial_end(bmain_src); if (retval) { BKE_reports_print(&reports, RPT_ERROR_ALL); BKE_reports_clear(&reports); ret = Py_None; Py_INCREF(ret); } else { if (BPy_reports_to_error(&reports, PyExc_IOError, true) == 0) { PyErr_SetString(PyExc_IOError, "Unknown error writing library data"); } ret = NULL; } finally: /* clear all flags for ID's added to the store (may run on error too) */ id_store = id_store_array; for (int i = 0; i < id_store_len; id_store++, i++) { if (use_fake_user) { if ((id_store->id_flag & LIB_FAKEUSER) == 0) { id_store->id->flag &= ~LIB_FAKEUSER; } } id_store->id->us = id_store->id_us; BKE_blendfile_write_partial_tag_ID(id_store->id, false); } MEM_freeN(id_store_array); return ret; }
static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) { wmOperatorType *ot; int error_val = 0; PointerRNA ptr; int operator_ret = OPERATOR_CANCELLED; char *opname; char *context_str = NULL; PyObject *kw = NULL; /* optional args */ PyObject *context_dict = NULL; /* optional args */ PyObject *context_dict_back; /* note that context is an int, python does the conversion in this case */ int context = WM_OP_EXEC_DEFAULT; int is_undo = false; /* XXX Todo, work out a better solution for passing on context, * could make a tuple from self and pack the name and Context into it... */ bContext *C = (bContext *)BPy_GetContext(); if (C == NULL) { PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators"); return NULL; } if (!PyArg_ParseTuple(args, "sO|O!si:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context_str, &is_undo)) { return NULL; } ot = WM_operatortype_find(opname, true); if (ot == NULL) { PyErr_Format(PyExc_AttributeError, "Calling operator \"bpy.ops.%s\" error, " "could not be found", opname); return NULL; } if (!pyrna_write_check()) { PyErr_Format(PyExc_RuntimeError, "Calling operator \"bpy.ops.%s\" error, " "can't modify blend data in this state (drawing/rendering)", opname); return NULL; } if (context_str) { if (RNA_enum_value_from_id(operator_context_items, context_str, &context) == 0) { char *enum_str = BPy_enum_as_string(operator_context_items); PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, " "expected a string enum in (%.200s)", opname, enum_str); MEM_freeN(enum_str); return NULL; } } if (context_dict == NULL || context_dict == Py_None) { context_dict = NULL; } else if (!PyDict_Check(context_dict)) { PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, " "custom context expected a dict or None, got a %.200s", opname, Py_TYPE(context_dict)->tp_name); return NULL; } context_dict_back = CTX_py_dict_get(C); CTX_py_dict_set(C, (void *)context_dict); Py_XINCREF(context_dict); /* so we done loose it */ if (WM_operator_poll_context((bContext *)C, ot, context) == false) { const char *msg = CTX_wm_operator_poll_msg_get(C); PyErr_Format(PyExc_RuntimeError, "Operator bpy.ops.%.200s.poll() %.200s", opname, msg ? msg : "failed, context is incorrect"); CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */ error_val = -1; } else { WM_operator_properties_create_ptr(&ptr, ot); WM_operator_properties_sanitize(&ptr, 0); if (kw && PyDict_Size(kw)) error_val = pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); if (error_val == 0) { ReportList *reports; reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD); /* own so these don't move into global reports */ #ifdef BPY_RELEASE_GIL /* release GIL, since a thread could be started from an operator * that updates a driver */ /* note: I have not seen any examples of code that does this * so it may not be officially supported but seems to work ok. */ { PyThreadState *ts = PyEval_SaveThread(); #endif operator_ret = WM_operator_call_py(C, ot, context, &ptr, reports, is_undo); #ifdef BPY_RELEASE_GIL /* regain GIL */ PyEval_RestoreThread(ts); } #endif error_val = BPy_reports_to_error(reports, PyExc_RuntimeError, false); /* operator output is nice to have in the terminal/console too */ if (reports->list.first) { char *report_str = BKE_reports_string(reports, 0); /* all reports */ if (report_str) { PySys_WriteStdout("%s\n", report_str); MEM_freeN(report_str); } } BKE_reports_clear(reports); if ((reports->flag & RPT_FREE) == 0) { MEM_freeN(reports); } } WM_operator_properties_free(&ptr); #if 0 /* if there is some way to know an operator takes args we should use this */ { /* no props */ if (kw != NULL) { PyErr_Format(PyExc_AttributeError, "Operator \"%s\" does not take any args", opname); return NULL; } WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL); } #endif } /* restore with original context dict, probably NULL but need this for nested operator calls */ Py_XDECREF(context_dict); CTX_py_dict_set(C, (void *)context_dict_back); if (error_val == -1) { return NULL; } /* when calling bpy.ops.wm.read_factory_settings() bpy.data's main pointer is freed by clear_globals(), * further access will crash blender. setting context is not needed in this case, only calling because this * function corrects bpy.data (internal Main pointer) */ BPY_modules_update(C); /* needed for when WM_OT_read_factory_settings us called from within a script */ bpy_import_main_set(CTX_data_main(C)); /* return operator_ret as a bpy enum */ return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret); }