safer 4.10.0__py3-none-any.whl → 4.11.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: safer
3
- Version: 4.10.0
3
+ Version: 4.11.0
4
4
  Summary: 🧿 A safer writer for files and streams 🧿
5
5
  License: MIT
6
6
  Author: Tom Ritchford
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3.8
12
12
  Classifier: Programming Language :: Python :: 3.9
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
+ Requires-Dist: black (>=23.12.0,<24.0.0)
15
16
  Description-Content-Type: text/markdown
16
17
 
17
18
  # 🧿 `safer`: A safer writer 🧿
@@ -0,0 +1,5 @@
1
+ safer.py,sha256=kpTfBG84oxJLOUnquz4yZpqTf97X4dm49fM1rMDygdo,21912
2
+ safer-4.11.0.dist-info/LICENSE,sha256=YrPqlE_MughiZSHUT2iVoduqlqmStMop9EEwCTdlzBw,1067
3
+ safer-4.11.0.dist-info/METADATA,sha256=uAF-YVfhEUFh12r18EFW2sVSXZaYh48CCiU_bP9STJg,5290
4
+ safer-4.11.0.dist-info/WHEEL,sha256=WGfLGfLX43Ei_YORXSnT54hxFygu34kMpcQdmgmEwCQ,88
5
+ safer-4.11.0.dist-info/RECORD,,
safer.py CHANGED
@@ -144,8 +144,6 @@ With `safer`
144
144
  print(item)
145
145
  # Either the whole file is written, or nothing
146
146
  """
147
- from pathlib import Path
148
- from typing import Callable, IO, Optional, Union
149
147
  import contextlib
150
148
  import functools
151
149
  import io
@@ -155,6 +153,8 @@ import shutil
155
153
  import sys
156
154
  import tempfile
157
155
  import traceback
156
+ from pathlib import Path
157
+ from typing import IO, Callable, Optional, Union
158
158
 
159
159
  # There's an edge case in #23 I can't yet fix, so I fail
160
160
  # deliberately
@@ -221,16 +221,20 @@ def writer(
221
221
  enabled: If `enabled` is falsey, the stream is returned unchanged
222
222
  """
223
223
  if isinstance(stream, (str, Path)):
224
- mode = 'wb' if is_binary else 'w'
225
224
  return open(
226
- stream, mode,
227
- delete_failures=delete_failures, dry_run=dry_run, enabled=enabled
225
+ stream,
226
+ 'wb' if is_binary else 'w',
227
+ delete_failures=delete_failures,
228
+ dry_run=dry_run,
229
+ enabled=enabled,
228
230
  )
229
231
 
230
232
  stream = stream or sys.stdout
231
233
  if not enabled:
232
234
  return stream
233
235
 
236
+ write: Optional[Callable]
237
+
234
238
  if callable(dry_run):
235
239
  write, dry_run = dry_run, True
236
240
 
@@ -244,6 +248,7 @@ def writer(
244
248
  def write(v):
245
249
  with stream:
246
250
  stream.write(v)
251
+
247
252
  else:
248
253
  write = getattr(stream, 'write', None)
249
254
 
@@ -282,6 +287,8 @@ def writer(
282
287
  else:
283
288
  raise ValueError('Stream is not a file, a socket, or callable')
284
289
 
290
+ closer: _StreamCloser
291
+
285
292
  if temp_file:
286
293
  closer = _FileStreamCloser(
287
294
  write,
@@ -303,7 +310,7 @@ def writer(
303
310
  def open(
304
311
  name: Union[Path, str],
305
312
  mode: str = 'r',
306
- buffering: bool = -1,
313
+ buffering: int = -1,
307
314
  encoding: Optional[str] = None,
308
315
  errors: Optional[str] = None,
309
316
  newline: Optional[str] = None,
@@ -312,7 +319,7 @@ def open(
312
319
  make_parents: bool = False,
313
320
  delete_failures: bool = True,
314
321
  temp_file: bool = False,
315
- dry_run: bool = False,
322
+ dry_run: Union[bool, Callable] = False,
316
323
  enabled: bool = True,
317
324
  ) -> IO:
318
325
  """
@@ -323,17 +330,19 @@ def open(
323
330
  if there is an exception.
324
331
 
325
332
  temp_file: If `temp_file` is truthy, write to a disk file and use
326
- os.replace() at the end, otherwise cache the writes in memory.
333
+ os.replace() at the end, otherwise cache the writes in memory.
327
334
 
328
- If `temp_file` is a string, use it as the name of the temporary
329
- file, otherwise select one in the same directory as the target
330
- file, or in the system tempfile for streams that aren't files.
335
+ If `temp_file` is a string, use it as the name of the temporary
336
+ file, otherwise select one in the same directory as the target
337
+ file, or in the system tempfile for streams that aren't files.
331
338
 
332
- dry_run:
333
- If dry_run is True, the file is not written to at all
339
+ dry_run: If `dry_run` is truthy, the file is not written at all
340
+ If `dry_run` is also callable, the results are passed to `dry_run()`
341
+ rather than being written.
334
342
 
335
343
  enabled:
336
- If `enabled` is falsey, the file is opened as normal
344
+ If `enabled` is falsey, safer is entirely bypassed, and
345
+ built-in `open()` is used instead.
337
346
 
338
347
  The remaining arguments are the same as for built-in `open()`.
339
348
 
@@ -367,9 +376,7 @@ def open(
367
376
  is_read = 'r' in mode and not is_copy
368
377
  is_binary = 'b' in mode
369
378
 
370
- kwargs = dict(
371
- encoding=encoding, errors=errors, newline=newline, opener=opener
372
- )
379
+ kwargs = dict(encoding=encoding, errors=errors, newline=newline, opener=opener)
373
380
 
374
381
  if isinstance(name, Path):
375
382
  name = str(name)
@@ -427,7 +434,7 @@ def open(
427
434
  buffering = io.DEFAULT_BUFFER_SIZE
428
435
 
429
436
  closer = _FileRenameCloser(
430
- name, temp_file, delete_failures, parent, dry_run
437
+ name, temp_file, delete_failures, parent, dry_run, is_binary
431
438
  )
432
439
 
433
440
  if is_copy and os.path.exists(name):
@@ -630,11 +637,13 @@ class _FileRenameCloser(_FileCloser):
630
637
  target_file,
631
638
  temp_file,
632
639
  delete_failures,
633
- parent=None,
634
- dry_run=False,
640
+ parent,
641
+ dry_run,
642
+ is_binary,
635
643
  ):
636
644
  self.target_file = target_file
637
645
  self.dry_run = dry_run
646
+ self.is_binary = is_binary
638
647
  super().__init__(temp_file, delete_failures, parent)
639
648
 
640
649
  def _success(self):
@@ -645,6 +654,10 @@ class _FileRenameCloser(_FileCloser):
645
654
  os.chmod(self.temp_file, 0o100644)
646
655
  os.replace(self.temp_file, self.target_file)
647
656
 
657
+ elif callable(self.dry_run):
658
+ with open(self.temp_file, 'rb' if self.is_binary else 'r') as fp:
659
+ self.dry_run(fp.read())
660
+
648
661
 
649
662
  class _StreamCloser(_Closer):
650
663
  def __init__(self, write, close_on_exit):
@@ -1,5 +0,0 @@
1
- safer.py,sha256=TphbmidXUkig_zXyOpJaWwhLdS6VxsjBUrHtVVVXB1M,21475
2
- safer-4.10.0.dist-info/LICENSE,sha256=YrPqlE_MughiZSHUT2iVoduqlqmStMop9EEwCTdlzBw,1067
3
- safer-4.10.0.dist-info/METADATA,sha256=98XGN9CdTZIMrlKM6GzZkuP1izYOwX6WMnRYS5LBJfQ,5249
4
- safer-4.10.0.dist-info/WHEEL,sha256=WGfLGfLX43Ei_YORXSnT54hxFygu34kMpcQdmgmEwCQ,88
5
- safer-4.10.0.dist-info/RECORD,,
File without changes