omlish 0.0.0.dev223__py3-none-any.whl → 0.0.0.dev224__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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,,