Skip to content

Commit

Permalink
BREAK: merge vscode.remove_setting() into remove_settings() (#376)
Browse files Browse the repository at this point in the history
* ENH: allow recursive remove in `vscode.remove_settings()`
* MAINT: remove redundant parentheses in types
  • Loading branch information
redeboer authored Aug 13, 2024
1 parent 6a5e511 commit e5c74f3
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 30 deletions.
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"ProjectURLs": "list",
"PyprojectTOML": "dict",
"PythonVersion": "str",
"RemovedKeys": ("obj", "compwa_policy.utilities.vscode.RemovedKeys"),
"Sequence": "typing.Sequence",
"T": "typing.TypeVar",
"Table": "tomlkit.items.Table",
Expand Down
2 changes: 1 addition & 1 deletion src/compwa_policy/check_dev_files/prettier.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _fix_config_content(no_prettierrc: bool) -> None:
if no_prettierrc:
with Executor() as do:
do(__remove_prettierrc)
do(vscode.remove_setting, {"[markdown]": "editor.wordWrap"})
do(vscode.remove_settings, {"[markdown]": {"editor.wordWrap"}})
else:
if not CONFIG_PATH.prettier.exists():
existing_content = ""
Expand Down
4 changes: 2 additions & 2 deletions src/compwa_policy/utilities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def hash_file(path: Path | str) -> str:
return sha256.hexdigest()


def read(input: Path | (io.TextIOBase | str)) -> str: # noqa: A002
def read(input: Path | io.TextIOBase | str) -> str: # noqa: A002
if isinstance(input, (Path, str)):
with open(input) as input_stream:
return input_stream.read()
Expand All @@ -74,7 +74,7 @@ def read(input: Path | (io.TextIOBase | str)) -> str: # noqa: A002
raise TypeError(msg)


def write(content: str, target: Path | (io.TextIOBase | str)) -> None:
def write(content: str, target: Path | io.TextIOBase | str) -> None:
if isinstance(target, str):
target = Path(target)
if isinstance(target, Path):
Expand Down
8 changes: 4 additions & 4 deletions src/compwa_policy/utilities/cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def __write_config(cfg: ConfigParser, output_path: Path | str) -> None:


def format_config(
input: Path | (io.TextIOBase | str), # noqa: A002
output: Path | (io.TextIOBase | str),
input: Path | io.TextIOBase | str, # noqa: A002
output: Path | io.TextIOBase | str,
additional_rules: Iterable[Callable[[str], str]] | None = None,
) -> None:
content = read(input)
Expand All @@ -74,7 +74,7 @@ def format_config(
write(content, target=output)


def open_config(definition: Path | (io.TextIOBase | str)) -> ConfigParser:
def open_config(definition: Path | io.TextIOBase | str) -> ConfigParser:
cfg = ConfigParser()
if isinstance(definition, io.TextIOBase):
text = definition.read()
Expand All @@ -97,7 +97,7 @@ def open_config(definition: Path | (io.TextIOBase | str)) -> ConfigParser:
return cfg


def write_config(cfg: ConfigParser, output: Path | (io.TextIOBase | str)) -> None:
def write_config(cfg: ConfigParser, output: Path | io.TextIOBase | str) -> None:
if isinstance(output, io.TextIOBase):
cfg.write(output)
elif isinstance(output, (Path, str)):
Expand Down
72 changes: 49 additions & 23 deletions src/compwa_policy/utilities/vscode.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@
import collections
import json
from collections import abc
from copy import deepcopy
from typing import TYPE_CHECKING, Iterable, OrderedDict, TypeVar, overload
from typing import (
TYPE_CHECKING,
Any,
Dict,
Iterable,
OrderedDict,
TypeVar,
Union,
overload,
)

from compwa_policy.errors import PrecommitError
from compwa_policy.utilities import CONFIG_PATH
Expand All @@ -20,33 +28,51 @@
V = TypeVar("V")


def remove_setting(key: str | dict) -> None:
old = __load_config(CONFIG_PATH.vscode_settings, create=True)
new = deepcopy(old)
_recursive_remove_setting(key, new)
_update_settings_if_changed(old, new)

RemovedKeys = Union[Iterable[str], Dict[str, "RemovedKeys"]]
"""Type for keys to be removed from a (nested) dictionary."""

def _recursive_remove_setting(nested_keys: str | dict, settings: dict) -> None:
if isinstance(nested_keys, str) and nested_keys in settings:
settings.pop(nested_keys)
elif isinstance(nested_keys, dict):
for key, sub_keys in nested_keys.items():
if key not in settings:
continue
if isinstance(sub_keys, str):
sub_keys = [sub_keys]
for sub_key in sub_keys:
_recursive_remove_setting(sub_key, settings[key])


def remove_settings(keys: Iterable[str]) -> None:
removed_keys = set(keys)
def remove_settings(keys: RemovedKeys) -> None:
settings = __load_config(CONFIG_PATH.vscode_settings, create=True)
new_settings = {k: v for k, v in settings.items() if k not in removed_keys}
new_settings = _remove_keys(settings, keys)
_update_settings_if_changed(settings, new=new_settings)


def _remove_keys(obj: Any, keys: RemovedKeys) -> dict:
"""Recursively remove keys from a (nested) dictionary.
>>> dct = {"a": 1, "b": 2, "c": 3, "d": [4, 5], "sub_key": {"d": 6, "e": [7, 8]}}
>>> _remove_keys(dct, {"a", "c"})
{'b': 2, 'd': [4, 5], 'sub_key': {'d': 6, 'e': [7, 8]}}
>>> _remove_keys(dct, {"sub_key": {"d"}})
{'a': 1, 'b': 2, 'c': 3, 'd': [4, 5], 'sub_key': {'e': [7, 8]}}
>>> _remove_keys(dct, {"sub_key": {"d", "e"}})
{'a': 1, 'b': 2, 'c': 3, 'd': [4, 5]}
"""
if not keys:
return obj
if not isinstance(obj, dict):
return obj
if isinstance(keys, dict):
new_dict = {}
for key, value in obj.items():
sub_keys_to_remove = keys.get(key, {})
new_value = _remove_keys(value, sub_keys_to_remove)
if (
isinstance(new_value, abc.Iterable)
and not isinstance(new_value, str)
and len(new_value) == 0
):
continue
new_dict[key] = _remove_keys(value, keys.get(key, {}))
return new_dict
if isinstance(keys, abc.Iterable) and not isinstance(keys, str):
removed_keys = set(keys)
return {k: v for k, v in obj.items() if k not in removed_keys}
msg = f"Invalid type for removed keys: {type(keys)}"
raise TypeError(msg)


def update_settings(new_settings: dict) -> None:
old = __load_config(CONFIG_PATH.vscode_settings, create=True)
updated = _update_dict_recursively(old, new_settings)
Expand Down

0 comments on commit e5c74f3

Please sign in to comment.