safer 5.0.0__py3-none-any.whl → 5.1.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.
safer/__init__.py CHANGED
@@ -147,6 +147,8 @@ With `safer`
147
147
  # Either the whole file is written, or nothing
148
148
 
149
149
  """
150
+ from __future__ import annotations
151
+
150
152
  import contextlib
151
153
  import functools
152
154
  import io
@@ -162,15 +164,15 @@ __all__ = 'writer', 'open', 'closer', 'dump', 'printer'
162
164
 
163
165
 
164
166
  def writer(
165
- stream: t.Union[t.Callable, None, t.IO, Path, str] = None,
166
- is_binary: t.Optional[bool] = None,
167
+ stream: t.Callable | None | t.IO | Path | str = None,
168
+ is_binary: bool | None = None,
167
169
  close_on_exit: bool = False,
168
170
  temp_file: bool = False,
169
171
  chunk_size: int = 0x100000,
170
172
  delete_failures: bool = True,
171
- dry_run: t.Union[bool, t.Callable] = False,
173
+ dry_run: bool | t.Callable = False,
172
174
  enabled: bool = True,
173
- ) -> t.Union[t.Callable, t.IO]:
175
+ ) -> t.Callable | t.IO:
174
176
  """
175
177
  Write safely to file streams, sockets and callables.
176
178
 
@@ -231,78 +233,84 @@ def writer(
231
233
  if not enabled:
232
234
  return stream
233
235
 
234
- write: t.Optional[t.Callable]
236
+ write: t.Callable | None
235
237
 
236
- if callable(dry_run):
237
- write, dry_run = dry_run, True
238
+ if close_on_exit and stream in (sys.stdout, sys.stderr):
239
+ raise ValueError('You cannot close stdout or stderr')
238
240
 
239
- elif dry_run:
240
- write = len
241
+ if dry_run:
242
+ close_on_exit = False
241
243
 
242
- elif close_on_exit and hasattr(stream, 'write'):
243
- if temp_file and BUG_MESSAGE:
244
- raise NotImplementedError(BUG_MESSAGE)
244
+ try:
245
+ if callable(dry_run):
246
+ write, dry_run = dry_run, True
245
247
 
246
- def write(v):
247
- with stream:
248
- stream.write(v)
248
+ elif dry_run:
249
+ write = len
249
250
 
250
- else:
251
- write = getattr(stream, 'write', None)
251
+ elif close_on_exit and hasattr(stream, 'write'):
252
+ if temp_file and BUG_MESSAGE:
253
+ raise NotImplementedError(BUG_MESSAGE)
252
254
 
253
- send = getattr(stream, 'send', None)
254
- mode = getattr(stream, 'mode', None)
255
+ def write(v):
256
+ with stream:
257
+ stream.write(v)
255
258
 
256
- if dry_run:
257
- close_on_exit = False
259
+ else:
260
+ write = getattr(stream, 'write', None)
258
261
 
259
- if close_on_exit and stream in (sys.stdout, sys.stderr):
260
- raise ValueError('You cannot close stdout or stderr')
262
+ send = getattr(stream, 'send', None)
263
+ mode = getattr(stream, 'mode', None)
261
264
 
262
- if write and mode:
263
- if not set('w+a').intersection(mode):
264
- raise ValueError('Stream mode "%s" is not a write mode' % mode)
265
+ if write and mode:
266
+ if not set('w+a').intersection(mode):
267
+ raise ValueError(f'Stream mode "{mode}" is not a write mode')
265
268
 
266
- binary_mode = 'b' in mode
267
- if is_binary is not None and is_binary is not binary_mode:
268
- raise ValueError('is_binary is inconsistent with the file stream')
269
+ binary_mode = 'b' in mode
270
+ if is_binary is not None and is_binary is not binary_mode:
271
+ raise ValueError('is_binary is inconsistent with the file stream')
269
272
 
270
- is_binary = binary_mode
273
+ is_binary = binary_mode
271
274
 
272
- elif dry_run:
273
- pass
275
+ elif dry_run:
276
+ pass
274
277
 
275
- elif send and hasattr(stream, 'recv'): # It looks like a socket:
276
- if not (is_binary is None or is_binary is True):
277
- raise ValueError('is_binary=False is inconsistent with a socket')
278
+ elif send and hasattr(stream, 'recv'): # It looks like a socket:
279
+ if not (is_binary is None or is_binary is True):
280
+ raise ValueError('is_binary=False is inconsistent with a socket')
278
281
 
279
- write = send
280
- is_binary = True
282
+ write = send
283
+ is_binary = True
281
284
 
282
- elif callable(stream):
283
- write = stream
285
+ elif callable(stream):
286
+ write = stream
284
287
 
285
- else:
286
- raise ValueError('Stream is not a file, a socket, or callable')
287
-
288
- closer: _StreamCloser
289
-
290
- if temp_file:
291
- closer = _FileStreamCloser(
292
- write,
293
- close_on_exit,
294
- is_binary,
295
- temp_file,
296
- chunk_size,
297
- delete_failures,
298
- )
299
- else:
300
- closer = _MemoryStreamCloser(write, close_on_exit, is_binary)
288
+ else:
289
+ raise ValueError('Stream is not a file, a socket, or callable')
290
+
291
+ closer: _StreamCloser
292
+
293
+ if temp_file:
294
+ closer = _FileStreamCloser(
295
+ write,
296
+ close_on_exit,
297
+ is_binary,
298
+ temp_file,
299
+ chunk_size,
300
+ delete_failures,
301
+ )
302
+ else:
303
+ closer = _MemoryStreamCloser(write, close_on_exit, is_binary)
304
+
305
+ if send is write:
306
+ closer.fp.send = write
301
307
 
302
- if send is write:
303
- closer.fp.send = write
308
+ return closer.fp
304
309
 
305
- return closer.fp
310
+ except Exception:
311
+ if close_on_exit:
312
+ getattr(stream, 'close', lambda: None)()
313
+ raise
306
314
 
307
315
 
308
316
  # There's an edge case in #23 I can't yet fix, so I fail
@@ -311,18 +319,18 @@ BUG_MESSAGE = 'Sorry, safer.writer fails if temp_file (#23)'
311
319
 
312
320
 
313
321
  def open(
314
- name: t.Union[Path, str],
322
+ name: Path | str,
315
323
  mode: str = 'r',
316
324
  buffering: int = -1,
317
- encoding: t.Optional[str] = None,
318
- errors: t.Optional[str] = None,
319
- newline: t.Optional[str] = None,
325
+ encoding: str | None = None,
326
+ errors: str | None = None,
327
+ newline: str | None = None,
320
328
  closefd: bool = True,
321
- opener: t.Optional[t.Callable] = None,
329
+ opener: t.Callable | None = None,
322
330
  make_parents: bool = False,
323
331
  delete_failures: bool = True,
324
332
  temp_file: bool = False,
325
- dry_run: t.Union[bool, t.Callable] = False,
333
+ dry_run: bool | t.Callable = False,
326
334
  enabled: bool = True,
327
335
  ) -> t.IO:
328
336
  """
@@ -385,7 +393,7 @@ def open(
385
393
  name = str(name)
386
394
 
387
395
  if not isinstance(name, str):
388
- raise TypeError('`name` must be string, not %s' % type(name).__name__)
396
+ raise TypeError(f'`name` must be string, not {type(name).__name__}')
389
397
 
390
398
  name = os.path.realpath(name)
391
399
  parent = os.path.dirname(os.path.abspath(name))
@@ -431,7 +439,7 @@ def open(
431
439
  raise ValueError("binary mode doesn't take an errors argument")
432
440
 
433
441
  if 'x' in mode and os.path.exists(name):
434
- raise FileExistsError("File exists: '%s'" % name)
442
+ raise FileExistsError(f"File exists: '{name}'")
435
443
 
436
444
  if buffering == -1:
437
445
  buffering = io.DEFAULT_BUFFER_SIZE
@@ -447,8 +455,8 @@ def open(
447
455
 
448
456
 
449
457
  def closer(
450
- stream: t.IO, is_binary: t.Optional[bool] = None, close_on_exit: bool = True, **kwds
451
- ) -> t.Union[t.Callable, t.IO]:
458
+ stream: t.IO, is_binary: bool | None = None, close_on_exit: bool = True, **kwds
459
+ ) -> t.Callable | t.IO:
452
460
  """
453
461
  Like `safer.writer()` but with `close_on_exit=True` by default
454
462
 
@@ -460,7 +468,7 @@ def closer(
460
468
 
461
469
  def dump(
462
470
  obj,
463
- stream: t.Union[t.Callable, None, t.IO, Path, str] = None,
471
+ stream: t.Callable | None | t.IO | Path | str = None,
464
472
  dump: t.Any = None,
465
473
  **kwargs,
466
474
  ) -> t.Any:
@@ -533,8 +541,8 @@ def _get_dumper(dump: t.Any) -> t.Callable:
533
541
 
534
542
  @contextlib.contextmanager
535
543
  def printer(
536
- name: t.Union[Path, str], mode: str = 'w', *args, **kwargs
537
- ) -> t.Generator[t.Callable, None, None]:
544
+ name: Path | str, mode: str = 'w', *args, **kwargs
545
+ ) -> t.Iterator[t.Callable]:
538
546
  """
539
547
  A context manager that yields a function that prints to the opened file,
540
548
  only writing to the original file at the exit of the context,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: safer
3
- Version: 5.0.0
3
+ Version: 5.1.0
4
4
  Summary: 🧿 A safer writer for files and streams 🧿
5
5
  Home-page: https://github.com/rec/safer
6
6
  License: MIT
@@ -0,0 +1,6 @@
1
+ safer/__init__.py,sha256=gol1HEWHBCBlrotKRuS2mSln5GAyv6PWdML09x9GZI8,22692
2
+ safer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ safer-5.1.0.dist-info/LICENSE,sha256=YrPqlE_MughiZSHUT2iVoduqlqmStMop9EEwCTdlzBw,1067
4
+ safer-5.1.0.dist-info/METADATA,sha256=TiGbpkpfSotKcUdbSdeR8kz27YdpbD1EroL_D52Zi0M,5449
5
+ safer-5.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
6
+ safer-5.1.0.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- safer/__init__.py,sha256=eRkfOSVTIr5Wd9aOF6EJBkfyizjeS_P6Uaeu0qBKe3Y,22455
2
- safer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- safer-5.0.0.dist-info/LICENSE,sha256=YrPqlE_MughiZSHUT2iVoduqlqmStMop9EEwCTdlzBw,1067
4
- safer-5.0.0.dist-info/METADATA,sha256=v2pjAfB1KHIGyg7W-fhSb0_mP2FOHePB8B7rPjzow8M,5449
5
- safer-5.0.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
6
- safer-5.0.0.dist-info/RECORD,,
File without changes
File without changes