py api additions needed for fixing [#34864].
authorCampbell Barton <ideasman42@gmail.com>
Fri, 5 Apr 2013 00:30:32 +0000 (00:30 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 5 Apr 2013 00:30:32 +0000 (00:30 +0000)
- add rna property 'as_bytes' method so you can get a string property as python bytes (bypass encoding).
- make bpy.path.abspath/relpath compatible with bytes.
- add 'relpath' option to bpy_extras.image_utils.load_image(), so you can load an image relative to a path.

release/scripts/modules/bpy/path.py
release/scripts/modules/bpy_extras/image_utils.py
source/blender/python/intern/bpy_rna.c

index 6c91568cbc17ef95aafceda0b38b8708aeac3d92..cfc0f4742157e00915bdbad4d3e52017bfa7d47b 100644 (file)
@@ -48,6 +48,10 @@ from _bpy_path import (extensions_audio,
                        )
 
 
+def _getattr_bytes(var, attr):
+    return var.path_resolve(attr, False).as_bytes()
+
+
 def abspath(path, start=None, library=None):
     """
     Returns the absolute path relative to the current blend file
@@ -60,13 +64,22 @@ def abspath(path, start=None, library=None):
        convenience, when the library is not None its path replaces *start*.
     :type library: :class:`bpy.types.Library`
     """
-    if path.startswith("//"):
-        if library:
-            start = _os.path.dirname(abspath(library.filepath))
-        return _os.path.join(_os.path.dirname(_bpy.data.filepath)
-                             if start is None else start,
-                             path[2:],
-                             )
+    if isinstance(path, bytes):
+        if path.startswith(b"//"):
+            if library:
+                start = _os.path.dirname(abspath(_getattr_bytes(library, "filepath")))
+            return _os.path.join(_os.path.dirname(_getattr_bytes(_bpy.data, "filepath"))
+                                 if start is None else start,
+                                 path[2:],
+                                 )
+    else:
+        if path.startswith("//"):
+            if library:
+                start = _os.path.dirname(abspath(library.filepath))
+            return _os.path.join(_os.path.dirname(_bpy.data.filepath)
+                                 if start is None else start,
+                                 path[2:],
+                                 )
 
     return path
 
@@ -79,10 +92,16 @@ def relpath(path, start=None):
        when not set the current filename is used.
     :type start: string
     """
-    if not path.startswith("//"):
-        if start is None:
-            start = _os.path.dirname(_bpy.data.filepath)
-        return "//" + _os.path.relpath(path, start)
+    if isinstance(path, bytes):
+        if not path.startswith(b"//"):
+            if start is None:
+                start = _os.path.dirname(_getattr_bytes(_bpy.data, "filepath"))
+            return b"//" + _os.path.relpath(path, start)
+    else:
+        if not path.startswith("//"):
+            if start is None:
+                start = _os.path.dirname(_bpy.data.filepath)
+            return "//" + _os.path.relpath(path, start)
 
     return path
 
index 36994d3fddd6c249011cb40f0ed553bd559b677f..5c63ce1218e2d8947b3fa8b59096ce98af2aff1b 100644 (file)
@@ -31,6 +31,7 @@ def load_image(imagepath,
                ncase_cmp=True,
                convert_callback=None,
                verbose=False,
+               relpath=None,
                ):
     """
     Return an image from the file path with options to search multiple paths
@@ -57,6 +58,8 @@ def load_image(imagepath,
        convert it to a PNG and return the PNG's path.
        For formats blender can read, simply return the path that is given.
     :type convert_callback: function
+    :arg relpath: If not None, make the file relative to this path.
+    :type relpath: None or string
     :return: an image or None
     :rtype: :class:`bpy.types.Image`
     """
@@ -100,6 +103,12 @@ def load_image(imagepath,
         if place_holder and image is None:
             image = _image_load_placeholder(path)
 
+        if image:
+            if relpath is not None:
+                # make relative
+                from bpy.path import relpath as relpath_fn
+                image.filepath_raw = relpath_fn(path, start=relpath)
+
         return image
 
     # -------------------------------------------------------------------------
index d6a82ce43eae1334b482c80d9e35a4be86739b56..df66ef923161f9052f952c9af5ee69156ab376d5 100644 (file)
@@ -3324,6 +3324,40 @@ static PyObject *pyrna_prop_path_from_id(BPy_PropertyRNA *self)
        return ret;
 }
 
+PyDoc_STRVAR(pyrna_prop_as_bytes_doc,
+".. method:: as_bytes()\n"
+"\n"
+"   Returns this string property as a byte rather then a python string.\n"
+"\n"
+"   :return: The string as bytes.\n"
+"   :rtype: bytes\n"
+);
+static PyObject *pyrna_prop_as_bytes(BPy_PropertyRNA *self)
+{
+
+       if (RNA_property_type(self->prop) != PROP_STRING) {
+               PyErr_Format(PyExc_TypeError,
+                            "%.200s.%.200s.as_bytes() must be a string",
+                            RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop));
+               return NULL;
+       }
+       else {
+               PyObject *ret;
+               char buf_fixed[256], *buf;
+               int buf_len;
+
+               buf = RNA_property_string_get_alloc(&self->ptr, self->prop, buf_fixed, sizeof(buf_fixed), &buf_len);
+
+               ret = PyBytes_FromStringAndSize(buf, buf_len);
+
+               if (buf_fixed != buf) {
+                       MEM_freeN(buf);
+               }
+
+               return ret;
+       }
+}
+
 PyDoc_STRVAR(pyrna_struct_type_recast_doc,
 ".. method:: type_recast()\n"
 "\n"
@@ -4685,6 +4719,7 @@ static struct PyMethodDef pyrna_struct_methods[] = {
 
 static struct PyMethodDef pyrna_prop_methods[] = {
        {"path_from_id", (PyCFunction)pyrna_prop_path_from_id, METH_NOARGS, pyrna_prop_path_from_id_doc},
+       {"as_bytes", (PyCFunction)pyrna_prop_as_bytes, METH_NOARGS, pyrna_prop_as_bytes_doc},
        {"__dir__", (PyCFunction)pyrna_prop_dir, METH_NOARGS, NULL},
        {NULL, NULL, 0, NULL}
 };