gpath.render
1from __future__ import annotations 2 3import functools 4from abc import ABC, abstractmethod 5from typing import Type 6 7from . import _rules 8from .platform import Platform 9 10 11__all__ = ( 12 'Renderable', 13 'RenderedPath', 14 'GenericRenderedPath', 15 'PosixRenderedPath', 16 'LinuxRenderedPath', 17 'MacOsRenderedPath', 18 'WindowsRenderedPath', 19) 20 21 22class Renderable(ABC): 23 """ 24 Abstract interface that represents any object that can be converted to a RenderedPath. 25 26 Abstract properties 27 ------------------- 28 `named_parts: list[str]` 29 : read-only named components of the path, not including the filesystem root, drive name, or any parent directories 30 31 `relative_parts: list[str]` 32 : read-only relative components of the path, not including the filesystem root or drive name, including one item for each level of parent directory 33 34 `absolute: bool` 35 : read-only flag for whether the path is an absolute path 36 37 `parent_level: int` 38 : read-only number of levels of parent directories that the path is relative to, which may be 0 39 """ 40 41 @property 42 @abstractmethod 43 def named_parts(self) -> list[str]: 44 pass 45 46 @property 47 @abstractmethod 48 def relative_parts(self) -> list[str]: 49 pass 50 51 @property 52 @abstractmethod 53 def absolute(self) -> bool: 54 pass 55 56 @property 57 @abstractmethod 58 def drive(self) -> str: 59 pass 60 61 @property 62 @abstractmethod 63 def parent_level(self) -> int: 64 pass 65 66 @abstractmethod 67 def __repr__(self) -> str: 68 """ 69 Return a string representation of the object instance for debugging 70 """ 71 pass 72 73 74@functools.total_ordering 75class RenderedPath(ABC): 76 """ 77 Abstract base class for rendered path objects that target a specific operating system. 78 79 Whereas GPath represents a generalised abstract path, RenderedPath represents a file path on a specific platform with properties defined by the specific type of filesystem. Note however that the RenderedPath still does not represent a real file in a real filesystem, and can represent file paths on a system other than local. 80 81 The additional semantics available to RenderedPath allows it to be: 82 - printed in a format preferred by the given platform 83 - meaningfully compared and sorted 84 """ 85 86 __slots__ = ('_path') 87 88 def __hash__(self) -> int: 89 """ 90 Calculate hash of the RenderedPath. 91 92 Usage: <code>hash(<var>rp</var>)</code> 93 """ 94 return hash(self._tuple) 95 96 def __init__(self, path: Renderable): 97 """ 98 Initialise a rendered path from any object that is Renderable. 99 """ 100 self._path: Renderable = path 101 102 def __eq__(self, other) -> bool: 103 """ 104 Check if two RenderedPaths have the same target platform, and check if they have equivalent values on that platform 105 106 Usage: <code><var>rp1</var> == <var>rp2</var></code> 107 """ 108 return type(self) == type(other) and self._tuple == other._tuple 109 110 def __lt__(self, other) -> bool: 111 """ 112 Check if `self` should be collated before `other` 113 114 Usage: <code><var>rp1</var> < <var>rp2</var></code> 115 """ 116 return self._tuple < other._tuple 117 118 def __bool__(self) -> bool: 119 """ 120 False if `self` is equivalent to an empty path on the target platform, and True otherwise 121 122 By default, False if `self` is a relative path without any relative components and without a drive, and True otherwise. 123 124 Usage: <code>bool(<var>rp</var>)</code>, <code>not <var>rp</var></code>, or <code>if <var>rp</var>:</code> 125 """ 126 return self._path.absolute or self._path.drive != "" or self._path.parent_level != 0 or len(self._path.named_parts) > 0 127 128 def __str__(self) -> str: 129 """ 130 Return a string representation of the path in the preferred format for the target platform 131 132 Usage: <code>str(<var>rp</var>)</code> 133 """ 134 return repr(self) 135 136 def __repr__(self) -> str: 137 """ 138 Return a string that, when printed, gives the Python code associated with instantiating a copy of `self`. 139 140 Usage: <code>repr(<var>rp</var>)</code> 141 """ 142 return f"{type(self).__name__}({repr(self._path)})" 143 144 @property 145 def _tuple(self) -> tuple: 146 return ( 147 self._path.absolute, 148 self._path.drive, 149 self._path.parent_level, 150 self._path.named_parts, 151 ) 152 153 154class GenericRenderedPath(RenderedPath): 155 """ 156 A rendered path that maximises interoperability between different target platforms, specifically between Windows and POSIX-like operating systems. 157 158 This is done at the expense of producing outputs that may not conform to platform recommendations but that should still be usable across different platforms. 159 160 Note that if the path contains a drive, it should be removed if the path is to be used on Linux or macOS. On Windows, forward slashes / will be used in favour of backslashes. 161 """ 162 def __str__(self) -> str: 163 if bool(self): 164 return (self._path.drive + _rules.generic_rules.drive_postfixes[0] if self._path.drive != "" else "") + (_rules.generic_rules.roots[0] if self._path.absolute else "") + _rules.generic_rules.separators[0].join(self._path.relative_parts) 165 else: 166 return _rules.generic_rules.current_indicators[0] 167 168 169class PosixRenderedPath(RenderedPath): 170 """ 171 A rendered path meant for POSIX-like operating systems, such as Linux and macOS. 172 173 If the original path contains a drive, it will be ignored for both printing and collation. Forward slashes are used always. 174 """ 175 def __str__(self) -> str: 176 if bool(self): 177 return (_rules.posix_rules.roots[0] if self._path.absolute else "") + _rules.posix_rules.separators[0].join(self._path.relative_parts) 178 else: 179 return _rules.posix_rules.current_indicators[0] 180 181 def __bool__(self) -> bool: 182 """ 183 False if `self` is a relative path without any relative components, and True otherwise. 184 185 Usage: <code>bool(<var>rp</var>)</code>, <code>not <var>rp</var></code>, or <code>if <var>rp</var>:</code> 186 """ 187 return self._path.absolute or self._path.parent_level != 0 or len(self._path.named_parts) > 0 188 189 @property 190 def _tuple(self) -> tuple: 191 return ( 192 self._path.absolute, 193 self._path.parent_level, 194 self._path.named_parts, 195 ) 196 197LinuxRenderedPath = PosixRenderedPath 198"""Alias of `PosixRenderedPath`""" 199 200MacOsRenderedPath = PosixRenderedPath 201"""Alias of `PosixRenderedPath`""" 202 203 204class WindowsRenderedPath(RenderedPath): 205 """ 206 A rendered path meant for Windows operating systems. 207 208 The path may or may not contain a drive, which affects both its printed output and its collation order. Backslashes are used always, although forward slashes are supported on Windows NT also. 209 """ 210 def __str__(self) -> str: 211 if bool(self): 212 return (self._path.drive + _rules.windows_rules.drive_postfixes[0] if self._path.drive != "" else "") + (_rules.windows_rules.roots[0] if self._path.absolute else "") + _rules.windows_rules.separators[0].join(self._path.relative_parts) 213 else: 214 return _rules.windows_rules.current_indicators[0] 215 216 217_render_of_platforms: dict[Platform, Type[RenderedPath]] = { 218 Platform.GENERIC: GenericRenderedPath, 219 Platform.POSIX: PosixRenderedPath, 220 Platform.WINDOWS: WindowsRenderedPath, 221} 222 223 224def get_type(platform: Platform) -> Type[RenderedPath]: 225 """Get the type of RenderedPath that corresponds to the given Platform""" 226 return _render_of_platforms[platform]
23class Renderable(ABC): 24 """ 25 Abstract interface that represents any object that can be converted to a RenderedPath. 26 27 Abstract properties 28 ------------------- 29 `named_parts: list[str]` 30 : read-only named components of the path, not including the filesystem root, drive name, or any parent directories 31 32 `relative_parts: list[str]` 33 : read-only relative components of the path, not including the filesystem root or drive name, including one item for each level of parent directory 34 35 `absolute: bool` 36 : read-only flag for whether the path is an absolute path 37 38 `parent_level: int` 39 : read-only number of levels of parent directories that the path is relative to, which may be 0 40 """ 41 42 @property 43 @abstractmethod 44 def named_parts(self) -> list[str]: 45 pass 46 47 @property 48 @abstractmethod 49 def relative_parts(self) -> list[str]: 50 pass 51 52 @property 53 @abstractmethod 54 def absolute(self) -> bool: 55 pass 56 57 @property 58 @abstractmethod 59 def drive(self) -> str: 60 pass 61 62 @property 63 @abstractmethod 64 def parent_level(self) -> int: 65 pass 66 67 @abstractmethod 68 def __repr__(self) -> str: 69 """ 70 Return a string representation of the object instance for debugging 71 """ 72 pass
Abstract interface that represents any object that can be converted to a RenderedPath.
Abstract properties
named_parts: list[str]
: read-only named components of the path, not including the filesystem root, drive name, or any parent directories
relative_parts: list[str]
: read-only relative components of the path, not including the filesystem root or drive name, including one item for each level of parent directory
absolute: bool
: read-only flag for whether the path is an absolute path
parent_level: int
: read-only number of levels of parent directories that the path is relative to, which may be 0
67 @abstractmethod 68 def __repr__(self) -> str: 69 """ 70 Return a string representation of the object instance for debugging 71 """ 72 pass
Return a string representation of the object instance for debugging
Inherited Members
- builtins.object
- __new__
- __hash__
- __str__
- __getattribute__
- __setattr__
- __delattr__
- __lt__
- __le__
- __eq__
- __ne__
- __gt__
- __ge__
- __reduce_ex__
- __reduce__
- __getstate__
- __subclasshook__
- __init_subclass__
- __format__
- __sizeof__
- __dir__
75@functools.total_ordering 76class RenderedPath(ABC): 77 """ 78 Abstract base class for rendered path objects that target a specific operating system. 79 80 Whereas GPath represents a generalised abstract path, RenderedPath represents a file path on a specific platform with properties defined by the specific type of filesystem. Note however that the RenderedPath still does not represent a real file in a real filesystem, and can represent file paths on a system other than local. 81 82 The additional semantics available to RenderedPath allows it to be: 83 - printed in a format preferred by the given platform 84 - meaningfully compared and sorted 85 """ 86 87 __slots__ = ('_path') 88 89 def __hash__(self) -> int: 90 """ 91 Calculate hash of the RenderedPath. 92 93 Usage: <code>hash(<var>rp</var>)</code> 94 """ 95 return hash(self._tuple) 96 97 def __init__(self, path: Renderable): 98 """ 99 Initialise a rendered path from any object that is Renderable. 100 """ 101 self._path: Renderable = path 102 103 def __eq__(self, other) -> bool: 104 """ 105 Check if two RenderedPaths have the same target platform, and check if they have equivalent values on that platform 106 107 Usage: <code><var>rp1</var> == <var>rp2</var></code> 108 """ 109 return type(self) == type(other) and self._tuple == other._tuple 110 111 def __lt__(self, other) -> bool: 112 """ 113 Check if `self` should be collated before `other` 114 115 Usage: <code><var>rp1</var> < <var>rp2</var></code> 116 """ 117 return self._tuple < other._tuple 118 119 def __bool__(self) -> bool: 120 """ 121 False if `self` is equivalent to an empty path on the target platform, and True otherwise 122 123 By default, False if `self` is a relative path without any relative components and without a drive, and True otherwise. 124 125 Usage: <code>bool(<var>rp</var>)</code>, <code>not <var>rp</var></code>, or <code>if <var>rp</var>:</code> 126 """ 127 return self._path.absolute or self._path.drive != "" or self._path.parent_level != 0 or len(self._path.named_parts) > 0 128 129 def __str__(self) -> str: 130 """ 131 Return a string representation of the path in the preferred format for the target platform 132 133 Usage: <code>str(<var>rp</var>)</code> 134 """ 135 return repr(self) 136 137 def __repr__(self) -> str: 138 """ 139 Return a string that, when printed, gives the Python code associated with instantiating a copy of `self`. 140 141 Usage: <code>repr(<var>rp</var>)</code> 142 """ 143 return f"{type(self).__name__}({repr(self._path)})" 144 145 @property 146 def _tuple(self) -> tuple: 147 return ( 148 self._path.absolute, 149 self._path.drive, 150 self._path.parent_level, 151 self._path.named_parts, 152 )
Abstract base class for rendered path objects that target a specific operating system.
Whereas GPath represents a generalised abstract path, RenderedPath represents a file path on a specific platform with properties defined by the specific type of filesystem. Note however that the RenderedPath still does not represent a real file in a real filesystem, and can represent file paths on a system other than local.
The additional semantics available to RenderedPath allows it to be:
- printed in a format preferred by the given platform
- meaningfully compared and sorted
97 def __init__(self, path: Renderable): 98 """ 99 Initialise a rendered path from any object that is Renderable. 100 """ 101 self._path: Renderable = path
Initialise a rendered path from any object that is Renderable.
89 def __hash__(self) -> int: 90 """ 91 Calculate hash of the RenderedPath. 92 93 Usage: <code>hash(<var>rp</var>)</code> 94 """ 95 return hash(self._tuple)
Calculate hash of the RenderedPath.
Usage: hash(rp)
103 def __eq__(self, other) -> bool: 104 """ 105 Check if two RenderedPaths have the same target platform, and check if they have equivalent values on that platform 106 107 Usage: <code><var>rp1</var> == <var>rp2</var></code> 108 """ 109 return type(self) == type(other) and self._tuple == other._tuple
Check if two RenderedPaths have the same target platform, and check if they have equivalent values on that platform
Usage: rp1 == rp2
111 def __lt__(self, other) -> bool: 112 """ 113 Check if `self` should be collated before `other` 114 115 Usage: <code><var>rp1</var> < <var>rp2</var></code> 116 """ 117 return self._tuple < other._tuple
Check if self should be collated before other
Usage: rp1 < rp2
119 def __bool__(self) -> bool: 120 """ 121 False if `self` is equivalent to an empty path on the target platform, and True otherwise 122 123 By default, False if `self` is a relative path without any relative components and without a drive, and True otherwise. 124 125 Usage: <code>bool(<var>rp</var>)</code>, <code>not <var>rp</var></code>, or <code>if <var>rp</var>:</code> 126 """ 127 return self._path.absolute or self._path.drive != "" or self._path.parent_level != 0 or len(self._path.named_parts) > 0
False if self is equivalent to an empty path on the target platform, and True otherwise
By default, False if self is a relative path without any relative components and without a drive, and True otherwise.
Usage: bool(rp), not rp, or if rp:
129 def __str__(self) -> str: 130 """ 131 Return a string representation of the path in the preferred format for the target platform 132 133 Usage: <code>str(<var>rp</var>)</code> 134 """ 135 return repr(self)
Return a string representation of the path in the preferred format for the target platform
Usage: str(rp)
137 def __repr__(self) -> str: 138 """ 139 Return a string that, when printed, gives the Python code associated with instantiating a copy of `self`. 140 141 Usage: <code>repr(<var>rp</var>)</code> 142 """ 143 return f"{type(self).__name__}({repr(self._path)})"
Return a string that, when printed, gives the Python code associated with instantiating a copy of self.
Usage: repr(rp)
91def _gt_from_lt(self, other): 92 'Return a > b. Computed by @total_ordering from (not a < b) and (a != b).' 93 op_result = type(self).__lt__(self, other) 94 if op_result is NotImplemented: 95 return op_result 96 return not op_result and self != other
Return a > b. Computed by @total_ordering from (not a < b) and (a != b).
98def _le_from_lt(self, other): 99 'Return a <= b. Computed by @total_ordering from (a < b) or (a == b).' 100 op_result = type(self).__lt__(self, other) 101 if op_result is NotImplemented: 102 return op_result 103 return op_result or self == other
Return a <= b. Computed by @total_ordering from (a < b) or (a == b).
105def _ge_from_lt(self, other): 106 'Return a >= b. Computed by @total_ordering from (not a < b).' 107 op_result = type(self).__lt__(self, other) 108 if op_result is NotImplemented: 109 return op_result 110 return not op_result
Return a >= b. Computed by @total_ordering from (not a < b).
Inherited Members
- builtins.object
- __new__
- __getattribute__
- __setattr__
- __delattr__
- __ne__
- __reduce_ex__
- __reduce__
- __getstate__
- __subclasshook__
- __init_subclass__
- __format__
- __sizeof__
- __dir__
155class GenericRenderedPath(RenderedPath): 156 """ 157 A rendered path that maximises interoperability between different target platforms, specifically between Windows and POSIX-like operating systems. 158 159 This is done at the expense of producing outputs that may not conform to platform recommendations but that should still be usable across different platforms. 160 161 Note that if the path contains a drive, it should be removed if the path is to be used on Linux or macOS. On Windows, forward slashes / will be used in favour of backslashes. 162 """ 163 def __str__(self) -> str: 164 if bool(self): 165 return (self._path.drive + _rules.generic_rules.drive_postfixes[0] if self._path.drive != "" else "") + (_rules.generic_rules.roots[0] if self._path.absolute else "") + _rules.generic_rules.separators[0].join(self._path.relative_parts) 166 else: 167 return _rules.generic_rules.current_indicators[0]
A rendered path that maximises interoperability between different target platforms, specifically between Windows and POSIX-like operating systems.
This is done at the expense of producing outputs that may not conform to platform recommendations but that should still be usable across different platforms.
Note that if the path contains a drive, it should be removed if the path is to be used on Linux or macOS. On Windows, forward slashes / will be used in favour of backslashes.
163 def __str__(self) -> str: 164 if bool(self): 165 return (self._path.drive + _rules.generic_rules.drive_postfixes[0] if self._path.drive != "" else "") + (_rules.generic_rules.roots[0] if self._path.absolute else "") + _rules.generic_rules.separators[0].join(self._path.relative_parts) 166 else: 167 return _rules.generic_rules.current_indicators[0]
Return a string representation of the path in the preferred format for the target platform
Usage: str(rp)
Inherited Members
- builtins.object
- __new__
- __getattribute__
- __setattr__
- __delattr__
- __ne__
- __reduce_ex__
- __reduce__
- __getstate__
- __subclasshook__
- __init_subclass__
- __format__
- __sizeof__
- __dir__
170class PosixRenderedPath(RenderedPath): 171 """ 172 A rendered path meant for POSIX-like operating systems, such as Linux and macOS. 173 174 If the original path contains a drive, it will be ignored for both printing and collation. Forward slashes are used always. 175 """ 176 def __str__(self) -> str: 177 if bool(self): 178 return (_rules.posix_rules.roots[0] if self._path.absolute else "") + _rules.posix_rules.separators[0].join(self._path.relative_parts) 179 else: 180 return _rules.posix_rules.current_indicators[0] 181 182 def __bool__(self) -> bool: 183 """ 184 False if `self` is a relative path without any relative components, and True otherwise. 185 186 Usage: <code>bool(<var>rp</var>)</code>, <code>not <var>rp</var></code>, or <code>if <var>rp</var>:</code> 187 """ 188 return self._path.absolute or self._path.parent_level != 0 or len(self._path.named_parts) > 0 189 190 @property 191 def _tuple(self) -> tuple: 192 return ( 193 self._path.absolute, 194 self._path.parent_level, 195 self._path.named_parts, 196 )
A rendered path meant for POSIX-like operating systems, such as Linux and macOS.
If the original path contains a drive, it will be ignored for both printing and collation. Forward slashes are used always.
176 def __str__(self) -> str: 177 if bool(self): 178 return (_rules.posix_rules.roots[0] if self._path.absolute else "") + _rules.posix_rules.separators[0].join(self._path.relative_parts) 179 else: 180 return _rules.posix_rules.current_indicators[0]
Return a string representation of the path in the preferred format for the target platform
Usage: str(rp)
182 def __bool__(self) -> bool: 183 """ 184 False if `self` is a relative path without any relative components, and True otherwise. 185 186 Usage: <code>bool(<var>rp</var>)</code>, <code>not <var>rp</var></code>, or <code>if <var>rp</var>:</code> 187 """ 188 return self._path.absolute or self._path.parent_level != 0 or len(self._path.named_parts) > 0
False if self is a relative path without any relative components, and True otherwise.
Usage: bool(rp), not rp, or if rp:
Inherited Members
- builtins.object
- __new__
- __getattribute__
- __setattr__
- __delattr__
- __ne__
- __reduce_ex__
- __reduce__
- __getstate__
- __subclasshook__
- __init_subclass__
- __format__
- __sizeof__
- __dir__
Alias of PosixRenderedPath
Alias of PosixRenderedPath
205class WindowsRenderedPath(RenderedPath): 206 """ 207 A rendered path meant for Windows operating systems. 208 209 The path may or may not contain a drive, which affects both its printed output and its collation order. Backslashes are used always, although forward slashes are supported on Windows NT also. 210 """ 211 def __str__(self) -> str: 212 if bool(self): 213 return (self._path.drive + _rules.windows_rules.drive_postfixes[0] if self._path.drive != "" else "") + (_rules.windows_rules.roots[0] if self._path.absolute else "") + _rules.windows_rules.separators[0].join(self._path.relative_parts) 214 else: 215 return _rules.windows_rules.current_indicators[0]
A rendered path meant for Windows operating systems.
The path may or may not contain a drive, which affects both its printed output and its collation order. Backslashes are used always, although forward slashes are supported on Windows NT also.
211 def __str__(self) -> str: 212 if bool(self): 213 return (self._path.drive + _rules.windows_rules.drive_postfixes[0] if self._path.drive != "" else "") + (_rules.windows_rules.roots[0] if self._path.absolute else "") + _rules.windows_rules.separators[0].join(self._path.relative_parts) 214 else: 215 return _rules.windows_rules.current_indicators[0]
Return a string representation of the path in the preferred format for the target platform
Usage: str(rp)
Inherited Members
- builtins.object
- __new__
- __getattribute__
- __setattr__
- __delattr__
- __ne__
- __reduce_ex__
- __reduce__
- __getstate__
- __subclasshook__
- __init_subclass__
- __format__
- __sizeof__
- __dir__