pathlib-next 0.1.1__tar.gz → 0.1.3__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.
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/PKG-INFO +1 -1
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/pyproject.toml +1 -1
- pathlib_next-0.1.3/src/example.py +66 -0
- pathlib_next-0.1.3/src/pathlib_next/mempath.py +149 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/uri/__init__.py +11 -5
- pathlib_next-0.1.1/src/example.py +0 -54
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/.gitignore +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/LICENSE +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/README.md +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/__init__.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/fspath.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/path.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/uri/query.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/uri/schemes/__init__.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/uri/schemes/file.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/uri/schemes/http.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/uri/schemes/sftp.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/uri/source.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/utils/__init__.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/utils/glob.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/utils/stat.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/src/pathlib_next/utils/sync.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/tests/test_local.py +0 -0
- {pathlib_next-0.1.1 → pathlib_next-0.1.3}/tests/test_uri.py +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from pathlib_next import Path, glob
|
|
2
|
+
from pathlib_next.mempath import MemPath
|
|
3
|
+
from pathlib_next.uri import Query, Source, UriPath
|
|
4
|
+
from pathlib_next.uri.schemes import *
|
|
5
|
+
from pathlib_next.utils.sync import PathSyncer
|
|
6
|
+
|
|
7
|
+
mempath = MemPath("test/test3")
|
|
8
|
+
mempath.parent.mkdir(parents=True, exist_ok=True)
|
|
9
|
+
mempath.write_text("test")
|
|
10
|
+
check = mempath.read_text()
|
|
11
|
+
mempath.parent.rm(recursive=True)
|
|
12
|
+
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
local = Path("./_ssh")
|
|
16
|
+
print(list(local.iterdir()))
|
|
17
|
+
query = Query({"test": "://$#!1", "test2&": [1, 2]})
|
|
18
|
+
q2 = Query(str(query)).to_dict()
|
|
19
|
+
for name, value in query:
|
|
20
|
+
print(f"{name}: {value}")
|
|
21
|
+
src = Source(scheme="scheme", userinfo="user", host="123.com", port=0)
|
|
22
|
+
test = {**src}
|
|
23
|
+
test2 = [*src]
|
|
24
|
+
dest = UriPath("file:./_ssh")
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# Norm test
|
|
28
|
+
#
|
|
29
|
+
with_dots = UriPath("a/b/c/d/../../test/.")
|
|
30
|
+
print(with_dots.normalized_path)
|
|
31
|
+
|
|
32
|
+
source_host = UriPath("file://test.com/path1/path2/path3/path4")
|
|
33
|
+
source_host.is_local()
|
|
34
|
+
|
|
35
|
+
rel_to = source_host.relative_to("/path1/path2")
|
|
36
|
+
dest = UriPath(dest)
|
|
37
|
+
test_ = UriPath("file:") / "test"
|
|
38
|
+
empty = UriPath()
|
|
39
|
+
uri = dest.as_uri()
|
|
40
|
+
|
|
41
|
+
test1 = dest / "test" / "test2/"
|
|
42
|
+
print(test1)
|
|
43
|
+
|
|
44
|
+
sftp_root = UriPath("sftp://root@sftpexample/")
|
|
45
|
+
print(sftp_root.as_posix())
|
|
46
|
+
authkeys = sftp_root / "root/.ssh/authorized_keys"
|
|
47
|
+
print(authkeys.as_posix())
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def checksum(uri: UriPath):
|
|
51
|
+
stat = uri.stat()
|
|
52
|
+
return hash(stat.st_size)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
syncer = PathSyncer(checksum, remove_missing=False)
|
|
56
|
+
syncer.sync((sftp_root / "root/.ssh"), dest, dry_run=True)
|
|
57
|
+
|
|
58
|
+
rocky_repo = UriPath("http://dl.rockylinux.org/pub")
|
|
59
|
+
|
|
60
|
+
glob_test = UriPath("file:./**/*.py")
|
|
61
|
+
|
|
62
|
+
for path in glob.glob(glob_test, recursive=True):
|
|
63
|
+
print(path)
|
|
64
|
+
|
|
65
|
+
print(rocky_repo.is_dir())
|
|
66
|
+
print(list(rocky_repo.iterdir()))
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import posixpath as _posix
|
|
3
|
+
from io import IOBase
|
|
4
|
+
from urllib.parse import quote as _urlquote
|
|
5
|
+
|
|
6
|
+
from .path import Path
|
|
7
|
+
from .utils.stat import FileStat, FileStatLike
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MemPathBackend(dict): ...
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MemBytesIO(io.BytesIO):
|
|
14
|
+
def __init__(self, initial_bytes: bytearray) -> None:
|
|
15
|
+
self._bytes = initial_bytes
|
|
16
|
+
super().__init__(initial_bytes)
|
|
17
|
+
|
|
18
|
+
def close(self) -> None:
|
|
19
|
+
self.seek(0)
|
|
20
|
+
self._bytes.clear()
|
|
21
|
+
self._bytes.extend(self.read())
|
|
22
|
+
return super().close()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MemPath(Path):
|
|
26
|
+
|
|
27
|
+
__slots__ = ("_backend", "_segments", "_normalized")
|
|
28
|
+
|
|
29
|
+
def __init__(self, *segments: str, backend: MemPathBackend = None, **kwargs):
|
|
30
|
+
self._segments = "/".join(segments).split("/")
|
|
31
|
+
self._backend = backend if backend is not None else MemPathBackend()
|
|
32
|
+
self._normalized = None
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def backend(self):
|
|
36
|
+
return self._backend
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def normalized(self):
|
|
40
|
+
if self._normalized is None:
|
|
41
|
+
self._normalized = (
|
|
42
|
+
_posix.normpath("/".join(self.segments))
|
|
43
|
+
.removeprefix(".")
|
|
44
|
+
.removeprefix("/")
|
|
45
|
+
.split("/")
|
|
46
|
+
)
|
|
47
|
+
return self._normalized
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def segments(self):
|
|
51
|
+
return self._segments
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def parts(self):
|
|
55
|
+
return self.segments, self.backend
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def parent(self):
|
|
59
|
+
segments = self.segments[:-1]
|
|
60
|
+
if segments == self.segments:
|
|
61
|
+
return self
|
|
62
|
+
return self.with_segments(*segments)
|
|
63
|
+
|
|
64
|
+
def relative_to(self, other):
|
|
65
|
+
raise NotImplementedError()
|
|
66
|
+
|
|
67
|
+
def with_segments(self, *segments: str):
|
|
68
|
+
return type(self)(*segments, backend=self.backend)
|
|
69
|
+
|
|
70
|
+
def as_uri(self):
|
|
71
|
+
path = "/".join(self.segments)
|
|
72
|
+
return f"mempath:{_urlquote(path)}"
|
|
73
|
+
|
|
74
|
+
def _parent_container(self) -> tuple[dict[str, bytearray], str]:
|
|
75
|
+
parent = self.backend
|
|
76
|
+
*ancestors, name = self.normalized
|
|
77
|
+
for path in ancestors:
|
|
78
|
+
if path not in parent:
|
|
79
|
+
raise FileNotFoundError(self.parent)
|
|
80
|
+
else:
|
|
81
|
+
parent = parent[path]
|
|
82
|
+
|
|
83
|
+
return parent, name
|
|
84
|
+
|
|
85
|
+
def _mkdir(self, mode: int):
|
|
86
|
+
parent, name = self._parent_container()
|
|
87
|
+
if name in parent:
|
|
88
|
+
raise FileExistsError(name)
|
|
89
|
+
parent[name] = {}
|
|
90
|
+
|
|
91
|
+
def rmdir(self):
|
|
92
|
+
parent, name = self._parent_container()
|
|
93
|
+
if not name:
|
|
94
|
+
raise FileNotFoundError(self)
|
|
95
|
+
content = parent.get(name)
|
|
96
|
+
if content is None:
|
|
97
|
+
raise FileNotFoundError(self)
|
|
98
|
+
elif not isinstance(content, dict):
|
|
99
|
+
raise NotADirectoryError(self)
|
|
100
|
+
elif len(content) != 0:
|
|
101
|
+
raise FileExistsError(self)
|
|
102
|
+
parent.pop(name)
|
|
103
|
+
|
|
104
|
+
def unlink(self, missing_ok=False):
|
|
105
|
+
parent, name = self._parent_container()
|
|
106
|
+
if not name:
|
|
107
|
+
if missing_ok:
|
|
108
|
+
return
|
|
109
|
+
raise FileNotFoundError(self)
|
|
110
|
+
content = parent.get(name)
|
|
111
|
+
if content is None:
|
|
112
|
+
if missing_ok:
|
|
113
|
+
return
|
|
114
|
+
raise FileNotFoundError(self)
|
|
115
|
+
elif isinstance(content, dict):
|
|
116
|
+
raise IsADirectoryError(self)
|
|
117
|
+
parent.pop(name)
|
|
118
|
+
|
|
119
|
+
def stat(self, *, follow_symlinks=True) -> FileStatLike:
|
|
120
|
+
parent, name = self._parent_container()
|
|
121
|
+
if not name:
|
|
122
|
+
return FileStat(is_dir=True)
|
|
123
|
+
|
|
124
|
+
if name not in parent:
|
|
125
|
+
return FileNotFoundError(self)
|
|
126
|
+
|
|
127
|
+
return FileStat(is_dir=isinstance(parent[name], dict))
|
|
128
|
+
|
|
129
|
+
def iterdir(self):
|
|
130
|
+
parent, name = self._parent_container()
|
|
131
|
+
content = parent.get(name) if name else parent
|
|
132
|
+
cls = type(self)
|
|
133
|
+
|
|
134
|
+
if not isinstance(content, dict):
|
|
135
|
+
raise NotADirectoryError(self)
|
|
136
|
+
for c in list(content.keys()):
|
|
137
|
+
yield cls(*self.segments, c, backend=self.backend)
|
|
138
|
+
|
|
139
|
+
def _open(self, mode="r", buffering=-1) -> IOBase:
|
|
140
|
+
parent, name = self._parent_container()
|
|
141
|
+
if "w" in mode:
|
|
142
|
+
content = parent.setdefault(name, bytearray())
|
|
143
|
+
return MemBytesIO(content)
|
|
144
|
+
elif name not in parent:
|
|
145
|
+
return FileNotFoundError(self)
|
|
146
|
+
else:
|
|
147
|
+
content = parent[name]
|
|
148
|
+
|
|
149
|
+
return io.BytesIO(content)
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import typing as _ty
|
|
3
|
-
import uritools
|
|
4
|
-
import posixpath as _posix
|
|
5
2
|
import pathlib as _pathlib
|
|
3
|
+
import posixpath as _posix
|
|
4
|
+
import typing as _ty
|
|
6
5
|
|
|
6
|
+
import uritools
|
|
7
7
|
|
|
8
8
|
if _ty.TYPE_CHECKING:
|
|
9
9
|
from typing import Self
|
|
10
10
|
|
|
11
11
|
from .. import utils as _utils
|
|
12
|
+
from ..path import Path, Pathname
|
|
12
13
|
from .query import Query
|
|
13
14
|
from .source import Source
|
|
14
15
|
|
|
15
|
-
from ..path import Path, Pathname
|
|
16
|
-
|
|
17
16
|
UriLike: _ty.TypeAlias = "str | Uri | os.PathLike"
|
|
18
17
|
|
|
19
18
|
_NOSOURCE = Source(None, None, None, None)
|
|
@@ -404,6 +403,13 @@ class UriPath(Uri, Path):
|
|
|
404
403
|
def _initbackend(self):
|
|
405
404
|
return None
|
|
406
405
|
|
|
406
|
+
def _from_parsed_parts(
|
|
407
|
+
self, source: Source, path: str, query: str, fragment: str, /, **kwargs
|
|
408
|
+
):
|
|
409
|
+
if "backend" not in kwargs:
|
|
410
|
+
kwargs["backend"] = self.backend
|
|
411
|
+
return super()._from_parsed_parts(source, path, query, fragment, **kwargs)
|
|
412
|
+
|
|
407
413
|
def _init(
|
|
408
414
|
self,
|
|
409
415
|
source: Source,
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
from pathlib_next.uri import UriPath, Query, Source
|
|
2
|
-
from pathlib_next.uri.schemes import *
|
|
3
|
-
from pathlib_next.utils.sync import PathSyncer
|
|
4
|
-
from pathlib_next import glob, Path
|
|
5
|
-
|
|
6
|
-
local = Path('./_ssh')
|
|
7
|
-
print(list(local.iterdir()))
|
|
8
|
-
query = Query({'test':'://$#!1', 'test2&': [1,2]})
|
|
9
|
-
q2 = Query(str(query)).to_dict()
|
|
10
|
-
for name, value in query:
|
|
11
|
-
print(f"{name}: {value}")
|
|
12
|
-
src = Source(scheme='scheme',userinfo='user', host='123.com', port=0)
|
|
13
|
-
test = {**src}
|
|
14
|
-
test2 = [*src]
|
|
15
|
-
dest = UriPath('file:./_ssh')
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
# Norm test
|
|
19
|
-
#
|
|
20
|
-
with_dots = UriPath('a/b/c/d/../../test/.')
|
|
21
|
-
print(with_dots.normalized_path)
|
|
22
|
-
|
|
23
|
-
source_host = UriPath('file://test.com/path1/path2/path3/path4')
|
|
24
|
-
source_host.is_local()
|
|
25
|
-
|
|
26
|
-
rel_to = source_host.relative_to('/path1/path2')
|
|
27
|
-
dest = UriPath(dest)
|
|
28
|
-
test_ = UriPath('file:') / 'test'
|
|
29
|
-
empty = UriPath()
|
|
30
|
-
uri = dest.as_uri()
|
|
31
|
-
|
|
32
|
-
test1 = dest / 'test' / 'test2/'
|
|
33
|
-
print(test1)
|
|
34
|
-
|
|
35
|
-
sftp_root = UriPath('sftp://root@sftpexample/')
|
|
36
|
-
print(sftp_root.as_posix())
|
|
37
|
-
authkeys = sftp_root / 'root/.ssh/authorized_keys'
|
|
38
|
-
print(authkeys.as_posix())
|
|
39
|
-
|
|
40
|
-
def checksum(uri:UriPath):
|
|
41
|
-
stat = uri.stat()
|
|
42
|
-
return hash(stat.st_size)
|
|
43
|
-
syncer =PathSyncer(checksum, remove_missing=False)
|
|
44
|
-
syncer.sync((sftp_root / 'root/.ssh'), dest, dry_run=True)
|
|
45
|
-
|
|
46
|
-
rocky_repo = UriPath('http://dl.rockylinux.org/pub')
|
|
47
|
-
|
|
48
|
-
glob_test = UriPath("file:./**/*.py")
|
|
49
|
-
|
|
50
|
-
for path in glob.glob(glob_test, recursive=True):
|
|
51
|
-
print(path)
|
|
52
|
-
|
|
53
|
-
print(rocky_repo.is_dir())
|
|
54
|
-
print(list(rocky_repo.iterdir()))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|