Files
test/source/blender/python/intern/bpy_library_write.cc
Brecht Van Lommel 920e709069 Refactor: Make header files more clangd and clang-tidy friendly
When using clangd or running clang-tidy on headers there are
currently many errors. These are noisy in IDEs, make auto fixes
impossible, and break features like code completion, refactoring
and navigation.

This makes source/blender headers work by themselves, which is
generally the goal anyway. But #includes and forward declarations
were often incomplete.

* Add #includes and forward declarations
* Add IWYU pragma: export in a few places
* Remove some unused #includes (but there are many more)
* Tweak ShaderCreateInfo macros to work better with clangd

Some types of headers still have errors, these could be fixed or
worked around with more investigation. Mostly preprocessor
template headers like NOD_static_types.h.

Note that that disabling WITH_UNITY_BUILD is required for clangd to
work properly, otherwise compile_commands.json does not contain
the information for the relevant source files.

For more details see the developer docs:
https://developer.blender.org/docs/handbook/tooling/clangd/

Pull Request: https://projects.blender.org/blender/blender/pulls/132608
2025-01-07 12:39:13 +01:00

198 lines
5.9 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup pythonintern
*
* Python API for writing a set of data-blocks into a file.
* Useful for writing out asset-libraries, defines: `bpy.data.libraries.write(...)`.
*/
#include <Python.h>
#include <cstddef>
#include "BLI_path_utils.hh"
#include "BLI_string.h"
#include "BKE_blendfile.hh"
#include "BKE_global.hh"
#include "BKE_lib_id.hh"
#include "BKE_main.hh"
#include "BKE_report.hh"
#include "BLO_writefile.hh"
#include "RNA_types.hh"
#include "bpy_capi_utils.hh"
#include "bpy_library.hh" /* Declaration for #BPY_library_load_method_def */
#include "bpy_rna.hh"
#include "../generic/py_capi_utils.hh"
#include "../generic/python_compat.hh"
using namespace blender::bke::blendfile;
PyDoc_STRVAR(
/* Wrap. */
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");
static PyObject *bpy_lib_write(BPy_PropertyRNA *self, PyObject *args, PyObject *kw)
{
/* args */
PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr};
char filepath_abs[FILE_MAX];
PyObject *datablocks = nullptr;
const PyC_StringEnumItems path_remap_items[] = {
{BLO_WRITE_PATH_REMAP_NONE, "NONE"},
{BLO_WRITE_PATH_REMAP_RELATIVE, "RELATIVE"},
{BLO_WRITE_PATH_REMAP_RELATIVE_ALL, "RELATIVE_ALL"},
{BLO_WRITE_PATH_REMAP_ABSOLUTE, "ABSOLUTE"},
{0, nullptr},
};
PyC_StringEnum path_remap = {path_remap_items, BLO_WRITE_PATH_REMAP_NONE};
bool use_fake_user = false, use_compress = false;
static const char *_keywords[] = {
"filepath",
"datablocks",
"path_remap",
"fake_user",
"compress",
nullptr,
};
static _PyArg_Parser _parser = {
PY_ARG_PARSER_HEAD_COMPAT()
"O&" /* `filepath` */
"O!" /* `datablocks` */
"|$" /* Optional keyword only arguments. */
"O&" /* `path_remap` */
"O&" /* `fake_user` */
"O&" /* `compress` */
":write",
_keywords,
nullptr,
};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
PyC_ParseUnicodeAsBytesAndSize,
&filepath_data,
&PySet_Type,
&datablocks,
PyC_ParseStringEnum,
&path_remap,
PyC_ParseBool,
&use_fake_user,
PyC_ParseBool,
&use_compress))
{
return nullptr;
}
Main *bmain_src = static_cast<Main *>(self->ptr->data); /* Typically #G_MAIN */
int write_flags = 0;
if (use_compress) {
write_flags |= G_FILE_COMPRESS;
}
STRNCPY(filepath_abs, filepath_data.value);
Py_XDECREF(filepath_data.value_coerce);
BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global());
PartialWriteContext partial_write_ctx{bmain_src->filepath};
const PartialWriteContext::IDAddOptions add_options{
(PartialWriteContext::IDAddOperations::ADD_DEPENDENCIES |
PartialWriteContext::IDAddOperations(
use_fake_user ? PartialWriteContext::IDAddOperations::SET_FAKE_USER : 0))};
if (PySet_GET_SIZE(datablocks) > 0) {
PyObject *it = PyObject_GetIter(datablocks);
PyObject *key;
while ((key = PyIter_Next(it))) {
/* Borrow from the set. */
Py_DECREF(key);
ID *id;
if (!pyrna_id_FromPyObject(key, &id)) {
PyErr_Format(PyExc_TypeError, "Expected an ID type, not %.200s", Py_TYPE(key)->tp_name);
break;
}
partial_write_ctx.id_add(id, add_options, nullptr);
}
Py_DECREF(it);
if (key) {
return nullptr;
}
}
BLI_assert(partial_write_ctx.is_valid());
/* write blend */
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);
bool success = partial_write_ctx.write(
filepath_abs, write_flags, path_remap.value_found, reports);
PyObject *py_return_value;
if (success) {
BKE_reports_print(&reports, RPT_ERROR_ALL);
py_return_value = Py_None;
Py_INCREF(py_return_value);
}
else {
if (BPy_reports_to_error(&reports, PyExc_IOError, false) == 0) {
PyErr_SetString(PyExc_IOError, "Unknown error writing library data");
}
py_return_value = nullptr;
}
BKE_reports_free(&reports);
return py_return_value;
}
#if (defined(__GNUC__) && !defined(__clang__))
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
PyMethodDef BPY_library_write_method_def = {
"write",
(PyCFunction)bpy_lib_write,
METH_VARARGS | METH_KEYWORDS,
bpy_lib_write_doc,
};
#if (defined(__GNUC__) && !defined(__clang__))
# pragma GCC diagnostic pop
#endif