pathier
13class Pathier(pathlib.Path): 14 """Subclasses the standard library pathlib.Path class.""" 15 16 def __new__(cls, *args, **kwargs): 17 if cls is Pathier: 18 cls = WindowsPath if os.name == "nt" else PosixPath 19 self = cls._from_parts(args) 20 if not self._flavour.is_supported: 21 raise NotImplementedError( 22 "cannot instantiate %r on your system" % (cls.__name__,) 23 ) 24 return self 25 26 def moveup(self, name: str) -> Self: 27 """Return a new Pathier obj that is a parent of this instance. 28 29 :param name: The parent directory that should be the stem of the returned Pathier obj. 30 'name' is case-sensitive and raises an exception if it isn't in self.parts. 31 >>> p = Pathier("C:\some\directory\in\your\system") 32 >>> print(p.moveup("directory")) 33 >>> "C:\some\directory" 34 >>> print(p.moveup("yeet")) 35 >>> "Exception: yeet is not a parent of C:\some\directory\in\your\system" """ 36 if name not in self.parts: 37 raise Exception(f"{name} is not a parent of {self}") 38 return Pathier(*(self.parts[: self.parts.index(name) + 1])) 39 40 def __sub__(self, levels: int) -> Self: 41 """Return a new Pathier obj moved up 'levels' number of parents from the current path. 42 >>> p = Pathier("C:\some\directory\in\your\system") 43 >>> new_p = p - 3 44 >>> print(new_p) 45 >>> "C:\some\directory" """ 46 path = self 47 for _ in range(levels): 48 path = path.parent 49 return path 50 51 def mkdir(self, mode: int = 511, parents: bool = True, exist_ok: bool = True): 52 """Create this directory. 53 Same as Path().mkdir() except 54 'parents' and 'exist_ok' default 55 to True instead of False.""" 56 super().mkdir(mode, parents, exist_ok) 57 58 def touch(self): 59 """Create file and parents if necessary.""" 60 self.parent.mkdir() 61 super().touch() 62 63 def write_text( 64 self, 65 data: Any, 66 encoding: Any | None = None, 67 errors: Any | None = None, 68 newline: Any | None = None, 69 parents: bool = True, 70 ): 71 """Write data to file. If a TypeError is raised, the function 72 will attempt to case data to a str and try the write again. 73 If a FileNotFoundError is raised and parents = True, 74 self.parent will be created.""" 75 write = functools.partial( 76 super().write_text, 77 encoding=encoding, 78 errors=errors, 79 newline=newline, 80 ) 81 try: 82 write(data) 83 except TypeError: 84 data = str(data) 85 write(data) 86 except FileNotFoundError: 87 if parents: 88 self.parent.mkdir(parents=True) 89 write(data) 90 else: 91 raise 92 except Exception as e: 93 raise 94 95 def write_bytes(self, data: bytes, parents: bool = True): 96 """Write bytes to file. 97 98 :param parents: If True and the write operation fails 99 with a FileNotFoundError, make the parent directory 100 and retry the write.""" 101 try: 102 super().write_bytes(data) 103 except FileNotFoundError: 104 if parents: 105 self.parent.mkdir(parents=True) 106 super().write_bytes(data) 107 else: 108 raise 109 except Exception as e: 110 raise 111 112 def json_loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any: 113 """Load json file.""" 114 return json.loads(self.read_text(encoding, errors)) 115 116 def json_dumps( 117 self, 118 data: Any, 119 encoding: Any | None = None, 120 errors: Any | None = None, 121 newline: Any | None = None, 122 sort_keys: bool = False, 123 indent: Any | None = None, 124 default: Any | None = None, 125 parents: bool = True, 126 ) -> Any: 127 """Dump data to json file.""" 128 self.write_text( 129 json.dumps(data, indent=indent, default=default, sort_keys=sort_keys), 130 encoding, 131 errors, 132 newline, 133 parents, 134 ) 135 136 def toml_loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any: 137 """Load toml file.""" 138 return tomlkit.loads(self.read_text(encoding, errors)) 139 140 def toml_dumps( 141 self, 142 data: Any, 143 encoding: Any | None = None, 144 errors: Any | None = None, 145 newline: Any | None = None, 146 sort_keys: bool = False, 147 parents: bool = True, 148 ): 149 """Dump data to toml file.""" 150 self.write_text( 151 tomlkit.dumps(data, sort_keys), encoding, errors, newline, parents 152 ) 153 154 def loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any: 155 """Load a json or toml file based off this instance's suffix.""" 156 match self.suffix: 157 case ".json": 158 return self.json_loads(encoding, errors) 159 case ".toml": 160 return self.toml_loads(encoding, errors) 161 162 def dumps( 163 self, 164 data: Any, 165 encoding: Any | None = None, 166 errors: Any | None = None, 167 newline: Any | None = None, 168 sort_keys: bool = False, 169 indent: Any | None = None, 170 default: Any | None = None, 171 parents: bool = True, 172 ): 173 """Dump data to a json or toml file based off this instance's suffix.""" 174 match self.suffix: 175 case ".json": 176 self.json_dumps( 177 data, encoding, errors, newline, sort_keys, indent, default, parents 178 ) 179 case ".toml": 180 self.toml_dumps(data, encoding, errors, newline, sort_keys, parents) 181 182 def delete(self, missing_ok: bool = True): 183 """Delete the file or folder pointed to by this instance. 184 Uses self.unlink() if a file and uses shutil.rmtree() if a directory.""" 185 if self.is_file(): 186 self.unlink(missing_ok) 187 elif self.is_dir(): 188 shutil.rmtree(self) 189 190 def copy( 191 self, new_path: Self | pathlib.Path | str, overwrite: bool = False 192 ) -> Self: 193 """Copy the path pointed to by this instance 194 to the instance pointed to by new_path using shutil.copyfile 195 or shutil.copytree. Returns the new path. 196 197 :param new_path: The copy destination. 198 199 :param overwrite: If True, files already existing in new_path 200 will be overwritten. If False, only files that don't exist in new_path 201 will be copied.""" 202 new_path = Pathier(new_path) 203 if self.is_dir(): 204 if overwrite or not new_path.exists(): 205 shutil.copytree(self, new_path, dirs_exist_ok=True) 206 else: 207 files = self.rglob("*.*") 208 for file in files: 209 dst = new_path.with_name(file.name) 210 if not dst.exists(): 211 shutil.copyfile(file, dst) 212 elif self.is_file(): 213 if overwrite or not new_path.exists(): 214 shutil.copyfile(self, new_path) 215 return new_path
Subclasses the standard library pathlib.Path class.
26 def moveup(self, name: str) -> Self: 27 """Return a new Pathier obj that is a parent of this instance. 28 29 :param name: The parent directory that should be the stem of the returned Pathier obj. 30 'name' is case-sensitive and raises an exception if it isn't in self.parts. 31 >>> p = Pathier("C:\some\directory\in\your\system") 32 >>> print(p.moveup("directory")) 33 >>> "C:\some\directory" 34 >>> print(p.moveup("yeet")) 35 >>> "Exception: yeet is not a parent of C:\some\directory\in\your\system" """ 36 if name not in self.parts: 37 raise Exception(f"{name} is not a parent of {self}") 38 return Pathier(*(self.parts[: self.parts.index(name) + 1]))
Return a new Pathier obj that is a parent of this instance.
Parameters
- name: The parent directory that should be the stem of the returned Pathier obj. '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"
51 def mkdir(self, mode: int = 511, parents: bool = True, exist_ok: bool = True): 52 """Create this directory. 53 Same as Path().mkdir() except 54 'parents' and 'exist_ok' default 55 to True instead of False.""" 56 super().mkdir(mode, parents, exist_ok)
Create this directory. Same as Path().mkdir() except 'parents' and 'exist_ok' default to True instead of False.
58 def touch(self): 59 """Create file and parents if necessary.""" 60 self.parent.mkdir() 61 super().touch()
Create file and parents if necessary.
63 def write_text( 64 self, 65 data: Any, 66 encoding: Any | None = None, 67 errors: Any | None = None, 68 newline: Any | None = None, 69 parents: bool = True, 70 ): 71 """Write data to file. If a TypeError is raised, the function 72 will attempt to case data to a str and try the write again. 73 If a FileNotFoundError is raised and parents = True, 74 self.parent will be created.""" 75 write = functools.partial( 76 super().write_text, 77 encoding=encoding, 78 errors=errors, 79 newline=newline, 80 ) 81 try: 82 write(data) 83 except TypeError: 84 data = str(data) 85 write(data) 86 except FileNotFoundError: 87 if parents: 88 self.parent.mkdir(parents=True) 89 write(data) 90 else: 91 raise 92 except Exception as e: 93 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.
95 def write_bytes(self, data: bytes, parents: bool = True): 96 """Write bytes to file. 97 98 :param parents: If True and the write operation fails 99 with a FileNotFoundError, make the parent directory 100 and retry the write.""" 101 try: 102 super().write_bytes(data) 103 except FileNotFoundError: 104 if parents: 105 self.parent.mkdir(parents=True) 106 super().write_bytes(data) 107 else: 108 raise 109 except Exception as e: 110 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.
112 def json_loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any: 113 """Load json file.""" 114 return json.loads(self.read_text(encoding, errors))
Load json file.
116 def json_dumps( 117 self, 118 data: Any, 119 encoding: Any | None = None, 120 errors: Any | None = None, 121 newline: Any | None = None, 122 sort_keys: bool = False, 123 indent: Any | None = None, 124 default: Any | None = None, 125 parents: bool = True, 126 ) -> Any: 127 """Dump data to json file.""" 128 self.write_text( 129 json.dumps(data, indent=indent, default=default, sort_keys=sort_keys), 130 encoding, 131 errors, 132 newline, 133 parents, 134 )
Dump data to json file.
136 def toml_loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any: 137 """Load toml file.""" 138 return tomlkit.loads(self.read_text(encoding, errors))
Load toml file.
140 def toml_dumps( 141 self, 142 data: Any, 143 encoding: Any | None = None, 144 errors: Any | None = None, 145 newline: Any | None = None, 146 sort_keys: bool = False, 147 parents: bool = True, 148 ): 149 """Dump data to toml file.""" 150 self.write_text( 151 tomlkit.dumps(data, sort_keys), encoding, errors, newline, parents 152 )
Dump data to toml file.
154 def loads(self, encoding: Any | None = None, errors: Any | None = None) -> Any: 155 """Load a json or toml file based off this instance's suffix.""" 156 match self.suffix: 157 case ".json": 158 return self.json_loads(encoding, errors) 159 case ".toml": 160 return self.toml_loads(encoding, errors)
Load a json or toml file based off this instance's suffix.
162 def dumps( 163 self, 164 data: Any, 165 encoding: Any | None = None, 166 errors: Any | None = None, 167 newline: Any | None = None, 168 sort_keys: bool = False, 169 indent: Any | None = None, 170 default: Any | None = None, 171 parents: bool = True, 172 ): 173 """Dump data to a json or toml file based off this instance's suffix.""" 174 match self.suffix: 175 case ".json": 176 self.json_dumps( 177 data, encoding, errors, newline, sort_keys, indent, default, parents 178 ) 179 case ".toml": 180 self.toml_dumps(data, encoding, errors, newline, sort_keys, parents)
Dump data to a json or toml file based off this instance's suffix.
182 def delete(self, missing_ok: bool = True): 183 """Delete the file or folder pointed to by this instance. 184 Uses self.unlink() if a file and uses shutil.rmtree() if a directory.""" 185 if self.is_file(): 186 self.unlink(missing_ok) 187 elif self.is_dir(): 188 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.
190 def copy( 191 self, new_path: Self | pathlib.Path | str, overwrite: bool = False 192 ) -> Self: 193 """Copy the path pointed to by this instance 194 to the instance pointed to by new_path using shutil.copyfile 195 or shutil.copytree. Returns the new path. 196 197 :param new_path: The copy destination. 198 199 :param overwrite: If True, files already existing in new_path 200 will be overwritten. If False, only files that don't exist in new_path 201 will be copied.""" 202 new_path = Pathier(new_path) 203 if self.is_dir(): 204 if overwrite or not new_path.exists(): 205 shutil.copytree(self, new_path, dirs_exist_ok=True) 206 else: 207 files = self.rglob("*.*") 208 for file in files: 209 dst = new_path.with_name(file.name) 210 if not dst.exists(): 211 shutil.copyfile(file, dst) 212 elif self.is_file(): 213 if overwrite or not new_path.exists(): 214 shutil.copyfile(self, new_path) 215 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.
Inherited Members
- pathlib.Path
- cwd
- home
- samefile
- iterdir
- glob
- rglob
- absolute
- resolve
- stat
- owner
- group
- open
- read_bytes
- read_text
- readlink
- chmod
- lchmod
- unlink
- rmdir
- lstat
- rename
- replace
- symlink_to
- hardlink_to
- link_to
- exists
- is_dir
- is_file
- is_mount
- is_symlink
- 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