pathier

1from .pathier import Pathier
2
3__all__ = ["Pathier"]
class Pathier(pathlib.Path):
 16class Pathier(pathlib.Path):
 17    """Subclasses the standard library pathlib.Path class."""
 18
 19    def __new__(cls, *args, **kwargs):
 20        if cls is Pathier:
 21            cls = WindowsPath if os.name == "nt" else PosixPath
 22        self = cls._from_parts(args)
 23        if not self._flavour.is_supported:
 24            raise NotImplementedError(
 25                "cannot instantiate %r on your system" % (cls.__name__,)
 26            )
 27        return self
 28
 29    # ===============================================stats===============================================
 30    @property
 31    def dob(self) -> datetime.datetime | None:
 32        """Returns the creation date of this file
 33        or directory as a dateime.datetime object."""
 34        if self.exists():
 35            return datetime.datetime.fromtimestamp(self.stat().st_ctime)
 36        else:
 37            return None
 38
 39    @property
 40    def age(self) -> float | None:
 41        """Returns the age in seconds of this file or directory."""
 42        if self.exists():
 43            return (datetime.datetime.now() - self.dob).total_seconds()
 44        else:
 45            return None
 46
 47    @property
 48    def mod_date(self) -> datetime.datetime | None:
 49        """Returns the modification date of this file
 50        or directory as a datetime.datetime object."""
 51        if self.exists():
 52            return datetime.datetime.fromtimestamp(self.stat().st_mtime)
 53        else:
 54            return None
 55
 56    @property
 57    def mod_delta(self) -> float | None:
 58        """Returns how long ago in seconds this file
 59        or directory was modified."""
 60        if self.exists():
 61            return (datetime.datetime.now() - self.mod_date).total_seconds()
 62        else:
 63            return None
 64
 65    def size(self, format: bool = False) -> int | str | None:
 66        """Returns the size in bytes of this file or directory.
 67        Returns None if this path doesn't exist.
 68
 69        :param format: If True, return value as a formatted string."""
 70        if not self.exists():
 71            return None
 72        if self.is_file():
 73            size = self.stat().st_size
 74        if self.is_dir():
 75            size = sum(file.stat().st_size for file in self.rglob("*.*"))
 76        if format:
 77            return self.format_size(size)
 78        return size
 79
 80    @staticmethod
 81    def format_size(size: int) -> str:
 82        """Format 'size' with common file size abbreviations
 83        and rounded to two decimal places.
 84        >>> 1234 -> "1.23 kb" """
 85        for unit in ["bytes", "kb", "mb", "gb", "tb", "pb"]:
 86            if unit != "bytes":
 87                size *= 0.001
 88            if size < 1000 or unit == "pb":
 89                return f"{round(size, 2)} {unit}"
 90
 91    def is_larger(self, path: Self) -> bool:
 92        """Returns whether this file or folder is larger than
 93        the one pointed to by 'path'."""
 94        return self.size() > path.size()
 95
 96    def is_older(self, path: Self) -> bool:
 97        """Returns whether this file or folder is older than
 98        the one pointed to by 'path'."""
 99        return self.dob < path.dob
100
101    def modified_more_recently(self, path: Self) -> bool:
102        """Returns whether this file or folder was modified
103        more recently than the one pointed to by 'path'."""
104        return self.mod_date > path.mod_date
105
106    # ===============================================navigation===============================================
107    def mkcwd(self):
108        """Make this path your current working directory."""
109        os.chdir(self)
110
111    @property
112    def in_PATH(self) -> bool:
113        """Return True if this
114        path is in sys.path."""
115        return str(self) in sys.path
116
117    def add_to_PATH(self, index: int = 0):
118        """Insert this path into sys.path
119        if it isn't already there.
120
121        :param index: The index of sys.path
122        to insert this path at."""
123        path = str(self)
124        if not self.in_PATH:
125            sys.path.insert(index, path)
126
127    def append_to_PATH(self):
128        """Append this path to sys.path
129        if it isn't already there."""
130        path = str(self)
131        if not self.in_PATH:
132            sys.path.append(path)
133
134    def remove_from_PATH(self):
135        """Remove this path from sys.path
136        if it's in sys.path."""
137        if self.in_PATH:
138            sys.path.remove(str(self))
139
140    def moveup(self, name: str) -> Self:
141        """Return a new Pathier object that is a parent of this instance.
142        'name' is case-sensitive and raises an exception if it isn't in self.parts.
143        >>> p = Pathier("C:\some\directory\in\your\system")
144        >>> print(p.moveup("directory"))
145        >>> "C:\some\directory"
146        >>> print(p.moveup("yeet"))
147        >>> "Exception: yeet is not a parent of C:\some\directory\in\your\system" """
148        if name not in self.parts:
149            raise Exception(f"{name} is not a parent of {self}")
150        return Pathier(*(self.parts[: self.parts.index(name) + 1]))
151
152    def __sub__(self, levels: int) -> Self:
153        """Return a new Pathier object moved up 'levels' number of parents from the current path.
154        >>> p = Pathier("C:\some\directory\in\your\system")
155        >>> new_p = p - 3
156        >>> print(new_p)
157        >>> "C:\some\directory" """
158        path = self
159        for _ in range(levels):
160            path = path.parent
161        return path
162
163    def move_under(self, name: str) -> Self:
164        """Return a new Pathier object such that the stem
165        is one level below the folder 'name'.
166        'name' is case-sensitive and raises an exception if it isn't in self.parts.
167        >>> p = Pathier("a/b/c/d/e/f/g")
168        >>> print(p.move_under("c"))
169        >>> 'a/b/c/d'"""
170        if name not in self.parts:
171            raise Exception(f"{name} is not a parent of {self}")
172        return self - (len(self.parts) - self.parts.index(name) - 2)
173
174    def separate(self, name: str, keep_name: bool = False) -> Self:
175        """Return a new Pathier object that is the
176        relative child path after 'name'.
177        'name' is case-sensitive and raises an exception if it isn't in self.parts.
178
179        :param keep_name: If True, the returned path will start with 'name'.
180        >>> p = Pathier("a/b/c/d/e/f/g")
181        >>> print(p.separate("c"))
182        >>> 'd/e/f/g'
183        >>> print(p.separate("c", True))
184        >>> 'c/d/e/f/g'"""
185        if name not in self.parts:
186            raise Exception(f"{name} is not a parent of {self}")
187        if keep_name:
188            return Pathier(*self.parts[self.parts.index(name) :])
189        return Pathier(*self.parts[self.parts.index(name) + 1 :])
190
191    # ============================================write and read============================================
192    def mkdir(self, mode: int = 511, parents: bool = True, exist_ok: bool = True):
193        """Create this directory.
194        Same as Path().mkdir() except
195        'parents' and 'exist_ok' default
196        to True instead of False."""
197        super().mkdir(mode, parents, exist_ok)
198
199    def touch(self):
200        """Create file and parents if necessary."""
201        self.parent.mkdir()
202        super().touch()
203
204    def write_text(
205        self,
206        data: Any,
207        encoding: Any | None = None,
208        errors: Any | None = None,
209        newline: Any | None = None,
210        parents: bool = True,
211    ):
212        """Write data to file. If a TypeError is raised, the function
213        will attempt to case data to a str and try the write again.
214        If a FileNotFoundError is raised and parents = True,
215        self.parent will be created."""
216        write = functools.partial(
217            super().write_text,
218            encoding=encoding,
219            errors=errors,
220            newline=newline,
221        )
222        try:
223            write(data)
224        except TypeError:
225            data = str(data)
226            write(data)
227        except FileNotFoundError:
228            if parents:
229                self.parent.mkdir(parents=True)
230                write(data)
231            else:
232                raise
233        except Exception as e:
234            raise
235
236    def write_bytes(self, data: bytes, parents: bool = True):
237        """Write bytes to file.
238
239        :param parents: If True and the write operation fails
240        with a FileNotFoundError, make the parent directory
241        and retry the write."""
242        try:
243            super().write_bytes(data)
244        except FileNotFoundError:
245            if parents:
246                self.parent.mkdir(parents=True)
247                super().write_bytes(data)
248            else:
249                raise
250        except Exception as e:
251            raise
252
253    def json_loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any:
254        """Load json file."""
255        return json.loads(self.read_text(encoding, errors))
256
257    def json_dumps(
258        self,
259        data: Any,
260        encoding: Any | None = None,
261        errors: Any | None = None,
262        newline: Any | None = None,
263        sort_keys: bool = False,
264        indent: Any | None = None,
265        default: Any | None = None,
266        parents: bool = True,
267    ) -> Any:
268        """Dump data to json file."""
269        self.write_text(
270            json.dumps(data, indent=indent, default=default, sort_keys=sort_keys),
271            encoding,
272            errors,
273            newline,
274            parents,
275        )
276
277    def toml_loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any:
278        """Load toml file."""
279        return tomlkit.loads(self.read_text(encoding, errors))
280
281    def toml_dumps(
282        self,
283        data: Any,
284        encoding: Any | None = None,
285        errors: Any | None = None,
286        newline: Any | None = None,
287        sort_keys: bool = False,
288        parents: bool = True,
289    ):
290        """Dump data to toml file."""
291        self.write_text(
292            tomlkit.dumps(data, sort_keys), encoding, errors, newline, parents
293        )
294
295    def loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any:
296        """Load a json or toml file based off this instance's suffix."""
297        match self.suffix:
298            case ".json":
299                return self.json_loads(encoding, errors)
300            case ".toml":
301                return self.toml_loads(encoding, errors)
302
303    def dumps(
304        self,
305        data: Any,
306        encoding: Any | None = None,
307        errors: Any | None = None,
308        newline: Any | None = None,
309        sort_keys: bool = False,
310        indent: Any | None = None,
311        default: Any | None = None,
312        parents: bool = True,
313    ):
314        """Dump data to a json or toml file based off this instance's suffix."""
315        match self.suffix:
316            case ".json":
317                self.json_dumps(
318                    data, encoding, errors, newline, sort_keys, indent, default, parents
319                )
320            case ".toml":
321                self.toml_dumps(data, encoding, errors, newline, sort_keys, parents)
322
323    def delete(self, missing_ok: bool = True):
324        """Delete the file or folder pointed to by this instance.
325        Uses self.unlink() if a file and uses shutil.rmtree() if a directory."""
326        if self.is_file():
327            self.unlink(missing_ok)
328        elif self.is_dir():
329            shutil.rmtree(self)
330
331    def copy(
332        self, new_path: Self | pathlib.Path | str, overwrite: bool = False
333    ) -> Self:
334        """Copy the path pointed to by this instance
335        to the instance pointed to by new_path using shutil.copyfile
336        or shutil.copytree. Returns the new path.
337
338        :param new_path: The copy destination.
339
340        :param overwrite: If True, files already existing in new_path
341        will be overwritten. If False, only files that don't exist in new_path
342        will be copied."""
343        new_path = Pathier(new_path)
344        if self.is_dir():
345            if overwrite or not new_path.exists():
346                shutil.copytree(self, new_path, dirs_exist_ok=True)
347            else:
348                files = self.rglob("*.*")
349                for file in files:
350                    dst = new_path.with_name(file.name)
351                    if not dst.exists():
352                        shutil.copyfile(file, dst)
353        elif self.is_file():
354            if overwrite or not new_path.exists():
355                shutil.copyfile(self, new_path)
356        return new_path
357
358    def backup(self, timestamp: bool = False) -> Self | None:
359        """Create a copy of this file or directory with `_backup` appended to the path stem.
360        If the path to be backed up doesn't exist, `None` is returned.
361        Otherwise a `Pathier` object for the backup is returned.
362
363        :param `timestamp`: Add a timestamp to the backup name to prevent overriding previous backups.
364
365        >>> path = Pathier("some_file.txt")
366        >>> path.backup()
367        >>> list(path.iterdir())
368        >>> ['some_file.txt', 'some_file_backup.txt']
369        >>> path.backup(True)
370        >>> list(path.iterdir())
371        >>> ['some_file.txt', 'some_file_backup.txt', 'some_file_backup_04-28-2023-06_25_52_PM.txt']"""
372        if not self.exists():
373            return None
374        backup_stem = f"{self.stem}_backup"
375        if timestamp:
376            backup_stem = f"{backup_stem}_{datetime.datetime.now().strftime('%m-%d-%Y-%I_%M_%S_%p')}"
377        backup_path = self.with_stem(backup_stem)
378        self.copy(backup_path, True)
379        return backup_path

Subclasses the standard library pathlib.Path class.

Pathier()
dob: datetime.datetime | None

Returns the creation date of this file or directory as a dateime.datetime object.

age: float | None

Returns the age in seconds of this file or directory.

mod_date: datetime.datetime | None

Returns the modification date of this file or directory as a datetime.datetime object.

mod_delta: float | None

Returns how long ago in seconds this file or directory was modified.

def size(self, format: bool = False) -> int | str | None:
65    def size(self, format: bool = False) -> int | str | None:
66        """Returns the size in bytes of this file or directory.
67        Returns None if this path doesn't exist.
68
69        :param format: If True, return value as a formatted string."""
70        if not self.exists():
71            return None
72        if self.is_file():
73            size = self.stat().st_size
74        if self.is_dir():
75            size = sum(file.stat().st_size for file in self.rglob("*.*"))
76        if format:
77            return self.format_size(size)
78        return size

Returns the size in bytes of this file or directory. Returns None if this path doesn't exist.

Parameters
  • format: If True, return value as a formatted string.
@staticmethod
def format_size(size: int) -> str:
80    @staticmethod
81    def format_size(size: int) -> str:
82        """Format 'size' with common file size abbreviations
83        and rounded to two decimal places.
84        >>> 1234 -> "1.23 kb" """
85        for unit in ["bytes", "kb", "mb", "gb", "tb", "pb"]:
86            if unit != "bytes":
87                size *= 0.001
88            if size < 1000 or unit == "pb":
89                return f"{round(size, 2)} {unit}"

Format 'size' with common file size abbreviations and rounded to two decimal places.

>>> 1234 -> "1.23 kb"
def is_larger(self, path: Self) -> bool:
91    def is_larger(self, path: Self) -> bool:
92        """Returns whether this file or folder is larger than
93        the one pointed to by 'path'."""
94        return self.size() > path.size()

Returns whether this file or folder is larger than the one pointed to by 'path'.

def is_older(self, path: Self) -> bool:
96    def is_older(self, path: Self) -> bool:
97        """Returns whether this file or folder is older than
98        the one pointed to by 'path'."""
99        return self.dob < path.dob

Returns whether this file or folder is older than the one pointed to by 'path'.

def modified_more_recently(self, path: Self) -> bool:
101    def modified_more_recently(self, path: Self) -> bool:
102        """Returns whether this file or folder was modified
103        more recently than the one pointed to by 'path'."""
104        return self.mod_date > path.mod_date

Returns whether this file or folder was modified more recently than the one pointed to by 'path'.

def mkcwd(self):
107    def mkcwd(self):
108        """Make this path your current working directory."""
109        os.chdir(self)

Make this path your current working directory.

in_PATH: bool

Return True if this path is in sys.path.

def add_to_PATH(self, index: int = 0):
117    def add_to_PATH(self, index: int = 0):
118        """Insert this path into sys.path
119        if it isn't already there.
120
121        :param index: The index of sys.path
122        to insert this path at."""
123        path = str(self)
124        if not self.in_PATH:
125            sys.path.insert(index, path)

Insert this path into sys.path if it isn't already there.

Parameters
  • index: The index of sys.path to insert this path at.
def append_to_PATH(self):
127    def append_to_PATH(self):
128        """Append this path to sys.path
129        if it isn't already there."""
130        path = str(self)
131        if not self.in_PATH:
132            sys.path.append(path)

Append this path to sys.path if it isn't already there.

def remove_from_PATH(self):
134    def remove_from_PATH(self):
135        """Remove this path from sys.path
136        if it's in sys.path."""
137        if self.in_PATH:
138            sys.path.remove(str(self))

Remove this path from sys.path if it's in sys.path.

def moveup(self, name: str) -> Self:
140    def moveup(self, name: str) -> Self:
141        """Return a new Pathier object that is a parent of this instance.
142        'name' is case-sensitive and raises an exception if it isn't in self.parts.
143        >>> p = Pathier("C:\some\directory\in\your\system")
144        >>> print(p.moveup("directory"))
145        >>> "C:\some\directory"
146        >>> print(p.moveup("yeet"))
147        >>> "Exception: yeet is not a parent of C:\some\directory\in\your\system" """
148        if name not in self.parts:
149            raise Exception(f"{name} is not a parent of {self}")
150        return Pathier(*(self.parts[: self.parts.index(name) + 1]))

Return a new Pathier object that is a parent of this instance. 'name' is case-sensitive and raises an exception if it isn't in self.parts.

>>> p = Pathier("C:\some\directory\in\your\system")
>>> print(p.moveup("directory"))
>>> "C:\some\directory"
>>> print(p.moveup("yeet"))
>>> "Exception: yeet is not a parent of C:\some\directory\in\your\system"
def move_under(self, name: str) -> Self:
163    def move_under(self, name: str) -> Self:
164        """Return a new Pathier object such that the stem
165        is one level below the folder 'name'.
166        'name' is case-sensitive and raises an exception if it isn't in self.parts.
167        >>> p = Pathier("a/b/c/d/e/f/g")
168        >>> print(p.move_under("c"))
169        >>> 'a/b/c/d'"""
170        if name not in self.parts:
171            raise Exception(f"{name} is not a parent of {self}")
172        return self - (len(self.parts) - self.parts.index(name) - 2)

Return a new Pathier object such that the stem is one level below the folder 'name'. 'name' is case-sensitive and raises an exception if it isn't in self.parts.

>>> p = Pathier("a/b/c/d/e/f/g")
>>> print(p.move_under("c"))
>>> 'a/b/c/d'
def separate(self, name: str, keep_name: bool = False) -> Self:
174    def separate(self, name: str, keep_name: bool = False) -> Self:
175        """Return a new Pathier object that is the
176        relative child path after 'name'.
177        'name' is case-sensitive and raises an exception if it isn't in self.parts.
178
179        :param keep_name: If True, the returned path will start with 'name'.
180        >>> p = Pathier("a/b/c/d/e/f/g")
181        >>> print(p.separate("c"))
182        >>> 'd/e/f/g'
183        >>> print(p.separate("c", True))
184        >>> 'c/d/e/f/g'"""
185        if name not in self.parts:
186            raise Exception(f"{name} is not a parent of {self}")
187        if keep_name:
188            return Pathier(*self.parts[self.parts.index(name) :])
189        return Pathier(*self.parts[self.parts.index(name) + 1 :])

Return a new Pathier object that is the relative child path after 'name'. 'name' is case-sensitive and raises an exception if it isn't in self.parts.

Parameters
  • keep_name: If True, the returned path will start with 'name'. >>> p = Pathier("a/b/c/d/e/f/g") >>> print(p.separate("c")) >>> 'd/e/f/g' >>> print(p.separate("c", True)) >>> 'c/d/e/f/g'
def mkdir(self, mode: int = 511, parents: bool = True, exist_ok: bool = True):
192    def mkdir(self, mode: int = 511, parents: bool = True, exist_ok: bool = True):
193        """Create this directory.
194        Same as Path().mkdir() except
195        'parents' and 'exist_ok' default
196        to True instead of False."""
197        super().mkdir(mode, parents, exist_ok)

Create this directory. Same as Path().mkdir() except 'parents' and 'exist_ok' default to True instead of False.

def touch(self):
199    def touch(self):
200        """Create file and parents if necessary."""
201        self.parent.mkdir()
202        super().touch()

Create file and parents if necessary.

def write_text( self, data: Any, encoding: typing.Any | None = None, errors: typing.Any | None = None, newline: typing.Any | None = None, parents: bool = True):
204    def write_text(
205        self,
206        data: Any,
207        encoding: Any | None = None,
208        errors: Any | None = None,
209        newline: Any | None = None,
210        parents: bool = True,
211    ):
212        """Write data to file. If a TypeError is raised, the function
213        will attempt to case data to a str and try the write again.
214        If a FileNotFoundError is raised and parents = True,
215        self.parent will be created."""
216        write = functools.partial(
217            super().write_text,
218            encoding=encoding,
219            errors=errors,
220            newline=newline,
221        )
222        try:
223            write(data)
224        except TypeError:
225            data = str(data)
226            write(data)
227        except FileNotFoundError:
228            if parents:
229                self.parent.mkdir(parents=True)
230                write(data)
231            else:
232                raise
233        except Exception as e:
234            raise

Write data to file. If a TypeError is raised, the function will attempt to case data to a str and try the write again. If a FileNotFoundError is raised and parents = True, self.parent will be created.

def write_bytes(self, data: bytes, parents: bool = True):
236    def write_bytes(self, data: bytes, parents: bool = True):
237        """Write bytes to file.
238
239        :param parents: If True and the write operation fails
240        with a FileNotFoundError, make the parent directory
241        and retry the write."""
242        try:
243            super().write_bytes(data)
244        except FileNotFoundError:
245            if parents:
246                self.parent.mkdir(parents=True)
247                super().write_bytes(data)
248            else:
249                raise
250        except Exception as e:
251            raise

Write bytes to file.

Parameters
  • parents: If True and the write operation fails with a FileNotFoundError, make the parent directory and retry the write.
def json_loads( self, encoding: typing.Any | None = None, errors: typing.Any | None = None) -> Any:
253    def json_loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any:
254        """Load json file."""
255        return json.loads(self.read_text(encoding, errors))

Load json file.

def json_dumps( self, data: Any, encoding: typing.Any | None = None, errors: typing.Any | None = None, newline: typing.Any | None = None, sort_keys: bool = False, indent: typing.Any | None = None, default: typing.Any | None = None, parents: bool = True) -> Any:
257    def json_dumps(
258        self,
259        data: Any,
260        encoding: Any | None = None,
261        errors: Any | None = None,
262        newline: Any | None = None,
263        sort_keys: bool = False,
264        indent: Any | None = None,
265        default: Any | None = None,
266        parents: bool = True,
267    ) -> Any:
268        """Dump data to json file."""
269        self.write_text(
270            json.dumps(data, indent=indent, default=default, sort_keys=sort_keys),
271            encoding,
272            errors,
273            newline,
274            parents,
275        )

Dump data to json file.

def toml_loads( self, encoding: typing.Any | None = None, errors: typing.Any | None = None) -> Any:
277    def toml_loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any:
278        """Load toml file."""
279        return tomlkit.loads(self.read_text(encoding, errors))

Load toml file.

def toml_dumps( self, data: Any, encoding: typing.Any | None = None, errors: typing.Any | None = None, newline: typing.Any | None = None, sort_keys: bool = False, parents: bool = True):
281    def toml_dumps(
282        self,
283        data: Any,
284        encoding: Any | None = None,
285        errors: Any | None = None,
286        newline: Any | None = None,
287        sort_keys: bool = False,
288        parents: bool = True,
289    ):
290        """Dump data to toml file."""
291        self.write_text(
292            tomlkit.dumps(data, sort_keys), encoding, errors, newline, parents
293        )

Dump data to toml file.

def loads( self, encoding: typing.Any | None = None, errors: typing.Any | None = None) -> Any:
295    def loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any:
296        """Load a json or toml file based off this instance's suffix."""
297        match self.suffix:
298            case ".json":
299                return self.json_loads(encoding, errors)
300            case ".toml":
301                return self.toml_loads(encoding, errors)

Load a json or toml file based off this instance's suffix.

def dumps( self, data: Any, encoding: typing.Any | None = None, errors: typing.Any | None = None, newline: typing.Any | None = None, sort_keys: bool = False, indent: typing.Any | None = None, default: typing.Any | None = None, parents: bool = True):
303    def dumps(
304        self,
305        data: Any,
306        encoding: Any | None = None,
307        errors: Any | None = None,
308        newline: Any | None = None,
309        sort_keys: bool = False,
310        indent: Any | None = None,
311        default: Any | None = None,
312        parents: bool = True,
313    ):
314        """Dump data to a json or toml file based off this instance's suffix."""
315        match self.suffix:
316            case ".json":
317                self.json_dumps(
318                    data, encoding, errors, newline, sort_keys, indent, default, parents
319                )
320            case ".toml":
321                self.toml_dumps(data, encoding, errors, newline, sort_keys, parents)

Dump data to a json or toml file based off this instance's suffix.

def delete(self, missing_ok: bool = True):
323    def delete(self, missing_ok: bool = True):
324        """Delete the file or folder pointed to by this instance.
325        Uses self.unlink() if a file and uses shutil.rmtree() if a directory."""
326        if self.is_file():
327            self.unlink(missing_ok)
328        elif self.is_dir():
329            shutil.rmtree(self)

Delete the file or folder pointed to by this instance. Uses self.unlink() if a file and uses shutil.rmtree() if a directory.

def copy( self, new_path: Union[Self, pathlib.Path, str], overwrite: bool = False) -> Self:
331    def copy(
332        self, new_path: Self | pathlib.Path | str, overwrite: bool = False
333    ) -> Self:
334        """Copy the path pointed to by this instance
335        to the instance pointed to by new_path using shutil.copyfile
336        or shutil.copytree. Returns the new path.
337
338        :param new_path: The copy destination.
339
340        :param overwrite: If True, files already existing in new_path
341        will be overwritten. If False, only files that don't exist in new_path
342        will be copied."""
343        new_path = Pathier(new_path)
344        if self.is_dir():
345            if overwrite or not new_path.exists():
346                shutil.copytree(self, new_path, dirs_exist_ok=True)
347            else:
348                files = self.rglob("*.*")
349                for file in files:
350                    dst = new_path.with_name(file.name)
351                    if not dst.exists():
352                        shutil.copyfile(file, dst)
353        elif self.is_file():
354            if overwrite or not new_path.exists():
355                shutil.copyfile(self, new_path)
356        return new_path

Copy the path pointed to by this instance to the instance pointed to by new_path using shutil.copyfile or shutil.copytree. Returns the new path.

Parameters
  • new_path: The copy destination.

  • overwrite: If True, files already existing in new_path will be overwritten. If False, only files that don't exist in new_path will be copied.

def backup(self, timestamp: bool = False) -> Optional[Self]:
358    def backup(self, timestamp: bool = False) -> Self | None:
359        """Create a copy of this file or directory with `_backup` appended to the path stem.
360        If the path to be backed up doesn't exist, `None` is returned.
361        Otherwise a `Pathier` object for the backup is returned.
362
363        :param `timestamp`: Add a timestamp to the backup name to prevent overriding previous backups.
364
365        >>> path = Pathier("some_file.txt")
366        >>> path.backup()
367        >>> list(path.iterdir())
368        >>> ['some_file.txt', 'some_file_backup.txt']
369        >>> path.backup(True)
370        >>> list(path.iterdir())
371        >>> ['some_file.txt', 'some_file_backup.txt', 'some_file_backup_04-28-2023-06_25_52_PM.txt']"""
372        if not self.exists():
373            return None
374        backup_stem = f"{self.stem}_backup"
375        if timestamp:
376            backup_stem = f"{backup_stem}_{datetime.datetime.now().strftime('%m-%d-%Y-%I_%M_%S_%p')}"
377        backup_path = self.with_stem(backup_stem)
378        self.copy(backup_path, True)
379        return backup_path

Create a copy of this file or directory with _backup appended to the path stem. If the path to be backed up doesn't exist, None is returned. Otherwise a Pathier object for the backup is returned.

Parameters
  • timestamp: Add a timestamp to the backup name to prevent overriding previous backups.
>>> path = Pathier("some_file.txt")
>>> path.backup()
>>> list(path.iterdir())
>>> ['some_file.txt', 'some_file_backup.txt']
>>> path.backup(True)
>>> list(path.iterdir())
>>> ['some_file.txt', 'some_file_backup.txt', 'some_file_backup_04-28-2023-06_25_52_PM.txt']
Inherited Members
pathlib.Path
cwd
home
samefile
iterdir
glob
rglob
absolute
resolve
stat
owner
group
open
read_bytes
read_text
chmod
lchmod
rmdir
lstat
rename
replace
exists
is_dir
is_file
is_mount
is_block_device
is_char_device
is_fifo
is_socket
expanduser
pathlib.PurePath
as_posix
as_uri
drive
root
anchor
name
suffix
suffixes
stem
with_name
with_stem
with_suffix
relative_to
is_relative_to
parts
joinpath
parent
parents
is_absolute
is_reserved
match