From 325d229061339fe01d8f22ea0365fd4f8ef33820 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Fri, 10 May 2024 19:57:48 -0700 Subject: [PATCH] [BUGFIX] Fix usage of ~ in paths (#981) Fixes path with tildes in them, i.e. `~/videos/youtube` --- .../scripting/scripting_functions.rst | 2 +- src/ytdl_sub/config/config_validator.py | 5 ++++- src/ytdl_sub/entries/script/custom_functions.py | 4 ++-- tests/unit/config/test_config_file.py | 14 ++++++++++++++ tests/unit/config/test_preset.py | 16 ++++++++++++++++ 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/docs/source/config_reference/scripting/scripting_functions.rst b/docs/source/config_reference/scripting/scripting_functions.rst index d5948fb5..ebb777d4 100644 --- a/docs/source/config_reference/scripting/scripting_functions.rst +++ b/docs/source/config_reference/scripting/scripting_functions.rst @@ -716,7 +716,7 @@ to_native_filepath :spec: ``to_native_filepath(filepath: String) -> String`` Convert any unix-based path separators ('/') with the OS's native -separator. +separator. In addition, expand ~ to absolute directories. truncate_filepath_if_too_long ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/ytdl_sub/config/config_validator.py b/src/ytdl_sub/config/config_validator.py index ff18b3fc..55a91f55 100644 --- a/src/ytdl_sub/config/config_validator.py +++ b/src/ytdl_sub/config/config_validator.py @@ -1,3 +1,5 @@ +import os +import posixpath from typing import Any from typing import Dict from typing import Optional @@ -147,7 +149,8 @@ class ConfigOptions(StrictDictValidator): The directory to temporarily store downloaded files before moving them into their final directory. Defaults to .ytdl-sub-working-directory """ - return self._working_directory.value + # Expands tildas to actual paths, use native os sep + return os.path.expanduser(self._working_directory.value.replace(posixpath.sep, os.sep)) @property def umask(self) -> Optional[str]: diff --git a/src/ytdl_sub/entries/script/custom_functions.py b/src/ytdl_sub/entries/script/custom_functions.py index 690095de..ded8c54f 100644 --- a/src/ytdl_sub/entries/script/custom_functions.py +++ b/src/ytdl_sub/entries/script/custom_functions.py @@ -36,9 +36,9 @@ class CustomFunctions: def to_native_filepath(filepath: String) -> String: """ Convert any unix-based path separators ('/') with the OS's native - separator. + separator. In addition, expand ~ to absolute directories. """ - return String(filepath.value.replace(posixpath.sep, os.sep)) + return String(os.path.expanduser(filepath.value.replace(posixpath.sep, os.sep))) @staticmethod def truncate_filepath_if_too_long(filepath: String) -> String: diff --git a/tests/unit/config/test_config_file.py b/tests/unit/config/test_config_file.py index 352ead2d..f18a41e0 100644 --- a/tests/unit/config/test_config_file.py +++ b/tests/unit/config/test_config_file.py @@ -1,4 +1,6 @@ +import os.path import re +from pathlib import Path from typing import Dict from typing import Optional @@ -94,6 +96,18 @@ class TestConfigFilePartiallyValidatesPresets: }, ) + def test_config_file_working_dir_home_dir(self): + out = ConfigFile( + name="test_tilda", + value={ + "configuration": {"working_directory": "~/working/dir"}, + }, + ) + + assert out.config_options.working_directory == str( + Path(os.path.expanduser("~")) / "working" / "dir" + ) + @pytest.mark.parametrize( "preset_dict", [ diff --git a/tests/unit/config/test_preset.py b/tests/unit/config/test_preset.py index de651ada..cb3c0b81 100644 --- a/tests/unit/config/test_preset.py +++ b/tests/unit/config/test_preset.py @@ -1,4 +1,6 @@ +import os.path import re +from pathlib import Path import pytest @@ -37,6 +39,20 @@ class TestPreset: }, ) + def test_preset_with_output_directory_tilda(self, config_file, output_options, youtube_video): + out = Preset( + config=config_file, + name="test", + value={ + "download": youtube_video, + "output_options": {"output_directory": "~/output/dir", "file_name": "{dne_var}"}, + "overrides": {"dne_var": "not dne"}, + }, + ) + assert out.overrides.apply_formatter(out.output_options.output_directory) == str( + Path(os.path.expanduser("~")) / "output" / "dir" + ) + def test_preset_parent(self, config_file, output_options, youtube_video): preset = Preset( config=config_file,