iokit 0.0.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.
iokit-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Vladislav A. Proskurov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
iokit-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.1
2
+ Name: iokit
3
+ Version: 0.0.1
4
+ Summary: Input Output Kit
5
+ Author-email: "Vladislav A. Proskurov" <rilshok@pm.me>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/rilshok/iokit
8
+ Project-URL: Repository, https://github.com/rilshok/iokit
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: humanize>=4.9.0
13
+ Requires-Dist: typing-extensions>=4.8.0
14
+ Requires-Dist: pytz>=2024.1
15
+
16
+ # iok
17
+ input / output kit
iokit-0.0.1/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # iok
2
+ input / output kit
@@ -0,0 +1,38 @@
1
+ [project]
2
+ name = "iokit"
3
+ description = "Input Output Kit"
4
+ readme = "README.md"
5
+ requires-python = ">=3.10"
6
+ license = {text = "MIT"}
7
+ dynamic = ["version"]
8
+ authors = [
9
+ {name = "Vladislav A. Proskurov", email = "rilshok@pm.me"},
10
+ ]
11
+ dependencies = [
12
+ "humanize>=4.9.0",
13
+ "typing-extensions>=4.8.0",
14
+ "pytz>=2024.1",
15
+ ]
16
+
17
+ [tool.setuptools.dynamic]
18
+ version = {attr = "iokit.__version__"}
19
+
20
+ [project.urls]
21
+ Homepage = "https://github.com/rilshok/iokit"
22
+ Repository = "https://github.com/rilshok/iokit"
23
+
24
+ [tool.mypy]
25
+ strict = true
26
+
27
+ [tool.ruff]
28
+ line-length = 100
29
+
30
+ [tool.ruff.format]
31
+ docstring-code-format = true
32
+
33
+ [tool.vulture]
34
+ make_whitelist = true
35
+ sort_by_size = true
36
+ verbose = true
37
+ min_confidence = 100
38
+ paths = ["src/iokit"]
iokit-0.0.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,9 @@
1
+ __all__ = [
2
+ "State",
3
+ "Txt",
4
+ "Gzip",
5
+ ]
6
+ __version__ = "0.0.1"
7
+
8
+ from .extensions import Gzip, Txt
9
+ from .state import State
@@ -0,0 +1,7 @@
1
+ __all__ = [
2
+ "Txt",
3
+ "Gzip",
4
+ ]
5
+
6
+ from .gz import Gzip
7
+ from .txt import Txt
@@ -0,0 +1,20 @@
1
+ import gzip
2
+ from io import BytesIO
3
+ from typing import Any
4
+
5
+ from iokit.state import State
6
+
7
+
8
+ class Gzip(State, suffix="gz"):
9
+ def __init__(self, state: State, compression: int = 1, **kwargs: Any):
10
+ data = BytesIO()
11
+ gzip_file = gzip.GzipFile(fileobj=data, mode="wb", compresslevel=compression, mtime=0)
12
+ with gzip_file as gzip_buffer:
13
+ gzip_buffer.write(state.data.getvalue())
14
+ super().__init__(data=data, name=state.name, **kwargs)
15
+
16
+ def load(self) -> State:
17
+ gzip_file = gzip.GzipFile(fileobj=self.data, mode="rb")
18
+ with gzip_file as file:
19
+ data = file.read()
20
+ return State(data=data, name=str(self.name).removesuffix(".gz")).cast()
@@ -0,0 +1,13 @@
1
+ from typing import Any
2
+
3
+ from iokit.state import State
4
+
5
+
6
+ class Txt(State, suffix="txt"):
7
+ def __init__(self, data: str, **kwargs: Any):
8
+ if not isinstance(data, str): # type: ignore
9
+ raise TypeError(f"Expected str, got {type(data).__name__}")
10
+ super().__init__(data=data.encode("utf-8"), **kwargs)
11
+
12
+ def load(self) -> str:
13
+ return self.data.getvalue().decode("utf-8")
@@ -0,0 +1,133 @@
1
+ from datetime import datetime
2
+ from io import BytesIO
3
+ from typing import Any
4
+
5
+ import pytz
6
+ from humanize import naturalsize
7
+ from typing_extensions import Self
8
+
9
+ Payload = BytesIO | bytes
10
+
11
+
12
+ def now() -> datetime:
13
+ return datetime.now(pytz.utc)
14
+
15
+
16
+ class StateName:
17
+ def __init__(self, name: str):
18
+ self._name = name
19
+
20
+ @property
21
+ def stem(self) -> str:
22
+ split = self._name.split(sep=".", maxsplit=1)
23
+ return split[0]
24
+
25
+ @stem.setter
26
+ def stem(self, new: str) -> None:
27
+ suffix = ".".join(self.suffixes)
28
+ self._name = f"{new}.{suffix}"
29
+
30
+ @property
31
+ def suffix(self) -> str:
32
+ split = self._name.rsplit(sep=".", maxsplit=1)
33
+ if len(split) == 2:
34
+ return f"{split[-1]}"
35
+ raise ValueError(f"State name '{self._name}' does not have a suffix")
36
+
37
+ @property
38
+ def suffixes(self) -> tuple[str, ...]:
39
+ split = self._name.split(sep=".")[1:]
40
+ return tuple(f"{s}" for s in split)
41
+
42
+ def __str__(self) -> str:
43
+ return self._name
44
+
45
+ def __repr__(self) -> str:
46
+ return self._name
47
+
48
+ @classmethod
49
+ def make(cls, stem: "str | StateName", suffix: str) -> Self:
50
+ if suffix:
51
+ return cls(f"{stem}.{suffix}")
52
+ return cls(str(stem))
53
+
54
+
55
+ class State:
56
+ _suffix: str = ""
57
+ _suffixes: tuple[str, ...] = ("",)
58
+
59
+ def __init__(self, data: Payload, name: str | StateName = "", time: datetime | None = None):
60
+ self._data = BytesIO(data) if isinstance(data, bytes) else data
61
+ self._name = StateName.make(name, self._suffix)
62
+ self._time = time or now()
63
+
64
+ def __init_subclass__(
65
+ cls,
66
+ suffix: str | None = None,
67
+ suffixes: tuple[str, ...] | None = None,
68
+ ) -> None:
69
+ if suffix is None and suffixes is not None:
70
+ if len(suffixes) == 0:
71
+ raise ValueError("State subclasses must define at least one suffix")
72
+ suffix = suffixes[0]
73
+ if suffix is not None and suffixes is None:
74
+ suffixes = (suffix,)
75
+
76
+ if suffix is not None and suffixes is not None:
77
+ if suffix not in suffixes:
78
+ suffixes = (suffix, *suffixes)
79
+
80
+ if suffix is None or suffixes is None:
81
+ raise ValueError("State subclasses must define a suffix or suffixes")
82
+
83
+ cls._suffix = suffix
84
+ cls._suffixes = suffixes
85
+
86
+ @property
87
+ def name(self) -> StateName:
88
+ return self._name
89
+
90
+ @name.setter
91
+ def name(self, value: str | StateName) -> None:
92
+ if isinstance(value, str):
93
+ value = StateName(value)
94
+ self._name = value
95
+
96
+ @property
97
+ def time(self) -> datetime:
98
+ return self._time
99
+
100
+ @time.setter
101
+ def time(self, value: datetime) -> None:
102
+ self._time = value
103
+
104
+ @property
105
+ def data(self) -> BytesIO:
106
+ self._data.seek(0)
107
+ return BytesIO(self._data.getvalue())
108
+
109
+ @property
110
+ def size(self) -> int:
111
+ return self._data.getbuffer().nbytes
112
+
113
+ def __repr__(self) -> str:
114
+ size = naturalsize(self.size, gnu=True)
115
+ return f"{self.name} ({size})"
116
+
117
+ def cast(self) -> "State":
118
+ suffix = self.name.suffix
119
+ for klass in State.__subclasses__():
120
+ if suffix in getattr(klass, "_suffixes"):
121
+ break
122
+ else:
123
+ raise ValueError(f"Unknown state suffix {suffix}")
124
+ state = klass.__new__(klass)
125
+ setattr(state, "_data", self.data)
126
+ setattr(state, "_name", self.name)
127
+ setattr(state, "_time", self.time)
128
+ return state
129
+
130
+ def load(self) -> Any:
131
+ if not self.name.suffix:
132
+ return self.data.getvalue()
133
+ return self.cast().load()
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.1
2
+ Name: iokit
3
+ Version: 0.0.1
4
+ Summary: Input Output Kit
5
+ Author-email: "Vladislav A. Proskurov" <rilshok@pm.me>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/rilshok/iokit
8
+ Project-URL: Repository, https://github.com/rilshok/iokit
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: humanize>=4.9.0
13
+ Requires-Dist: typing-extensions>=4.8.0
14
+ Requires-Dist: pytz>=2024.1
15
+
16
+ # iok
17
+ input / output kit
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/iokit/__init__.py
5
+ src/iokit/state.py
6
+ src/iokit.egg-info/PKG-INFO
7
+ src/iokit.egg-info/SOURCES.txt
8
+ src/iokit.egg-info/dependency_links.txt
9
+ src/iokit.egg-info/requires.txt
10
+ src/iokit.egg-info/top_level.txt
11
+ src/iokit/extensions/__init__.py
12
+ src/iokit/extensions/gz.py
13
+ src/iokit/extensions/txt.py
@@ -0,0 +1,3 @@
1
+ humanize>=4.9.0
2
+ typing-extensions>=4.8.0
3
+ pytz>=2024.1
@@ -0,0 +1 @@
1
+ iokit