def test_login_to_login_authentication(self): """ Ensure the configuration will always pick the user passed in when there is no script user in the project configuration. """ default_user = self._create_session_user("default_user") configuration = Configuration(None, None) # Create a default user. with patch( "tank.authentication.ShotgunAuthenticator.get_default_user", return_value=default_user ): current_user = self._create_session_user("current_user") configuration._set_authenticated_user( current_user, current_user.login, sgtk.authentication.serialize_user(current_user) ) # we should be using the same login... self.assertEqual(sgtk.get_authenticated_user().login, current_user.login) # ... but we shouldn't be using the name ShotgunUser instance. It should # have been serialized and deserialized. self.assertNotEqual(id(sgtk.get_authenticated_user()), id(current_user))
def test_fail_reinstantiating(self): """ Ensure the configuration will recover if the user can't be serialized/unserialized. """ configuration = Configuration(None, None) default_user = self._create_session_user("default_user") # Create a default user. with patch( "tank.authentication.ShotgunAuthenticator.get_default_user", return_value=default_user ): # Python 2.6 doesn't support multi-expression with statement, so nest the calls instead. with patch( "tank_vendor.shotgun_authentication.deserialize_user", wraps=tank_vendor.shotgun_authentication.deserialize_user ) as deserialize_wrapper: current_user = self._create_session_user("current_user") configuration._set_authenticated_user(current_user, current_user.login, "invalid") deserialize_wrapper.assert_called_once_with("invalid") # Because we couldn't unserialize, we should just get the same login... self.assertEqual(sgtk.get_authenticated_user().login, current_user.login) # ... and the original ShotgunUser back. self.assertEqual(id(sgtk.get_authenticated_user()), id(current_user))
def test_script_to_noscript_authentication(self): """ Ensure that bootstrapping with a script into a project without a script user in its configuration will pick the bootstrap user. """ configuration = Configuration(None, None) user_for_bootstrap = self._create_script_user("api_script_for_bootstrap") user_for_project = self._create_session_user("project_user") # Create a default user. with patch( "tank.authentication.ShotgunAuthenticator.get_default_user", return_value=user_for_project ): configuration._set_authenticated_user( user_for_bootstrap, user_for_bootstrap.login, sgtk.authentication.serialize_user(user_for_bootstrap) ) # we should be using the same login... auth_user = sgtk.get_authenticated_user() self.assertIsNone(auth_user.login) self.assertEqual(auth_user.login, user_for_bootstrap.login) self.assertEqual(auth_user.impl.get_script(), user_for_bootstrap.impl.get_script()) # ... but we shouldn't be using the name ShotgunUser instance. It should # have been serialized and deserialized. self.assertNotEqual(id(auth_user), id(user_for_bootstrap))
def test_login_based_authentication(self): """ Ensure the configuration will always pick the user passed in when there is no script user. """ configuration = Configuration(None, None) self._mock_default_user.login = "******" user = MagicMock(login="******") configuration._set_authenticated_user(user) self.assertEqual(sgtk.get_authenticated_user(), user)
def get_cache_path(identifier_dict): """ Create a file name given a dictionary of identifiers, e.g. ``{shot: 123, project: 345}`` etc. A hash value will be computed based on the identifier and used to determine the path. The current user will be added to the hash in order to make it user-centric. If the hash key 'prefix' is detected, this will be added to the path as a parent folder to the cache file. This provides a simple way to organize different caches into different folders. :param dict identifier_dict: Dictionary of identifying data. :retuns: path on disk, relative to the current bundle's cache location. """ params_hash = hashlib.md5() for (k, v) in identifier_dict.iteritems(): params_hash.update(str(k)) params_hash.update(str(v)) # add current user to hash user = sgtk.get_authenticated_user() if user and user.login: params_hash.update(user.login) cache_location = sgtk.platform.current_bundle().cache_location if FOLDER_PREFIX_KEY in identifier_dict: # if FOLDER_PREFIX_KEY is found in the hash, # this will be added as a folder to the path data_cache_path = os.path.join( cache_location, "external_cfg", identifier_dict[FOLDER_PREFIX_KEY], "%s.pkl" % params_hash.hexdigest() ) else: data_cache_path = os.path.join( cache_location, "external_cfg", "%s.pkl" % params_hash.hexdigest() ) logger.debug( "Resolved cache path for %s to %s" % (identifier_dict, data_cache_path) ) return data_cache_path
def test_endpoint_url_swap(self): """ Make sure that if the endpoint changes after the bootstrap that we're using the new endpoint. """ configuration = Configuration(None, None) bootstrap_user = self._create_session_user("default_user") project_user = self._create_session_user("default_user", "https://test-2.shotgunstudio.com") with patch( "tank.authentication.ShotgunAuthenticator.get_default_user", return_value=project_user ): configuration._set_authenticated_user( bootstrap_user, bootstrap_user.login, sgtk.authentication.serialize_user(bootstrap_user) ) self.assertEqual(sgtk.get_authenticated_user().host, "https://test-2.shotgunstudio.com")
def test_script_to_script_authentication(self): """ Ensure a project configuration overrides a script user used for bootstrapping. """ configuration = Configuration(None, None) script_user_for_bootstrap = self._create_script_user("api_script_for_bootstrap") script_user_for_project = self._create_script_user("api_script_for_project") # Create a default user. with patch( "tank.authentication.ShotgunAuthenticator.get_default_user", return_value=script_user_for_project ): configuration._set_authenticated_user( script_user_for_bootstrap, script_user_for_bootstrap.login, sgtk.authentication.serialize_user(script_user_for_bootstrap) ) # The ShotgunUser instance from get_authenticated_user was retrieved # through get_default_user, so we simply need to compare the object ids. self.assertEqual(id(sgtk.get_authenticated_user()), id(script_user_for_project))
def test_endpoint_url_swap(self): """ Make sure that if the endpoint changes after the bootstrap that we're using the new endpoint. """ configuration = Configuration(None, None) bootstrap_user = self._create_session_user("default_user") project_user = self._create_session_user( "default_user", "https://test-2.shotgunstudio.com" ) with patch( "tank.authentication.ShotgunAuthenticator.get_default_user", return_value=project_user, ): configuration._set_authenticated_user( bootstrap_user, bootstrap_user.login, sgtk.authentication.serialize_user(bootstrap_user), ) self.assertEqual( sgtk.get_authenticated_user().host, "https://test-2.shotgunstudio.com" )
def test_script_to_script_authentication(self): """ Ensure a project configuration overrides a script user used for bootstrapping. """ configuration = Configuration(None, None) script_user_for_bootstrap = self._create_script_user("api_script_for_bootstrap") script_user_for_project = self._create_script_user("api_script_for_project") # Create a default user. with patch( "tank.authentication.ShotgunAuthenticator.get_default_user", return_value=script_user_for_project ): configuration._set_authenticated_user( script_user_for_bootstrap, script_user_for_bootstrap.login, sgtk.authentication.serialize_user(script_user_for_bootstrap) ) # The ShotgunUser instance from get_authenticated_user was retrieved # through get_default_user, so we simply need to compare the object ids. self.assertEqual(id(sgtk.get_authenticated_user()), id(script_user_for_project))
def test_login_to_script_authentication(self): """ Ensure the configuration will always pick the script user when project configuration has one. """ configuration = Configuration(None, None) script_user = self._create_script_user("api_script") # Create a default user. with patch( "tank.authentication.ShotgunAuthenticator.get_default_user", return_value=script_user ): current_user = self._create_session_user("current_user") configuration._set_authenticated_user( current_user, current_user.login, sgtk.authentication.serialize_user(current_user) ) # The ShotgunUser instance from get_authenticated_user was retrieved # through get_default_user, so we simply need to compare the object ids. self.assertEqual(id(sgtk.get_authenticated_user()), id(script_user))
def setUp(self, parameters=None): """ Sets up a Shotgun Mockgun instance with a project and a basic project scaffold on disk. :param parameters: Dictionary with additional parameters to control the setup. The method currently supports the following parameters: - 'project_tank_name': 'name' - Set the tank_name of the project to something explicit. If not specified, this will default to 'project_code' - 'mockgun_schema_path': '/path/to/file' - Pass a specific schema to use with mockgun. If not specified, the tk-core fixture schema will be used. - 'mockgun_schema_entity_path': '/path/to/file' - Pass a specific entity schema to use with mockgun. If not specified, the tk-core fixture schema will be used. - 'primary_root_name': 'name' - Set the primary root name, default to 'unit_tests'. """ self.addCleanup(self._assert_teardown_called) # Override SHOTGUN_HOME so that unit tests can be sandboxed. self._old_shotgun_home = os.environ.get(self.SHOTGUN_HOME) os.environ[self.SHOTGUN_HOME] = TANK_TEMP # Make sure the global settings instance has been reset so anything from a previous test doesn't # leak into the next one. UserSettings.clear_singleton() parameters = parameters or {} self._do_io = parameters.get("do_io", True) if "project_tank_name" in parameters: project_tank_name = parameters["project_tank_name"] else: # default project name project_tank_name = "project_code" # now figure out mockgun location # 1. see if we have it explicitly specified in the parameters # 2. if not, check if the fixtures location has a mockgun folder # 3. if not, fall back on built in mockgun fixtures if "mockgun_schema_path" in parameters: mockgun_schema_path = parameters["mockgun_schema_path"] elif os.path.exists(os.path.join(self.fixtures_root, "mockgun")): mockgun_schema_path = os.path.join( self.fixtures_root, "mockgun", "schema.pickle" ) else: # use the std core fixtures mockgun_schema_path = os.path.join( self.tank_source_path, "tests", "fixtures", "mockgun", "schema.pickle" ) if "mockgun_schema_entity_path" in parameters: mockgun_schema_entity_path = parameters["mockgun_schema_entity_path"] elif os.path.exists(os.path.join(self.fixtures_root, "mockgun")): mockgun_schema_entity_path = os.path.join( self.fixtures_root, "mockgun", "schema_entity.pickle" ) else: # use the std core fixtures mockgun_schema_entity_path = os.path.join( self.tank_source_path, "tests", "fixtures", "mockgun", "schema_entity.pickle" ) # The name to use for our primary storage self.primary_root_name = parameters.get("primary_root_name", "unit_tests") # set up mockgun to use our schema mockgun.Shotgun.set_schema_paths(mockgun_schema_path, mockgun_schema_entity_path) self.tank_temp = TANK_TEMP self.cache_root = os.path.join(self.tank_temp, "cache_root") # Mock this so that authentication manager works even tough we are not in a config. # If we don't mock it than the path cache calling get_current_user will fail. self._mock_return_value( "tank.util.shotgun.connection.get_associated_sg_config_data", {"host": "https://somewhere.shotgunstudio.com"} ) # define entity for test project self.project = { "type": "Project", "id": 1, "tank_name": project_tank_name, "name": "project_name", "archived": False, } self.project_root = os.path.join(self.tank_temp, self.project["tank_name"].replace("/", os.path.sep)) self.pipeline_config_root = os.path.join(self.tank_temp, "pipeline_configuration") if self._do_io: # move away previous data self._move_project_data() # create new structure os.makedirs(self.project_root) os.makedirs(self.pipeline_config_root) # # copy tank util scripts shutil.copy( os.path.join(self.tank_source_path, "setup", "root_binaries", "tank"), os.path.join(self.pipeline_config_root, "tank") ) shutil.copy( os.path.join(self.tank_source_path, "setup", "root_binaries", "tank.bat"), os.path.join(self.pipeline_config_root, "tank.bat") ) # project level config directories self.project_config = os.path.join(self.pipeline_config_root, "config") # create project cache directory project_cache_dir = os.path.join(self.pipeline_config_root, "cache") if self._do_io: os.mkdir(project_cache_dir) # define entity for pipeline configuration self.sg_pc_entity = {"type": "PipelineConfiguration", "code": "Primary", "id": 123, "project": self.project, "windows_path": self.pipeline_config_root, "mac_path": self.pipeline_config_root, "linux_path": self.pipeline_config_root} # add files needed by the pipeline config pc_yml = os.path.join(self.pipeline_config_root, "config", "core", "pipeline_configuration.yml") pc_yml_data = ("{ project_name: %s, use_shotgun_path_cache: true, pc_id: %d, " "project_id: %d, pc_name: %s}\n\n" % (self.project["tank_name"], self.sg_pc_entity["id"], self.project["id"], self.sg_pc_entity["code"])) if self._do_io: self.create_file(pc_yml, pc_yml_data) loc_yml = os.path.join(self.pipeline_config_root, "config", "core", "install_location.yml") loc_yml_data = "Windows: '%s'\nDarwin: '%s'\nLinux: '%s'" % ( self.pipeline_config_root, self.pipeline_config_root, self.pipeline_config_root ) if self._do_io: self.create_file(loc_yml, loc_yml_data) # inject this file which toolkit is probing for to determine # if an installation has been localized. localize_token_file = os.path.join(self.pipeline_config_root, "install", "core", "_core_upgrader.py") if self._do_io: self.create_file(localize_token_file, "foo bar") roots = {self.primary_root_name: {}} for os_name in ["windows_path", "linux_path", "mac_path"]: # TODO make os specific roots roots[self.primary_root_name][os_name] = self.tank_temp if self._do_io: roots_path = os.path.join(self.pipeline_config_root, "config", "core", "roots.yml") roots_file = open(roots_path, "w") roots_file.write(yaml.dump(roots)) roots_file.close() # clear bundle in-memory cache sgtk.descriptor.io_descriptor.factory.g_cached_instances = {} if self._do_io: self.pipeline_configuration = sgtk.pipelineconfig_factory.from_path(self.pipeline_config_root) self.tk = tank.Tank(self.pipeline_configuration) # set up mockgun and make sure shotgun connection calls route via mockgun self.mockgun = mockgun.Shotgun("http://unit_test_mock_sg", "mock_user", "mock_key") # fake a version response from the server self.mockgun.server_info = {"version": (7, 0, 0)} self._mock_return_value("tank.util.shotgun.connection.get_associated_sg_base_url", "http://unit_test_mock_sg") self._mock_return_value("tank.util.shotgun.connection.create_sg_connection", self.mockgun) self._mock_return_value("tank.util.shotgun.get_associated_sg_base_url", "http://unit_test_mock_sg") self._mock_return_value("tank.util.shotgun.create_sg_connection", self.mockgun) # add project to mock sg and path cache db if self._do_io: self.add_production_path(self.project_root, self.project) # add pipeline configuration self.add_to_sg_mock_db(self.project) self.add_to_sg_mock_db(self.sg_pc_entity) # add local storage self.primary_storage = {"type": "LocalStorage", "id": 7777, "code": self.primary_root_name, "windows_path": self.tank_temp, "linux_path": self.tank_temp, "mac_path": self.tank_temp} self.add_to_sg_mock_db(self.primary_storage) # back up the authenticated user in case a unit test doesn't clean up correctly. self._authenticated_user = sgtk.get_authenticated_user()
def _return_repo_path(self, project_name): """ Use Shotgun (Toolkit and Database) to get data and return the correct code repo root path for the Project that Toolkit launched. @return str repo_path: The root of the path based on information gleaned from Shotgun. """ repo_path = None LOGGER.debug(MY_SEP) shotgun_inst = sgtk.api.shotgun.connection.get_sg_connection() sg_filters = [['project.Project.name', 'is', project_name]] sg_fields = [ 'id', 'code', 'project', 'sg_ss_tools_repo', 'sg_ss_tools_repo_custom_path', 'windows_path' ] sgtk_configs = shotgun_inst.find('PipelineConfiguration', sg_filters, sg_fields) wanted_repo_key = None sg_auth = sgtk.get_authenticated_user() sgtk_core_user = sg_auth.login sgtk_module_path = sgtk.get_sgtk_module_path() if '\\' in sgtk_module_path: sgtk_module_path = sgtk_module_path.replace('\\', '/') sgtk_cfg_path = '/'.join(sgtk_module_path.split('/')[:5]) LOGGER.debug('sgtk_module_path >> {}'.format(sgtk_module_path)) LOGGER.debug('sgtk_cfg_path >> {}'.format(sgtk_cfg_path)) for my_config in sgtk_configs: my_config_repo_key = my_config['sg_ss_tools_repo'] my_config_repo_custom = my_config['sg_ss_tools_repo_custom_path'] my_config_path = my_config['windows_path'] if '\\' in my_config_path: my_config_path = my_config_path.replace('\\', '/') if my_config_path == sgtk_cfg_path: wanted_repo_key = my_config_repo_key m = 'wanted_repo_key >> {}'.format(wanted_repo_key) LOGGER.debug(m) break if wanted_repo_key: if wanted_repo_key == 'custom': # --- For developers to point to *any* pipeline code repository # --- as specified in the called Shotgun configuration... repo_path = my_config_repo_custom if '\\' in repo_path: repo_path = repo_path.replace('\\', '/') if repo_path.endswith('/'): repo_path = repo_path.strip('/') if not os.path.exists(repo_path): m = 'Custom path does not exist! >> {}'.format(repo_path) raise tank.TankError(m) elif wanted_repo_key == 'dev': # --- For developers to do individual tesing against clones of # --- same-named repositories within their X:/dev location... repo_path = 'X:/dev/ss_dev_{0}/{1}_repo'.format( sgtk_core_user, project_name) # --- If it's not a Project-specific repo, we have to resort # --- to the generic studio repo... if not os.path.exists(repo_path): repo_path = 'X:/dev/ss_dev_{0}/ss_studio_repo'.format( sgtk_core_user, project_name) elif wanted_repo_key == 'project': # --- For everyone to launch using a Project-specific repo... repo_path = 'X:/tools/projects/{0}/{0}_repo'.format( project_name) else: # --- For everyone to launch using the generic studio repo... repo_path = 'X:/tools/ss_studio_repo' LOGGER.debug(MY_SEP) # --- Check to make sure the resolved path, whatever it is, still # --- exists at the given location... # if not os.path.exists(repo_path): # m = 'Resolved path does not exist! >> {}'.format(repo_path) # raise tank.TankError(m) return repo_path
def setUp(self, parameters=None): """ Sets up a Shotgun Mockgun instance with a project and a basic project scaffold on disk. :param parameters: Dictionary with additional parameters to control the setup. The method currently supports the following parameters: - 'project_tank_name': 'name' - Set the tank_name of the project to something explicit. If not specified, this will default to 'project_code' - 'mockgun_schema_path': '/path/to/file' - Pass a specific schema to use with mockgun. If not specified, the tk-core fixture schema will be used. - 'mockgun_schema_entity_path': '/path/to/file' - Pass a specific entity schema to use with mockgun. If not specified, the tk-core fixture schema will be used. """ parameters = parameters or {} if "project_tank_name" in parameters: project_tank_name = parameters["project_tank_name"] else: # default project name project_tank_name = "project_code" if "mockgun_schema_path" in parameters: mockgun_schema_path = parameters["mockgun_schema_path"] else: mockgun_schema_path = os.path.join(self.fixtures_root, "mockgun", "schema.pickle") if "mockgun_schema_entity_path" in parameters: mockgun_schema_entity_path = parameters["mockgun_schema_entity_path"] else: mockgun_schema_entity_path = os.path.join(self.fixtures_root, "mockgun", "schema_entity.pickle") # set up mockgun to use our schema mockgun.Shotgun.set_schema_paths(mockgun_schema_path, mockgun_schema_entity_path) self.tank_temp = TANK_TEMP self.init_cache_location = os.path.join(self.tank_temp, "init_cache.cache") self.cache_root = os.path.join(self.tank_temp, "cache_root") patch = mock.patch("tank.pipelineconfig_factory._get_cache_location", return_value=self.init_cache_location) patch.start() self.addCleanup(patch.stop) # Mock this so that authentication manager works even tough we are not in a config. # If we don't mock it than the path cache calling get_current_user will fail. patch = mock.patch( "tank.util.shotgun.get_associated_sg_config_data", return_value={"host": "https://somewhere.shotguntudio.com"} ) patch.start() self.addCleanup(patch.stop) # define entity for test project self.project = {"type": "Project", "id": 1, "tank_name": project_tank_name, "name": "project_name"} self.project_root = os.path.join(self.tank_temp, self.project["tank_name"].replace("/", os.path.sep) ) self.pipeline_config_root = os.path.join(self.tank_temp, "pipeline_configuration") # move away previous data self._move_project_data() # create new structure os.makedirs(self.project_root) os.makedirs(self.pipeline_config_root) # project level config directories self.project_config = os.path.join(self.pipeline_config_root, "config") # create project cache directory project_cache_dir = os.path.join(self.pipeline_config_root, "cache") os.mkdir(project_cache_dir) # define entity for pipeline configuration self.sg_pc_entity = {"type": "PipelineConfiguration", "code": "Primary", "id": 123, "project": self.project, "windows_path": self.pipeline_config_root, "mac_path": self.pipeline_config_root, "linux_path": self.pipeline_config_root} # add files needed by the pipeline config pc_yml = os.path.join(self.pipeline_config_root, "config", "core", "pipeline_configuration.yml") pc_yml_data = ("{ project_name: %s, use_shotgun_path_cache: true, pc_id: %d, " "project_id: %d, pc_name: %s}\n\n" % (self.project["tank_name"], self.sg_pc_entity["id"], self.project["id"], self.sg_pc_entity["code"])) self.create_file(pc_yml, pc_yml_data) loc_yml = os.path.join(self.pipeline_config_root, "config", "core", "install_location.yml") loc_yml_data = "Windows: '%s'\nDarwin: '%s'\nLinux: '%s'" % (self.pipeline_config_root, self.pipeline_config_root, self.pipeline_config_root) self.create_file(loc_yml, loc_yml_data) roots = {"primary": {}} for os_name in ["windows_path", "linux_path", "mac_path"]: #TODO make os specific roots roots["primary"][os_name] = self.tank_temp roots_path = os.path.join(self.pipeline_config_root, "config", "core", "roots.yml") roots_file = open(roots_path, "w") roots_file.write(yaml.dump(roots)) roots_file.close() self.pipeline_configuration = sgtk.pipelineconfig_factory.from_path(self.pipeline_config_root) self.tk = tank.Tank(self.pipeline_configuration) # set up mockgun and make sure shotgun connection calls route via mockgun self.mockgun = mockgun.Shotgun("http://unit_test_mock_sg", "mock_user", "mock_key") # fake a version response from the server self.mockgun.server_info = {"version": (7, 0, 0)} patch = mock.patch("tank.util.shotgun.get_associated_sg_base_url", return_value="http://unit_test_mock_sg") patch.start() self.addCleanup(patch.stop) patch = mock.patch("tank.util.shotgun.create_sg_connection", return_value=self.mockgun) patch.start() self.addCleanup(patch.stop) # add project to mock sg and path cache db self.add_production_path(self.project_root, self.project) # add pipeline configuration self.add_to_sg_mock_db(self.sg_pc_entity) # add local storage self.primary_storage = {"type": "LocalStorage", "id": 7777, "code": "primary", "windows_path": self.tank_temp, "linux_path": self.tank_temp, "mac_path": self.tank_temp } self.add_to_sg_mock_db(self.primary_storage) # back up the authenticated user in case a unit test doesn't clean up correctly. self._authenticated_user = sgtk.get_authenticated_user()
def _return_repo_paths(self, project_name): """Use Shotgun (Toolkit and Database) to get data and return the correct code repo root paths for the Project that Toolkit launched. Args: project_name (str): The Project's full name in Shotgun. Returns: list: The roots of the repo paths based on information gleaned from Shotgun. """ repo_paths = [] sg_auth = sgtk.get_authenticated_user() sgtk_core_user = sg_auth.login spr_path = self.return_spr_path() spr_split = os.path.basename(spr_path).split('_') v_maj = spr_split[2] v_min = spr_split[3] # --- Get the Project short name... proj_short_name = self.return_proj_short_name(project_name) # --- Get the SG configs... sgtk_configs = self.return_sgtk_configs(project_name) wanted_repo_key, my_config_repo_custom = self.return_wanted_repo_key( sgtk_configs) # --- First check ('custom')... if wanted_repo_key == 'custom': if my_config_repo_custom: if os.path.exists(my_config_repo_custom): repo_path = my_config_repo_custom.replace('\\', '/') repo_path = repo_path.strip('/') if os.path.exists(repo_path): repo_paths.append(repo_path) # --- Second check ('dev')... if wanted_repo_key == 'dev': # --- For developers to do individual tesing against clones of # --- same-named repositories within their X:/dev location... repo_path = 'X:/dev/ss_dev_{}'.format(sgtk_core_user) repo_path += '/{0}_pipeline_{1}_{2}_dev_master_repo'.format( proj_short_name, v_maj, v_min) # --- If it's not a Project-specific repo, we have to resort # --- to the generic studio repo dev clone... if not os.path.exists(repo_path): spr_base = os.path.basename(spr_path) repo_path = 'X:/dev/ss_dev_{0}/{1}'.format( sgtk_core_user, spr_base) if os.path.exists(repo_path): repo_paths.append(repo_path) # --- Third check ('project')... if wanted_repo_key == 'project': repo_path = 'X:/tools/projects/{}'.format(project_name) repo_path += '/{0}_pipeline_{1}_{2}_repo'.format( proj_short_name, v_maj, v_min) if os.path.exists(repo_path): repo_paths.append(repo_path) # --- Always include the studio repo as the last repo path in the # --- list, and return the first entry from the list (the same if # --- there's only one entry in the list)... repo_paths.append(spr_path) return repo_paths
def _run_external_process(self, cache_path, entity_type, entity_id, engine_name, pre_cache=False): """ Helper method. Executes the external caching process. :param int cache_path: Path to cache file to write :param str entity_type: Associated entity type :param int entity_id: Associated entity id :param str engine_name: Engine to start :param bool pre_cache: Whether to pre-cache all bundles during bootstrap :raises: SubprocessCalledProcessError """ # launch external process to carry out caching. script = os.path.abspath( os.path.join(os.path.dirname(__file__), "..", "scripts", "external_runner.py")) # We might have paths in sys.path that aren't in PYTHONPATH. We'll make # sure that we prepend our current pathing to that prior to spawning any # subprocesses. current_pypath = os.environ.get("PYTHONPATH") args_file = create_parameter_file( dict( action="cache_actions", cache_path=cache_path, configuration_uri=self.descriptor_uri, pipeline_config_id=self.pipeline_configuration_id, plugin_id=self.plugin_id, engine_name=engine_name, entity_type=entity_type, entity_id=entity_id, bundle_cache_fallback_paths=self._bundle.engine.sgtk. bundle_cache_fallback_paths, # the engine icon becomes the process icon icon_path=self._bundle.engine.icon_256, pre_cache=pre_cache, pythonpath=current_pypath, )) args = [ self.interpreter, script, sgtk.bootstrap.ToolkitManager.get_core_python_path(), args_file ] logger.debug("Launching external script: %s", args) # Ensure the credentials are still valid before launching the command in # a separate process. We need do to this in advance because the process # that will be launched might not have PySide and as such won't be able # to prompt the user to re-authenticate. sgtk.get_authenticated_user().refresh_credentials() for path in sys.path: sgtk.util.prepend_path_to_env_var("PYTHONPATH", path) try: # Note: passing a copy of the environment in resolves some odd behavior with # the environment of processes spawned from the external_runner. This caused # some very bad behavior where it looked like PYTHONPATH was inherited from # this top-level environment rather than what is being set in external_runner # prior to launch. This is less critical here when caching configs, because # we're unlikely to spawn additional processes from the external_runner, but # just to cover our backsides, this is safest. output = subprocess_check_output(args, env=os.environ.copy()) logger.debug("External caching complete. Output: %s" % output) finally: # Leave PYTHONPATH the way we found it. if current_pypath is None: del os.environ["PYTHONPATH"] else: os.environ["PYTHONPATH"] = current_pypath # clean up temp file sgtk.util.filesystem.safe_delete_file(args_file)
def _return_repo_path(self, project_name): """ Use Shotgun (Toolkit and Database) to get data and return the correct code repo root path for the Project that Toolkit launched. @return str repo_path: The root of the path based on information gleaned from Shotgun. """ repo_path = None logger.debug(my_sep) shotgun_inst = sgtk.api.shotgun.connection.get_sg_connection() sg_filters = [['project.Project.name', 'is', project_name]] sg_fields = [ 'id', 'code', 'project', 'sg_ss_tools_repo', 'windows_path' ] sgtk_configs = shotgun_inst.find('PipelineConfiguration', sg_filters, sg_fields) wanted_repo_key = None sg_auth = sgtk.get_authenticated_user() sgtk_core_user = sg_auth.login sgtk_module_path = sgtk.get_sgtk_module_path() if '\\' in sgtk_module_path: sgtk_module_path = sgtk_module_path.replace('\\', '/') sgtk_cfg_path = '/'.join(sgtk_module_path.split('/')[:5]) logger.debug('sgtk_module_path >> {}'.format(sgtk_module_path)) logger.debug('sgtk_cfg_path >> {}'.format(sgtk_cfg_path)) for my_config in sgtk_configs: my_config_repo_key = my_config['sg_ss_tools_repo'] my_config_path = my_config['windows_path'] if '\\' in my_config_path: my_config_path = my_config_path.replace('\\', '/') if my_config_path == sgtk_cfg_path: wanted_repo_key = my_config_repo_key logger.debug( 'wanted_repo_key >> {}'.format(wanted_repo_key)) break if wanted_repo_key: if wanted_repo_key == 'dev': repo_path = 'X:/dev/ss_dev_{0}/{1}_repo'.format( sgtk_core_user, project_name) # --- If it's not a Project-specific repo, we have to resort to # --- the generic studio repo... if not os.path.exists(repo_path): repo_path = 'X:/dev/ss_dev_{0}/ss_studio_repo'.format( sgtk_core_user, project_name) elif wanted_repo_key == 'project': repo_path = 'X:/tools/projects/{0}/{0}_repo'.format( project_name) else: repo_path = 'X:/tools/ss_studio_repo' logger.debug(my_sep) return repo_path
def setUp(self, parameters=None): """ Sets up a Shotgun Mockgun instance with a project and a basic project scaffold on disk. :param parameters: Dictionary with additional parameters to control the setup. The method currently supports the following parameters: - 'project_tank_name': 'name' - Set the tank_name of the project to something explicit. If not specified, this will default to 'project_code' - 'mockgun_schema_path': '/path/to/file' - Pass a specific schema to use with mockgun. If not specified, the tk-core fixture schema will be used. - 'mockgun_schema_entity_path': '/path/to/file' - Pass a specific entity schema to use with mockgun. If not specified, the tk-core fixture schema will be used. """ # Override SHOTGUN_HOME so that unit tests can be sandboxed. self._old_shotgun_home = os.environ.get(self.SHOTGUN_HOME) os.environ[self.SHOTGUN_HOME] = TANK_TEMP # Make sure the global settings instance has been reset so anything from a previous test doesn't # leak into the next one. UserSettings.clear_singleton() parameters = parameters or {} if "project_tank_name" in parameters: project_tank_name = parameters["project_tank_name"] else: # default project name project_tank_name = "project_code" # now figure out mockgun location # 1. see if we have it explicitly specified in the parameters # 2. if not, check if the fixtures location has a mockgun folder # 3. if not, fall back on built in mockgun fixtures if "mockgun_schema_path" in parameters: mockgun_schema_path = parameters["mockgun_schema_path"] elif os.path.exists(os.path.join(self.fixtures_root, "mockgun")): mockgun_schema_path = os.path.join( self.fixtures_root, "mockgun", "schema.pickle" ) else: # use the std core fixtures mockgun_schema_path = os.path.join( self.tank_source_path, "tests", "fixtures", "mockgun", "schema.pickle" ) if "mockgun_schema_entity_path" in parameters: mockgun_schema_entity_path = parameters["mockgun_schema_entity_path"] elif os.path.exists(os.path.join(self.fixtures_root, "mockgun")): mockgun_schema_entity_path = os.path.join( self.fixtures_root, "mockgun", "schema_entity.pickle" ) else: # use the std core fixtures mockgun_schema_entity_path = os.path.join( self.tank_source_path, "tests", "fixtures", "mockgun", "schema_entity.pickle" ) # set up mockgun to use our schema mockgun.Shotgun.set_schema_paths(mockgun_schema_path, mockgun_schema_entity_path) self.tank_temp = TANK_TEMP self.cache_root = os.path.join(self.tank_temp, "cache_root") # Mock this so that authentication manager works even tough we are not in a config. # If we don't mock it than the path cache calling get_current_user will fail. self._mock_return_value( "tank.util.shotgun.get_associated_sg_config_data", {"host": "https://somewhere.shotguntudio.com"} ) # define entity for test project self.project = {"type": "Project", "id": 1, "tank_name": project_tank_name, "name": "project_name"} self.project_root = os.path.join(self.tank_temp, self.project["tank_name"].replace("/", os.path.sep) ) self.pipeline_config_root = os.path.join(self.tank_temp, "pipeline_configuration") # move away previous data self._move_project_data() # create new structure os.makedirs(self.project_root) os.makedirs(self.pipeline_config_root) # project level config directories self.project_config = os.path.join(self.pipeline_config_root, "config") # create project cache directory project_cache_dir = os.path.join(self.pipeline_config_root, "cache") os.mkdir(project_cache_dir) # define entity for pipeline configuration self.sg_pc_entity = {"type": "PipelineConfiguration", "code": "Primary", "id": 123, "project": self.project, "windows_path": self.pipeline_config_root, "mac_path": self.pipeline_config_root, "linux_path": self.pipeline_config_root} # add files needed by the pipeline config pc_yml = os.path.join(self.pipeline_config_root, "config", "core", "pipeline_configuration.yml") pc_yml_data = ("{ project_name: %s, use_shotgun_path_cache: true, pc_id: %d, " "project_id: %d, pc_name: %s}\n\n" % (self.project["tank_name"], self.sg_pc_entity["id"], self.project["id"], self.sg_pc_entity["code"])) self.create_file(pc_yml, pc_yml_data) loc_yml = os.path.join(self.pipeline_config_root, "config", "core", "install_location.yml") loc_yml_data = "Windows: '%s'\nDarwin: '%s'\nLinux: '%s'" % (self.pipeline_config_root, self.pipeline_config_root, self.pipeline_config_root) self.create_file(loc_yml, loc_yml_data) # inject this file which toolkit is probing for to determine # if an installation has been localized. localize_token_file = os.path.join(self.pipeline_config_root, "install", "core", "_core_upgrader.py") self.create_file(localize_token_file, "foo bar") roots = {"primary": {}} for os_name in ["windows_path", "linux_path", "mac_path"]: #TODO make os specific roots roots["primary"][os_name] = self.tank_temp roots_path = os.path.join(self.pipeline_config_root, "config", "core", "roots.yml") roots_file = open(roots_path, "w") roots_file.write(yaml.dump(roots)) roots_file.close() # clear bundle in-memory cache sgtk.descriptor.io_descriptor.factory.g_cached_instances = {} self.pipeline_configuration = sgtk.pipelineconfig_factory.from_path(self.pipeline_config_root) self.tk = tank.Tank(self.pipeline_configuration) # set up mockgun and make sure shotgun connection calls route via mockgun self.mockgun = mockgun.Shotgun("http://unit_test_mock_sg", "mock_user", "mock_key") # fake a version response from the server self.mockgun.server_info = {"version": (7, 0, 0)} self._mock_return_value("tank.util.shotgun.get_associated_sg_base_url", "http://unit_test_mock_sg") self._mock_return_value("tank.util.shotgun.create_sg_connection", self.mockgun) # add project to mock sg and path cache db self.add_production_path(self.project_root, self.project) # add pipeline configuration self.add_to_sg_mock_db(self.sg_pc_entity) # add local storage self.primary_storage = {"type": "LocalStorage", "id": 7777, "code": "primary", "windows_path": self.tank_temp, "linux_path": self.tank_temp, "mac_path": self.tank_temp } self.add_to_sg_mock_db(self.primary_storage) # back up the authenticated user in case a unit test doesn't clean up correctly. self._authenticated_user = sgtk.get_authenticated_user()
#!python2 # -*- coding:utf-8 -*- #coding=gbk import sgtk import os, sys, threading import busyDialog import time, pprint import Queue import ctypes, inspect from sgtk.platform.pyqt import QtCore, QtGui, QtWidgets logger = sgtk.platform.get_logger(__name__) sg = sgtk.get_authenticated_user().create_sg_connection() def show_dialog(app_instance): app_instance.engine.show_dialog("Batch Publisher...", app_instance, BatchPublisherUI) def _async_raise(tid, exctype): tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1:
def _setUp(self, parameters): """ See documentation for setUp. """ self.addCleanup(self._assert_teardown_called) # Override SHOTGUN_HOME so that unit tests can be sandboxed. self._old_shotgun_home = os.environ.get(self.SHOTGUN_HOME) os.environ[self.SHOTGUN_HOME] = TANK_TEMP # Make sure the global settings instance has been reset so anything from a previous test doesn't # leak into the next one. UserSettings.clear_singleton() parameters = parameters or {} self._do_io = parameters.get("do_io", True) # now figure out mockgun location # 1. see if we have it explicitly specified in the parameters # 2. if not, check if the fixtures location has a mockgun folder # 3. if not, fall back on built in mockgun fixtures if "mockgun_schema_path" in parameters: mockgun_schema_path = parameters["mockgun_schema_path"] elif os.path.exists(os.path.join(self.fixtures_root, "mockgun")): mockgun_schema_path = os.path.join(self.fixtures_root, "mockgun", "schema.pickle") else: # use the std core fixtures mockgun_schema_path = os.path.join(self.tank_source_path, "tests", "fixtures", "mockgun", "schema.pickle") if "mockgun_schema_entity_path" in parameters: mockgun_schema_entity_path = parameters[ "mockgun_schema_entity_path"] elif os.path.exists(os.path.join(self.fixtures_root, "mockgun")): mockgun_schema_entity_path = os.path.join(self.fixtures_root, "mockgun", "schema_entity.pickle") else: # use the std core fixtures mockgun_schema_entity_path = os.path.join( self.tank_source_path, "tests", "fixtures", "mockgun", "schema_entity.pickle", ) # set up mockgun to use our schema mockgun.Shotgun.set_schema_paths(mockgun_schema_path, mockgun_schema_entity_path) # Mock this so that authentication manager works even tough we are not in a config. # If we don't mock it than the path cache calling get_current_user will fail. self._mock_return_value( "tank.util.shotgun.connection.get_associated_sg_config_data", {"host": "https://somewhere.shotgunstudio.com"}, ) # set up mockgun and make sure shotgun connection calls route via mockgun self.mockgun = mockgun.Shotgun("http://unit_test_mock_sg", "mock_user", "mock_key") # fake a version response from the server self.mockgun.server_info = {"version": (7, 0, 0)} self._mock_return_value( "tank.util.shotgun.connection.get_associated_sg_base_url", "http://unit_test_mock_sg", ) self._mock_return_value( "tank.util.shotgun.connection.create_sg_connection", self.mockgun) self._mock_return_value("tank.util.shotgun.get_associated_sg_base_url", "http://unit_test_mock_sg") self._mock_return_value("tank.util.shotgun.create_sg_connection", self.mockgun) # now, set up a project, pipeline configuration and storage root for testing # The name to use for our primary storage self.primary_root_name = parameters.get("primary_root_name", "unit_tests") self.tank_temp = TANK_TEMP self.cache_root = os.path.join(self.tank_temp, "cache_root") # Initialize storage roots self.roots = {self.primary_root_name: {}} for os_name in ["windows_path", "linux_path", "mac_path"]: # TODO make os specific roots self.roots[self.primary_root_name][os_name] = self.tank_temp # initialize list of projects for testing. if "project_tank_name" in parameters: project_tank_name = parameters["project_tank_name"] else: # default project name project_tank_name = "project_code" self.project, self.project_root = self.create_project( {"tank_name": project_tank_name}) ( self.sg_pc_entity, self.pipeline_configuration, self.pipeline_config_root, self.project_config, self.tk, ) = self.create_pipeline_configuration(self.project, {"code": "Primary"}) if self._do_io: # add the project root to the production path (once self.tk is initialized) self.add_production_path(self.project_root, self.project) # add local storage self.primary_storage = { "type": "LocalStorage", "id": 7777, "code": self.primary_root_name, "windows_path": self.tank_temp, "linux_path": self.tank_temp, "mac_path": self.tank_temp, } self.add_to_sg_mock_db(self.primary_storage) # back up the authenticated user in case a unit test doesn't clean up correctly. self._authenticated_user = sgtk.get_authenticated_user() sgtk.util.login.g_shotgun_current_user_cache = "unknown" sgtk.util.login.g_shotgun_user_cache = "unknown"