Script to test import operators, so a single command can execute an operator on all files in a directory and optionally save out blend files for inspection.

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 :)
This commit is contained in:
Campbell Barton 2011-02-01 12:47:50 +00:00
parent ffe7bde02c
commit 0d3cf5c8a6
5 changed files with 155 additions and 5 deletions

View 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)

View 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);

View 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;

View 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");

View File

@ -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()