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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/python/intern')
-rw-r--r--source/blender/python/intern/bpy.c27
-rw-r--r--source/blender/python/intern/bpy.h2
-rw-r--r--source/blender/python/intern/bpy_app_translations.c4
-rw-r--r--source/blender/python/intern/bpy_capi_utils.c3
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h6
-rw-r--r--source/blender/python/intern/bpy_driver.c42
-rw-r--r--source/blender/python/intern/bpy_driver.h8
-rw-r--r--source/blender/python/intern/bpy_interface.c23
-rw-r--r--source/blender/python/intern/bpy_interface_run.c32
-rw-r--r--source/blender/python/intern/bpy_library_load.c249
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c8
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.h8
-rw-r--r--source/blender/python/intern/bpy_props.c18
-rw-r--r--source/blender/python/intern/bpy_props.h4
-rw-r--r--source/blender/python/intern/bpy_rna.c16
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/intern/bpy_rna_array.c3
-rw-r--r--source/blender/python/intern/bpy_rna_data.c2
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c3
-rw-r--r--source/blender/python/intern/bpy_rna_driver.h3
20 files changed, 224 insertions, 241 deletions
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 3377b2c283e..c792773272b 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -94,10 +94,13 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self))
return ret;
}
-static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
+static bool bpy_blend_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- PyList_APPEND((PyObject *)userdata, PyC_UnicodeFromByte(path_src));
- return false; /* never edits the path */
+ PyObject *py_list = bpath_data->user_data;
+ PyList_APPEND(py_list, PyC_UnicodeFromByte(path_src));
+ return false; /* Never edits the path. */
}
PyDoc_STRVAR(bpy_blend_paths_doc,
@@ -115,7 +118,7 @@ PyDoc_STRVAR(bpy_blend_paths_doc,
" :rtype: list of strings\n");
static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- int flag = 0;
+ eBPathForeachFlag flag = 0;
PyObject *list;
bool absolute = false;
@@ -137,18 +140,23 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
}
if (absolute) {
- flag |= BKE_BPATH_TRAVERSE_ABS;
+ flag |= BKE_BPATH_FOREACH_PATH_ABSOLUTE;
}
if (!packed) {
- flag |= BKE_BPATH_TRAVERSE_SKIP_PACKED;
+ flag |= BKE_BPATH_FOREACH_PATH_SKIP_PACKED;
}
if (local) {
- flag |= BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
+ flag |= BKE_BPATH_FOREACH_PATH_SKIP_LINKED;
}
list = PyList_New(0);
- BKE_bpath_traverse_main(G_MAIN, bpy_blend_paths_visit_cb, flag, (void *)list);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = G_MAIN,
+ .callback_function = bpy_blend_foreach_path_cb,
+ .flag = flag,
+ .user_data = list,
+ });
return list;
}
@@ -442,9 +450,6 @@ static PyObject *bpy_import_test(const char *modname)
return mod;
}
-/******************************************************************************
- * Description: Creates the bpy module and adds it to sys.modules for importing
- ******************************************************************************/
void BPy_init_modules(struct bContext *C)
{
PointerRNA ctx_ptr;
diff --git a/source/blender/python/intern/bpy.h b/source/blender/python/intern/bpy.h
index 25a047edfb5..b77a3e9fb7d 100644
--- a/source/blender/python/intern/bpy.h
+++ b/source/blender/python/intern/bpy.h
@@ -26,7 +26,9 @@ extern "C" {
struct bContext;
+/** Creates the bpy module and adds it to `sys.modules` for importing. */
void BPy_init_modules(struct bContext *C);
+
extern PyObject *bpy_package_py;
/* bpy_interface_atexit.c */
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index de70035eb2b..4fa71c0c976 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -69,12 +69,12 @@ static BlenderAppTranslations *_translations = NULL;
/** \} */
-#ifdef WITH_INTERNATIONAL
-
/* ------------------------------------------------------------------- */
/** \name Helpers for GHash
* \{ */
+#ifdef WITH_INTERNATIONAL
+
typedef struct GHashKey {
const char *msgctxt;
const char *msgid;
diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c
index 8e9d8c02c03..ed01132ed4e 100644
--- a/source/blender/python/intern/bpy_capi_utils.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -56,9 +56,6 @@ short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool
return (report_str == NULL) ? 0 : -1;
}
-/**
- * A version of #BKE_report_write_file_fp that uses Python's stdout.
- */
void BPy_reports_write_stdout(const ReportList *reports, const char *header)
{
if (header) {
diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h
index 80e92d918ac..0e4a28fb657 100644
--- a/source/blender/python/intern/bpy_capi_utils.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -33,6 +33,9 @@ struct ReportList;
/* error reporting */
short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear);
+/**
+ * A version of #BKE_report_write_file_fp that uses Python's stdout.
+ */
void BPy_reports_write_stdout(const struct ReportList *reports, const char *header);
bool BPy_errors_to_report_ex(struct ReportList *reports,
const char *error_prefix,
@@ -44,6 +47,9 @@ bool BPy_errors_to_report(struct ReportList *reports);
struct bContext *BPY_context_get(void);
extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate);
+/**
+ * Context should be used but not now because it causes some bugs.
+ */
extern void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate);
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 7effa25e6e8..bd1f3cd301f 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -57,19 +57,12 @@
# include <opcode.h>
#endif
-/**
- * For PyDrivers
- * (drivers using one-line Python expressions to express relationships between targets).
- */
PyObject *bpy_pydriver_Dict = NULL;
#ifdef USE_BYTECODE_WHITELIST
static PyObject *bpy_pydriver_Dict__whitelist = NULL;
#endif
-/* For faster execution we keep a special dictionary for pydrivers, with
- * the needed modules and aliases.
- */
int bpy_pydriver_create_dict(void)
{
PyObject *d, *mod;
@@ -220,11 +213,6 @@ static void bpy_pydriver_namespace_clear_self(void)
}
}
-/* Update function, it gets rid of pydrivers global dictionary, forcing
- * BPY_driver_exec to recreate it. This function is used to force
- * reloading the Blender text module "pydrivers.py", if available, so
- * updates in it reach pydriver evaluation.
- */
void BPY_driver_reset(void)
{
PyGILState_STATE gilstate;
@@ -429,28 +417,24 @@ static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
}
}
-/**
- * This evaluates Python driver expressions, `driver_orig->expression`
- * is a Python expression that should evaluate to a float number, which is returned.
- *
- * (old) NOTE: PyGILState_Ensure() isn't always called because python can call
- * the bake operator which intern starts a thread which calls scene update
- * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
- * if #PyGILState_Ensure() is needed, see T27683.
- *
- * (new) NOTE: checking if python is running is not thread-safe T28114
- * now release the GIL on python operator execution instead, using
- * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
- *
- * For copy-on-write we always cache expressions and write errors in the
- * original driver, otherwise these would get freed while editing. Due to
- * the GIL this is thread-safe.
- */
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
ChannelDriver *driver,
ChannelDriver *driver_orig,
const AnimationEvalContext *anim_eval_context)
{
+ /* (old) NOTE: PyGILState_Ensure() isn't always called because python can call
+ * the bake operator which intern starts a thread which calls scene update
+ * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
+ * if #PyGILState_Ensure() is needed, see T27683.
+ *
+ * (new) NOTE: checking if python is running is not thread-safe T28114
+ * now release the GIL on python operator execution instead, using
+ * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
+ *
+ * For copy-on-write we always cache expressions and write errors in the
+ * original driver, otherwise these would get freed while editing.
+ * Due to the GIL this is thread-safe. */
+
PyObject *driver_vars = NULL;
PyObject *retval = NULL;
diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h
index d5064d9fa56..b7bb0f846e8 100644
--- a/source/blender/python/intern/bpy_driver.h
+++ b/source/blender/python/intern/bpy_driver.h
@@ -24,7 +24,15 @@
extern "C" {
#endif
+/**
+ * For faster execution we keep a special dictionary for py-drivers, with
+ * the needed modules and aliases.
+ */
int bpy_pydriver_create_dict(void);
+/**
+ * For PyDrivers
+ * (drivers using one-line Python expressions to express relationships between targets).
+ */
extern PyObject *bpy_pydriver_Dict;
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 95affa9dba9..faa668df775 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -80,6 +80,7 @@
#include "../mathutils/mathutils.h"
/* Logging types to use anywhere in the Python modules. */
+
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_CONTEXT, "bpy.context");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_INTERFACE, "bpy.interface");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna");
@@ -103,7 +104,6 @@ static double bpy_timer_run; /* time for each python script run */
static double bpy_timer_run_tot; /* accumulate python runs */
#endif
-/* use for updating while a python script runs - in case of file load */
void BPY_context_update(bContext *C)
{
/* don't do this from a non-main (e.g. render) thread, it can cause a race
@@ -141,7 +141,6 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
}
}
-/* context should be used but not now because it causes some bugs */
void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
{
py_call_level--;
@@ -175,16 +174,6 @@ static void bpy_context_end(bContext *C)
CTX_wm_operator_poll_msg_clear(C);
}
-/**
- * Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
- * In this case we don't want the Python context to override the values as it causes problems
- * see T66256.
- *
- * \param dict_p: A pointer to #bContext.data.py_context so we can assign a new value.
- * \param dict_orig: The value of #bContext.data.py_context_orig to check if we need to copy.
- *
- * \note Typically accessed via #BPY_context_dict_clear_members macro.
- */
void BPY_context_dict_clear_members_array(void **dict_p,
void *dict_orig,
const char *context_members[],
@@ -238,9 +227,6 @@ void BPY_text_free_code(Text *text)
}
}
-/**
- * Needed so the #Main pointer in `bpy.data` doesn't become out of date.
- */
void BPY_modules_update(void)
{
#if 0 /* slow, this runs all the time poll, draw etc 100's of time a sec. */
@@ -333,7 +319,6 @@ static void pystatus_exit_on_error(PyStatus status)
}
#endif
-/* call BPY_context_set first */
void BPY_python_start(bContext *C, int argc, const char **argv)
{
#ifndef WITH_PYTHON_MODULE
@@ -881,9 +866,6 @@ static void bpy_module_free(void *UNUSED(mod))
#endif
-/**
- * Avoids duplicating keyword list.
- */
bool BPY_string_is_keyword(const char *str)
{
/* list is from...
@@ -905,8 +887,7 @@ bool BPY_string_is_keyword(const char *str)
return false;
}
-/* EVIL, define text.c functions here... */
-/* BKE_text.h */
+/* EVIL: define `text.c` functions here (declared in `BKE_text.h`). */
int text_check_identifier_unicode(const uint ch)
{
return (ch < 255 && text_check_identifier((char)ch)) || Py_UNICODE_ISALNUM(ch);
diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c
index f7d6a33c904..bc21c91074f 100644
--- a/source/blender/python/intern/bpy_interface_run.c
+++ b/source/blender/python/intern/bpy_interface_run.c
@@ -80,6 +80,14 @@ typedef struct {
} PyModuleObject;
#endif
+/**
+ * Execute a file-path or text-block.
+ *
+ * \param reports: Report exceptions as errors (may be NULL).
+ * \param do_jump: See #BPY_run_text.
+ *
+ * \note Share a function for this since setup/cleanup logic is the same.
+ */
static bool python_script_exec(
bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump)
{
@@ -212,7 +220,6 @@ static bool python_script_exec(
/** \name Run Text / Filename / String
* \{ */
-/* Can run a file or text block */
bool BPY_run_filepath(bContext *C, const char *filepath, struct ReportList *reports)
{
return python_script_exec(C, filepath, NULL, reports, false);
@@ -271,17 +278,11 @@ static bool bpy_run_string_impl(bContext *C,
return ok;
}
-/**
- * Run an expression, matches: `exec(compile(..., "eval"))`
- */
bool BPY_run_string_eval(bContext *C, const char *imports[], const char *expr)
{
return bpy_run_string_impl(C, imports, expr, Py_eval_input);
}
-/**
- * Run an entire script, matches: `exec(compile(..., "exec"))`
- */
bool BPY_run_string_exec(bContext *C, const char *imports[], const char *expr)
{
return bpy_run_string_impl(C, imports, expr, Py_file_input);
@@ -330,9 +331,6 @@ static void run_string_handle_error(struct BPy_RunErrInfo *err_info)
Py_XDECREF(py_err_str);
}
-/**
- * \return success
- */
bool BPY_run_string_as_number(bContext *C,
const char *imports[],
const char *expr,
@@ -342,10 +340,6 @@ bool BPY_run_string_as_number(bContext *C,
PyGILState_STATE gilstate;
bool ok = true;
- if (!r_value || !expr) {
- return -1;
- }
-
if (expr[0] == '\0') {
*r_value = 0.0;
return ok;
@@ -364,9 +358,6 @@ bool BPY_run_string_as_number(bContext *C,
return ok;
}
-/**
- * \return success
- */
bool BPY_run_string_as_string_and_size(bContext *C,
const char *imports[],
const char *expr,
@@ -374,7 +365,6 @@ bool BPY_run_string_as_string_and_size(bContext *C,
char **r_value,
size_t *r_value_size)
{
- BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
bool ok = true;
@@ -406,18 +396,12 @@ bool BPY_run_string_as_string(bContext *C,
return BPY_run_string_as_string_and_size(C, imports, expr, err_info, r_value, &value_dummy_size);
}
-/**
- * Support both int and pointers.
- *
- * \return success
- */
bool BPY_run_string_as_intptr(bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
intptr_t *r_value)
{
- BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
bool ok = true;
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 059d692a9ba..fe279c0b940 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -34,6 +34,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -346,11 +347,63 @@ static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
PyErr_Restore(exc, val, tb);
}
+struct LibExitLappContextItemsIterData {
+ short idcode;
+ BPy_Library *py_library;
+ PyObject *py_list;
+ Py_ssize_t py_list_size;
+};
+
+static bool bpy_lib_exit_lapp_context_items_cb(BlendfileLinkAppendContext *lapp_context,
+ BlendfileLinkAppendContextItem *item,
+ void *userdata)
+{
+ struct LibExitLappContextItemsIterData *data = userdata;
+
+ /* Since `bpy_lib_exit` loops over all ID types, all items in `lapp_context` end up being looped
+ * over for each ID type, so when it does not match the item can simply be skipped: it either has
+ * already been processed, or will be processed in a later loop. */
+ if (BKE_blendfile_link_append_context_item_idcode_get(lapp_context, item) != data->idcode) {
+ return true;
+ }
+
+ const int py_list_index = POINTER_AS_INT(
+ BKE_blendfile_link_append_context_item_userdata_get(lapp_context, item));
+ ID *new_id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);
+
+ BLI_assert(py_list_index < data->py_list_size);
+
+ /* Fully invalid items (which got set to `Py_None` already in first loop of `bpy_lib_exit`)
+ * should never be accessed here, since their index should never be set to any item in
+ * `lapp_context`. */
+ PyObject *item_src = PyList_GET_ITEM(data->py_list, py_list_index);
+ BLI_assert(item_src != Py_None);
+
+ PyObject *py_item;
+ if (new_id != NULL) {
+ PointerRNA newid_ptr;
+ RNA_id_pointer_create(new_id, &newid_ptr);
+ py_item = pyrna_struct_CreatePyObject(&newid_ptr);
+ }
+ else {
+ const char *item_idname = PyUnicode_AsUTF8(item_src);
+ const char *idcode_name_plural = BKE_idtype_idcode_to_name_plural(data->idcode);
+
+ bpy_lib_exit_warn_idname(data->py_library, idcode_name_plural, item_idname);
+
+ py_item = Py_INCREF_RET(Py_None);
+ }
+
+ PyList_SET_ITEM(data->py_list, py_list_index, py_item);
+
+ Py_DECREF(item_src);
+
+ return true;
+}
+
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
Main *bmain = self->bmain;
- Main *mainl = NULL;
- const int err = 0;
const bool do_append = ((self->flag & FILE_LINK) == 0);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
@@ -360,134 +413,100 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra);
- mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params);
-
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
- if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
- const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- // printf("lib: %s\n", name_plural);
- if (ls && PyList_Check(ls)) {
- /* loop */
- const Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
-
- for (i = 0; i < size; i++) {
- PyObject *item_src = PyList_GET_ITEM(ls, i);
- PyObject *item_dst; /* must be set below */
- const char *item_idname = PyUnicode_AsUTF8(item_src);
-
- // printf(" %s\n", item_idname);
-
- if (item_idname) {
- ID *id = BLO_library_link_named_part(
- mainl, &(self->blo_handle), idcode, item_idname, &liblink_params);
- if (id) {
-
- if (self->bmain_is_temp) {
- /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */
- BLI_assert(id->tag & LIB_TAG_TEMP_MAIN);
- }
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, self->abspath, self->blo_handle);
-#ifdef USE_RNA_DATABLOCKS
- /* swap name for pointer to the id */
- item_dst = PyCapsule_New((void *)id, NULL, NULL);
-#else
- /* leave as is */
- continue;
-#endif
- }
- else {
- bpy_lib_exit_warn_idname(self, name_plural, item_idname);
- /* just warn for now */
- /* err = -1; */
- item_dst = Py_INCREF_RET(Py_None);
- }
-
- /* ID or None */
- }
- else {
- /* XXX, could complain about this */
- bpy_lib_exit_warn_type(self, item_src);
- PyErr_Clear();
- item_dst = Py_INCREF_RET(Py_None);
- }
-
- /* item_dst must be new or already incref'd */
- Py_DECREF(item_src);
- PyList_SET_ITEM(ls, i, item_dst);
- }
- }
- }
+ int idcode_step = 0;
+ short idcode;
+ while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) {
+ continue;
}
- }
- if (err == -1) {
- /* exception raised above, XXX, this leaks some memory */
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- return NULL;
- }
+ const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls == NULL || !PyList_Check(ls)) {
+ continue;
+ }
- Library *lib = mainl->curlib; /* newly added lib, assign before append end */
- BLO_library_link_end(mainl, &(self->blo_handle), &liblink_params);
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
+ const Py_ssize_t size = PyList_GET_SIZE(ls);
+ if (size == 0) {
+ continue;
+ }
- GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__);
+ /* loop */
+ for (Py_ssize_t i = 0; i < size; i++) {
+ PyObject *item_src = PyList_GET_ITEM(ls, i);
+ const char *item_idname = PyUnicode_AsUTF8(item_src);
- /* copied from wm_operator.c */
- {
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
+ // printf(" %s\n", item_idname);
- /* append, rather than linking */
- if (do_append) {
- BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
+ /* NOTE: index of item in py list is stored in userdata pointer, so that it can be found
+ * later on to replace the ID name by the actual ID pointer. */
+ if (item_idname != NULL) {
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, item_idname, idcode, POINTER_FROM_INT(i));
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
+ }
+ else {
+ /* XXX, could complain about this */
+ bpy_lib_exit_warn_type(self, item_src);
+ PyErr_Clear();
+
+#ifdef USE_RNA_DATABLOCKS
+ /* We can replace the item immediately with `None`. */
+ PyObject *py_item = Py_INCREF_RET(Py_None);
+ PyList_SET_ITEM(ls, i, py_item);
+ Py_DECREF(item_src);
+#endif
+ }
}
}
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+ BKE_blendfile_link(lapp_context, NULL);
+ if (do_append) {
+ BKE_blendfile_append(lapp_context, NULL);
+ }
- /* finally swap the capsules for real bpy objects
- * important since BLO_library_append_end initializes NodeTree types used by srna->refine */
+ /* If enabled, replace named items in given lists by the final matching new ID pointer. */
#ifdef USE_RNA_DATABLOCKS
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
- if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
- const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- if (ls && PyList_Check(ls)) {
- const Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
- PyObject *item;
-
- for (i = 0; i < size; i++) {
- item = PyList_GET_ITEM(ls, i);
- if (PyCapsule_CheckExact(item)) {
- PointerRNA id_ptr;
- ID *id;
-
- id = PyCapsule_GetPointer(item, NULL);
- id = BLI_ghash_lookup_default(old_to_new_ids, id, id);
- Py_DECREF(item);
-
- RNA_id_pointer_create(id, &id_ptr);
- item = pyrna_struct_CreatePyObject(&id_ptr);
- PyList_SET_ITEM(ls, i, item);
- }
- }
- }
- }
+ idcode_step = 0;
+ while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) {
+ continue;
+ }
+ const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls == NULL || !PyList_Check(ls)) {
+ continue;
}
+
+ const Py_ssize_t size = PyList_GET_SIZE(ls);
+ if (size == 0) {
+ continue;
+ }
+
+ /* Loop over linked items in `lapp_context` to find matching python one in the list, and
+ * replace them with proper ID pointer. */
+ struct LibExitLappContextItemsIterData iter_data = {
+ .idcode = idcode, .py_library = self, .py_list = ls, .py_list_size = size};
+ BKE_blendfile_link_append_context_item_foreach(
+ lapp_context,
+ bpy_lib_exit_lapp_context_items_cb,
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT,
+ &iter_data);
}
-#endif /* USE_RNA_DATABLOCKS */
+#endif // USE_RNA_DATABLOCKS
+
+ BLO_blendhandle_close(self->blo_handle);
+ self->blo_handle = NULL;
+
+ BKE_blendfile_link_append_context_free(lapp_context);
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- BLI_ghash_free(old_to_new_ids, NULL, NULL);
Py_RETURN_NONE;
}
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index c2d7257e458..bee64f5de2c 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -115,10 +115,6 @@ static void operator_properties_init(wmOperatorType *ot)
/* end 'ot->prop' assignment */
}
-/**
- * Generic function used by all Python defined operators
- * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
- */
void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
{
/* take care not to overwrite anything set in
@@ -135,10 +131,6 @@ void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
operator_properties_init(ot);
}
-/**
- * Generic function used by all Python defined macro-operators
- * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
- */
void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata)
{
wmOperatorType *data = (wmOperatorType *)userdata;
diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h
index 9e496cd8d26..41deb06814b 100644
--- a/source/blender/python/intern/bpy_operator_wrap.h
+++ b/source/blender/python/intern/bpy_operator_wrap.h
@@ -30,7 +30,15 @@ extern "C" {
PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args);
/* exposed to rna/wm api */
+/**
+ * Generic function used by all Python defined operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata);
+/**
+ * Generic function used by all Python defined macro-operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata);
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 13c7d2947cf..ed9547ee13f 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -434,6 +434,10 @@ static PyObject *bpy_prop_deferred_data_CreatePyObject(PyObject *fn, PyObject *k
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Shared Property Utilities
+ * \{ */
+
/* PyObject's */
static PyObject *pymeth_BoolProperty = NULL;
static PyObject *pymeth_BoolVectorProperty = NULL;
@@ -2630,10 +2634,14 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" This function must take 2 values (self, value) and return None.\n" \
" :type set: function\n"
-#define BPY_PROPDEF_TYPE_DOC \
+#define BPY_PROPDEF_POINTER_TYPE_DOC \
" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n"
+#define BPY_PROPDEF_COLLECTION_TYPE_DOC \
+ " :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \
+ " :type type: class\n"
+
#define BPY_PROPDEF_TAGS_DOC \
" :arg tags: Enumerator of tags that are defined by parent class.\n" \
" :type tags: set\n"
@@ -3981,7 +3989,7 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
"update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
- "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ "\n" BPY_PROPDEF_POINTER_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
BPY_PROPDEF_POLL_DOC BPY_PROPDEF_UPDATE_DOC);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -4104,7 +4112,7 @@ PyDoc_STRVAR(BPy_CollectionProperty_doc,
"tags=set())\n"
"\n"
" Returns a new collection property definition.\n"
- "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ "\n" BPY_PROPDEF_COLLECTION_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC
BPY_PROPDEF_TAGS_DOC);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -4392,10 +4400,6 @@ PyObject *BPY_rna_props(void)
return submodule;
}
-/**
- * Run this on exit, clearing all Python callback users and disable the RNA callback,
- * as it would be called after Python has already finished.
- */
void BPY_rna_props_clear_all(void)
{
/* Remove all user counts, so this isn't considered a leak from Python's perspective. */
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index e6bbd6f708d..9d739540919 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -25,6 +25,10 @@ extern "C" {
#endif
PyObject *BPY_rna_props(void);
+/**
+ * Run this on exit, clearing all Python callback users and disable the RNA callback,
+ * as it would be called after Python has already finished.
+ */
void BPY_rna_props_clear_all(void);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 707de1c2581..a79a0ed32bf 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1462,10 +1462,6 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
return ret;
}
-/**
- * This function is used by operators and converting dicts into collections.
- * It takes keyword args and fills them with property values.
- */
int pyrna_pydict_to_props(PointerRNA *ptr,
PyObject *kw,
const bool all_args,
@@ -7545,7 +7541,6 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop)
return (PyObject *)pyrna;
}
-/* Utility func to be used by external modules, sneaky! */
PyObject *pyrna_id_CreatePyObject(ID *id)
{
if (id) {
@@ -7777,9 +7772,6 @@ static struct PyModuleDef bpy_types_module_def = {
NULL, /* m_free */
};
-/**
- * Accessed from Python as 'bpy.types'
- */
PyObject *BPY_rna_types(void)
{
PyObject *submodule = PyModule_Create(&bpy_types_module_def);
@@ -7864,11 +7856,6 @@ StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *e
}
/* Orphan functions, not sure where they should go. */
-/**
- * Get the SRNA for methods attached to types.
- *
- * Caller needs to raise error.
- */
StructRNA *srna_from_self(PyObject *self, const char *error_prefix)
{
@@ -9094,9 +9081,6 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
Py_RETURN_NONE;
}
-/**
- * Extend RNA types with C/API methods, properties.
- */
void pyrna_struct_type_extend_capi(struct StructRNA *srna,
struct PyMethodDef *method,
struct PyGetSetDef *getset)
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 2096734ef96..9a6339c0a89 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -401,6 +401,10 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
return NULL;
}
+ if (result) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+
return PyBool_FromLong(result);
}
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index fcc796d4545..270c9ad431c 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -990,9 +990,10 @@ PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
return pyrna_prop_CreatePyObject(ptr, prop);
}
-/* TODO: multi-dimensional arrays. */
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
{
+ /* TODO: multi-dimensional arrays. */
+
const int len = RNA_property_array_length(ptr, prop);
int type;
int i;
diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c
index 639999b69d4..c781fe4a4e7 100644
--- a/source/blender/python/intern/bpy_rna_data.c
+++ b/source/blender/python/intern/bpy_rna_data.c
@@ -177,7 +177,7 @@ static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args,
ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type);
- STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name);
+ STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->filepath);
return (PyObject *)ret;
}
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index 3bddd0ad8c0..0bb8b1ba3e1 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -34,9 +34,6 @@
#include "bpy_rna_driver.h" /* own include */
-/**
- * A version of #driver_get_variable_value which returns a PyObject.
- */
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar)
{
PyObject *driver_arg = NULL;
diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h
index cc2c4550870..e34c7e4597c 100644
--- a/source/blender/python/intern/bpy_rna_driver.h
+++ b/source/blender/python/intern/bpy_rna_driver.h
@@ -28,6 +28,9 @@ struct PathResolvedRNA;
extern "C" {
#endif
+/**
+ * A version of #driver_get_variable_value which returns a #PyObject.
+ */
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna);