Skip to content

Commit cc058ce

Browse files
committed
Add new functions to PathPlus to read and write lines of text and JSON data.
1 parent 9efa262 commit cc058ce

File tree

2 files changed

+210
-1
lines changed

2 files changed

+210
-1
lines changed

domdf_python_tools/paths.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@
3535
#
3636

3737
# stdlib
38+
import json
3839
import os
3940
import pathlib
4041
import shutil
4142
import stat
42-
from typing import IO, Any, Callable, Optional
43+
import types
44+
from typing import IO, Any, Callable, Iterable, List, Optional
4345

4446
# this package
4547
from domdf_python_tools.typing import PathLike
@@ -403,6 +405,26 @@ def write_text(
403405

404406
return super().write_text(data, encoding=encoding, errors=errors)
405407

408+
def write_lines(
409+
self,
410+
data: Iterable[str],
411+
encoding: Optional[str] = "UTF-8",
412+
errors: Optional[str] = None,
413+
) -> None:
414+
"""
415+
Open the file in text mode, write the given list of lines to it without trailing spaces,
416+
and close the file.
417+
418+
:param data:
419+
:type data: str
420+
:param encoding: The encoding to write to the file using.
421+
:param errors:
422+
423+
.. versionadded:: 0.5.0
424+
"""
425+
426+
return self.write_clean("\n".join(data), encoding=encoding, errors=errors)
427+
406428
def read_text(
407429
self,
408430
encoding: Optional[str] = "UTF-8",
@@ -421,6 +443,25 @@ def read_text(
421443

422444
return super().read_text(encoding=encoding, errors=errors)
423445

446+
def read_lines(
447+
self,
448+
encoding: Optional[str] = "UTF-8",
449+
errors: Optional[str] = None,
450+
) -> List[str]:
451+
"""
452+
Open the file in text mode, return a list containing the lines in the file,
453+
and close the file.
454+
455+
:param encoding: The encoding to write to the file using.
456+
:param errors:
457+
458+
:return: The content of the file.
459+
460+
.. versionadded:: 0.5.0
461+
"""
462+
463+
return self.read_text(encoding=encoding, errors=errors).split("\n")
464+
424465
def open(
425466
self,
426467
mode: str = "r",
@@ -452,6 +493,60 @@ def open(
452493
encoding = None
453494
return super().open(mode, buffering=buffering, encoding=encoding, errors=errors, newline=newline)
454495

496+
def dump_json(
497+
self,
498+
data: Any,
499+
encoding: Optional[str] = "UTF-8",
500+
errors: Optional[str] = None,
501+
json_library: types.ModuleType = json,
502+
**kwargs,
503+
) -> int:
504+
"""
505+
Dump ``data`` to the file.
506+
507+
:param data: The object to serialise to JSON.
508+
:param encoding: The encoding to write to the file using.
509+
:param errors:
510+
:param json_library: The JSON serialisation library to use.
511+
:param kwargs: Keyword arguments to pass to the JSON serialisation function.
512+
513+
.. versionadded:: 0.5.0
514+
"""
515+
516+
return self.write_text(
517+
json_library.dumps(data, **kwargs), # type: ignore
518+
encoding=encoding,
519+
errors=errors,
520+
)
521+
522+
def load_json(
523+
self,
524+
encoding: Optional[str] = "UTF-8",
525+
errors: Optional[str] = None,
526+
json_library: types.ModuleType = json,
527+
**kwargs,
528+
) -> Any:
529+
"""
530+
Load JSON data from the file.
531+
532+
:param encoding: The encoding to write to the file using.
533+
:param errors:
534+
:param json_library: The JSON serialisation library to use.
535+
:param kwargs: Keyword arguments to pass to the JSON deserialisation function.
536+
537+
:return: The deserialised JSON data.
538+
539+
.. versionadded:: 0.5.0
540+
"""
541+
542+
return json_library.loads( # type: ignore
543+
self.read_text(
544+
encoding=encoding,
545+
errors=errors,
546+
),
547+
**kwargs,
548+
)
549+
455550

456551
class PosixPathPlus(PathPlus, pathlib.PurePosixPath):
457552
"""Path subclass for non-Windows systems.

tests/test_paths.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import shutil
1515
import sys
1616
from tempfile import TemporaryDirectory
17+
from textwrap import dedent
1718

1819
# 3rd party
1920
import pytest
@@ -486,3 +487,116 @@ def test_copytree_exists_stdlib():
486487

487488
with pytest.raises(FileExistsError, match=r".*[\\/]dest"):
488489
shutil.copytree(srcdir, destdir)
490+
491+
492+
def test_write_lines():
493+
with TemporaryDirectory() as tmpdir:
494+
tmpdir_p = PathPlus(tmpdir)
495+
496+
tmp_file = tmpdir_p / "test.txt"
497+
498+
contents = [
499+
"this",
500+
"is",
501+
"a",
502+
"list",
503+
"of",
504+
"words",
505+
"to",
506+
"write",
507+
"to",
508+
"the",
509+
"file",
510+
]
511+
512+
tmp_file.write_lines(contents)
513+
514+
assert tmp_file.read_text(
515+
) == dedent("""\
516+
this
517+
is
518+
a
519+
list
520+
of
521+
words
522+
to
523+
write
524+
to
525+
the
526+
file
527+
""")
528+
529+
530+
def test_read_lines(tmpdir):
531+
tmpdir_p = PathPlus(tmpdir)
532+
533+
tmp_file = tmpdir_p / "test.txt"
534+
535+
contents = dedent("""\
536+
this
537+
is
538+
a
539+
list
540+
of
541+
words
542+
to
543+
write
544+
to
545+
the
546+
file
547+
""")
548+
549+
tmp_file.write_text(contents)
550+
551+
assert tmp_file.read_lines() == [
552+
"this",
553+
"is",
554+
"a",
555+
"list",
556+
"of",
557+
"words",
558+
"to",
559+
"write",
560+
"to",
561+
"the",
562+
"file",
563+
'',
564+
]
565+
566+
567+
def test_dump_json(tmpdir):
568+
tmpdir_p = PathPlus(tmpdir)
569+
570+
tmp_file = tmpdir_p / "test.txt"
571+
572+
tmp_file.dump_json({"key": "value", "int": 1234, "float": 12.34})
573+
574+
assert tmp_file.read_text() == '{"key": "value", "int": 1234, "float": 12.34}'
575+
576+
tmp_file.dump_json({"key": "value", "int": 1234, "float": 12.34}, indent=2)
577+
578+
assert tmp_file.read_text() == dedent("""\
579+
{
580+
"key": "value",
581+
"int": 1234,
582+
"float": 12.34
583+
}""")
584+
585+
586+
def test_load_json(tmpdir):
587+
tmpdir_p = PathPlus(tmpdir)
588+
589+
tmp_file = tmpdir_p / "test.txt"
590+
591+
tmp_file.write_text('{"key": "value", "int": 1234, "float": 12.34}')
592+
593+
assert tmp_file.load_json() == {"key": "value", "int": 1234, "float": 12.34}
594+
595+
tmp_file.write_text(dedent("""\
596+
{
597+
"key": "value",
598+
"int": 1234,
599+
"float": 12.34
600+
}"""))
601+
602+
assert tmp_file.load_json() == {"key": "value", "int": 1234, "float": 12.34}

0 commit comments

Comments
 (0)