etlplus 0.17.2__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 (68) hide show
  1. etlplus/file/_imports.py +35 -20
  2. etlplus/file/_io.py +138 -15
  3. etlplus/file/_r.py +48 -0
  4. etlplus/file/_sql.py +224 -0
  5. etlplus/file/accdb.py +7 -6
  6. etlplus/file/arrow.py +13 -24
  7. etlplus/file/avro.py +13 -10
  8. etlplus/file/bson.py +61 -22
  9. etlplus/file/cbor.py +13 -25
  10. etlplus/file/cfg.py +7 -6
  11. etlplus/file/conf.py +7 -6
  12. etlplus/file/core.py +1 -1
  13. etlplus/file/csv.py +8 -7
  14. etlplus/file/dat.py +9 -6
  15. etlplus/file/dta.py +15 -30
  16. etlplus/file/duckdb.py +29 -122
  17. etlplus/file/feather.py +15 -30
  18. etlplus/file/fwf.py +16 -14
  19. etlplus/file/gz.py +12 -7
  20. etlplus/file/hbs.py +7 -6
  21. etlplus/file/hdf5.py +31 -6
  22. etlplus/file/ini.py +17 -24
  23. etlplus/file/ion.py +7 -6
  24. etlplus/file/jinja2.py +7 -6
  25. etlplus/file/json.py +10 -11
  26. etlplus/file/log.py +7 -6
  27. etlplus/file/mat.py +7 -6
  28. etlplus/file/mdb.py +7 -6
  29. etlplus/file/msgpack.py +13 -25
  30. etlplus/file/mustache.py +7 -6
  31. etlplus/file/nc.py +30 -21
  32. etlplus/file/ndjson.py +10 -6
  33. etlplus/file/numbers.py +7 -6
  34. etlplus/file/ods.py +10 -6
  35. etlplus/file/orc.py +15 -30
  36. etlplus/file/parquet.py +10 -6
  37. etlplus/file/pb.py +22 -23
  38. etlplus/file/pbf.py +7 -6
  39. etlplus/file/properties.py +15 -29
  40. etlplus/file/proto.py +14 -20
  41. etlplus/file/psv.py +8 -7
  42. etlplus/file/rda.py +19 -51
  43. etlplus/file/rds.py +19 -51
  44. etlplus/file/sas7bdat.py +10 -30
  45. etlplus/file/sav.py +13 -24
  46. etlplus/file/sqlite.py +25 -83
  47. etlplus/file/stub.py +8 -6
  48. etlplus/file/sylk.py +7 -6
  49. etlplus/file/tab.py +8 -7
  50. etlplus/file/toml.py +14 -17
  51. etlplus/file/tsv.py +8 -7
  52. etlplus/file/txt.py +10 -7
  53. etlplus/file/vm.py +7 -6
  54. etlplus/file/wks.py +7 -6
  55. etlplus/file/xls.py +8 -5
  56. etlplus/file/xlsm.py +10 -6
  57. etlplus/file/xlsx.py +10 -6
  58. etlplus/file/xml.py +11 -9
  59. etlplus/file/xpt.py +13 -33
  60. etlplus/file/yaml.py +10 -11
  61. etlplus/file/zip.py +10 -5
  62. etlplus/file/zsav.py +7 -6
  63. {etlplus-0.17.2.dist-info → etlplus-0.17.3.dist-info}/METADATA +1 -1
  64. {etlplus-0.17.2.dist-info → etlplus-0.17.3.dist-info}/RECORD +68 -66
  65. {etlplus-0.17.2.dist-info → etlplus-0.17.3.dist-info}/WHEEL +0 -0
  66. {etlplus-0.17.2.dist-info → etlplus-0.17.3.dist-info}/entry_points.txt +0 -0
  67. {etlplus-0.17.2.dist-info → etlplus-0.17.3.dist-info}/licenses/LICENSE +0 -0
  68. {etlplus-0.17.2.dist-info → etlplus-0.17.3.dist-info}/top_level.txt +0 -0
etlplus/file/hdf5.py CHANGED
@@ -19,13 +19,14 @@ Notes
19
19
 
20
20
  from __future__ import annotations
21
21
 
22
- from pathlib import Path
23
22
  from typing import cast
24
23
 
25
24
  from ..types import JSONData
26
25
  from ..types import JSONList
26
+ from ..types import StrPath
27
27
  from . import stub
28
28
  from ._imports import get_pandas
29
+ from ._io import coerce_path
29
30
 
30
31
  # SECTION: EXPORTS ========================================================== #
31
32
 
@@ -46,7 +47,23 @@ DEFAULT_KEY = 'data'
46
47
  # SECTION: INTERNAL FUNCTIONS =============================================== #
47
48
 
48
49
 
49
- def _raise_tables_error(err: ImportError) -> None:
50
+ def _raise_tables_error(
51
+ err: ImportError,
52
+ ) -> None:
53
+ """
54
+ Raise a consistent ImportError for missing PyTables support.
55
+
56
+ Parameters
57
+ ----------
58
+ err : ImportError
59
+ The original ImportError raised when trying to use HDF5 support without
60
+ the required dependency.
61
+
62
+ Raises
63
+ ------
64
+ ImportError
65
+ Consistent ImportError indicating that PyTables is required.
66
+ """
50
67
  raise ImportError(
51
68
  'HDF5 support requires optional dependency "tables".\n'
52
69
  'Install with: pip install tables',
@@ -57,21 +74,28 @@ def _raise_tables_error(err: ImportError) -> None:
57
74
 
58
75
 
59
76
  def read(
60
- path: Path,
77
+ path: StrPath,
61
78
  ) -> JSONList:
62
79
  """
63
80
  Read HDF5 content from *path*.
64
81
 
65
82
  Parameters
66
83
  ----------
67
- path : Path
84
+ path : StrPath
68
85
  Path to the HDF5 file on disk.
69
86
 
70
87
  Returns
71
88
  -------
72
89
  JSONList
73
90
  The list of dictionaries read from the HDF5 file.
91
+
92
+ Raises
93
+ ------
94
+ ValueError
95
+ If multiple datasets are found in the HDF5 file without a clear key to
96
+ use.
74
97
  """
98
+ path = coerce_path(path)
75
99
  pandas = get_pandas('HDF5')
76
100
  try:
77
101
  store = pandas.HDFStore(path)
@@ -96,7 +120,7 @@ def read(
96
120
 
97
121
 
98
122
  def write(
99
- path: Path,
123
+ path: StrPath,
100
124
  data: JSONData,
101
125
  ) -> int:
102
126
  """
@@ -104,7 +128,7 @@ def write(
104
128
 
105
129
  Parameters
106
130
  ----------
107
- path : Path
131
+ path : StrPath
108
132
  Path to the HDF5 file on disk.
109
133
  data : JSONData
110
134
  Data to write as HDF5 file. Should be a list of dictionaries or a
@@ -115,4 +139,5 @@ def write(
115
139
  int
116
140
  The number of rows written to the HDF5 file.
117
141
  """
142
+ path = coerce_path(path)
118
143
  return stub.write(path, data, format_name='HDF5')
etlplus/file/ini.py CHANGED
@@ -20,11 +20,14 @@ Notes
20
20
  from __future__ import annotations
21
21
 
22
22
  import configparser
23
- from pathlib import Path
24
- from typing import Any
25
23
 
26
24
  from ..types import JSONData
27
25
  from ..types import JSONDict
26
+ from ..types import StrPath
27
+ from ._io import coerce_path
28
+ from ._io import ensure_parent_dir
29
+ from ._io import require_dict_payload
30
+ from ._io import stringify_value
28
31
 
29
32
  # SECTION: EXPORTS ========================================================== #
30
33
 
@@ -36,28 +39,18 @@ __all__ = [
36
39
  ]
37
40
 
38
41
 
39
- # SECTION: INTERNAL FUNCTIONS =============================================== #
40
-
41
-
42
- def _stringify(value: Any) -> str:
43
- """Normalize INI values into strings."""
44
- if value is None:
45
- return ''
46
- return str(value)
47
-
48
-
49
42
  # SECTION: FUNCTIONS ======================================================== #
50
43
 
51
44
 
52
45
  def read(
53
- path: Path,
46
+ path: StrPath,
54
47
  ) -> JSONData:
55
48
  """
56
49
  Read INI content from *path*.
57
50
 
58
51
  Parameters
59
52
  ----------
60
- path : Path
53
+ path : StrPath
61
54
  Path to the INI file on disk.
62
55
 
63
56
  Returns
@@ -65,6 +58,7 @@ def read(
65
58
  JSONData
66
59
  The structured data read from the INI file.
67
60
  """
61
+ path = coerce_path(path)
68
62
  parser = configparser.ConfigParser()
69
63
  parser.read(path, encoding='utf-8')
70
64
 
@@ -81,7 +75,7 @@ def read(
81
75
 
82
76
 
83
77
  def write(
84
- path: Path,
78
+ path: StrPath,
85
79
  data: JSONData,
86
80
  ) -> int:
87
81
  """
@@ -89,7 +83,7 @@ def write(
89
83
 
90
84
  Parameters
91
85
  ----------
92
- path : Path
86
+ path : StrPath
93
87
  Path to the INI file on disk.
94
88
  data : JSONData
95
89
  Data to write as INI. Should be a dictionary.
@@ -104,17 +98,16 @@ def write(
104
98
  TypeError
105
99
  If *data* is not a dictionary.
106
100
  """
107
- if isinstance(data, list):
108
- raise TypeError('INI payloads must be a dict')
109
- if not isinstance(data, dict):
110
- raise TypeError('INI payloads must be a dict')
101
+ path = coerce_path(path)
102
+ payload = require_dict_payload(data, format_name='INI')
111
103
 
112
104
  parser = configparser.ConfigParser()
113
- for section, values in data.items():
105
+ for section, values in payload.items():
114
106
  if section == 'DEFAULT':
115
107
  if isinstance(values, dict):
116
108
  parser['DEFAULT'] = {
117
- key: _stringify(value) for key, value in values.items()
109
+ key: stringify_value(value)
110
+ for key, value in values.items()
118
111
  }
119
112
  else:
120
113
  raise TypeError('INI DEFAULT section must be a dict')
@@ -122,10 +115,10 @@ def write(
122
115
  if not isinstance(values, dict):
123
116
  raise TypeError('INI sections must map to dicts')
124
117
  parser[section] = {
125
- key: _stringify(value) for key, value in values.items()
118
+ key: stringify_value(value) for key, value in values.items()
126
119
  }
127
120
 
128
- path.parent.mkdir(parents=True, exist_ok=True)
121
+ ensure_parent_dir(path)
129
122
  with path.open('w', encoding='utf-8', newline='') as handle:
130
123
  parser.write(handle)
131
124
  return 1
etlplus/file/ion.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 ION content from *path*.
45
45
 
46
46
  Parameters
47
47
  ----------
48
- path : Path
48
+ path : StrPath
49
49
  Path to the ION 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 ION file on disk.
70
70
  data : JSONData
71
71
  Data to write as ION. 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 ION file.
78
78
  """
79
+ path = coerce_path(path)
79
80
  return stub.write(path, data, format_name='ION')
etlplus/file/jinja2.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 JINJA2 content from *path*.
46
46
 
47
47
  Parameters
48
48
  ----------
49
- path : Path
49
+ path : StrPath
50
50
  Path to the JINJA2 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 JINJA2 file on disk.
71
71
  data : JSONData
72
72
  Data to write as JINJA2 file. Should be a list of dictionaries or a
@@ -77,4 +77,5 @@ def write(
77
77
  int
78
78
  The number of rows written to the JINJA2 file.
79
79
  """
80
+ path = coerce_path(path)
80
81
  return stub.write(path, data, format_name='JINJA2')
etlplus/file/json.py CHANGED
@@ -19,11 +19,13 @@ Notes
19
19
  from __future__ import annotations
20
20
 
21
21
  import json
22
- from pathlib import Path
23
22
 
24
23
  from ..types import JSONData
24
+ from ..types import StrPath
25
25
  from ..utils import count_records
26
+ from ._io import coerce_path
26
27
  from ._io import coerce_record_payload
28
+ from ._io import ensure_parent_dir
27
29
 
28
30
  # SECTION: EXPORTS ========================================================== #
29
31
 
@@ -39,7 +41,7 @@ __all__ = [
39
41
 
40
42
 
41
43
  def read(
42
- path: Path,
44
+ path: StrPath,
43
45
  ) -> JSONData:
44
46
  """
45
47
  Read JSON content from *path*.
@@ -48,19 +50,15 @@ def read(
48
50
 
49
51
  Parameters
50
52
  ----------
51
- path : Path
53
+ path : StrPath
52
54
  Path to the JSON file on disk.
53
55
 
54
56
  Returns
55
57
  -------
56
58
  JSONData
57
59
  The structured data read from the JSON file.
58
-
59
- Raises
60
- ------
61
- TypeError
62
- If the JSON root is not an object or an array of objects.
63
60
  """
61
+ path = coerce_path(path)
64
62
  with path.open('r', encoding='utf-8') as handle:
65
63
  loaded = json.load(handle)
66
64
 
@@ -68,7 +66,7 @@ def read(
68
66
 
69
67
 
70
68
  def write(
71
- path: Path,
69
+ path: StrPath,
72
70
  data: JSONData,
73
71
  ) -> int:
74
72
  """
@@ -76,7 +74,7 @@ def write(
76
74
 
77
75
  Parameters
78
76
  ----------
79
- path : Path
77
+ path : StrPath
80
78
  Path to the JSON file on disk.
81
79
  data : JSONData
82
80
  Data to serialize as JSON.
@@ -86,7 +84,8 @@ def write(
86
84
  int
87
85
  The number of records written to the JSON file.
88
86
  """
89
- path.parent.mkdir(parents=True, exist_ok=True)
87
+ path = coerce_path(path)
88
+ ensure_parent_dir(path)
90
89
  with path.open('w', encoding='utf-8') as handle:
91
90
  json.dump(
92
91
  data,
etlplus/file/log.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 LOG content from *path*.
45
45
 
46
46
  Parameters
47
47
  ----------
48
- path : Path
48
+ path : StrPath
49
49
  Path to the LOG 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 LOG file on disk.
70
70
  data : JSONData
71
71
  Data to write as LOG. 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 LOG file.
78
78
  """
79
+ path = coerce_path(path)
79
80
  return stub.write(path, data, format_name='LOG')
etlplus/file/mat.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 MAT content from *path*.
45
45
 
46
46
  Parameters
47
47
  ----------
48
- path : Path
48
+ path : StrPath
49
49
  Path to the MAT 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 MAT file on disk.
70
70
  data : JSONData
71
71
  Data to write as MAT 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 MAT file.
78
78
  """
79
+ path = coerce_path(path)
79
80
  return stub.write(path, data, format_name='MAT')
etlplus/file/mdb.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 CSV content from *path*.
46
46
 
47
47
  Parameters
48
48
  ----------
49
- path : Path
49
+ path : StrPath
50
50
  Path to the CSV 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 CSV file on disk.
71
71
  data : JSONData
72
72
  Data to write as CSV. Should be a list of dictionaries or a
@@ -77,4 +77,5 @@ def write(
77
77
  int
78
78
  The number of rows written to the CSV file.
79
79
  """
80
+ path = coerce_path(path)
80
81
  return stub.write(path, data, format_name='DAT')
etlplus/file/msgpack.py CHANGED
@@ -18,12 +18,12 @@ Notes
18
18
 
19
19
  from __future__ import annotations
20
20
 
21
- from pathlib import Path
22
- from typing import Any
23
-
24
21
  from ..types import JSONData
25
- from ._imports import get_optional_module
22
+ from ..types import StrPath
23
+ from ._imports import get_dependency
24
+ from ._io import coerce_path
26
25
  from ._io import coerce_record_payload
26
+ from ._io import ensure_parent_dir
27
27
  from ._io import normalize_records
28
28
 
29
29
  # SECTION: EXPORTS ========================================================== #
@@ -36,32 +36,18 @@ __all__ = [
36
36
  ]
37
37
 
38
38
 
39
- # SECTION: INTERNAL FUNCTIONS =============================================== #
40
-
41
-
42
- def _get_msgpack() -> Any:
43
- """Return the msgpack module, importing it on first use."""
44
- return get_optional_module(
45
- 'msgpack',
46
- error_message=(
47
- 'MSGPACK support requires optional dependency "msgpack".\n'
48
- 'Install with: pip install msgpack'
49
- ),
50
- )
51
-
52
-
53
39
  # SECTION: FUNCTIONS ======================================================== #
54
40
 
55
41
 
56
42
  def read(
57
- path: Path,
43
+ path: StrPath,
58
44
  ) -> JSONData:
59
45
  """
60
46
  Read MsgPack content from *path*.
61
47
 
62
48
  Parameters
63
49
  ----------
64
- path : Path
50
+ path : StrPath
65
51
  Path to the MsgPack file on disk.
66
52
 
67
53
  Returns
@@ -69,14 +55,15 @@ def read(
69
55
  JSONData
70
56
  The structured data read from the MsgPack file.
71
57
  """
72
- msgpack = _get_msgpack()
58
+ path = coerce_path(path)
59
+ msgpack = get_dependency('msgpack', format_name='MSGPACK')
73
60
  with path.open('rb') as handle:
74
61
  payload = msgpack.unpackb(handle.read(), raw=False)
75
62
  return coerce_record_payload(payload, format_name='MSGPACK')
76
63
 
77
64
 
78
65
  def write(
79
- path: Path,
66
+ path: StrPath,
80
67
  data: JSONData,
81
68
  ) -> int:
82
69
  """
@@ -84,7 +71,7 @@ def write(
84
71
 
85
72
  Parameters
86
73
  ----------
87
- path : Path
74
+ path : StrPath
88
75
  Path to the MsgPack file on disk.
89
76
  data : JSONData
90
77
  Data to write as MsgPack. Should be a list of dictionaries or a
@@ -95,10 +82,11 @@ def write(
95
82
  int
96
83
  The number of rows written to the MsgPack file.
97
84
  """
98
- msgpack = _get_msgpack()
85
+ path = coerce_path(path)
86
+ msgpack = get_dependency('msgpack', format_name='MSGPACK')
99
87
  records = normalize_records(data, 'MSGPACK')
100
88
  payload: JSONData = records if isinstance(data, list) else records[0]
101
- path.parent.mkdir(parents=True, exist_ok=True)
89
+ ensure_parent_dir(path)
102
90
  with path.open('wb') as handle:
103
91
  handle.write(msgpack.packb(payload, use_bin_type=True))
104
92
  return len(records)
etlplus/file/mustache.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 MUSTACHE content from *path*.
46
46
 
47
47
  Parameters
48
48
  ----------
49
- path : Path
49
+ path : StrPath
50
50
  Path to the MUSTACHE 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 MUSTACHE file on disk.
71
71
  data : JSONData
72
72
  Data to write as MUSTACHE file. Should be a list of dictionaries or a
@@ -77,4 +77,5 @@ def write(
77
77
  int
78
78
  The number of rows written to the MUSTACHE file.
79
79
  """
80
+ path = coerce_path(path)
80
81
  return stub.write(path, data, format_name='MUSTACHE')