pathlib-next 0.1.2__tar.gz → 0.1.4__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.
Files changed (24) hide show
  1. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/PKG-INFO +1 -1
  2. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/pyproject.toml +1 -1
  3. pathlib_next-0.1.4/src/example.py +66 -0
  4. pathlib_next-0.1.4/src/pathlib_next/mempath.py +171 -0
  5. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/uri/__init__.py +4 -5
  6. pathlib_next-0.1.2/src/example.py +0 -54
  7. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/.gitignore +0 -0
  8. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/LICENSE +0 -0
  9. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/README.md +0 -0
  10. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/__init__.py +0 -0
  11. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/fspath.py +0 -0
  12. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/path.py +0 -0
  13. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/uri/query.py +0 -0
  14. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/uri/schemes/__init__.py +0 -0
  15. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/uri/schemes/file.py +0 -0
  16. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/uri/schemes/http.py +0 -0
  17. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/uri/schemes/sftp.py +0 -0
  18. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/uri/source.py +0 -0
  19. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/utils/__init__.py +0 -0
  20. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/utils/glob.py +0 -0
  21. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/utils/stat.py +0 -0
  22. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/src/pathlib_next/utils/sync.py +0 -0
  23. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/tests/test_local.py +0 -0
  24. {pathlib_next-0.1.2 → pathlib_next-0.1.4}/tests/test_uri.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pathlib_next
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Generic Path Protocol based pathlib
5
5
  Project-URL: Homepage, https://github.com/jose-pr/pathlib_next/
6
6
  Project-URL: Issues, https://github.com/jose-pr/pathlib_next/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pathlib_next"
7
- version = "0.1.2"
7
+ version = "0.1.4"
8
8
  authors = [{ name = "Jose A" }]
9
9
  description = "Generic Path Protocol based pathlib"
10
10
  readme = "README.md"
@@ -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") / "subpath"
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,171 @@
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, Pathname
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__(
30
+ self, *segments: str | Pathname | Path, backend: MemPathBackend = None, **kwargs
31
+ ):
32
+ _segments = []
33
+ _backend = None
34
+ for segment in segments:
35
+ if isinstance(segment, MemPath):
36
+ _segments.extend(segment.segments)
37
+ _backend = segment.backend
38
+ elif isinstance(segment, Path):
39
+ raise NotImplementedError()
40
+ elif isinstance(segment, Pathname):
41
+ _segments.extend(segment.segments)
42
+ else:
43
+ _segments.append(segment)
44
+ self._segments = "/".join(_segments).split("/")
45
+ if _backend and backend is None:
46
+ backend = _backend
47
+ self._backend = backend if backend is not None else MemPathBackend()
48
+ self._normalized = None
49
+
50
+ def __repr__(self):
51
+ return "{}({!r})".format(type(self).__name__, self.as_uri())
52
+
53
+ def __str__(self) -> str:
54
+ return self.as_uri()
55
+
56
+ @property
57
+ def backend(self):
58
+ return self._backend
59
+
60
+ @property
61
+ def normalized(self):
62
+ if self._normalized is None:
63
+ self._normalized = (
64
+ _posix.normpath("/".join(self.segments))
65
+ .removeprefix(".")
66
+ .removeprefix("/")
67
+ .split("/")
68
+ )
69
+ return self._normalized
70
+
71
+ @property
72
+ def segments(self):
73
+ return self._segments
74
+
75
+ @property
76
+ def parts(self):
77
+ return self.segments, self.backend
78
+
79
+ @property
80
+ def parent(self):
81
+ segments = self.segments[:-1]
82
+ if segments == self.segments:
83
+ return self
84
+ return self.with_segments(*segments)
85
+
86
+ def relative_to(self, other):
87
+ raise NotImplementedError()
88
+
89
+ def with_segments(self, *segments: str):
90
+ return type(self)(*segments, backend=self.backend)
91
+
92
+ def as_uri(self):
93
+ path = "/".join(self.segments)
94
+ return f"mempath:{_urlquote(path)}"
95
+
96
+ def _parent_container(self) -> tuple[dict[str, bytearray], str]:
97
+ parent = self.backend
98
+ *ancestors, name = self.normalized
99
+ for path in ancestors:
100
+ if path not in parent:
101
+ raise FileNotFoundError(self.parent)
102
+ else:
103
+ parent = parent[path]
104
+
105
+ return parent, name
106
+
107
+ def _mkdir(self, mode: int):
108
+ parent, name = self._parent_container()
109
+ if name in parent:
110
+ raise FileExistsError(name)
111
+ parent[name] = {}
112
+
113
+ def rmdir(self):
114
+ parent, name = self._parent_container()
115
+ if not name:
116
+ raise FileNotFoundError(self)
117
+ content = parent.get(name)
118
+ if content is None:
119
+ raise FileNotFoundError(self)
120
+ elif not isinstance(content, dict):
121
+ raise NotADirectoryError(self)
122
+ elif len(content) != 0:
123
+ raise FileExistsError(self)
124
+ parent.pop(name)
125
+
126
+ def unlink(self, missing_ok=False):
127
+ parent, name = self._parent_container()
128
+ if not name:
129
+ if missing_ok:
130
+ return
131
+ raise FileNotFoundError(self)
132
+ content = parent.get(name)
133
+ if content is None:
134
+ if missing_ok:
135
+ return
136
+ raise FileNotFoundError(self)
137
+ elif isinstance(content, dict):
138
+ raise IsADirectoryError(self)
139
+ parent.pop(name)
140
+
141
+ def stat(self, *, follow_symlinks=True) -> FileStatLike:
142
+ parent, name = self._parent_container()
143
+ if not name:
144
+ return FileStat(is_dir=True)
145
+
146
+ if name not in parent:
147
+ return FileNotFoundError(self)
148
+
149
+ return FileStat(is_dir=isinstance(parent[name], dict))
150
+
151
+ def iterdir(self):
152
+ parent, name = self._parent_container()
153
+ content = parent.get(name) if name else parent
154
+ cls = type(self)
155
+
156
+ if not isinstance(content, dict):
157
+ raise NotADirectoryError(self)
158
+ for c in list(content.keys()):
159
+ yield cls(*self.segments, c, backend=self.backend)
160
+
161
+ def _open(self, mode="r", buffering=-1) -> IOBase:
162
+ parent, name = self._parent_container()
163
+ if "w" in mode:
164
+ content = parent.setdefault(name, bytearray())
165
+ return MemBytesIO(content)
166
+ elif name not in parent:
167
+ return FileNotFoundError(self)
168
+ else:
169
+ content = parent[name]
170
+
171
+ 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)
@@ -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