Script to test import operators, so a single command can execute an operator on all...
authorCampbell Barton <ideasman42@gmail.com>
Tue, 1 Feb 2011 12:47:50 +0000 (12:47 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 1 Feb 2011 12:47:50 +0000 (12:47 +0000)
This comes in handy for testing importers against 100's of files, quickly showing breakages and easier to setup then unit tests.

Example usage:

  blender.bin --background --python source/tests/batch_import.py -- \
              --operator="bpy.ops.import_scene.obj" \
              --path="/data/testfiles/obj" \
              --match="*.obj" \
              --start=0 --end=50 \
              --save_path="/tmp/test"

Also found my name was spelt wrong in some places :)

release/scripts/templates/background_job.py
source/blender/editors/mesh/editmesh_tools.c
source/blender/makesdna/intern/dna_genfile.c
source/blender/windowmanager/intern/wm_operators.c
source/tests/batch_import.py [new file with mode: 0644]

index f199ee5ad50000d1866b8604004f1dbd9b9e3375..0337f8f492283d965415f7d2c5ebc3c951b82f28 100644 (file)
@@ -82,7 +82,7 @@ def main():
 
     # When --help or no args are given, print this help
     usage_text = "Run blender in background mode with this script:"
-    usage_text += "  blender -b -P " + __file__ + " -- [options]"
+    usage_text += "  blender --background --python " + __file__ + " -- [options]"
 
     parser = optparse.OptionParser(usage=usage_text)
 
index 3e359101f3a5f3a6f948728869432a1984f7978a..9e6f8f7f078e940e6f8ae930747f60c1175cd808 100644 (file)
@@ -7150,7 +7150,7 @@ static int sort_faces_exec(bContext *C, wmOperator *op)
        if (!v3d) return OPERATOR_CANCELLED;
 
        /* This operator work in Object Mode, not in edit mode.
-        * After talk with Cambell we agree that there is no point to port this to EditMesh right now.
+        * After talk with Campbell we agree that there is no point to port this to EditMesh right now.
         * so for now, we just exit_editmode and enter_editmode at the end of this function.
         */
        ED_object_exit_editmode(C, EM_FREEDATA);
index cd14acd520c9303efc1ec1ade9e9e30ff4b7be7c..c103e74ca34a9da85596ee8805a00660814def40 100644 (file)
@@ -43,7 +43,7 @@
 
 /* gcc 4.1 on mingw was complaining that __int64 was already defined
 actually is saw the line below as typedef long long long long... 
-Anyhow, since its already defined, its safe to do an ifndef here- Cambpell*/
+Anyhow, since its already defined, its safe to do an ifndef here- Campbell */
 #ifdef FREE_WINDOWS
 #ifndef __int64
 typedef long long __int64;
index 1b602b167c72b6d1d78fe2d5f77cc15d7a1669a9..43c4551d0dcbdbcbf7691c9242da5309924cf8aa 100644 (file)
@@ -1786,8 +1786,8 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot)
        ot->invoke= wm_save_as_mainfile_invoke;
        ot->exec= wm_save_as_mainfile_exec;
        ot->check= blend_save_check;
-       ot->poll= WM_operator_winactive;
-       
+       /* ommit window poll so this can work in background mode */
+
        WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH);
        RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file");
        RNA_def_boolean(ot->srna, "relative_remap", 1, "Remap Relative", "Remap relative paths when saving in a different directory");
diff --git a/source/tests/batch_import.py b/source/tests/batch_import.py
new file mode 100644 (file)
index 0000000..6a941f3
--- /dev/null
@@ -0,0 +1,150 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""
+Example Usage:
+  blender --background --python source/tests/batch_import.py --  --operator="bpy.ops.import_scene.obj" --path="/fe/obj" --match="*.obj" --start=0 --end=10 --save_path=/tmp/test
+"""
+
+import os
+import sys
+
+
+def batch_import(operator="",
+                   path="",
+                   save_path="",
+                   match="",
+                   start=0,
+                   end=sys.maxsize,
+                   ):
+
+    print(list(globals().keys()))
+    import fnmatch
+
+    path = os.path.normpath(path)
+    path = os.path.abspath(path)
+
+    match_upper = match.upper()
+    pattern_match = lambda a: fnmatch.fnmatchcase(a.upper(), match_upper)
+
+    def file_generator(path):
+        for dirpath, dirnames, filenames in os.walk(path):
+
+            # skip '.svn'
+            if dirpath.startswith("."):
+                continue
+
+            for filename in filenames:
+                if pattern_match(filename):
+                    yield os.path.join(dirpath, filename)
+
+    print("Collecting %r files in %s" % (match, path), end="")
+
+    files = list(file_generator(path))
+    files_len = len(files)
+    end = min(end, len(files))
+    print(" found %d" % files_len, end="")
+
+    files.sort()
+    files = files[start:end]
+    if len(files) != files_len:
+        print(" using a subset in (%d, %d), total %d" % (start, end, len(files)), end="")
+
+    print("")
+
+    import bpy
+    op = eval(operator)
+    for i, f in enumerate(files):
+        print("    %s(filepath=%r) # %d of %d" % (operator, f, i + start, len(files)))
+        bpy.ops.wm.read_factory_settings()
+
+        op(filepath=f)
+
+        if save_path:
+            fout = os.path.join(save_path, os.path.relpath(f, path))
+            fout_blend = os.path.splitext(fout)[0] + ".blend"
+
+            print("\tSaving: %r" % fout_blend)
+
+            fout_dir = os.path.dirname(fout_blend)
+            if not os.path.exists(fout_dir):
+                os.makedirs(fout_dir)
+
+            bpy.ops.wm.save_as_mainfile(filepath=fout_blend)
+
+
+def main():
+    import optparse
+
+    # get the args passed to blender after "--", all of which are ignored by blender specifically
+    # so python may receive its own arguments
+    argv = sys.argv
+
+    if "--" not in argv:
+        argv = []  # as if no args are passed
+    else:
+        argv = argv[argv.index("--") + 1:]  # get all args after "--"
+
+    # When --help or no args are given, print this help
+    usage_text = "Run blender in background mode with this script:"
+    usage_text += "  blender --background --python " + __file__ + " -- [options]"
+
+    parser = optparse.OptionParser(usage=usage_text)
+
+    # Example background utility, add some text and renders or saves it (with options)
+    # Possible types are: string, int, long, choice, float and complex.
+    parser.add_option("-o", "--operator", dest="operator", help="This text will be used to render an image", type="string")
+    parser.add_option("-p", "--path", dest="path", help="Path to use for searching for files", type='string')
+    parser.add_option("-m", "--match", dest="match", help="Wildcard to match filename", type="string")
+    parser.add_option("-s", "--save_path", dest="save_path", help="Save the input file to a blend file in a new location", metavar='string')
+    parser.add_option("-S", "--start", dest="start", help="From collected files, start with this index", metavar='int')
+    parser.add_option("-E", "--end", dest="end", help="From collected files, end with this index", metavar='int')
+
+    options, args = parser.parse_args(argv)  # In this example we wont use the args
+
+    if not argv:
+        parser.print_help()
+        return
+
+    if not options.operator:
+        print("Error: --operator=\"some string\" argument not given, aborting.")
+        parser.print_help()
+        return
+
+    if options.start is None:
+        options.start = 0
+
+    if options.end is None:
+        options.end = sys.maxsize
+
+    # Run the example function
+    batch_import(operator=options.operator,
+                 path=options.path,
+                 save_path=options.save_path,
+                 match=options.match,
+                 start=int(options.start),
+                 end=int(options.end),
+                 )
+
+    print("batch job finished, exiting")
+
+
+if __name__ == "__main__":
+    main()