Merge branch 'develop' into feature/pyblish-ftrack

This commit is contained in:
Milan Kolar 2018-11-23 21:47:03 +01:00
commit a04aecc2fa
6 changed files with 321 additions and 147 deletions

9
.flake8 Normal file
View file

@ -0,0 +1,9 @@
[flake8]
# ignore = D203
exclude =
.git,
__pycache__,
docs,
*/vendor
max-complexity = 30

View file

@ -1,56 +1,201 @@
import sys
import os
import argparse
from app.lib.utils import forward
import subprocess
import threading
import time
from app import style
from app.vendor.Qt import QtCore, QtGui, QtWidgets
from pype.ftrack import credentials, login_dialog as login_dialog
from app.api import Logger
from FtrackServer import FtrackServer
log = Logger.getLogger(__name__)
# Validation if alredy logged into Ftrack
def validate():
validation = False
cred = credentials._get_credentials()
if 'username' in cred and 'apiKey' in cred:
validation = credentials._check_credentials(
cred['username'],
cred['apiKey']
)
if validation is False:
login_dialog.run_login()
else:
login_dialog.run_login()
class FtrackRunner:
def __init__(self, main_parent=None, parent=None):
validation = credentials._check_credentials()
if not validation:
print("We are unable to connect to Ftrack")
sys.exit()
self.parent = parent
self.loginWidget = login_dialog.Login_Dialog_ui(self)
self.actionThread = None
self.actionServer = FtrackServer('action')
self.eventThread = None
self.eventServer = FtrackServer('event')
# Entered arguments
parser = argparse.ArgumentParser()
parser.add_argument("--actionserver", action="store_true",
help="launch action server for ftrack")
parser.add_argument("--eventserver", action="store_true",
help="launch action server for ftrack")
parser.add_argument("--logout", action="store_true",
help="launch action server for ftrack")
self.boolLogged = False
self.boolActionServer = False
self.boolEventServer = False
kwargs, args = parser.parse_known_args()
def showLoginWidget(self):
self.loginWidget.show()
if kwargs.logout:
credentials._clear_credentials()
sys.exit()
else:
validate()
def validate(self):
validation = False
cred = credentials._get_credentials()
try:
if 'username' in cred and 'apiKey' in cred:
validation = credentials._check_credentials(
cred['username'],
cred['apiKey']
)
if validation is False:
self.showLoginWidget()
else:
self.showLoginWidget()
if kwargs.eventserver:
fname = os.path.join(os.environ["FTRACK_ACTION_SERVER"], "eventServer.py")
returncode = forward([
sys.executable, "-u", fname
])
except Exception as e:
log.error("We are unable to connect to Ftrack: {0}".format(e))
else:
fname = os.path.join(os.environ["FTRACK_ACTION_SERVER"], "actionServer.py")
returncode = forward([
sys.executable, "-u", fname
])
validation = credentials._check_credentials()
if validation is True:
log.info("Connected to Ftrack successfully")
self.loginChange()
else:
log.warning("Please sign in to Ftrack")
self.boolLogged = False
self.setMenuVisibility()
sys.exit(returncode)
return validation
# Necessary - login_dialog works with this method after logging in
def loginChange(self):
self.boolLogged = True
self.setMenuVisibility()
self.runActionServer()
def logout(self):
credentials._clear_credentials()
self.stopActionServer()
self.stopEventServer()
log.info("Logged out of Ftrack")
self.boolLogged = False
self.setMenuVisibility()
# Actions part
def runActionServer(self):
if self.actionThread is None:
self.actionThread = threading.Thread(target=self.setActionServer)
self.actionThread.daemon=True
self.actionThread.start()
log.info("Ftrack action server launched")
self.boolActionServer = True
self.setMenuVisibility()
def setActionServer(self):
self.actionServer.run_server()
def resetActionServer(self):
self.stopActionServer()
self.runActionServer()
def stopActionServer(self):
try:
self.actionServer.stop_session()
if self.actionThread is not None:
self.actionThread.join()
self.actionThread = None
log.info("Ftrack action server stopped")
self.boolActionServer = False
self.setMenuVisibility()
except Exception as e:
log.error("During Killing action server: {0}".format(e))
# Events part
def runEventServer(self):
if self.eventThread is None:
self.eventThread = threading.Thread(target=self.setEventServer)
self.eventThread.daemon=True
self.eventThread.start()
log.info("Ftrack event server launched")
self.boolEventServer = True
self.setMenuVisibility()
def setEventServer(self):
self.eventServer.run_server()
def resetEventServer(self):
self.stopEventServer()
self.runEventServer()
def stopEventServer(self):
try:
self.eventServer.stop_session()
if self.eventThread is not None:
self.eventThread.join()
self.eventThread = None
log.info("Ftrack event server stopped")
self.boolEventServer = False
self.setMenuVisibility()
except Exception as e:
log.error("During Killing Event server: {0}".format(e))
# Definition of Tray menu
def trayMenu(self, parent):
# Menu for Tray App
self.menu = QtWidgets.QMenu('Ftrack', parent)
self.menu.setProperty('submenu', 'on')
self.menu.setStyleSheet(style.load_stylesheet())
# Actions - server
self.smActionS = self.menu.addMenu("Action server")
self.aRunActionS = QtWidgets.QAction("Run action server", self.smActionS)
self.aRunActionS.triggered.connect(self.runActionServer)
self.aResetActionS = QtWidgets.QAction("Reset action server", self.smActionS)
self.aResetActionS.triggered.connect(self.resetActionServer)
self.aStopActionS = QtWidgets.QAction("Stop action server", self.smActionS)
self.aStopActionS.triggered.connect(self.stopActionServer)
self.smActionS.addAction(self.aRunActionS)
self.smActionS.addAction(self.aResetActionS)
self.smActionS.addAction(self.aStopActionS)
# Actions - server
self.smEventS = self.menu.addMenu("Event server")
self.aRunEventS = QtWidgets.QAction("Run event server", self.smEventS)
self.aRunEventS.triggered.connect(self.runEventServer)
self.aResetEventS = QtWidgets.QAction("Reset event server", self.smEventS)
self.aResetEventS.triggered.connect(self.resetEventServer)
self.aStopEventS = QtWidgets.QAction("Stop event server", self.smEventS)
self.aStopEventS.triggered.connect(self.stopEventServer)
self.smEventS.addAction(self.aRunEventS)
self.smEventS.addAction(self.aResetEventS)
self.smEventS.addAction(self.aStopEventS)
# Actions - basic
self.aLogin = QtWidgets.QAction("Login",self.menu)
self.aLogin.triggered.connect(self.validate)
self.aLogout = QtWidgets.QAction("Logout",self.menu)
self.aLogout.triggered.connect(self.logout)
self.menu.addAction(self.aLogin)
self.menu.addAction(self.aLogout)
self.boolLogged = False
self.setMenuVisibility()
return self.menu
# Definition of visibility of each menu actions
def setMenuVisibility(self):
self.smActionS.menuAction().setVisible(self.boolLogged)
self.smEventS.menuAction().setVisible(self.boolLogged)
self.aLogin.setVisible(not self.boolLogged)
self.aLogout.setVisible(self.boolLogged)
if self.boolLogged is False:
return
self.aRunActionS.setVisible(not self.boolActionServer)
self.aResetActionS.setVisible(self.boolActionServer)
self.aStopActionS.setVisible(self.boolActionServer)
self.aRunEventS.setVisible(not self.boolEventServer)
self.aResetEventS.setVisible(self.boolEventServer)
self.aStopEventS.setVisible(self.boolEventServer)

View file

@ -17,9 +17,15 @@ class Login_Dialog_ui(QtWidgets.QWidget):
buttons = []
labels = []
def __init__(self):
def __init__(self, parent=None):
super().__init__()
super(Login_Dialog_ui, self).__init__()
self.parent = parent
self.setWindowIcon(self.parent.parent.icon)
self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint)
self.loginSignal.connect(self.loginWithCredentials)
self._translate = QtCore.QCoreApplication.translate
@ -32,12 +38,11 @@ class Login_Dialog_ui(QtWidgets.QWidget):
self.resize(self.SIZE_W, self.SIZE_H)
self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H))
self.setMaximumSize(QtCore.QSize(self.SIZE_W+100, self.SIZE_H+100))
self.setStyleSheet(style.load_stylesheet())
self.setLayout(self._main())
self.setWindowTitle('FTrack Login')
self.show()
self.setWindowTitle('Pype - Ftrack Login')
def _main(self):
self.main = QtWidgets.QVBoxLayout()
@ -163,15 +168,15 @@ class Login_Dialog_ui(QtWidgets.QWidget):
entity.setStyleSheet("border: 1px solid red;")
def enter_credentials(self):
user = self.user_input.text().strip()
api = self.api_input.text().strip()
username = self.user_input.text().strip()
apiKey = self.api_input.text().strip()
msg = "You didn't enter "
missing = []
if user == "":
if username == "":
missing.append("Username")
self._invalid_input(self.user_input)
if api == "":
if apiKey == "":
missing.append("API Key")
self._invalid_input(self.api_input)
@ -179,7 +184,7 @@ class Login_Dialog_ui(QtWidgets.QWidget):
self.setError("{0} {1}".format(msg, " and ".join(missing)))
return
verification = credentials._check_credentials(user, api)
verification = credentials._check_credentials(username, apiKey)
if verification:
credentials._save_credentials(username, apiKey)
@ -280,23 +285,12 @@ class Login_Dialog_ui(QtWidgets.QWidget):
if verification is True:
credentials._save_credentials(username, apiKey)
credentials._set_env(username, apiKey)
self.parent.loginChange()
self._close_widget()
def closeEvent(self, event):
event.ignore()
self._close_widget()
def _close_widget(self):
self.close()
class Login_Dialog(Login_Dialog_ui):
def __init__(self):
super(Login_Dialog, self).__init__()
def getApp():
return QtWidgets.QApplication(sys.argv)
def run_login():
app = getApp()
ui = Login_Dialog()
ui.show()
app.exec_()
self.hide()

View file

@ -1,86 +1,30 @@
import os
from avalon import api, lib, pipeline
import sys
from avalon import api, pipeline
class FusionRenderNode(api.Action):
name = "fusionrendernode9"
label = "F9 Render Node"
icon = "object-group"
order = 997
def is_compatible(self, session):
"""Return whether the action is compatible with the session"""
if "AVALON_PROJECT" in session:
return False
return True
def process(self, session, **kwargs):
"""Implement the behavior for when the action is triggered
Args:
session (dict): environment dictionary
Returns:
Popen instance of newly spawned process
"""
# Update environment with session
env = os.environ.copy()
env.update(session)
# Get executable by name
app = lib.get_application(self.name)
env.update(app["environment"])
executable = lib.which(app["executable"])
return lib.launch(executable=executable, args=[], environment=env)
class VrayRenderSlave(api.Action):
name = "vrayrenderslave"
label = "V-Ray Slave"
icon = "object-group"
order = 996
def is_compatible(self, session):
"""Return whether the action is compatible with the session"""
if "AVALON_PROJECT" in session:
return False
return True
def process(self, session, **kwargs):
"""Implement the behavior for when the action is triggered
Args:
session (dict): environment dictionary
Returns:
Popen instance of newly spawned process
"""
# Update environment with session
env = os.environ.copy()
env.update(session)
# Get executable by name
app = lib.get_application(self.name)
env.update(app["environment"])
executable = lib.which(app["executable"])
# Run as server
arguments = ["-server", "-portNumber=20207"]
return lib.launch(executable=executable,
args=arguments,
environment=env)
PACKAGE_DIR = os.path.dirname(__file__)
PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins", "launcher")
ACTIONS_DIR = os.path.join(PLUGINS_DIR, "actions")
def register_launcher_actions():
"""Register specific actions which should be accessible in the launcher"""
pipeline.register_plugin(api.Action, FusionRenderNode)
pipeline.register_plugin(api.Action, VrayRenderSlave)
actions = []
ext = ".py"
sys.path.append(ACTIONS_DIR)
for f in os.listdir(ACTIONS_DIR):
file, extention = os.path.splitext(f)
if ext in extention:
module = __import__(file)
klass = getattr(module, file)
actions.append(klass)
if actions is []:
return
for action in actions:
print("Using launcher action from config @ '{}'".format(action.name))
pipeline.register_plugin(api.Action, action)

View file

@ -0,0 +1,38 @@
import os
from avalon import api, lib
class FusionRenderNode(api.Action):
name = "fusionrendernode9"
label = "F9 Render Node"
icon = "object-group"
order = 997
def is_compatible(self, session):
"""Return whether the action is compatible with the session"""
if "AVALON_PROJECT" in session:
return False
return True
def process(self, session, **kwargs):
"""Implement the behavior for when the action is triggered
Args:
session (dict): environment dictionary
Returns:
Popen instance of newly spawned process
"""
# Update environment with session
env = os.environ.copy()
env.update(session)
# Get executable by name
app = lib.get_application(self.name)
env.update(app["environment"])
executable = lib.which(app["executable"])
return lib.launch(executable=executable, args=[], environment=env)

View file

@ -0,0 +1,44 @@
import os
from avalon import api, lib
class VrayRenderSlave(api.Action):
name = "vrayrenderslave"
label = "V-Ray Slave"
icon = "object-group"
order = 996
def is_compatible(self, session):
"""Return whether the action is compatible with the session"""
if "AVALON_PROJECT" in session:
return False
return True
def process(self, session, **kwargs):
"""Implement the behavior for when the action is triggered
Args:
session (dict): environment dictionary
Returns:
Popen instance of newly spawned process
"""
# Update environment with session
env = os.environ.copy()
env.update(session)
# Get executable by name
app = lib.get_application(self.name)
env.update(app["environment"])
executable = lib.which(app["executable"])
# Run as server
arguments = ["-server", "-portNumber=20207"]
return lib.launch(executable=executable,
args=arguments,
environment=env)