ominfra 0.0.0.dev433__py3-none-any.whl → 0.0.0.dev501__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.
Potentially problematic release.
This version of ominfra might be problematic. Click here for more details.
- ominfra/README.md +26 -0
- ominfra/__about__.py +5 -2
- ominfra/clouds/aws/instancetypes/cache.json.gz +0 -0
- ominfra/clouds/aws/journald2aws/main.py +1 -1
- ominfra/clouds/aws/models/{base.py → base/__init__.py} +6 -0
- ominfra/clouds/aws/models/base/_dataclasses.py +721 -0
- ominfra/clouds/aws/models/gen/cli.py +2 -1
- ominfra/clouds/aws/models/gen/gen.py +16 -7
- ominfra/clouds/aws/models/services/{ec2.py → ec2/__init__.py} +123 -1
- ominfra/clouds/aws/models/services/ec2/_dataclasses.py +30654 -0
- ominfra/clouds/aws/models/services/{lambda_.py → lambda_/__init__.py} +139 -1
- ominfra/clouds/aws/models/services/lambda_/_dataclasses.py +4182 -0
- ominfra/clouds/aws/models/services/{rds.py → rds/__init__.py} +244 -78
- ominfra/clouds/aws/models/services/rds/_dataclasses.py +8231 -0
- ominfra/clouds/aws/models/services/{s3.py → s3/__init__.py} +9 -1
- ominfra/clouds/aws/models/services/s3/_dataclasses.py +5014 -0
- ominfra/manage/bootstrap_.py +1 -1
- ominfra/manage/main.py +1 -2
- ominfra/manage/targets/bestpython.sh +1 -1
- ominfra/scripts/journald2aws.py +748 -71
- ominfra/scripts/manage.py +824 -99
- ominfra/scripts/supervisor.py +925 -123
- ominfra/supervisor/main.py +1 -1
- {ominfra-0.0.0.dev433.dist-info → ominfra-0.0.0.dev501.dist-info}/METADATA +7 -5
- {ominfra-0.0.0.dev433.dist-info → ominfra-0.0.0.dev501.dist-info}/RECORD +29 -23
- {ominfra-0.0.0.dev433.dist-info → ominfra-0.0.0.dev501.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev433.dist-info → ominfra-0.0.0.dev501.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev433.dist-info → ominfra-0.0.0.dev501.dist-info}/licenses/LICENSE +0 -0
- {ominfra-0.0.0.dev433.dist-info → ominfra-0.0.0.dev501.dist-info}/top_level.txt +0 -0
ominfra/scripts/supervisor.py
CHANGED
|
@@ -65,6 +65,7 @@ import io
|
|
|
65
65
|
import itertools
|
|
66
66
|
import json
|
|
67
67
|
import logging
|
|
68
|
+
import operator
|
|
68
69
|
import os
|
|
69
70
|
import os.path
|
|
70
71
|
import pwd
|
|
@@ -98,11 +99,98 @@ if sys.version_info < (3, 8):
|
|
|
98
99
|
raise OSError(f'Requires python (3, 8), got {sys.version_info} from {sys.executable}') # noqa
|
|
99
100
|
|
|
100
101
|
|
|
102
|
+
def __omlish_amalg__(): # noqa
|
|
103
|
+
return dict(
|
|
104
|
+
src_files=[
|
|
105
|
+
dict(path='errors.py', sha1='eed49133c64621fb5f081ba7f249e8c4c8745025'),
|
|
106
|
+
dict(path='privileges.py', sha1='80fffb4966565e70b6300381800ff849616a1daa'),
|
|
107
|
+
dict(path='states.py', sha1='7e80da5abde756a47bb01fff1967e35ee9f754e5'),
|
|
108
|
+
dict(path='utils/diag.py', sha1='65f6491a57b3b8ff6dc166c4136c39e49e008c8d'),
|
|
109
|
+
dict(path='utils/fs.py', sha1='f18fd3d60c863e05d91c8e4735b86629334f5181'),
|
|
110
|
+
dict(path='utils/ostypes.py', sha1='81aa9dc830189ae7095c2b8c823e28ce4a808e8d'),
|
|
111
|
+
dict(path='utils/signals.py', sha1='445bab01dcd0144194f330e55accee1277992626'),
|
|
112
|
+
dict(path='utils/strings.py', sha1='c4ced4877e366a64b7d366353ab9e5691c587f38'),
|
|
113
|
+
dict(path='../../omlish/configs/types.py', sha1='f7a5584cd6eccb77d18d729796072a162e9a8790'),
|
|
114
|
+
dict(path='../../omlish/formats/ini/sections.py', sha1='731c92cce82e183d1d4bdc23fc781fad62187394'),
|
|
115
|
+
dict(path='../../omlish/formats/toml/parser.py', sha1='73dac82289350ab951c4bcdbfe61167fa221f26f'),
|
|
116
|
+
dict(path='../../omlish/formats/toml/writer.py', sha1='6ea41d7e724bb1dcf6bd84b88993ff4e8798e021'),
|
|
117
|
+
dict(path='../../omlish/http/versions.py', sha1='197685ffbb62a457a0e8d4047a9df26aebd7dae4'),
|
|
118
|
+
dict(path='../../omlish/io/readers.py', sha1='4b19ab4a87f2fa2a6f6c3cad7e1f3892b7cbd3a4'),
|
|
119
|
+
dict(path='../../omlish/lite/abstract.py', sha1='a2fc3f3697fa8de5247761e9d554e70176f37aac'),
|
|
120
|
+
dict(path='../../omlish/lite/asyncs.py', sha1='b3f2251c56617ce548abf9c333ac996b63edb23e'),
|
|
121
|
+
dict(path='../../omlish/lite/attrops.py', sha1='c1ebfb8573d766d34593c452a2377208d02726dc'),
|
|
122
|
+
dict(path='../../omlish/lite/cached.py', sha1='0c33cf961ac8f0727284303c7a30c5ea98f714f2'),
|
|
123
|
+
dict(path='../../omlish/lite/check.py', sha1='bb6b6b63333699b84462951a854d99ae83195b94'),
|
|
124
|
+
dict(path='../../omlish/lite/json.py', sha1='57eeddc4d23a17931e00284ffa5cb6e3ce089486'),
|
|
125
|
+
dict(path='../../omlish/lite/objects.py', sha1='9566bbf3530fd71fcc56321485216b592fae21e9'),
|
|
126
|
+
dict(path='../../omlish/lite/reflect.py', sha1='c4fec44bf144e9d93293c996af06f6c65fc5e63d'),
|
|
127
|
+
dict(path='../../omlish/lite/strings.py', sha1='89831ecbc34ad80e118a865eceb390ed399dc4d6'),
|
|
128
|
+
dict(path='../../omlish/lite/typing.py', sha1='048bb5fb8ecad5be101516f8f3b7996707f5bc42'),
|
|
129
|
+
dict(path='../../omlish/logs/levels.py', sha1='91405563d082a5eba874da82aac89d83ce7b6152'),
|
|
130
|
+
dict(path='../../omlish/logs/std/filters.py', sha1='f36aab646d84d31e295b33aaaaa6f8b67ff38b3d'),
|
|
131
|
+
dict(path='../../omlish/logs/std/proxy.py', sha1='3e7301a2aa351127f9c85f61b2f85dcc3f15aafb'),
|
|
132
|
+
dict(path='../../omlish/logs/warnings.py', sha1='c4eb694b24773351107fcc058f3620f1dbfb6799'),
|
|
133
|
+
dict(path='../../omlish/sockets/addresses.py', sha1='26533e88a8073f89646c0f77f1fbe0869282ab0e'),
|
|
134
|
+
dict(path='events.py', sha1='d30d903b7d664f76e738ed939b7ec0e6e6861a0a'),
|
|
135
|
+
dict(path='utils/collections.py', sha1='f9c3c8a52e6057e938730746eaa28e48a5b757c6'),
|
|
136
|
+
dict(path='utils/fds.py', sha1='cf9b2a52cc74b2aaebed656ba16888e4322746ec'),
|
|
137
|
+
dict(path='utils/users.py', sha1='d440d9deb2f03b4611bc0eb0ad186f9a994d84f7'),
|
|
138
|
+
dict(path='../../omlish/configs/formats.py', sha1='9bc4f953b4b8700f6f109e6f49e2d70f8e48ce7c'),
|
|
139
|
+
dict(path='../../omlish/configs/processing/names.py', sha1='3ae4c9e921929eb64cee6150cc86f35fee0f2070'),
|
|
140
|
+
dict(path='../../omlish/http/coro/io.py', sha1='2cdf6529c37a37cc0c1db2e02032157cf906d5d6'),
|
|
141
|
+
dict(path='../../omlish/http/parsing.py', sha1='3fea28dc6341908ba7c8fad42bf7bbe711f21b82'),
|
|
142
|
+
dict(path='../../omlish/io/buffers.py', sha1='45a5f79c6d71f02ab82082a48d63ebbd10959031'),
|
|
143
|
+
dict(path='../../omlish/io/fdio/handlers.py', sha1='e81356d4d73a670c35a972476a6338d0b737662b'),
|
|
144
|
+
dict(path='../../omlish/io/fdio/pollers.py', sha1='022d5a8a24412764864ca95186a167698b739baf'),
|
|
145
|
+
dict(path='../../omlish/lite/marshal.py', sha1='96348f5f2a26dc27d842d33cc3927e9da163436b'),
|
|
146
|
+
dict(path='../../omlish/lite/maybes.py', sha1='04d2fcbea17028a5e6b8e7a7fb742375495ed233'),
|
|
147
|
+
dict(path='../../omlish/lite/runtime.py', sha1='2e752a27ae2bf89b1bb79b4a2da522a3ec360c70'),
|
|
148
|
+
dict(path='../../omlish/logs/infos.py', sha1='4dd104bd468a8c438601dd0bbda619b47d2f1620'),
|
|
149
|
+
dict(path='../../omlish/logs/protocols.py', sha1='05ca4d1d7feb50c4e3b9f22ee371aa7bf4b3dbd1'),
|
|
150
|
+
dict(path='../../omlish/logs/std/json.py', sha1='2a75553131e4d5331bb0cedde42aa183f403fc3b'),
|
|
151
|
+
dict(path='../../omlish/os/journald.py', sha1='7485cad562f8b9b4f71efd41a6177660f7d62e55'),
|
|
152
|
+
dict(path='configs.py', sha1='61f986fc5c9591194f72c3b4ffa4b018770710ed'),
|
|
153
|
+
dict(path='pipes.py', sha1='ad9315c50bffe81ee204227163d85ab366ce5320'),
|
|
154
|
+
dict(path='setup.py', sha1='4be12354bb45cf7773fd98ad9695aa330ae07fe6'),
|
|
155
|
+
dict(path='utils/os.py', sha1='9f7314f1c0c34a8154e9acf38a5b916b2e310b4d'),
|
|
156
|
+
dict(path='../../omlish/http/handlers.py', sha1='40629060bac22ea5e94b720b57001861a4ec9031'),
|
|
157
|
+
dict(path='../../omlish/io/fdio/kqueue.py', sha1='c90ba13e9e5ee795b6af752a6f25f8bcfd7f88a0'),
|
|
158
|
+
dict(path='../../omlish/lite/configs.py', sha1='c8602e0e197ef1133e7e8e248935ac745bfd46cb'),
|
|
159
|
+
dict(path='../../omlish/lite/inject.py', sha1='6f097e3170019a34ff6834d36fcc9cbeed3a7ab4'),
|
|
160
|
+
dict(path='../../omlish/logs/contexts.py', sha1='1000a6d5ddfb642865ca532e34b1d50759781cf0'),
|
|
161
|
+
dict(path='../../omlish/logs/std/standard.py', sha1='5c97c1b9f7ead58d6127d047b873398f708f288d'),
|
|
162
|
+
dict(path='types.py', sha1='7ef67f710fb54c3af067aa596cb593f33eafe380'),
|
|
163
|
+
dict(path='../../omlish/http/coro/server/server.py', sha1='c0a980afa8346dbc20570acddb2b3b579bfc1ce0'),
|
|
164
|
+
dict(path='../../omlish/logs/base.py', sha1='8d06faee05fead6b1dd98c9035a5b042af4aebb1'),
|
|
165
|
+
dict(path='../../omlish/logs/std/records.py', sha1='8bbf6ef9eccb3a012c6ca416ddf3969450fd8fc9'),
|
|
166
|
+
dict(path='dispatchers.py', sha1='33fe5ae77e33b3cfabb97b1a1c0f06dd0cc54703'),
|
|
167
|
+
dict(path='groupsimpl.py', sha1='4fe587a6eaff7dd874b54450be62f9689283d230'),
|
|
168
|
+
dict(path='process.py', sha1='ec0903adbde7552ba8a6aad9030716ef57fc4a6c'),
|
|
169
|
+
dict(path='../../omlish/http/coro/server/fdio.py', sha1='3f1b4865e589a336f942a763dc11ce42fa5c8857'),
|
|
170
|
+
dict(path='../../omlish/logs/asyncs.py', sha1='ab11b70033d9f2e9a4e70254185aa1c6130c6077'),
|
|
171
|
+
dict(path='../../omlish/logs/std/loggers.py', sha1='a569179445d6a8a942b5dcfad1d1f77702868803'),
|
|
172
|
+
dict(path='groups.py', sha1='a02a602d28793e5c84fbe7bfbcfa6ccce2ee0788'),
|
|
173
|
+
dict(path='spawning.py', sha1='9e65e562395ad04e3f3a314f946b7a4e58a601da'),
|
|
174
|
+
dict(path='../../omlish/logs/modules.py', sha1='dd7d5f8e63fe8829dfb49460f3929ab64b68ee14'),
|
|
175
|
+
dict(path='dispatchersimpl.py', sha1='701947899daef9f68c4277495594031cf73d9a62'),
|
|
176
|
+
dict(path='http.py', sha1='6a144e4c93abefc5f9cdba207e807ea75f8f2d5d'),
|
|
177
|
+
dict(path='io.py', sha1='6ba708a8396c212afdd1d314c9b5804c2d66646e'),
|
|
178
|
+
dict(path='processimpl.py', sha1='7edbbcd39a8ed1fd195c760da894620617a9d969'),
|
|
179
|
+
dict(path='setupimpl.py', sha1='b4b8b8c3e1d71a0e6794fb0a845181f3662a6bfd'),
|
|
180
|
+
dict(path='signals.py', sha1='645361d922557b5cedddbd261b3f1485b96555dd'),
|
|
181
|
+
dict(path='spawningimpl.py', sha1='c770e0017c2388fe59897d12fe67c3b6b7b2ca5a'),
|
|
182
|
+
dict(path='supervisor.py', sha1='a97a13ec71deaf6eacabb1527f373b21b89209af'),
|
|
183
|
+
dict(path='inject.py', sha1='6ad254bcf1c78e0b8a1d7bb3940628857e3bb60c'),
|
|
184
|
+
dict(path='main.py', sha1='8bd55a46b4a4fc4ad0034205384b0b49b8374c7a'),
|
|
185
|
+
],
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
101
189
|
########################################
|
|
102
190
|
|
|
103
191
|
|
|
104
192
|
# ../../omlish/configs/types.py
|
|
105
|
-
ConfigMap = ta.Mapping[str, ta.Any]
|
|
193
|
+
ConfigMap = ta.Mapping[str, ta.Any] # ta.TypeAlias
|
|
106
194
|
|
|
107
195
|
# ../../omlish/formats/ini/sections.py
|
|
108
196
|
IniSectionSettingsMap = ta.Mapping[str, ta.Mapping[str, ta.Union[str, ta.Sequence[str]]]] # ta.TypeAlias
|
|
@@ -112,7 +200,7 @@ TomlParseFloat = ta.Callable[[str], ta.Any] # ta.TypeAlias
|
|
|
112
200
|
TomlKey = ta.Tuple[str, ...] # ta.TypeAlias
|
|
113
201
|
TomlPos = int # ta.TypeAlias
|
|
114
202
|
|
|
115
|
-
# ../../omlish/lite/
|
|
203
|
+
# ../../omlish/lite/abstract.py
|
|
116
204
|
T = ta.TypeVar('T')
|
|
117
205
|
|
|
118
206
|
# ../../omlish/lite/cached.py
|
|
@@ -135,7 +223,7 @@ A2 = ta.TypeVar('A2')
|
|
|
135
223
|
LogLevel = int # ta.TypeAlias
|
|
136
224
|
|
|
137
225
|
# ../../omlish/sockets/addresses.py
|
|
138
|
-
SocketAddress = ta.Any
|
|
226
|
+
SocketAddress = ta.Any # ta.TypeAlias
|
|
139
227
|
|
|
140
228
|
# events.py
|
|
141
229
|
EventCallback = ta.Callable[['Event'], None] # ta.TypeAlias
|
|
@@ -166,16 +254,16 @@ HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse'] # ta.T
|
|
|
166
254
|
HttpHandlerResponseData = ta.Union[bytes, 'HttpHandlerResponseStreamedData'] # ta.TypeAlias # noqa
|
|
167
255
|
|
|
168
256
|
# ../../omlish/lite/inject.py
|
|
169
|
-
InjectorKeyCls = ta.Union[type, ta.NewType]
|
|
170
|
-
InjectorProviderFn = ta.Callable[['Injector'], ta.Any]
|
|
171
|
-
InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
|
172
|
-
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
|
257
|
+
InjectorKeyCls = ta.Union[type, ta.NewType] # ta.TypeAlias
|
|
258
|
+
InjectorProviderFn = ta.Callable[['Injector'], ta.Any] # ta.TypeAlias
|
|
259
|
+
InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn'] # ta.TypeAlias
|
|
260
|
+
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings'] # ta.TypeAlias
|
|
173
261
|
|
|
174
262
|
# ../../omlish/logs/contexts.py
|
|
175
263
|
LoggingContextInfoT = ta.TypeVar('LoggingContextInfoT', bound=LoggingContextInfo)
|
|
176
264
|
|
|
177
265
|
# ../../omlish/http/coro/server/server.py
|
|
178
|
-
CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer']
|
|
266
|
+
CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer'] # ta.TypeAlias
|
|
179
267
|
|
|
180
268
|
|
|
181
269
|
########################################
|
|
@@ -1725,6 +1813,36 @@ class HttpProtocolVersions:
|
|
|
1725
1813
|
HTTP_2_0 = HttpProtocolVersion(2, 0)
|
|
1726
1814
|
|
|
1727
1815
|
|
|
1816
|
+
########################################
|
|
1817
|
+
# ../../../omlish/io/readers.py
|
|
1818
|
+
|
|
1819
|
+
|
|
1820
|
+
##
|
|
1821
|
+
|
|
1822
|
+
|
|
1823
|
+
class RawBytesReader(ta.Protocol):
|
|
1824
|
+
def read1(self, n: int = -1, /) -> bytes: ...
|
|
1825
|
+
|
|
1826
|
+
|
|
1827
|
+
class BufferedBytesReader(RawBytesReader, ta.Protocol):
|
|
1828
|
+
def read(self, n: int = -1, /) -> bytes: ...
|
|
1829
|
+
|
|
1830
|
+
def readall(self) -> bytes: ...
|
|
1831
|
+
|
|
1832
|
+
|
|
1833
|
+
#
|
|
1834
|
+
|
|
1835
|
+
|
|
1836
|
+
class AsyncRawBytesReader(ta.Protocol):
|
|
1837
|
+
def read1(self, n: int = -1, /) -> ta.Awaitable[bytes]: ...
|
|
1838
|
+
|
|
1839
|
+
|
|
1840
|
+
class AsyncBufferedBytesReader(AsyncRawBytesReader, ta.Protocol):
|
|
1841
|
+
def read(self, n: int = -1, /) -> ta.Awaitable[bytes]: ...
|
|
1842
|
+
|
|
1843
|
+
def readall(self) -> ta.Awaitable[bytes]: ...
|
|
1844
|
+
|
|
1845
|
+
|
|
1728
1846
|
########################################
|
|
1729
1847
|
# ../../../omlish/lite/abstract.py
|
|
1730
1848
|
|
|
@@ -1740,25 +1858,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
1740
1858
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
1741
1859
|
|
|
1742
1860
|
|
|
1743
|
-
def
|
|
1861
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
1862
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
1863
|
+
|
|
1864
|
+
# Stage 1: direct abstract methods
|
|
1865
|
+
|
|
1866
|
+
abstracts = {
|
|
1867
|
+
a
|
|
1868
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
1869
|
+
for a, v in list(cls.__dict__.items())
|
|
1870
|
+
if is_abstract_method(v)
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
# Stage 2: inherited abstract methods
|
|
1874
|
+
|
|
1875
|
+
for base in cls.__bases__:
|
|
1876
|
+
# Get __abstractmethods__ from base if it exists
|
|
1877
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
1878
|
+
continue
|
|
1879
|
+
|
|
1880
|
+
# Iterate over abstract methods in base
|
|
1881
|
+
for key in base_abstracts:
|
|
1882
|
+
# Check if this class has an attribute with this name
|
|
1883
|
+
try:
|
|
1884
|
+
value = getattr(cls, key)
|
|
1885
|
+
except AttributeError:
|
|
1886
|
+
# Attribute not found in this class, skip
|
|
1887
|
+
continue
|
|
1888
|
+
|
|
1889
|
+
# Check if it's still abstract
|
|
1890
|
+
if is_abstract_method(value):
|
|
1891
|
+
abstracts.add(key)
|
|
1892
|
+
|
|
1893
|
+
return frozenset(abstracts)
|
|
1894
|
+
|
|
1895
|
+
|
|
1896
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
1744
1897
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
1745
1898
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
1746
1899
|
# implementation (especially during testing), and we want to handle both cases.
|
|
1747
1900
|
return cls
|
|
1748
1901
|
|
|
1749
|
-
abstracts
|
|
1750
|
-
|
|
1751
|
-
for scls in cls.__bases__:
|
|
1752
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
1753
|
-
value = getattr(cls, name, None)
|
|
1754
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
1755
|
-
abstracts.add(name)
|
|
1756
|
-
|
|
1757
|
-
for name, value in cls.__dict__.items():
|
|
1758
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
1759
|
-
abstracts.add(name)
|
|
1760
|
-
|
|
1761
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
1902
|
+
abstracts = compute_abstract_methods(cls)
|
|
1903
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
1762
1904
|
return cls
|
|
1763
1905
|
|
|
1764
1906
|
|
|
@@ -1812,23 +1954,26 @@ class Abstract:
|
|
|
1812
1954
|
super().__init_subclass__(**kwargs)
|
|
1813
1955
|
|
|
1814
1956
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
1815
|
-
ams
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1957
|
+
if ams := compute_abstract_methods(cls):
|
|
1958
|
+
amd = {
|
|
1959
|
+
a: mcls
|
|
1960
|
+
for mcls in cls.__mro__[::-1]
|
|
1961
|
+
for a in ams
|
|
1962
|
+
if a in mcls.__dict__
|
|
1963
|
+
}
|
|
1821
1964
|
|
|
1822
|
-
if ams:
|
|
1823
1965
|
raise AbstractTypeError(
|
|
1824
1966
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
1825
1967
|
', '.join(sorted([
|
|
1826
1968
|
'.'.join([
|
|
1827
|
-
*([
|
|
1828
|
-
|
|
1969
|
+
*([
|
|
1970
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
1971
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
1972
|
+
] if c is not None else '?'),
|
|
1829
1973
|
a,
|
|
1830
1974
|
])
|
|
1831
|
-
for a
|
|
1975
|
+
for a in ams
|
|
1976
|
+
for c in [amd.get(a)]
|
|
1832
1977
|
])),
|
|
1833
1978
|
)
|
|
1834
1979
|
|
|
@@ -1845,6 +1990,150 @@ class Abstract:
|
|
|
1845
1990
|
update_abstracts(cls, force=True)
|
|
1846
1991
|
|
|
1847
1992
|
|
|
1993
|
+
########################################
|
|
1994
|
+
# ../../../omlish/lite/asyncs.py
|
|
1995
|
+
|
|
1996
|
+
|
|
1997
|
+
##
|
|
1998
|
+
|
|
1999
|
+
|
|
2000
|
+
async def opt_await(aw: ta.Optional[ta.Awaitable[T]]) -> ta.Optional[T]:
|
|
2001
|
+
return (await aw if aw is not None else None)
|
|
2002
|
+
|
|
2003
|
+
|
|
2004
|
+
async def async_list(ai: ta.AsyncIterable[T]) -> ta.List[T]:
|
|
2005
|
+
return [v async for v in ai]
|
|
2006
|
+
|
|
2007
|
+
|
|
2008
|
+
async def async_enumerate(ai: ta.AsyncIterable[T]) -> ta.AsyncIterable[ta.Tuple[int, T]]:
|
|
2009
|
+
i = 0
|
|
2010
|
+
async for e in ai:
|
|
2011
|
+
yield (i, e)
|
|
2012
|
+
i += 1
|
|
2013
|
+
|
|
2014
|
+
|
|
2015
|
+
##
|
|
2016
|
+
|
|
2017
|
+
|
|
2018
|
+
def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[..., ta.Awaitable[T]]:
|
|
2019
|
+
async def inner(*args, **kwargs):
|
|
2020
|
+
return fn(*args, **kwargs)
|
|
2021
|
+
|
|
2022
|
+
return functools.wraps(fn)(inner) if wrap else inner
|
|
2023
|
+
|
|
2024
|
+
|
|
2025
|
+
##
|
|
2026
|
+
|
|
2027
|
+
|
|
2028
|
+
class SyncAwaitCoroutineNotTerminatedError(Exception):
|
|
2029
|
+
pass
|
|
2030
|
+
|
|
2031
|
+
|
|
2032
|
+
def sync_await(aw: ta.Awaitable[T]) -> T:
|
|
2033
|
+
"""
|
|
2034
|
+
Allows for the synchronous execution of async functions which will never actually *externally* await anything. These
|
|
2035
|
+
functions are allowed to await any number of other functions - including contextmanagers and generators - so long as
|
|
2036
|
+
nothing ever actually 'leaks' out of the function, presumably to an event loop.
|
|
2037
|
+
"""
|
|
2038
|
+
|
|
2039
|
+
ret = missing = object()
|
|
2040
|
+
|
|
2041
|
+
async def thunk():
|
|
2042
|
+
nonlocal ret
|
|
2043
|
+
|
|
2044
|
+
ret = await aw
|
|
2045
|
+
|
|
2046
|
+
cr = thunk()
|
|
2047
|
+
try:
|
|
2048
|
+
try:
|
|
2049
|
+
cr.send(None)
|
|
2050
|
+
except StopIteration:
|
|
2051
|
+
pass
|
|
2052
|
+
|
|
2053
|
+
if ret is missing or cr.cr_await is not None or cr.cr_running:
|
|
2054
|
+
raise SyncAwaitCoroutineNotTerminatedError('Not terminated')
|
|
2055
|
+
|
|
2056
|
+
finally:
|
|
2057
|
+
cr.close()
|
|
2058
|
+
|
|
2059
|
+
return ta.cast(T, ret)
|
|
2060
|
+
|
|
2061
|
+
|
|
2062
|
+
#
|
|
2063
|
+
|
|
2064
|
+
|
|
2065
|
+
def sync_aiter(ai: ta.AsyncIterator[T]) -> ta.Iterator[T]:
|
|
2066
|
+
while True:
|
|
2067
|
+
try:
|
|
2068
|
+
o = sync_await(ai.__anext__())
|
|
2069
|
+
except StopAsyncIteration:
|
|
2070
|
+
break
|
|
2071
|
+
yield o
|
|
2072
|
+
|
|
2073
|
+
|
|
2074
|
+
def sync_async_list(ai: ta.AsyncIterable[T]) -> ta.List[T]:
|
|
2075
|
+
"""
|
|
2076
|
+
Uses `sync_await` to synchronously read the full contents of a function call returning an async iterator, given that
|
|
2077
|
+
the function never externally awaits anything.
|
|
2078
|
+
"""
|
|
2079
|
+
|
|
2080
|
+
lst: ta.Optional[ta.List[T]] = None
|
|
2081
|
+
|
|
2082
|
+
async def inner():
|
|
2083
|
+
nonlocal lst
|
|
2084
|
+
|
|
2085
|
+
lst = [v async for v in ai]
|
|
2086
|
+
|
|
2087
|
+
sync_await(inner())
|
|
2088
|
+
|
|
2089
|
+
if not isinstance(lst, list):
|
|
2090
|
+
raise TypeError(lst)
|
|
2091
|
+
|
|
2092
|
+
return lst
|
|
2093
|
+
|
|
2094
|
+
|
|
2095
|
+
#
|
|
2096
|
+
|
|
2097
|
+
|
|
2098
|
+
@ta.final
|
|
2099
|
+
class SyncAwaitContextManager(ta.Generic[T]):
|
|
2100
|
+
def __init__(self, acm: ta.AsyncContextManager[T]) -> None:
|
|
2101
|
+
self._acm = acm
|
|
2102
|
+
|
|
2103
|
+
def __repr__(self) -> str:
|
|
2104
|
+
return f'{self.__class__.__name__}({self._acm!r})'
|
|
2105
|
+
|
|
2106
|
+
def __enter__(self) -> T:
|
|
2107
|
+
return sync_await(self._acm.__aenter__())
|
|
2108
|
+
|
|
2109
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
2110
|
+
return sync_await(self._acm.__aexit__(exc_type, exc_val, exc_tb))
|
|
2111
|
+
|
|
2112
|
+
|
|
2113
|
+
sync_async_with = SyncAwaitContextManager
|
|
2114
|
+
|
|
2115
|
+
|
|
2116
|
+
##
|
|
2117
|
+
|
|
2118
|
+
|
|
2119
|
+
@ta.final
|
|
2120
|
+
class SyncToAsyncContextManager(ta.Generic[T]):
|
|
2121
|
+
def __init__(self, cm: ta.ContextManager[T]) -> None:
|
|
2122
|
+
self._cm = cm
|
|
2123
|
+
|
|
2124
|
+
def __repr__(self) -> str:
|
|
2125
|
+
return f'{self.__class__.__name__}({self._cm!r})'
|
|
2126
|
+
|
|
2127
|
+
async def __aenter__(self) -> T:
|
|
2128
|
+
return self._cm.__enter__()
|
|
2129
|
+
|
|
2130
|
+
async def __aexit__(self, exc_type, exc_value, traceback, /):
|
|
2131
|
+
return self._cm.__exit__(exc_type, exc_value, traceback)
|
|
2132
|
+
|
|
2133
|
+
|
|
2134
|
+
as_async_context_manager = SyncToAsyncContextManager
|
|
2135
|
+
|
|
2136
|
+
|
|
1848
2137
|
########################################
|
|
1849
2138
|
# ../../../omlish/lite/attrops.py
|
|
1850
2139
|
"""
|
|
@@ -1853,6 +2142,8 @@ TODO:
|
|
|
1853
2142
|
- per-attr repr transform / filter
|
|
1854
2143
|
- __ne__ ? cases where it still matters
|
|
1855
2144
|
- ordering ?
|
|
2145
|
+
- repr_filter: ta.Union[ta.Callable[[ta.Any], ta.Optional[str]], ta.Literal['not_none', 'truthy']]] ?
|
|
2146
|
+
- unify repr/repr_fn/repr_filter
|
|
1856
2147
|
"""
|
|
1857
2148
|
|
|
1858
2149
|
|
|
@@ -1870,6 +2161,8 @@ class AttrOps(ta.Generic[T]):
|
|
|
1870
2161
|
display: ta.Optional[str] = None,
|
|
1871
2162
|
|
|
1872
2163
|
repr: bool = True, # noqa
|
|
2164
|
+
repr_fn: ta.Optional[ta.Callable[[ta.Any], ta.Optional[str]]] = None,
|
|
2165
|
+
|
|
1873
2166
|
hash: bool = True, # noqa
|
|
1874
2167
|
eq: bool = True,
|
|
1875
2168
|
) -> None:
|
|
@@ -1884,6 +2177,8 @@ class AttrOps(ta.Generic[T]):
|
|
|
1884
2177
|
self._display = display
|
|
1885
2178
|
|
|
1886
2179
|
self._repr = repr
|
|
2180
|
+
self._repr_fn = repr_fn
|
|
2181
|
+
|
|
1887
2182
|
self._hash = hash
|
|
1888
2183
|
self._eq = eq
|
|
1889
2184
|
|
|
@@ -1891,21 +2186,30 @@ class AttrOps(ta.Generic[T]):
|
|
|
1891
2186
|
def of(
|
|
1892
2187
|
cls,
|
|
1893
2188
|
o: ta.Union[
|
|
1894
|
-
str,
|
|
1895
|
-
ta.Tuple[str, str],
|
|
1896
2189
|
'AttrOps.Attr',
|
|
2190
|
+
str,
|
|
2191
|
+
ta.Tuple[str, ta.Union[str, ta.Mapping[str, ta.Any]]],
|
|
2192
|
+
ta.Mapping[str, ta.Any],
|
|
1897
2193
|
],
|
|
1898
2194
|
) -> 'AttrOps.Attr':
|
|
1899
2195
|
if isinstance(o, AttrOps.Attr):
|
|
1900
2196
|
return o
|
|
1901
2197
|
elif isinstance(o, str):
|
|
1902
2198
|
return cls(o)
|
|
2199
|
+
elif isinstance(o, tuple):
|
|
2200
|
+
name, x = o
|
|
2201
|
+
kw: ta.Mapping[str, ta.Any]
|
|
2202
|
+
if isinstance(x, str):
|
|
2203
|
+
kw = dict(display=x)
|
|
2204
|
+
elif isinstance(x, ta.Mapping):
|
|
2205
|
+
kw = x
|
|
2206
|
+
else:
|
|
2207
|
+
raise TypeError(x)
|
|
2208
|
+
return cls(name, **kw)
|
|
2209
|
+
elif isinstance(o, ta.Mapping):
|
|
2210
|
+
return cls(**o)
|
|
1903
2211
|
else:
|
|
1904
|
-
|
|
1905
|
-
return cls(
|
|
1906
|
-
name,
|
|
1907
|
-
display=disp,
|
|
1908
|
-
)
|
|
2212
|
+
raise TypeError(o)
|
|
1909
2213
|
|
|
1910
2214
|
@property
|
|
1911
2215
|
def name(self) -> str:
|
|
@@ -1923,19 +2227,34 @@ class AttrOps(ta.Generic[T]):
|
|
|
1923
2227
|
def eq(self) -> bool:
|
|
1924
2228
|
return self._eq
|
|
1925
2229
|
|
|
2230
|
+
@staticmethod
|
|
2231
|
+
def opt_repr(o: ta.Any) -> ta.Optional[str]:
|
|
2232
|
+
return repr(o) if o is not None else None
|
|
2233
|
+
|
|
2234
|
+
@staticmethod
|
|
2235
|
+
def truthy_repr(o: ta.Any) -> ta.Optional[str]:
|
|
2236
|
+
return repr(o) if o else None
|
|
2237
|
+
|
|
2238
|
+
#
|
|
2239
|
+
|
|
1926
2240
|
@ta.overload
|
|
1927
2241
|
def __init__(
|
|
1928
2242
|
self,
|
|
1929
2243
|
*attrs: ta.Sequence[ta.Union[
|
|
1930
2244
|
str,
|
|
1931
|
-
ta.Tuple[str, str],
|
|
2245
|
+
ta.Tuple[str, ta.Union[str, ta.Mapping[str, ta.Any]]],
|
|
2246
|
+
ta.Mapping[str, ta.Any],
|
|
1932
2247
|
Attr,
|
|
1933
2248
|
]],
|
|
2249
|
+
|
|
1934
2250
|
with_module: bool = False,
|
|
1935
2251
|
use_qualname: bool = False,
|
|
1936
2252
|
with_id: bool = False,
|
|
2253
|
+
terse: bool = False,
|
|
1937
2254
|
repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = None,
|
|
1938
2255
|
recursive: bool = False,
|
|
2256
|
+
|
|
2257
|
+
cache_hash: ta.Union[bool, str] = False,
|
|
1939
2258
|
subtypes_eq: bool = False,
|
|
1940
2259
|
) -> None:
|
|
1941
2260
|
...
|
|
@@ -1945,16 +2264,20 @@ class AttrOps(ta.Generic[T]):
|
|
|
1945
2264
|
self,
|
|
1946
2265
|
attrs_fn: ta.Callable[[T], ta.Tuple[ta.Union[
|
|
1947
2266
|
ta.Any,
|
|
1948
|
-
ta.Tuple[str, ta.Any],
|
|
2267
|
+
ta.Tuple[ta.Any, ta.Union[str, ta.Mapping[str, ta.Any]]],
|
|
1949
2268
|
Attr,
|
|
1950
2269
|
], ...]],
|
|
1951
2270
|
/,
|
|
1952
2271
|
*,
|
|
2272
|
+
|
|
1953
2273
|
with_module: bool = False,
|
|
1954
2274
|
use_qualname: bool = False,
|
|
1955
2275
|
with_id: bool = False,
|
|
2276
|
+
terse: bool = False,
|
|
1956
2277
|
repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = None,
|
|
1957
2278
|
recursive: bool = False,
|
|
2279
|
+
|
|
2280
|
+
cache_hash: ta.Union[bool, str] = False,
|
|
1958
2281
|
subtypes_eq: bool = False,
|
|
1959
2282
|
) -> None:
|
|
1960
2283
|
...
|
|
@@ -1962,11 +2285,15 @@ class AttrOps(ta.Generic[T]):
|
|
|
1962
2285
|
def __init__(
|
|
1963
2286
|
self,
|
|
1964
2287
|
*args,
|
|
2288
|
+
|
|
1965
2289
|
with_module=False,
|
|
1966
2290
|
use_qualname=False,
|
|
1967
2291
|
with_id=False,
|
|
2292
|
+
terse=False,
|
|
1968
2293
|
repr_filter=None,
|
|
1969
2294
|
recursive=False,
|
|
2295
|
+
|
|
2296
|
+
cache_hash=False,
|
|
1970
2297
|
subtypes_eq=False,
|
|
1971
2298
|
) -> None:
|
|
1972
2299
|
if args and len(args) == 1 and callable(args[0]):
|
|
@@ -1977,8 +2304,11 @@ class AttrOps(ta.Generic[T]):
|
|
|
1977
2304
|
self._with_module: bool = with_module
|
|
1978
2305
|
self._use_qualname: bool = use_qualname
|
|
1979
2306
|
self._with_id: bool = with_id
|
|
2307
|
+
self._terse: bool = terse
|
|
1980
2308
|
self._repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = repr_filter
|
|
1981
2309
|
self._recursive: bool = recursive
|
|
2310
|
+
|
|
2311
|
+
self._cache_hash: ta.Union[bool, str] = cache_hash
|
|
1982
2312
|
self._subtypes_eq: bool = subtypes_eq
|
|
1983
2313
|
|
|
1984
2314
|
@property
|
|
@@ -2013,20 +2343,27 @@ class AttrOps(ta.Generic[T]):
|
|
|
2013
2343
|
|
|
2014
2344
|
attrs: ta.List[AttrOps.Attr] = []
|
|
2015
2345
|
for o in raw:
|
|
2016
|
-
if isinstance(o, AttrOps.Attr):
|
|
2017
|
-
attrs.append(o)
|
|
2346
|
+
if isinstance(o, (AttrOps.Attr, ta.Mapping)):
|
|
2347
|
+
attrs.append(AttrOps.Attr.of(o))
|
|
2018
2348
|
continue
|
|
2019
2349
|
|
|
2350
|
+
kw: ta.Mapping[str, ta.Any]
|
|
2020
2351
|
if isinstance(o, tuple):
|
|
2021
|
-
|
|
2352
|
+
cap, x = o
|
|
2353
|
+
if isinstance(x, str):
|
|
2354
|
+
kw = dict(display=x)
|
|
2355
|
+
elif isinstance(x, ta.Mapping):
|
|
2356
|
+
kw = x
|
|
2357
|
+
else:
|
|
2358
|
+
raise TypeError(x)
|
|
2022
2359
|
else:
|
|
2023
|
-
|
|
2360
|
+
cap, kw = o, {}
|
|
2024
2361
|
|
|
2025
2362
|
path = tuple(rec(cap))
|
|
2026
2363
|
|
|
2027
2364
|
attrs.append(AttrOps.Attr(
|
|
2028
2365
|
'.'.join(path),
|
|
2029
|
-
|
|
2366
|
+
**kw,
|
|
2030
2367
|
))
|
|
2031
2368
|
|
|
2032
2369
|
return attrs
|
|
@@ -2043,19 +2380,27 @@ class AttrOps(ta.Generic[T]):
|
|
|
2043
2380
|
pass
|
|
2044
2381
|
|
|
2045
2382
|
def _repr(o: T) -> str:
|
|
2046
|
-
vs =
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
if self._repr_filter is None
|
|
2052
|
-
|
|
2383
|
+
vs: ta.List[str] = []
|
|
2384
|
+
for a in self._attrs:
|
|
2385
|
+
if not a._repr: # noqa
|
|
2386
|
+
continue
|
|
2387
|
+
v = getattr(o, a._name) # noqa
|
|
2388
|
+
if self._repr_filter is not None and not self._repr_filter(v):
|
|
2389
|
+
continue
|
|
2390
|
+
if (rfn := a._repr_fn) is None: # noqa
|
|
2391
|
+
rfn = repr
|
|
2392
|
+
if (vr := rfn(v)) is None:
|
|
2393
|
+
continue
|
|
2394
|
+
if self._terse:
|
|
2395
|
+
vs.append(vr)
|
|
2396
|
+
else:
|
|
2397
|
+
vs.append(f'{a._display}={vr}') # noqa
|
|
2053
2398
|
|
|
2054
2399
|
return (
|
|
2055
2400
|
f'{o.__class__.__module__ + "." if self._with_module else ""}'
|
|
2056
2401
|
f'{o.__class__.__qualname__ if self._use_qualname else o.__class__.__name__}'
|
|
2057
|
-
f'{("@" + hex(id(o))[2:]) if self._with_id else ""}'
|
|
2058
|
-
f'({vs})'
|
|
2402
|
+
f'{("@" + hex(id(o))[2:]) if self._with_id else ""}' # noqa
|
|
2403
|
+
f'({", ".join(vs)})'
|
|
2059
2404
|
)
|
|
2060
2405
|
|
|
2061
2406
|
if self._recursive:
|
|
@@ -2080,6 +2425,8 @@ class AttrOps(ta.Generic[T]):
|
|
|
2080
2425
|
|
|
2081
2426
|
#
|
|
2082
2427
|
|
|
2428
|
+
_DEFAULT_CACHED_HASH_ATTR: ta.ClassVar[str] = '__cached_hash__'
|
|
2429
|
+
|
|
2083
2430
|
_hash: ta.Callable[[T], int]
|
|
2084
2431
|
|
|
2085
2432
|
@property
|
|
@@ -2089,13 +2436,33 @@ class AttrOps(ta.Generic[T]):
|
|
|
2089
2436
|
except AttributeError:
|
|
2090
2437
|
pass
|
|
2091
2438
|
|
|
2092
|
-
def
|
|
2439
|
+
def _calc_hash(o: T) -> int:
|
|
2093
2440
|
return hash(tuple(
|
|
2094
2441
|
getattr(o, a._name) # noqa
|
|
2095
2442
|
for a in self._attrs
|
|
2096
2443
|
if a._hash # noqa
|
|
2097
2444
|
))
|
|
2098
2445
|
|
|
2446
|
+
if (ch := self._cache_hash) is not False:
|
|
2447
|
+
if ch is True:
|
|
2448
|
+
cha = self._DEFAULT_CACHED_HASH_ATTR
|
|
2449
|
+
elif isinstance(ch, str):
|
|
2450
|
+
cha = ch
|
|
2451
|
+
else:
|
|
2452
|
+
raise TypeError(ch)
|
|
2453
|
+
|
|
2454
|
+
def _cached_hash(o: T) -> int:
|
|
2455
|
+
try:
|
|
2456
|
+
return object.__getattribute__(o, cha)
|
|
2457
|
+
except AttributeError:
|
|
2458
|
+
object.__setattr__(o, cha, h := _calc_hash(o))
|
|
2459
|
+
return h
|
|
2460
|
+
|
|
2461
|
+
_hash = _cached_hash
|
|
2462
|
+
|
|
2463
|
+
else:
|
|
2464
|
+
_hash = _calc_hash
|
|
2465
|
+
|
|
2099
2466
|
self._hash = _hash
|
|
2100
2467
|
return _hash
|
|
2101
2468
|
|
|
@@ -2236,6 +2603,62 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
|
2236
2603
|
return _AsyncCachedNullary(fn)
|
|
2237
2604
|
|
|
2238
2605
|
|
|
2606
|
+
##
|
|
2607
|
+
|
|
2608
|
+
|
|
2609
|
+
cached_property = functools.cached_property
|
|
2610
|
+
|
|
2611
|
+
|
|
2612
|
+
class _cached_property: # noqa
|
|
2613
|
+
"""Backported to pick up https://github.com/python/cpython/commit/056dfc71dce15f81887f0bd6da09d6099d71f979 ."""
|
|
2614
|
+
|
|
2615
|
+
def __init__(self, func):
|
|
2616
|
+
self.func = func
|
|
2617
|
+
self.attrname = None # noqa
|
|
2618
|
+
self.__doc__ = func.__doc__
|
|
2619
|
+
self.__module__ = func.__module__
|
|
2620
|
+
|
|
2621
|
+
_NOT_FOUND = object()
|
|
2622
|
+
|
|
2623
|
+
def __set_name__(self, owner, name):
|
|
2624
|
+
if self.attrname is None:
|
|
2625
|
+
self.attrname = name # noqa
|
|
2626
|
+
elif name != self.attrname:
|
|
2627
|
+
raise TypeError(
|
|
2628
|
+
f'Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r}).',
|
|
2629
|
+
)
|
|
2630
|
+
|
|
2631
|
+
def __get__(self, instance, owner=None):
|
|
2632
|
+
if instance is None:
|
|
2633
|
+
return self
|
|
2634
|
+
if self.attrname is None:
|
|
2635
|
+
raise TypeError('Cannot use cached_property instance without calling __set_name__ on it.')
|
|
2636
|
+
|
|
2637
|
+
try:
|
|
2638
|
+
cache = instance.__dict__
|
|
2639
|
+
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
|
2640
|
+
raise TypeError(
|
|
2641
|
+
f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {self.attrname!r} property.",
|
|
2642
|
+
) from None
|
|
2643
|
+
|
|
2644
|
+
val = cache.get(self.attrname, self._NOT_FOUND)
|
|
2645
|
+
|
|
2646
|
+
if val is self._NOT_FOUND:
|
|
2647
|
+
val = self.func(instance)
|
|
2648
|
+
try:
|
|
2649
|
+
cache[self.attrname] = val
|
|
2650
|
+
except TypeError:
|
|
2651
|
+
raise TypeError(
|
|
2652
|
+
f"The '__dict__' attribute on {type(instance).__name__!r} instance does not support item "
|
|
2653
|
+
f"assignment for caching {self.attrname!r} property.",
|
|
2654
|
+
) from None
|
|
2655
|
+
|
|
2656
|
+
return val
|
|
2657
|
+
|
|
2658
|
+
|
|
2659
|
+
globals()['cached_property'] = _cached_property
|
|
2660
|
+
|
|
2661
|
+
|
|
2239
2662
|
########################################
|
|
2240
2663
|
# ../../../omlish/lite/check.py
|
|
2241
2664
|
"""
|
|
@@ -3024,6 +3447,12 @@ def format_num_bytes(num_bytes: int) -> str:
|
|
|
3024
3447
|
|
|
3025
3448
|
##
|
|
3026
3449
|
# A workaround for typing deficiencies (like `Argument 2 to NewType(...) must be subclassable`).
|
|
3450
|
+
#
|
|
3451
|
+
# Note that this problem doesn't happen at runtime - it happens in mypy:
|
|
3452
|
+
#
|
|
3453
|
+
# mypy <(echo "import typing as ta; MyCallback = ta.NewType('MyCallback', ta.Callable[[], None])")
|
|
3454
|
+
# /dev/fd/11:1:22: error: Argument 2 to NewType(...) must be subclassable (got "Callable[[], None]") [valid-newtype]
|
|
3455
|
+
#
|
|
3027
3456
|
|
|
3028
3457
|
|
|
3029
3458
|
@dc.dataclass(frozen=True)
|
|
@@ -3069,6 +3498,39 @@ class Func3(ta.Generic[A0, A1, A2, T]):
|
|
|
3069
3498
|
##
|
|
3070
3499
|
|
|
3071
3500
|
|
|
3501
|
+
@dc.dataclass(frozen=True)
|
|
3502
|
+
class CachedFunc0(ta.Generic[T]):
|
|
3503
|
+
fn: ta.Callable[[], T]
|
|
3504
|
+
|
|
3505
|
+
def __call__(self) -> T:
|
|
3506
|
+
try:
|
|
3507
|
+
return object.__getattribute__(self, '_value')
|
|
3508
|
+
except AttributeError:
|
|
3509
|
+
pass
|
|
3510
|
+
|
|
3511
|
+
value = self.fn()
|
|
3512
|
+
object.__setattr__(self, '_value', value)
|
|
3513
|
+
return value
|
|
3514
|
+
|
|
3515
|
+
|
|
3516
|
+
@dc.dataclass(frozen=True)
|
|
3517
|
+
class AsyncCachedFunc0(ta.Generic[T]):
|
|
3518
|
+
fn: ta.Callable[[], ta.Awaitable[T]]
|
|
3519
|
+
|
|
3520
|
+
async def __call__(self) -> T:
|
|
3521
|
+
try:
|
|
3522
|
+
return object.__getattribute__(self, '_value')
|
|
3523
|
+
except AttributeError:
|
|
3524
|
+
pass
|
|
3525
|
+
|
|
3526
|
+
value = await self.fn()
|
|
3527
|
+
object.__setattr__(self, '_value', value)
|
|
3528
|
+
return value
|
|
3529
|
+
|
|
3530
|
+
|
|
3531
|
+
##
|
|
3532
|
+
|
|
3533
|
+
|
|
3072
3534
|
_TYPING_ANNOTATIONS_ATTR = '__annotate__' if sys.version_info >= (3, 14) else '__annotations__'
|
|
3073
3535
|
|
|
3074
3536
|
|
|
@@ -4114,6 +4576,72 @@ def build_config_named_children(
|
|
|
4114
4576
|
return lst
|
|
4115
4577
|
|
|
4116
4578
|
|
|
4579
|
+
########################################
|
|
4580
|
+
# ../../../omlish/http/coro/io.py
|
|
4581
|
+
|
|
4582
|
+
|
|
4583
|
+
##
|
|
4584
|
+
|
|
4585
|
+
|
|
4586
|
+
class CoroHttpIo:
|
|
4587
|
+
def __new__(cls, *args, **kwargs): # noqa
|
|
4588
|
+
raise TypeError
|
|
4589
|
+
|
|
4590
|
+
def __init_subclass__(cls, **kwargs): # noqa
|
|
4591
|
+
raise TypeError
|
|
4592
|
+
|
|
4593
|
+
#
|
|
4594
|
+
|
|
4595
|
+
MAX_LINE: ta.ClassVar[int] = 65536
|
|
4596
|
+
|
|
4597
|
+
#
|
|
4598
|
+
|
|
4599
|
+
class Io(Abstract):
|
|
4600
|
+
pass
|
|
4601
|
+
|
|
4602
|
+
#
|
|
4603
|
+
|
|
4604
|
+
class AnyLogIo(Io, Abstract):
|
|
4605
|
+
pass
|
|
4606
|
+
|
|
4607
|
+
#
|
|
4608
|
+
|
|
4609
|
+
@dc.dataclass(frozen=True)
|
|
4610
|
+
class ConnectIo(Io):
|
|
4611
|
+
args: ta.Tuple[ta.Any, ...]
|
|
4612
|
+
kwargs: ta.Optional[ta.Dict[str, ta.Any]] = None
|
|
4613
|
+
|
|
4614
|
+
server_hostname: ta.Optional[str] = None
|
|
4615
|
+
|
|
4616
|
+
#
|
|
4617
|
+
|
|
4618
|
+
class CloseIo(Io):
|
|
4619
|
+
pass
|
|
4620
|
+
|
|
4621
|
+
#
|
|
4622
|
+
|
|
4623
|
+
class AnyReadIo(Io): # noqa
|
|
4624
|
+
pass
|
|
4625
|
+
|
|
4626
|
+
@dc.dataclass(frozen=True)
|
|
4627
|
+
class ReadIo(AnyReadIo):
|
|
4628
|
+
sz: ta.Optional[int]
|
|
4629
|
+
|
|
4630
|
+
@dc.dataclass(frozen=True)
|
|
4631
|
+
class ReadLineIo(AnyReadIo):
|
|
4632
|
+
sz: int
|
|
4633
|
+
|
|
4634
|
+
@dc.dataclass(frozen=True)
|
|
4635
|
+
class PeekIo(AnyReadIo):
|
|
4636
|
+
sz: int
|
|
4637
|
+
|
|
4638
|
+
#
|
|
4639
|
+
|
|
4640
|
+
@dc.dataclass(frozen=True)
|
|
4641
|
+
class WriteIo(Io):
|
|
4642
|
+
data: bytes
|
|
4643
|
+
|
|
4644
|
+
|
|
4117
4645
|
########################################
|
|
4118
4646
|
# ../../../omlish/http/parsing.py
|
|
4119
4647
|
# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
|
@@ -4529,6 +5057,10 @@ class HttpRequestParser:
|
|
|
4529
5057
|
|
|
4530
5058
|
########################################
|
|
4531
5059
|
# ../../../omlish/io/buffers.py
|
|
5060
|
+
"""
|
|
5061
|
+
TODO:
|
|
5062
|
+
- overhaul and just coro-ify pyio?
|
|
5063
|
+
"""
|
|
4532
5064
|
|
|
4533
5065
|
|
|
4534
5066
|
##
|
|
@@ -4707,6 +5239,9 @@ class ReadableListBuffer:
|
|
|
4707
5239
|
|
|
4708
5240
|
self._lst: list[bytes] = []
|
|
4709
5241
|
|
|
5242
|
+
def __bool__(self) -> ta.NoReturn:
|
|
5243
|
+
raise TypeError("Use 'buf is not None' or 'len(buf)'.")
|
|
5244
|
+
|
|
4710
5245
|
def __len__(self) -> int:
|
|
4711
5246
|
return sum(map(len, self._lst))
|
|
4712
5247
|
|
|
@@ -4732,6 +5267,9 @@ class ReadableListBuffer:
|
|
|
4732
5267
|
|
|
4733
5268
|
def read(self, n: ta.Optional[int] = None) -> ta.Optional[bytes]:
|
|
4734
5269
|
if n is None:
|
|
5270
|
+
if not self._lst:
|
|
5271
|
+
return b''
|
|
5272
|
+
|
|
4735
5273
|
o = b''.join(self._lst)
|
|
4736
5274
|
self._lst = []
|
|
4737
5275
|
return o
|
|
@@ -4770,6 +5308,110 @@ class ReadableListBuffer:
|
|
|
4770
5308
|
r = self.read_until_(delim)
|
|
4771
5309
|
return r if isinstance(r, bytes) else None
|
|
4772
5310
|
|
|
5311
|
+
#
|
|
5312
|
+
|
|
5313
|
+
DEFAULT_BUFFERED_READER_CHUNK_SIZE: ta.ClassVar[int] = -1
|
|
5314
|
+
|
|
5315
|
+
@ta.final
|
|
5316
|
+
class _BufferedBytesReader(BufferedBytesReader):
|
|
5317
|
+
def __init__(
|
|
5318
|
+
self,
|
|
5319
|
+
raw: RawBytesReader,
|
|
5320
|
+
buf: 'ReadableListBuffer',
|
|
5321
|
+
*,
|
|
5322
|
+
chunk_size: ta.Optional[int] = None,
|
|
5323
|
+
) -> None:
|
|
5324
|
+
self._raw = raw
|
|
5325
|
+
self._buf = buf
|
|
5326
|
+
self._chunk_size = chunk_size or ReadableListBuffer.DEFAULT_BUFFERED_READER_CHUNK_SIZE
|
|
5327
|
+
|
|
5328
|
+
def read1(self, n: int = -1, /) -> bytes:
|
|
5329
|
+
if n < 0:
|
|
5330
|
+
n = self._chunk_size
|
|
5331
|
+
if not n:
|
|
5332
|
+
return b''
|
|
5333
|
+
if 0 < n <= len(self._buf):
|
|
5334
|
+
return self._buf.read(n) or b''
|
|
5335
|
+
return self._raw.read1(n)
|
|
5336
|
+
|
|
5337
|
+
def read(self, /, n: int = -1) -> bytes:
|
|
5338
|
+
if n < 0:
|
|
5339
|
+
return self.readall()
|
|
5340
|
+
while len(self._buf) < n:
|
|
5341
|
+
if not (b := self._raw.read1(n)):
|
|
5342
|
+
break
|
|
5343
|
+
self._buf.feed(b)
|
|
5344
|
+
return self._buf.read(n) or b''
|
|
5345
|
+
|
|
5346
|
+
def readall(self) -> bytes:
|
|
5347
|
+
buf = io.BytesIO()
|
|
5348
|
+
buf.write(self._buf.read() or b'')
|
|
5349
|
+
while (b := self._raw.read1(self._chunk_size)):
|
|
5350
|
+
buf.write(b)
|
|
5351
|
+
return buf.getvalue()
|
|
5352
|
+
|
|
5353
|
+
def new_buffered_reader(
|
|
5354
|
+
self,
|
|
5355
|
+
raw: RawBytesReader,
|
|
5356
|
+
*,
|
|
5357
|
+
chunk_size: ta.Optional[int] = None,
|
|
5358
|
+
) -> BufferedBytesReader:
|
|
5359
|
+
return self._BufferedBytesReader(
|
|
5360
|
+
raw,
|
|
5361
|
+
self,
|
|
5362
|
+
chunk_size=chunk_size,
|
|
5363
|
+
)
|
|
5364
|
+
|
|
5365
|
+
@ta.final
|
|
5366
|
+
class _AsyncBufferedBytesReader(AsyncBufferedBytesReader):
|
|
5367
|
+
def __init__(
|
|
5368
|
+
self,
|
|
5369
|
+
raw: AsyncRawBytesReader,
|
|
5370
|
+
buf: 'ReadableListBuffer',
|
|
5371
|
+
*,
|
|
5372
|
+
chunk_size: ta.Optional[int] = None,
|
|
5373
|
+
) -> None:
|
|
5374
|
+
self._raw = raw
|
|
5375
|
+
self._buf = buf
|
|
5376
|
+
self._chunk_size = chunk_size or ReadableListBuffer.DEFAULT_BUFFERED_READER_CHUNK_SIZE
|
|
5377
|
+
|
|
5378
|
+
async def read1(self, n: int = -1, /) -> bytes:
|
|
5379
|
+
if n < 0:
|
|
5380
|
+
n = self._chunk_size
|
|
5381
|
+
if not n:
|
|
5382
|
+
return b''
|
|
5383
|
+
if 0 < n <= len(self._buf):
|
|
5384
|
+
return self._buf.read(n) or b''
|
|
5385
|
+
return await self._raw.read1(n)
|
|
5386
|
+
|
|
5387
|
+
async def read(self, /, n: int = -1) -> bytes:
|
|
5388
|
+
if n < 0:
|
|
5389
|
+
return await self.readall()
|
|
5390
|
+
while len(self._buf) < n:
|
|
5391
|
+
if not (b := await self._raw.read1(n)):
|
|
5392
|
+
break
|
|
5393
|
+
self._buf.feed(b)
|
|
5394
|
+
return self._buf.read(n) or b''
|
|
5395
|
+
|
|
5396
|
+
async def readall(self) -> bytes:
|
|
5397
|
+
buf = io.BytesIO()
|
|
5398
|
+
buf.write(self._buf.read() or b'')
|
|
5399
|
+
while b := await self._raw.read1(self._chunk_size):
|
|
5400
|
+
buf.write(b)
|
|
5401
|
+
return buf.getvalue()
|
|
5402
|
+
|
|
5403
|
+
def new_async_buffered_reader(
|
|
5404
|
+
self,
|
|
5405
|
+
raw: AsyncRawBytesReader,
|
|
5406
|
+
*,
|
|
5407
|
+
chunk_size: ta.Optional[int] = None,
|
|
5408
|
+
) -> AsyncBufferedBytesReader:
|
|
5409
|
+
return self._AsyncBufferedBytesReader(
|
|
5410
|
+
raw,
|
|
5411
|
+
self,
|
|
5412
|
+
chunk_size=chunk_size,
|
|
5413
|
+
)
|
|
5414
|
+
|
|
4773
5415
|
|
|
4774
5416
|
##
|
|
4775
5417
|
|
|
@@ -5960,6 +6602,13 @@ class Maybe(ta.Generic[T]):
|
|
|
5960
6602
|
else:
|
|
5961
6603
|
return other
|
|
5962
6604
|
|
|
6605
|
+
@ta.final
|
|
6606
|
+
def or_none(self) -> ta.Optional[T]:
|
|
6607
|
+
if self.present:
|
|
6608
|
+
return self.must()
|
|
6609
|
+
else:
|
|
6610
|
+
return None
|
|
6611
|
+
|
|
5963
6612
|
@ta.final
|
|
5964
6613
|
def or_else_get(self, supplier: ta.Callable[[], ta.Union[T, U]]) -> ta.Union[T, U]:
|
|
5965
6614
|
if self.present:
|
|
@@ -6014,8 +6663,6 @@ class _JustMaybe(_Maybe[T]):
|
|
|
6014
6663
|
__slots__ = ('_v', '_hash')
|
|
6015
6664
|
|
|
6016
6665
|
def __init__(self, v: T) -> None:
|
|
6017
|
-
super().__init__()
|
|
6018
|
-
|
|
6019
6666
|
self._v = v
|
|
6020
6667
|
|
|
6021
6668
|
@property
|
|
@@ -6073,6 +6720,13 @@ class _EmptyMaybe(_Maybe[T]):
|
|
|
6073
6720
|
Maybe._empty = _EmptyMaybe() # noqa
|
|
6074
6721
|
|
|
6075
6722
|
|
|
6723
|
+
##
|
|
6724
|
+
|
|
6725
|
+
|
|
6726
|
+
setattr(Maybe, 'just', _JustMaybe) # noqa
|
|
6727
|
+
setattr(Maybe, 'empty', functools.partial(operator.attrgetter('_empty'), Maybe))
|
|
6728
|
+
|
|
6729
|
+
|
|
6076
6730
|
########################################
|
|
6077
6731
|
# ../../../omlish/lite/runtime.py
|
|
6078
6732
|
|
|
@@ -8676,6 +9330,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
8676
9330
|
self._infos[type(info)] = info
|
|
8677
9331
|
return self
|
|
8678
9332
|
|
|
9333
|
+
def get_infos(self) -> ta.Mapping[ta.Type[LoggingContextInfo], LoggingContextInfo]:
|
|
9334
|
+
return self._infos
|
|
9335
|
+
|
|
8679
9336
|
def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
|
8680
9337
|
return self._infos.get(ty)
|
|
8681
9338
|
|
|
@@ -8698,7 +9355,7 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
8698
9355
|
_stack_offset: int
|
|
8699
9356
|
_stack_info: bool
|
|
8700
9357
|
|
|
8701
|
-
def inc_stack_offset(self, ofs: int = 1) -> '
|
|
9358
|
+
def inc_stack_offset(self, ofs: int = 1) -> 'CaptureLoggingContextImpl':
|
|
8702
9359
|
if hasattr(self, '_stack_offset'):
|
|
8703
9360
|
self._stack_offset += ofs
|
|
8704
9361
|
return self
|
|
@@ -8730,10 +9387,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
8730
9387
|
|
|
8731
9388
|
|
|
8732
9389
|
########################################
|
|
8733
|
-
# ../../../omlish/logs/standard.py
|
|
9390
|
+
# ../../../omlish/logs/std/standard.py
|
|
8734
9391
|
"""
|
|
8735
9392
|
TODO:
|
|
8736
|
-
- !! move to std !!
|
|
8737
9393
|
- structured
|
|
8738
9394
|
- prefixed
|
|
8739
9395
|
- debug
|
|
@@ -9392,48 +10048,21 @@ class CoroHttpServer:
|
|
|
9392
10048
|
|
|
9393
10049
|
#
|
|
9394
10050
|
|
|
9395
|
-
class Io(Abstract):
|
|
9396
|
-
pass
|
|
9397
|
-
|
|
9398
|
-
#
|
|
9399
|
-
|
|
9400
|
-
class AnyLogIo(Io):
|
|
9401
|
-
pass
|
|
9402
|
-
|
|
9403
10051
|
@dc.dataclass(frozen=True)
|
|
9404
|
-
class ParsedRequestLogIo(AnyLogIo):
|
|
10052
|
+
class ParsedRequestLogIo(CoroHttpIo.AnyLogIo):
|
|
9405
10053
|
request: ParsedHttpRequest
|
|
9406
10054
|
|
|
9407
10055
|
@dc.dataclass(frozen=True)
|
|
9408
|
-
class ErrorLogIo(AnyLogIo):
|
|
10056
|
+
class ErrorLogIo(CoroHttpIo.AnyLogIo):
|
|
9409
10057
|
error: 'CoroHttpServer.Error'
|
|
9410
10058
|
|
|
9411
10059
|
#
|
|
9412
10060
|
|
|
9413
|
-
class AnyReadIo(Io): # noqa
|
|
9414
|
-
pass
|
|
9415
|
-
|
|
9416
|
-
@dc.dataclass(frozen=True)
|
|
9417
|
-
class ReadIo(AnyReadIo):
|
|
9418
|
-
sz: int
|
|
9419
|
-
|
|
9420
|
-
@dc.dataclass(frozen=True)
|
|
9421
|
-
class ReadLineIo(AnyReadIo):
|
|
9422
|
-
sz: int
|
|
9423
|
-
|
|
9424
|
-
#
|
|
9425
|
-
|
|
9426
|
-
@dc.dataclass(frozen=True)
|
|
9427
|
-
class WriteIo(Io):
|
|
9428
|
-
data: bytes
|
|
9429
|
-
|
|
9430
|
-
#
|
|
9431
|
-
|
|
9432
10061
|
@dc.dataclass(frozen=True)
|
|
9433
10062
|
class CoroHandleResult:
|
|
9434
10063
|
close_reason: ta.Literal['response', 'internal', None] = None
|
|
9435
10064
|
|
|
9436
|
-
def coro_handle(self) -> ta.Generator[Io, ta.Optional[bytes], CoroHandleResult]:
|
|
10065
|
+
def coro_handle(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], CoroHandleResult]:
|
|
9437
10066
|
return self._coro_run_handler(self._coro_handle_one())
|
|
9438
10067
|
|
|
9439
10068
|
class Close(Exception): # noqa
|
|
@@ -9442,20 +10071,20 @@ class CoroHttpServer:
|
|
|
9442
10071
|
def _coro_run_handler(
|
|
9443
10072
|
self,
|
|
9444
10073
|
gen: ta.Generator[
|
|
9445
|
-
ta.Union[AnyLogIo, AnyReadIo, _Response],
|
|
10074
|
+
ta.Union[CoroHttpIo.AnyLogIo, CoroHttpIo.AnyReadIo, _Response],
|
|
9446
10075
|
ta.Optional[bytes],
|
|
9447
10076
|
None,
|
|
9448
10077
|
],
|
|
9449
|
-
) -> ta.Generator[Io, ta.Optional[bytes], CoroHandleResult]:
|
|
10078
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], CoroHandleResult]:
|
|
9450
10079
|
i: ta.Optional[bytes]
|
|
9451
10080
|
o: ta.Any = next(gen)
|
|
9452
10081
|
while True:
|
|
9453
10082
|
try:
|
|
9454
|
-
if isinstance(o,
|
|
10083
|
+
if isinstance(o, CoroHttpIo.AnyLogIo):
|
|
9455
10084
|
i = None
|
|
9456
10085
|
yield o
|
|
9457
10086
|
|
|
9458
|
-
elif isinstance(o,
|
|
10087
|
+
elif isinstance(o, CoroHttpIo.AnyReadIo):
|
|
9459
10088
|
i = check.isinstance((yield o), bytes)
|
|
9460
10089
|
|
|
9461
10090
|
elif isinstance(o, self._Response):
|
|
@@ -9463,10 +10092,10 @@ class CoroHttpServer:
|
|
|
9463
10092
|
|
|
9464
10093
|
r = self._preprocess_response(o)
|
|
9465
10094
|
hb = self._build_response_head_bytes(r)
|
|
9466
|
-
check.none((yield
|
|
10095
|
+
check.none((yield CoroHttpIo.WriteIo(hb)))
|
|
9467
10096
|
|
|
9468
10097
|
for b in self._yield_response_data(r):
|
|
9469
|
-
yield
|
|
10098
|
+
yield CoroHttpIo.WriteIo(b)
|
|
9470
10099
|
|
|
9471
10100
|
o.close()
|
|
9472
10101
|
if o.close_connection:
|
|
@@ -9494,7 +10123,7 @@ class CoroHttpServer:
|
|
|
9494
10123
|
raise
|
|
9495
10124
|
|
|
9496
10125
|
def _coro_handle_one(self) -> ta.Generator[
|
|
9497
|
-
ta.Union[AnyLogIo, AnyReadIo, _Response],
|
|
10126
|
+
ta.Union[CoroHttpIo.AnyLogIo, CoroHttpIo.AnyReadIo, _Response],
|
|
9498
10127
|
ta.Optional[bytes],
|
|
9499
10128
|
None,
|
|
9500
10129
|
]:
|
|
@@ -9504,7 +10133,7 @@ class CoroHttpServer:
|
|
|
9504
10133
|
sz = next(gen)
|
|
9505
10134
|
while True:
|
|
9506
10135
|
try:
|
|
9507
|
-
line = check.isinstance((yield
|
|
10136
|
+
line = check.isinstance((yield CoroHttpIo.ReadLineIo(sz)), bytes)
|
|
9508
10137
|
sz = gen.send(line)
|
|
9509
10138
|
except StopIteration as e:
|
|
9510
10139
|
parsed = e.value
|
|
@@ -9543,7 +10172,7 @@ class CoroHttpServer:
|
|
|
9543
10172
|
|
|
9544
10173
|
request_data: ta.Optional[bytes]
|
|
9545
10174
|
if (cl := parsed.headers.get('Content-Length')) is not None:
|
|
9546
|
-
request_data = check.isinstance((yield
|
|
10175
|
+
request_data = check.isinstance((yield CoroHttpIo.ReadIo(int(cl))), bytes)
|
|
9547
10176
|
else:
|
|
9548
10177
|
request_data = None
|
|
9549
10178
|
|
|
@@ -9630,6 +10259,11 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9630
10259
|
|
|
9631
10260
|
##
|
|
9632
10261
|
|
|
10262
|
+
# This will be 1 for [Sync]Logger and 0 for AsyncLogger - in sync loggers these methods remain present on the stack,
|
|
10263
|
+
# in async loggers they return a coroutine to be awaited and thus aren't actually present when said coroutine is
|
|
10264
|
+
# awaited.
|
|
10265
|
+
_level_proxy_method_stack_offset: int
|
|
10266
|
+
|
|
9633
10267
|
@ta.overload
|
|
9634
10268
|
def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
|
9635
10269
|
...
|
|
@@ -9644,7 +10278,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9644
10278
|
|
|
9645
10279
|
@ta.final
|
|
9646
10280
|
def log(self, level: LogLevel, *args, **kwargs):
|
|
9647
|
-
return self._log(
|
|
10281
|
+
return self._log(
|
|
10282
|
+
CaptureLoggingContextImpl(
|
|
10283
|
+
level,
|
|
10284
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10285
|
+
),
|
|
10286
|
+
*args,
|
|
10287
|
+
**kwargs,
|
|
10288
|
+
)
|
|
9648
10289
|
|
|
9649
10290
|
#
|
|
9650
10291
|
|
|
@@ -9662,7 +10303,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9662
10303
|
|
|
9663
10304
|
@ta.final
|
|
9664
10305
|
def debug(self, *args, **kwargs):
|
|
9665
|
-
return self._log(
|
|
10306
|
+
return self._log(
|
|
10307
|
+
CaptureLoggingContextImpl(
|
|
10308
|
+
NamedLogLevel.DEBUG,
|
|
10309
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10310
|
+
),
|
|
10311
|
+
*args,
|
|
10312
|
+
**kwargs,
|
|
10313
|
+
)
|
|
9666
10314
|
|
|
9667
10315
|
#
|
|
9668
10316
|
|
|
@@ -9680,7 +10328,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9680
10328
|
|
|
9681
10329
|
@ta.final
|
|
9682
10330
|
def info(self, *args, **kwargs):
|
|
9683
|
-
return self._log(
|
|
10331
|
+
return self._log(
|
|
10332
|
+
CaptureLoggingContextImpl(
|
|
10333
|
+
NamedLogLevel.INFO,
|
|
10334
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10335
|
+
),
|
|
10336
|
+
*args,
|
|
10337
|
+
**kwargs,
|
|
10338
|
+
)
|
|
9684
10339
|
|
|
9685
10340
|
#
|
|
9686
10341
|
|
|
@@ -9698,7 +10353,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9698
10353
|
|
|
9699
10354
|
@ta.final
|
|
9700
10355
|
def warning(self, *args, **kwargs):
|
|
9701
|
-
return self._log(
|
|
10356
|
+
return self._log(
|
|
10357
|
+
CaptureLoggingContextImpl(
|
|
10358
|
+
NamedLogLevel.WARNING,
|
|
10359
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10360
|
+
),
|
|
10361
|
+
*args,
|
|
10362
|
+
**kwargs,
|
|
10363
|
+
)
|
|
9702
10364
|
|
|
9703
10365
|
#
|
|
9704
10366
|
|
|
@@ -9716,7 +10378,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9716
10378
|
|
|
9717
10379
|
@ta.final
|
|
9718
10380
|
def error(self, *args, **kwargs):
|
|
9719
|
-
return self._log(
|
|
10381
|
+
return self._log(
|
|
10382
|
+
CaptureLoggingContextImpl(
|
|
10383
|
+
NamedLogLevel.ERROR,
|
|
10384
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10385
|
+
),
|
|
10386
|
+
*args,
|
|
10387
|
+
**kwargs,
|
|
10388
|
+
)
|
|
9720
10389
|
|
|
9721
10390
|
#
|
|
9722
10391
|
|
|
@@ -9734,7 +10403,15 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9734
10403
|
|
|
9735
10404
|
@ta.final
|
|
9736
10405
|
def exception(self, *args, exc_info: LoggingExcInfoArg = True, **kwargs):
|
|
9737
|
-
return self._log(
|
|
10406
|
+
return self._log(
|
|
10407
|
+
CaptureLoggingContextImpl(
|
|
10408
|
+
NamedLogLevel.ERROR,
|
|
10409
|
+
exc_info=exc_info,
|
|
10410
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10411
|
+
),
|
|
10412
|
+
*args,
|
|
10413
|
+
**kwargs,
|
|
10414
|
+
)
|
|
9738
10415
|
|
|
9739
10416
|
#
|
|
9740
10417
|
|
|
@@ -9752,24 +10429,53 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
9752
10429
|
|
|
9753
10430
|
@ta.final
|
|
9754
10431
|
def critical(self, *args, **kwargs):
|
|
9755
|
-
return self._log(
|
|
10432
|
+
return self._log(
|
|
10433
|
+
CaptureLoggingContextImpl(
|
|
10434
|
+
NamedLogLevel.CRITICAL,
|
|
10435
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
10436
|
+
),
|
|
10437
|
+
*args,
|
|
10438
|
+
**kwargs,
|
|
10439
|
+
)
|
|
9756
10440
|
|
|
9757
10441
|
##
|
|
9758
10442
|
|
|
9759
10443
|
@abc.abstractmethod
|
|
9760
|
-
def _log(
|
|
10444
|
+
def _log(
|
|
10445
|
+
self,
|
|
10446
|
+
ctx: CaptureLoggingContext,
|
|
10447
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10448
|
+
*args: ta.Any,
|
|
10449
|
+
**kwargs: ta.Any,
|
|
10450
|
+
) -> T:
|
|
9761
10451
|
raise NotImplementedError
|
|
9762
10452
|
|
|
9763
10453
|
|
|
9764
10454
|
class Logger(AnyLogger[None], Abstract):
|
|
10455
|
+
_level_proxy_method_stack_offset: int = 1
|
|
10456
|
+
|
|
9765
10457
|
@abc.abstractmethod
|
|
9766
|
-
def _log(
|
|
10458
|
+
def _log(
|
|
10459
|
+
self,
|
|
10460
|
+
ctx: CaptureLoggingContext,
|
|
10461
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10462
|
+
*args: ta.Any,
|
|
10463
|
+
**kwargs: ta.Any,
|
|
10464
|
+
) -> None:
|
|
9767
10465
|
raise NotImplementedError
|
|
9768
10466
|
|
|
9769
10467
|
|
|
9770
10468
|
class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
|
|
10469
|
+
_level_proxy_method_stack_offset: int = 0
|
|
10470
|
+
|
|
9771
10471
|
@abc.abstractmethod
|
|
9772
|
-
def _log(
|
|
10472
|
+
def _log(
|
|
10473
|
+
self,
|
|
10474
|
+
ctx: CaptureLoggingContext,
|
|
10475
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10476
|
+
*args: ta.Any,
|
|
10477
|
+
**kwargs: ta.Any,
|
|
10478
|
+
) -> ta.Awaitable[None]:
|
|
9773
10479
|
raise NotImplementedError
|
|
9774
10480
|
|
|
9775
10481
|
|
|
@@ -9784,13 +10490,25 @@ class AnyNopLogger(AnyLogger[T], Abstract):
|
|
|
9784
10490
|
|
|
9785
10491
|
@ta.final
|
|
9786
10492
|
class NopLogger(AnyNopLogger[None], Logger):
|
|
9787
|
-
def _log(
|
|
10493
|
+
def _log(
|
|
10494
|
+
self,
|
|
10495
|
+
ctx: CaptureLoggingContext,
|
|
10496
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10497
|
+
*args: ta.Any,
|
|
10498
|
+
**kwargs: ta.Any,
|
|
10499
|
+
) -> None:
|
|
9788
10500
|
pass
|
|
9789
10501
|
|
|
9790
10502
|
|
|
9791
10503
|
@ta.final
|
|
9792
10504
|
class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
|
|
9793
|
-
async def _log(
|
|
10505
|
+
async def _log(
|
|
10506
|
+
self,
|
|
10507
|
+
ctx: CaptureLoggingContext,
|
|
10508
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
10509
|
+
*args: ta.Any,
|
|
10510
|
+
**kwargs: ta.Any,
|
|
10511
|
+
) -> None:
|
|
9794
10512
|
pass
|
|
9795
10513
|
|
|
9796
10514
|
|
|
@@ -10603,7 +11321,7 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
|
|
|
10603
11321
|
*,
|
|
10604
11322
|
read_size: int = 0x10000,
|
|
10605
11323
|
write_size: int = 0x10000,
|
|
10606
|
-
log_handler: ta.Optional[ta.Callable[[CoroHttpServer,
|
|
11324
|
+
log_handler: ta.Optional[ta.Callable[[CoroHttpServer, CoroHttpIo.AnyLogIo], None]] = None,
|
|
10607
11325
|
) -> None:
|
|
10608
11326
|
check.state(not sock.getblocking())
|
|
10609
11327
|
|
|
@@ -10623,13 +11341,13 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
|
|
|
10623
11341
|
)
|
|
10624
11342
|
self._srv_coro: ta.Optional[
|
|
10625
11343
|
ta.Generator[
|
|
10626
|
-
|
|
11344
|
+
CoroHttpIo.Io,
|
|
10627
11345
|
ta.Optional[bytes],
|
|
10628
11346
|
CoroHttpServer.CoroHandleResult,
|
|
10629
11347
|
],
|
|
10630
11348
|
] = self._coro_srv.coro_handle()
|
|
10631
11349
|
|
|
10632
|
-
self._cur_io: ta.Optional[
|
|
11350
|
+
self._cur_io: ta.Optional[CoroHttpIo.Io] = None
|
|
10633
11351
|
self._next_io()
|
|
10634
11352
|
|
|
10635
11353
|
#
|
|
@@ -10652,22 +11370,22 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
|
|
|
10652
11370
|
o = None
|
|
10653
11371
|
break
|
|
10654
11372
|
|
|
10655
|
-
if isinstance(o,
|
|
11373
|
+
if isinstance(o, CoroHttpIo.AnyLogIo):
|
|
10656
11374
|
if self._log_handler is not None:
|
|
10657
11375
|
self._log_handler(self._coro_srv, o)
|
|
10658
11376
|
o = None
|
|
10659
11377
|
|
|
10660
|
-
elif isinstance(o,
|
|
11378
|
+
elif isinstance(o, CoroHttpIo.ReadIo):
|
|
10661
11379
|
if (d := self._read_buf.read(o.sz)) is None:
|
|
10662
11380
|
break
|
|
10663
11381
|
o = None
|
|
10664
11382
|
|
|
10665
|
-
elif isinstance(o,
|
|
11383
|
+
elif isinstance(o, CoroHttpIo.ReadLineIo):
|
|
10666
11384
|
if (d := self._read_buf.read_until(b'\n')) is None:
|
|
10667
11385
|
break
|
|
10668
11386
|
o = None
|
|
10669
11387
|
|
|
10670
|
-
elif isinstance(o,
|
|
11388
|
+
elif isinstance(o, CoroHttpIo.WriteIo):
|
|
10671
11389
|
check.none(self._write_buf)
|
|
10672
11390
|
self._write_buf = IncrementalWriteBuffer(o.data, write_size=self._write_size)
|
|
10673
11391
|
break
|
|
@@ -10701,11 +11419,11 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
|
|
|
10701
11419
|
|
|
10702
11420
|
self._read_buf.feed(buf)
|
|
10703
11421
|
|
|
10704
|
-
if isinstance(self._cur_io,
|
|
11422
|
+
if isinstance(self._cur_io, CoroHttpIo.AnyReadIo):
|
|
10705
11423
|
self._next_io()
|
|
10706
11424
|
|
|
10707
11425
|
def on_writable(self) -> None:
|
|
10708
|
-
check.isinstance(self._cur_io,
|
|
11426
|
+
check.isinstance(self._cur_io, CoroHttpIo.WriteIo)
|
|
10709
11427
|
wb = check.not_none(self._write_buf)
|
|
10710
11428
|
while wb.rem > 0:
|
|
10711
11429
|
def send(d: bytes) -> int:
|
|
@@ -10725,6 +11443,70 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
|
|
|
10725
11443
|
self._next_io()
|
|
10726
11444
|
|
|
10727
11445
|
|
|
11446
|
+
########################################
|
|
11447
|
+
# ../../../omlish/logs/asyncs.py
|
|
11448
|
+
|
|
11449
|
+
|
|
11450
|
+
##
|
|
11451
|
+
|
|
11452
|
+
|
|
11453
|
+
class AsyncLoggerToLogger(Logger):
|
|
11454
|
+
def __init__(self, u: AsyncLogger) -> None:
|
|
11455
|
+
super().__init__()
|
|
11456
|
+
|
|
11457
|
+
self._u = u
|
|
11458
|
+
|
|
11459
|
+
def get_effective_level(self) -> LogLevel:
|
|
11460
|
+
return self._u.get_effective_level()
|
|
11461
|
+
|
|
11462
|
+
def _log(
|
|
11463
|
+
self,
|
|
11464
|
+
ctx: CaptureLoggingContext,
|
|
11465
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
11466
|
+
*args: ta.Any,
|
|
11467
|
+
**kwargs: ta.Any,
|
|
11468
|
+
) -> None:
|
|
11469
|
+
# Nope out early to avoid sync_await if possible - don't bother in the LoggerToAsyncLogger.
|
|
11470
|
+
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
11471
|
+
return
|
|
11472
|
+
|
|
11473
|
+
# Note: we hardcode the stack offset of sync_await (which is 2 - sync_await + sync_await.thunk). In non-lite
|
|
11474
|
+
# code, lang.sync_await uses a cext if present to avoid being on the py stack, which would obviously complicate
|
|
11475
|
+
# this, but this is lite code so we will always have the non-c version.
|
|
11476
|
+
sync_await(
|
|
11477
|
+
self._u._log( # noqa
|
|
11478
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(3),
|
|
11479
|
+
msg,
|
|
11480
|
+
*args,
|
|
11481
|
+
**kwargs,
|
|
11482
|
+
),
|
|
11483
|
+
)
|
|
11484
|
+
|
|
11485
|
+
|
|
11486
|
+
class LoggerToAsyncLogger(AsyncLogger):
|
|
11487
|
+
def __init__(self, u: Logger) -> None:
|
|
11488
|
+
super().__init__()
|
|
11489
|
+
|
|
11490
|
+
self._u = u
|
|
11491
|
+
|
|
11492
|
+
def get_effective_level(self) -> LogLevel:
|
|
11493
|
+
return self._u.get_effective_level()
|
|
11494
|
+
|
|
11495
|
+
async def _log(
|
|
11496
|
+
self,
|
|
11497
|
+
ctx: CaptureLoggingContext,
|
|
11498
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
11499
|
+
*args: ta.Any,
|
|
11500
|
+
**kwargs: ta.Any,
|
|
11501
|
+
) -> None:
|
|
11502
|
+
return self._u._log( # noqa
|
|
11503
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(),
|
|
11504
|
+
msg,
|
|
11505
|
+
*args,
|
|
11506
|
+
**kwargs,
|
|
11507
|
+
)
|
|
11508
|
+
|
|
11509
|
+
|
|
10728
11510
|
########################################
|
|
10729
11511
|
# ../../../omlish/logs/std/loggers.py
|
|
10730
11512
|
|
|
@@ -10748,7 +11530,12 @@ class StdLogger(Logger):
|
|
|
10748
11530
|
def get_effective_level(self) -> LogLevel:
|
|
10749
11531
|
return self._std.getEffectiveLevel()
|
|
10750
11532
|
|
|
10751
|
-
def _log(
|
|
11533
|
+
def _log(
|
|
11534
|
+
self,
|
|
11535
|
+
ctx: CaptureLoggingContext,
|
|
11536
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
11537
|
+
*args: ta.Any,
|
|
11538
|
+
) -> None:
|
|
10752
11539
|
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
10753
11540
|
return
|
|
10754
11541
|
|
|
@@ -10893,8 +11680,23 @@ class ProcessSpawning:
|
|
|
10893
11680
|
##
|
|
10894
11681
|
|
|
10895
11682
|
|
|
11683
|
+
def _get_module_std_logger(mod_globals: ta.Mapping[str, ta.Any]) -> logging.Logger:
|
|
11684
|
+
return logging.getLogger(mod_globals.get('__name__'))
|
|
11685
|
+
|
|
11686
|
+
|
|
10896
11687
|
def get_module_logger(mod_globals: ta.Mapping[str, ta.Any]) -> Logger:
|
|
10897
|
-
return StdLogger(
|
|
11688
|
+
return StdLogger(_get_module_std_logger(mod_globals))
|
|
11689
|
+
|
|
11690
|
+
|
|
11691
|
+
def get_module_async_logger(mod_globals: ta.Mapping[str, ta.Any]) -> AsyncLogger:
|
|
11692
|
+
return LoggerToAsyncLogger(get_module_logger(mod_globals))
|
|
11693
|
+
|
|
11694
|
+
|
|
11695
|
+
def get_module_loggers(mod_globals: ta.Mapping[str, ta.Any]) -> ta.Tuple[Logger, AsyncLogger]:
|
|
11696
|
+
return (
|
|
11697
|
+
log := get_module_logger(mod_globals),
|
|
11698
|
+
LoggerToAsyncLogger(log),
|
|
11699
|
+
)
|
|
10898
11700
|
|
|
10899
11701
|
|
|
10900
11702
|
########################################
|