httk-core 2.0.0__py3-none-any.whl
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.
- httk/core/__init__.py +112 -0
- httk/core/_discover.py +35 -0
- httk/core/_plugins.py +95 -0
- httk/core/dataloader.py +263 -0
- httk/core/datastream/__init__.py +80 -0
- httk/core/datastream/bytestream_api.py +33 -0
- httk/core/datastream/bytestream_backend.py +12 -0
- httk/core/datastream/bytestream_bytes.py +52 -0
- httk/core/datastream/bytestream_bytes_view.py +31 -0
- httk/core/datastream/bytestream_common.py +38 -0
- httk/core/datastream/bytestream_file.py +53 -0
- httk/core/datastream/bytestream_file_view.py +189 -0
- httk/core/datastream/bytestream_filename.py +53 -0
- httk/core/datastream/bytestream_filename_view.py +34 -0
- httk/core/datastream/bytestream_like.py +17 -0
- httk/core/datastream/bytestream_request.py +69 -0
- httk/core/datastream/bytestream_request_view.py +44 -0
- httk/core/datastream/bytestream_url.py +74 -0
- httk/core/datastream/bytestream_url_view.py +35 -0
- httk/core/datastream/bytestream_view.py +16 -0
- httk/core/datastream/compression.py +183 -0
- httk/core/datastream/textstream_api.py +33 -0
- httk/core/datastream/textstream_backend.py +12 -0
- httk/core/datastream/textstream_common.py +37 -0
- httk/core/datastream/textstream_file.py +45 -0
- httk/core/datastream/textstream_file_view.py +201 -0
- httk/core/datastream/textstream_filename.py +55 -0
- httk/core/datastream/textstream_filename_view.py +35 -0
- httk/core/datastream/textstream_like.py +15 -0
- httk/core/datastream/textstream_request.py +72 -0
- httk/core/datastream/textstream_request_view.py +44 -0
- httk/core/datastream/textstream_string.py +47 -0
- httk/core/datastream/textstream_string_view.py +31 -0
- httk/core/datastream/textstream_url.py +77 -0
- httk/core/datastream/textstream_url_view.py +35 -0
- httk/core/datastream/textstream_view.py +16 -0
- httk/core/loading.py +29 -0
- httk/core/py.typed +0 -0
- httk/core/register.py +30 -0
- httk/core/views/__init__.py +5 -0
- httk/core/views/backend.py +49 -0
- httk/core/views/unwrapping.py +12 -0
- httk/core/views/view.py +56 -0
- httk/handlers/core/__init__.py +0 -0
- httk_core-2.0.0.dist-info/METADATA +76 -0
- httk_core-2.0.0.dist-info/RECORD +49 -0
- httk_core-2.0.0.dist-info/WHEEL +5 -0
- httk_core-2.0.0.dist-info/licenses/LICENSE +661 -0
- httk_core-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import urllib.request
|
|
2
|
+
from typing import Any, Self
|
|
3
|
+
|
|
4
|
+
from ..views import unwrap
|
|
5
|
+
from .textstream_backend import TextstreamBackend
|
|
6
|
+
from .textstream_like import TextstreamLike
|
|
7
|
+
from .textstream_view import TextstreamView
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TextstreamRequestView(TextstreamView, urllib.request.Request):
|
|
11
|
+
"""
|
|
12
|
+
A view presenting an underlying data streaming backend via a urllib.request.Request.
|
|
13
|
+
This view is mostly useful for providing a Request to functions that will open it.
|
|
14
|
+
Note: this view is not lazy (it does not fetch); it only mirrors the underlying request/URL.
|
|
15
|
+
|
|
16
|
+
Raises TypeError if created with a streaming data source that does not come with a URL.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
_backend: TextstreamBackend
|
|
20
|
+
|
|
21
|
+
def __new__(cls, obj: TextstreamLike, **hints: Any) -> Self:
|
|
22
|
+
if isinstance(obj, cls):
|
|
23
|
+
return obj
|
|
24
|
+
backend = cls._prepare_backend(obj, hints)
|
|
25
|
+
request = getattr(backend, "request", None)
|
|
26
|
+
if request is not None:
|
|
27
|
+
full_url, data, headers = request.full_url, request.data, request.headers
|
|
28
|
+
else:
|
|
29
|
+
url = getattr(backend, "url", None)
|
|
30
|
+
if url is None:
|
|
31
|
+
raise TypeError("This backend cannot be represented as a Request (no underlying URL)")
|
|
32
|
+
full_url, data, headers = url, None, {}
|
|
33
|
+
instance = super().__new__(cls)
|
|
34
|
+
# Request is mutable, so its state is initialized here in __new__ (keeping __init__ a no-op),
|
|
35
|
+
# so that rewrapping an existing view via cls(view) does not re-initialize it.
|
|
36
|
+
urllib.request.Request.__init__(instance, full_url, data=data, headers=headers)
|
|
37
|
+
instance._backend = backend
|
|
38
|
+
return instance
|
|
39
|
+
|
|
40
|
+
def __init__(self, obj: TextstreamLike, **hints: Any) -> None:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
def unwrap(self) -> Any:
|
|
44
|
+
return unwrap(self._backend)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import io
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from .compression import reject_text_native_compression
|
|
5
|
+
from .textstream_backend import TextstreamBackend
|
|
6
|
+
from .textstream_common import TextstreamCommon
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TextstreamString(TextstreamCommon, TextstreamBackend):
|
|
10
|
+
"""
|
|
11
|
+
Backend for streaming text backed by an actual string
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
s: str
|
|
15
|
+
_f: io.TextIOBase | None
|
|
16
|
+
_underlying: io.IOBase | None
|
|
17
|
+
_closed: bool
|
|
18
|
+
|
|
19
|
+
# Cannot type annotate __new__ as `Self | None` for some reason
|
|
20
|
+
def __new__(cls, content: str, **hints: Any) -> Any:
|
|
21
|
+
if not isinstance(content, str):
|
|
22
|
+
return None
|
|
23
|
+
if hints and hints.get("kind", "content") != "content":
|
|
24
|
+
return None
|
|
25
|
+
return super().__new__(cls)
|
|
26
|
+
|
|
27
|
+
def __init__(self, content: str, **hints: Any) -> None:
|
|
28
|
+
reject_text_native_compression(hints.get("compression"))
|
|
29
|
+
self.s = content
|
|
30
|
+
self._f = None
|
|
31
|
+
self._underlying = None
|
|
32
|
+
self._closed = False
|
|
33
|
+
|
|
34
|
+
def _ensure_f(self) -> io.TextIOBase:
|
|
35
|
+
if self._closed:
|
|
36
|
+
raise ValueError("I/O operation on closed stream")
|
|
37
|
+
if self._f is None:
|
|
38
|
+
self._f = io.StringIO(self.s)
|
|
39
|
+
return self._f
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def name(self) -> str | None:
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def closed(self) -> bool:
|
|
47
|
+
return self._closed
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from typing import Any, Self
|
|
2
|
+
|
|
3
|
+
from ..views import unwrap
|
|
4
|
+
from .textstream_backend import TextstreamBackend
|
|
5
|
+
from .textstream_like import TextstreamLike
|
|
6
|
+
from .textstream_view import TextstreamView
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TextstreamStringView(TextstreamView, str):
|
|
10
|
+
"""
|
|
11
|
+
A view presenting an underlying data streaming as a string.
|
|
12
|
+
This view can be used both to pass a string in place of streaming data, and for reading streaming data into a string.
|
|
13
|
+
Note: this view is not lazy (this is impossible for views inherting str, since str is immutable), hence all the streaming data
|
|
14
|
+
is read immedately upon creating this view.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
_backend: TextstreamBackend
|
|
18
|
+
|
|
19
|
+
def __new__(cls, obj: TextstreamLike, **hints: Any) -> Self:
|
|
20
|
+
if isinstance(obj, cls):
|
|
21
|
+
return obj
|
|
22
|
+
backend = cls._prepare_backend(obj, hints)
|
|
23
|
+
instance = super().__new__(cls, backend.read())
|
|
24
|
+
instance._backend = backend
|
|
25
|
+
return instance
|
|
26
|
+
|
|
27
|
+
def __init__(self, obj: TextstreamLike, **hints: Any) -> None:
|
|
28
|
+
super().__init__()
|
|
29
|
+
|
|
30
|
+
def unwrap(self) -> Any:
|
|
31
|
+
return unwrap(self._backend)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import urllib.parse
|
|
3
|
+
import urllib.request
|
|
4
|
+
from typing import Any, cast
|
|
5
|
+
|
|
6
|
+
from .compression import open_compressed, validate_compression
|
|
7
|
+
from .textstream_backend import TextstreamBackend
|
|
8
|
+
from .textstream_common import TextstreamCommon
|
|
9
|
+
|
|
10
|
+
_URL_SCHEMES = ("http", "https", "ftp", "file")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TextstreamURL(TextstreamCommon, TextstreamBackend):
|
|
14
|
+
"""
|
|
15
|
+
Backend for streaming text fetched from a URL string.
|
|
16
|
+
A bare string is interpreted as a URL when its scheme is one of http, https, ftp, or file,
|
|
17
|
+
or when an explicit kind="url" hint is given.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
_url: str
|
|
21
|
+
_timeout: float | None
|
|
22
|
+
_encoding: str | None
|
|
23
|
+
_compression: str
|
|
24
|
+
_f: io.TextIOBase | None
|
|
25
|
+
_underlying: io.IOBase | None
|
|
26
|
+
_closed: bool
|
|
27
|
+
|
|
28
|
+
# mypy does not allow to type annotate __new__ as `Self | None` for some reason
|
|
29
|
+
def __new__(cls, url: str, **hints: Any) -> Any:
|
|
30
|
+
if not isinstance(url, str):
|
|
31
|
+
return None
|
|
32
|
+
kind = hints.get("kind")
|
|
33
|
+
if kind == "url":
|
|
34
|
+
if not urllib.parse.urlsplit(url).scheme:
|
|
35
|
+
return None
|
|
36
|
+
return super().__new__(cls)
|
|
37
|
+
if kind is None and urllib.parse.urlsplit(url).scheme in _URL_SCHEMES:
|
|
38
|
+
return super().__new__(cls)
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
def __init__(self, url: str, **hints: Any) -> None:
|
|
42
|
+
self._url = url
|
|
43
|
+
self._timeout = hints.get("timeout")
|
|
44
|
+
self._encoding = hints.get("encoding")
|
|
45
|
+
self._compression = hints.get("compression", "auto")
|
|
46
|
+
validate_compression(self._compression)
|
|
47
|
+
self._f = None
|
|
48
|
+
self._underlying = None
|
|
49
|
+
self._closed = False
|
|
50
|
+
|
|
51
|
+
def _ensure_f(self) -> io.TextIOBase:
|
|
52
|
+
if self._closed:
|
|
53
|
+
raise ValueError("I/O operation on closed stream")
|
|
54
|
+
if self._f is None:
|
|
55
|
+
if self._timeout is None:
|
|
56
|
+
resp = urllib.request.urlopen(self._url)
|
|
57
|
+
else:
|
|
58
|
+
resp = urllib.request.urlopen(self._url, timeout=self._timeout)
|
|
59
|
+
encoding = self._encoding or resp.headers.get_content_charset() or "utf-8"
|
|
60
|
+
raw = cast(io.IOBase, resp)
|
|
61
|
+
name = urllib.parse.urlsplit(self._url).path
|
|
62
|
+
decompressed = open_compressed(raw, compression=self._compression, name=name)
|
|
63
|
+
self._underlying = raw if decompressed is not raw else None
|
|
64
|
+
self._f = io.TextIOWrapper(cast(io.BufferedReader, decompressed), encoding=encoding)
|
|
65
|
+
return self._f
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def name(self) -> str | None:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def url(self) -> str:
|
|
73
|
+
return self._url
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def closed(self) -> bool:
|
|
77
|
+
return self._closed
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Any, Self
|
|
2
|
+
|
|
3
|
+
from ..views import unwrap
|
|
4
|
+
from .textstream_backend import TextstreamBackend
|
|
5
|
+
from .textstream_like import TextstreamLike
|
|
6
|
+
from .textstream_view import TextstreamView
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TextstreamURLView(TextstreamView, str):
|
|
10
|
+
"""
|
|
11
|
+
A view presenting an underlying data streaming backend via a URL string.
|
|
12
|
+
This view is mostly useful for providing a URL to functions that will open it.
|
|
13
|
+
Note: this view is not lazy (this is impossible for views inheriting str, since str is immutable).
|
|
14
|
+
|
|
15
|
+
Raises TypeError if created with a streaming data source that does not come with a URL.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
_backend: TextstreamBackend
|
|
19
|
+
|
|
20
|
+
def __new__(cls, obj: TextstreamLike, **hints: Any) -> Self:
|
|
21
|
+
if isinstance(obj, cls):
|
|
22
|
+
return obj
|
|
23
|
+
backend = cls._prepare_backend(obj, hints)
|
|
24
|
+
url = getattr(backend, "url", None)
|
|
25
|
+
if url is None:
|
|
26
|
+
raise TypeError("This backend cannot be represented as a URL (no underlying URL)")
|
|
27
|
+
instance = super().__new__(cls, url)
|
|
28
|
+
instance._backend = backend
|
|
29
|
+
return instance
|
|
30
|
+
|
|
31
|
+
def __init__(self, obj: TextstreamLike, **hints: Any) -> None:
|
|
32
|
+
super().__init__()
|
|
33
|
+
|
|
34
|
+
def unwrap(self) -> Any:
|
|
35
|
+
return unwrap(self._backend)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import ClassVar, Self
|
|
2
|
+
|
|
3
|
+
from ..views import View
|
|
4
|
+
from .textstream_backend import TextstreamBackend
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TextstreamView(View[TextstreamBackend]):
|
|
8
|
+
"""
|
|
9
|
+
Abstract base class for all views of streaming text data.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
_backend_base_cls: ClassVar[type[TextstreamBackend]] = TextstreamBackend # type: ignore[type-abstract]
|
|
13
|
+
_view_base_cls: ClassVar[type[Self]]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
TextstreamView._view_base_cls = TextstreamView
|
httk/core/loading.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#
|
|
2
|
+
# The high-throughput toolkit (httk)
|
|
3
|
+
# Copyright (C) 2012-2024 the httk AUTHORS
|
|
4
|
+
#
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
8
|
+
# License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from .register import loaders
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def load(filename: str, **kwargs: Any) -> Any:
|
|
25
|
+
ext = Path(filename).suffix.lower()
|
|
26
|
+
if ext:
|
|
27
|
+
return loaders.dispatch(ext, filename, **kwargs)
|
|
28
|
+
else:
|
|
29
|
+
raise Exception("Could not determine file type.")
|
httk/core/py.typed
ADDED
|
File without changes
|
httk/core/register.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#
|
|
2
|
+
# The high-throughput toolkit (httk)
|
|
3
|
+
# Copyright (C) 2012-2024 the httk AUTHORS
|
|
4
|
+
#
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
8
|
+
# License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
from ._plugins import PluginRegistry
|
|
20
|
+
|
|
21
|
+
loaders = PluginRegistry()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def register_loader(*, name: str, loader: str, extensions: tuple[str, ...]) -> None:
|
|
25
|
+
for ext in extensions:
|
|
26
|
+
loaders.register(key=ext.lower(), handler=loader, name=name)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def known_extensions() -> list[str]:
|
|
30
|
+
return loaders.keys()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import Any, ClassVar, Self, cast
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Backend[BackendT: Backend](ABC):
|
|
6
|
+
"""
|
|
7
|
+
Abstract base class to be subclassed into classes that keep track of alternative
|
|
8
|
+
representations of certain types of data, all adhering to a common API interface.
|
|
9
|
+
|
|
10
|
+
The class variable backend_classes is a list of all classes that can carry the kind of data the subclass represents.
|
|
11
|
+
|
|
12
|
+
A system of "hints" are used primarily to disambiguate between multiple valid interpretations of the same input object.
|
|
13
|
+
Unless otherwise documented for a specific backend, extra hints that do not affect this interpretation are ignored.
|
|
14
|
+
|
|
15
|
+
A set of backends are meant to be combined with a set of Views.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# Subclasses must implement this class variable, which only appear as a type annotation here
|
|
19
|
+
backend_classes: ClassVar[list[type["Backend[Any]"]]]
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def create(cls: type[Self], obj: Any, **hints: Any) -> Self:
|
|
23
|
+
"""
|
|
24
|
+
Given a source data (obj) and a set of hints, create a backend from one of the alternatives in the class variable `backend_classes`.
|
|
25
|
+
|
|
26
|
+
By design this creation depends heavily on order of the classes in `backend_classes`.
|
|
27
|
+
Each class is tried in the order they appear until one of them is successful, in the sense that their `__new__` does not return None.
|
|
28
|
+
Sometimes multiple backend classes can handle the same input type. In that case, dispatch is guided by keyword arguments `**hints`,
|
|
29
|
+
with the convention that:
|
|
30
|
+
|
|
31
|
+
* if a hint named `kind` is given, a backend class should accept the object only if it matches that `kind`;
|
|
32
|
+
* when `kind` matches, additional unrecognized hints may be ignored.
|
|
33
|
+
"""
|
|
34
|
+
for t in cls.backend_classes:
|
|
35
|
+
instance = t(obj, **hints)
|
|
36
|
+
if instance is not None:
|
|
37
|
+
return cast(Self, instance)
|
|
38
|
+
raise TypeError(f"Cannot represent {type(obj)} as {cls.__name__}")
|
|
39
|
+
|
|
40
|
+
def __init__(self, backend, **hints) -> None:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
def unwrap(self) -> Any:
|
|
44
|
+
"""
|
|
45
|
+
Return the most raw representation possible of this backend, i.e., if it uses a backend with an internal representaion -
|
|
46
|
+
or if it can (possibly lossly) convert itself into a more raw representation that still would be recognized as a <Something>Like type,
|
|
47
|
+
that representation will be returned. If this is not possible, the instance itself is returned.
|
|
48
|
+
"""
|
|
49
|
+
return self
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def unwrap(obj: Any) -> Any:
|
|
5
|
+
"""
|
|
6
|
+
Given a Backend or a View, return the most raw representation possible, i.e., if the backend has an internal representaion -
|
|
7
|
+
or if it can (possibly lossly) convert itself into a more raw representation that still would be recognized as a <Something>Like type,
|
|
8
|
+
that representation will be returned. If this is not possible, the instance itself is returned.
|
|
9
|
+
"""
|
|
10
|
+
if hasattr(obj, "unwrap"):
|
|
11
|
+
return obj.unwrap()
|
|
12
|
+
return obj
|
httk/core/views/view.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from typing import Any, ClassVar
|
|
2
|
+
|
|
3
|
+
from .backend import Backend
|
|
4
|
+
from .unwrapping import unwrap
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class View[BackendT: Backend]:
|
|
8
|
+
"""
|
|
9
|
+
A set of views allow manipulating data and state of a backend through different interfaces.
|
|
10
|
+
Hence, creating a View from a Backend, or from another View, allows to read and operate on the data through the interface of that view,
|
|
11
|
+
even if it is not the natural representation of the underlying data.
|
|
12
|
+
|
|
13
|
+
Important: views are always meant to reference the data and state of *the same* underlying object, hence, e.g.:
|
|
14
|
+
|
|
15
|
+
* If a function is given an X object, and the function applies an Xvariant1View and then calls, e.g., close() via that view,
|
|
16
|
+
the excpectation should be that the original X object is now also closed.
|
|
17
|
+
* When, e.g., a TextstreamStringView is created on an already partially read stream, only the unread data will appear through that string interface.
|
|
18
|
+
|
|
19
|
+
All backends and views of the same kind of data (X) should be combined into a type union XLike that functions use to declare they support this kind of data.
|
|
20
|
+
Such functions should start with creating a View on the passed data, giving them access to the data in a single desired format.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# Python typing, and mypy in particular, have trouble with variables being assigned abstract base classes
|
|
24
|
+
_backend_base_cls: ClassVar[Any] # Subclass of Backend that defines a set of backends for similar data
|
|
25
|
+
_view_base_cls: ClassVar[Any] # Subclass of view that defines a set of views of similar data
|
|
26
|
+
_backend: BackendT
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def _prepare_backend(
|
|
30
|
+
cls,
|
|
31
|
+
obj: Any,
|
|
32
|
+
hints: dict[str, Any],
|
|
33
|
+
) -> BackendT:
|
|
34
|
+
"""
|
|
35
|
+
Normalize an arbitrary backend/view/raw object into a backend suitable for constructing a view.
|
|
36
|
+
|
|
37
|
+
Behavior:
|
|
38
|
+
- if `obj` is already one of the accepted views, unwrap its underlying backend to adopt it;
|
|
39
|
+
- if `obj` is a backend inheriting from the right superclass, return it unchanged.
|
|
40
|
+
- if `obj` otherwise try to create a backend from that superclass via `backend_cls.create(obj, **hints)`;
|
|
41
|
+
|
|
42
|
+
`hints` are forwarded for backend selection/disambiguation.
|
|
43
|
+
"""
|
|
44
|
+
if isinstance(obj, cls._view_base_cls):
|
|
45
|
+
return obj._backend
|
|
46
|
+
if not isinstance(obj, cls._backend_base_cls):
|
|
47
|
+
return cls._backend_base_cls.create(obj, **hints)
|
|
48
|
+
return obj
|
|
49
|
+
|
|
50
|
+
def unwrap(self) -> Any:
|
|
51
|
+
"""
|
|
52
|
+
Return the most raw representation possible of this view, i.e., if it uses a backend with an internal representaion -
|
|
53
|
+
or if it can (possibly lossly) convert itself into a more raw representation that still would be recognized as a <Something>Like type,
|
|
54
|
+
that representation will be returned. If this is not possible, the instance itself is returned.
|
|
55
|
+
"""
|
|
56
|
+
return unwrap(self._backend)
|
|
File without changes
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: httk-core
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: httk₂ core functionality
|
|
5
|
+
Author-email: Rickard Armiento <rickard-gpg@armiento.net>
|
|
6
|
+
License-Expression: AGPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://httk.org
|
|
8
|
+
Project-URL: Documentation, https://docs.httk.org/httk-core/
|
|
9
|
+
Project-URL: Repository, https://github.com/httk/httk-core
|
|
10
|
+
Project-URL: Issues, https://github.com/httk/httk-core/issues
|
|
11
|
+
Keywords: Materials Discovery,Materials Informatics,Materials Science
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
25
|
+
Requires-Dist: black; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff; extra == "dev"
|
|
27
|
+
Requires-Dist: isort; extra == "dev"
|
|
28
|
+
Requires-Dist: pyright; extra == "dev"
|
|
29
|
+
Requires-Dist: mypy; extra == "dev"
|
|
30
|
+
Provides-Extra: docs
|
|
31
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
32
|
+
Requires-Dist: furo; extra == "docs"
|
|
33
|
+
Requires-Dist: myst-parser; extra == "docs"
|
|
34
|
+
Requires-Dist: myst-nb; extra == "docs"
|
|
35
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
36
|
+
Requires-Dist: sphinx-copybutton; extra == "docs"
|
|
37
|
+
Requires-Dist: sphinx-autoapi; extra == "docs"
|
|
38
|
+
Provides-Extra: release
|
|
39
|
+
Requires-Dist: build>=1.2; extra == "release"
|
|
40
|
+
Requires-Dist: twine>=6.0; extra == "release"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
# httk-core
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
> **⚠️ PRE-RELEASE**
|
|
48
|
+
>
|
|
49
|
+
> The version assigned to *httk-core* designates the overall version of *httk₂*,
|
|
50
|
+
> and thus starts at v2.0.0. However, versions v2.0.* are to be considered
|
|
51
|
+
> prereleases, and semantic versioning will not be used until v2.1.0.
|
|
52
|
+
|
|
53
|
+
`httk-core` is the central lightweight dependency shared by httk₂ modules.
|
|
54
|
+
|
|
55
|
+
It provides:
|
|
56
|
+
|
|
57
|
+
- the `httk.core` package within the PEP 420 native `httk` namespace;
|
|
58
|
+
- shared view/backend and data-stream primitives; and
|
|
59
|
+
- plugin discovery and aggregate operations such as `httk.core.load`, to which
|
|
60
|
+
other httk modules can register handlers.
|
|
61
|
+
|
|
62
|
+
Most users should install the [`httk2`](https://github.com/httk/httk2)
|
|
63
|
+
metapackage, which selects a useful set of httk modules:
|
|
64
|
+
|
|
65
|
+
```console
|
|
66
|
+
pip install httk2
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Install only the core package with:
|
|
70
|
+
|
|
71
|
+
```console
|
|
72
|
+
pip install httk-core
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Other distributions, such as `httk-io`, install their own packages under the
|
|
76
|
+
same `httk` namespace and can then be imported as `httk.io`.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
httk/core/__init__.py,sha256=YSARcnjJER8mFkrsQRiCHSOHDE_KATkuvn2E2mvt18I,2895
|
|
2
|
+
httk/core/_discover.py,sha256=pEWZs-Kn2nQe3p5Edhek676iVZ10rGePR80fEc4D_NM,1215
|
|
3
|
+
httk/core/_plugins.py,sha256=9CwgeF6G97tHyMOZkeJQZE_ZCQNZ5AIKUfkDYD9QV_M,3092
|
|
4
|
+
httk/core/dataloader.py,sha256=2lFzg8i5j3ovNg-O-pMH9a41LVynqNoEDIAGYmFfF_Q,10081
|
|
5
|
+
httk/core/loading.py,sha256=VUXGwSWLhtYEyF1b5XX9qgNfutDGkBPueUgm71pkX68,1081
|
|
6
|
+
httk/core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
httk/core/register.py,sha256=c7ZHZ2guB9TmaYPRLr5rRZ3kNCZvbG0RSbTpI85vRak,1090
|
|
8
|
+
httk/core/datastream/__init__.py,sha256=PpDxhJrfeTW6UliPcMTcKutmZKO_3UsWANP5yYjjX84,2738
|
|
9
|
+
httk/core/datastream/bytestream_api.py,sha256=ad53pPAwZC17dfW0ldv9R6ZVl5QdEA_vqckgtr1utyI,871
|
|
10
|
+
httk/core/datastream/bytestream_backend.py,sha256=etGEfI1rMGLcxkgFM92yO9p3gnXd3ZK3L3SBZEMSLKQ,314
|
|
11
|
+
httk/core/datastream/bytestream_bytes.py,sha256=DiKzl0ivt5OOrtpM4q02krVqYgVmbU-74qmrUMgeVok,1646
|
|
12
|
+
httk/core/datastream/bytestream_bytes_view.py,sha256=tWZuThktCHFjq_X5ZDiXUCjEjgthJ0KC9QrHHYbUNVo,1107
|
|
13
|
+
httk/core/datastream/bytestream_common.py,sha256=LDIXkViHlrgzn2xQT2EeRVMhtzG9GCADv9rI7vr8Lb8,1134
|
|
14
|
+
httk/core/datastream/bytestream_file.py,sha256=DKwCs0EjEGP78UVMiTH8w5hL2c0GbUxtonQI4POxWvs,1834
|
|
15
|
+
httk/core/datastream/bytestream_file_view.py,sha256=bLpU_CH8fqlr2SBf-H18q09NXOMb7uIWoyvB7yFPQWA,5604
|
|
16
|
+
httk/core/datastream/bytestream_filename.py,sha256=6S_6fIHWiFiW3y7FERR7qzaXEZWkU7X2iWSokYI052M,1725
|
|
17
|
+
httk/core/datastream/bytestream_filename_view.py,sha256=w3OULUJvLJaHGvOP9l9v3Yen118J0IPNFaKnsYMnlrg,1245
|
|
18
|
+
httk/core/datastream/bytestream_like.py,sha256=U2RFkuVF9IQx7Ax3-bypx7sEhIeqMt5rFa-uUy3gF38,322
|
|
19
|
+
httk/core/datastream/bytestream_request.py,sha256=bW6BBIa3mgd7T8dYTymJ--x0rxvIIzArgrk_ZNTi4yA,2262
|
|
20
|
+
httk/core/datastream/bytestream_request_view.py,sha256=69fPVjRZY1qBqf0aeoCq93OL-obzyeHr0Ll-sPLhhkc,1816
|
|
21
|
+
httk/core/datastream/bytestream_url.py,sha256=ThzfvtvHz_YfL20lo6jlOB2rUGDQY0F-4y9q-CXWFZM,2410
|
|
22
|
+
httk/core/datastream/bytestream_url_view.py,sha256=ZqSVX4vIYLpIjqPdMDfXySqcSGM_kj7MelcU3iMBYwY,1251
|
|
23
|
+
httk/core/datastream/bytestream_view.py,sha256=g87V1HQXFRUZGUBgyk3mWCjim7jVqsfPFcRqq3AgC5k,436
|
|
24
|
+
httk/core/datastream/compression.py,sha256=P6d0lyXjbWn7wYYyxhKs944dTakWzBV6ieVJgUvQeMk,6966
|
|
25
|
+
httk/core/datastream/textstream_api.py,sha256=7ltSE1eiCufUea3dfPlr1FWPyczzbLB2-gWV1Aezboo,868
|
|
26
|
+
httk/core/datastream/textstream_backend.py,sha256=_tfj1KfgXOUhByT4ueW9wAfuqFV4tImDPqAkzp19atY,314
|
|
27
|
+
httk/core/datastream/textstream_common.py,sha256=nYupIVL_g3CdCx_Dw3W2K8NdGLlJb2UcXeaJQtqHBWU,1079
|
|
28
|
+
httk/core/datastream/textstream_file.py,sha256=1ukkIWQF2YIEcgHaR2AFrL6vojQ_Mxqy3_dF5k5JsKM,1462
|
|
29
|
+
httk/core/datastream/textstream_file_view.py,sha256=0qvTXYiXEwJRKIwExK4lY3FPz5AKE-3_31-mX5W5gS8,6420
|
|
30
|
+
httk/core/datastream/textstream_filename.py,sha256=AVuUlmQ8ItsJ78F3msV7uqGmxigerZTx5tq0dHCXns0,1902
|
|
31
|
+
httk/core/datastream/textstream_filename_view.py,sha256=2E_e0DKE_XeitInKOKIJHxLo0qlSm-Y8cvRsDSHeMvs,1332
|
|
32
|
+
httk/core/datastream/textstream_like.py,sha256=R2eGKVWGS12i5thtjA8dqpuvkBlVE0rFqqtPwyLvMDY,299
|
|
33
|
+
httk/core/datastream/textstream_request.py,sha256=DPFDBHUjttFBd3YZYox6KOC74udajOglnIEFVCBP6Pc,2505
|
|
34
|
+
httk/core/datastream/textstream_request_view.py,sha256=EflFJJ3dgUhUmuFblIauwoUY5Rsv088hwIaDf6RxjJk,1816
|
|
35
|
+
httk/core/datastream/textstream_string.py,sha256=VipgoYgLiSEsePzhgs0xbbxwFwIWgQqI6lEwkj2HlzI,1334
|
|
36
|
+
httk/core/datastream/textstream_string_view.py,sha256=z9NxkXjRD62QqJW3-inMPRi7lIBNfr7tjuAugD9nmTE,1111
|
|
37
|
+
httk/core/datastream/textstream_url.py,sha256=j1gjNQKlIUiGDyxVMLRC1mLKZIeTAOWmGZkUWB6R8oc,2653
|
|
38
|
+
httk/core/datastream/textstream_url_view.py,sha256=DOUovDax_JevCB8gkLAYAoLRGpblS1ddO-vLZKGEub8,1251
|
|
39
|
+
httk/core/datastream/textstream_view.py,sha256=S4lgenptFquuO5gqAc7R2GBQkjQgXhCR9IJzHmdhg2E,436
|
|
40
|
+
httk/core/views/__init__.py,sha256=o2794D3HSQPwIqP31ujvgceR_iHqS1-xAMoQTvl0mYs,124
|
|
41
|
+
httk/core/views/backend.py,sha256=m2EMCK9A8a_j216lIN024wv8IIjAkFf-IKLI2Lu6wEg,2485
|
|
42
|
+
httk/core/views/unwrapping.py,sha256=VyFC-QWokBuDHpTCmSBRVjQgQIe9nF-TWm7joo7uZTc,512
|
|
43
|
+
httk/core/views/view.py,sha256=yL3ML_OX26vFodTSDCtqkU5uHZ24c08HwOpxjDNOWs8,2892
|
|
44
|
+
httk/handlers/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
|
+
httk_core-2.0.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
46
|
+
httk_core-2.0.0.dist-info/METADATA,sha256=_6od5xP_hrLJln7gLUYUVRsiA4yguBnDq7radPTr2VI,2756
|
|
47
|
+
httk_core-2.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
48
|
+
httk_core-2.0.0.dist-info/top_level.txt,sha256=UBbnLJzPWLPWOl6JzJzeLuWa3uq7iStjxrP4741hFRg,5
|
|
49
|
+
httk_core-2.0.0.dist-info/RECORD,,
|