示例#1
0
文件: api.py 项目: chenqizhi1/tk-core
    def template_from_path(self, path):
        """
        Finds a template that matches the given path::

            >>> import sgtk
            >>> tk = sgtk.sgtk_from_path("/studio/project_root")
            >>> tk.template_from_path("/studio/my_proj/assets/Car/Anim/work")
            <Sgtk Template maya_asset_project: assets/%(Asset)s/%(Step)s/work>


        :param path: Path to match against a template
        :returns: :class:`TemplatePath` or None if no match could be found.
        """
        matched_templates = self.templates_from_path(path)

        if len(matched_templates) == 0:
            return None
        elif len(matched_templates) == 1:
            return matched_templates[0]
        else:
            # ambiguity!
            # We're erroring out anyway, take the time to create helpful debug info!
            matched_fields = []
            for template in matched_templates:
                matched_fields.append(template.get_fields(path))

            msg = "%d templates are matching the path '%s'.\n" % (
                len(matched_templates),
                path,
            )
            msg += "The overlapping templates are:\n"
            for fields, template in zip(matched_fields, matched_templates):
                msg += "%s\n%s\n" % (template, fields)
            raise TankMultipleMatchingTemplatesError(msg)
示例#2
0
    def get_fields(self, input_path, skip_keys=None):
        """
        Extracts key name, value pairs from a string. Example::

            >>> input_path = '/studio_root/sgtk/demo_project_1/sequences/seq_1/shot_2/comp/publish/henry.v003.ma'
            >>> template_path.get_fields(input_path)

            {'Sequence': 'seq_1',
             'Shot': 'shot_2',
             'Step': 'comp',
             'name': 'henry',
             'version': 3}

        :param input_path: Source path for values
        :type input_path: String
        :param skip_keys: Optional keys to skip
        :type skip_keys: List

        :returns: Values found in the path based on keys in template
        :rtype: Dictionary
        """
        path_parser = None
        fields = None

        for ordered_keys, static_tokens in zip(self._ordered_keys,
                                               self._static_tokens):
            path_parser = TemplatePathParser(ordered_keys, static_tokens)
            fields = path_parser.parse_path(input_path, skip_keys)
            if fields != None:
                break

        if fields is None:
            raise TankError("Template %s: %s" %
                            (str(self), path_parser.last_error))

        return fields
    def __init__(
        self,
        name,
        default=None,
        choices=None,
        shotgun_entity_type=None,
        shotgun_field_name=None,
        exclusions=None,
        abstract=False,
        length=None,
    ):
        """
        :param str name: Name by which the key will be referred.
        :param default: Default value for this key. If the default is a callable, it will be invoked
                        without any parameters whenever a default value is required.
        :param choices: List of possible values for this key. Can be either a list or a dictionary
                        of choice:label pairs.
        :param str shotgun_entity_type: For keys directly linked to a shotgun field, the entity type.
        :param str shotgun_field_name: For keys directly linked to a shotgun field, the field name.
        :param list exclusions: List of forbidden values.
        :param bool abstract: Flagging that this should be treated as an abstract key.
        :param int length: If non-None, indicating that the value should be of a fixed length.
        """
        self._name = name
        self._default = default

        # special handling for choices:
        if isinstance(choices, dict):
            # new style choices dictionary containing choice:label pairs:
            self._choices = choices
        elif isinstance(choices, list) or isinstance(choices, set):
            # old style choices - labels and choices are the same:
            self._choices = dict(list(zip(choices, choices)))
        else:
            self._choices = {}

        self._exclusions = exclusions or []
        self._shotgun_entity_type = shotgun_entity_type
        self._shotgun_field_name = shotgun_field_name
        self._is_abstract = abstract
        self._length = length
        self._last_error = ""

        # check that the key name doesn't contain invalid characters
        if not re.match(r"^%s$" % constants.TEMPLATE_KEY_NAME_REGEX, name):
            raise TankError("%s: Name contains invalid characters. "
                            "Valid characters are %s." %
                            (self, constants.VALID_TEMPLATE_KEY_NAME_DESC))

        # Validation
        if self.shotgun_field_name and not self.shotgun_entity_type:
            raise TankError(
                "%s: Shotgun field requires a shotgun entity be set." % self)

        if self.is_abstract and self.default is None:
            raise TankError(
                "%s: Fields marked as abstract needs to have a default value!"
                % self)

        if not ((self.default is None) or self.validate(self.default)):
            raise TankError(self._last_error)

        if not all(self.validate(choice) for choice in self.choices):
            raise TankError(self._last_error)
示例#4
0
    def _unregister_filesystem_location_ids(self, ids, log, prompt):
        """
        Performs the unregistration of a path from the path cache database.
        Will recursively unregister any child items parented to the given
        filesystem location id.

        :param ids: List of filesystem location ids to unregister
        :param log: Logging instance
        :param prompt: Should the user be presented with confirmation prompts?
        :returns: List of dictionaries to represents the items that were unregistered.
                  Each dictionary has keys path and entity, where entity is a standard
                  Shotgun-style link dictionary containing the keys type and id.
                  Note that the shotgun ids returned will refer to retired objects in
                  Shotgun rather than live ones.
        """
        # tuple index constants for readability

        if len(ids) == 0:
            log.info("No associated folders found!")
            return []

        # first of all, make sure we are up to date.
        pc = path_cache.PathCache(self.tk)
        try:
            pc.synchronize()
        finally:
            pc.close()

        # now use the path cache to get a list of all folders (recursively) that are
        # linked up to the folders registered for this entity.
        # store this in a set so that we ensure a unique set of matches

        paths = set()
        pc = path_cache.PathCache(self.tk)
        path_ids = []
        paths = []
        try:
            for sg_fs_id in ids:
                # get path subtree for this id via the path cache
                for path_obj in pc.get_folder_tree_from_sg_id(sg_fs_id):
                    # store in the set as a tuple which is immutable
                    paths.append(path_obj["path"])
                    path_ids.append(path_obj["sg_id"])
        finally:
            pc.close()

        log.info("")
        log.info("The following folders will be unregistered:")
        for p in paths:
            log.info(" - %s" % p)

        log.info("")
        log.info(
            "Proceeding will unregister the above paths from Toolkit's path cache. "
            "This will not alter any of the content in the file system, but once you have "
            "unregistered the paths, they will not be recognized by Shotgun until you run "
            "Toolkit folder creation again.")
        log.info("")
        log.info(
            "This is useful if you have renamed an Asset or Shot and want to move its "
            "files to a new location on disk. In this case, start by unregistering the "
            "folders for the entity, then rename the Shot or Asset in Shotgun. "
            "Next, create new folders on disk using Toolkit's 'create folders' "
            "command. Finally, move the files to the new location on disk.")
        log.info("")
        if prompt:
            val = input(
                "Proceed with unregistering the above folders? (Yes/No) ? [Yes]: "
            )
            if val != "" and not val.lower().startswith("y"):
                log.info("Exiting! Nothing was unregistered.")
                return []

        log.info("Unregistering folders from Shotgun...")
        log.info("")

        path_cache.PathCache.remove_filesystem_location_entries(
            self.tk, path_ids)

        # lastly, another sync
        pc = path_cache.PathCache(self.tk)
        try:
            pc.synchronize()
        finally:
            pc.close()

        log.info("")
        log.info("Unregister complete. %s paths were unregistered." %
                 len(paths))

        # now shuffle the return data into a list of dicts
        return_data = []
        for path_id, path in zip(path_ids, paths):
            return_data.append({
                "path": path,
                "entity": {
                    "type": path_cache.SHOTGUN_ENTITY,
                    "id": path_id
                },
            })

        return return_data