# GPath
**GPath** is a Python package that provides a robust, generalised abstract file path that allows path manipulations independent from the local environment, maximising cross-platform compatibility.
[](https://pypi.org/project/generic-path/) [](https://github.com/yushiyangk/GPath) [](https://gpath.gnayihs.uy/)
## Install
```
pip install generic-path
```
## Basic examples
Import GPath:
```python
from gpath import GPath
```
Create a GPath object and manipulate it:
```python
g = GPath("/usr/bin")
common = GPath.find_common(g, "/usr/local/bin") # GPath("/usr")
relpath = g.relpath_from("/usr/local/bin") # GPath("../../bin")
joined = GPath.join("/usr/local/bin", relpath) # GPath("/usr/bin")
assert g == joined
```
For function arguments, strings or `os.PathLike` objects can be used interchangeably with GPaths.
Binary operations are also supported:
```python
g1 = GPath("C:/Windows/System32")
g2 = GPath("../SysWOW64/drivers")
added = g1 + g2 # GPath("C:/Windows/SysWOW64/drivers")
subtracted = g1 - 1 # GPath("C:/Windows")
# Shift the imaginary current working directory in relative paths
shifted_right = g2 >> 1 # GPath("../../SysWOW64/drivers")
shifted_left = g2 << 1 # GPath("SysWOW64/drivers")
```
The `GPath.partition()` method is useful when dealing with paths from various different sources:
```python
partitions = GPath.partition("/usr/bin", "/usr/local/bin", "../../doc", "C:/Windows", "C:/Program Files")
assert partitions == {
GPath("/usr") : [GPath("bin"), GPath("local/bin")],
GPath("../../doc") : [GPath("")],
GPath("C:/") : [GPath("Windows"), GPath("Program Files")],
}
```
## Issues
Found a bug? Please [report an issue](https://github.com/yushiyangk/GPath/issues), or, better yet, [contribute a bugfix](https://github.com/yushiyangk/GPath/pulls).
## Compatibility
The default `GPath()` interface supports the vast majority of valid file paths on Windows, Linux and macOS (and other POSIX-like operating systems), with some limited caveats.
### Linux, macOS and POSIX
If using `GPath()`,
- any backslashes `\` (after parsing escape sequences) in the path will be treated as path separators
- if the second character of the path is a colon <code><var>x</var>:</code>, the first character <var>`x`</var> will be treated as a drive letter
These issues can be avoided by using `GPath.from_posix()` instead. This will cause all `\` and `:` to be treated as normal characters in file names.
### Windows
- trailing dots `.` and spaces ` ` will not be stripped
- reserved MS-DOS device names (such as AUX, CLOCK$, COM0 through COM9, CON, LPT0 through LPT9, NUL, PRN) will be treated as normal file names
## Changelog
This project follows [PEP 440](https://peps.python.org/pep-0440/) and [Semantic Versioning (SemVer)](https://semver.org/spec/v2.0.0.html). In addition to the guarantees specified by SemVer, for versions before 1.0, this project guarantees backwards compatibility of the API for patch version updates (0.<var>y</var>.<b><var>z</var></b>).
The recommended version specifier is <code>generic-path ~= <var>x</var>.<var>y</var></code> for version 1.0 and later, and <code>generic-path ~= <var>0</var>.<var>y</var>.<var>z</var></code> for versions prior to 1.0.
### 0.5.1
- Improved documentation
### 0.5
- Added support for Python 3.12 and 3.13
- Dropped support for end-of-life Python versions 3.7 and 3.8
- Removed methods `Platform.__new__` and `Platform.__format__` that were unintentionally documented as public
### 0.4.5
- Improved documentation
### 0.4.4
- Added the ability to force GPath to interpret a path string as originating from a specific operating system, which prevents problems in edge cases, using the new `platform` argument in `GPath.__init__()`; this also propagates to new GPaths returned by operations
- Added the read-only property <code><var>g</var>.platform</code> for this propagating platform parameter
- Added static methods `from_posix()`, `from_windows()` (and aliases `from_linux()` and `from_macos()`) as alternative interfaces to call the constructor for a specific platform
- Added submodule `gpath.platform` with a `Platform` enum for specifying platforms (either as a string given in `gpath.platform.platform_names` or as a `gpath.Platform` object)
- Added <code><var>g</var>.render()</code>, which returns a `RenderedPath` object for printing and sorting in a platform-specific manner
- Added submodule `gpath.render` containing subclasses of `RenderedPath` that define the render behaviour for each platform
- GenericRenderedPath resembles the previous behaviour of GPath, and prints with forward slashes `/`
- PosixRenderedPath ignores drive names when sorting and printing, and always prints with forward slashes `/`
- WindowsRenderedPath always prints with backslashes `\`
- Fixed bug with encoding propagation in the copy constructor
### 0.4.3
- Fixed support for bytes in older versions of Python
### 0.4.1, 0.4.2
- Fixed documentation and readme
### 0.4
#### Breaking API changes
- Replaced the following instance methods with read-only properties:
- <code><var>g</var>.get_parent_level()</code> → <code><var>g</var>.parent_level</code>
- <code><var>g</var>.get_parent_parts()</code> → <code><var>g</var>.parent_parts</code>
- <code><var>g</var>.get_device()</code> → <code><var>g</var>.drive</code> (renamed `device` to `drive`)
- <code><var>g</var>.is_absolute()</code> → <code><var>g</var>.absolute</code>
- <code><var>g</var>.is_root()</code> → <code><var>g</var>.root</code>
- Replaced <code><var>g</var>.get_parts()</code> and <code><var>g</var>.from_parts()</code> with the read-only properties <code><var>g</var>.named_parts</code> and <code><var>g</var>.relative_parts</code>
- Replaced `GPath.find_common()` with <code><var>g</var>.common_with()</code> and added <code><var>g1</var> & <var>g2</var></code> as an alias for <code><var>g</var>.common_with()</code> with default options
- Removed the ability to sort GPaths, and removed the following comparison operators:
- <code><var>g1</var> < <var>g2</var></code>
- <code><var>g1</var> <= <var>g2</var></code>
- <code><var>g1</var> > <var>g2</var></code>
- <code><var>g1</var> >= <var>g2</var></code>
- Removed package constants `PATH_SEPARATOR`, `PATH_CURRENT`, `PATH_PARENT`, and typedef `PathLike`
#### Breaking behavioural changes
- Changed <code><var>g1</var> + <var>g2</var></code>, <code><var>g1</var> / <var>g2</var></code> and <code><var>g</var>.join()</code> so that appending an absolute path overwrites the left operand; previously the left operand would be returned unchanged
- Changed <code><var>g1</var> == <var>g2</var></code> so that it can return True even when the left operand is GPath-like but not a GPath object
#### Other changes
- Added <code><var>g</var>.as_absolute()</code>, <code><var>g</var>.as_relative()</code>, <code><var>g</var>.with_drive()</code>, <code><var>g</var>.without_drive()</code> for returning modified copies of the path
- Added support for drive names in relative paths
- Added support for instantiating a GPath with a bytes-like object, <code>GPath(<var>byteslike</var>)</code> (or, fixed the constructor that was previously broken for bytes-like objects)
- Added an argument to `GPath.__init__()` to allow specifying encoding (default `'utf-8'`), which propagates to new GPaths when performing operations with other bytes-like operands
- Added the read-only property <code><var>g</var>.encoding</code> for this propagating encoding
- Added abstract base classes for GPath, from `collections.abc`
- Fixed <code><var>g1</var> / <var>g2</var></code>
- Fixed small errors in web documentation
### 0.3
- Renamed `GPath.current` to `GPath.current_dir` and `GPath.parent` to `GPath.parent_dir`
- Renamed <code><var>g</var>.is_root()</code> to <code><var>g</var>.is_absolute()</code>
- Renamed the optional arguments in <code><var>g</var>.find_common()</code> and <code><var>g</var>.partition()</code>, from `common_current` and `common_parent` to `allow_current` and `allow_parent`
- Added a new <code><var>g</var>.is_root()</code> that checks whether the path is exactly root
- Added <code><var>g</var>.\_\_div\_\_()</code> as an alias of <code><var>g</var>.\_\_add\_\_()</code>
- Added web documentation at https://gpath.gnayihs.uy/
### 0.2.1
- Fixed basic example in README
### 0.2
- Added support for Python versions 3.7 through 3.9; previously only 3.10 and 3.11 were supported
### 0.1
- Initial version
Raw data
{
"_id": null,
"home_page": null,
"name": "generic-path",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "python, filepath, filesystem, cross-platform",
"author": null,
"author_email": "Yu Shiyang <yu.shiyang@gnayihs.uy>",
"download_url": "https://files.pythonhosted.org/packages/27/00/32e732ae8690e1a927071df3bdfa330d96618c01747a16f4a78db194e35d/generic_path-0.5.1.post1.tar.gz",
"platform": null,
"description": "# GPath\r\n\r\n**GPath** is a Python package that provides a robust, generalised abstract file path that allows path manipulations independent from the local environment, maximising cross-platform compatibility.\r\n\r\n[](https://pypi.org/project/generic-path/) [](https://github.com/yushiyangk/GPath) [](https://gpath.gnayihs.uy/)\r\n\r\n## Install\r\n\r\n```\r\npip install generic-path\r\n```\r\n\r\n## Basic examples\r\n\r\nImport GPath:\r\n```python\r\nfrom gpath import GPath\r\n```\r\n\r\nCreate a GPath object and manipulate it:\r\n```python\r\ng = GPath(\"/usr/bin\")\r\n\r\ncommon = GPath.find_common(g, \"/usr/local/bin\") # GPath(\"/usr\")\r\nrelpath = g.relpath_from(\"/usr/local/bin\") # GPath(\"../../bin\")\r\njoined = GPath.join(\"/usr/local/bin\", relpath) # GPath(\"/usr/bin\")\r\nassert g == joined\r\n```\r\n\r\nFor function arguments, strings or `os.PathLike` objects can be used interchangeably with GPaths.\r\n\r\nBinary operations are also supported:\r\n```python\r\ng1 = GPath(\"C:/Windows/System32\")\r\ng2 = GPath(\"../SysWOW64/drivers\")\r\n\r\nadded = g1 + g2 # GPath(\"C:/Windows/SysWOW64/drivers\")\r\nsubtracted = g1 - 1 # GPath(\"C:/Windows\")\r\n\r\n# Shift the imaginary current working directory in relative paths\r\nshifted_right = g2 >> 1 # GPath(\"../../SysWOW64/drivers\")\r\nshifted_left = g2 << 1 # GPath(\"SysWOW64/drivers\")\r\n```\r\n\r\nThe `GPath.partition()` method is useful when dealing with paths from various different sources:\r\n```python\r\npartitions = GPath.partition(\"/usr/bin\", \"/usr/local/bin\", \"../../doc\", \"C:/Windows\", \"C:/Program Files\")\r\n\r\nassert partitions == {\r\n\tGPath(\"/usr\") : [GPath(\"bin\"), GPath(\"local/bin\")],\r\n\tGPath(\"../../doc\") : [GPath(\"\")],\r\n\tGPath(\"C:/\") : [GPath(\"Windows\"), GPath(\"Program Files\")],\r\n}\r\n```\r\n\r\n## Issues\r\n\r\nFound a bug? Please [report an issue](https://github.com/yushiyangk/GPath/issues), or, better yet, [contribute a bugfix](https://github.com/yushiyangk/GPath/pulls).\r\n\r\n## Compatibility\r\n\r\nThe default `GPath()` interface supports the vast majority of valid file paths on Windows, Linux and macOS (and other POSIX-like operating systems), with some limited caveats.\r\n\r\n### Linux, macOS and POSIX\r\n\r\nIf using `GPath()`,\r\n- any backslashes `\\` (after parsing escape sequences) in the path will be treated as path separators\r\n- if the second character of the path is a colon <code><var>x</var>:</code>, the first character <var>`x`</var> will be treated as a drive letter\r\n\r\nThese issues can be avoided by using `GPath.from_posix()` instead. This will cause all `\\` and `:` to be treated as normal characters in file names.\r\n\r\n### Windows\r\n\r\n- trailing dots `.` and spaces ` ` will not be stripped\r\n- reserved MS-DOS device names (such as AUX, CLOCK$, COM0 through COM9, CON, LPT0 through LPT9, NUL, PRN) will be treated as normal file names\r\n\r\n## Changelog\r\n\r\nThis project follows [PEP 440](https://peps.python.org/pep-0440/) and [Semantic Versioning (SemVer)](https://semver.org/spec/v2.0.0.html). In addition to the guarantees specified by SemVer, for versions before 1.0, this project guarantees backwards compatibility of the API for patch version updates (0.<var>y</var>.<b><var>z</var></b>).\r\n\r\nThe recommended version specifier is <code>generic-path ~= <var>x</var>.<var>y</var></code> for version 1.0 and later, and <code>generic-path ~= <var>0</var>.<var>y</var>.<var>z</var></code> for versions prior to 1.0.\r\n\r\n### 0.5.1\r\n\r\n- Improved documentation\r\n\r\n### 0.5\r\n\r\n- Added support for Python 3.12 and 3.13\r\n- Dropped support for end-of-life Python versions 3.7 and 3.8\r\n- Removed methods `Platform.__new__` and `Platform.__format__` that were unintentionally documented as public\r\n\r\n### 0.4.5\r\n\r\n- Improved documentation\r\n\r\n### 0.4.4\r\n\r\n- Added the ability to force GPath to interpret a path string as originating from a specific operating system, which prevents problems in edge cases, using the new `platform` argument in `GPath.__init__()`; this also propagates to new GPaths returned by operations\r\n\t- Added the read-only property <code><var>g</var>.platform</code> for this propagating platform parameter\r\n\t- Added static methods `from_posix()`, `from_windows()` (and aliases `from_linux()` and `from_macos()`) as alternative interfaces to call the constructor for a specific platform\r\n\t- Added submodule `gpath.platform` with a `Platform` enum for specifying platforms (either as a string given in `gpath.platform.platform_names` or as a `gpath.Platform` object)\r\n- Added <code><var>g</var>.render()</code>, which returns a `RenderedPath` object for printing and sorting in a platform-specific manner\r\n\t- Added submodule `gpath.render` containing subclasses of `RenderedPath` that define the render behaviour for each platform\r\n\t- GenericRenderedPath resembles the previous behaviour of GPath, and prints with forward slashes `/`\r\n\t- PosixRenderedPath ignores drive names when sorting and printing, and always prints with forward slashes `/`\r\n\t- WindowsRenderedPath always prints with backslashes `\\`\r\n- Fixed bug with encoding propagation in the copy constructor\r\n\r\n### 0.4.3\r\n\r\n- Fixed support for bytes in older versions of Python\r\n\r\n### 0.4.1, 0.4.2\r\n\r\n- Fixed documentation and readme\r\n\r\n### 0.4\r\n\r\n#### Breaking API changes\r\n\r\n- Replaced the following instance methods with read-only properties:\r\n\t- <code><var>g</var>.get_parent_level()</code> \u2192 <code><var>g</var>.parent_level</code>\r\n\t- <code><var>g</var>.get_parent_parts()</code> \u2192 <code><var>g</var>.parent_parts</code>\r\n\t- <code><var>g</var>.get_device()</code> \u2192 <code><var>g</var>.drive</code> (renamed `device` to `drive`)\r\n\t- <code><var>g</var>.is_absolute()</code> \u2192 <code><var>g</var>.absolute</code>\r\n\t- <code><var>g</var>.is_root()</code> \u2192 <code><var>g</var>.root</code>\r\n- Replaced <code><var>g</var>.get_parts()</code> and <code><var>g</var>.from_parts()</code> with the read-only properties <code><var>g</var>.named_parts</code> and <code><var>g</var>.relative_parts</code>\r\n- Replaced `GPath.find_common()` with <code><var>g</var>.common_with()</code> and added <code><var>g1</var> & <var>g2</var></code> as an alias for <code><var>g</var>.common_with()</code> with default options\r\n- Removed the ability to sort GPaths, and removed the following comparison operators:\r\n\t- <code><var>g1</var> < <var>g2</var></code>\r\n\t- <code><var>g1</var> <= <var>g2</var></code>\r\n\t- <code><var>g1</var> > <var>g2</var></code>\r\n\t- <code><var>g1</var> >= <var>g2</var></code>\r\n- Removed package constants `PATH_SEPARATOR`, `PATH_CURRENT`, `PATH_PARENT`, and typedef `PathLike`\r\n\r\n#### Breaking behavioural changes\r\n\r\n- Changed <code><var>g1</var> + <var>g2</var></code>, <code><var>g1</var> / <var>g2</var></code> and <code><var>g</var>.join()</code> so that appending an absolute path overwrites the left operand; previously the left operand would be returned unchanged\r\n- Changed <code><var>g1</var> == <var>g2</var></code> so that it can return True even when the left operand is GPath-like but not a GPath object\r\n\r\n#### Other changes\r\n\r\n- Added <code><var>g</var>.as_absolute()</code>, <code><var>g</var>.as_relative()</code>, <code><var>g</var>.with_drive()</code>, <code><var>g</var>.without_drive()</code> for returning modified copies of the path\r\n- Added support for drive names in relative paths\r\n- Added support for instantiating a GPath with a bytes-like object, <code>GPath(<var>byteslike</var>)</code> (or, fixed the constructor that was previously broken for bytes-like objects)\r\n- Added an argument to `GPath.__init__()` to allow specifying encoding (default `'utf-8'`), which propagates to new GPaths when performing operations with other bytes-like operands\r\n- Added the read-only property <code><var>g</var>.encoding</code> for this propagating encoding\r\n- Added abstract base classes for GPath, from `collections.abc`\r\n- Fixed <code><var>g1</var> / <var>g2</var></code>\r\n- Fixed small errors in web documentation\r\n\r\n### 0.3\r\n\r\n- Renamed `GPath.current` to `GPath.current_dir` and `GPath.parent` to `GPath.parent_dir`\r\n- Renamed <code><var>g</var>.is_root()</code> to <code><var>g</var>.is_absolute()</code>\r\n- Renamed the optional arguments in <code><var>g</var>.find_common()</code> and <code><var>g</var>.partition()</code>, from `common_current` and `common_parent` to `allow_current` and `allow_parent`\r\n- Added a new <code><var>g</var>.is_root()</code> that checks whether the path is exactly root\r\n- Added <code><var>g</var>.\\_\\_div\\_\\_()</code> as an alias of <code><var>g</var>.\\_\\_add\\_\\_()</code>\r\n- Added web documentation at https://gpath.gnayihs.uy/\r\n\r\n### 0.2.1\r\n\r\n- Fixed basic example in README\r\n\r\n### 0.2\r\n\r\n- Added support for Python versions 3.7 through 3.9; previously only 3.10 and 3.11 were supported\r\n\r\n### 0.1\r\n\r\n- Initial version\r\n",
"bugtrack_url": null,
"license": "MPL-2.0",
"summary": "Generalised abstract file path that provides path manipulations independent from the local environment",
"version": "0.5.1.post1",
"project_urls": {
"Documentation": "https://gpath.gnayihs.uy/",
"Homepage": "https://github.com/yushiyangk/GPath",
"Issues": "https://github.com/yushiyangk/GPath/issues"
},
"split_keywords": [
"python",
" filepath",
" filesystem",
" cross-platform"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "eee55c0c64cba935db3542183de2ea84d1374182f643100704a068eddd92ad7a",
"md5": "919b859dd587624cdf7b35ecf0817071",
"sha256": "83e558b1ba3bb5aa7c226911b24e15e51047bf50cedbf5ba1b92dec44a424c7f"
},
"downloads": -1,
"filename": "generic_path-0.5.1.post1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "919b859dd587624cdf7b35ecf0817071",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 24923,
"upload_time": "2025-01-27T17:13:35",
"upload_time_iso_8601": "2025-01-27T17:13:35.428903Z",
"url": "https://files.pythonhosted.org/packages/ee/e5/5c0c64cba935db3542183de2ea84d1374182f643100704a068eddd92ad7a/generic_path-0.5.1.post1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "270032e732ae8690e1a927071df3bdfa330d96618c01747a16f4a78db194e35d",
"md5": "c4abb9d1655d0901904cdd7277d9d4fc",
"sha256": "a241f0b30cdbaca613b70fed885bc458ea402a0fd149dbb7388c70d1b28e15d7"
},
"downloads": -1,
"filename": "generic_path-0.5.1.post1.tar.gz",
"has_sig": false,
"md5_digest": "c4abb9d1655d0901904cdd7277d9d4fc",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 137795,
"upload_time": "2025-01-27T17:13:37",
"upload_time_iso_8601": "2025-01-27T17:13:37.925708Z",
"url": "https://files.pythonhosted.org/packages/27/00/32e732ae8690e1a927071df3bdfa330d96618c01747a16f4a78db194e35d/generic_path-0.5.1.post1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-27 17:13:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "yushiyangk",
"github_project": "GPath",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"tox": true,
"lcname": "generic-path"
}