etlplus 0.16.10__py3-none-any.whl → 0.17.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. etlplus/file/README.md +33 -0
  2. etlplus/file/_imports.py +35 -20
  3. etlplus/file/_io.py +138 -15
  4. etlplus/file/_r.py +48 -0
  5. etlplus/file/_sql.py +224 -0
  6. etlplus/file/accdb.py +7 -6
  7. etlplus/file/arrow.py +29 -10
  8. etlplus/file/avro.py +13 -10
  9. etlplus/file/bson.py +94 -10
  10. etlplus/file/cbor.py +29 -17
  11. etlplus/file/cfg.py +7 -6
  12. etlplus/file/conf.py +7 -6
  13. etlplus/file/core.py +1 -1
  14. etlplus/file/csv.py +8 -7
  15. etlplus/file/dat.py +52 -11
  16. etlplus/file/dta.py +36 -16
  17. etlplus/file/duckdb.py +72 -11
  18. etlplus/file/enums.py +29 -0
  19. etlplus/file/feather.py +15 -30
  20. etlplus/file/fwf.py +44 -10
  21. etlplus/file/gz.py +12 -7
  22. etlplus/file/hbs.py +7 -6
  23. etlplus/file/hdf5.py +71 -8
  24. etlplus/file/ini.py +60 -17
  25. etlplus/file/ion.py +7 -6
  26. etlplus/file/jinja2.py +7 -6
  27. etlplus/file/json.py +10 -11
  28. etlplus/file/log.py +7 -6
  29. etlplus/file/mat.py +7 -6
  30. etlplus/file/mdb.py +7 -6
  31. etlplus/file/msgpack.py +27 -15
  32. etlplus/file/mustache.py +7 -6
  33. etlplus/file/nc.py +69 -11
  34. etlplus/file/ndjson.py +10 -6
  35. etlplus/file/numbers.py +7 -6
  36. etlplus/file/ods.py +48 -11
  37. etlplus/file/orc.py +15 -30
  38. etlplus/file/parquet.py +10 -6
  39. etlplus/file/pb.py +36 -24
  40. etlplus/file/pbf.py +7 -6
  41. etlplus/file/properties.py +44 -18
  42. etlplus/file/proto.py +24 -18
  43. etlplus/file/psv.py +12 -11
  44. etlplus/file/rda.py +57 -15
  45. etlplus/file/rds.py +50 -14
  46. etlplus/file/sas7bdat.py +26 -16
  47. etlplus/file/sav.py +34 -16
  48. etlplus/file/sqlite.py +70 -10
  49. etlplus/file/stub.py +8 -6
  50. etlplus/file/sylk.py +7 -6
  51. etlplus/file/tab.py +13 -13
  52. etlplus/file/toml.py +56 -17
  53. etlplus/file/tsv.py +8 -7
  54. etlplus/file/txt.py +10 -7
  55. etlplus/file/vm.py +7 -6
  56. etlplus/file/wks.py +7 -6
  57. etlplus/file/xls.py +8 -5
  58. etlplus/file/xlsm.py +48 -10
  59. etlplus/file/xlsx.py +10 -6
  60. etlplus/file/xml.py +11 -9
  61. etlplus/file/xpt.py +46 -10
  62. etlplus/file/yaml.py +10 -11
  63. etlplus/file/zip.py +10 -5
  64. etlplus/file/zsav.py +7 -6
  65. {etlplus-0.16.10.dist-info → etlplus-0.17.3.dist-info}/METADATA +44 -26
  66. {etlplus-0.16.10.dist-info → etlplus-0.17.3.dist-info}/RECORD +70 -68
  67. {etlplus-0.16.10.dist-info → etlplus-0.17.3.dist-info}/WHEEL +0 -0
  68. {etlplus-0.16.10.dist-info → etlplus-0.17.3.dist-info}/entry_points.txt +0 -0
  69. {etlplus-0.16.10.dist-info → etlplus-0.17.3.dist-info}/licenses/LICENSE +0 -0
  70. {etlplus-0.16.10.dist-info → etlplus-0.17.3.dist-info}/top_level.txt +0 -0
etlplus/file/txt.py CHANGED
@@ -16,11 +16,12 @@ Notes
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- from pathlib import Path
20
-
21
19
  from ..types import JSONData
22
20
  from ..types import JSONList
21
+ from ..types import StrPath
23
22
  from ..utils import count_records
23
+ from ._io import coerce_path
24
+ from ._io import ensure_parent_dir
24
25
  from ._io import normalize_records
25
26
 
26
27
  # SECTION: EXPORTS ========================================================== #
@@ -37,14 +38,14 @@ __all__ = [
37
38
 
38
39
 
39
40
  def read(
40
- path: Path,
41
+ path: StrPath,
41
42
  ) -> JSONList:
42
43
  """
43
44
  Read TXT content from *path*.
44
45
 
45
46
  Parameters
46
47
  ----------
47
- path : Path
48
+ path : StrPath
48
49
  Path to the TXT file on disk.
49
50
 
50
51
  Returns
@@ -52,6 +53,7 @@ def read(
52
53
  JSONList
53
54
  The list of dictionaries read from the TXT file.
54
55
  """
56
+ path = coerce_path(path)
55
57
  rows: JSONList = []
56
58
  with path.open('r', encoding='utf-8') as handle:
57
59
  for line in handle:
@@ -63,7 +65,7 @@ def read(
63
65
 
64
66
 
65
67
  def write(
66
- path: Path,
68
+ path: StrPath,
67
69
  data: JSONData,
68
70
  ) -> int:
69
71
  """
@@ -71,7 +73,7 @@ def write(
71
73
 
72
74
  Parameters
73
75
  ----------
74
- path : Path
76
+ path : StrPath
75
77
  Path to the TXT file on disk.
76
78
  data : JSONData
77
79
  Data to write. Expects ``{'text': '...'} `` or a list of those.
@@ -87,12 +89,13 @@ def write(
87
89
  If any item in *data* is not a dictionary or if any dictionary
88
90
  does not contain a ``'text'`` key.
89
91
  """
92
+ path = coerce_path(path)
90
93
  rows = normalize_records(data, 'TXT')
91
94
 
92
95
  if not rows:
93
96
  return 0
94
97
 
95
- path.parent.mkdir(parents=True, exist_ok=True)
98
+ ensure_parent_dir(path)
96
99
  with path.open('w', encoding='utf-8') as handle:
97
100
  for row in rows:
98
101
  if 'text' not in row:
etlplus/file/vm.py CHANGED
@@ -19,11 +19,11 @@ Notes
19
19
 
20
20
  from __future__ import annotations
21
21
 
22
- from pathlib import Path
23
-
24
22
  from ..types import JSONData
25
23
  from ..types import JSONList
24
+ from ..types import StrPath
26
25
  from . import stub
26
+ from ._io import coerce_path
27
27
 
28
28
  # SECTION: EXPORTS ========================================================== #
29
29
 
@@ -39,14 +39,14 @@ __all__ = [
39
39
 
40
40
 
41
41
  def read(
42
- path: Path,
42
+ path: StrPath,
43
43
  ) -> JSONList:
44
44
  """
45
45
  Read VM content from *path*.
46
46
 
47
47
  Parameters
48
48
  ----------
49
- path : Path
49
+ path : StrPath
50
50
  Path to the VM file on disk.
51
51
 
52
52
  Returns
@@ -58,7 +58,7 @@ def read(
58
58
 
59
59
 
60
60
  def write(
61
- path: Path,
61
+ path: StrPath,
62
62
  data: JSONData,
63
63
  ) -> int:
64
64
  """
@@ -66,7 +66,7 @@ def write(
66
66
 
67
67
  Parameters
68
68
  ----------
69
- path : Path
69
+ path : StrPath
70
70
  Path to the VM file on disk.
71
71
  data : JSONData
72
72
  Data to write as VM file. Should be a list of dictionaries or a single
@@ -77,4 +77,5 @@ def write(
77
77
  int
78
78
  The number of rows written to the VM file.
79
79
  """
80
+ path = coerce_path(path)
80
81
  return stub.write(path, data, format_name='VM')
etlplus/file/wks.py CHANGED
@@ -18,11 +18,11 @@ Notes
18
18
 
19
19
  from __future__ import annotations
20
20
 
21
- from pathlib import Path
22
-
23
21
  from ..types import JSONData
24
22
  from ..types import JSONList
23
+ from ..types import StrPath
25
24
  from . import stub
25
+ from ._io import coerce_path
26
26
 
27
27
  # SECTION: EXPORTS ========================================================== #
28
28
 
@@ -38,14 +38,14 @@ __all__ = [
38
38
 
39
39
 
40
40
  def read(
41
- path: Path,
41
+ path: StrPath,
42
42
  ) -> JSONList:
43
43
  """
44
44
  Read WKS content from *path*.
45
45
 
46
46
  Parameters
47
47
  ----------
48
- path : Path
48
+ path : StrPath
49
49
  Path to the WKS file on disk.
50
50
 
51
51
  Returns
@@ -57,7 +57,7 @@ def read(
57
57
 
58
58
 
59
59
  def write(
60
- path: Path,
60
+ path: StrPath,
61
61
  data: JSONData,
62
62
  ) -> int:
63
63
  """
@@ -65,7 +65,7 @@ def write(
65
65
 
66
66
  Parameters
67
67
  ----------
68
- path : Path
68
+ path : StrPath
69
69
  Path to the WKS file on disk.
70
70
  data : JSONData
71
71
  Data to write as WKS file. Should be a list of dictionaries or a
@@ -76,4 +76,5 @@ def write(
76
76
  int
77
77
  The number of rows written to the WKS file.
78
78
  """
79
+ path = coerce_path(path)
79
80
  return stub.write(path, data, format_name='WKS')
etlplus/file/xls.py CHANGED
@@ -6,12 +6,13 @@ Helpers for reading Excel XLS files (write is not supported).
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- from pathlib import Path
10
9
  from typing import cast
11
10
 
12
11
  from ..types import JSONData
13
12
  from ..types import JSONList
13
+ from ..types import StrPath
14
14
  from ._imports import get_pandas
15
+ from ._io import coerce_path
15
16
 
16
17
  # SECTION: EXPORTS ========================================================== #
17
18
 
@@ -27,14 +28,14 @@ __all__ = [
27
28
 
28
29
 
29
30
  def read(
30
- path: Path,
31
+ path: StrPath,
31
32
  ) -> JSONList:
32
33
  """
33
34
  Read XLS content from *path*.
34
35
 
35
36
  Parameters
36
37
  ----------
37
- path : Path
38
+ path : StrPath
38
39
  Path to the XLS file on disk.
39
40
 
40
41
  Returns
@@ -47,6 +48,7 @@ def read(
47
48
  ImportError
48
49
  If the optional dependency "xlrd" is not installed.
49
50
  """
51
+ path = coerce_path(path)
50
52
  pandas = get_pandas('XLS')
51
53
  try:
52
54
  frame = pandas.read_excel(path, engine='xlrd')
@@ -59,7 +61,7 @@ def read(
59
61
 
60
62
 
61
63
  def write(
62
- path: Path,
64
+ path: StrPath,
63
65
  data: JSONData,
64
66
  ) -> int:
65
67
  """
@@ -71,7 +73,7 @@ def write(
71
73
 
72
74
  Parameters
73
75
  ----------
74
- path : Path
76
+ path : StrPath
75
77
  Path to the XLS file on disk.
76
78
  data : JSONData
77
79
  Data to write.
@@ -86,4 +88,5 @@ def write(
86
88
  RuntimeError
87
89
  If XLS writing is attempted.
88
90
  """
91
+ path = coerce_path(path)
89
92
  raise RuntimeError('XLS write is not supported; use XLSX instead')
etlplus/file/xlsm.py CHANGED
@@ -1,8 +1,8 @@
1
1
  """
2
2
  :mod:`etlplus.file.xlsm` module.
3
3
 
4
- Stub helpers for reading/writing Microsoft Excel Macro-Enabled (XLSM)
5
- spreadsheet files (not implemented yet).
4
+ Helpers for reading/writing Microsoft Excel Macro-Enabled (XLSM)
5
+ spreadsheet files.
6
6
 
7
7
  Notes
8
8
  -----
@@ -19,11 +19,15 @@ Notes
19
19
 
20
20
  from __future__ import annotations
21
21
 
22
- from pathlib import Path
22
+ from typing import cast
23
23
 
24
24
  from ..types import JSONData
25
25
  from ..types import JSONList
26
- from . import stub
26
+ from ..types import StrPath
27
+ from ._imports import get_pandas
28
+ from ._io import coerce_path
29
+ from ._io import ensure_parent_dir
30
+ from ._io import normalize_records
27
31
 
28
32
  # SECTION: EXPORTS ========================================================== #
29
33
 
@@ -39,26 +43,40 @@ __all__ = [
39
43
 
40
44
 
41
45
  def read(
42
- path: Path,
46
+ path: StrPath,
43
47
  ) -> JSONList:
44
48
  """
45
49
  Read XLSM content from *path*.
46
50
 
47
51
  Parameters
48
52
  ----------
49
- path : Path
53
+ path : StrPath
50
54
  Path to the XLSM file on disk.
51
55
 
52
56
  Returns
53
57
  -------
54
58
  JSONList
55
59
  The list of dictionaries read from the XLSM file.
60
+
61
+ Raises
62
+ ------
63
+ ImportError
64
+ If optional dependencies for XLSM support are missing.
56
65
  """
57
- return stub.read(path, format_name='XLSM')
66
+ path = coerce_path(path)
67
+ pandas = get_pandas('XLSM')
68
+ try:
69
+ frame = pandas.read_excel(path)
70
+ except ImportError as e: # pragma: no cover
71
+ raise ImportError(
72
+ 'XLSM support requires optional dependency "openpyxl".\n'
73
+ 'Install with: pip install openpyxl',
74
+ ) from e
75
+ return cast(JSONList, frame.to_dict(orient='records'))
58
76
 
59
77
 
60
78
  def write(
61
- path: Path,
79
+ path: StrPath,
62
80
  data: JSONData,
63
81
  ) -> int:
64
82
  """
@@ -66,7 +84,7 @@ def write(
66
84
 
67
85
  Parameters
68
86
  ----------
69
- path : Path
87
+ path : StrPath
70
88
  Path to the XLSM file on disk.
71
89
  data : JSONData
72
90
  Data to write as XLSM file. Should be a list of dictionaries or a
@@ -76,5 +94,25 @@ def write(
76
94
  -------
77
95
  int
78
96
  The number of rows written to the XLSM file.
97
+
98
+ Raises
99
+ ------
100
+ ImportError
101
+ If optional dependencies for XLSM support are missing.
79
102
  """
80
- return stub.write(path, data, format_name='XLSM')
103
+ path = coerce_path(path)
104
+ records = normalize_records(data, 'XLSM')
105
+ if not records:
106
+ return 0
107
+
108
+ pandas = get_pandas('XLSM')
109
+ ensure_parent_dir(path)
110
+ frame = pandas.DataFrame.from_records(records)
111
+ try:
112
+ frame.to_excel(path, index=False)
113
+ except ImportError as e: # pragma: no cover
114
+ raise ImportError(
115
+ 'XLSM support requires optional dependency "openpyxl".\n'
116
+ 'Install with: pip install openpyxl',
117
+ ) from e
118
+ return len(records)
etlplus/file/xlsx.py CHANGED
@@ -6,12 +6,14 @@ Helpers for reading/writing Excel XLSX files.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- from pathlib import Path
10
9
  from typing import cast
11
10
 
12
11
  from ..types import JSONData
13
12
  from ..types import JSONList
13
+ from ..types import StrPath
14
14
  from ._imports import get_pandas
15
+ from ._io import coerce_path
16
+ from ._io import ensure_parent_dir
15
17
  from ._io import normalize_records
16
18
 
17
19
  # SECTION: EXPORTS ========================================================== #
@@ -28,14 +30,14 @@ __all__ = [
28
30
 
29
31
 
30
32
  def read(
31
- path: Path,
33
+ path: StrPath,
32
34
  ) -> JSONList:
33
35
  """
34
36
  Read XLSX content from *path*.
35
37
 
36
38
  Parameters
37
39
  ----------
38
- path : Path
40
+ path : StrPath
39
41
  Path to the XLSX file on disk.
40
42
 
41
43
  Returns
@@ -48,6 +50,7 @@ def read(
48
50
  ImportError
49
51
  If optional dependencies for XLSX support are missing.
50
52
  """
53
+ path = coerce_path(path)
51
54
  pandas = get_pandas('XLSX')
52
55
  try:
53
56
  frame = pandas.read_excel(path)
@@ -60,7 +63,7 @@ def read(
60
63
 
61
64
 
62
65
  def write(
63
- path: Path,
66
+ path: StrPath,
64
67
  data: JSONData,
65
68
  ) -> int:
66
69
  """
@@ -68,7 +71,7 @@ def write(
68
71
 
69
72
  Parameters
70
73
  ----------
71
- path : Path
74
+ path : StrPath
72
75
  Path to the XLSX file on disk.
73
76
  data : JSONData
74
77
  Data to write.
@@ -83,12 +86,13 @@ def write(
83
86
  ImportError
84
87
  If optional dependencies for XLSX support are missing.
85
88
  """
89
+ path = coerce_path(path)
86
90
  records = normalize_records(data, 'XLSX')
87
91
  if not records:
88
92
  return 0
89
93
 
90
94
  pandas = get_pandas('XLSX')
91
- path.parent.mkdir(parents=True, exist_ok=True)
95
+ ensure_parent_dir(path)
92
96
  frame = pandas.DataFrame.from_records(records)
93
97
  try:
94
98
  frame.to_excel(path, index=False)
etlplus/file/xml.py CHANGED
@@ -18,12 +18,14 @@ Notes
18
18
  from __future__ import annotations
19
19
 
20
20
  import xml.etree.ElementTree as ET
21
- from pathlib import Path
22
21
  from typing import Any
23
22
 
24
23
  from ..types import JSONData
25
24
  from ..types import JSONDict
25
+ from ..types import StrPath
26
26
  from ..utils import count_records
27
+ from ._io import coerce_path
28
+ from ._io import ensure_parent_dir
27
29
 
28
30
  # SECTION: EXPORTS ========================================================== #
29
31
 
@@ -124,10 +126,7 @@ def _element_to_dict(
124
126
  result[tag] = child_data
125
127
 
126
128
  for key, value in element.attrib.items():
127
- if key in result:
128
- result[f'@{key}'] = value
129
- else:
130
- result[key] = value
129
+ result[f'@{key}'] = value
131
130
  return result
132
131
 
133
132
 
@@ -135,14 +134,14 @@ def _element_to_dict(
135
134
 
136
135
 
137
136
  def read(
138
- path: Path,
137
+ path: StrPath,
139
138
  ) -> JSONDict:
140
139
  """
141
140
  Read XML content from *path*.
142
141
 
143
142
  Parameters
144
143
  ----------
145
- path : Path
144
+ path : StrPath
146
145
  Path to the XML file on disk.
147
146
 
148
147
  Returns
@@ -150,6 +149,7 @@ def read(
150
149
  JSONDict
151
150
  Nested dictionary representation of the XML file.
152
151
  """
152
+ path = coerce_path(path)
153
153
  tree = ET.parse(path)
154
154
  root = tree.getroot()
155
155
 
@@ -157,7 +157,7 @@ def read(
157
157
 
158
158
 
159
159
  def write(
160
- path: Path,
160
+ path: StrPath,
161
161
  data: JSONData,
162
162
  *,
163
163
  root_tag: str,
@@ -167,7 +167,7 @@ def write(
167
167
 
168
168
  Parameters
169
169
  ----------
170
- path : Path
170
+ path : StrPath
171
171
  Path to the XML file on disk.
172
172
  data : JSONData
173
173
  Data to write as XML.
@@ -179,6 +179,7 @@ def write(
179
179
  int
180
180
  The number of records written to the XML file.
181
181
  """
182
+ path = coerce_path(path)
182
183
  if isinstance(data, dict) and len(data) == 1:
183
184
  root_name, payload = next(iter(data.items()))
184
185
  root_element = _dict_to_element(str(root_name), payload)
@@ -186,6 +187,7 @@ def write(
186
187
  root_element = _dict_to_element(root_tag, data)
187
188
 
188
189
  tree = ET.ElementTree(root_element)
190
+ ensure_parent_dir(path)
189
191
  tree.write(path, encoding='utf-8', xml_declaration=True)
190
192
 
191
193
  return count_records(data)
etlplus/file/xpt.py CHANGED
@@ -1,8 +1,7 @@
1
1
  """
2
2
  :mod:`etlplus.file.xpt` module.
3
3
 
4
- Stub helpers for reading/writing SAS Transport (XPT) files (not implemented
5
- yet).
4
+ Helpers for reading/writing SAS Transport (XPT) files.
6
5
 
7
6
  Notes
8
7
  -----
@@ -19,11 +18,16 @@ Notes
19
18
 
20
19
  from __future__ import annotations
21
20
 
22
- from pathlib import Path
21
+ from typing import cast
23
22
 
24
23
  from ..types import JSONData
25
24
  from ..types import JSONList
26
- from . import stub
25
+ from ..types import StrPath
26
+ from ._imports import get_dependency
27
+ from ._imports import get_pandas
28
+ from ._io import coerce_path
29
+ from ._io import ensure_parent_dir
30
+ from ._io import normalize_records
27
31
 
28
32
  # SECTION: EXPORTS ========================================================== #
29
33
 
@@ -39,14 +43,14 @@ __all__ = [
39
43
 
40
44
 
41
45
  def read(
42
- path: Path,
46
+ path: StrPath,
43
47
  ) -> JSONList:
44
48
  """
45
49
  Read XPT content from *path*.
46
50
 
47
51
  Parameters
48
52
  ----------
49
- path : Path
53
+ path : StrPath
50
54
  Path to the XPT file on disk.
51
55
 
52
56
  Returns
@@ -54,11 +58,22 @@ def read(
54
58
  JSONList
55
59
  The list of dictionaries read from the XPT file.
56
60
  """
57
- return stub.read(path, format_name='XPT')
61
+ path = coerce_path(path)
62
+ pandas = get_pandas('XPT')
63
+ pyreadstat = get_dependency('pyreadstat', format_name='XPT')
64
+ reader = getattr(pyreadstat, 'read_xport', None)
65
+ if reader is not None:
66
+ frame, _meta = reader(str(path))
67
+ return cast(JSONList, frame.to_dict(orient='records'))
68
+ try:
69
+ frame = pandas.read_sas(path, format='xport')
70
+ except TypeError:
71
+ frame = pandas.read_sas(path)
72
+ return cast(JSONList, frame.to_dict(orient='records'))
58
73
 
59
74
 
60
75
  def write(
61
- path: Path,
76
+ path: StrPath,
62
77
  data: JSONData,
63
78
  ) -> int:
64
79
  """
@@ -66,7 +81,7 @@ def write(
66
81
 
67
82
  Parameters
68
83
  ----------
69
- path : Path
84
+ path : StrPath
70
85
  Path to the XPT file on disk.
71
86
  data : JSONData
72
87
  Data to write as XPT file. Should be a list of dictionaries or a
@@ -76,5 +91,26 @@ def write(
76
91
  -------
77
92
  int
78
93
  The number of rows written to the XPT file.
94
+
95
+ Raises
96
+ ------
97
+ ImportError
98
+ If "pyreadstat" is not installed with write support.
79
99
  """
80
- return stub.write(path, data, format_name='XPT')
100
+ path = coerce_path(path)
101
+ records = normalize_records(data, 'XPT')
102
+ if not records:
103
+ return 0
104
+
105
+ pandas = get_pandas('XPT')
106
+ pyreadstat = get_dependency('pyreadstat', format_name='XPT')
107
+ writer = getattr(pyreadstat, 'write_xport', None)
108
+ if writer is None:
109
+ raise ImportError(
110
+ 'XPT write support requires "pyreadstat" with write_xport().',
111
+ )
112
+
113
+ ensure_parent_dir(path)
114
+ frame = pandas.DataFrame.from_records(records)
115
+ writer(frame, str(path))
116
+ return len(records)
etlplus/file/yaml.py CHANGED
@@ -17,12 +17,13 @@ Notes
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from pathlib import Path
21
-
22
20
  from ..types import JSONData
21
+ from ..types import StrPath
23
22
  from ..utils import count_records
24
23
  from ._imports import get_yaml
24
+ from ._io import coerce_path
25
25
  from ._io import coerce_record_payload
26
+ from ._io import ensure_parent_dir
26
27
 
27
28
  # SECTION: EXPORTS ========================================================== #
28
29
 
@@ -38,7 +39,7 @@ __all__ = [
38
39
 
39
40
 
40
41
  def read(
41
- path: Path,
42
+ path: StrPath,
42
43
  ) -> JSONData:
43
44
  """
44
45
  Read YAML content from *path*.
@@ -47,19 +48,15 @@ def read(
47
48
 
48
49
  Parameters
49
50
  ----------
50
- path : Path
51
+ path : StrPath
51
52
  Path to the YAML file on disk.
52
53
 
53
54
  Returns
54
55
  -------
55
56
  JSONData
56
57
  The structured data read from the YAML file.
57
-
58
- Raises
59
- ------
60
- TypeError
61
- If the YAML root is not an object or an array of objects.
62
58
  """
59
+ path = coerce_path(path)
63
60
  with path.open('r', encoding='utf-8') as handle:
64
61
  loaded = get_yaml().safe_load(handle)
65
62
 
@@ -67,7 +64,7 @@ def read(
67
64
 
68
65
 
69
66
  def write(
70
- path: Path,
67
+ path: StrPath,
71
68
  data: JSONData,
72
69
  ) -> int:
73
70
  """
@@ -75,7 +72,7 @@ def write(
75
72
 
76
73
  Parameters
77
74
  ----------
78
- path : Path
75
+ path : StrPath
79
76
  Path to the YAML file on disk.
80
77
  data : JSONData
81
78
  Data to write as YAML.
@@ -85,6 +82,8 @@ def write(
85
82
  int
86
83
  The number of records written.
87
84
  """
85
+ path = coerce_path(path)
86
+ ensure_parent_dir(path)
88
87
  with path.open('w', encoding='utf-8') as handle:
89
88
  get_yaml().safe_dump(
90
89
  data,