From 4df10e785efdb2f7679c61cd45b4373ffad63828 Mon Sep 17 00:00:00 2001 From: Nathaniel Landau Date: Thu, 30 Mar 2023 10:33:51 -0400 Subject: [PATCH] fix: improve TOML error handing and docs for Windows paths (#31) * fix: improve TOML error handing and documentation for Windows paths * build(linting): pash ruff v2.0.260 --- .pre-commit-config.yaml | 2 +- README.md | 6 ++++ poetry.lock | 38 +++++++++++------------ pyproject.toml | 2 +- src/obsidian_metadata/_config/config.py | 9 ++++-- src/obsidian_metadata/_utils/utilities.py | 4 ++- src/obsidian_metadata/models/vault.py | 8 ++--- tests/config_test.py | 2 ++ 8 files changed, 42 insertions(+), 29 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b970682..7fe3b91 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -61,7 +61,7 @@ repos: entry: yamllint --strict --config-file .yamllint.yml - repo: "https://github.com/charliermarsh/ruff-pre-commit" - rev: "v0.0.259" + rev: "v0.0.260" hooks: - id: ruff args: ["--extend-ignore", "I001,D301,D401"] diff --git a/README.md b/README.md index 0ff877f..2d26c84 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,8 @@ Below is an example with two vaults. ["Vault One"] # Name of the vault. # Path to your obsidian vault + # Note for Windows users: Windows paths must use `\\` as the path separator due to a limitation with how TOML parses strings. + # Example: "C:\\Users\\username\\Documents\\Obsidian" path = "/path/to/vault" # Folders within the vault to ignore when indexing metadata @@ -141,6 +143,10 @@ Below is an example with two vaults. To bypass the configuration file and specify a vault to use at runtime use the `--vault-path` option. +**Note for Windows users:** +Due to how TOMML parses strings, Windows paths must use `\\` as the path separator. +For example: `C:\\Users\\username\\Documents\\Obsidian` + ### Make Bulk Updates Bulk edits are supported by importing a CSV file containing the following columns. Column headers must be lowercase. diff --git a/poetry.lock b/poetry.lock index 23310a1..ad0c477 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1059,29 +1059,29 @@ files = [ [[package]] name = "ruff" -version = "0.0.259" +version = "0.0.260" description = "An extremely fast Python linter, written in Rust." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.0.259-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:f3938dc45e2a3f818e9cbd53007265c22246fbfded8837b2c563bf0ebde1a226"}, - {file = "ruff-0.0.259-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:22e1e35bf5f12072cd644d22afd9203641ccf258bc14ff91aa1c43dc14f6047d"}, - {file = "ruff-0.0.259-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2fb20e89e85d147c85caa807707a1488bccc1f3854dc3d53533e89b52a0c5ff"}, - {file = "ruff-0.0.259-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:49e903bcda19f6bb0725a962c058eb5d61f40d84ef52ed53b61939b69402ab4e"}, - {file = "ruff-0.0.259-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71f0ef1985e9a6696fa97da8459917fa34bdaa2c16bd33bd5edead585b7d44f7"}, - {file = "ruff-0.0.259-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7cfef26619cba184d59aa7fa17b48af5891d51fc0b755a9bc533478a10d4d066"}, - {file = "ruff-0.0.259-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79b02fa17ec1fd8d306ae302cb47fb614b71e1f539997858243769bcbe78c6d9"}, - {file = "ruff-0.0.259-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:428507fb321b386dda70d66cd1a8aa0abf51d7c197983d83bb9e4fa5ee60300b"}, - {file = "ruff-0.0.259-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5fbaea9167f1852757f02133e5daacdb8c75b3431343205395da5b10499927a"}, - {file = "ruff-0.0.259-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:40ae87f2638484b7e8a7567b04a7af719f1c484c5bf132038b702bb32e1f6577"}, - {file = "ruff-0.0.259-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:29e2b77b7d5da6a7dd5cf9b738b511355c5734ece56f78e500d4b5bffd58c1a0"}, - {file = "ruff-0.0.259-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b3c1beacf6037e7f0781d4699d9a2dd4ba2462f475be5b1f45cf84c4ba3c69d"}, - {file = "ruff-0.0.259-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:daaea322e7e85f4c13d82be9536309e1c4b8b9851bb0cbc7eeb15d490fd46bf9"}, - {file = "ruff-0.0.259-py3-none-win32.whl", hash = "sha256:38704f151323aa5858370a2f792e122cc25e5d1aabe7d42ceeab83da18f0b456"}, - {file = "ruff-0.0.259-py3-none-win_amd64.whl", hash = "sha256:aa9449b898287e621942cc71b9327eceb8f0c357e4065fecefb707ef2d978df8"}, - {file = "ruff-0.0.259-py3-none-win_arm64.whl", hash = "sha256:e4f39e18702de69faaaee3969934b92d7467285627f99a5b6ecd55a7d9f5d086"}, - {file = "ruff-0.0.259.tar.gz", hash = "sha256:8b56496063ab3bfdf72339a5fbebb8bd46e5c5fee25ef11a9f03b208fa0562ec"}, + {file = "ruff-0.0.260-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:c559650b623f3fbdc39c7ed1bcb064765c666a53ee738c53d1461afbf3f23db2"}, + {file = "ruff-0.0.260-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:90ff1479e292a84c388a8a035d223247ddeea5f6760752a9142b88b6d59ac334"}, + {file = "ruff-0.0.260-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25584d1b9f445fde72651caab97e7430a4c5bfd2a0ce9af39868753826cba10d"}, + {file = "ruff-0.0.260-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8032e35357384a29791c75194a71e314031171eb0731fcaa872dfaf4c1f4470a"}, + {file = "ruff-0.0.260-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4fa7293f97c021825b3b72f2bf53f0eb4f59625608a889678c1fc6660f412d"}, + {file = "ruff-0.0.260-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8bec0271e2c8cd36bcf915cb9f6a93e40797a3ff3d2cda4ca87b7bed9e598472"}, + {file = "ruff-0.0.260-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e075a61aaff8ebe56172217f0ac14c5df9637b289bf161ac697445a9003d5c2"}, + {file = "ruff-0.0.260-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8678f54eb2696481618902a10c3cb28325f3323799af99997ad6f06005ea4f5"}, + {file = "ruff-0.0.260-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57d9f0bfdef739b76aa3112b9182a214f0f34589a2659f88353492c7670fe2fe"}, + {file = "ruff-0.0.260-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ec1f77219ba5adaa194289cb82ba924ff2ed931fd00b8541d66a1724c89fbc9"}, + {file = "ruff-0.0.260-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:aae2170a7ec6f7fc4a73db30aa7aa7fce936176bf66bf85f77f69ddd1dd4a665"}, + {file = "ruff-0.0.260-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f847b72ef994ab88e9da250c7eb5cbb3f1555b92a9f22c5ed1c27a44b7e98d6"}, + {file = "ruff-0.0.260-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6dd705d4eff405c2b70513188fbff520f49db6df91f0d5e8258c5d469efa58bc"}, + {file = "ruff-0.0.260-py3-none-win32.whl", hash = "sha256:3866a96b2ef92c7d837ba6bf8fc9dd125a67886f1c5512ad6fa5d5fefaceff87"}, + {file = "ruff-0.0.260-py3-none-win_amd64.whl", hash = "sha256:0733d524946decbd4f1e63f7dc26820f5c1e6c31da529ba20fb995057f8e79b1"}, + {file = "ruff-0.0.260-py3-none-win_arm64.whl", hash = "sha256:12542a26f189a5a10c719bfa14d415d0511ac05e5c9ff5e79cc9d5cc50b81bc8"}, + {file = "ruff-0.0.260.tar.gz", hash = "sha256:ea8f94262f33b81c47ee9d81f455b144e94776f5c925748cb0c561a12206eae1"}, ] [[package]] @@ -1321,4 +1321,4 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "4eb179bbb559eb12dd73f673a8e7f80706386c88f5d777d5de4ca9b7612ace60" +content-hash = "61ab3ff1aa55c93eeec465752dcc92de12fc1c02206184913b67db1c590d3ed8" diff --git a/pyproject.toml b/pyproject.toml index 35ab1a6..fb966ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ pdoc = "^13.0.1" poethepoet = "^0.19.0" pre-commit = "^3.2.1" - ruff = "^0.0.259" + ruff = "^0.0.260" sh = "2.0.3" typeguard = "^3.0.2" types-python-dateutil = "^2.8.19.11" diff --git a/src/obsidian_metadata/_config/config.py b/src/obsidian_metadata/_config/config.py index c0a87ce..2151b14 100644 --- a/src/obsidian_metadata/_config/config.py +++ b/src/obsidian_metadata/_config/config.py @@ -77,10 +77,11 @@ class Config: VaultConfig(vault_name=key, vault_config=self.config[key]) for key in self.config ] except TypeError as e: - log.error(f"Configuration file is invalid: '{self.config_path}'") + log.error(f"Configuration file is invalid: '{self.config_path}'\n{e}") raise typer.Exit(code=1) from e log.debug(f"Loaded configuration from '{self.config_path}'") + log.trace("Configuration:") log.trace(self.config) def __rich_repr__(self) -> rich.repr.Result: # pragma: no cover @@ -91,10 +92,10 @@ class Config: def _load_config(self) -> dict[str, Any]: """Load the configuration file.""" try: - with self.config_path.open(encoding="utf-8") as fp: + with self.config_path.open(mode="rt", encoding="utf-8") as fp: return tomlkit.load(fp) except tomlkit.exceptions.TOMLKitError as e: - alerts.error(f"Could not parse '{self.config_path}'") + alerts.error(f"Could not parse '{self.config_path}'\n{e}") raise typer.Exit(code=1) from e def _validate_config_path(self, config_path: Path | None) -> Path: @@ -117,6 +118,8 @@ class Config: ["Vault 1"] # Name of the vault. # Path to your obsidian vault + # Note for Windows users: Windows paths must use `\\` as the path separator due to a limitation with how TOML parses strings. + # Example: "C:\\Users\\username\\Documents\\Obsidian" path = "{vault_path}" # Folders within the vault to ignore when indexing metadata diff --git a/src/obsidian_metadata/_utils/utilities.py b/src/obsidian_metadata/_utils/utilities.py index 74fb9ec..63018c0 100644 --- a/src/obsidian_metadata/_utils/utilities.py +++ b/src/obsidian_metadata/_utils/utilities.py @@ -282,7 +282,9 @@ def remove_markdown_sections( return text -def validate_csv_bulk_imports(csv_path: Path, note_paths: list) -> dict[str, list[dict[str, str]]]: +def validate_csv_bulk_imports( # noqa: C901 + csv_path: Path, note_paths: list +) -> dict[str, list[dict[str, str]]]: """Validate the bulk import CSV file. Args: diff --git a/src/obsidian_metadata/models/vault.py b/src/obsidian_metadata/models/vault.py index 6aef46d..c0fe40b 100644 --- a/src/obsidian_metadata/models/vault.py +++ b/src/obsidian_metadata/models/vault.py @@ -319,7 +319,7 @@ class Vault: return num_changed - def export_metadata(self, path: str, export_format: str = "csv") -> None: + def export_metadata(self, path: str, export_format: str = "csv") -> None: # noqa: C901 """Write metadata to a csv file. Args: @@ -333,7 +333,7 @@ class Vault: match export_format: case "csv": - with export_file.open(mode="w", encoding="UTF8") as f: + with export_file.open(mode="w", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["Metadata Type", "Key", "Value"]) @@ -361,7 +361,7 @@ class Vault: "tags": self.metadata.tags, } - with export_file.open(mode="w", encoding="UTF8") as f: + with export_file.open(mode="w", encoding="utf-8") as f: json.dump(dict_to_dump, f, indent=4, ensure_ascii=False, sort_keys=True) def export_notes_to_csv(self, path: str) -> None: @@ -375,7 +375,7 @@ class Vault: alerts.error(f"Path does not exist: {export_file.parent}") raise typer.Exit(code=1) - with export_file.open(mode="w", encoding="UTF8") as f: + with export_file.open(mode="w", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["path", "type", "key", "value"]) diff --git a/tests/config_test.py b/tests/config_test.py index 28bc960..1ffdcf3 100644 --- a/tests/config_test.py +++ b/tests/config_test.py @@ -103,6 +103,8 @@ def test_no_config_no_vault(tmp_path, mocker) -> None: ["Vault 1"] # Name of the vault. # Path to your obsidian vault + # Note for Windows users: Windows paths must use `\\` as the path separator due to a limitation with how TOML parses strings. + # Example: "C:\\Users\\username\\Documents\\Obsidian" path = "{str(fake_vault)}" # Folders within the vault to ignore when indexing metadata