Skip to content

Commit 83cb0f5

Browse files
committed
Added new YamlEditor class to simplify reading and updating YAML files.
1 parent a34dab9 commit 83cb0f5

File tree

2 files changed

+102
-25
lines changed

2 files changed

+102
-25
lines changed

repo_helper/cli/commands/suggest.py

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -182,30 +182,11 @@ def classifiers(add: bool, status: Optional[int], library: Optional[bool]):
182182

183183
if add:
184184

185-
# 3rd party
186-
from ruamel.yaml import YAML
185+
# this package
186+
from repo_helper.configuration import YamlEditor
187187

188-
yaml = YAML()
189-
yaml.indent(offset=1)
190-
yaml.width = 4096 # type: ignore
191-
yaml.preserve_quotes = True # type: ignore
192-
193-
data = yaml.load((rh.target_repo / "repo_helper.yml").read_text())
194-
195-
if "classifiers" in data:
196-
data["classifiers"] = natsorted({*data["classifiers"], *suggested_classifiers})
197-
198-
yaml.explicit_start = True # type: ignore
199-
200-
with (rh.target_repo / "repo_helper.yml").open('w') as fp:
201-
yaml.dump(data, fp)
202-
203-
else:
204-
yaml.explicit_start = False # type: ignore
205-
206-
with (rh.target_repo / "repo_helper.yml").open('a') as fp:
207-
fp.write('\n')
208-
yaml.dump({"classifiers": natsorted(suggested_classifiers)}, fp)
188+
yaml = YamlEditor()
189+
yaml.update_key(rh.target_repo / "repo_helper.yml", "classifiers", suggested_classifiers, sort=True)
209190

210191

211192
# TODO: flags for interactive options, and clean output when piped

repo_helper/configuration/__init__.py

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
# stdlib
2727
import json
2828
import re
29-
from typing import Any, Dict, List, Mapping, MutableMapping
29+
from typing import Any, Dict, List, Mapping, MutableMapping, Optional, Sequence, Set, Union
3030

3131
# 3rd party
3232
from configconfig.metaclass import ConfigVarMeta
@@ -36,7 +36,8 @@
3636
from domdf_python_tools.paths import PathPlus
3737
from domdf_python_tools.typing import PathLike
3838
from domdf_python_tools.versions import Version
39-
from natsort import natsorted
39+
from natsort import natsorted # type: ignore
40+
from ruamel.yaml import YAML
4041

4142
# this package
4243
import repo_helper
@@ -223,6 +224,7 @@
223224
"tox_unmanaged",
224225
"standalone_contrib_guide",
225226
"assignee",
227+
"YamlEditor",
226228
]
227229

228230

@@ -355,3 +357,97 @@ def dump_schema() -> Dict[str, Any]:
355357
print(f"Wrote schema to {schema_file}")
356358

357359
return schema
360+
361+
362+
class YamlEditor(YAML):
363+
"""
364+
Class to read, dump and edit YAML files.
365+
"""
366+
367+
width: Optional[int] # type: ignore
368+
369+
#: Whether to preserve quotes when writing to file.
370+
preserve_quotes: Optional[bool] # type: ignore
371+
372+
#: Whether to include an explicit start to the document when writing to file.
373+
explicit_start: Optional[bool] # type: ignore
374+
375+
def __init__(self, **kwargs):
376+
super().__init__(**kwargs)
377+
378+
self.indent(offset=1)
379+
self.width = 4096
380+
self.preserve_quotes = True
381+
382+
def load_file(self, filename: PathLike) -> Union[Dict, List]:
383+
"""
384+
Load the given YAML file and return its contents.
385+
386+
:param filename:
387+
"""
388+
389+
filename = PathPlus(filename)
390+
return self.load(filename.read_text())
391+
392+
def dump_to_file(self, data: Union[MutableMapping, Sequence], filename: PathLike, mode: str = 'w'):
393+
"""
394+
Dump the given data to the specified file.
395+
396+
:param data:
397+
:param filename:
398+
:param mode:
399+
"""
400+
401+
# TODO: dump to StringIO and use write_clean
402+
403+
explicit_start = self.explicit_start
404+
405+
try:
406+
filename = PathPlus(filename)
407+
408+
with filename.open(mode) as fp:
409+
410+
if 'w' in mode:
411+
self.explicit_start = True
412+
elif 'a' in mode:
413+
self.explicit_start = False
414+
fp.write('\n')
415+
416+
self.dump(data, fp)
417+
418+
finally:
419+
self.explicit_start = explicit_start
420+
421+
def update_key(
422+
self,
423+
filename: PathLike,
424+
key: str,
425+
new_value: Union[MutableMapping, Sequence, Set, str, float],
426+
*,
427+
sort: bool = False,
428+
):
429+
"""
430+
Set ``key`` in ``filename`` to ``new_value``.
431+
432+
:param filename:
433+
:param key:
434+
:param new_value:
435+
:param sort: Whether to sort the updated value.
436+
"""
437+
data = self.load_file(filename)
438+
439+
if sort:
440+
sort_func = natsorted
441+
else:
442+
443+
def sort_func(values):
444+
if isinstance(values, Set):
445+
return list(values)
446+
else:
447+
return values
448+
449+
if key in data:
450+
data[key] = sort_func({*data[key], *new_value}) # type: ignore
451+
self.dump_to_file(data, filename, mode='w')
452+
else:
453+
self.dump_to_file({key: sort_func(new_value)}, filename, mode='a')

0 commit comments

Comments
 (0)