Пример #1
0
    def _get_render_package_path(self):
        """
        Calc the path to the render package.

        The name is not always known until
        preview/submission time because it is based on the filename and
        possibly a timestamp. What this means, practically, is that it won't
        show up in the extra uploads window along with
        other dependencies when the glob or smart-scan button is pushed.
        It will however always show up in the preview window.

        We replace spaces in the filename because of a bug in Clarisse
        https://www.isotropix.com/user/bugtracker/376

        Returns:
            string: path
        """
        current_filename = ix.application.get_current_project_filename()
        path = os.path.splitext(current_filename)[0]

        path = os.path.join(os.path.dirname(path),
                            os.path.basename(path).replace(" ", "_"))

        try:
            if self.timestamp_render_package:
                return Path("{}_ct{}.project".format(path, self.timestamp))
            else:
                return Path("{}_ct.project".format(path))
        except ValueError:
            ix.log_error(
                'Cannot create a submission from this file: "{}". Has it ever been saved?'
                .format(current_filename))
Пример #2
0
class PathExpansionTest(unittest.TestCase):
    def setUp(self):
        self.env = {
            "HOME": "/users/joebloggs",
            "SHOT": "/metropolis/shot01",
            "DEPT": "texturing",
        }

    def test_posix_tilde_input(self):
        with mock.patch.dict("os.environ", self.env):
            self.p = Path("~/a/b/c")
            self.assertEqual(self.p.posix_path(), "/users/joebloggs/a/b/c")

    def test_posix_var_input(self):
        with mock.patch.dict("os.environ", self.env):
            self.p = Path("$SHOT/a/b/c")
            self.assertEqual(self.p.posix_path(), "/metropolis/shot01/a/b/c")

    def test_posix_two_var_input(self):
        with mock.patch.dict("os.environ", self.env):
            self.p = Path("$SHOT/a/b/$DEPT/c")
            self.assertEqual(self.p.posix_path(),
                             "/metropolis/shot01/a/b/texturing/c")

    def test_windows_var_input(self):
        with mock.patch.dict("os.environ", self.env):
            self.p = Path("$HOME\\a\\b\\c")
            self.assertEqual(self.p.windows_path(),
                             "\\users\\joebloggs\\a\\b\\c")
            self.assertEqual(self.p.posix_path(), "/users/joebloggs/a/b/c")
Пример #3
0
class AbsPosixPathTest(unittest.TestCase):
    def setUp(self):
        self.p = Path("/a/b/c")

    def test_posix_path_out(self):
        self.assertEqual(self.p.posix_path(), "/a/b/c")

    def test_win_path_out(self):
        self.assertEqual(self.p.windows_path(), "\\a\\b\\c")
Пример #4
0
class SpecifyDriveLetterUse(unittest.TestCase):
    def test_remove_from_path(self):
        self.p = Path("C:\\a\\b\\c")
        self.assertEqual(self.p.posix_path(with_drive=False), "/a/b/c")
        self.assertEqual(self.p.windows_path(with_drive=False), "\\a\\b\\c")

    def test_remove_from_root_path(self):
        self.p = Path("C:\\")
        self.assertEqual(self.p.posix_path(with_drive=False), "/")
        self.assertEqual(self.p.windows_path(with_drive=False), "\\")
Пример #5
0
class RootPath(unittest.TestCase):
    def test_root_path(self):
        self.p = Path("/")
        self.assertEqual(self.p.posix_path(), "/")
        self.assertEqual(self.p.windows_path(), "\\")

    def test_drive_letter_root_path(self):
        self.p = Path("C:\\")
        self.assertEqual(self.p.posix_path(), "C:/")
        self.assertEqual(self.p.windows_path(), "C:\\")
Пример #6
0
class WindowsMixedPathTest(unittest.TestCase):
    def test_abs_in_posix_path_out(self):
        self.p = Path("\\a\\b\\c/d/e")
        self.assertEqual(self.p.posix_path(), "/a/b/c/d/e")

    def test_abs_in_windows_path_out(self):
        self.p = Path("\\a\\b\\c/d/e")
        self.assertEqual(self.p.windows_path(), "\\a\\b\\c\\d\\e")

    def test_letter_abs_in_posix_path_out(self):
        self.p = Path("C:\\a\\b\\c/d/e")
        self.assertEqual(self.p.posix_path(), "C:/a/b/c/d/e")

    def test_letter_abs_in_windows_path_out(self):
        self.p = Path("C:\\a\\b\\c/d/e")
        self.assertEqual(self.p.windows_path(), "C:\\a\\b\\c\\d\\e")
Пример #7
0
class AbsWindowsPathTest(unittest.TestCase):
    def setUp(self):
        self.p = Path("C:\\a\\b\\c")

    def test_posix_path_out(self):
        self.assertEqual(self.p.posix_path(), "C:/a/b/c")

    def test_win_path_out(self):
        self.assertEqual(self.p.windows_path(), "C:\\a\\b\\c")

    # consider just testing on both platforms
    def test_os_path_out(self):
        with mock.patch("os.name", "posix"):
            self.assertEqual(self.p.os_path(), "C:/a/b/c")
        with mock.patch("os.name", "nt"):
            self.assertEqual(self.p.os_path(), "C:\\a\\b\\c")
Пример #8
0
 def test_common_path_when_duplicate_entries_of_single_path(self):
     d = PathList()
     files = [
         "/users/joebloggs/tmp/foo.txt", "/users/joebloggs/tmp/foo.txt"
     ]
     d.add(*files)
     self.assertEqual(d.common_path(), Path("/users/joebloggs/tmp/foo.txt"))
Пример #9
0
    def _set_tokens(self):
        """Env tokens are variables to help the user build expressions.

        The user interface has fields for strings such as job title,
        task command. The user can use these tokens with <angle brackets> to build those strings. Tokens at the Submission
        level are also available in Job level fields, and likewise
        tokens at the Job level are available in Task level fields.
        """
        tokens = {}

        pdir_val = ix.application.get_factory().get_vars().get(
            "PDIR").get_string()

        tokens["ct_pdir"] = '"{}"'.format(
            Path(pdir_val).posix_path(with_drive=False))

        tokens["ct_temp_dir"] = "{}".format(
            self.tmpdir.posix_path(with_drive=False))
        tokens["ct_timestamp"] = self.timestamp
        tokens["ct_submitter"] = self.node.get_name()

        tokens["ct_render_package"] = '"{}"'.format(
            self.render_package_path.posix_path(with_drive=False))

        tokens["ct_project"] = self.project["name"]

        return tokens
Пример #10
0
 def test_next_reset_after_add(self):
     d = PathList()
     d.add("/file1", "/file2", "/file3")
     next(d)
     next(d)
     d.add("/file4")
     self.assertEqual(next(d), Path("/file1"))
Пример #11
0
    def common_path(self):
        """Find the common path among entries.

        This is useful for determining output directory when many
        renders are rendering to different places.

        In the case where
        only single path exists, it is not possible to tell from its
        name whether it is a file or directory. We don't want this
        method to touch the filesystem, that should be someone else's
        problem. A trailing slash would be a hint, but the absence of a
        trailing slash does not mean its a regular file. Therefore, in
        the case of a single file we return it AS-IS and the caller can
        then stat to find out for sure.

        If no files exist return None.

        If the filesystem root is the common path, return root path, which is
        not entirely correct on windows with drive letters.
        """
        if not self._entries:
            return None

        def _all_the_same(rhs):
            return all(n == rhs[0] for n in rhs[1:])

        levels = zip(*[p.all_components for p in self._entries])

        common = [x[0] for x in takewhile(_all_the_same, levels)]
        return Path(common or "/")
Пример #12
0
def system_dependencies():
    """
    Provides a list of system files to be sent to the render node.

    These will be copied to a directory in preparation for uploading.

    This is part of a strategy to satisfy 2 constraints.
    1. Dont store special logic on the sidecar.
    2. Don't make the render command un-runnable on the local machine.

    See docs in ct_cnode and ct_prep for more info.

    Returns:
        list: Each element is a source/destination pair of paths.
        [
            {"src": "/some/path.ext", "dest": "/other/path.ext"},
            ...
        ]
    """

    result = []
    conductor_scripts_directory = os.path.join(
        os.environ["CONDUCTOR_LOCATION"], "conductor", "clarisse", "scripts")
    conductor_tmp_dir = os.path.join(
        ix.application.get_factory().get_vars().get("CTEMP").get_string(),
        "conductor")

    for script in CONDUCTOR_SCRIPTS:
        src_path = Path(os.path.join(conductor_scripts_directory,
                                     script)).posix_path()
        dest_path = Path(os.path.join(conductor_tmp_dir, script)).posix_path()

        result.append({"src": src_path, "dest": dest_path})

    config_dir = (ix.application.get_factory().get_vars().get(
        "CLARISSE_USER_CONFIG_DIR").get_string())

    config_src_file = Path(os.path.join(config_dir,
                                        CLARISSE_CFG_FILENAME)).posix_path()
    config_dest_file = Path(
        os.path.join(conductor_tmp_dir, CLARISSE_CFG_FILENAME)).posix_path()

    result.append({"src": config_src_file, "dest": config_dest_file})

    return result
Пример #13
0
 def test_common_path_when_one_path_is_the_common_path(self):
     d = PathList()
     files = [
         "/users/joebloggs/tmp",
         "/users/joebloggs/tmp/bolly/operation",
         "/users/joebloggs/tmp/stay/go",
     ]
     d.add(*files)
     self.assertEqual(d.common_path(), Path("/users/joebloggs/tmp"))
Пример #14
0
 def test_common_path(self):
     d = PathList()
     files = [
         "/users/joebloggs/tmp/foobar/test",
         "/users/joebloggs/tmp/baz/fripp",
         "/users/joebloggs/tmp/elephant/corner",
     ]
     d.add(*files)
     self.assertEqual(d.common_path(), Path("/users/joebloggs/tmp"))
Пример #15
0
 def test_common_path_when_common_prefix_in_filename(self):
     d = PathList()
     files = [
         "/users/joebloggs/tmp/dissention/perfect",
         "/users/joebloggs/tmp/disagreement/crimson",
         "/users/joebloggs/tmp/diatribe/belew",
     ]
     d.add(*files)
     self.assertEqual(d.common_path(), Path("/users/joebloggs/tmp"))
Пример #16
0
    def __init__(self, obj):
        """
        Collect data from the Clarisse UI.

        Collect attribute values that are common to all jobs, then call
        _set_tokens(). After _set_tokens has been called, the Submission level
        token variables are valid and calls to evaluate expressions will
        correctly resolve where those tokens have been used.
        """
        self.node = obj

        if self.node.is_kindof("ConductorJob"):
            self.nodes = [obj]
        else:
            raise NotImplementedError

        self.localize_before_ship = self.node.get_attribute(
            "localize_contexts").get_bool()
        self.project_filename = ix.application.get_current_project_filename()
        self.timestamp = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
        self.timestamp_render_package = self.node.get_attribute(
            "timestamp_render_package").get_bool()

        self.tmpdir = Path(
            os.path.join(
                ix.application.get_factory().get_vars().get(
                    "CTEMP").get_string(),
                "conductor",
            ))
        self.render_package_path = self._get_render_package_path()
        self.should_delete_render_package = self.node.get_attribute(
            "clean_up_render_package").get_bool()

        self.local_upload = self.node.get_attribute("local_upload").get_bool()
        self.force_upload = self.node.get_attribute("force_upload").get_bool()
        self.upload_only = self.node.get_attribute("upload_only").get_bool()
        self.project = self._get_project()
        self.notifications = self._get_notifications()
        self.tokens = self._set_tokens()

        self.jobs = []
        for node in self.nodes:
            job = Job(node, self.tokens, self.render_package_path)
            self.jobs.append(job)
Пример #17
0
 def test_common_path_when_lowest_path_is_the_common_path(self):
     d = PathList()
     files = [
         "/users/joebloggs/tmp/foo.txt",
         "/users/joebloggs/tmp/modelman.jpg",
         "/users/joebloggs/tmp/ration.cpp",
         "/users/joebloggs/tmp/bill.project",
     ]
     d.add(*files)
     self.assertEqual(d.common_path(), Path("/users/joebloggs/tmp"))
Пример #18
0
 def test_common_different_drive_letter(self):
     d = PathList()
     files = [
         "D://users/joebloggs/tmp/foo.txt",
         "D://users/joebloggs/tmp/modelman.jpg",
         "C://users/joebloggs/tmp/ration.cpp",
         "C://users/joebloggs/tmp/bill.project",
     ]
     d.add(*files)
     self.assertEqual(d.common_path(), Path("/"))
Пример #19
0
class PathContextExpansionTest(unittest.TestCase):
    def setUp(self):

        self.env = {
            "HOME": "/users/joebloggs",
            "SHOT": "/metropolis/shot01",
            "DEPT": "texturing",
        }

        self.context = {
            "HOME": "/users/janedoe",
            "FOO": "fooval",
            "BAR_FLY1_": "bar_fly1_val",
            "ROOT_DIR": "/some/root",
        }

    def test_path_replaces_context(self):
        self.p = Path("$ROOT_DIR/thefile.jpg", context=self.context)
        self.assertEqual(self.p.posix_path(), "/some/root/thefile.jpg")

    def test_path_replaces_multiple_context(self):
        self.p = Path("$ROOT_DIR/$BAR_FLY1_/thefile.jpg", context=self.context)
        self.assertEqual(self.p.posix_path(),
                         "/some/root/bar_fly1_val/thefile.jpg")

    def test_path_context_overrides_env(self):
        self.p = Path("$HOME/thefile.jpg", context=self.context)
        self.assertEqual(self.p.posix_path(), "/users/janedoe/thefile.jpg")

    def test_path_leave_unknown_variable_in_tact(self):
        self.p = Path("$ROOT_DIR/$BAR_FLY1_/$FOO/thefile.$F.jpg",
                      context=self.context)
        self.assertEqual(self.p.posix_path(),
                         "/some/root/bar_fly1_val/fooval/thefile.$F.jpg")

    def test_relative_path_var_fails(self):
        with self.assertRaises(ValueError):
            self.p = Path("$FOO/a/b/c", context=self.context)
Пример #20
0
    def _add_one(self, path):
        """Add a single file.

        Note that when an element is added, it may cause the list to
        change next time it is deduplicated, which includes getting
        shorter. This could happen if a containing directory is added.
        Therefore we have to set the peg position to zero.
        """

        if not type(path).__name__ == "Path":
            path = Path(path)
        self._entries.append(path)
        self._clean = False
        self._current = 0
Пример #21
0
    def glob(self):
        """Glob expansion for entries containing globbable characters.

        We don't simply glob every entry since that would remove entries
        that don't yet exist. And we can't just rely on zero glob
        results because it may have been a legitimate zero result if it
        was globbable but matched nothing. So we test for glob
        characters (*|?|[) to determine whether to attempt a glob.
        """
        self._deduplicate()
        result = []
        for entry in self._entries:
            pp = entry.posix_path()
            if GLOBBABLE_REGEX.search(pp):
                globs = glob.glob(entry.posix_path())
                result += globs
            else:
                result.append(pp)
        self._entries = [Path(g) for g in result]
        self._clean = False
        self._current = 0
Пример #22
0
 def test_unpacking(self):
     d = PathList()
     d.add(Path("/a/file1"), Path("/a/file2"))
     a, b = d
     self.assertEqual(type(a), Path)
Пример #23
0
 def __contains__(self, key):
     if not isinstance(key, Path):
         key = Path(key)
     return key in self._entries
Пример #24
0
 def test_dedup_same_paths(self):
     d = PathList()
     d.add(Path("/file1"), Path("/file2"), Path("/file2"))
     self.assertEqual(len(d), 2)
     self.assertIn(Path("/file1"), d)
     self.assertIn(Path("/file2"), d)
Пример #25
0
class Submission(object):
    """
    Submission holds all data needed for a submission.

    It has potentially many Jobs, and those Jobs each have many Tasks. A
    Submission can provide the correct args to send to Conductor, or it can be
    used to create a dry run to show the user what will happen.

    A Submission also sets a list of tokens that the user can access as <angle
    bracket> tokens in order to build strings in the UI such as commands, job
    title, and (soon to be added) metadata.
    """
    def __init__(self, obj):
        """
        Collect data from the Clarisse UI.

        Collect attribute values that are common to all jobs, then call
        _set_tokens(). After _set_tokens has been called, the Submission level
        token variables are valid and calls to evaluate expressions will
        correctly resolve where those tokens have been used.
        """
        self.node = obj

        if self.node.is_kindof("ConductorJob"):
            self.nodes = [obj]
        else:
            raise NotImplementedError

        self.localize_before_ship = self.node.get_attribute(
            "localize_contexts").get_bool()
        self.project_filename = ix.application.get_current_project_filename()
        self.timestamp = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
        self.timestamp_render_package = self.node.get_attribute(
            "timestamp_render_package").get_bool()

        self.tmpdir = Path(
            os.path.join(
                ix.application.get_factory().get_vars().get(
                    "CTEMP").get_string(),
                "conductor",
            ))
        self.render_package_path = self._get_render_package_path()
        self.should_delete_render_package = self.node.get_attribute(
            "clean_up_render_package").get_bool()

        self.local_upload = self.node.get_attribute("local_upload").get_bool()
        self.force_upload = self.node.get_attribute("force_upload").get_bool()
        self.upload_only = self.node.get_attribute("upload_only").get_bool()
        self.project = self._get_project()
        self.notifications = self._get_notifications()
        self.tokens = self._set_tokens()

        self.jobs = []
        for node in self.nodes:
            job = Job(node, self.tokens, self.render_package_path)
            self.jobs.append(job)

    def _get_project(self):
        """Get the project from the attr.

        Get its ID in case the current project is no longer in the list
        of projects at conductor, throw an error.
        """

        projects = ConductorDataBlock().projects()
        project_att = self.node.get_attribute("conductor_project_name")
        label = project_att.get_applied_preset_label()
        try:
            found = next(p for p in projects if str(p["name"]) == label)
        except StopIteration:
            ix.log_error(
                'Cannot find project "{}" at Conductor.'.format(label))

        return {"id": found["id"], "name": str(found["name"])}

    def _get_notifications(self):
        """Get notification prefs."""
        if not self.node.get_attribute("notify").get_bool():
            return None

        emails = self.node.get_attribute("email_addresses").get_string()
        return [email.strip() for email in emails.split(",") if email.strip()]

    def _set_tokens(self):
        """Env tokens are variables to help the user build expressions.

        The user interface has fields for strings such as job title,
        task command. The user can use these tokens with <angle brackets> to build those strings. Tokens at the Submission
        level are also available in Job level fields, and likewise
        tokens at the Job level are available in Task level fields.
        """
        tokens = {}

        pdir_val = ix.application.get_factory().get_vars().get(
            "PDIR").get_string()

        tokens["ct_pdir"] = '"{}"'.format(
            Path(pdir_val).posix_path(with_drive=False))

        tokens["ct_temp_dir"] = "{}".format(
            self.tmpdir.posix_path(with_drive=False))
        tokens["ct_timestamp"] = self.timestamp
        tokens["ct_submitter"] = self.node.get_name()

        tokens["ct_render_package"] = '"{}"'.format(
            self.render_package_path.posix_path(with_drive=False))

        tokens["ct_project"] = self.project["name"]

        return tokens

    def _get_render_package_path(self):
        """
        Calc the path to the render package.

        The name is not always known until
        preview/submission time because it is based on the filename and
        possibly a timestamp. What this means, practically, is that it won't
        show up in the extra uploads window along with
        other dependencies when the glob or smart-scan button is pushed.
        It will however always show up in the preview window.

        We replace spaces in the filename because of a bug in Clarisse
        https://www.isotropix.com/user/bugtracker/376

        Returns:
            string: path
        """
        current_filename = ix.application.get_current_project_filename()
        path = os.path.splitext(current_filename)[0]

        path = os.path.join(os.path.dirname(path),
                            os.path.basename(path).replace(" ", "_"))

        try:
            if self.timestamp_render_package:
                return Path("{}_ct{}.project".format(path, self.timestamp))
            else:
                return Path("{}_ct.project".format(path))
        except ValueError:
            ix.log_error(
                'Cannot create a submission from this file: "{}". Has it ever been saved?'
                .format(current_filename))

    def get_args(self):
        """
        Prepare the args for submission to conductor.

        Returns:
            list: list of dicts containing submission args per job.
        """

        result = []
        submission_args = {}

        submission_args["local_upload"] = self.local_upload
        submission_args["upload_only"] = self.upload_only
        submission_args["force"] = self.force_upload
        submission_args["project"] = self.project["name"]
        submission_args["notify"] = self.notifications

        for job in self.jobs:
            args = job.get_args(self.upload_only)
            args.update(submission_args)
            result.append(args)
        return result

    def submit(self):
        """
        Submit all jobs.

        Returns:
            list: list of response dictionaries, containing response codes
            and descriptions.
        """

        submission_args = self.get_args()
        self.write_render_package()

        do_submission, submission_args = self.legalize_upload_paths(
            submission_args)
        results = []
        if do_submission:

            for job_args in submission_args:
                try:
                    remote_job = conductor_submit.Submit(job_args)
                    response, response_code = remote_job.main()
                    results.append({
                        "code": response_code,
                        "response": response
                    })
                except BaseException:
                    results.append({
                        "code":
                        "undefined",
                        "response":
                        "".join(traceback.format_exception(*sys.exc_info())),
                    })
            for result in results:
                ix.log_info(result)
        else:
            return [{
                "code": "undefined",
                "response": "Submission cancelled by user"
            }]

        self._after_submit()
        return results

    def write_render_package(self):
        """
        Write a package suitable for rendering.

        A render package is a project file with a special name.
        """

        app = ix.application
        clarisse_window = app.get_event_window()

        self._before_write_package()
        current_filename = app.get_current_project_filename()
        current_window_title = clarisse_window.get_title()

        package_file = self.render_package_path.posix_path()
        with cu.disabled_app():
            success = ix.application.save_project(package_file)
            ix.application.set_current_project_filename(current_filename)
            clarisse_window.set_title(current_window_title)

        self._after_write_package()

        if not success:
            ix.log_error(
                "Failed to export render package {}".format(package_file))

        ix.log_info("Wrote package to {}".format(package_file))
        return package_file

    def legalize_upload_paths(self, submission_args):
        """
        Alert the user of missing files. If the user doesn't want to continue
        with missing files, the result will be False. Otherwise it will be True
        and the potentially adjusted args are returned.

        Args:
            submission_args (list): list of job args.

        Returns:
           tuple (bool, adjusted args):
        """
        missing_files = []

        for job_args in submission_args:
            existing_files = []
            for path in job_args["upload_paths"]:
                if os.path.exists(path):
                    existing_files.append(path)
                else:
                    missing_files.append(path)

            job_args["upload_paths"] = existing_files
        missing_files = sorted(list(set(missing_files)))
        if not missing_files_ui.proceed(missing_files):
            return (False, [])
        return (True, submission_args)

    def _before_write_package(self):
        """
        Prepare to write render package.
        """
        if self.localize_before_ship:
            _localize_contexts()
            _remove_conductor()

        self._prepare_temp_directory()
        self._copy_system_dependencies_to_temp()

    def _prepare_temp_directory(self):
        """
        Make sure the temp directory has a conductor subdirectory.
        """
        tmpdir = self.tmpdir.posix_path()
        try:
            os.makedirs(tmpdir)
        except OSError as ex:
            if not (ex.errno == errno.EEXIST and os.path.isdir(tmpdir)):
                raise

    def _copy_system_dependencies_to_temp(self):
        """
        Copy over all system dependencies to a tmp folder.

        Wrapper scripts, config files etc. The clarisse.cfg file is special. See
        ../clarisse_config.py
        """
        for entry in deps.system_dependencies():
            if os.path.isfile(entry["src"]):
                if entry["src"].endswith(".cfg"):
                    safe_config = ccfg.legalize(entry["src"])
                    with open(entry["dest"], "w") as dest:
                        dest.write(safe_config)
                    ix.log_info("Copy with mods {} to {}".format(
                        entry["src"], entry["dest"]))
                else:
                    ix.log_info("Copy {} to {}".format(entry["src"],
                                                       entry["dest"]))
                    shutil.copy(entry["src"], entry["dest"])

    def _after_submit(self):
        """Clean up, and potentially other post submission actions."""
        self._delete_render_package()

    def _after_write_package(self):
        """
        Runs operations after saving the render package.

        If we did something destructive, like localize contexts, then
        a backup will have been saved and we now reload it. This strategy
        is used because Clarisse's undo is broken when it comes to
        undoing context localization.
        """
        if self.localize_before_ship:
            self._revert_to_saved_scene()

    def _delete_render_package(self):
        """
        Delete the render package from disk if the user wants to.
        """
        if self.should_delete_render_package:
            render_package_file = self.render_package_path.posix_path()
            if os.path.exists(render_package_file):
                os.remove(render_package_file)

    def _revert_to_saved_scene(self):
        """
        If contexts were localized, we will load the saved scene.
        """
        with cu.waiting_cursor():
            with cu.disabled_app():
                ix.application.load_project(self.project_filename)

    @property
    def node_name(self):
        """node_name."""
        return self.node.get_name()

    @property
    def filename(self):
        """filename."""
        return ix.application.get_current_project_filename()

    def has_notifications(self):
        """has_notifications."""
        return bool(self.notifications)

    @property
    def email_addresses(self):
        """email_addresses."""
        if not self.has_notifications():
            return []
        return self.notifications["email"]["addresses"]
Пример #26
0
 def test_common_path_is_slash_when_root(self):
     d = PathList()
     files = ["/users/joebloggs/tmp/foo.txt", "/dev/joebloggs/tmp/foo.txt"]
     d.add(*files)
     self.assertEqual(d.common_path(), Path("/"))
Пример #27
0
 def test_abs_in_posix_path_out(self):
     self.p = Path("\\a\\b\\c/d/e")
     self.assertEqual(self.p.posix_path(), "/a/b/c/d/e")
Пример #28
0
 def test_adds_paths(self):
     d = PathList()
     d.add(Path("/a/file1"), Path("/a/file2"))
     self.assertEqual(len(d), 2)
Пример #29
0
 def test_adds_mix(self):
     d = PathList()
     d.add("/a/file1", "/a/file2", Path("/a/file3"))
     self.assertEqual(len(d), 3)
Пример #30
0
 def test_next(self):
     d = PathList()
     d.add("/file1", "/file2", "/file3")
     self.assertEqual(next(d), Path("/file1"))
     self.assertEqual(next(d), Path("/file2"))