[Bf-blender-cvs] [f94b87b] master: New python API for units handling.

Bastien Montagne noreply at git.blender.org
Tue Jun 17 16:08:44 CEST 2014


Commit: f94b87bbb89b2350be2f5b26c2afb2372fd9d99c
Author: Bastien Montagne
Date:   Tue Jun 17 16:03:40 2014 +0200
https://developer.blender.org/rBf94b87bbb89b2350be2f5b26c2afb2372fd9d99c

New python API for units handling.

Exposes all supported unit systems & types, and to_value()/to_string() functions.

Reviewed and enhanced by CampbellBarton, many thanks!

Differential Revision: https://developer.blender.org/D416

===================================================================

M	release/scripts/modules/bpy/utils.py
M	source/blender/python/generic/py_capi_utils.c
M	source/blender/python/generic/py_capi_utils.h
M	source/blender/python/intern/CMakeLists.txt
M	source/blender/python/intern/bpy.c
M	source/blender/python/intern/bpy_interface.c
A	source/blender/python/intern/bpy_utils_units.c
A	source/blender/python/intern/bpy_utils_units.h

===================================================================

diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py
index ce1efa4..5621af2 100644
--- a/release/scripts/modules/bpy/utils.py
+++ b/release/scripts/modules/bpy/utils.py
@@ -44,6 +44,7 @@ __all__ = (
     "script_paths",
     "smpte_from_frame",
     "smpte_from_seconds",
+    "units",
     "unregister_class",
     "unregister_module",
     "user_resource",
@@ -58,6 +59,7 @@ from _bpy import (
     )
 from _bpy import script_paths as _bpy_script_paths
 from _bpy import user_resource as _user_resource
+from _bpy import _utils_units as units
 
 import bpy as _bpy
 import os as _os
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 54e27a3..8454f5b 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -904,3 +904,73 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
 
 	return ret;
 }
+
+
+/**
+ * \return -1 on error, else 0
+ *
+ * \note it is caller's responsibility to acquire & release GIL!
+ */
+int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename)
+{
+	PyObject *py_dict, *mod, *retval;
+	int error_ret = 0;
+	PyObject *main_mod = NULL;
+
+	PyC_MainModule_Backup(&main_mod);
+
+	py_dict = PyC_DefaultNameSpace(filename);
+
+	mod = PyImport_ImportModule("math");
+	if (mod) {
+		PyDict_Merge(py_dict, PyModule_GetDict(mod), 0); /* 0 - don't overwrite existing values */
+		Py_DECREF(mod);
+	}
+	else { /* highly unlikely but possibly */
+		PyErr_Print();
+		PyErr_Clear();
+	}
+
+	retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
+
+	if (retval == NULL) {
+		error_ret = -1;
+	}
+	else {
+		double val;
+
+		if (PyTuple_Check(retval)) {
+			/* Users my have typed in 10km, 2m
+			 * add up all values */
+			int i;
+			val = 0.0;
+
+			for (i = 0; i < PyTuple_GET_SIZE(retval); i++) {
+				const double val_item = PyFloat_AsDouble(PyTuple_GET_ITEM(retval, i));
+				if (val_item == -1 && PyErr_Occurred()) {
+					val = -1;
+					break;
+				}
+				val += val_item;
+			}
+		}
+		else {
+			val = PyFloat_AsDouble(retval);
+		}
+		Py_DECREF(retval);
+
+		if (val == -1 && PyErr_Occurred()) {
+			error_ret = -1;
+		}
+		else if (!finite(val)) {
+			*value = 0.0;
+		}
+		else {
+			*value = val;
+		}
+	}
+
+	PyC_MainModule_Restore(main_mod);
+
+	return error_ret;
+}
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 0afc4dd..559a8e1 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -73,4 +73,6 @@ int       PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int
 int       PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix);
 PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);
 
+int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename);
+
 #endif  /* __PY_CAPI_UTILS_H__ */
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 0605f40..70b4df7 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRC
 	bpy_rna_callback.c
 	bpy_traceback.c
 	bpy_util.c
+	bpy_utils_units.c
 	stubs.c
 
 	gpu.h
@@ -91,6 +92,7 @@ set(SRC
 	bpy_rna_callback.h
 	bpy_traceback.h
 	bpy_util.h
+	bpy_utils_units.h
 	../BPY_extern.h
 )
 
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 8910482..5fd19d3 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -49,6 +49,7 @@
 #include "bpy_props.h"
 #include "bpy_library.h"
 #include "bpy_operator.h"
+#include "bpy_utils_units.h"
 
 #include "MEM_guardedalloc.h"
 
@@ -334,6 +335,7 @@ void BPy_init_modules(void)
 	/* ops is now a python module that does the conversion from SOME_OT_foo -> some.foo */
 	PyModule_AddObject(mod, "ops", BPY_operator_module());
 	PyModule_AddObject(mod, "app", BPY_app_struct());
+	PyModule_AddObject(mod, "_utils_units", BPY_utils_units());
 
 	/* bpy context */
 	RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr);
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index bf2de02..b7752b3 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -566,15 +566,12 @@ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
 	PyGILState_Release(gilstate);
 }
 
-
 /* return -1 on error, else 0 */
 int BPY_button_exec(bContext *C, const char *expr, double *value, const bool verbose)
 {
 	PyGILState_STATE gilstate;
-	PyObject *py_dict, *mod, *retval;
 	int error_ret = 0;
-	PyObject *main_mod = NULL;
-	
+
 	if (!value || !expr) return -1;
 
 	if (expr[0] == '\0') {
@@ -584,59 +581,8 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const bool ver
 
 	bpy_context_set(C, &gilstate);
 
-	PyC_MainModule_Backup(&main_mod);
-
-	py_dict = PyC_DefaultNameSpace("<blender button>");
-
-	mod = PyImport_ImportModule("math");
-	if (mod) {
-		PyDict_Merge(py_dict, PyModule_GetDict(mod), 0); /* 0 - don't overwrite existing values */
-		Py_DECREF(mod);
-	}
-	else { /* highly unlikely but possibly */
-		PyErr_Print();
-		PyErr_Clear();
-	}
-	
-	retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
-	
-	if (retval == NULL) {
-		error_ret = -1;
-	}
-	else {
-		double val;
-
-		if (PyTuple_Check(retval)) {
-			/* Users my have typed in 10km, 2m
-			 * add up all values */
-			int i;
-			val = 0.0;
+	error_ret = PyC_RunString_AsNumber(expr, value, "<blender button>");
 
-			for (i = 0; i < PyTuple_GET_SIZE(retval); i++) {
-				const double val_item = PyFloat_AsDouble(PyTuple_GET_ITEM(retval, i));
-				if (val_item == -1 && PyErr_Occurred()) {
-					val = -1;
-					break;
-				}
-				val += val_item;
-			}
-		}
-		else {
-			val = PyFloat_AsDouble(retval);
-		}
-		Py_DECREF(retval);
-		
-		if (val == -1 && PyErr_Occurred()) {
-			error_ret = -1;
-		}
-		else if (!finite(val)) {
-			*value = 0.0;
-		}
-		else {
-			*value = val;
-		}
-	}
-	
 	if (error_ret) {
 		if (verbose) {
 			BPy_errors_to_report(CTX_wm_reports(C));
@@ -646,10 +592,8 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const bool ver
 		}
 	}
 
-	PyC_MainModule_Restore(main_mod);
-	
 	bpy_context_clear(C, &gilstate);
-	
+
 	return error_ret;
 }
 
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
new file mode 100644
index 0000000..cdbd57b
--- /dev/null
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -0,0 +1,332 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_utils_units.c
+ *  \ingroup pythonintern
+ *
+ * This file defines a singleton py object accessed via 'bpy.utils.units',
+ * which exposes various data and functions useful in units handling.
+ */
+
+/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
+#define PY_SSIZE_T_CLEAN
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
+
+#include "BPY_extern.h"
+#include "bpy_utils_units.h"
+
+#include "../generic/py_capi_utils.h"
+
+#include "BKE_unit.h"
+
+/***** C-defined systems and types *****/
+
+static PyTypeObject BPyUnitsSystemsType;
+static PyTypeObject BPyUnitsCategoriesType;
+
+/* XXX Maybe better as externs of BKE_unit.h ? */
+static const char *bpyunits_usystem_items[] = {
+	"NONE",
+	"METRIC",
+	"IMPERIAL",
+	NULL,
+};
+
+static const char *bpyunits_ucategorie_items[] = {
+	"NONE",
+	"LENGTH",
+	"AREA",
+	"VOLUME",
+	"MASS",
+	"ROTATION",
+	"TIME",
+	"VELOCITY",
+	"ACCELERATION",
+	"CAMERA",
+	NULL,
+};
+
+/**
+ * These fields are just empty placeholders, actual values get set in initializations functions.
+ * This allows us to avoid many handwriting, and above all, to keep all systems/categories definition stuff in
+ * ``BKE_unit.h``.
+ */
+static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usystem_items)];
+static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)];
+
+static PyStructSequence_Desc bpyunits_systems_desc = {
+	(char *)"bpy.utils.units.systems",     /* name */
+	(char *)"This named tuple contains all pre-defined unit systems",    /* doc */
+	bpyunits_systems_fields,    /* fields */
+	ARRAY_SIZE(bpyunits_systems_fields) - 1
+};
+static PyStructSequence_Desc bpyunits_categories_desc = {
+	(char *)"bpy.utils.units.categories",     /* name */
+	(char *)"This named tuple contains all pre-defined unit names",    /* doc */
+	bpyunits_categories_fields,    /* fields */
+	ARRAY_SIZE(bpyunits_categories_fields) - 1
+};
+
+/**
+ * Simple utility function to initialize #PyStructSequence_Desc
+ */
+static PyObject *py_structseq_from_strings(
+        PyTypeObject *py_type,
+        PyStructSequence_Desc *py_sseq_desc,
+        const char **str_items)
+{
+	PyObject *py_struct_seq;
+	int pos = 0;
+
+	const char **str_iter;
+	PyStructSequence_Field *desc;
+
+	/* initialize array */
+	/* We really populate the contexts' fields here! */
+	for (str_iter = str_items, desc = py_sseq_desc->fields; *str_iter; str_iter++, desc++) {
+		desc->name = (ch

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list