PyQt4/QProcess Nuke v9 问题
PyQt4/QProcess issues with Nuke v9
PyQt4/QProcess Nuke v9 问题...
我正尝试在我的工作场所使用 QProcess 运行 在 Nuke 中进行渲染。我想使用 QProcess 的原因是因为我在 Whosebug 社区的帮助下设置了这个任务管理器,它需要一个命令列表并按顺序 运行 一个一个地执行它,并且还允许我显示输出。您可以查看我在这里发布的问题:
现在我主要是想 运行 Nuke 通过这个 "Task Manager" 进行渲染。但是每次我这样做都会给我一个错误,即 QProcess 在 运行ning 时被破坏了。我的意思是我用 subprocess 测试了这个并且工作得很好。所以我不确定为什么渲染不能通过 QProcess 工作。
所以为了做更多的测试,我在家里写了一个简化版本。不过,我 运行 遇到的第一个问题是显然无法从 Nuke 的 python.exe 中找到 PyQt4。尽管我的主要 Python 版本有 PyQt4。但是显然我安装的 PyQt4 存在兼容性问题,因为我的主要 Python 版本是 2.7.12,而我的 Nuke 的 python 版本是 2.7.3。所以我想"fine then i'll just directly install PyQt4 inside my Nuke directory"。所以我抓住了这个 link 并将这个 PyQt 版本安装到我的 Nuke 目录中:
http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.10.3/PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x64.exe
所以我 运行 我的小测试似乎在做与我工作场所相同的事情,QProcess 刚刚被销毁。所以我想也许添加 "waitForFinished()" 可能会做一些不同的事情,但它给了我这个错误,上面写着:
The procedure entry point ??4QString@@QEAAAEAV0@$$QEAV0@@Z could not be located in the dynamic link library QtCore4.dll
也给我这个错误:
ImportError: 无法加载 C:\Program Files\Nuke9.0v8\nuke-9.0.8.dll
现在我真的不能再在家里做任何测试了,我的工作室放假了。所以我有两个问题想请教:
1) 我看到的有关 "procedure entry point" 的错误是什么?只有当我尝试在 QProcess 实例中调用某些东西时才会发生。
2) 为什么我的 QProcess 在渲染完成之前就被销毁了??为什么子流程不会发生这种情况?如何提交 Nuke 渲染作业,同时获得与子进程相同的结果?
这是我的测试代码:
import os
import sys
import subprocess
import PyQt4
from PyQt4 import QtCore
class Task:
def __init__(self, program, args=None):
self._program = program
self._args = args or []
@property
def program(self):
return self._program
@property
def args(self):
return self._args
class SequentialManager(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
progressChanged = QtCore.pyqtSignal(int)
dataChanged = QtCore.pyqtSignal(str)
#^ this is how we can send a signal and can declare what type
# of information we want to pass with this signal
def __init__(self, parent=None):
# super(SequentialManager, self).__init__(parent)
# QtCore.QObject.__init__(self,parent)
QtCore.QObject.__init__(self)
self._progress = 0
self._tasks = []
self._process = QtCore.QProcess(self)
self._process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self._process.finished.connect(self._on_finished)
self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)
def execute(self, tasks):
self._tasks = iter(tasks)
#this 'iter()' method creates an iterator object
self.started.emit()
self._progress = 0
self.progressChanged.emit(self._progress)
self._execute_next()
def _execute_next(self):
try:
task = next(self._tasks)
except StopIteration:
return False
else:
print 'starting %s' % task.args
self._process.start(task.program, task.args)
return True
def _on_finished(self):
self._process_task()
if not self._execute_next():
self.finished.emit()
def _on_readyReadStandardOutput(self):
output = self._process.readAllStandardOutput()
result = output.data().decode()
self.dataChanged.emit(result)
def _process_task(self):
self._progress += 1
self.progressChanged.emit(self._progress)
class outputLog(QtCore.QObject):
def __init__(self, parent=None, parentWindow=None):
QtCore.QObject.__init__(self)
self._manager = SequentialManager(self)
def startProcess(self, tasks):
# self._manager.progressChanged.connect(self._progressbar.setValue)
self._manager.dataChanged.connect(self.on_dataChanged)
self._manager.started.connect(self.on_started)
self._manager.finished.connect(self.on_finished)
self._manager.execute(tasks)
@QtCore.pyqtSlot()
def on_started(self):
print 'process started'
@QtCore.pyqtSlot()
def on_finished(self):
print 'finished'
@QtCore.pyqtSlot(str)
def on_dataChanged(self, message):
if message:
print message
def nukeTestRender():
import nuke
nuke.scriptOpen('D:/PC6/Documents/nukeTestRender/nukeTestRender.nk')
writeNode = None
for node in nuke.allNodes():
if node.Class() == 'Write':
writeNode = node
framesList = [1, 20, 30, 40]
fr = nuke.FrameRanges(framesList)
# nuke.execute(writeNode, fr)
for x in range(20):
print 'random'
def run():
nukePythonEXE = 'C:/Program Files/Nuke9.0v8/python.exe'
thisFile = os.path.dirname(os.path.abspath("__file__"))
print thisFile
cmd = '"%s" %s renderCheck' %(nukePythonEXE, __file__)
cmd2 = [__file__, 'renderCheck']
cmdList = [Task(nukePythonEXE, cmd2)]
# subprocess.call(cmd, stdin=None, stdout=None, stderr=None, shell=False)
taskManager = outputLog()
taskManager.startProcess(cmdList)
taskManager._manager._process.waitForFinished()
if __name__ == "__main__":
print sys.argv
if len(sys.argv) == 1:
run()
elif len(sys.argv) == 2:
nukeTestRender()
我已经想出了一个答案,所以我将详细写在下面:
基本上,我在安装 PyQt4 时遇到错误,因为它与我的 Nuke 版本不兼容,因此显然更推荐使用 Nuke 中包含的 PySide。但是 Nuke 的 Python 可执行文件本身无法找到 PySide,需要将一些路径添加到 sys.path:
paths = ['C:\Program Files\Nuke9.0v8\lib\site-packages,
C:\Users\Desktop02\.nuke',
'C:\Program Files\Nuke9.0v8\plugins',
'C:\Program Files\Nuke9.0v8\pythonextensions\site-packages\setuptools-0.6c11-py2.6.egg',
'C:\Program Files\Nuke9.0v8\pythonextensions\site-packages\protobuf-2.5.0-py2.6.egg',
'C:\Program Files\Nuke9.0v8\pythonextensions\site-packages',
'C:\Program Files\Nuke9.0v8\plugins\modules',
'C:\Program Files\Nuke9.0v8\configs\Python\site-packages',
'C:\Users\Desktop02\.nuke\Python\site-packages']
for path in paths:
sys.path.append(path)
我通过在 GUI 模式下打开 Nuke 和 Python 可执行文件并比较两者 sys.path 以查看 Python 可执行文件缺少什么来找到丢失的路径。
然后回答我自己的主要问题:如果我在 QProcess 实例上调用 waitForFinished(-1),这将忽略此函数的默认 30 秒限制...答案来自此线程:
QProcess and shell : Destroyed while process is still running
所以这是我生成的工作代码:
import os
import sys
import subprocess
sysArgs = sys.argv
try:
import nuke
from PySide import QtCore
except ImportError:
raise ImportError('nuke not currently importable')
class Task:
def __init__(self, program, args=None):
self._program = program
self._args = args or []
@property
def program(self):
return self._program
@property
def args(self):
return self._args
class SequentialManager(QtCore.QObject):
started = QtCore.Signal()
finished = QtCore.Signal()
progressChanged = QtCore.Signal(int)
dataChanged = QtCore.Signal(str)
#^ this is how we can send a signal and can declare what type
# of information we want to pass with this signal
def __init__(self, parent=None):
# super(SequentialManager, self).__init__(parent)
# QtCore.QObject.__init__(self,parent)
QtCore.QObject.__init__(self)
self._progress = 0
self._tasks = []
self._process = QtCore.QProcess(self)
self._process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self._process.finished.connect(self._on_finished)
self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)
def execute(self, tasks):
self._tasks = iter(tasks)
#this 'iter()' method creates an iterator object
self.started.emit()
self._progress = 0
self.progressChanged.emit(self._progress)
self._execute_next()
def _execute_next(self):
try:
task = next(self._tasks)
except StopIteration:
return False
else:
print 'starting %s' % task.args
self._process.start(task.program, task.args)
return True
def _on_finished(self):
self._process_task()
if not self._execute_next():
self.finished.emit()
def _on_readyReadStandardOutput(self):
output = self._process.readAllStandardOutput()
result = output.data().decode()
self.dataChanged.emit(result)
def _process_task(self):
self._progress += 1
self.progressChanged.emit(self._progress)
class outputLog(QtCore.QObject):
def __init__(self, parent=None, parentWindow=None):
QtCore.QObject.__init__(self)
self._manager = SequentialManager(self)
def startProcess(self, tasks):
# self._manager.progressChanged.connect(self._progressbar.setValue)
self._manager.dataChanged.connect(self.on_dataChanged)
self._manager.started.connect(self.on_started)
self._manager.finished.connect(self.on_finished)
self._manager.execute(tasks)
@QtCore.Slot()
def on_started(self):
print 'process started'
@QtCore.Slot()
def on_finished(self):
print 'finished'
@QtCore.Slot(str)
def on_dataChanged(self, message):
if message:
print message
def nukeTestRender():
import nuke
nuke.scriptOpen('D:/PC6/Documents/nukeTestRender/nukeTestRender.nk')
writeNode = None
for node in nuke.allNodes():
if node.Class() == 'Write':
writeNode = node
framesList = [1, 20, 30, 40]
fr = nuke.FrameRanges(framesList)
nuke.execute(writeNode, fr)
# nuke.execute(writeNode, start=1, end=285)
for x in range(20):
print 'random'
def run():
nukePythonEXE = 'C:/Program Files/Nuke9.0v8/python.exe'
thisFile = os.path.dirname(os.path.abspath("__file__"))
print thisFile
cmd = '"%s" %s renderCheck' %(nukePythonEXE, sysArgs[0])
cmd2 = [sysArgs[0], 'renderCheck']
cmdList = [Task(nukePythonEXE, cmd2)]
# subprocess.call(cmd, stdin=None, stdout=None, stderr=None, shell=False)
taskManager = outputLog()
taskManager.startProcess(cmdList)
taskManager._manager._process.waitForFinished(-1)
if __name__ == "__main__":
print sys.argv
if len(sysArgs) == 1:
run()
elif len(sysArgs) == 2:
nukeTestRender()
无论出于何种原因,PySide 拒绝在没有先导入 nuke 模块的情况下为我加载。并且在导入 nuke 时还有一个已知错误,它会删除所有 sys.argv 参数,因此必须在 nuke 导入之前先将其存储在某个地方...
PyQt4/QProcess Nuke v9 问题...
我正尝试在我的工作场所使用 QProcess 运行 在 Nuke 中进行渲染。我想使用 QProcess 的原因是因为我在 Whosebug 社区的帮助下设置了这个任务管理器,它需要一个命令列表并按顺序 运行 一个一个地执行它,并且还允许我显示输出。您可以查看我在这里发布的问题:
现在我主要是想 运行 Nuke 通过这个 "Task Manager" 进行渲染。但是每次我这样做都会给我一个错误,即 QProcess 在 运行ning 时被破坏了。我的意思是我用 subprocess 测试了这个并且工作得很好。所以我不确定为什么渲染不能通过 QProcess 工作。
所以为了做更多的测试,我在家里写了一个简化版本。不过,我 运行 遇到的第一个问题是显然无法从 Nuke 的 python.exe 中找到 PyQt4。尽管我的主要 Python 版本有 PyQt4。但是显然我安装的 PyQt4 存在兼容性问题,因为我的主要 Python 版本是 2.7.12,而我的 Nuke 的 python 版本是 2.7.3。所以我想"fine then i'll just directly install PyQt4 inside my Nuke directory"。所以我抓住了这个 link 并将这个 PyQt 版本安装到我的 Nuke 目录中:
http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.10.3/PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x64.exe
所以我 运行 我的小测试似乎在做与我工作场所相同的事情,QProcess 刚刚被销毁。所以我想也许添加 "waitForFinished()" 可能会做一些不同的事情,但它给了我这个错误,上面写着:
The procedure entry point ??4QString@@QEAAAEAV0@$$QEAV0@@Z could not be located in the dynamic link library QtCore4.dll
也给我这个错误:
ImportError: 无法加载 C:\Program Files\Nuke9.0v8\nuke-9.0.8.dll
现在我真的不能再在家里做任何测试了,我的工作室放假了。所以我有两个问题想请教:
1) 我看到的有关 "procedure entry point" 的错误是什么?只有当我尝试在 QProcess 实例中调用某些东西时才会发生。
2) 为什么我的 QProcess 在渲染完成之前就被销毁了??为什么子流程不会发生这种情况?如何提交 Nuke 渲染作业,同时获得与子进程相同的结果?
这是我的测试代码:
import os
import sys
import subprocess
import PyQt4
from PyQt4 import QtCore
class Task:
def __init__(self, program, args=None):
self._program = program
self._args = args or []
@property
def program(self):
return self._program
@property
def args(self):
return self._args
class SequentialManager(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
progressChanged = QtCore.pyqtSignal(int)
dataChanged = QtCore.pyqtSignal(str)
#^ this is how we can send a signal and can declare what type
# of information we want to pass with this signal
def __init__(self, parent=None):
# super(SequentialManager, self).__init__(parent)
# QtCore.QObject.__init__(self,parent)
QtCore.QObject.__init__(self)
self._progress = 0
self._tasks = []
self._process = QtCore.QProcess(self)
self._process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self._process.finished.connect(self._on_finished)
self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)
def execute(self, tasks):
self._tasks = iter(tasks)
#this 'iter()' method creates an iterator object
self.started.emit()
self._progress = 0
self.progressChanged.emit(self._progress)
self._execute_next()
def _execute_next(self):
try:
task = next(self._tasks)
except StopIteration:
return False
else:
print 'starting %s' % task.args
self._process.start(task.program, task.args)
return True
def _on_finished(self):
self._process_task()
if not self._execute_next():
self.finished.emit()
def _on_readyReadStandardOutput(self):
output = self._process.readAllStandardOutput()
result = output.data().decode()
self.dataChanged.emit(result)
def _process_task(self):
self._progress += 1
self.progressChanged.emit(self._progress)
class outputLog(QtCore.QObject):
def __init__(self, parent=None, parentWindow=None):
QtCore.QObject.__init__(self)
self._manager = SequentialManager(self)
def startProcess(self, tasks):
# self._manager.progressChanged.connect(self._progressbar.setValue)
self._manager.dataChanged.connect(self.on_dataChanged)
self._manager.started.connect(self.on_started)
self._manager.finished.connect(self.on_finished)
self._manager.execute(tasks)
@QtCore.pyqtSlot()
def on_started(self):
print 'process started'
@QtCore.pyqtSlot()
def on_finished(self):
print 'finished'
@QtCore.pyqtSlot(str)
def on_dataChanged(self, message):
if message:
print message
def nukeTestRender():
import nuke
nuke.scriptOpen('D:/PC6/Documents/nukeTestRender/nukeTestRender.nk')
writeNode = None
for node in nuke.allNodes():
if node.Class() == 'Write':
writeNode = node
framesList = [1, 20, 30, 40]
fr = nuke.FrameRanges(framesList)
# nuke.execute(writeNode, fr)
for x in range(20):
print 'random'
def run():
nukePythonEXE = 'C:/Program Files/Nuke9.0v8/python.exe'
thisFile = os.path.dirname(os.path.abspath("__file__"))
print thisFile
cmd = '"%s" %s renderCheck' %(nukePythonEXE, __file__)
cmd2 = [__file__, 'renderCheck']
cmdList = [Task(nukePythonEXE, cmd2)]
# subprocess.call(cmd, stdin=None, stdout=None, stderr=None, shell=False)
taskManager = outputLog()
taskManager.startProcess(cmdList)
taskManager._manager._process.waitForFinished()
if __name__ == "__main__":
print sys.argv
if len(sys.argv) == 1:
run()
elif len(sys.argv) == 2:
nukeTestRender()
我已经想出了一个答案,所以我将详细写在下面:
基本上,我在安装 PyQt4 时遇到错误,因为它与我的 Nuke 版本不兼容,因此显然更推荐使用 Nuke 中包含的 PySide。但是 Nuke 的 Python 可执行文件本身无法找到 PySide,需要将一些路径添加到 sys.path:
paths = ['C:\Program Files\Nuke9.0v8\lib\site-packages,
C:\Users\Desktop02\.nuke',
'C:\Program Files\Nuke9.0v8\plugins',
'C:\Program Files\Nuke9.0v8\pythonextensions\site-packages\setuptools-0.6c11-py2.6.egg',
'C:\Program Files\Nuke9.0v8\pythonextensions\site-packages\protobuf-2.5.0-py2.6.egg',
'C:\Program Files\Nuke9.0v8\pythonextensions\site-packages',
'C:\Program Files\Nuke9.0v8\plugins\modules',
'C:\Program Files\Nuke9.0v8\configs\Python\site-packages',
'C:\Users\Desktop02\.nuke\Python\site-packages']
for path in paths:
sys.path.append(path)
我通过在 GUI 模式下打开 Nuke 和 Python 可执行文件并比较两者 sys.path 以查看 Python 可执行文件缺少什么来找到丢失的路径。
然后回答我自己的主要问题:如果我在 QProcess 实例上调用 waitForFinished(-1),这将忽略此函数的默认 30 秒限制...答案来自此线程:
QProcess and shell : Destroyed while process is still running
所以这是我生成的工作代码:
import os
import sys
import subprocess
sysArgs = sys.argv
try:
import nuke
from PySide import QtCore
except ImportError:
raise ImportError('nuke not currently importable')
class Task:
def __init__(self, program, args=None):
self._program = program
self._args = args or []
@property
def program(self):
return self._program
@property
def args(self):
return self._args
class SequentialManager(QtCore.QObject):
started = QtCore.Signal()
finished = QtCore.Signal()
progressChanged = QtCore.Signal(int)
dataChanged = QtCore.Signal(str)
#^ this is how we can send a signal and can declare what type
# of information we want to pass with this signal
def __init__(self, parent=None):
# super(SequentialManager, self).__init__(parent)
# QtCore.QObject.__init__(self,parent)
QtCore.QObject.__init__(self)
self._progress = 0
self._tasks = []
self._process = QtCore.QProcess(self)
self._process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self._process.finished.connect(self._on_finished)
self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)
def execute(self, tasks):
self._tasks = iter(tasks)
#this 'iter()' method creates an iterator object
self.started.emit()
self._progress = 0
self.progressChanged.emit(self._progress)
self._execute_next()
def _execute_next(self):
try:
task = next(self._tasks)
except StopIteration:
return False
else:
print 'starting %s' % task.args
self._process.start(task.program, task.args)
return True
def _on_finished(self):
self._process_task()
if not self._execute_next():
self.finished.emit()
def _on_readyReadStandardOutput(self):
output = self._process.readAllStandardOutput()
result = output.data().decode()
self.dataChanged.emit(result)
def _process_task(self):
self._progress += 1
self.progressChanged.emit(self._progress)
class outputLog(QtCore.QObject):
def __init__(self, parent=None, parentWindow=None):
QtCore.QObject.__init__(self)
self._manager = SequentialManager(self)
def startProcess(self, tasks):
# self._manager.progressChanged.connect(self._progressbar.setValue)
self._manager.dataChanged.connect(self.on_dataChanged)
self._manager.started.connect(self.on_started)
self._manager.finished.connect(self.on_finished)
self._manager.execute(tasks)
@QtCore.Slot()
def on_started(self):
print 'process started'
@QtCore.Slot()
def on_finished(self):
print 'finished'
@QtCore.Slot(str)
def on_dataChanged(self, message):
if message:
print message
def nukeTestRender():
import nuke
nuke.scriptOpen('D:/PC6/Documents/nukeTestRender/nukeTestRender.nk')
writeNode = None
for node in nuke.allNodes():
if node.Class() == 'Write':
writeNode = node
framesList = [1, 20, 30, 40]
fr = nuke.FrameRanges(framesList)
nuke.execute(writeNode, fr)
# nuke.execute(writeNode, start=1, end=285)
for x in range(20):
print 'random'
def run():
nukePythonEXE = 'C:/Program Files/Nuke9.0v8/python.exe'
thisFile = os.path.dirname(os.path.abspath("__file__"))
print thisFile
cmd = '"%s" %s renderCheck' %(nukePythonEXE, sysArgs[0])
cmd2 = [sysArgs[0], 'renderCheck']
cmdList = [Task(nukePythonEXE, cmd2)]
# subprocess.call(cmd, stdin=None, stdout=None, stderr=None, shell=False)
taskManager = outputLog()
taskManager.startProcess(cmdList)
taskManager._manager._process.waitForFinished(-1)
if __name__ == "__main__":
print sys.argv
if len(sysArgs) == 1:
run()
elif len(sysArgs) == 2:
nukeTestRender()
无论出于何种原因,PySide 拒绝在没有先导入 nuke 模块的情况下为我加载。并且在导入 nuke 时还有一个已知错误,它会删除所有 sys.argv 参数,因此必须在 nuke 导入之前先将其存储在某个地方...