etlplus 0.11.8__py3-none-any.whl → 0.11.9__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.
etlplus/cli/handlers.py CHANGED
@@ -570,7 +570,7 @@ def transform_handler(
570
570
  data = transform(payload, cast(TransformOperations, operations_payload))
571
571
 
572
572
  if target and target != '-':
573
- File.from_path(target, file_format=target_format).write(data)
573
+ File(target, file_format=target_format).write(data)
574
574
  print(f'Data transformed and saved to {target}')
575
575
  return 0
576
576
 
etlplus/database/ddl.py CHANGED
@@ -203,7 +203,7 @@ def load_table_spec(
203
203
  raise ValueError('Spec must be .json, .yml, or .yaml')
204
204
 
205
205
  try:
206
- spec = File.from_path(spec_path).read()
206
+ spec = File(spec_path).read()
207
207
  except ImportError as e:
208
208
  if suffix in {'.yml', '.yaml'}:
209
209
  raise RuntimeError(
etlplus/file/core.py CHANGED
@@ -11,7 +11,6 @@ from dataclasses import dataclass
11
11
  from pathlib import Path
12
12
 
13
13
  from ..types import JSONData
14
- from ..types import StrPath
15
14
  from . import csv
16
15
  from . import json
17
16
  from . import xml
@@ -43,7 +42,15 @@ class File:
43
42
  Path to the file on disk.
44
43
  file_format : FileFormat | None, optional
45
44
  Explicit format. If omitted, the format is inferred from the file
46
- extension (``.csv``, ``.json``, or ``.xml``).
45
+ extension (``.csv``, ``.json``, etc.).
46
+
47
+ Parameters
48
+ ----------
49
+ path : StrPath
50
+ Path to the file on disk.
51
+ file_format : FileFormat | str | None, optional
52
+ Explicit format. If omitted, the format is inferred from the file
53
+ extension (``.csv``, ``.json``, etc.).
47
54
  """
48
55
 
49
56
  # -- Attributes -- #
@@ -62,16 +69,10 @@ class File:
62
69
  extension is unknown, the attribute is left as ``None`` and will be
63
70
  validated later by :meth:`_ensure_format`.
64
71
  """
65
- # Normalize incoming path (allow str in constructor) to Path.
66
- if isinstance(self.path, str):
67
- self.path = Path(self.path)
68
-
72
+ self.path = Path(self.path)
73
+ self.file_format = self._coerce_format(self.file_format)
69
74
  if self.file_format is None:
70
- try:
71
- self.file_format = self._guess_format()
72
- except ValueError:
73
- # Leave as None; _ensure_format() will raise on use if needed.
74
- pass
75
+ self.file_format = self._maybe_guess_format()
75
76
 
76
77
  # -- Internal Instance Methods -- #
77
78
 
@@ -84,6 +85,28 @@ class File:
84
85
  if not self.path.exists():
85
86
  raise FileNotFoundError(f'File not found: {self.path}')
86
87
 
88
+ def _coerce_format(
89
+ self,
90
+ file_format: FileFormat | str | None,
91
+ ) -> FileFormat | None:
92
+ """
93
+ Normalize the file format input.
94
+
95
+ Parameters
96
+ ----------
97
+ file_format : FileFormat | str | None
98
+ File format specifier. Strings are coerced into
99
+ :class:`FileFormat`.
100
+
101
+ Returns
102
+ -------
103
+ FileFormat | None
104
+ A normalized file format, or ``None`` when unspecified.
105
+ """
106
+ if file_format is None or isinstance(file_format, FileFormat):
107
+ return file_format
108
+ return FileFormat.coerce(file_format)
109
+
87
110
  def _ensure_format(self) -> FileFormat:
88
111
  """
89
112
  Resolve the active format, guessing from extension if needed.
@@ -125,6 +148,21 @@ class File:
125
148
  f'Cannot infer file format from extension {self.path.suffix!r}',
126
149
  )
127
150
 
151
+ def _maybe_guess_format(self) -> FileFormat | None:
152
+ """
153
+ Try to infer the format, returning ``None`` if it cannot be inferred.
154
+
155
+ Returns
156
+ -------
157
+ FileFormat | None
158
+ The inferred format, or ``None`` if inference fails.
159
+ """
160
+ try:
161
+ return self._guess_format()
162
+ except ValueError:
163
+ # Leave as None; _ensure_format() will raise on use if needed.
164
+ return None
165
+
128
166
  # -- Instance Methods -- #
129
167
 
130
168
  def read(self) -> JSONData:
@@ -192,37 +230,3 @@ class File:
192
230
  case FileFormat.YAML:
193
231
  return yaml.write(self.path, data)
194
232
  raise ValueError(f'Unsupported format: {fmt}')
195
-
196
- # -- Class Methods -- #
197
-
198
- @classmethod
199
- def from_path(
200
- cls,
201
- path: StrPath,
202
- *,
203
- file_format: FileFormat | str | None = None,
204
- ) -> File:
205
- """
206
- Create a :class:`File` from any path-like and optional format.
207
-
208
- Parameters
209
- ----------
210
- path : StrPath
211
- Path to the file on disk.
212
- file_format : FileFormat | str | None, optional
213
- Explicit format. If omitted, the format is inferred from the file
214
- extension (``.csv``, ``.json``, or ``.xml``).
215
-
216
- Returns
217
- -------
218
- File
219
- The constructed :class:`File` instance.
220
- """
221
- resolved = Path(path)
222
- ff: FileFormat | None
223
- if isinstance(file_format, str):
224
- ff = FileFormat.coerce(file_format)
225
- else:
226
- ff = file_format
227
-
228
- return cls(resolved, ff)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: etlplus
3
- Version: 0.11.8
3
+ Version: 0.11.9
4
4
  Summary: A Swiss Army knife for simple ETL operations
5
5
  Home-page: https://github.com/Dagitali/ETLPlus
6
6
  Author: ETLPlus Team
@@ -32,7 +32,7 @@ etlplus/api/rate_limiting/rate_limiter.py,sha256=Uxozqd_Ej5Lsj-M-mLT2WexChgWh7x3
32
32
  etlplus/cli/__init__.py,sha256=J97-Rv931IL1_b4AXnB7Fbbd7HKnHBpx18NQfC_kE6c,299
33
33
  etlplus/cli/commands.py,sha256=g8_m3A8HEMyTRu2HctNiRoi2gtB5oSZCUEcyq-PIXos,24669
34
34
  etlplus/cli/constants.py,sha256=E6Uy4WauLa_0zkzxqImXh-bb1gKdb9sBZQVc8QOzr2Q,1943
35
- etlplus/cli/handlers.py,sha256=Gf0lq5j5e5RK2SsIqTGjC9lqEKvJJ13lZk3yUD8gupc,17764
35
+ etlplus/cli/handlers.py,sha256=FvnYWKRg4u7iCcIvAJtpjDEbqw2DHj3G34NXJbMwnHk,17754
36
36
  etlplus/cli/io.py,sha256=EFaBPYaBOyOllfMQWXgTjy-MPiGfNejicpD7ROrPyAE,7840
37
37
  etlplus/cli/main.py,sha256=IgeqxypixfwLHR-QcpgVMQ7vMZ865bXOh2oO9v-BWeM,5234
38
38
  etlplus/cli/options.py,sha256=vfXT3YLh7wG1iC-aTdSg6ItMC8l6n0Lozmy53XjqLbA,1199
@@ -46,13 +46,13 @@ etlplus/config/profile.py,sha256=Ss2zedQGjkaGSpvBLTD4SZaWViMJ7TJPLB8Q2_BTpPg,189
46
46
  etlplus/config/types.py,sha256=a0epJ3z16HQ5bY3Ctf8s_cQPa3f0HHcwdOcjCP2xoG4,4954
47
47
  etlplus/config/utils.py,sha256=4SUHMkt5bKBhMhiJm-DrnmE2Q4TfOgdNCKz8PJDS27o,3443
48
48
  etlplus/database/__init__.py,sha256=AKJsDl2RHuRGPS-eXgNJeh4aSncJP5Y0yLApBF6i7i8,1052
49
- etlplus/database/ddl.py,sha256=CKrxGWGKkick--AnUUzBRGpH30f4h8RuE3JXOLg420o,7923
49
+ etlplus/database/ddl.py,sha256=0dEM9SJMMabkhI_h-Fc0j9a1Sl5lSyZdI0bIeBVGm10,7913
50
50
  etlplus/database/engine.py,sha256=PUxXLvLPyc-KaxuW7fXe12wYci7EvUp-Ad1H3bGhUog,4058
51
51
  etlplus/database/orm.py,sha256=gCSqH-CjQz6tV9133-VqgiwokK5ylun0BwXaIWfImAo,10008
52
52
  etlplus/database/schema.py,sha256=813C0Dd3WE53KTYot4dgjAxctgKXLXx-8_Rk_4r2e28,7022
53
53
  etlplus/database/types.py,sha256=_pkQyC14TzAlgyeIqZG4F5LWYknZbHw3TW68Auk7Ya0,795
54
54
  etlplus/file/__init__.py,sha256=X03bosSM-uSd6dh3ur0un6_ozFRw2Tm4PE6kVUjtXK8,475
55
- etlplus/file/core.py,sha256=oQsqoFp3PEt1cgHyNeK36gim45RFPV6lZ3R4hvFm5Nw,6447
55
+ etlplus/file/core.py,sha256=oMEzvs2RKtE95TX-HWz__PavjHwlhcTk-D9Jti99AXU,6675
56
56
  etlplus/file/csv.py,sha256=VbMW_NaqCw03HlfvYzb9MoAgCXI3cl9qc4dASkTHoyw,1880
57
57
  etlplus/file/enums.py,sha256=rwrbwj6PejG0c5v6jzcsmeNu9cSqDyWB1foIuM5UyJo,6648
58
58
  etlplus/file/json.py,sha256=xSV5PkZ_tZQuZNdLr1FQUwuCQXyL7Ch3WRJ3hkw0p68,1911
@@ -63,9 +63,9 @@ etlplus/templates/ddl.sql.j2,sha256=s8fMWvcb4eaJVXkifuib1aQPljtZ8buuyB_uA-ZdU3Q,
63
63
  etlplus/templates/view.sql.j2,sha256=Iy8DHfhq5yyvrUKDxqp_aHIEXY4Tm6j4wT7YDEFWAhk,2180
64
64
  etlplus/validation/__init__.py,sha256=Pe5Xg1_EA4uiNZGYu5WTF3j7odjmyxnAJ8rcioaplSQ,1254
65
65
  etlplus/validation/utils.py,sha256=Mtqg449VIke0ziy_wd2r6yrwJzQkA1iulZC87FzXMjo,10201
66
- etlplus-0.11.8.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
67
- etlplus-0.11.8.dist-info/METADATA,sha256=j8BQpzSkBMHdll616-fmDCxV4izMcnCsl686nFAHttM,21036
68
- etlplus-0.11.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
69
- etlplus-0.11.8.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
70
- etlplus-0.11.8.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
71
- etlplus-0.11.8.dist-info/RECORD,,
66
+ etlplus-0.11.9.dist-info/licenses/LICENSE,sha256=MuNO63i6kWmgnV2pbP2SLqP54mk1BGmu7CmbtxMmT-U,1069
67
+ etlplus-0.11.9.dist-info/METADATA,sha256=G8vVH8Z8HJYymyRoBpcpm8SY4o7PkGkgjQsu2q_d_8M,21036
68
+ etlplus-0.11.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
69
+ etlplus-0.11.9.dist-info/entry_points.txt,sha256=6w-2-jzuPa55spzK34h-UKh2JTEShh38adFRONNP9QE,45
70
+ etlplus-0.11.9.dist-info/top_level.txt,sha256=aWWF-udn_sLGuHTM6W6MLh99ArS9ROkUWO8Mi8y1_2U,8
71
+ etlplus-0.11.9.dist-info/RECORD,,