python-fsutil 0.14.0__tar.gz → 0.15.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python-fsutil-0.14.0/python_fsutil.egg-info → python_fsutil-0.15.0}/PKG-INFO +4 -5
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/README.md +1 -1
- python_fsutil-0.15.0/fsutil/__init__.py +199 -0
- python_fsutil-0.15.0/fsutil/archives.py +163 -0
- python_fsutil-0.15.0/fsutil/args.py +13 -0
- python_fsutil-0.15.0/fsutil/checks.py +114 -0
- python_fsutil-0.15.0/fsutil/converters.py +34 -0
- python_fsutil-0.15.0/fsutil/deps.py +13 -0
- python_fsutil-0.15.0/fsutil/info.py +187 -0
- python_fsutil-0.15.0/fsutil/io.py +231 -0
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/fsutil/metadata.py +1 -1
- python_fsutil-0.15.0/fsutil/operations.py +536 -0
- python_fsutil-0.15.0/fsutil/paths.py +199 -0
- python_fsutil-0.15.0/fsutil/perms.py +28 -0
- python_fsutil-0.15.0/fsutil/types.py +6 -0
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/pyproject.toml +2 -3
- {python-fsutil-0.14.0 → python_fsutil-0.15.0/python_fsutil.egg-info}/PKG-INFO +4 -5
- python_fsutil-0.15.0/python_fsutil.egg-info/SOURCES.txt +34 -0
- python_fsutil-0.15.0/tests/test_archives.py +133 -0
- python_fsutil-0.15.0/tests/test_args.py +29 -0
- python_fsutil-0.15.0/tests/test_checks.py +111 -0
- python_fsutil-0.15.0/tests/test_converters.py +86 -0
- python_fsutil-0.15.0/tests/test_deps.py +25 -0
- python_fsutil-0.15.0/tests/test_info.py +167 -0
- python_fsutil-0.15.0/tests/test_io.py +204 -0
- python_fsutil-0.15.0/tests/test_metadata.py +25 -0
- python_fsutil-0.15.0/tests/test_operations.py +538 -0
- python_fsutil-0.15.0/tests/test_paths.py +191 -0
- python_fsutil-0.15.0/tests/test_perms.py +26 -0
- python-fsutil-0.14.0/fsutil/__init__.py +0 -1495
- python-fsutil-0.14.0/python_fsutil.egg-info/SOURCES.txt +0 -13
- python-fsutil-0.14.0/tests/test.py +0 -1389
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/LICENSE.txt +0 -0
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/MANIFEST.in +0 -0
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/fsutil/py.typed +0 -0
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/python_fsutil.egg-info/dependency_links.txt +0 -0
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/python_fsutil.egg-info/top_level.txt +0 -0
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/setup.cfg +0 -0
- {python-fsutil-0.14.0 → python_fsutil-0.15.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: python-fsutil
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: high-level file-system operations for lazy devs.
|
|
5
5
|
Author-email: Fabio Caccamo <fabio.caccamo@gmail.com>
|
|
6
6
|
Maintainer-email: Fabio Caccamo <fabio.caccamo@gmail.com>
|
|
@@ -42,11 +42,10 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
42
42
|
Classifier: Natural Language :: English
|
|
43
43
|
Classifier: Operating System :: OS Independent
|
|
44
44
|
Classifier: Programming Language :: Python :: 3
|
|
45
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
46
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
47
45
|
Classifier: Programming Language :: Python :: 3.10
|
|
48
46
|
Classifier: Programming Language :: Python :: 3.11
|
|
49
47
|
Classifier: Programming Language :: Python :: 3.12
|
|
48
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
50
49
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
51
50
|
Classifier: Topic :: Desktop Environment :: File Managers
|
|
52
51
|
Classifier: Topic :: Software Development :: Build Tools
|
|
@@ -507,7 +506,7 @@ permissions = fsutil.get_permissions(path)
|
|
|
507
506
|
#### `get_unique_name`
|
|
508
507
|
|
|
509
508
|
```python
|
|
510
|
-
# Get a unique name for a directory/file
|
|
509
|
+
# Get a unique name for a directory/file at the given directory path.
|
|
511
510
|
unique_name = fsutil.get_unique_name(path, prefix="", suffix="", extension="", separator="-")
|
|
512
511
|
```
|
|
513
512
|
|
|
@@ -449,7 +449,7 @@ permissions = fsutil.get_permissions(path)
|
|
|
449
449
|
#### `get_unique_name`
|
|
450
450
|
|
|
451
451
|
```python
|
|
452
|
-
# Get a unique name for a directory/file
|
|
452
|
+
# Get a unique name for a directory/file at the given directory path.
|
|
453
453
|
unique_name = fsutil.get_unique_name(path, prefix="", suffix="", extension="", separator="-")
|
|
454
454
|
```
|
|
455
455
|
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from fsutil.archives import (
|
|
4
|
+
create_tar_file,
|
|
5
|
+
create_zip_file,
|
|
6
|
+
extract_tar_file,
|
|
7
|
+
extract_zip_file,
|
|
8
|
+
)
|
|
9
|
+
from fsutil.checks import (
|
|
10
|
+
assert_dir,
|
|
11
|
+
assert_exists,
|
|
12
|
+
assert_file,
|
|
13
|
+
assert_not_dir,
|
|
14
|
+
assert_not_exists,
|
|
15
|
+
assert_not_file,
|
|
16
|
+
exists,
|
|
17
|
+
is_dir,
|
|
18
|
+
is_empty,
|
|
19
|
+
is_empty_dir,
|
|
20
|
+
is_empty_file,
|
|
21
|
+
is_file,
|
|
22
|
+
)
|
|
23
|
+
from fsutil.converters import convert_size_bytes_to_string, convert_size_string_to_bytes
|
|
24
|
+
from fsutil.info import (
|
|
25
|
+
get_dir_creation_date,
|
|
26
|
+
get_dir_creation_date_formatted,
|
|
27
|
+
get_dir_hash,
|
|
28
|
+
get_dir_last_modified_date,
|
|
29
|
+
get_dir_last_modified_date_formatted,
|
|
30
|
+
get_dir_size,
|
|
31
|
+
get_dir_size_formatted,
|
|
32
|
+
get_file_creation_date,
|
|
33
|
+
get_file_creation_date_formatted,
|
|
34
|
+
get_file_hash,
|
|
35
|
+
get_file_last_modified_date,
|
|
36
|
+
get_file_last_modified_date_formatted,
|
|
37
|
+
get_file_size,
|
|
38
|
+
get_file_size_formatted,
|
|
39
|
+
)
|
|
40
|
+
from fsutil.io import (
|
|
41
|
+
read_file,
|
|
42
|
+
read_file_from_url,
|
|
43
|
+
read_file_json,
|
|
44
|
+
read_file_lines,
|
|
45
|
+
read_file_lines_count,
|
|
46
|
+
write_file,
|
|
47
|
+
write_file_json,
|
|
48
|
+
)
|
|
49
|
+
from fsutil.metadata import (
|
|
50
|
+
__author__,
|
|
51
|
+
__copyright__,
|
|
52
|
+
__description__,
|
|
53
|
+
__email__,
|
|
54
|
+
__license__,
|
|
55
|
+
__title__,
|
|
56
|
+
__version__,
|
|
57
|
+
)
|
|
58
|
+
from fsutil.operations import (
|
|
59
|
+
clean_dir,
|
|
60
|
+
copy_dir,
|
|
61
|
+
copy_dir_content,
|
|
62
|
+
copy_file,
|
|
63
|
+
create_dir,
|
|
64
|
+
create_file,
|
|
65
|
+
delete_dir,
|
|
66
|
+
delete_dir_content,
|
|
67
|
+
delete_dirs,
|
|
68
|
+
delete_file,
|
|
69
|
+
delete_files,
|
|
70
|
+
download_file,
|
|
71
|
+
list_dirs,
|
|
72
|
+
list_files,
|
|
73
|
+
make_dirs,
|
|
74
|
+
make_dirs_for_file,
|
|
75
|
+
move_dir,
|
|
76
|
+
move_file,
|
|
77
|
+
remove_dir,
|
|
78
|
+
remove_dir_content,
|
|
79
|
+
remove_dirs,
|
|
80
|
+
remove_file,
|
|
81
|
+
remove_files,
|
|
82
|
+
rename_dir,
|
|
83
|
+
rename_file,
|
|
84
|
+
rename_file_basename,
|
|
85
|
+
rename_file_extension,
|
|
86
|
+
replace_dir,
|
|
87
|
+
replace_file,
|
|
88
|
+
search_dirs,
|
|
89
|
+
search_files,
|
|
90
|
+
)
|
|
91
|
+
from fsutil.paths import (
|
|
92
|
+
get_file_basename,
|
|
93
|
+
get_file_extension,
|
|
94
|
+
get_filename,
|
|
95
|
+
get_parent_dir,
|
|
96
|
+
get_unique_name,
|
|
97
|
+
join_filename,
|
|
98
|
+
join_filepath,
|
|
99
|
+
join_path,
|
|
100
|
+
split_filename,
|
|
101
|
+
split_filepath,
|
|
102
|
+
split_path,
|
|
103
|
+
transform_filepath,
|
|
104
|
+
)
|
|
105
|
+
from fsutil.perms import get_permissions, set_permissions
|
|
106
|
+
|
|
107
|
+
__all__ = [
|
|
108
|
+
"__author__",
|
|
109
|
+
"__copyright__",
|
|
110
|
+
"__description__",
|
|
111
|
+
"__email__",
|
|
112
|
+
"__license__",
|
|
113
|
+
"__title__",
|
|
114
|
+
"__version__",
|
|
115
|
+
"assert_dir",
|
|
116
|
+
"assert_exists",
|
|
117
|
+
"assert_file",
|
|
118
|
+
"assert_not_dir",
|
|
119
|
+
"assert_not_exists",
|
|
120
|
+
"assert_not_file",
|
|
121
|
+
"clean_dir",
|
|
122
|
+
"convert_size_bytes_to_string",
|
|
123
|
+
"convert_size_string_to_bytes",
|
|
124
|
+
"copy_dir",
|
|
125
|
+
"copy_dir_content",
|
|
126
|
+
"copy_file",
|
|
127
|
+
"create_dir",
|
|
128
|
+
"create_file",
|
|
129
|
+
"create_tar_file",
|
|
130
|
+
"create_zip_file",
|
|
131
|
+
"delete_dir",
|
|
132
|
+
"delete_dir_content",
|
|
133
|
+
"delete_dirs",
|
|
134
|
+
"delete_file",
|
|
135
|
+
"delete_files",
|
|
136
|
+
"download_file",
|
|
137
|
+
"exists",
|
|
138
|
+
"extract_tar_file",
|
|
139
|
+
"extract_zip_file",
|
|
140
|
+
"get_dir_creation_date",
|
|
141
|
+
"get_dir_creation_date_formatted",
|
|
142
|
+
"get_dir_hash",
|
|
143
|
+
"get_dir_last_modified_date",
|
|
144
|
+
"get_dir_last_modified_date_formatted",
|
|
145
|
+
"get_dir_size",
|
|
146
|
+
"get_dir_size_formatted",
|
|
147
|
+
"get_file_basename",
|
|
148
|
+
"get_file_creation_date",
|
|
149
|
+
"get_file_creation_date_formatted",
|
|
150
|
+
"get_file_extension",
|
|
151
|
+
"get_file_hash",
|
|
152
|
+
"get_file_last_modified_date",
|
|
153
|
+
"get_file_last_modified_date_formatted",
|
|
154
|
+
"get_file_size",
|
|
155
|
+
"get_file_size_formatted",
|
|
156
|
+
"get_filename",
|
|
157
|
+
"get_parent_dir",
|
|
158
|
+
"get_permissions",
|
|
159
|
+
"get_unique_name",
|
|
160
|
+
"is_dir",
|
|
161
|
+
"is_empty",
|
|
162
|
+
"is_empty_dir",
|
|
163
|
+
"is_empty_file",
|
|
164
|
+
"is_file",
|
|
165
|
+
"join_filename",
|
|
166
|
+
"join_filepath",
|
|
167
|
+
"join_path",
|
|
168
|
+
"list_dirs",
|
|
169
|
+
"list_files",
|
|
170
|
+
"make_dirs",
|
|
171
|
+
"make_dirs_for_file",
|
|
172
|
+
"move_dir",
|
|
173
|
+
"move_file",
|
|
174
|
+
"read_file",
|
|
175
|
+
"read_file_from_url",
|
|
176
|
+
"read_file_json",
|
|
177
|
+
"read_file_lines",
|
|
178
|
+
"read_file_lines_count",
|
|
179
|
+
"remove_dir",
|
|
180
|
+
"remove_dir_content",
|
|
181
|
+
"remove_dirs",
|
|
182
|
+
"remove_file",
|
|
183
|
+
"remove_files",
|
|
184
|
+
"rename_dir",
|
|
185
|
+
"rename_file",
|
|
186
|
+
"rename_file_basename",
|
|
187
|
+
"rename_file_extension",
|
|
188
|
+
"replace_dir",
|
|
189
|
+
"replace_file",
|
|
190
|
+
"search_dirs",
|
|
191
|
+
"search_files",
|
|
192
|
+
"set_permissions",
|
|
193
|
+
"split_filename",
|
|
194
|
+
"split_filepath",
|
|
195
|
+
"split_path",
|
|
196
|
+
"transform_filepath",
|
|
197
|
+
"write_file",
|
|
198
|
+
"write_file_json",
|
|
199
|
+
]
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import tarfile
|
|
6
|
+
import zipfile
|
|
7
|
+
from collections.abc import Callable, Iterable
|
|
8
|
+
from typing import Literal
|
|
9
|
+
|
|
10
|
+
from fsutil.args import get_path as _get_path
|
|
11
|
+
from fsutil.checks import (
|
|
12
|
+
assert_exists,
|
|
13
|
+
assert_file,
|
|
14
|
+
assert_not_dir,
|
|
15
|
+
assert_not_exists,
|
|
16
|
+
assert_not_file,
|
|
17
|
+
is_dir,
|
|
18
|
+
is_file,
|
|
19
|
+
)
|
|
20
|
+
from fsutil.operations import make_dirs, make_dirs_for_file, remove_file
|
|
21
|
+
from fsutil.paths import get_filename, join_path
|
|
22
|
+
from fsutil.types import PathIn
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def create_tar_file(
|
|
26
|
+
path: PathIn,
|
|
27
|
+
content_paths: list[PathIn],
|
|
28
|
+
*,
|
|
29
|
+
overwrite: bool = True,
|
|
30
|
+
compression: str = "", # literal: gz, bz2, xz
|
|
31
|
+
) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Create tar file at path compressing directories/files listed in content_paths.
|
|
34
|
+
If overwrite is allowed and dest tar already exists, it will be overwritten.
|
|
35
|
+
"""
|
|
36
|
+
path = _get_path(path)
|
|
37
|
+
assert_not_dir(path)
|
|
38
|
+
if not overwrite:
|
|
39
|
+
assert_not_exists(path)
|
|
40
|
+
make_dirs_for_file(path)
|
|
41
|
+
|
|
42
|
+
def _write_content_to_tar_file(
|
|
43
|
+
file: tarfile.TarFile, content_path: PathIn, basedir: str = ""
|
|
44
|
+
) -> None:
|
|
45
|
+
path = _get_path(content_path)
|
|
46
|
+
assert_exists(path)
|
|
47
|
+
if is_file(path):
|
|
48
|
+
filename = get_filename(path)
|
|
49
|
+
filepath = join_path(basedir, filename)
|
|
50
|
+
file.add(path, filepath)
|
|
51
|
+
elif is_dir(path):
|
|
52
|
+
for item_name in os.listdir(path):
|
|
53
|
+
item_path = join_path(path, item_name)
|
|
54
|
+
item_basedir = (
|
|
55
|
+
join_path(basedir, item_name) if is_dir(item_path) else basedir
|
|
56
|
+
)
|
|
57
|
+
_write_content_to_tar_file(file, item_path, item_basedir)
|
|
58
|
+
|
|
59
|
+
mode = f"w:{compression}" if compression else "w"
|
|
60
|
+
with tarfile.open(path, mode=mode) as file: # type: ignore
|
|
61
|
+
for content_path in content_paths:
|
|
62
|
+
_write_content_to_tar_file(file, content_path)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def create_zip_file(
|
|
66
|
+
path: PathIn,
|
|
67
|
+
content_paths: list[PathIn],
|
|
68
|
+
*,
|
|
69
|
+
overwrite: bool = True,
|
|
70
|
+
compression: int = zipfile.ZIP_DEFLATED,
|
|
71
|
+
) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Create zip file at path compressing directories/files listed in content_paths.
|
|
74
|
+
If overwrite is allowed and dest zip already exists, it will be overwritten.
|
|
75
|
+
"""
|
|
76
|
+
path = _get_path(path)
|
|
77
|
+
assert_not_dir(path)
|
|
78
|
+
if not overwrite:
|
|
79
|
+
assert_not_exists(path)
|
|
80
|
+
make_dirs_for_file(path)
|
|
81
|
+
|
|
82
|
+
def _write_content_to_zip_file(
|
|
83
|
+
file: zipfile.ZipFile, content_path: PathIn, basedir: str = ""
|
|
84
|
+
) -> None:
|
|
85
|
+
path = _get_path(content_path)
|
|
86
|
+
assert_exists(path)
|
|
87
|
+
if is_file(path):
|
|
88
|
+
filename = get_filename(path)
|
|
89
|
+
filepath = join_path(basedir, filename)
|
|
90
|
+
file.write(path, filepath)
|
|
91
|
+
elif is_dir(path):
|
|
92
|
+
for item_name in os.listdir(path):
|
|
93
|
+
item_path = join_path(path, item_name)
|
|
94
|
+
item_basedir = (
|
|
95
|
+
join_path(basedir, item_name) if is_dir(item_path) else basedir
|
|
96
|
+
)
|
|
97
|
+
_write_content_to_zip_file(file, item_path, item_basedir)
|
|
98
|
+
|
|
99
|
+
with zipfile.ZipFile(path, "w", compression) as file:
|
|
100
|
+
for content_path in content_paths:
|
|
101
|
+
_write_content_to_zip_file(file, content_path)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def extract_tar_file(
|
|
105
|
+
path: PathIn,
|
|
106
|
+
dest: PathIn,
|
|
107
|
+
*,
|
|
108
|
+
autodelete: bool = False,
|
|
109
|
+
content_paths: Iterable[tarfile.TarInfo] | None = None,
|
|
110
|
+
filter: (
|
|
111
|
+
Callable[[tarfile.TarInfo, str], tarfile.TarInfo | None]
|
|
112
|
+
| Literal["fully_trusted", "tar", "data"]
|
|
113
|
+
)
|
|
114
|
+
| None = None,
|
|
115
|
+
) -> None:
|
|
116
|
+
"""
|
|
117
|
+
Extract tar file at path to dest path.
|
|
118
|
+
If autodelete, the archive will be deleted after extraction.
|
|
119
|
+
If content_paths list is defined,
|
|
120
|
+
only listed items will be extracted, otherwise all.
|
|
121
|
+
"""
|
|
122
|
+
path = _get_path(path)
|
|
123
|
+
dest = _get_path(dest)
|
|
124
|
+
assert_file(path)
|
|
125
|
+
assert_not_file(dest)
|
|
126
|
+
make_dirs(dest)
|
|
127
|
+
with tarfile.TarFile(path, "r") as file:
|
|
128
|
+
if sys.version_info < (3, 12):
|
|
129
|
+
file.extractall(dest, members=content_paths)
|
|
130
|
+
else:
|
|
131
|
+
# https://docs.python.org/3/library/tarfile.html#tarfile-extraction-filter
|
|
132
|
+
file.extractall(
|
|
133
|
+
dest,
|
|
134
|
+
members=content_paths,
|
|
135
|
+
numeric_owner=False,
|
|
136
|
+
filter=(filter or "data"),
|
|
137
|
+
)
|
|
138
|
+
if autodelete:
|
|
139
|
+
remove_file(path)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def extract_zip_file(
|
|
143
|
+
path: PathIn,
|
|
144
|
+
dest: PathIn,
|
|
145
|
+
*,
|
|
146
|
+
autodelete: bool = False,
|
|
147
|
+
content_paths: Iterable[str | zipfile.ZipInfo] | None = None,
|
|
148
|
+
) -> None:
|
|
149
|
+
"""
|
|
150
|
+
Extract zip file at path to dest path.
|
|
151
|
+
If autodelete, the archive will be deleted after extraction.
|
|
152
|
+
If content_paths list is defined,
|
|
153
|
+
only listed items will be extracted, otherwise all.
|
|
154
|
+
"""
|
|
155
|
+
path = _get_path(path)
|
|
156
|
+
dest = _get_path(dest)
|
|
157
|
+
assert_file(path)
|
|
158
|
+
assert_not_file(dest)
|
|
159
|
+
make_dirs(dest)
|
|
160
|
+
with zipfile.ZipFile(path, "r") as file:
|
|
161
|
+
file.extractall(dest, members=content_paths)
|
|
162
|
+
if autodelete:
|
|
163
|
+
remove_file(path)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from fsutil.args import get_path as _get_path
|
|
6
|
+
from fsutil.types import PathIn
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def assert_dir(path: PathIn) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Raise an OSError if the given path doesn't exist or it is not a directory.
|
|
12
|
+
"""
|
|
13
|
+
path = _get_path(path)
|
|
14
|
+
if not is_dir(path):
|
|
15
|
+
raise OSError(f"Invalid directory path: {path}")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def assert_exists(path: PathIn) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Raise an OSError if the given path doesn't exist.
|
|
21
|
+
"""
|
|
22
|
+
path = _get_path(path)
|
|
23
|
+
if not exists(path):
|
|
24
|
+
raise OSError(f"Invalid item path: {path}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def assert_file(path: PathIn) -> None:
|
|
28
|
+
"""
|
|
29
|
+
Raise an OSError if the given path doesn't exist or it is not a file.
|
|
30
|
+
"""
|
|
31
|
+
path = _get_path(path)
|
|
32
|
+
if not is_file(path):
|
|
33
|
+
raise OSError(f"Invalid file path: {path}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def assert_not_dir(path: PathIn) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Raise an OSError if the given path is an existing directory.
|
|
39
|
+
"""
|
|
40
|
+
path = _get_path(path)
|
|
41
|
+
if is_dir(path):
|
|
42
|
+
raise OSError(f"Invalid path, directory already exists: {path}")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def assert_not_exists(path: PathIn) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Raise an OSError if the given path already exists.
|
|
48
|
+
"""
|
|
49
|
+
path = _get_path(path)
|
|
50
|
+
if exists(path):
|
|
51
|
+
raise OSError(f"Invalid path, item already exists: {path}")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def assert_not_file(path: PathIn) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Raise an OSError if the given path is an existing file.
|
|
57
|
+
"""
|
|
58
|
+
path = _get_path(path)
|
|
59
|
+
if is_file(path):
|
|
60
|
+
raise OSError(f"Invalid path, file already exists: {path}")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def exists(path: PathIn) -> bool:
|
|
64
|
+
"""
|
|
65
|
+
Check if a directory of a file exists at the given path.
|
|
66
|
+
"""
|
|
67
|
+
path = _get_path(path)
|
|
68
|
+
return os.path.exists(path)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def is_dir(path: PathIn) -> bool:
|
|
72
|
+
"""
|
|
73
|
+
Determine whether the specified path represents an existing directory.
|
|
74
|
+
"""
|
|
75
|
+
path = _get_path(path)
|
|
76
|
+
return os.path.isdir(path)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def is_empty(path: PathIn) -> bool:
|
|
80
|
+
"""
|
|
81
|
+
Determine whether the specified path represents an empty directory or an empty file.
|
|
82
|
+
"""
|
|
83
|
+
path = _get_path(path)
|
|
84
|
+
assert_exists(path)
|
|
85
|
+
if is_dir(path):
|
|
86
|
+
return is_empty_dir(path)
|
|
87
|
+
return is_empty_file(path)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def is_empty_dir(path: PathIn) -> bool:
|
|
91
|
+
"""
|
|
92
|
+
Determine whether the specified path represents an empty directory.
|
|
93
|
+
"""
|
|
94
|
+
path = _get_path(path)
|
|
95
|
+
assert_dir(path)
|
|
96
|
+
return len(os.listdir(path)) == 0
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def is_empty_file(path: PathIn) -> bool:
|
|
100
|
+
"""
|
|
101
|
+
Determine whether the specified path represents an empty file.
|
|
102
|
+
"""
|
|
103
|
+
from fsutil.info import get_file_size
|
|
104
|
+
|
|
105
|
+
path = _get_path(path)
|
|
106
|
+
return get_file_size(path) == 0
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def is_file(path: PathIn) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
Determine whether the specified path represents an existing file.
|
|
112
|
+
"""
|
|
113
|
+
path = _get_path(path)
|
|
114
|
+
return os.path.isfile(path)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
SIZE_UNITS = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def convert_size_bytes_to_string(size: int) -> str:
|
|
7
|
+
"""
|
|
8
|
+
Convert the given size bytes to string using the right unit suffix.
|
|
9
|
+
"""
|
|
10
|
+
size_num = float(size)
|
|
11
|
+
units = SIZE_UNITS
|
|
12
|
+
factor = 0
|
|
13
|
+
factor_limit = len(units) - 1
|
|
14
|
+
while (size_num >= 1024) and (factor <= factor_limit):
|
|
15
|
+
size_num /= 1024
|
|
16
|
+
factor += 1
|
|
17
|
+
size_units = units[factor]
|
|
18
|
+
size_str = f"{size_num:.2f}" if (factor > 1) else f"{size_num:.0f}"
|
|
19
|
+
size_str = f"{size_str} {size_units}"
|
|
20
|
+
return size_str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def convert_size_string_to_bytes(size: str) -> float | int:
|
|
24
|
+
"""
|
|
25
|
+
Convert the given size string to bytes.
|
|
26
|
+
"""
|
|
27
|
+
units = [item.lower() for item in SIZE_UNITS]
|
|
28
|
+
parts = size.strip().replace(" ", " ").split(" ")
|
|
29
|
+
amount = float(parts[0])
|
|
30
|
+
unit = parts[1]
|
|
31
|
+
factor = units.index(unit.lower())
|
|
32
|
+
if not factor:
|
|
33
|
+
return amount
|
|
34
|
+
return int((1024**factor) * amount)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from types import ModuleType
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def require_requests() -> ModuleType:
|
|
5
|
+
try:
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
return requests
|
|
9
|
+
except ImportError as error:
|
|
10
|
+
raise ModuleNotFoundError(
|
|
11
|
+
"'requests' module is not installed, "
|
|
12
|
+
"it can be installed by running: 'pip install requests'"
|
|
13
|
+
) from error
|