omlish 0.0.0.dev223__py3-none-any.whl → 0.0.0.dev224__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.
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev223'
2
- __revision__ = '383167fabe843d406905492267a5c570dae7cba3'
1
+ __version__ = '0.0.0.dev224'
2
+ __revision__ = '0980d15b9ba0f06f68cf7bdb68fbc8626696075f'
3
3
 
4
4
 
5
5
  #
omlish/http/handlers.py CHANGED
@@ -63,14 +63,65 @@ class HttpHandler_(abc.ABC): # noqa
63
63
  raise NotImplementedError
64
64
 
65
65
 
66
+ ##
67
+
68
+
66
69
  @dc.dataclass(frozen=True)
67
70
  class LoggingHttpHandler(HttpHandler_):
68
71
  handler: HttpHandler
69
72
  log: logging.Logger
70
- level: int = logging.INFO
73
+ level: int = logging.DEBUG
71
74
 
72
75
  def __call__(self, req: HttpHandlerRequest) -> HttpHandlerResponse:
73
76
  self.log.log(self.level, '%r', req)
74
77
  resp = self.handler(req)
75
78
  self.log.log(self.level, '%r', resp)
76
79
  return resp
80
+
81
+
82
+ ##
83
+
84
+
85
+ @dc.dataclass(frozen=True)
86
+ class BytesResponseHttpHandler(HttpHandler_):
87
+ data: bytes
88
+
89
+ status: ta.Union[http.HTTPStatus, int] = 200
90
+ content_type: ta.Optional[str] = 'application/octet-stream'
91
+ headers: ta.Optional[ta.Mapping[str, str]] = None
92
+ close_connection: bool = True
93
+
94
+ def __call__(self, req: HttpHandlerRequest) -> HttpHandlerResponse:
95
+ return HttpHandlerResponse(
96
+ status=self.status,
97
+ headers={
98
+ **({'Content-Type': self.content_type} if self.content_type else {}),
99
+ 'Content-Length': str(len(self.data)),
100
+ **(self.headers or {}),
101
+ },
102
+ data=self.data,
103
+ close_connection=self.close_connection,
104
+ )
105
+
106
+
107
+ @dc.dataclass(frozen=True)
108
+ class StringResponseHttpHandler(HttpHandler_):
109
+ data: str
110
+
111
+ status: ta.Union[http.HTTPStatus, int] = 200
112
+ content_type: ta.Optional[str] = 'text/plain; charset=utf-8'
113
+ headers: ta.Optional[ta.Mapping[str, str]] = None
114
+ close_connection: bool = True
115
+
116
+ def __call__(self, req: HttpHandlerRequest) -> HttpHandlerResponse:
117
+ data = self.data.encode('utf-8')
118
+ return HttpHandlerResponse(
119
+ status=self.status,
120
+ headers={
121
+ **({'Content-Type': self.content_type} if self.content_type else {}),
122
+ 'Content-Length': str(len(data)),
123
+ **(self.headers or {}),
124
+ },
125
+ data=data,
126
+ close_connection=self.close_connection,
127
+ )
omlish/lite/timing.py ADDED
@@ -0,0 +1,8 @@
1
+ from ..logs.timing import LogTimingContext
2
+ from ..logs.timing import log_timing_context
3
+ from .logs import log
4
+
5
+
6
+ LogTimingContext.DEFAULT_LOG = log
7
+
8
+ log_timing_context = log_timing_context # noqa
omlish/logs/timing.py ADDED
@@ -0,0 +1,58 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import logging
4
+ import time
5
+ import typing as ta
6
+
7
+
8
+ ##
9
+
10
+
11
+ class LogTimingContext:
12
+ DEFAULT_LOG: ta.ClassVar[ta.Optional[logging.Logger]] = None
13
+
14
+ class _NOT_SPECIFIED: # noqa
15
+ def __new__(cls, *args, **kwargs): # noqa
16
+ raise TypeError
17
+
18
+ def __init__(
19
+ self,
20
+ description: str,
21
+ *,
22
+ log: ta.Union[logging.Logger, ta.Type[_NOT_SPECIFIED], None] = _NOT_SPECIFIED, # noqa
23
+ level: int = logging.DEBUG,
24
+ ) -> None:
25
+ super().__init__()
26
+
27
+ self._description = description
28
+ if log is self._NOT_SPECIFIED:
29
+ log = self.DEFAULT_LOG # noqa
30
+ self._log: ta.Optional[logging.Logger] = log # type: ignore
31
+ self._level = level
32
+
33
+ def set_description(self, description: str) -> 'LogTimingContext':
34
+ self._description = description
35
+ return self
36
+
37
+ _begin_time: float
38
+ _end_time: float
39
+
40
+ def __enter__(self) -> 'LogTimingContext':
41
+ self._begin_time = time.time()
42
+
43
+ if self._log is not None:
44
+ self._log.log(self._level, f'Begin : {self._description}') # noqa
45
+
46
+ return self
47
+
48
+ def __exit__(self, exc_type, exc_val, exc_tb):
49
+ self._end_time = time.time()
50
+
51
+ if self._log is not None:
52
+ self._log.log(
53
+ self._level,
54
+ f'End : {self._description} - {self._end_time - self._begin_time:0.2f} s elapsed',
55
+ )
56
+
57
+
58
+ log_timing_context = LogTimingContext
omlish/secrets/tempssl.py CHANGED
@@ -1,10 +1,14 @@
1
1
  # @omlish-lite
2
2
  # ruff: noqa: UP006 UP007
3
+ import dataclasses as dc
3
4
  import os.path
4
- import subprocess
5
5
  import tempfile
6
6
  import typing as ta
7
7
 
8
+ from ..lite.cached import cached_nullary
9
+ from ..subprocesses import SubprocessRun
10
+ from ..subprocesses import SubprocessRunOutput
11
+ from ..subprocesses import subprocesses
8
12
  from .ssl import SslCert
9
13
 
10
14
 
@@ -13,11 +17,15 @@ class TempSslCert(ta.NamedTuple):
13
17
  temp_dir: str
14
18
 
15
19
 
16
- def generate_temp_localhost_ssl_cert() -> TempSslCert:
17
- temp_dir = tempfile.mkdtemp()
20
+ @dc.dataclass(frozen=True)
21
+ class TempSslCertGenerator:
22
+ @cached_nullary
23
+ def temp_dir(self) -> str:
24
+ return tempfile.mkdtemp()
18
25
 
19
- proc = subprocess.run(
20
- [
26
+ @cached_nullary
27
+ def make_run(self) -> SubprocessRun:
28
+ return SubprocessRun.of(
21
29
  'openssl',
22
30
  'req',
23
31
  '-x509',
@@ -32,19 +40,33 @@ def generate_temp_localhost_ssl_cert() -> TempSslCert:
32
40
 
33
41
  '-subj', '/CN=localhost',
34
42
  '-addext', 'subjectAltName = DNS:localhost,IP:127.0.0.1',
35
- ],
36
- cwd=temp_dir,
37
- capture_output=True,
38
- check=False,
39
- )
40
-
41
- if proc.returncode:
42
- raise RuntimeError(f'Failed to generate temp ssl cert: {proc.stderr=}')
43
-
44
- return TempSslCert(
45
- SslCert(
46
- key_file=os.path.join(temp_dir, 'key.pem'),
47
- cert_file=os.path.join(temp_dir, 'cert.pem'),
48
- ),
49
- temp_dir,
50
- )
43
+
44
+ cwd=self.temp_dir(),
45
+ capture_output=True,
46
+ check=False,
47
+ )
48
+
49
+ def handle_run_output(self, proc: SubprocessRunOutput) -> TempSslCert:
50
+ if proc.returncode:
51
+ raise RuntimeError(f'Failed to generate temp ssl cert: {proc.stderr=}')
52
+
53
+ key_file = os.path.join(self.temp_dir(), 'key.pem')
54
+ cert_file = os.path.join(self.temp_dir(), 'cert.pem')
55
+ for file in [key_file, cert_file]:
56
+ if not os.path.isfile(file):
57
+ raise RuntimeError(f'Failed to generate temp ssl cert (file not found): {file}')
58
+
59
+ return TempSslCert(
60
+ SslCert(
61
+ key_file=key_file,
62
+ cert_file=cert_file,
63
+ ),
64
+ temp_dir=self.temp_dir(),
65
+ )
66
+
67
+ def run(self) -> TempSslCert:
68
+ return self.handle_run_output(subprocesses.run_(self.make_run()))
69
+
70
+
71
+ def generate_temp_localhost_ssl_cert() -> TempSslCert:
72
+ return TempSslCertGenerator().run()
omlish/subprocesses.py CHANGED
@@ -265,6 +265,25 @@ class SubprocessRun:
265
265
  capture_output: ta.Optional[bool] = None
266
266
  kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
267
267
 
268
+ @classmethod
269
+ def of(
270
+ cls,
271
+ *cmd: str,
272
+ input: ta.Any = None, # noqa
273
+ timeout: ta.Optional[float] = None,
274
+ check: bool = False,
275
+ capture_output: ta.Optional[bool] = None,
276
+ **kwargs: ta.Any,
277
+ ) -> 'SubprocessRun':
278
+ return cls(
279
+ cmd=cmd,
280
+ input=input,
281
+ timeout=timeout,
282
+ check=check,
283
+ capture_output=capture_output,
284
+ kwargs=kwargs,
285
+ )
286
+
268
287
 
269
288
  @dc.dataclass(frozen=True)
270
289
  class SubprocessRunOutput(ta.Generic[T]):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omlish
3
- Version: 0.0.0.dev223
3
+ Version: 0.0.0.dev224
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=YGmAnUBszmosQQ_7Hh2wwtDiYdYZ4unNKYzOtALuels,7968
2
- omlish/__about__.py,sha256=cfcfKE_bobX_WDE8x_mLyrVgIGJv3TZdMAc3Zrzc3xs,3380
2
+ omlish/__about__.py,sha256=S2Ri9mbwlQ-KusjCoVjZBcGHhAJnlWUTzvhVU8dKD9Q,3380
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=ubu7lHwss5V4UznbejAI0qXhXahrU01MysuHOZI9C4U,8116
5
5
  omlish/cached.py,sha256=UI-XTFBwA6YXWJJJeBn-WkwBkfzDjLBBaZf4nIJA9y0,510
@@ -11,7 +11,7 @@ omlish/libc.py,sha256=8r7Ejyhttk9ruCfBkxNTrlzir5WPbDE2vmY7VPlceMA,15362
11
11
  omlish/outcome.py,sha256=ABIE0zjjTyTNtn-ZqQ_9_mUzLiBQ3sDAyqc9JVD8N2k,7852
12
12
  omlish/runmodule.py,sha256=PWvuAaJ9wQQn6bx9ftEL3_d04DyotNn8dR_twm2pgw0,700
13
13
  omlish/shlex.py,sha256=bsW2XUD8GiMTUTDefJejZ5AyqT1pTgWMPD0BMoF02jE,248
14
- omlish/subprocesses.py,sha256=kI9z5_D8J30BrAKu6FvsCvnIvmWGEMIc3jbGbvmSmFA,12510
14
+ omlish/subprocesses.py,sha256=CKWBnuliVfeIcQjPuIZMMk6uY2bk8LpCW9egMVA059E,13013
15
15
  omlish/sync.py,sha256=QJ79kxmIqDP9SeHDoZAf--DpFIhDQe1jACy8H4N0yZI,2928
16
16
  omlish/algorithm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  omlish/algorithm/all.py,sha256=FudUHwoaRLNNmqYM3jhP2Yd2BpmYhNBRPaVZzARMoSc,194
@@ -304,7 +304,7 @@ omlish/http/consts.py,sha256=7BJ4D1MdIvqBcepkgCfBFHolgTwbOlqsOEiee_IjxOA,2289
304
304
  omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
305
305
  omlish/http/dates.py,sha256=Otgp8wRxPgNGyzx8LFowu1vC4EKJYARCiAwLFncpfHM,2875
306
306
  omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
307
- omlish/http/handlers.py,sha256=QUjS2C3k7SqoL9yaAssfNIvfHYzNtg8Xfpsq2KC7fFU,1839
307
+ omlish/http/handlers.py,sha256=l6JLDuK9XhYvF1IudnPz5hWTZW1dXRjUBSO4Uyck0LE,3365
308
308
  omlish/http/headers.py,sha256=ZMmjrEiYjzo0YTGyK0YsvjdwUazktGqzVVYorY4fd44,5081
309
309
  omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
310
310
  omlish/http/jwt.py,sha256=6Rigk1WrJ059DY4jDIKnxjnChWb7aFdermj2AI2DSvk,4346
@@ -432,6 +432,7 @@ omlish/lite/resources.py,sha256=YNSmX1Ohck1aoWRs55a-o5ChVbFJIQhtbqE-XwF55Oc,326
432
432
  omlish/lite/runtime.py,sha256=XQo408zxTdJdppUZqOWHyeUR50VlCpNIExNGHz4U6O4,459
433
433
  omlish/lite/secrets.py,sha256=3Mz3V2jf__XU9qNHcH56sBSw95L3U2UPL24bjvobG0c,816
434
434
  omlish/lite/strings.py,sha256=QGxT1Yh4oI8ycsfeobxnjEhvDob_GiAKLeIhZwo1j24,1986
435
+ omlish/lite/timing.py,sha256=aVu3hEDB_jyTF_ryZI7iU-xg4q8CNwqpp9Apfru_iwY,196
435
436
  omlish/lite/types.py,sha256=fP5EMyBdEp2LmDxcHjUDtwAMdR06ISr9lKOL7smWfHM,140
436
437
  omlish/lite/typing.py,sha256=U3-JaEnkDSYxK4tsu_MzUn3RP6qALBe5FXQXpD-licE,1090
437
438
  omlish/logs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -447,6 +448,7 @@ omlish/logs/noisy.py,sha256=Ubc-eTH6ZbGYsLfUUi69JAotwuUwzb-SJBeGo_0dIZI,348
447
448
  omlish/logs/protocol.py,sha256=NzyCeNBN-fyKpJinhECfjUQSd5MxZLiYbuLCTtW6QUU,4500
448
449
  omlish/logs/proxy.py,sha256=A-ROPUUAlF397qTbEqhel6YhQMstNuXL3Xmts7w9dAo,2347
449
450
  omlish/logs/standard.py,sha256=FbKdF2Z4Na5i2TNwKn0avLJXyICe2JKsPufjvKCHGn0,3162
451
+ omlish/logs/timing.py,sha256=XrFUHIPT4EHDujLKbGs9fGFMmoM3NEP8xPRaESJr7bQ,1513
450
452
  omlish/logs/utils.py,sha256=mzHrZ9ji75p5A8qR29eUr05CBAHMb8J753MSkID_VaQ,393
451
453
  omlish/manifests/__init__.py,sha256=P2B0dpT8D7l5lJwRGPA92IcQj6oeXfd90X5-q9BJrKg,51
452
454
  omlish/manifests/load.py,sha256=LrWAvBfdzDkFdLuVwfw2RwFvLjxx-rvfkpU9eBsWeIc,5626
@@ -515,7 +517,7 @@ omlish/secrets/pwhash.py,sha256=Goktn-swmC6PXqfRBnDrH_Lr42vjckT712UyErPjzkw,4102
515
517
  omlish/secrets/secrets.py,sha256=QNgOmRcIRK2fx49bIbBBM2rYbe6IhhLgk8fKvq8guoI,7963
516
518
  omlish/secrets/ssl.py,sha256=TvO1BJeCCBPsOLjO-QH7Q0DC-NS8onfmRxbl4ntOnd8,147
517
519
  omlish/secrets/subprocesses.py,sha256=ffjfbgPbEE_Pwb_87vG4yYR2CGZy3I31mHNCo_0JtHw,1212
518
- omlish/secrets/tempssl.py,sha256=8yFLb3Q19zVtciFZL7LEeK1LIXaYxvtSaxZX2L13Xx8,1048
520
+ omlish/secrets/tempssl.py,sha256=pAmTRFgR23pFRUAIzJrxeJg4JbYFvaVcEtWtvSYyxHw,1932
519
521
  omlish/sockets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
520
522
  omlish/sockets/addresses.py,sha256=vbVeQBkzI513H4vRv-JS89QtRbr9U8v5zqkm3oODl_s,1869
521
523
  omlish/sockets/bind.py,sha256=TnG5nm0pnuMxRA02TG2W40RbutrPA6tkOJtbZvBjDWU,8063
@@ -665,9 +667,9 @@ omlish/text/indent.py,sha256=YjtJEBYWuk8--b9JU_T6q4yxV85_TR7VEVr5ViRCFwk,1336
665
667
  omlish/text/minja.py,sha256=jZC-fp3Xuhx48ppqsf2Sf1pHbC0t8XBB7UpUUoOk2Qw,5751
666
668
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
667
669
  omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
668
- omlish-0.0.0.dev223.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
669
- omlish-0.0.0.dev223.dist-info/METADATA,sha256=fmmzRE5W14ixJfioXsdtMRVBzze_mKcI_1ZFfKDVQ34,4176
670
- omlish-0.0.0.dev223.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
671
- omlish-0.0.0.dev223.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
672
- omlish-0.0.0.dev223.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
673
- omlish-0.0.0.dev223.dist-info/RECORD,,
670
+ omlish-0.0.0.dev224.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
671
+ omlish-0.0.0.dev224.dist-info/METADATA,sha256=mQhHJnChb7Igih2af4khc6lOSNpkVqyv8j2xaVk0IpQ,4176
672
+ omlish-0.0.0.dev224.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
673
+ omlish-0.0.0.dev224.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
674
+ omlish-0.0.0.dev224.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
675
+ omlish-0.0.0.dev224.dist-info/RECORD,,