1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup pythonintern
19  *
20  * This file defines the animation related methods used in bpy_rna.c
21  */
22 
23 #include <Python.h>
24 #include <float.h> /* FLT_MAX */
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_string.h"
29 #include "BLI_string_utils.h"
30 #include "BLI_utildefines.h"
31 
32 #include "DNA_anim_types.h"
33 #include "DNA_scene_types.h"
34 
35 #include "ED_keyframes_edit.h"
36 #include "ED_keyframing.h"
37 
38 #include "BKE_anim_data.h"
39 #include "BKE_animsys.h"
40 #include "BKE_context.h"
41 #include "BKE_fcurve.h"
42 #include "BKE_global.h"
43 #include "BKE_idtype.h"
44 #include "BKE_lib_id.h"
45 #include "BKE_report.h"
46 
47 #include "RNA_access.h"
48 #include "RNA_enum_types.h"
49 
50 #include "WM_api.h"
51 #include "WM_types.h"
52 
53 #include "bpy_capi_utils.h"
54 #include "bpy_rna.h"
55 #include "bpy_rna_anim.h"
56 
57 #include "../generic/python_utildefines.h"
58 
59 #include "DEG_depsgraph_build.h"
60 
61 /* for keyframes and drivers */
pyrna_struct_anim_args_parse_ex(PointerRNA * ptr,const char * error_prefix,const char * path,const char ** r_path_full,int * r_index,bool * r_path_no_validate)62 static int pyrna_struct_anim_args_parse_ex(PointerRNA *ptr,
63                                            const char *error_prefix,
64                                            const char *path,
65                                            const char **r_path_full,
66                                            int *r_index,
67                                            bool *r_path_no_validate)
68 {
69   const bool is_idbase = RNA_struct_is_ID(ptr->type);
70   PropertyRNA *prop;
71   PointerRNA r_ptr;
72 
73   if (ptr->data == NULL) {
74     PyErr_Format(
75         PyExc_TypeError, "%.200s this struct has no data, can't be animated", error_prefix);
76     return -1;
77   }
78 
79   /* full paths can only be given from ID base */
80   if (is_idbase) {
81     int path_index = -1;
82     if (RNA_path_resolve_property_full(ptr, path, &r_ptr, &prop, &path_index) == false) {
83       prop = NULL;
84     }
85     else if (path_index != -1) {
86       PyErr_Format(PyExc_ValueError,
87                    "%.200s path includes index, must be a separate argument",
88                    error_prefix,
89                    path);
90       return -1;
91     }
92     else if (ptr->owner_id != r_ptr.owner_id) {
93       PyErr_Format(PyExc_ValueError, "%.200s path spans ID blocks", error_prefix, path);
94       return -1;
95     }
96   }
97   else {
98     prop = RNA_struct_find_property(ptr, path);
99     r_ptr = *ptr;
100   }
101 
102   if (prop == NULL) {
103     if (r_path_no_validate) {
104       *r_path_no_validate = true;
105       return -1;
106     }
107     PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not found", error_prefix, path);
108     return -1;
109   }
110 
111   if (r_path_no_validate) {
112     /* Don't touch the index. */
113   }
114   else {
115     if (!RNA_property_animateable(&r_ptr, prop)) {
116       PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not animatable", error_prefix, path);
117       return -1;
118     }
119 
120     if (RNA_property_array_check(prop) == 0) {
121       if ((*r_index) == -1) {
122         *r_index = 0;
123       }
124       else {
125         PyErr_Format(PyExc_TypeError,
126                      "%.200s index %d was given while property \"%s\" is not an array",
127                      error_prefix,
128                      *r_index,
129                      path);
130         return -1;
131       }
132     }
133     else {
134       const int array_len = RNA_property_array_length(&r_ptr, prop);
135       if ((*r_index) < -1 || (*r_index) >= array_len) {
136         PyErr_Format(PyExc_TypeError,
137                      "%.200s index out of range \"%s\", given %d, array length is %d",
138                      error_prefix,
139                      path,
140                      *r_index,
141                      array_len);
142         return -1;
143       }
144     }
145   }
146 
147   if (is_idbase) {
148     *r_path_full = BLI_strdup(path);
149   }
150   else {
151     *r_path_full = RNA_path_from_ID_to_property(&r_ptr, prop);
152 
153     if (*r_path_full == NULL) {
154       PyErr_Format(PyExc_TypeError, "%.200s could not make path to \"%s\"", error_prefix, path);
155       return -1;
156     }
157   }
158 
159   return 0;
160 }
161 
pyrna_struct_anim_args_parse(PointerRNA * ptr,const char * error_prefix,const char * path,const char ** r_path_full,int * r_index)162 static int pyrna_struct_anim_args_parse(PointerRNA *ptr,
163                                         const char *error_prefix,
164                                         const char *path,
165                                         const char **r_path_full,
166                                         int *r_index)
167 {
168   return pyrna_struct_anim_args_parse_ex(ptr, error_prefix, path, r_path_full, r_index, NULL);
169 }
170 
171 /**
172  * Unlike #pyrna_struct_anim_args_parse \a r_path_full may be copied from \a path.
173  */
pyrna_struct_anim_args_parse_no_resolve(PointerRNA * ptr,const char * error_prefix,const char * path,const char ** r_path_full)174 static int pyrna_struct_anim_args_parse_no_resolve(PointerRNA *ptr,
175                                                    const char *error_prefix,
176                                                    const char *path,
177                                                    const char **r_path_full)
178 {
179   const bool is_idbase = RNA_struct_is_ID(ptr->type);
180   if (is_idbase) {
181     *r_path_full = path;
182     return 0;
183   }
184 
185   char *path_prefix = RNA_path_from_ID_to_struct(ptr);
186   if (path_prefix == NULL) {
187     PyErr_Format(PyExc_TypeError,
188                  "%.200s could not make path for type %s",
189                  error_prefix,
190                  RNA_struct_identifier(ptr->type));
191     return -1;
192   }
193 
194   if (*path == '[') {
195     *r_path_full = BLI_string_joinN(path_prefix, path);
196   }
197   else {
198     *r_path_full = BLI_string_join_by_sep_charN('.', path_prefix, path);
199   }
200   MEM_freeN(path_prefix);
201 
202   return 0;
203 }
204 
pyrna_struct_anim_args_parse_no_resolve_fallback(PointerRNA * ptr,const char * error_prefix,const char * path,const char ** r_path_full,int * r_index)205 static int pyrna_struct_anim_args_parse_no_resolve_fallback(PointerRNA *ptr,
206                                                             const char *error_prefix,
207                                                             const char *path,
208                                                             const char **r_path_full,
209                                                             int *r_index)
210 {
211   bool path_unresolved = false;
212   if (pyrna_struct_anim_args_parse_ex(
213           ptr, error_prefix, path, r_path_full, r_index, &path_unresolved) == -1) {
214     if (path_unresolved == true) {
215       if (pyrna_struct_anim_args_parse_no_resolve(ptr, error_prefix, path, r_path_full) == -1) {
216         return -1;
217       }
218     }
219     else {
220       return -1;
221     }
222   }
223   return 0;
224 }
225 
226 /* internal use for insert and delete */
pyrna_struct_keyframe_parse(PointerRNA * ptr,PyObject * args,PyObject * kw,const char * parse_str,const char * error_prefix,const char ** r_path_full,int * r_index,float * r_cfra,const char ** r_group_name,int * r_options)227 static int pyrna_struct_keyframe_parse(PointerRNA *ptr,
228                                        PyObject *args,
229                                        PyObject *kw,
230                                        const char *parse_str,
231                                        const char *error_prefix,
232                                        /* return values */
233                                        const char **r_path_full,
234                                        int *r_index,
235                                        float *r_cfra,
236                                        const char **r_group_name,
237                                        int *r_options)
238 {
239   static const char *kwlist[] = {"data_path", "index", "frame", "group", "options", NULL};
240   PyObject *pyoptions = NULL;
241   const char *path;
242 
243   /* note, parse_str MUST start with 's|ifsO!' */
244   if (!PyArg_ParseTupleAndKeywords(args,
245                                    kw,
246                                    parse_str,
247                                    (char **)kwlist,
248                                    &path,
249                                    r_index,
250                                    r_cfra,
251                                    r_group_name,
252                                    &PySet_Type,
253                                    &pyoptions)) {
254     return -1;
255   }
256 
257   if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, r_path_full, r_index) == -1) {
258     return -1;
259   }
260 
261   if (*r_cfra == FLT_MAX) {
262     *r_cfra = CTX_data_scene(BPY_context_get())->r.cfra;
263   }
264 
265   /* flag may be null (no option currently for remove keyframes e.g.). */
266   if (r_options) {
267     if (pyoptions &&
268         (pyrna_set_to_enum_bitfield(
269              rna_enum_keying_flag_items_api, pyoptions, r_options, error_prefix) == -1)) {
270       return -1;
271     }
272 
273     *r_options |= INSERTKEY_NO_USERPREF;
274   }
275 
276   return 0; /* success */
277 }
278 
279 char pyrna_struct_keyframe_insert_doc[] =
280     ".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, "
281     "group=\"\", options=set())\n"
282     "\n"
283     "   Insert a keyframe on the property given, adding fcurves and animation data when "
284     "necessary.\n"
285     "\n"
286     "   :arg data_path: path to the property to key, analogous to the fcurve's data path.\n"
287     "   :type data_path: string\n"
288     "   :arg index: array index of the property to key.\n"
289     "      Defaults to -1 which will key all indices or a single channel if the property is not "
290     "an array.\n"
291     "   :type index: int\n"
292     "   :arg frame: The frame on which the keyframe is inserted, defaulting to the current "
293     "frame.\n"
294     "   :type frame: float\n"
295     "   :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
296     "yet.\n"
297     "   :type group: str\n"
298     "   :arg options: Optional set of flags:\n"
299     "\n"
300     "      - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant "
301     "F-Curves.\n"
302     "      - ``INSERTKEY_VISUAL`` Insert keyframes based on 'visual transforms'.\n"
303     "      - ``INSERTKEY_XYZ_TO_RGB`` Color for newly added transformation F-Curves (Location, "
304     "Rotation, Scale) is based on the transform axis.\n"
305     "      - ``INSERTKEY_REPLACE`` Only replace already existing keyframes.\n"
306     "      - ``INSERTKEY_AVAILABLE`` Only insert into already existing F-Curves.\n"
307     "      - ``INSERTKEY_CYCLE_AWARE`` Take cyclic extrapolation into account "
308     "(Cycle-Aware Keying option).\n"
309     "   :type flag: set\n"
310     "   :return: Success of keyframe insertion.\n"
311     "   :rtype: boolean\n";
pyrna_struct_keyframe_insert(BPy_StructRNA * self,PyObject * args,PyObject * kw)312 PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw)
313 {
314   /* args, pyrna_struct_keyframe_parse handles these */
315   const char *path_full = NULL;
316   int index = -1;
317   float cfra = FLT_MAX;
318   const char *group_name = NULL;
319   const char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */
320   int options = 0;
321 
322   PYRNA_STRUCT_CHECK_OBJ(self);
323 
324   if (pyrna_struct_keyframe_parse(&self->ptr,
325                                   args,
326                                   kw,
327                                   "s|ifsO!:bpy_struct.keyframe_insert()",
328                                   "bpy_struct.keyframe_insert()",
329                                   &path_full,
330                                   &index,
331                                   &cfra,
332                                   &group_name,
333                                   &options) == -1) {
334     return NULL;
335   }
336 
337   /* This assumes that keyframes are only added on original data & using the active depsgraph. If
338    * it turns out to be necessary for some reason to insert keyframes on evaluated objects, we can
339    * revisit this and add an explicit `depsgraph` keyword argument to the function call.
340    *
341    * It is unlikely that driver code (which is the reason this depsgraph pointer is obtained) will
342    * be executed from this function call, as this only happens when `options` has
343    * `INSERTKEY_DRIVER`, which is not exposed to Python. */
344   bContext *C = BPY_context_get();
345   struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
346   const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
347                                                                                     cfra);
348 
349   if (self->ptr.type == &RNA_NlaStrip) {
350     /* Handle special properties for NLA Strips, whose F-Curves are stored on the
351      * strips themselves. These are stored separately or else the properties will
352      * not have any effect.
353      */
354     ReportList reports;
355     bool result = false;
356 
357     PointerRNA ptr = self->ptr;
358     PropertyRNA *prop = NULL;
359     const char *prop_name;
360 
361     BKE_reports_init(&reports, RPT_STORE);
362 
363     /* Retrieve the property identifier from the full path, since we can't get it any other way */
364     prop_name = strrchr(path_full, '.');
365     if ((prop_name >= path_full) && (prop_name + 1 < path_full + strlen(path_full))) {
366       prop = RNA_struct_find_property(&ptr, prop_name + 1);
367     }
368 
369     if (prop) {
370       NlaStrip *strip = ptr.data;
371       FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
372       result = insert_keyframe_direct(
373           &reports, ptr, prop, fcu, &anim_eval_context, keytype, NULL, options);
374     }
375     else {
376       BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
377     }
378     MEM_freeN((void *)path_full);
379 
380     if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
381       return NULL;
382     }
383 
384     return PyBool_FromLong(result);
385   }
386 
387   ID *id = self->ptr.owner_id;
388   ReportList reports;
389   bool result;
390 
391   BKE_reports_init(&reports, RPT_STORE);
392 
393   BLI_assert(BKE_id_is_in_global_main(id));
394   result = (insert_keyframe(G_MAIN,
395                             &reports,
396                             id,
397                             NULL,
398                             group_name,
399                             path_full,
400                             index,
401                             &anim_eval_context,
402                             keytype,
403                             NULL,
404                             options) != 0);
405   MEM_freeN((void *)path_full);
406 
407   if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
408     return NULL;
409   }
410 
411   return PyBool_FromLong(result);
412 }
413 
414 char pyrna_struct_keyframe_delete_doc[] =
415     ".. method:: keyframe_delete(data_path, index=-1, frame=bpy.context.scene.frame_current, "
416     "group=\"\")\n"
417     "\n"
418     "   Remove a keyframe from this properties fcurve.\n"
419     "\n"
420     "   :arg data_path: path to the property to remove a key, analogous to the fcurve's data "
421     "path.\n"
422     "   :type data_path: string\n"
423     "   :arg index: array index of the property to remove a key. Defaults to -1 removing all "
424     "indices or a single channel if the property is not an array.\n"
425     "   :type index: int\n"
426     "   :arg frame: The frame on which the keyframe is deleted, defaulting to the current frame.\n"
427     "   :type frame: float\n"
428     "   :arg group: The name of the group the F-Curve should be added to if it doesn't exist "
429     "yet.\n"
430     "   :type group: str\n"
431     "   :return: Success of keyframe deletion.\n"
432     "   :rtype: boolean\n";
pyrna_struct_keyframe_delete(BPy_StructRNA * self,PyObject * args,PyObject * kw)433 PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw)
434 {
435   /* args, pyrna_struct_keyframe_parse handles these */
436   const char *path_full = NULL;
437   int index = -1;
438   float cfra = FLT_MAX;
439   const char *group_name = NULL;
440 
441   PYRNA_STRUCT_CHECK_OBJ(self);
442 
443   if (pyrna_struct_keyframe_parse(&self->ptr,
444                                   args,
445                                   kw,
446                                   "s|ifsO!:bpy_struct.keyframe_delete()",
447                                   "bpy_struct.keyframe_insert()",
448                                   &path_full,
449                                   &index,
450                                   &cfra,
451                                   &group_name,
452                                   NULL) == -1) {
453     return NULL;
454   }
455   if (self->ptr.type == &RNA_NlaStrip) {
456     /* Handle special properties for NLA Strips, whose F-Curves are stored on the
457      * strips themselves. These are stored separately or else the properties will
458      * not have any effect.
459      */
460     ReportList reports;
461     bool result = false;
462 
463     PointerRNA ptr = self->ptr;
464     PropertyRNA *prop = NULL;
465     const char *prop_name;
466 
467     BKE_reports_init(&reports, RPT_STORE);
468 
469     /* Retrieve the property identifier from the full path, since we can't get it any other way */
470     prop_name = strrchr(path_full, '.');
471     if ((prop_name >= path_full) && (prop_name + 1 < path_full + strlen(path_full))) {
472       prop = RNA_struct_find_property(&ptr, prop_name + 1);
473     }
474 
475     if (prop) {
476       ID *id = ptr.owner_id;
477       NlaStrip *strip = ptr.data;
478       FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
479 
480       /* NOTE: This should be true, or else we wouldn't be able to get here. */
481       BLI_assert(fcu != NULL);
482 
483       if (BKE_fcurve_is_protected(fcu)) {
484         BKE_reportf(
485             &reports,
486             RPT_WARNING,
487             "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
488             strip->name,
489             BKE_idtype_idcode_to_name(GS(id->name)),
490             id->name + 2);
491       }
492       else {
493         /* remove the keyframe directly
494          * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
495          *       and delete_keyframe() expects the FCurve to be part of an action
496          */
497         bool found = false;
498         int i;
499 
500         /* try to find index of beztriple to get rid of */
501         i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
502         if (found) {
503           /* delete the key at the index (will sanity check + do recalc afterwards) */
504           delete_fcurve_key(fcu, i, 1);
505           result = true;
506         }
507       }
508     }
509     else {
510       BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
511     }
512     MEM_freeN((void *)path_full);
513 
514     if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
515       return NULL;
516     }
517 
518     return PyBool_FromLong(result);
519   }
520 
521   bool result;
522   ReportList reports;
523 
524   BKE_reports_init(&reports, RPT_STORE);
525 
526   result = (delete_keyframe(G.main, &reports, self->ptr.owner_id, NULL, path_full, index, cfra) !=
527             0);
528   MEM_freeN((void *)path_full);
529 
530   if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
531     return NULL;
532   }
533 
534   return PyBool_FromLong(result);
535 }
536 
537 char pyrna_struct_driver_add_doc[] =
538     ".. method:: driver_add(path, index=-1)\n"
539     "\n"
540     "   Adds driver(s) to the given property\n"
541     "\n"
542     "   :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
543     "   :type path: string\n"
544     "   :arg index: array index of the property drive. Defaults to -1 for all indices or a single "
545     "channel if the property is not an array.\n"
546     "   :type index: int\n"
547     "   :return: The driver(s) added.\n"
548     "   :rtype: :class:`bpy.types.FCurve` or list if index is -1 with an array property.\n";
pyrna_struct_driver_add(BPy_StructRNA * self,PyObject * args)549 PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
550 {
551   const char *path, *path_full;
552   int index = -1;
553 
554   PYRNA_STRUCT_CHECK_OBJ(self);
555 
556   if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index)) {
557     return NULL;
558   }
559 
560   if (pyrna_struct_anim_args_parse(
561           &self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) == -1) {
562     return NULL;
563   }
564 
565   PyObject *ret = NULL;
566   ReportList reports;
567   int result;
568 
569   BKE_reports_init(&reports, RPT_STORE);
570 
571   result = ANIM_add_driver(&reports,
572                            (ID *)self->ptr.owner_id,
573                            path_full,
574                            index,
575                            CREATEDRIVER_WITH_FMODIFIER,
576                            DRIVER_TYPE_PYTHON);
577 
578   if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
579     return NULL;
580   }
581 
582   if (result) {
583     ID *id = self->ptr.owner_id;
584     AnimData *adt = BKE_animdata_from_id(id);
585     FCurve *fcu;
586 
587     PointerRNA tptr;
588 
589     if (index == -1) { /* all, use a list */
590       int i = 0;
591       ret = PyList_New(0);
592       while ((fcu = BKE_fcurve_find(&adt->drivers, path_full, i++))) {
593         RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
594         PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr));
595       }
596     }
597     else {
598       fcu = BKE_fcurve_find(&adt->drivers, path_full, index);
599       RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
600       ret = pyrna_struct_CreatePyObject(&tptr);
601     }
602 
603     bContext *context = BPY_context_get();
604     WM_event_add_notifier(BPY_context_get(), NC_ANIMATION | ND_FCURVES_ORDER, NULL);
605     DEG_relations_tag_update(CTX_data_main(context));
606   }
607   else {
608     /* XXX, should be handled by reports, */
609     PyErr_SetString(PyExc_TypeError,
610                     "bpy_struct.driver_add(): failed because of an internal error");
611     return NULL;
612   }
613 
614   MEM_freeN((void *)path_full);
615 
616   return ret;
617 }
618 
619 char pyrna_struct_driver_remove_doc[] =
620     ".. method:: driver_remove(path, index=-1)\n"
621     "\n"
622     "   Remove driver(s) from the given property\n"
623     "\n"
624     "   :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
625     "   :type path: string\n"
626     "   :arg index: array index of the property drive. Defaults to -1 for all indices or a single "
627     "channel if the property is not an array.\n"
628     "   :type index: int\n"
629     "   :return: Success of driver removal.\n"
630     "   :rtype: boolean\n";
pyrna_struct_driver_remove(BPy_StructRNA * self,PyObject * args)631 PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args)
632 {
633   const char *path, *path_full;
634   int index = -1;
635 
636   PYRNA_STRUCT_CHECK_OBJ(self);
637 
638   if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index)) {
639     return NULL;
640   }
641 
642   if (pyrna_struct_anim_args_parse_no_resolve_fallback(
643           &self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) == -1) {
644     return NULL;
645   }
646 
647   short result;
648   ReportList reports;
649 
650   BKE_reports_init(&reports, RPT_STORE);
651 
652   result = ANIM_remove_driver(&reports, (ID *)self->ptr.owner_id, path_full, index, 0);
653 
654   if (path != path_full) {
655     MEM_freeN((void *)path_full);
656   }
657 
658   if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) {
659     return NULL;
660   }
661 
662   bContext *context = BPY_context_get();
663   WM_event_add_notifier(context, NC_ANIMATION | ND_FCURVES_ORDER, NULL);
664   DEG_relations_tag_update(CTX_data_main(context));
665 
666   return PyBool_FromLong(result);
667 }
668