コード例 #1
0
    def get_publish_name(self, path, sequence=False):
        """
        Given a file path, return the display name to use for publishing.

        Typically, this is a name where the path and any version number are
        removed in order to keep the publish name consistent as subsequent
        versions are published.

        Example::

            # versioned file. remove the version
            in: /path/to/the/file/scene.v001.ma
            out: scene.ma

            # image sequence. replace the frame number with #s
            in: /path/to/the/file/my_file.001.jpg
            out: my_file.###.jpg

        :param path: The path to a file, likely one to be published.
        :param sequence: If True, treat the path as a sequence name and replace
            the frame number with placeholder

        :return: A publish display name for the provided path.
        """

        publisher = self.parent

        logger = publisher.logger
        logger.debug("Getting publish name for path: %s ..." % (path,))

        path_info = publisher.util.get_file_path_components(path)
        filename = path_info["filename"]

        version_pattern_match = re.search(VERSION_REGEX, filename)
        frame_pattern_match = re.search(FRAME_REGEX, filename)

        if version_pattern_match:
            # found a version number, use the other groups to remove it
            prefix = version_pattern_match.group(1)
            if len(version_pattern_match.groups()) == 5:
                extension = version_pattern_match.group(5)
            else:
                extension = version_pattern_match.group(4) or ""
            if extension:
                publish_name = "%s.%s" % (prefix, extension)
            else:
                publish_name = prefix
        elif frame_pattern_match and sequence:
            # found a frame number, meplace it with #s
            prefix = frame_pattern_match.group(1)
            frame_sep = frame_pattern_match.group(2)
            frame = frame_pattern_match.group(3)
            display_str = "#" * len(frame)
            extension = frame_pattern_match.group(4) or ""
            publish_name = "%s%s%s.%s" % (prefix, frame_sep, display_str, extension)
        else:
            publish_name = filename

        logger.debug("Returning publish name: %s" % (publish_name,))
        return publish_name
コード例 #2
0
    def get_version_number(self, path):
        """
        Extract a version number from the supplied path.

        This is used by plugins that need to know what version number to
        associate with the file when publishing.

        :param path: The path to a file, likely one to be published.

        :return: An integer representing the version number in the supplied
            path. If no version found, ``None`` will be returned.
        """

        publisher = self.parent

        logger = publisher.logger
        logger.debug("Getting version number for path: %s ..." % (path,))

        path_info = publisher.util.get_file_path_components(path)
        filename = path_info["filename"]

        # default if no version number detected
        version_number = None

        # if there's a version in the filename, extract it
        version_pattern_match = re.search(VERSION_REGEX, filename)

        if version_pattern_match:
            version_number = int(version_pattern_match.group("version"))

        logger.debug("Returning version number: %s" % (version_number,))
        return version_number
コード例 #3
0
    def get_publish_name(self, path, sequence=False):
        """
        Given a file path, return the display name to use for publishing.

        Typically, this is a name where the path and any version number are
        removed in order to keep the publish name consistent as subsequent
        versions are published.

        Example::

            # versioned file. remove the version
            in: /path/to/the/file/scene.v001.ma
            out: scene.ma

            # image sequence. replace the frame number with #s
            in: /path/to/the/file/my_file.001.jpg
            out: my_file.###.jpg

        :param path: The path to a file, likely one to be published.
        :param sequence: If True, treat the path as a sequence name and replace
            the frame number with placeholder

        :return: A publish display name for the provided path.
        """

        publisher = self.parent

        logger = publisher.logger
        logger.debug("Getting publish name for path: %s ..." % (path,))

        path_info = publisher.util.get_file_path_components(path)
        filename = path_info["filename"]

        match = re.search(VERSION_REGEX, filename)
        # frame_pattern_match = re.search(FRAME_REGEX, filename)

        if match:
            publish_name = publish_code = match.group("prefix")
            if match.group("version"):
                publish_code += match.group("ver_sep")
                publish_code += "v" + match.group("version")
            if match.group("rep"):
                publish_name += match.group("rep_sep")
                publish_name += match.group("rep")
                publish_code += match.group("rep_sep")
                publish_code += match.group("rep")
            if match.group("frame"):
                display_str = "#" * len(match.group("frame"))
                publish_name += match.group("frame_sep")
                publish_name += display_str
                publish_code += match.group("frame_sep")
                publish_code += display_str
            publish_name += "." + match.group("ext")
            publish_code += "." + match.group("ext")
        else:
            publish_name = filename
            publish_code = filename

        logger.debug("Returning publish name, publish code: {},{}".format(publish_name, publish_code))
        return publish_name, publish_code
コード例 #4
0
    def _definition_variations(self, definition):
        """
        Determines all possible definition based on combinations of optional sectionals.

        "{foo}"               ==> ['{foo}']
        "{foo}_{bar}"         ==> ['{foo}_{bar}']
        "{foo}[_{bar}]"       ==> ['{foo}', '{foo}_{bar}']
        "{foo}_[{bar}_{baz}]" ==> ['{foo}_', '{foo}_{bar}_{baz}']

        """
        # split definition by optional sections
        tokens = re.split(r"(\[[^]]*\])", definition)

        # seed with empty string
        definitions = [""]
        for token in tokens:
            temp_definitions = []
            # regex return some blank strings, skip them
            if token == "":
                continue
            if token.startswith("["):
                # check that optional contains a key
                if not re.search("{*%s}" % constants.TEMPLATE_KEY_NAME_REGEX,
                                 token):
                    raise TankError(
                        'Optional sections must include a key definition. Token: "%s" Template: %s'
                        % (token, self))

                # Add definitions skipping this optional value
                temp_definitions = definitions[:]
                # strip brackets from token
                token = re.sub(r"[\[\]]", "", token)

            # check non-optional contains no dangleing brackets
            if re.search(r"[\[\]]", token):
                raise TankError(
                    "Square brackets are not allowed outside of optional section definitions."
                )

            # make defintions with token appended
            for definition in definitions:
                temp_definitions.append(definition + token)

            definitions = temp_definitions

        return definitions
コード例 #5
0
    def get_next_version_path(self, path):
        """
        Given a file path, return a path to the next version.

        This is typically used by auto-versioning logic in plugins that need to
        save the current work file to the next version number.

        If no version can be identified in the supplied path, ``None`` will be
        returned, indicating that the next version path can't be determined.

        :param path: The path to a file, likely one to be published.

        :return: The path to the next version of the supplied path.
        """

        publisher = self.parent

        logger = publisher.logger
        logger.debug("Getting next version of path: %s ..." % (path, ))

        # default
        next_version_path = None

        path_info = publisher.util.get_file_path_components(path)
        filename = path_info["filename"]

        # see if there's a version in the supplied path
        version_pattern_match = re.search(VERSION_REGEX, filename)

        if version_pattern_match:
            prefix = version_pattern_match.group(1)
            version_sep = version_pattern_match.group(2)
            version_str = version_pattern_match.group(3)
            extension = version_pattern_match.group(4) or ""

            # make sure we maintain the same padding
            padding = len(version_str)

            # bump the version number
            next_version_number = int(version_str) + 1

            # create a new version string filled with the appropriate 0 padding
            next_version_str = "v%s" % (
                str(next_version_number).zfill(padding))

            new_filename = "%s%s%s" % (prefix, version_sep, next_version_str)
            if extension:
                new_filename = "%s.%s" % (new_filename, extension)

            # build the new path in the same folder
            next_version_path = os.path.join(path_info["folder"], new_filename)

        logger.debug("Returning next version path: %s" % (next_version_path, ))
        return next_version_path
コード例 #6
0
ファイル: test_sgre.py プロジェクト: mdfisher/tk-core
    def test_unicode_override(self):
        """
        Ensure that the unicode flag overrides the flag insertion behavior.
        """
        char = u"a漢字"
        expr = r"a\w+"

        # test all wrapped methods
        self.assertTrue(bool(sgre.compile(expr, flags=re.U).match(char)))
        self.assertEqual(len(sgre.findall(expr, char, flags=re.U)), 1)
        self.assertTrue(bool(sgre.match(expr, char, flags=re.U)))
        self.assertTrue(bool(sgre.search(expr, char, flags=re.U)))
        self.assertEqual(len(sgre.split(expr, "$ %s @" % char, flags=re.U)), 2)
        self.assertEqual(sgre.sub(expr, "@", char, flags=re.U), "@")
コード例 #7
0
ファイル: test_sgre.py プロジェクト: mdfisher/tk-core
    def test_wrap(self):
        r"""
        Ensure that sgre injects the re.ASCII flag appropriately, and that
        unicode characters do not match `\w` in Python 2 or 3.
        """
        char = u"漢字"
        expr = r"\w+"

        # test all wrapped methods
        self.assertFalse(bool(sgre.compile(expr).match(char)))
        self.assertEqual(len(sgre.findall(expr, char)), 0)
        self.assertFalse(bool(sgre.match(expr, char)))
        self.assertFalse(bool(sgre.search(expr, char)))
        self.assertEqual(len(sgre.split(expr, "$ %s @" % char)), 1)
        self.assertEqual(sgre.sub(expr, "@", char), char)
コード例 #8
0
ファイル: test_sgre.py プロジェクト: mdfisher/tk-core
    def test_wrap_kwarg(self):
        r"""
        Ensure that sgre injects the re.ASCII flag appropriately when flags are
        also passed as keyword arguments, and that unicode characters do not
        match `\w` in Python 2 or 3.
        """
        char = u"a漢字"
        expr = r"a\w+"

        # test all wrapped methods
        self.assertFalse(bool(sgre.compile(expr, flags=re.I).match(char)))
        self.assertEqual(len(sgre.findall(expr, char, flags=re.I)), 0)
        self.assertFalse(bool(sgre.match(expr, char, flags=re.I)))
        self.assertFalse(bool(sgre.search(expr, char, flags=re.I)))
        self.assertEqual(len(sgre.split(expr, "$ %s @" % char, flags=re.I)), 1)
        self.assertEqual(sgre.sub(expr, "@", char, flags=re.I), char)
コード例 #9
0
ファイル: build_plugin.py プロジェクト: chenqizhi1/tk-core
def _validate_manifest(source_path):
    """
    Validate that the manifest file is present and valid.

    :param source_path: Source path to plugin
    :return: parsed yaml content of manifest file
    """
    # check for source manifest file
    manifest_path = os.path.join(source_path, "info.yml")
    if not os.path.exists(manifest_path):
        raise TankError("Cannot find plugin manifest '%s'" % manifest_path)

    logger.debug("Reading %s" % manifest_path)
    try:
        with open(manifest_path, "rt") as fh:
            manifest_data = yaml.load(fh)
    except Exception as e:
        raise TankError("Cannot parse info.yml manifest: %s" % e)

    logger.debug("Validating manifest...")

    # legacy check - if we find entry_point, convert it across
    # to be plugin_id
    if "entry_point" in manifest_data:
        logger.warning(
            "Found legacy entry_point syntax. Please upgrade to use plugin_id instead."
        )
        manifest_data["plugin_id"] = manifest_data["entry_point"]

    for parameter in REQUIRED_MANIFEST_PARAMETERS:
        if parameter not in manifest_data:
            raise TankError(
                "Required plugin manifest parameter '%s' missing in '%s'" %
                (parameter, manifest_path))

    # plugin_id needs to be alpha numeric + period
    if re.search(r"^[a-zA-Z0-9_\.]+$", manifest_data["plugin_id"]) is None:
        raise TankError(
            "Plugin id can only contain alphanumerics, period and underscore characters."
        )

    return manifest_data
コード例 #10
0
    def get_frame_sequence_path(self, path, frame_spec=None):
        """
        Given a path with a frame number, return the sequence path where the
        frame number is replaced with a given frame specification such as
        ``{FRAME}`` or ``%04d`` or ``$F``.

        :param path: The input path with a frame number
        :param frame_spec: The frame specification to replace the frame number
            with.

        :return: The full frame sequence path
        """

        publisher = self.parent
        path_info = publisher.util.get_file_path_components(path)

        # see if there is a frame number
        frame_pattern_match = re.search(VERSION_REGEX, path_info["filename"])

        if not frame_pattern_match or not frame_pattern_match.group("frame"):
            # no frame number detected. carry on.
            return None

        prefix = frame_pattern_match.group("pre_frame")
        frame_sep = frame_pattern_match.group("frame_sep")
        frame_str = frame_pattern_match.group("frame")
        extension = frame_pattern_match.group("ext") or ""

        # make sure we maintain the same padding
        if not frame_spec:
            padding = len(frame_str)
            frame_spec = "%%0%dd" % (padding,)

        seq_filename = "%s%s%s" % (prefix, frame_sep, frame_spec)

        if extension:
            seq_filename = "%s.%s" % (seq_filename, extension)

        # build the full sequence path
        return os.path.join(path_info["folder"], seq_filename)
コード例 #11
0
    def get_version_path(self, path, version):
        """
        Given a path without a version number, return the path with the supplied
        version number.

        If a version number is detected in the supplied path, the path will be
        returned as-is.

        :param path: The path to inject a version number.
        :param version: The version number to inject.

        :return: The modified path with the supplied version number inserted.
        """

        publisher = self.parent

        logger = publisher.logger
        logger.debug("Getting version %s of path: %s ..." % (version, path))

        path_info = publisher.util.get_file_path_components(path)
        filename = path_info["filename"]

        # see if there's a version in the supplied path
        version_pattern_match = re.search(VERSION_REGEX, filename)

        if version_pattern_match and version_pattern_match.group("version"):
            # version number already in the path. return the original path
            return path

        (basename, ext) = os.path.splitext(filename)

        # construct the new filename with the version number inserted
        version_filename = "%s.%s%s" % (basename, version, ext)

        # construct the new, full path
        version_path = os.path.join(path_info["folder"], version_filename)

        logger.debug("Returning version path: %s" % (version_path,))
        return version_path
コード例 #12
0
    def get_frame_sequences(self, folder, extensions=None, frame_spec=None):
        """
        Given a folder, inspect the contained files to find what appear to be
        files with frame numbers.

        :param folder: The path to a folder potentially containing a sequence of
            files.

        :param extensions: A list of file extensions to retrieve paths for.
            If not supplied, the extension will be ignored.

        :param frame_spec: A string to use to represent the frame number in the
            return sequence path.

        :return: A list of tuples for each identified frame sequence. The first
            item in the tuple is a sequence path with the frame number replaced
            with the supplied frame specification. If no frame spec is supplied,
            a python string format spec will be returned with the padding found
            in the file.


            Example::

            get_frame_sequences(
                "/path/to/the/folder",
                ["exr", "jpg"],
                frame_spec="{FRAME}"
            )

            [
                (
                    "/path/to/the/supplied/folder/key_light1.{FRAME}.exr",
                    [<frame_1_path>, <frame_2_path>, ...]
                ),
                (
                    "/path/to/the/supplied/folder/fill_light1.{FRAME}.jpg",
                    [<frame_1_path>, <frame_2_path>, ...]
                )
            ]
        """

        publisher = self.parent
        logger = publisher.logger

        logger.debug("Looking for sequences in folder: '%s'..." % (folder,))

        # list of already processed file names
        processed_names = {}

        # examine the files in the folder
        for filename in os.listdir(folder):
            file_path = os.path.join(folder, filename)

            if os.path.isdir(file_path):
                # ignore subfolders
                continue

            # see if there is a frame number
            frame_pattern_match = re.search(VERSION_REGEX, filename)

            if not frame_pattern_match:
                # no frame number detected. carry on.
                continue

            prefix = frame_pattern_match.group("prefix")
            frame_sep = frame_pattern_match.group("frame_sep")
            frame_str = frame_pattern_match.group("frame")
            extension = frame_pattern_match.group("ext") or ""

            # filename without a frame number.
            file_no_frame = "%s.%s" % (prefix, extension)

            if file_no_frame in processed_names:
                # already processed this sequence. add the file to the list
                processed_names[file_no_frame]["file_list"].append(file_path)
                continue

            if extensions and extension not in extensions:
                # not one of the extensions supplied
                continue

            # make sure we maintain the same padding
            if not frame_spec:
                padding = len(frame_str)
                frame_spec = "%%0%dd" % (padding,)

            seq_filename = "%s%s%s" % (prefix, frame_sep, frame_spec)

            if extension:
                seq_filename = "%s.%s" % (seq_filename, extension)

            # build the path in the same folder
            seq_path = os.path.join(folder, seq_filename)

            # remember each seq path identified and a list of files matching the
            # seq pattern
            processed_names[file_no_frame] = {
                "sequence_path": seq_path,
                "file_list": [file_path],
            }

        # build the final list of sequence paths to return
        frame_sequences = []
        for file_no_frame in processed_names:

            seq_info = processed_names[file_no_frame]
            seq_path = seq_info["sequence_path"]

            logger.debug("Found sequence: %s" % (seq_path,))
            frame_sequences.append((seq_path, seq_info["file_list"]))

        return frame_sequences