diff --git a/addon/flamenco/job_types_propgroup.py b/addon/flamenco/job_types_propgroup.py index f3370e36..56732462 100644 --- a/addon/flamenco/job_types_propgroup.py +++ b/addon/flamenco/job_types_propgroup.py @@ -85,6 +85,18 @@ class JobTypePropertyGroup: label: str = self.bl_rna.properties[setting_key].name # type: ignore return label + def locals(self, context: bpy.types.Context) -> dict[str, object]: + """Return the local variables for job type evaluation.""" + return { + "bpy": bpy, + "C": context, + "jobname": context.scene.flamenco_job_name, + "Path": Path, + "abspath": self.abspath, + "last_n_dir_parts": self.last_n_dir_parts, + "settings": self, + } + def eval_and_assign( self, context: bpy.types.Context, @@ -103,14 +115,7 @@ class JobTypePropertyGroup: ) -> Any: """Evaluate `setting_eval` and return the result.""" - eval_locals = { - "bpy": bpy, - "C": context, - "jobname": context.scene.flamenco_job_name, - "Path": Path, - "last_n_dir_parts": self.last_n_dir_parts, - "settings": self, - } + eval_locals = self.locals(context) try: value = eval(setting_eval, {}, eval_locals) except Exception as ex: @@ -200,6 +205,15 @@ class JobTypePropertyGroup: subset = Path(*dirpath.parts[-n:]) return subset + @staticmethod + def abspath(filepath: Union[str, Path]) -> Path: + """Return the filepath as absolute path.""" + + # This changes blendfile-relative paths to absolute. + # It does not resolve `..` entries, though. + abs_unclean = Path(bpy.path.abspath(str(filepath))) + return bpathlib.make_absolute(abs_unclean) + # Mapping from AvailableJobType.setting.type to a callable that converts a value # to the appropriate type. This is necessary due to the ambiguity between floats diff --git a/internal/manager/job_compilers/scripts/simple_blender_render.js b/internal/manager/job_compilers/scripts/simple_blender_render.js index 42aa3418..08259437 100644 --- a/internal/manager/job_compilers/scripts/simple_blender_render.js +++ b/internal/manager/job_compilers/scripts/simple_blender_render.js @@ -15,7 +15,7 @@ const JOB_TYPE = { { key: "add_path_components", type: "int32", required: true, default: 0, propargs: {min: 0, max: 32}, visible: "submission", description: "Number of path components of the current blend file to use in the render output path"}, { key: "render_output_path", type: "string", subtype: "file_path", editable: false, - eval: "str(Path(bpy.path.abspath(settings.render_output_root), last_n_dir_parts(settings.add_path_components), jobname, '{timestamp}', '######'))", + eval: "str(Path(abspath(settings.render_output_root), last_n_dir_parts(settings.add_path_components), jobname, '{timestamp}', '######'))", description: "Final file path of where render output will be saved"}, // Automatically evaluated settings: diff --git a/web/project-website/content/usage/job-types/_index.md b/web/project-website/content/usage/job-types/_index.md index 52eea156..92cbcab2 100644 --- a/web/project-website/content/usage/job-types/_index.md +++ b/web/project-website/content/usage/job-types/_index.md @@ -117,13 +117,14 @@ following names: directory path manipulation. Note that this does *not* understand Blender's `//` prefix for blendfile-relative paths. Use `bpy.path.abspath()` to turn those into an absolute path if necessary. +- `abspath(path: str | Path) -> Path`: a function that returns the given path as + absolute path. Unlike `bpy.path.abspath()` this also resolves `..` entries. - `last_n_dir_parts(n, Optional[file_path])`: a function that returns the last `n` directory parts of some file's path. For example, `last_n_dir_parts(2, '/complex/path/to/a/file.blend')` will return `to/a`, as those are the last `2` components of the directory. If `file_path` is ommitted, it uses the current blend file, i.e. `bpy.data.filepath`. - [bpy]: https://docs.blender.org/api/master/ [context]: https://docs.blender.org/api/master/bpy.context.html [pathlib]: https://docs.python.org/3/library/pathlib.html