error can be locked within properties()

and simplified the componenterrors again
This commit is contained in:
tassaron 2017-07-25 22:02:47 -04:00
parent 661526b073
commit 15d70474d4
6 changed files with 46 additions and 66 deletions

View File

@ -19,7 +19,7 @@ class ComponentMetaclass(type(QtCore.QObject)):
return func(self, *args, **kwargs) return func(self, *args, **kwargs)
except Exception: except Exception:
try: try:
raise ComponentInitError(self, 'initialization process') raise ComponentError(self, 'initialization process')
except ComponentError: except ComponentError:
return return
return initializationWrapper return initializationWrapper
@ -63,7 +63,13 @@ class ComponentMetaclass(type(QtCore.QObject)):
if self._lockedProperties is not None: if self._lockedProperties is not None:
return self._lockedProperties return self._lockedProperties
else: else:
return func(self) try:
return func(self)
except Exception:
try:
raise ComponentError(self, 'properties')
except ComponentError:
return []
return propertiesWrapper return propertiesWrapper
def errorWrapper(func): def errorWrapper(func):
@ -396,18 +402,18 @@ class Component(QtCore.QObject, metaclass=ComponentMetaclass):
''' '''
class ComponentException(RuntimeError): class ComponentError(RuntimeError):
'''A base class for component errors''' '''Gives the MainWindow a traceback to display, and cancels the export.'''
_prevErrors = [] prevErrors = []
def __init__(self, caller, name, immediate): def __init__(self, caller, name):
print('ComponentError by %s: %s' % (caller.name, name)) print('ComponentError by %s: %s' % (caller.name, name))
super().__init__() super().__init__()
if len(ComponentException._prevErrors) > 1: if len(ComponentError.prevErrors) > 1:
ComponentException._prevErrors.pop() ComponentError.prevErrors.pop()
ComponentException._prevErrors.insert(0, name) ComponentError.prevErrors.insert(0, name)
if name in ComponentException._prevErrors[1:]: if name in ComponentError.prevErrors[1:]:
# Don't create multiple windows for repeated messages # Don't create multiple windows for repeated messages
return return
@ -434,28 +440,4 @@ class ComponentException(RuntimeError):
) )
) )
if immediate: caller._error.emit(string, detail)
caller._error.emit(string, detail)
else:
caller.lockProperties(['error'])
caller.lockError((string, detail))
class ComponentError(ComponentException):
'''
Use for general Python errors caused by a component at any time.
Raising this gives the MainWindow a traceback to display and
cancels any export in progress.
'''
def __init__(self, caller, name):
ComponentException.__init__(self, caller, name, True)
class ComponentInitError(ComponentError):
'''
Use for Python errors in preFrameRender, while the export is starting.
This will end the video thread in a clean way by locking the component
into an error state so the export definitely won't begin.
'''
def __init__(self, caller, name):
ComponentException.__init__(self, caller, name, False)

View File

@ -154,33 +154,28 @@ class Component(Component):
return frame return frame
def properties(self): def properties(self):
# TODO: Disallow selecting the same video you're exporting to
props = [] props = []
if not self.videoPath or self.badVideo \
or not os.path.exists(self.videoPath): if not self.videoPath:
return ['error'] self.lockError("There is no video selected.")
elif self.badVideo:
self.lockError("Could not identify an audio stream in this video.")
elif not os.path.exists(self.videoPath):
self.lockError("The video selected does not exist!")
elif (os.path.realpath(self.videoPath) ==
os.path.realpath(
self.parent.window.lineEdit_outputFile.text())):
self.lockError("Input and output paths match.")
if self.useAudio: if self.useAudio:
props.append('audio') props.append('audio')
self.testAudioStream() if not testAudioStream(self.videoPath) \
if self.badAudio: and self.error() is None:
return ['error'] self.lockError(
"Could not identify an audio stream in this video.")
return props return props
def error(self):
if self.badAudio:
return "Could not identify an audio stream in this video."
if not self.videoPath:
return "There is no video selected."
if not os.path.exists(self.videoPath):
return "The video selected does not exist!"
if self.badVideo:
return "The video selected is corrupt!"
def testAudioStream(self):
self.badAudio = testAudioStream(self.videoPath)
def audio(self): def audio(self):
params = {} params = {}
if self.volume != 1.0: if self.volume != 1.0:

View File

@ -573,16 +573,16 @@ class MainWindow(QtWidgets.QMainWindow):
@QtCore.pyqtSlot(str, str) @QtCore.pyqtSlot(str, str)
def videoThreadError(self, msg, detail): def videoThreadError(self, msg, detail):
self.showMessage(
msg=msg,
detail=detail,
icon='Warning',
)
try: try:
self.stopVideo() self.stopVideo()
except AttributeError as e: except AttributeError as e:
if 'videoWorker' not in str(e): if 'videoWorker' not in str(e):
raise raise
self.showMessage(
msg=msg,
detail=detail,
icon='Warning',
)
def changeEncodingStatus(self, status): def changeEncodingStatus(self, status):
self.encoding = status self.encoding = status

BIN
src/presetmanager.pyc Normal file

Binary file not shown.

View File

@ -224,9 +224,9 @@ def testAudioStream(filename):
try: try:
checkOutput(audioTestCommand, stderr=subprocess.DEVNULL) checkOutput(audioTestCommand, stderr=subprocess.DEVNULL)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
return True
else:
return False return False
else:
return True
def getAudioDuration(filename): def getAudioDuration(filename):

View File

@ -163,24 +163,27 @@ class Worker(QtCore.QObject):
except ComponentError: except ComponentError:
pass pass
if 'error' in comp.properties(): compProps = comp.properties()
if 'error' in compProps or comp.error() is not None:
self.cancel() self.cancel()
self.canceled = True self.canceled = True
canceledByComponent = True canceledByComponent = True
compError = comp.error() \ compError = comp.error() \
if type(comp.error()) is tuple else (comp.error(), '') if type(comp.error()) is tuple else (comp.error(), '')
errMsg = ( errMsg = (
"Component #%s encountered an error!" % compNo "Component #%s (%s) encountered an error!" % (
str(compNo), comp.name
)
if comp.error() is None else if comp.error() is None else
'Export cancelled by component #%s (%s): %s' % ( 'Export cancelled by component #%s (%s): %s' % (
str(compNo), str(compNo),
str(comp), comp.name,
compError[0] compError[0]
) )
) )
comp._error.emit(errMsg, compError[1]) comp._error.emit(errMsg, compError[1])
break break
if 'static' in comp.properties(): if 'static' in compProps:
self.staticComponents[compNo] = \ self.staticComponents[compNo] = \
comp.frameRender(compNo, 0).copy() comp.frameRender(compNo, 0).copy()