pathlib-next 0.1.2__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.
Files changed (24) hide show
  1. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/PKG-INFO +1 -1
  2. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/pyproject.toml +1 -1
  3. pathlib_next-0.1.3/src/example.py +66 -0
  4. pathlib_next-0.1.3/src/pathlib_next/mempath.py +149 -0
  5. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/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.3}/.gitignore +0 -0
  8. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/LICENSE +0 -0
  9. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/README.md +0 -0
  10. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/__init__.py +0 -0
  11. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/fspath.py +0 -0
  12. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/path.py +0 -0
  13. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/uri/query.py +0 -0
  14. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/uri/schemes/__init__.py +0 -0
  15. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/uri/schemes/file.py +0 -0
  16. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/uri/schemes/http.py +0 -0
  17. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/uri/schemes/sftp.py +0 -0
  18. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/uri/source.py +0 -0
  19. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/utils/__init__.py +0 -0
  20. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/utils/glob.py +0 -0
  21. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/utils/stat.py +0 -0
  22. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/src/pathlib_next/utils/sync.py +0 -0
  23. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/tests/test_local.py +0 -0
  24. {pathlib_next-0.1.2 → pathlib_next-0.1.3}/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.3
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.3"
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")
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)
@@ -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