19
19
# Copytight © 2008 Ned Batchelder
20
20
# Licensed under CC-BY-SA
21
21
#
22
- # Parts of the docstrings based on the Python 3.8.2 Documentation
22
+ # Parts of the docstrings and the PathPlus class based on the Python 3.8.2 Documentation
23
23
# Licensed under the Python Software Foundation License Version 2.
24
24
# Copyright © 2001-2020 Python Software Foundation. All rights reserved.
25
25
# Copyright © 2000 BeOpen.com . All rights reserved.
47
47
import pathlib
48
48
import shutil
49
49
import stat
50
- from typing import IO , Callable , Optional
50
+ from typing import Any , IO , Callable , Optional
51
51
52
52
# this package
53
53
from domdf_python_tools .typing import PathLike
54
54
55
55
56
- def append (var : str , filename : PathLike ) :
56
+ def append (var : str , filename : PathLike , ** kwargs ) -> int :
57
57
"""
58
58
Append ``var`` to the file ``filename`` in the current directory.
59
59
@@ -67,8 +67,8 @@ def append(var: str, filename: PathLike):
67
67
:param filename: The file to append to
68
68
"""
69
69
70
- with open (os .path .join (os .getcwd (), filename ), 'a' ) as f :
71
- f .write (var )
70
+ with open (os .path .join (os .getcwd (), filename ), 'a' , ** kwargs ) as f :
71
+ return f .write (var )
72
72
73
73
74
74
def copytree (
@@ -106,12 +106,12 @@ def copytree(
106
106
s = os .path .join (src , item )
107
107
d = os .path .join (dst , item )
108
108
if os .path .isdir (s ):
109
- shutil .copytree (s , d , symlinks , ignore )
109
+ return shutil .copytree (s , d , symlinks , ignore )
110
110
else :
111
- shutil .copy2 (s , d )
111
+ return shutil .copy2 (s , d )
112
112
113
113
114
- def delete (filename : PathLike ):
114
+ def delete (filename : PathLike , ** kwargs ):
115
115
"""
116
116
Delete the file in the current directory.
117
117
@@ -124,12 +124,12 @@ def delete(filename: PathLike):
124
124
:param filename: The file to delete
125
125
"""
126
126
127
- os .remove (os .path .join (os .getcwd (), filename ))
127
+ os .remove (os .path .join (os .getcwd (), filename ), ** kwargs )
128
128
129
129
130
- def maybe_make (directory : PathLike , mode = 0o777 , parents : bool = False , exist_ok : bool = False ):
130
+ def maybe_make (directory : PathLike , mode : int = 0o777 , parents : bool = False , exist_ok : bool = False ):
131
131
"""
132
- Create a directory at this given path, but only if the directory does not already exist.
132
+ Create a directory at the given path, but only if the directory does not already exist.
133
133
134
134
:param directory: Directory to create
135
135
:param mode: Combined with the process’ umask value to determine the file mode and access flags
@@ -167,7 +167,7 @@ def parent_path(path: PathLike) -> pathlib.Path:
167
167
return path .parent
168
168
169
169
170
- def read (filename : PathLike ) -> str :
170
+ def read (filename : PathLike , ** kwargs ) -> str :
171
171
"""
172
172
Read a file in the current directory (in text mode).
173
173
@@ -185,7 +185,7 @@ def read(filename: PathLike) -> str:
185
185
186
186
# TODO: docstring
187
187
188
- with open (os .path .join (os .getcwd (), filename )) as f :
188
+ with open (os .path .join (os .getcwd (), filename ), ** kwargs ) as f :
189
189
return f .read ()
190
190
191
191
@@ -223,7 +223,7 @@ def relpath(path: PathLike, relative_to: Optional[PathLike] = None) -> pathlib.P
223
223
relpath2 = relpath
224
224
225
225
226
- def write (var : str , filename : PathLike ) -> None :
226
+ def write (var : str , filename : PathLike , ** kwargs ) -> None :
227
227
"""
228
228
Write a variable to file in the current directory.
229
229
@@ -233,7 +233,7 @@ def write(var: str, filename: PathLike) -> None:
233
233
:param filename: The file to write to
234
234
"""
235
235
236
- with open (os .path .join (os .getcwd (), filename ), 'w' ) as f :
236
+ with open (os .path .join (os .getcwd (), filename ), 'w' , ** kwargs ) as f :
237
237
f .write (var )
238
238
239
239
@@ -271,3 +271,167 @@ def make_executable(filename: PathLike) -> None:
271
271
272
272
st = os .stat (str (filename ))
273
273
os .chmod (str (filename ), st .st_mode | stat .S_IXUSR | stat .S_IXGRP | stat .S_IXOTH )
274
+
275
+
276
+ class PathPlus (pathlib .Path ):
277
+ """
278
+ Subclass of :mod:`pathlib.Path` with additional methods and a default encoding of UTF-8.
279
+
280
+ Path represents a filesystem path but unlike PurePath, also offers
281
+ methods to do system calls on path objects. Depending on your system,
282
+ instantiating a Path will return either a PosixPath or a WindowsPath
283
+ object. You can also instantiate a PosixPath or WindowsPath directly,
284
+ but cannot instantiate a WindowsPath on a POSIX system or vice versa.
285
+ """
286
+
287
+ def __new__ (cls , * args , ** kwargs ):
288
+ if cls is PathPlus :
289
+ cls = WindowsPathPlus if os .name == 'nt' else PosixPathPlus
290
+ self = cls ._from_parts (args , init = False )
291
+ if not self ._flavour .is_supported :
292
+ raise NotImplementedError (f"cannot instantiate { cls .__name__ !r} on your system" )
293
+ self ._init ()
294
+ return self
295
+
296
+ def make_executable (self ):
297
+ """
298
+ Make the file executable.
299
+ """
300
+
301
+ make_executable (self )
302
+
303
+ def write_clean (
304
+ self ,
305
+ string : str ,
306
+ encoding : Optional [str ] = "UTF-8" ,
307
+ errors : Optional [str ] = None ,
308
+ ):
309
+ """
310
+ Open the file in text mode, write to it without trailing spaces, and close the file.
311
+
312
+ :param string:
313
+ :type string: str
314
+ :param encoding: The encoding to write to the file using. Default ``"UTF-8"``.
315
+ :param errors:
316
+ """
317
+
318
+ with self .open ("w" , encoding = encoding , errors = errors ) as fp :
319
+ clean_writer (string , fp )
320
+
321
+ def maybe_make (
322
+ self ,
323
+ mode : int = 0o777 ,
324
+ parents : bool = False ,
325
+ exist_ok : bool = False ,
326
+ ):
327
+ """
328
+ Create a directory at this path, but only if the directory does not already exist.
329
+
330
+ :param mode: Combined with the process’ umask value to determine the file mode and access flags
331
+ :type mode:
332
+ :param parents: If :py:obj:`False` (the default), a missing parent raises a :class:`~python:FileNotFoundError`.
333
+ If :py:obj:`True`, any missing parents of this path are created as needed; they are created with the
334
+ default permissions without taking mode into account (mimicking the POSIX mkdir -p command).
335
+ :type parents: bool, optional
336
+ :param exist_ok: If :py:obj:`False` (the default), a :class:`~python:FileExistsError` is raised if the
337
+ target directory already exists. If :py:obj:`True`, :class:`~python:FileExistsError` exceptions
338
+ will be ignored (same behavior as the POSIX mkdir -p command), but only if the last path
339
+ component is not an existing non-directory file.
340
+ :type exist_ok: bool, optional
341
+ """
342
+
343
+ maybe_make (self , mode = mode , parents = parents , exist_ok = exist_ok )
344
+
345
+ def append_text (
346
+ self ,
347
+ string : str ,
348
+ encoding : Optional [str ] = "UTF-8" ,
349
+ errors : Optional [str ] = None ,
350
+ ):
351
+ """
352
+ Open the file in text mode, append the given string to it, and close the file.
353
+
354
+ :param string:
355
+ :type string: str
356
+ :param encoding: The encoding to write to the file using. Default ``"UTF-8"``.
357
+ :param errors:
358
+ """
359
+
360
+ with self .open ("a" , encoding = encoding , errors = errors ) as fp :
361
+ fp .write (string )
362
+
363
+ def write_text (
364
+ self ,
365
+ data : str ,
366
+ encoding : Optional [str ] = "UTF-8" ,
367
+ errors : Optional [str ] = None ,
368
+ ) -> int :
369
+ """
370
+ Open the file in text mode, write to it, and close the file.
371
+
372
+ :param data:
373
+ :type data: str
374
+ :param encoding: The encoding to write to the file using. Default ``"UTF-8"``.
375
+ :param errors:
376
+ """
377
+
378
+ return super ().write_text (data , encoding = encoding , errors = errors )
379
+
380
+ def read_text (
381
+ self ,
382
+ encoding : Optional [str ] = "UTF-8" ,
383
+ errors : Optional [str ] = None ,
384
+ ) -> str :
385
+ """
386
+ Open the file in text mode, read it, and close the file.
387
+
388
+ :param encoding: The encoding to write to the file using. Default ``"UTF-8"``.
389
+ :param errors:
390
+
391
+ :return: The content of the file.
392
+ """
393
+
394
+ return super ().read_text (encoding = encoding , errors = errors )
395
+
396
+ def open (
397
+ self ,
398
+ mode : str = "r" ,
399
+ buffering : int = - 1 ,
400
+ encoding : Optional [str ] = "UTF-8" ,
401
+ errors : Optional [str ] = None ,
402
+ newline : Optional [str ] = None ,
403
+ ) -> IO [Any ]:
404
+
405
+ """
406
+ Open the file pointed by this path and return a file object, as
407
+ the built-in open() function does.
408
+ """
409
+
410
+ if 'b' in mode :
411
+ encoding = None
412
+ return super ().open (mode , buffering = buffering , encoding = encoding , errors = errors , newline = newline )
413
+
414
+
415
+ class PosixPathPlus (PathPlus , pathlib .PurePosixPath ):
416
+ """Path subclass for non-Windows systems.
417
+
418
+ On a POSIX system, instantiating a PathPlus object should return an instance of this class.
419
+ """
420
+ __slots__ = ()
421
+
422
+
423
+ class WindowsPathPlus (PathPlus , pathlib .PureWindowsPath ):
424
+ """Path subclass for Windows systems.
425
+
426
+ On a Windows system, instantiating a PathPlus object should return an instance of this class.
427
+ """
428
+ __slots__ = ()
429
+
430
+ def owner (self ): # pragma: no cover
431
+ raise NotImplementedError ("Path.owner() is unsupported on this system" )
432
+
433
+ def group (self ): # pragma: no cover
434
+ raise NotImplementedError ("Path.group() is unsupported on this system" )
435
+
436
+ def is_mount (self ): # pragma: no cover
437
+ raise NotImplementedError ("Path.is_mount() is unsupported on this system" )
0 commit comments