Example #1
0
 def _fix_key_names(self, definition, keys):
     """
     Substitutes key name for name used in definition
     """
     # Substitute key names for original key input names(key aliasing)
     substitutions = [(key_name, key.name)
                      for key_name, key in keys.items()
                      if key_name != key.name]
     for old_name, new_name in substitutions:
         old_def = r"{%s}" % old_name
         new_def = r"{%s}" % new_name
         definition = re.sub(old_def, new_def, definition)
     return definition
Example #2
0
    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), "@")
Example #3
0
    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)
Example #4
0
    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)
Example #5
0
    def init_app(self):
        """
        Called as the application is being initialized
        """

        tk_multi_publish2 = self.import_module("tk_multi_publish2")

        # the manager class provides the interface for publishing. We store a
        # reference to it to enable the create_publish_manager method exposed on
        # the application itself
        self._manager_class = tk_multi_publish2.PublishManager

        # make the util methods available via the app instance
        self._util = tk_multi_publish2.util

        # make the base plugins available via the app
        self._base_hooks = tk_multi_publish2.base_hooks

        display_name = self.get_setting("display_name")
        # "Publish Render" ---> publish_render
        command_name = display_name.lower()
        # replace all non alphanumeric characters by '_'
        command_name = re.sub(r"[^0-9a-zA-Z]+", "_", command_name)

        self.modal = self.get_setting("modal")

        pre_publish_hook_path = self.get_setting(
            self.CONFIG_PRE_PUBLISH_HOOK_PATH)
        self.pre_publish_hook = self.create_hook_instance(
            pre_publish_hook_path)

        # register command
        cb = lambda: tk_multi_publish2.show_dialog(self)
        menu_caption = "%s..." % display_name
        menu_options = {
            "short_name": command_name,
            "description": "Publishing of data to Shotgun",
            # dark themed icon for engines that recognize this format
            "icons": {
                "dark": {
                    "png": os.path.join(self.disk_location,
                                        "icon_256_dark.png")
                }
            },
        }
        self.engine.register_command(menu_caption, cb, menu_options)
Example #6
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
Example #7
0
def _get_published_file_path(published_file):
    """
    Return the path on disk for the given published file.
    """

    if published_file is None:
        return None

    path = published_file.get("path", None)
    if path is None:
        return ""

    # Return the local path right away, if we have it
    if path.get("local_path", None) is not None:
        return path["local_path"]

    # This published file came from a zero config publish, it will
    # have a file URL rather than a local path.
    path_on_disk = path.get("url", None)
    if path_on_disk is not None:
        # We might have something like a %20, which needs to be
        # unquoted into a space, as an example.
        if "%" in path_on_disk:
            path_on_disk = urllib.parse.unquote(path_on_disk)

        # If this came from a file url via a zero-config style publish
        # then we'll need to remove that from the head in order to end
        # up with the local disk path to the file.
        #
        # On Windows, we will have a path like file:///E:/path/to/file.jpg
        # and we need to ditch all three of the slashes at the head. On
        # other operating systems it will just be file:///path/to/file.jpg
        # and we will want to keep the leading slash.
        if util.is_windows():
            pattern = r"^file:///"
        else:
            pattern = r"^file://"

        path_on_disk = re.sub(pattern, "", path_on_disk)

    return path_on_disk
Example #8
0
def _bake_manifest(manifest_data, config_uri, core_descriptor, plugin_root):
    """
    Bake the info.yml manifest into a python file.

    :param manifest_data: info.yml manifest data
    :param config_uri: Configuration descriptor uri string to use at runtime
    :param core_descriptor: descriptor object pointing at core to use for bootstrap
    :param plugin_root: Root path for plugin
    """
    # suffix our generated python module with plugin id for uniqueness
    # replace all non-alphanumeric chars with underscores.
    module_name = "sgtk_plugin_%s" % re.sub(r"\W", "_",
                                            manifest_data["plugin_id"])
    full_module_path = os.path.join(plugin_root, "python", module_name)
    filesystem.ensure_folder_exists(full_module_path)

    # write __init__.py
    try:
        with open(os.path.join(full_module_path, "__init__.py"), "wt") as fh:
            fh.write("# this file was auto generated.\n")
            fh.write("from . import manifest\n")
            fh.write("# end of file.\n")
    except Exception as e:
        raise TankError("Cannot write __init__.py file: %s" % e)

    # now bake out the manifest into code
    params_path = os.path.join(full_module_path, "manifest.py")

    try:

        with open(params_path, "wt") as fh:

            fh.write("# this file was auto generated.\n\n\n")

            fh.write('base_configuration="%s"\n' % config_uri)

            for (parameter, value) in manifest_data.items():

                if parameter == "base_configuration":
                    continue

                if isinstance(value, str):
                    fh.write('%s="%s"\n' %
                             (parameter, value.replace('"', "'")))
                elif isinstance(value, int):
                    fh.write("%s=%d\n" % (parameter, value))
                elif isinstance(value, bool):
                    fh.write("%s=%s\n" % (parameter, value))
                else:
                    raise ValueError(
                        "Invalid manifest value %s: %s - data type not supported!"
                        % (parameter, value))

            fh.write("\n\n# system generated parameters\n")
            fh.write('BUILD_DATE="%s"\n' %
                     datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
            fh.write("BUILD_GENERATION=%d\n" % BUILD_GENERATION)

            # Write out helper function 'get_sgtk_pythonpath()'.
            # this makes it easy for a plugin to import sgtk
            if not core_descriptor:
                # If we don't have core_descriptor, the plugin will use the
                # system installed tk-core. Arguably in that case we don't need
                # this method, but let's keep things consistent.
                fh.write("\n\n")
                fh.write("def get_sgtk_pythonpath(plugin_root):\n")
                fh.write('    """ \n')
                fh.write(
                    "    Auto generated helper method which returns the \n")
                fh.write("    path to the core bundled with the plugin.\n")
                fh.write("    \n")
                fh.write("    For more information, see the documentation.\n")
                fh.write('    """ \n')
                fh.write("    import os\n")
                fh.write("    import sgtk\n")
                fh.write(
                    "    return os.path.dirname(os.path.dirname(sgtk.__file__))\n"
                )
                fh.write("\n\n")

            elif core_descriptor.get_path().startswith(plugin_root):
                # The core descriptor is cached inside our plugin, build a relative
                # path from the plugin root.
                core_path_parts = os.path.normpath(
                    core_descriptor.get_path()).split(os.path.sep)
                core_path_relative_parts = core_path_parts[
                    core_path_parts.index(BUNDLE_CACHE_ROOT_FOLDER_NAME):]
                core_path_relative_parts.append("python")

                fh.write("\n\n")
                fh.write("def get_sgtk_pythonpath(plugin_root):\n")
                fh.write('    """ \n')
                fh.write(
                    "    Auto generated helper method which returns the \n")
                fh.write("    path to the core bundled with the plugin.\n")
                fh.write("    \n")
                fh.write("    For more information, see the documentation.\n")
                fh.write('    """ \n')
                fh.write("    import os\n")
                fh.write("    return os.path.join(plugin_root, %s)\n" %
                         ", ".join('"%s"' % dir
                                   for dir in core_path_relative_parts))
                fh.write("\n\n")

            else:
                # the core descriptor is outside of bundle cache!
                logger.warning(
                    "Your core %r has its payload outside the plugin bundle cache. "
                    "This plugin cannot be distributed to others." %
                    core_descriptor)

                core_path_parts = os.path.normpath(
                    core_descriptor.get_path()).split(os.path.sep)
                core_path_parts.append("python")

                # because we are using an external core, the plugin_root parameter
                # is simply ignored in any calls from the plugin code to
                # get_sgtk_pythonpath()
                fh.write("\n\n")
                fh.write("def get_sgtk_pythonpath(plugin_root):\n")
                fh.write(
                    "    # NOTE - this was built with a core that is not part of the plugin. \n"
                )
                fh.write(
                    "    # The plugin_root parameter is therefore ignored.\n")
                fh.write(
                    "    # This is normally only done during development and \n"
                )
                fh.write(
                    "    # typically means that the plugin cannot run on other machines \n"
                )
                fh.write("    # than the one where it was built. \n")
                fh.write("    # \n")
                fh.write(
                    "    # For more information, see the documentation.\n")
                fh.write("    # \n")
                fh.write("    return r'%s'\n" %
                         os.path.sep.join(core_path_parts))
                fh.write("\n\n")

            # Write out helper function 'initialize_manager()'.
            # This method is a convenience method to make it easier to
            # set up the bootstrap manager given a plugin config

            fh.write("\n\n")
            fh.write("def initialize_manager(manager, plugin_root):\n")
            fh.write('    """ \n')
            fh.write("    Auto generated helper method which initializes\n")
            fh.write("    a toolkit manager with common plugin parameters.\n")
            fh.write("    \n")
            fh.write("    For more information, see the documentation.\n")
            fh.write('    """ \n')
            fh.write("    import os\n")

            # set base configuration
            fh.write("    manager.base_configuration = '%s'\n" % config_uri)

            # set entry point
            fh.write("    manager.plugin_id = '%s'\n" %
                     manifest_data["plugin_id"])

            # set shotgun config lookup flag if defined
            if "do_shotgun_config_lookup" in manifest_data:
                fh.write("    manager.do_shotgun_config_lookup = %s\n" %
                         manifest_data["do_shotgun_config_lookup"])

            # set bundle cache fallback path
            fh.write(
                "    bundle_cache_path = os.path.join(plugin_root, 'bundle_cache')\n"
            )
            fh.write(
                "    manager.bundle_cache_fallback_paths = [bundle_cache_path]\n"
            )

            fh.write("    return manager\n")

            fh.write("\n\n")
            fh.write("# end of file.\n")

    except Exception as e:
        logger.exception(e)
        raise TankError("Cannot write manifest file: %s" % e)
Example #9
0
 def _clean_definition(self, definition):
     # Create definition with key names as strings with no format, enum or default values
     regex = r"{(%s)}" % constants.TEMPLATE_KEY_NAME_REGEX
     cleaned_definition = re.sub(regex, r"%(\g<1>)s", definition)
     return cleaned_definition
Example #10
0
 def _replace_text(name, value, text):
     pattern = "{{<{pattern}>}}".format(pattern=name)
     # be sure to escape \ character to avoid having KeyError
     value = value.replace("\\", "\\\\")
     text = re.sub(pattern, value, text)
     return text