Skip to content

Commit 402ccd7

Browse files
committed
x
1 parent 49fd725 commit 402ccd7

6 files changed

Lines changed: 67 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
* the methods `Json.update()` and `Data.set_value_by_path_id()` now intake a dictionary as `update_values` param, instead of a list of strings
2222
* added a new param to the methods `FormatCodes.remove_ansi()` and `FormatCodes.remove_formatting()`:<br>
2323
<code>_ignore_linebreaks: *bool* = False</code> whether to include linebreaks in the removal positions or not
24+
* renamed param `correct_path` in `Path.extend()` and param `correct_paths` in `File.extend_or_make_path()` to `use_closest_match`, since this name describes its functionality better
25+
* moved the method `extend_or_make_path()` from the `xx_file` module to the `xx_path` module and renamed it to `extend_or_make()`
2426

2527
## 18.03.2025 `v1.6.8`
2628
* made it possible to escape formatting codes by putting a slash (`/` *or* `\\`) at the beginning inside the brackets (*e.g.* `[/red]`)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ from xulbux import rgba, hsla, hexa
5555
| <h3>[`xx_file`](https://github.com/XulbuX/PythonLibraryXulbuX/wiki/xx_file)</h3> | advanced working with files (*create files, rename file-extensions, ...*) |
5656
| <h3>[`xx_format_codes`](https://github.com/XulbuX/PythonLibraryXulbuX/wiki/xx_format_codes)</h3> | easy pretty printing with custom format codes (*print, inputs, custom format codes to ANSI, ...*) |
5757
| <h3>[`xx_json`](https://github.com/XulbuX/PythonLibraryXulbuX/wiki/xx_json)</h3> | advanced working with json files (*read, create, update, ...*) |
58-
| <h3>`xx_path`</h3> | advanced path operations (*get paths, smart-extend relative paths, delete paths, ...*) |
58+
| <h3>[`xx_path`](https://github.com/XulbuX/PythonLibraryXulbuX/wiki/xx_path)</h3> | advanced path operations (*get paths, smart-extend relative paths, delete paths, ...*) |
5959
| <h3>`xx_regex`</h3> | generated regex pattern-templates (*match bracket- and quote pairs, match colors, ...*) |
6060
| <h3>[`xx_string`](https://github.com/XulbuX/PythonLibraryXulbuX/wiki/xx_string)</h3> | helpful actions when working with strings. (*normalize, escape, decompose, ...*) |
6161
| <h3>`xx_system`</h3> | advanced system actions (*restart with message, check installed Python libs, ...*) |

src/xulbux/xx_file.py

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
import os as _os
55

66

7-
class SameContentFileExistsError(FileExistsError):
8-
pass
7+
# YAPF: disable
8+
class SameContentFileExistsError(FileExistsError): ...
9+
# YAPF: enable
910

1011

1112
class File:
@@ -40,24 +41,3 @@ def create(file: str, content: str = "", force: bool = False) -> str:
4041
f.write(content)
4142
full_path = _os.path.abspath(file)
4243
return full_path
43-
44-
@staticmethod
45-
def extend_or_make_path(
46-
file: str,
47-
search_in: str | list[str] = None,
48-
prefer_base_dir: bool = True,
49-
correct_paths: bool = False,
50-
) -> str:
51-
"""Tries to find the file and extend the path to be absolute and if the file was not found:\n
52-
Generate the absolute path to the file in the CWD or the running program's base-directory.\n
53-
----------------------------------------------------------------------------------------------
54-
If the `file` is not found in predefined directories, it will be searched in the `search_in`
55-
directory/directories. If the file is still not found, it will return the path to the file in
56-
the base-dir per default or to the file in the CWD if `prefer_base_dir` is set to `False`.\n
57-
----------------------------------------------------------------------------------------------
58-
If `correct_paths` is true, it is possible to have typos in the `search_in` path/s and it
59-
will still find the file if it is under one of those paths."""
60-
try:
61-
return Path.extend(file, search_in, raise_error=True, correct_path=correct_paths)
62-
except FileNotFoundError:
63-
return _os.path.join(Path.script_dir, file) if prefer_base_dir else _os.path.join(_os.getcwd(), file)

src/xulbux/xx_json.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from .xx_data import Data
22
from .xx_file import File
3+
from .xx_path import Path
34

45
from typing import Any
56
import json as _json
@@ -24,7 +25,7 @@ def read(
2425
additionally. (returns: `[processed_json, original_json]`)"""
2526
if not json_file.endswith(".json"):
2627
json_file += ".json"
27-
file_path = File.extend_or_make_path(json_file, prefer_base_dir=True)
28+
file_path = Path.extend_or_make(json_file, prefer_script_dir=True)
2829
with open(file_path, "r") as f:
2930
content = f.read()
3031
try:
@@ -55,7 +56,7 @@ def create(
5556
To always overwrite the file, set the `force` parameter to `True`."""
5657
if not json_file.endswith(".json"):
5758
json_file += ".json"
58-
file_path = File.extend_or_make_path(json_file, prefer_base_dir=True)
59+
file_path = Path.extend_or_make(json_file, prefer_script_dir=True)
5960
File.create(
6061
file=file_path,
6162
content=Data.to_str(data, indent, compactness, as_json=True),

src/xulbux/xx_path.py

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
import sys as _sys
66
import os as _os
77

8+
from regex import P
9+
810

911
# YAPF: disable
10-
class ProcessNotFoundError(Exception):
11-
pass
12+
class PathNotFoundError(FileNotFoundError): ...
1213

1314
class _Cwd:
1415
def __get__(self, obj, owner=None):
@@ -39,9 +40,26 @@ class Path:
3940
"""The path to the directory of the current script."""
4041

4142
@staticmethod
42-
def extend(path: str, search_in: str | list[str] = None, raise_error: bool = False, correct_path: bool = False) -> str:
43-
if path in (None, ""):
44-
return path
43+
def extend(
44+
rel_path: str,
45+
search_in: str | list[str] = None,
46+
raise_error: bool = False,
47+
use_closest_match: bool = False,
48+
) -> Optional[str]:
49+
"""Tries to locate and extend a relative path to an absolute path.\n
50+
--------------------------------------------------------------------------------
51+
If the `rel_path` couldn't be located in predefined directories, it will be
52+
searched in the `search_in` directory/s. If the `rel_path` is still not found,
53+
it returns `None` or raises a `PathNotFoundError` if `raise_error` is true.\n
54+
--------------------------------------------------------------------------------
55+
If `use_closest_match` is true, it is possible to have typos in the `search_in`
56+
path/s and it will still find the file if it is under one of those paths."""
57+
if rel_path in (None, ""):
58+
if raise_error:
59+
raise PathNotFoundError("Path is empty.")
60+
return None
61+
elif _os.path.isabs(rel_path):
62+
return rel_path
4563

4664
def get_closest_match(dir: str, part: str) -> Optional[str]:
4765
try:
@@ -56,7 +74,7 @@ def find_path(start: str, parts: list[str]) -> Optional[str]:
5674
for part in parts:
5775
if _os.path.isfile(current):
5876
return current
59-
closest_match = get_closest_match(current, part) if correct_path else part
77+
closest_match = get_closest_match(current, part) if use_closest_match else part
6078
current = _os.path.join(current, closest_match) if closest_match else None
6179
if current is None:
6280
return None
@@ -71,13 +89,13 @@ def expand_env_path(p: str) -> str:
7189
parts[i] = _os.environ[parts[i].upper()]
7290
return "".join(parts)
7391

74-
path = _os.path.normpath(expand_env_path(path))
75-
if _os.path.isabs(path):
76-
drive, rel_path = _os.path.splitdrive(path)
92+
rel_path = _os.path.normpath(expand_env_path(rel_path))
93+
if _os.path.isabs(rel_path):
94+
drive, rel_path = _os.path.splitdrive(rel_path)
7795
rel_path = rel_path.lstrip(_os.sep)
7896
search_dirs = (drive + _os.sep) if drive else [_os.sep]
7997
else:
80-
rel_path = path.lstrip(_os.sep)
98+
rel_path = rel_path.lstrip(_os.sep)
8199
base_dir = Path.script_dir
82100
search_dirs = (
83101
_os.getcwd(),
@@ -92,15 +110,42 @@ def expand_env_path(p: str) -> str:
92110
full_path = _os.path.join(search_dir, rel_path)
93111
if _os.path.exists(full_path):
94112
return full_path
95-
match = find_path(search_dir, path_parts) if correct_path else None
113+
match = find_path(search_dir, path_parts) if use_closest_match else None
96114
if match:
97115
return match
98116
if raise_error:
99-
raise FileNotFoundError(f"Path '{path}' not found in specified directories.")
100-
return _os.path.join(search_dirs[0], rel_path)
117+
raise PathNotFoundError(f"Path '{rel_path}' not found in specified directories.")
118+
return None
119+
120+
@staticmethod
121+
def extend_or_make(
122+
rel_path: str,
123+
search_in: str | list[str] = None,
124+
prefer_script_dir: bool = True,
125+
use_closest_match: bool = False,
126+
) -> str:
127+
"""Tries to locate and extend a relative path to an absolute path, and if the `rel_path`
128+
couldn't be located, it generates a path, as if it was located.\n
129+
-----------------------------------------------------------------------------------------
130+
If the `rel_path` couldn't be located in predefined directories, it will be searched in
131+
the `search_in` directory/s. If the `rel_path` is still not found, it will makes a path
132+
that points to where the `rel_path` would be in the script directory, even though the
133+
`rel_path` doesn't exist there. If `prefer_script_dir` is false, it will instead make a
134+
path that points to where the `rel_path` would be in the CWD.\n
135+
-----------------------------------------------------------------------------------------
136+
If `use_closest_match` is true, it is possible to have typos in the `search_in` path/s
137+
and it will still find the file if it is under one of those paths."""
138+
try:
139+
return Path.extend(rel_path, search_in, raise_error=True, use_closest_match=use_closest_match)
140+
except PathNotFoundError:
141+
return _os.path.join(Path.script_dir, rel_path) if prefer_script_dir else _os.path.join(_os.getcwd(), rel_path)
101142

102143
@staticmethod
103144
def remove(path: str, only_content: bool = False) -> None:
145+
"""Removes the directory or the directory's content at the specified path.\n
146+
-----------------------------------------------------------------------------
147+
Normally it removes the directory and its content, but if `only_content` is
148+
true, the directory is kept and only its contents are removed."""
104149
if not _os.path.exists(path):
105150
return None
106151
if not only_content:

src/xulbux/xx_system.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88

99

1010
# YAPF: disable
11-
class ProcessNotFoundError(Exception):
12-
pass
13-
1411
class _IsElevated:
1512
def __get__(self, obj, owner=None):
1613
try:

0 commit comments

Comments
 (0)