pathlibutil 0.1.9__tar.gz → 0.2.1__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.
- {pathlibutil-0.1.9 → pathlibutil-0.2.1}/PKG-INFO +11 -3
- {pathlibutil-0.1.9 → pathlibutil-0.2.1}/README.md +10 -2
- {pathlibutil-0.1.9 → pathlibutil-0.2.1}/pathlibutil/__init__.py +1 -1
- pathlibutil-0.2.1/pathlibutil/json.py +48 -0
- {pathlibutil-0.1.9 → pathlibutil-0.2.1}/pathlibutil/path.py +84 -18
- {pathlibutil-0.1.9 → pathlibutil-0.2.1}/pathlibutil/types.py +2 -1
- {pathlibutil-0.1.9 → pathlibutil-0.2.1}/pyproject.toml +26 -23
- {pathlibutil-0.1.9 → pathlibutil-0.2.1}/LICENSE +0 -0
- {pathlibutil-0.1.9 → pathlibutil-0.2.1}/pathlibutil/base.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pathlibutil
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: inherits from pathlib.Path with methods for hashing, copying, deleting and more
|
|
5
5
|
Home-page: https://d-chris.github.io
|
|
6
6
|
License: MIT
|
|
@@ -32,6 +32,7 @@ Description-Content-Type: text/markdown
|
|
|
32
32
|
[](https://d-chris.github.io/pathlibutil)
|
|
33
33
|
[](https://github.com/d-chris/pathlibutil)
|
|
34
34
|
[](https://d-chris.github.io/pathlibutil/htmlcov)
|
|
35
|
+
[](https://github.com/pre-commit/pre-commit)
|
|
35
36
|
|
|
36
37
|
---
|
|
37
38
|
|
|
@@ -55,6 +56,12 @@ Description-Content-Type: text/markdown
|
|
|
55
56
|
- `Path.with_suffix()` to change the multiple suffixes of a file
|
|
56
57
|
- `Path.cwd()` to get the current working directory or executable path when script is bundled, e.g. with `pyinstaller`
|
|
57
58
|
- `Path.resolve()` to resolve a unc path to a mapped windows drive.
|
|
59
|
+
- `Path.walk()` to walk over a directory tree like `os.walk()`
|
|
60
|
+
- `Path.iterdir()` with `recursive` all files from the directory tree will be yielded and `exclude_dirs` via callable.
|
|
61
|
+
|
|
62
|
+
JSON serialization of `Path` objects is supported in `pathlibutil.json`.
|
|
63
|
+
|
|
64
|
+
- `pathlibutil.json.dumps()` and `pathlibutil.json.dump()` to serialize `Path` objects as posix paths.
|
|
58
65
|
|
|
59
66
|
## Installation
|
|
60
67
|
|
|
@@ -176,7 +183,7 @@ deleted directories and the amount of memory freed in MB.
|
|
|
176
183
|
> `Path.delete()`, `Path.size()` and `ByteInt`
|
|
177
184
|
|
|
178
185
|
```python
|
|
179
|
-
from pathlibutil import
|
|
186
|
+
from pathlibutil import ByteInt, Path
|
|
180
187
|
|
|
181
188
|
mem = ByteInt(0)
|
|
182
189
|
i = 0
|
|
@@ -203,9 +210,10 @@ to register new archive formats.
|
|
|
203
210
|
> Path.make_archive(), Path.archive_formats and Path.move()
|
|
204
211
|
|
|
205
212
|
```python
|
|
206
|
-
import pathlibutil
|
|
207
213
|
import shutil
|
|
208
214
|
|
|
215
|
+
import pathlibutil
|
|
216
|
+
|
|
209
217
|
|
|
210
218
|
class RegisterFooBarFormat(pathlibutil.Path, archive="foobar"):
|
|
211
219
|
@classmethod
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
[](https://d-chris.github.io/pathlibutil)
|
|
9
9
|
[](https://github.com/d-chris/pathlibutil)
|
|
10
10
|
[](https://d-chris.github.io/pathlibutil/htmlcov)
|
|
11
|
+
[](https://github.com/pre-commit/pre-commit)
|
|
11
12
|
|
|
12
13
|
---
|
|
13
14
|
|
|
@@ -31,6 +32,12 @@
|
|
|
31
32
|
- `Path.with_suffix()` to change the multiple suffixes of a file
|
|
32
33
|
- `Path.cwd()` to get the current working directory or executable path when script is bundled, e.g. with `pyinstaller`
|
|
33
34
|
- `Path.resolve()` to resolve a unc path to a mapped windows drive.
|
|
35
|
+
- `Path.walk()` to walk over a directory tree like `os.walk()`
|
|
36
|
+
- `Path.iterdir()` with `recursive` all files from the directory tree will be yielded and `exclude_dirs` via callable.
|
|
37
|
+
|
|
38
|
+
JSON serialization of `Path` objects is supported in `pathlibutil.json`.
|
|
39
|
+
|
|
40
|
+
- `pathlibutil.json.dumps()` and `pathlibutil.json.dump()` to serialize `Path` objects as posix paths.
|
|
34
41
|
|
|
35
42
|
## Installation
|
|
36
43
|
|
|
@@ -152,7 +159,7 @@ deleted directories and the amount of memory freed in MB.
|
|
|
152
159
|
> `Path.delete()`, `Path.size()` and `ByteInt`
|
|
153
160
|
|
|
154
161
|
```python
|
|
155
|
-
from pathlibutil import
|
|
162
|
+
from pathlibutil import ByteInt, Path
|
|
156
163
|
|
|
157
164
|
mem = ByteInt(0)
|
|
158
165
|
i = 0
|
|
@@ -179,9 +186,10 @@ to register new archive formats.
|
|
|
179
186
|
> Path.make_archive(), Path.archive_formats and Path.move()
|
|
180
187
|
|
|
181
188
|
```python
|
|
182
|
-
import pathlibutil
|
|
183
189
|
import shutil
|
|
184
190
|
|
|
191
|
+
import pathlibutil
|
|
192
|
+
|
|
185
193
|
|
|
186
194
|
class RegisterFooBarFormat(pathlibutil.Path, archive="foobar"):
|
|
187
195
|
@classmethod
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from pathlibutil.path import Path, Register7zFormat
|
|
6
|
-
from pathlibutil.types import ByteInt, TimeInt, byteint
|
|
6
|
+
from pathlibutil.types import ByteInt, StatResult, TimeInt, byteint
|
|
7
7
|
|
|
8
8
|
__all__ = ["Path", "Register7zFormat", "ByteInt", "byteint", "TimeInt", "StatResult"]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Wrapper around the `json` module that provides a custom JSON encoder for `pathlib.Path`
|
|
3
|
+
objects. This allows `pathlib.Path` objects to be serialized to JSON without having to
|
|
4
|
+
convert them to strings first.
|
|
5
|
+
|
|
6
|
+
```python
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from pathlibutil.json import dump
|
|
9
|
+
|
|
10
|
+
data = {"file": Path(__file__)}
|
|
11
|
+
|
|
12
|
+
with open("data.json", "w") as f:
|
|
13
|
+
dump(data, f)
|
|
14
|
+
```
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import functools
|
|
18
|
+
import json
|
|
19
|
+
import pathlib
|
|
20
|
+
from json import load, loads
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PathEncoder(json.JSONEncoder):
|
|
24
|
+
"""
|
|
25
|
+
JSON encoder that converts `pathlib.Path` objects to their string representation.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def default(self, obj):
|
|
29
|
+
"""
|
|
30
|
+
Convert `pathlib.Path` objects to a string using `pathlib.Path.as_posix()`.
|
|
31
|
+
"""
|
|
32
|
+
if isinstance(obj, pathlib.Path):
|
|
33
|
+
return obj.as_posix()
|
|
34
|
+
|
|
35
|
+
return super().default(obj)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@functools.wraps(json.dump)
|
|
39
|
+
def dump(obj, fp, *, cls=PathEncoder, **kwargs):
|
|
40
|
+
return json.dump(obj, fp, cls=cls, **kwargs)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@functools.wraps(json.dumps)
|
|
44
|
+
def dumps(obj, *, cls=PathEncoder, **kwargs):
|
|
45
|
+
return json.dumps(obj, cls=cls, **kwargs)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
__all__ = ["load", "loads", "dump", "dumps", "PathEncoder"]
|
|
@@ -6,7 +6,7 @@ import re
|
|
|
6
6
|
import shutil
|
|
7
7
|
import subprocess
|
|
8
8
|
import sys
|
|
9
|
-
from typing import Callable, Dict, Generator, List, Literal, Set, Union
|
|
9
|
+
from typing import Callable, Dict, Generator, List, Literal, Set, Tuple, Union
|
|
10
10
|
|
|
11
11
|
from pathlibutil.base import BasePath, _Path
|
|
12
12
|
from pathlibutil.types import ByteInt, StatResult, _stat_result, byteint
|
|
@@ -22,8 +22,8 @@ class Path(BasePath):
|
|
|
22
22
|
|
|
23
23
|
- Contextmanger lets you change the current working directory.
|
|
24
24
|
```python
|
|
25
|
-
with Path(
|
|
26
|
-
print(f
|
|
25
|
+
with Path("path/to/directory") as cwd:
|
|
26
|
+
print(f"current working directory: {cwd}")
|
|
27
27
|
```
|
|
28
28
|
"""
|
|
29
29
|
|
|
@@ -84,15 +84,20 @@ class Path(BasePath):
|
|
|
84
84
|
if not self.is_file():
|
|
85
85
|
raise FileNotFoundError(f"'{self}' is not an existing file")
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
args = (kwargs.pop("length"),)
|
|
89
|
-
except KeyError:
|
|
90
|
-
args = ()
|
|
91
|
-
|
|
92
|
-
return hashlib.new(
|
|
87
|
+
hash = hashlib.new(
|
|
93
88
|
name=algorithm or self.default_hash,
|
|
94
89
|
data=self.read_bytes(),
|
|
95
|
-
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
return hash.hexdigest()
|
|
94
|
+
except TypeError as e:
|
|
95
|
+
try:
|
|
96
|
+
length = kwargs["length"]
|
|
97
|
+
except KeyError:
|
|
98
|
+
raise e
|
|
99
|
+
|
|
100
|
+
return hash.hexdigest(length)
|
|
96
101
|
|
|
97
102
|
def verify(
|
|
98
103
|
self, digest: str, algorithm: str = None, *, strict: bool = True, **kwargs
|
|
@@ -512,6 +517,7 @@ class Path(BasePath):
|
|
|
512
517
|
capture_output=True,
|
|
513
518
|
shell=True,
|
|
514
519
|
encoding="cp850",
|
|
520
|
+
check=True,
|
|
515
521
|
)
|
|
516
522
|
|
|
517
523
|
return result.stdout
|
|
@@ -523,7 +529,7 @@ class Path(BasePath):
|
|
|
523
529
|
re.IGNORECASE | re.MULTILINE,
|
|
524
530
|
)
|
|
525
531
|
return {
|
|
526
|
-
match.group("unc") + "\\": match.group("drive") + ":\\"
|
|
532
|
+
match.group("unc") + "\\": cls(match.group("drive") + ":\\")
|
|
527
533
|
for match in mapped_drives
|
|
528
534
|
}
|
|
529
535
|
except Exception:
|
|
@@ -538,7 +544,7 @@ class Path(BasePath):
|
|
|
538
544
|
|
|
539
545
|
try:
|
|
540
546
|
drive = self._netuse[self.anchor]
|
|
541
|
-
return
|
|
547
|
+
return drive.joinpath(self.relative_to(self.anchor))
|
|
542
548
|
except KeyError:
|
|
543
549
|
return self
|
|
544
550
|
|
|
@@ -567,6 +573,68 @@ class Path(BasePath):
|
|
|
567
573
|
|
|
568
574
|
return p._resolve_unc()
|
|
569
575
|
|
|
576
|
+
def walk(
|
|
577
|
+
self,
|
|
578
|
+
top_down: bool = True,
|
|
579
|
+
on_error: Callable[[OSError], object] = None,
|
|
580
|
+
follow_symlinks: bool = False,
|
|
581
|
+
) -> Generator[Tuple[_Path, List[str], List[str]], None, None]:
|
|
582
|
+
"""
|
|
583
|
+
Walks the directory tree and yields a 3-tuple of (dirpath, dirnames, filenames).
|
|
584
|
+
"""
|
|
585
|
+
try:
|
|
586
|
+
yield from super().walk(
|
|
587
|
+
top_down,
|
|
588
|
+
on_error,
|
|
589
|
+
follow_symlinks,
|
|
590
|
+
)
|
|
591
|
+
except AttributeError:
|
|
592
|
+
for dirpath, dirnames, filenames in os.walk(
|
|
593
|
+
self,
|
|
594
|
+
top_down,
|
|
595
|
+
on_error,
|
|
596
|
+
follow_symlinks,
|
|
597
|
+
):
|
|
598
|
+
yield self.__class__(dirpath), dirnames, filenames
|
|
599
|
+
|
|
600
|
+
def iterdir(
|
|
601
|
+
self,
|
|
602
|
+
*,
|
|
603
|
+
recursive: Union[bool, int] = False,
|
|
604
|
+
exclude_dirs: Callable[[_Path], bool] = None,
|
|
605
|
+
**kwargs,
|
|
606
|
+
) -> Generator[_Path, None, None]:
|
|
607
|
+
"""
|
|
608
|
+
Iterates over the files in the directory.
|
|
609
|
+
|
|
610
|
+
If `recursive` is `True` all files from the directory tree will
|
|
611
|
+
be yielded if it is an `integer` files are yielded to this max. directory depth
|
|
612
|
+
optional` **kwargs` are passed to `Path.walk()`.
|
|
613
|
+
|
|
614
|
+
When recursing, folders can be excluded by passing a callable for
|
|
615
|
+
`exclude_dirs`, e.g.
|
|
616
|
+
|
|
617
|
+
```python
|
|
618
|
+
def exclude_version_control(dirpath: _Path) -> bool:
|
|
619
|
+
return dirpath.name in (".git", ".svn", ".hg", ".bzr", "CVS")
|
|
620
|
+
```
|
|
621
|
+
"""
|
|
622
|
+
if recursive is not False:
|
|
623
|
+
if exclude_dirs and not callable(exclude_dirs):
|
|
624
|
+
raise TypeError("exclude_dirs must be a callable")
|
|
625
|
+
|
|
626
|
+
depth = recursive if type(recursive) is int else None
|
|
627
|
+
|
|
628
|
+
for root, dirs, files in self.walk(**kwargs):
|
|
629
|
+
if depth is not None and len(root.relative_to(self).parts) >= depth:
|
|
630
|
+
dirs[:] = []
|
|
631
|
+
elif exclude_dirs:
|
|
632
|
+
dirs[:] = [d for d in dirs if not exclude_dirs(root.joinpath(d))]
|
|
633
|
+
|
|
634
|
+
yield from (root.joinpath(file) for file in files)
|
|
635
|
+
else:
|
|
636
|
+
yield from super().iterdir()
|
|
637
|
+
|
|
570
638
|
|
|
571
639
|
class Register7zFormat(Path, archive="7z"):
|
|
572
640
|
"""
|
|
@@ -583,20 +651,18 @@ class Register7zFormat(Path, archive="7z"):
|
|
|
583
651
|
|
|
584
652
|
Example:
|
|
585
653
|
```python
|
|
586
|
-
class Register7zArchive(pathlibutil.Path, archive=
|
|
654
|
+
class Register7zArchive(pathlibutil.Path, archive="7z"):
|
|
587
655
|
@classmethod
|
|
588
656
|
def _register_archive_format(cls):
|
|
589
657
|
try:
|
|
590
658
|
from py7zr import pack_7zarchive, unpack_7zarchive
|
|
591
659
|
except ModuleNotFoundError:
|
|
592
|
-
raise ModuleNotFoundError(
|
|
660
|
+
raise ModuleNotFoundError("pip install pathlibutil[7z]")
|
|
593
661
|
else:
|
|
594
662
|
shutil.register_archive_format(
|
|
595
|
-
|
|
596
|
-
)
|
|
597
|
-
shutil.register_unpack_format(
|
|
598
|
-
'7z', ['.7z'], unpack_7zarchive
|
|
663
|
+
"7z", pack_7zarchive, description="7zip archive"
|
|
599
664
|
)
|
|
665
|
+
shutil.register_unpack_format("7z", [".7z"], unpack_7zarchive)
|
|
600
666
|
```
|
|
601
667
|
"""
|
|
602
668
|
|
|
@@ -2,7 +2,7 @@ import functools
|
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
4
|
from datetime import datetime, tzinfo
|
|
5
|
-
from typing import Set, Tuple, TypeVar
|
|
5
|
+
from typing import Iterable, Set, Tuple, TypeVar
|
|
6
6
|
|
|
7
7
|
_ByteInt = TypeVar("_ByteInt", bound="ByteInt")
|
|
8
8
|
_stat_result = TypeVar("_stat_result", bound="os.stat_result")
|
|
@@ -206,6 +206,7 @@ def byteint(func):
|
|
|
206
206
|
```python
|
|
207
207
|
randbyte = byteint(random.randint)
|
|
208
208
|
|
|
209
|
+
|
|
209
210
|
@byteint
|
|
210
211
|
def randhexbyte():
|
|
211
212
|
return hex(random.randint(0, 2**32))
|
|
@@ -1,31 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "poetry.core.masonry.api"
|
|
3
|
+
|
|
4
|
+
requires = [
|
|
5
|
+
"poetry-core",
|
|
6
|
+
]
|
|
7
|
+
|
|
1
8
|
[tool.poetry]
|
|
2
9
|
name = "pathlibutil"
|
|
3
|
-
version = "v0.1
|
|
10
|
+
version = "v0.2.1"
|
|
4
11
|
description = "inherits from pathlib.Path with methods for hashing, copying, deleting and more"
|
|
5
|
-
authors = ["Christoph Dörrer <d-chris@web.de>"]
|
|
12
|
+
authors = [ "Christoph Dörrer <d-chris@web.de>" ]
|
|
6
13
|
readme = "README.md"
|
|
7
14
|
license = "MIT"
|
|
8
15
|
classifiers = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
"Programming Language :: Python :: 3.8",
|
|
17
|
+
"Programming Language :: Python :: 3.9",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
16
23
|
]
|
|
17
|
-
keywords = ["pathlib", "hashlib", "shutil"]
|
|
24
|
+
keywords = [ "pathlib", "hashlib", "shutil" ]
|
|
18
25
|
homepage = "https://d-chris.github.io"
|
|
19
26
|
repository = "https://github.com/d-chris/pathlibutil"
|
|
20
27
|
documentation = "https://d-chris.github.io/pathlibutil"
|
|
21
|
-
include = ["LICENSE"]
|
|
28
|
+
include = [ "LICENSE" ]
|
|
22
29
|
|
|
23
30
|
[tool.poetry.dependencies]
|
|
24
31
|
python = ">=3.8.1,<3.13"
|
|
25
32
|
py7zr = { version = "^0.20.2", optional = true }
|
|
26
33
|
|
|
27
34
|
[tool.poetry.extras]
|
|
28
|
-
7z = ["py7zr"]
|
|
35
|
+
7z = [ "py7zr" ]
|
|
29
36
|
|
|
30
37
|
[tool.poetry.group.dev.dependencies]
|
|
31
38
|
pytest = "^7.4.3"
|
|
@@ -55,19 +62,15 @@ name = "testpypi"
|
|
|
55
62
|
url = "https://test.pypi.org/legacy/"
|
|
56
63
|
priority = "explicit"
|
|
57
64
|
|
|
58
|
-
[build-system]
|
|
59
|
-
requires = ["poetry-core"]
|
|
60
|
-
build-backend = "poetry.core.masonry.api"
|
|
61
|
-
|
|
62
65
|
[tool.pytest.ini_options]
|
|
63
66
|
minversion = "6.0"
|
|
64
67
|
testpaths = "tests"
|
|
65
68
|
addopts = [
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
"--random-order",
|
|
70
|
+
"--color=yes",
|
|
71
|
+
"-s",
|
|
72
|
+
# "--cov=pathlibutil",
|
|
73
|
+
# "--cov-report=term-missing:skip-covered",
|
|
74
|
+
# "--cov-append",
|
|
75
|
+
# "--cov-report=html",
|
|
73
76
|
]
|
|
File without changes
|
|
File without changes
|