Blender V4.3
bpy_library_write.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12#include <Python.h>
13#include <cstddef>
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_path_utils.hh"
18#include "BLI_string.h"
19#include "BLI_utildefines.h"
20
21#include "BKE_blendfile.hh"
22#include "BKE_global.hh"
23#include "BKE_lib_id.hh"
24#include "BKE_main.hh"
25#include "BKE_report.hh"
26
27#include "BLO_writefile.hh"
28
29#include "RNA_types.hh"
30
31#include "bpy_capi_utils.hh"
32#include "bpy_library.hh" /* Declaration for #BPY_library_load_method_def */
33#include "bpy_rna.hh"
34
37
38using namespace blender::bke::blendfile;
39
41 /* Wrap. */
42 bpy_lib_write_doc,
43 ".. method:: write(filepath, datablocks, path_remap=False, fake_user=False, compress=False)\n"
44 "\n"
45 " Write data-blocks into a blend file.\n"
46 "\n"
47 " .. note::\n"
48 "\n"
49 " Indirectly referenced data-blocks will be expanded and written too.\n"
50 "\n"
51 " :arg filepath: The path to write the blend-file.\n"
52 " :type filepath: str | bytes\n"
53 " :arg datablocks: set of data-blocks.\n"
54 " :type datablocks: set[:class:`bpy.types.ID`]\n"
55 " :arg path_remap: Optionally remap paths when writing the file:\n"
56 "\n"
57 " - ``NONE`` No path manipulation (default).\n"
58 " - ``RELATIVE`` Remap paths that are already relative to the new location.\n"
59 " - ``RELATIVE_ALL`` Remap all paths to be relative to the new location.\n"
60 " - ``ABSOLUTE`` Make all paths absolute on writing.\n"
61 "\n"
62 " :type path_remap: str\n"
63 " :arg fake_user: When True, data-blocks will be written with fake-user flag enabled.\n"
64 " :type fake_user: bool\n"
65 " :arg compress: When True, write a compressed blend file.\n"
66 " :type compress: bool\n");
67static PyObject *bpy_lib_write(BPy_PropertyRNA *self, PyObject *args, PyObject *kw)
68{
69 /* args */
70 PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr};
71 char filepath_abs[FILE_MAX];
72 PyObject *datablocks = nullptr;
73
74 const PyC_StringEnumItems path_remap_items[] = {
77 {BLO_WRITE_PATH_REMAP_RELATIVE_ALL, "RELATIVE_ALL"},
79 {0, nullptr},
80 };
81 PyC_StringEnum path_remap = {path_remap_items, BLO_WRITE_PATH_REMAP_NONE};
82
83 bool use_fake_user = false, use_compress = false;
84
85 static const char *_keywords[] = {
86 "filepath",
87 "datablocks",
88 "path_remap",
89 "fake_user",
90 "compress",
91 nullptr,
92 };
93 static _PyArg_Parser _parser = {
95 "O&" /* `filepath` */
96 "O!" /* `datablocks` */
97 "|$" /* Optional keyword only arguments. */
98 "O&" /* `path_remap` */
99 "O&" /* `fake_user` */
100 "O&" /* `compress` */
101 ":write",
102 _keywords,
103 nullptr,
104 };
105 if (!_PyArg_ParseTupleAndKeywordsFast(args,
106 kw,
107 &_parser,
109 &filepath_data,
110 &PySet_Type,
111 &datablocks,
113 &path_remap,
115 &use_fake_user,
117 &use_compress))
118 {
119 return nullptr;
120 }
121
122 Main *bmain_src = static_cast<Main *>(self->ptr.data); /* Typically #G_MAIN */
123 int write_flags = 0;
124
125 if (use_compress) {
126 write_flags |= G_FILE_COMPRESS;
127 }
128
129 STRNCPY(filepath_abs, filepath_data.value);
130 Py_XDECREF(filepath_data.value_coerce);
131
133
134 PartialWriteContext partial_write_ctx{bmain_src->filepath};
136 PartialWriteContext::IDAddOperations::ADD_DEPENDENCIES |
137 (use_fake_user ? PartialWriteContext::IDAddOperations::SET_FAKE_USER : 0))};
138
139 Py_ssize_t pos, hash;
140 PyObject *key;
141 ID *id = nullptr;
142
143 pos = hash = 0;
144 while (_PySet_NextEntry(datablocks, &pos, &key, &hash)) {
145 if (!pyrna_id_FromPyObject(key, &id)) {
146 PyErr_Format(PyExc_TypeError, "Expected an ID type, not %.200s", Py_TYPE(key)->tp_name);
147 return nullptr;
148 }
149 else {
150 partial_write_ctx.id_add(id, add_options, nullptr);
151 }
152 }
153 BLI_assert(partial_write_ctx.is_valid());
154
155 /* write blend */
156 ReportList reports;
157
158 BKE_reports_init(&reports, RPT_STORE);
159 bool success = partial_write_ctx.write(
160 filepath_abs, write_flags, path_remap.value_found, reports);
161
162 PyObject *py_return_value;
163 if (success) {
165 py_return_value = Py_None;
166 Py_INCREF(py_return_value);
167 }
168 else {
169 if (BPy_reports_to_error(&reports, PyExc_IOError, false) == 0) {
170 PyErr_SetString(PyExc_IOError, "Unknown error writing library data");
171 }
172 py_return_value = nullptr;
173 }
174
175 BKE_reports_free(&reports);
176
177 return py_return_value;
178}
179
180#if (defined(__GNUC__) && !defined(__clang__))
181# pragma GCC diagnostic push
182# pragma GCC diagnostic ignored "-Wcast-function-type"
183#endif
184
186 "write",
187 (PyCFunction)bpy_lib_write,
188 METH_VARARGS | METH_KEYWORDS,
189 bpy_lib_write_doc,
190};
191
192#if (defined(__GNUC__) && !defined(__clang__))
193# pragma GCC diagnostic pop
194#endif
@ G_FILE_COMPRESS
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:837
void BKE_reports_free(ReportList *reports)
Definition report.cc:69
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:54
void BKE_reports_print(ReportList *reports, eReportType level)
Definition report.cc:315
#define BLI_assert(a)
Definition BLI_assert.h:50
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
#define STRNCPY(dst, src)
Definition BLI_string.h:593
external writefile.cc function prototypes.
@ BLO_WRITE_PATH_REMAP_NONE
@ BLO_WRITE_PATH_REMAP_RELATIVE_ALL
@ BLO_WRITE_PATH_REMAP_ABSOLUTE
@ BLO_WRITE_PATH_REMAP_RELATIVE
#define RPT_ERROR_ALL
Read Guarded memory(de)allocation.
short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool clear)
PyObject * self
PyDoc_STRVAR(bpy_lib_write_doc, ".. method:: write(filepath, datablocks, path_remap=False, fake_user=False, compress=False)\n" "\n" " Write data-blocks into a blend file.\n" "\n" " .. note::\n" "\n" " Indirectly referenced data-blocks will be expanded and written too.\n" "\n" " :arg filepath: The path to write the blend-file.\n" " :type filepath: str | bytes\n" " :arg datablocks: set of data-blocks.\n" " :type datablocks: set[:class:`bpy.types.ID`]\n" " :arg path_remap: Optionally remap paths when writing the file:\n" "\n" " - ``NONE`` No path manipulation (default).\n" " - ``RELATIVE`` Remap paths that are already relative to the new location.\n" " - ``RELATIVE_ALL`` Remap all paths to be relative to the new location.\n" " - ``ABSOLUTE`` Make all paths absolute on writing.\n" "\n" " :type path_remap: str\n" " :arg fake_user: When True, data-blocks will be written with fake-user flag enabled.\n" " :type fake_user: bool\n" " :arg compress: When True, write a compressed blend file.\n" " :type compress: bool\n")
PyMethodDef BPY_library_write_method_def
static PyObject * bpy_lib_write(BPy_PropertyRNA *self, PyObject *args, PyObject *kw)
bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
Definition bpy_rna.cc:7812
#define hash
Definition noise.c:154
int PyC_ParseUnicodeAsBytesAndSize(PyObject *o, void *p)
int PyC_ParseStringEnum(PyObject *o, void *p)
int PyC_ParseBool(PyObject *o, void *p)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
Definition DNA_ID.h:413
char filepath[1024]
Definition BKE_main.hh:136