def create_sg_connection(user="******"): """ Creates a standard tank shotgun connection. Note! This method returns *a brand new sg API instance*. It is slow. Always consider using tk.shotgun and if you don't have a tk instance, consider using get_sg_connection(). Whenever a Shotgun API instance is created, it pings the server to check that it is running the right versions etc. This is slow and inefficient and means that there will be a delay every time create_sg_connection is called. :param user: Optional shotgun config user to use when connecting to shotgun, as defined in shotgun.yml. This is a deprecated flag and should not be used. :returns: SG API instance """ # Avoids cyclic imports. from ... import api sg_user = api.get_authenticated_user() # If there is no user, that's probably because we're running in an old script that doesn't use # the authenticated user concept. In that case, we'll do what we've always been doing in the # past, which is read shotgun.yml and expect there to be a script user. if sg_user is None: log.debug( "This tk session has no associated authenticated user. Falling back to " "creating a shotgun API instance based on script based credentials in the " "shotgun.yml configuration file.") # try to find the shotgun.yml path try: config_file_path = __get_sg_config() except TankError, e: log.error( "Trying to create a shotgun connection but this tk session does not have " "an associated authenticated user. Therefore attempted to fall back on " "a legacy authentication method where script based credentials are " "located in a file relative to the location of the core API code. This " "lookup in turn failed. No credentials can be determined and no connection " "to Shotgun can be made. Details: %s" % e) raise TankError( "Cannot connect to Shotgun - this tk session does not have " "an associated user and attempts to determine a valid shotgun " "via legacy configuration files failed. Details: %s" % e) log.debug("Creating shotgun connection based on details in %s" % config_file_path) config_data = __get_sg_config_data_with_script_user( config_file_path, user) # Credentials were passed in, so let's run the legacy authentication # mechanism for script user. api_handle = shotgun_api3.Shotgun( config_data["host"], script_name=config_data["api_script"], api_key=config_data["api_key"], http_proxy=config_data.get("http_proxy"), connect=False)
def __create_sg_connection(config_data=None, user=None): """ Creates a standard Toolkit shotgun connection. :param config_data: Configuration data dictionary. Keys host, api_script and api_key are expected, while http_proxy is optional. If None, the user parameter will be used to determine which credentials to use. :param user: Shotgun user from the shotgun_authentication module to use to create the connection. Won't be used if config_data is set. Can be None. :raises TankError: Raised if both config_data and user are None. :returns: A Shotgun connection. """ if config_data: # Credentials were passed in, so let's run the legacy authentication # mechanism for script user. sg = shotgun_api3.Shotgun(config_data["host"], script_name=config_data["api_script"], api_key=config_data["api_key"], http_proxy=config_data.get("http_proxy")) elif user: sg = user.create_sg_connection() else: raise TankError("No Shotgun user available.") # bolt on our custom user agent manager sg.tk_user_agent_handler = ToolkitUserAgentHandler(sg) return sg
def _get_site_infos(url, http_proxy=None): """ Get and cache the desired site infos. We want this method to fail as quickly as possible if there are any issues. Failure is not considered critical, thus known exceptions are silently ignored. At the moment this method is only used to make the GUI show/hide some of the input fields. :param url: Url of the site to query. :param http_proxy: HTTP proxy to use, if any. :returns: A dictionary with the site infos. """ infos = {} try: # Temporary shotgun instance, used only for the purpose of checking # the site infos. # # The constructor of Shotgun requires either a username/login or # key/scriptname pair or a session_token. The token is only used in # calls which need to be authenticated. The 'info' call does not # require authentication. http_proxy = _sanitize_http_proxy(http_proxy).netloc if http_proxy: get_logger().debug( "Using HTTP proxy to connect to the Shotgun server: %s", http_proxy) # Checks if the information is in the cache, is missing or out of date. if url not in INFOS_CACHE or ( (time.time() - INFOS_CACHE[url][0]) > INFOS_CACHE_TIMEOUT): get_logger().info("Infos for site '%s' not in cache or expired", url) sg = shotgun_api3.Shotgun(url, session_token="dummy", connect=False, http_proxy=http_proxy) # Remove delay between attempts at getting the site info. Since # this is called in situations where blocking during multiple # attempts can make UIs less responsive, we'll avoid sleeping. # This change was introduced after delayed retries were added in # python-api v3.0.41 sg.config.rpc_attempt_interval = 0 infos = sg.info() INFOS_CACHE[url] = (time.time(), infos) else: get_logger().info("Infos for site '%s' found in cache", url) infos = INFOS_CACHE[url][1] # pylint: disable=broad-except except Exception as exc: # Silently ignore exceptions get_logger().debug("Unable to connect with %s, got exception '%s'", url, exc) return infos
def _get_site_infos(url, http_proxy=None): """ Get and cache the desired site infos. We want this method to fail as quickly as possible if there are any issues. Failure is not considered critical, thus known exceptions are silently ignored. At the moment this method is only used to make the GUI show/hide some of the input fields. :param url: Url of the site to query. :param http_proxy: HTTP proxy to use, if any. :returns: A dictionary with the site infos. """ infos = {} try: # Temporary shotgun instance, used only for the purpose of checking # the site infos. # # The constructor of Shotgun requires either a username/login or # key/scriptname pair or a session_token. The token is only used in # calls which need to be authenticated. The 'info' call does not # require authentication. http_proxy = _sanitize_http_proxy(http_proxy).netloc if http_proxy: get_logger().debug( "Using HTTP proxy to connect to the Shotgun server: %s", http_proxy ) # Checks if the information is in the cache, is missing or out of date. if url not in INFOS_CACHE or ((time.time() - INFOS_CACHE[url][0]) > INFOS_CACHE_TIMEOUT): get_logger().info("Infos for site '%s' not in cache or expired", url) infos = shotgun_api3.Shotgun( url, session_token="dummy", connect=False, http_proxy=http_proxy ).info() INFOS_CACHE[url] = (time.time(), infos) else: get_logger().info("Infos for site '%s' found in cache", url) infos = INFOS_CACHE[url][1] except Exception as e: # Silently ignore exceptions get_logger().debug("Unable to connect with %s, got exception '%s'", url, e) return infos
def __create_sg_connection(config_data=None, user=None): """ Creates a standard Toolkit shotgun connection. :param config_data: Configuration data dictionary. Keys host, api_script and api_key are expected, while http_proxy is optional. If None, the user parameter will be used to determine which credentials to use. :param user: Shotgun user from the shotgun_authentication module to use to create the connection. Won't be used if config_data is set. Can be None. :raises TankError: Raised if both config_data and user are None. :returns: A Shotgun connection. """ if config_data: # Credentials were passed in, so let's run the legacy authentication # mechanism for script user. sg = shotgun_api3.Shotgun(config_data["host"], script_name=config_data["api_script"], api_key=config_data["api_key"], http_proxy=config_data.get("http_proxy"), connect=config_data.get("connect", True)) if "timeout_secs" in config_data: sg.config.timeout_secs = config_data.get("timeout_secs") # The timeout can't be set until after the sg instance is created (when it has already # stored the timeout setting in the connection). We have to force it to re-spawn # the connection with the new timeout settings. It will create a new conneciton # automatically the next time it's called. There shouldn't be a connection yet, but # if there is, let's close it just in case. sg.close() elif user: sg = user.create_sg_connection() else: raise TankError("No Shotgun user available.") # bolt on our custom user agent manager sg.tk_user_agent_handler = ToolkitUserAgentHandler(sg) return sg
# not expressly granted therein are reserved by Shotgun Software Inc. import sgtk import os import sys import threading # # by importing QT from sgtk rather than directly, we ensure that # the code will be compatible with both PySide and PyQt. from sgtk.platform.qt import QtCore, QtGui from .ui.dialog import Ui_Dialog from tank_vendor import shotgun_api3 sg = shotgun_api3.Shotgun("https://legend.shotgunstudio.com", script_name="toolkit", api_key="d0211b3fecd9b4f0141545e7fd07965a5331eee13842700f1b6477ecffba5977") import logging from os import walk import csv from pprint import PrettyPrinter logger = sgtk.platform.get_logger(__name__) import random import string import tempfile def show_dialog(app_instance): """ Shows the main dialog window. """
def __create_sg_app_store_connection(self): """ Creates a shotgun connection that can be used to access the Toolkit app store. :returns: (sg, dict) where the first item is the shotgun api instance and the second is an sg entity dictionary (keys type/id) corresponding to to the user used to connect to the app store. """ # maintain a cache for performance # cache is keyed by client shotgun site # this assumes that there is a strict # 1:1 relationship between app store accounts # and shotgun sites. sg_url = self._sg_connection.base_url if sg_url not in self._app_store_connections: # Connect to associated Shotgun site and retrieve the credentials to use to # connect to the app store site try: (script_name, script_key) = self.__get_app_store_key_from_shotgun() except urllib2.HTTPError, e: if e.code == 403: # edge case alert! # this is likely because our session token in shotgun has expired. # The authentication system is based around wrapping the shotgun API, # and requesting authentication if needed. Because the app store # credentials is a separate endpoint and doesn't go via the shotgun # API, we have to explicitly check. # # trigger a refresh of our session token by issuing a shotgun API call self._sg_connection.find_one("HumanUser", []) # and retry (script_name, script_key) = self.__get_app_store_key_from_shotgun() else: raise log.debug("Connecting to %s..." % constants.SGTK_APP_STORE) # Connect to the app store and resolve the script user id we are connecting with. # Set the timeout explicitly so we ensure the connection won't hang in cases where # a response is not returned in a reasonable amount of time. app_store_sg = shotgun_api3.Shotgun( constants.SGTK_APP_STORE, script_name=script_name, api_key=script_key, http_proxy=self.__get_app_store_proxy_setting(), connect=False) # set the default timeout for app store connections app_store_sg.config.timeout_secs = constants.SGTK_APP_STORE_CONN_TIMEOUT # determine the script user running currently # get the API script user ID from shotgun try: script_user = app_store_sg.find_one( "ApiUser", filters=[["firstname", "is", script_name]], fields=["type", "id"]) except shotgun_api3.AuthenticationFault: raise InvalidAppStoreCredentialsError( "The Toolkit App Store credentials found in Shotgun are invalid.\n" "Please contact %s to resolve this issue." % SUPPORT_EMAIL) # Connection errors can occur for a variety of reasons. For example, there is no # internet access or there is a proxy server blocking access to the Toolkit app store. except (httplib2.HttpLib2Error, httplib2.socks.HTTPError, httplib.HTTPException), e: raise TankAppStoreConnectionError(e)
def __create_sg_app_store_connection(self): """ Creates a shotgun connection that can be used to access the Toolkit app store. :returns: (sg, dict) where the first item is the shotgun api instance and the second is an sg entity dictionary (keys type/id) corresponding to to the user used to connect to the app store. """ # maintain a cache for performance # cache is keyed by client shotgun site # this assumes that there is a strict # 1:1 relationship between app store accounts # and shotgun sites. if os.environ.get(constants.DISABLE_APPSTORE_ACCESS_ENV_VAR, "0") == "1": message = ( "The '%s' environment variable is active, preventing connection to app store." % constants.DISABLE_APPSTORE_ACCESS_ENV_VAR ) log.debug(message) raise TankAppStoreConnectionError(message) sg_url = self._sg_connection.base_url if sg_url not in self._app_store_connections: # Connect to associated Shotgun site and retrieve the credentials to use to # connect to the app store site try: (script_name, script_key) = self.__get_app_store_key_from_shotgun() except urllib.error.HTTPError as e: if e.code == 403: # edge case alert! # this is likely because our session token in shotgun has expired. # The authentication system is based around wrapping the shotgun API, # and requesting authentication if needed. Because the app store # credentials is a separate endpoint and doesn't go via the shotgun # API, we have to explicitly check. # # trigger a refresh of our session token by issuing a shotgun API call self._sg_connection.find_one("HumanUser", []) # and retry (script_name, script_key) = self.__get_app_store_key_from_shotgun() else: raise app_store = os.environ.get("SGTK_APP_STORE", constants.SGTK_APP_STORE) log.debug("Connecting to %s..." % app_store) # Connect to the app store and resolve the script user id we are connecting with. # Set the timeout explicitly so we ensure the connection won't hang in cases where # a response is not returned in a reasonable amount of time. app_store_sg = shotgun_api3.Shotgun( app_store, script_name=script_name, api_key=script_key, http_proxy=self.__get_app_store_proxy_setting(), connect=False, ) # set the default timeout for app store connections app_store_sg.config.timeout_secs = constants.SGTK_APP_STORE_CONN_TIMEOUT # determine the script user running currently # get the API script user ID from shotgun try: script_user = app_store_sg.find_one( "ApiUser", filters=[["firstname", "is", script_name]], fields=["type", "id"], ) except shotgun_api3.AuthenticationFault: raise InvalidAppStoreCredentialsError( "The Toolkit App Store credentials found in Shotgun are invalid.\n" "Please contact support at %s to resolve this issue." % SUPPORT_URL ) # Connection errors can occur for a variety of reasons. For example, there is no # internet access or there is a proxy server blocking access to the Toolkit app store. except ( httplib2.HttpLib2Error, httplib2.socks.HTTPError, http_client.HTTPException, ) as e: raise TankAppStoreConnectionError(e) # In cases where there is a firewall/proxy blocking access to the app store, sometimes # the firewall will drop the connection instead of rejecting it. The API request will # timeout which unfortunately results in a generic SSLError with only the message text # to give us a clue why the request failed. # The exception raised in this case is "ssl.SSLError: The read operation timed out" except httplib2.ssl.SSLError as e: if "timed" in e.message: raise TankAppStoreConnectionError( "Connection to %s timed out: %s" % (app_store_sg.config.server, e) ) else: # other type of ssl error raise TankAppStoreError(e) except Exception as e: raise TankAppStoreError(e) if script_user is None: raise TankAppStoreError( "Could not evaluate the current App Store User! Please contact support." ) self._app_store_connections[sg_url] = (app_store_sg, script_user) return self._app_store_connections[sg_url]