Skip to content

Commit 8c3d9b2

Browse files
committed
Move Blender version check to separate function, rework subprocessing
1 parent 9b5f7f4 commit 8c3d9b2

File tree

1 file changed

+92
-74
lines changed

1 file changed

+92
-74
lines changed

src/windows/views/blender_listview.py

+92-74
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,71 @@ class Worker(QObject):
658658
blender_error_with_data = pyqtSignal(str) # 1007
659659
enable_interface = pyqtSignal() # 1008
660660

661+
def __init__(self):
662+
super().__init__()
663+
s = settings.get_settings()
664+
self.blender_exec_path = s.get("blender_command")
665+
666+
# Init regex expression used to determine blender's render progress
667+
self.blender_frame_re = re.compile(r"Fra:([0-9,]*)")
668+
self.blender_saved_re = re.compile(r"Saved: '(.*\.png)")
669+
self.blender_version_re = re.compile(
670+
r"^Blender ([0-9a-z\.]*)", flags=re.MULTILINE)
671+
672+
self.version = None
673+
self.process = None
674+
self.is_running = False
675+
676+
self.startupinfo = None
677+
if sys.platform == 'win32':
678+
self.startupinfo = subprocess.STARTUPINFO()
679+
self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
680+
681+
def blender_version_check(self):
682+
# Check the version of Blender
683+
command_get_version = [self.blender_exec_path, '-v']
684+
log.debug("Checking Blender version, command: {}".format(
685+
" ".join([shlex.quote(x) for x in command_get_version])))
686+
687+
try:
688+
if self.process:
689+
self.process.terminate()
690+
self.process = subprocess.Popen(
691+
command_get_version,
692+
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
693+
startupinfo=self.startupinfo,
694+
)
695+
# Give Blender up to 10 seconds to respond
696+
(out, err) = self.process.communicate(timeout=10)
697+
except subprocess.SubprocessError:
698+
# Error running command. Most likely the blender executable path in
699+
# the settings is incorrect, or is not a supported Blender version
700+
self.blender_error_nodata.emit()
701+
return False
702+
except subprocess.TimeoutExpired:
703+
self.process.kill()
704+
self.blender_error_nodata.emit()
705+
return False
706+
except Exception:
707+
log.error("Version check exception", exc_info=1)
708+
return
709+
710+
ver_string = out.decode('utf-8')
711+
log.debug("Blender output:\n%s", ver_string)
712+
713+
ver_match = self.blender_version_re.search(ver_string)
714+
if not ver_match:
715+
raise Exception("No Blender version detected in output")
716+
log.debug("Matched %s in output", str(ver_match))
717+
718+
self.version = ver_match.group(1)
719+
log.info("Found Blender version {}".format(self.version))
720+
721+
if self.version < info.BLENDER_MIN_VERSION:
722+
# Wrong version of Blender.
723+
self.blender_version_error.emit(self.version)
724+
return (self.version >= info.BLENDER_MIN_VERSION)
725+
661726
@pyqtSlot()
662727
def Cancel(self):
663728
"""Cancel worker render"""
@@ -670,35 +735,20 @@ def Cancel(self):
670735
def Render(self, blend_file_path, target_script, preview_frame=0):
671736
""" Worker's Render method which invokes the Blender rendering commands """
672737

673-
# Init regex expression used to determine blender's render progress
674-
s = settings.get_settings()
675-
676738
_ = get_app()._tr
677739

678740
# get the blender executable path
679-
self.blender_exec_path = s.get("blender_command")
680741
self.blend_file_path = blend_file_path
681742
self.target_script = target_script
682-
self.preview_mode = bool(preview_frame > 0)
683-
self.frame_detected = False
684-
self.last_frame = 0
685-
self.version = None
686-
self.command_output = ""
687-
self.process = None
688-
self.is_running = False
689-
690-
blender_frame_re = re.compile(r"Fra:([0-9,]*)")
691-
blender_saved_re = re.compile(r"Saved: '(.*\.png)")
692-
blender_version_re = re.compile(r"Blender (.*?) ")
743+
preview_mode = bool(preview_frame > 0)
744+
command_output = ""
693745

694-
startupinfo = None
695-
if sys.platform == 'win32':
696-
startupinfo = subprocess.STARTUPINFO()
697-
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
746+
if not self.version:
747+
if not self.blender_version_check():
748+
return
698749

699750
try:
700751
# Shell the blender command to create the image sequence
701-
command_get_version = [self.blender_exec_path, '-v']
702752
command_render = [
703753
self.blender_exec_path, '-b', self.blend_file_path,
704754
'-y', '-P', self.target_script
@@ -711,49 +761,18 @@ def Render(self, blend_file_path, target_script, preview_frame=0):
711761
# Render entire animation
712762
command_render.extend(['-a'])
713763

714-
# Check the version of Blender
715-
import shlex
716-
log.info("Checking Blender version, command: {}".format(
717-
" ".join([shlex.quote(x) for x in command_get_version])))
718-
719-
self.process = subprocess.Popen(
720-
command_get_version,
721-
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
722-
startupinfo=startupinfo,
723-
)
724-
725-
# Check the version of Blender
726-
try:
727-
# Give Blender up to 10 seconds to respond
728-
(out, err) = self.process.communicate(timeout=10)
729-
except subprocess.TimeoutExpired:
730-
self.blender_error_nodata.emit()
731-
return
732-
733-
ver_string = out.decode('utf-8')
734-
ver_match = blender_version_re.search(ver_string)
735-
736-
if not ver_match:
737-
raise Exception("No Blender version detected in output")
738-
739-
self.version = ver_match.group(1)
740-
log.info("Found Blender version {}".format(self.version))
741-
742-
if self.version < info.BLENDER_MIN_VERSION:
743-
# Wrong version of Blender.
744-
self.blender_version_error.emit(self.version)
745-
return
746-
747764
# debug info
748-
log.info("Running Blender, command: {}".format(
765+
log.debug("Running Blender, command: {}".format(
749766
" ".join([shlex.quote(x) for x in command_render])))
750-
log.info("Blender output:")
767+
log.debug("Blender output:")
751768

752-
# Run real command to render Blender project
769+
# Run command to render Blender frame(s)
770+
if self.process:
771+
self.process.terminate()
753772
self.process = subprocess.Popen(
754773
command_render, bufsize=512,
755774
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
756-
startupinfo=startupinfo,
775+
startupinfo=self.startupinfo,
757776
)
758777
self.is_running = True
759778

@@ -763,42 +782,41 @@ def Render(self, blend_file_path, target_script, preview_frame=0):
763782
self.is_running = False
764783
self.blender_error_nodata.emit()
765784
raise
766-
except Exception as ex:
767-
log.error("Worker exception: {}".format(ex))
785+
except Exception:
786+
log.error("Worker exception", exc_info=1)
768787
return
769788

789+
last_frame = 0
790+
frame_saved = False
770791
while self.is_running and self.process.poll() is None:
771-
for outline in iter(self.process.stdout.readline, b''):
772-
line = outline.decode('utf-8').strip()
792+
for out_line in iter(self.process.stdout.readline, b''):
793+
line = out_line.decode('utf-8').strip()
773794

774795
# Skip blank output
775796
if not line:
776797
continue
777798

778799
# append all output into a variable, and log
779-
self.command_output = self.command_output + line + "\n"
780-
log.info(" {}".format(line))
800+
command_output += line + "\n"
801+
log.debug(" {}".format(line))
781802

782803
# Look for progress info in the Blender Output
783-
output_frame = blender_frame_re.search(line)
784-
output_saved = blender_saved_re.search(line)
785-
786-
# Does it have a match?
787-
if output_frame or output_saved:
788-
# Yes, we have a match
789-
self.frame_detected = True
804+
output_frame = self.blender_frame_re.search(line)
805+
output_saved = self.blender_saved_re.search(line)
790806

791807
if output_frame:
792808
current_frame = int(output_frame.group(1))
793809

794810
# Update progress bar
795-
if current_frame != self.last_frame and not self.preview_mode:
811+
if current_frame != last_frame and not preview_mode:
796812
# update progress on frame change, if in 'render' mode
797813
self.progress.emit(current_frame)
798814

799-
self.last_frame = current_frame
815+
last_frame = current_frame
800816

801817
if output_saved:
818+
frame_saved = True
819+
log.debug("Saved frame %d", last_frame)
802820
# Update preview image
803821
self.image_updated.emit(output_saved.group(1))
804822

@@ -808,13 +826,13 @@ def Render(self, blend_file_path, target_script, preview_frame=0):
808826
self.enable_interface.emit()
809827

810828
# Check if NO FRAMES are detected
811-
if not self.frame_detected:
829+
if not frame_saved:
812830
# Show Error that no frames are detected. This is likely caused by
813831
# the wrong command being executed... or an error in Blender.
814832
self.blender_error_with_data.emit(_("No frame was found in the output from Blender"))
815833

816834
# Done with render (i.e. close window)
817-
elif self.is_running and not self.preview_mode:
835+
elif self.is_running and not preview_mode:
818836
# only add file to project data if in 'render' mode and not canceled
819837
self.finished.emit()
820838

0 commit comments

Comments
 (0)