1 # SPDX-FileCopyrightText: 2011-2023 Blender Authors
3 # SPDX-License-Identifier: GPL-2.0-or-later
12 blender --factory-startup --python ./tests/utils/batch_load_blendfiles.py
14 Arguments may be passed in:
16 blender --factory-startup --python ./tests/utils/batch_load_blendfiles.py -- --sort-by=SIZE --range=0:10 --wait=0.1
22 from collections
.abc
import (
26 SOURCE_DIR
= os
.path
.abspath(os
.path
.normpath(os
.path
.join(os
.path
.dirname(__file__
), "..", "..")))
27 LIB_DIR
= os
.path
.abspath(os
.path
.normpath(os
.path
.join(SOURCE_DIR
, "lib")))
30 "PATH": lambda path
: path
,
31 "SIZE": lambda path
: os
.path
.getsize(path
),
35 def blend_list(path
: str) -> Iterator
[str]:
36 for dirpath
, dirnames
, filenames
in os
.walk(path
):
38 dirnames
[:] = [d
for d
in dirnames
if not d
.startswith(".")]
39 for filename
in filenames
:
40 if filename
.lower().endswith(".blend"):
41 filepath
= os
.path
.join(dirpath
, filename
)
45 def print_load_message(filepath
: str, index
: int) -> None:
46 msg
= "({:d}): {:s}".format(index
, filepath
)
52 def load_blend_file(filepath
: str) -> None:
53 import bpy
# type: ignore
54 bpy
.ops
.wm
.open_mainfile(filepath
=filepath
)
57 def load_files_immediately(blend_files
: list[str], blend_file_index_offset
: int) -> None:
58 index
= blend_file_index_offset
59 for filepath
in blend_files
:
60 print_load_message(filepath
, index
)
62 load_blend_file(filepath
)
65 def load_files_with_wait(blend_files
: list[str], blend_file_index_offset
: int, wait
: float) -> None:
68 def load_on_timer() -> float |
None:
70 if index
>= len(blend_files
):
73 filepath
= blend_files
[index
]
74 print_load_message(filepath
, index
+ blend_file_index_offset
)
77 load_blend_file(filepath
)
81 bpy
.app
.timers
.register(load_on_timer
, persistent
=True)
84 def argparse_handle_int_range(value
: str) -> tuple[int, int]:
85 range_beg
, sep
, range_end
= value
.partition(":")
87 raise argparse
.ArgumentTypeError("Expected a \":\" separator!")
89 result
= int(range_beg
), int(range_end
)
90 except Exception as ex
:
91 raise argparse
.ArgumentTypeError("Expected two integers: {!s}".format(ex
))
95 def argparse_create() -> argparse
.ArgumentParser
:
97 sort_by_choices
= tuple(sorted(SORT_BY_FN
.keys()))
99 # When `--help` or no arguments are given, print this help.
100 epilog
= "Use to automate loading many blend files in a single Blender instance."
102 parser
= argparse
.ArgumentParser(
103 formatter_class
=argparse
.RawTextHelpFormatter
,
114 help="Path to recursively search blend files.",
119 dest
='files_sort_by',
120 choices
=sort_by_choices
,
123 metavar
='SORT_METHOD',
124 help='Order to load files {:s}.'.format(repr(sort_by_choices
)),
130 type=argparse_handle_int_range
,
132 default
=(0, sys
.maxsize
),
135 "The beginning and end range separated by a \":\", e.g."
136 "useful for loading a range of files known to cause problems."
147 "Time to wait between loading files, "
148 "implies redrawing and even allows user interaction (-1.0 to disable)."
155 def main() -> int |
None:
157 argv_sep
= sys
.argv
.index("--")
161 argv
= [] if argv_sep
== -1 else sys
.argv
[argv_sep
+ 1:]
162 args
= argparse_create().parse_args(argv
)
165 if not os
.path
.exists(args
.blend_dir
):
166 sys
.stderr
.write("Path {!r} not found!\n".format(args
.blend_dir
))
168 blend_files
= list(blend_list(args
.blend_dir
))
170 sys
.stderr
.write("No blend files in {!r}!\n".format(args
.blend_dir
))
173 blend_files
.sort(key
=SORT_BY_FN
[args
.files_sort_by
])
175 range_beg
, range_end
= args
.files_range
177 blend_files_total
= len(blend_files
)
179 blend_files
= blend_files
[range_beg
:range_end
]
181 print("Found {:,d} files within {!r}".format(blend_files_total
, args
.blend_dir
))
182 if len(blend_files
) != blend_files_total
:
183 print("Using a sub-range of {:,d}".format(len(blend_files
)))
185 if args
.wait
== -1.0:
186 load_files_immediately(blend_files
, range_beg
)
188 load_files_with_wait(blend_files
, range_beg
, args
.wait
)
194 if __name__
== "__main__":
196 if result
is not None: