omlish 0.0.0.dev290__py3-none-any.whl → 0.0.0.dev292__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.dev290'
2
- __revision__ = 'ebbb2a4babf1f763c1caf685dbe12bcde2fa251f'
1
+ __version__ = '0.0.0.dev292'
2
+ __revision__ = '049add36e73b2356410aa68bca39c19cff8047d2'
3
3
 
4
4
 
5
5
  #
@@ -16,12 +16,14 @@ from .impls import get_impl_func_cls_set
16
16
 
17
17
 
18
18
  T = ta.TypeVar('T')
19
+ R = ta.TypeVar('R')
20
+ P = ta.ParamSpec('P')
19
21
 
20
22
 
21
23
  ##
22
24
 
23
25
 
24
- class Method:
26
+ class Method(ta.Generic[P, R]):
25
27
  def __init__(
26
28
  self,
27
29
  func: ta.Callable,
@@ -170,13 +172,27 @@ class Method:
170
172
  func = self.get_dispatch_func(instance_cls)
171
173
  return func.__get__(instance, owner) # noqa
172
174
 
173
- def __call__(self, instance, *args, **kwargs):
175
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
176
+ instance, *rest = args
174
177
  instance_cls = type(instance)
175
178
  try:
176
179
  func = self._dispatch_func_cache[weakref.ref(instance_cls)]
177
180
  except KeyError:
178
181
  func = self.get_dispatch_func(instance_cls)
179
- return func.__get__(instance)(*args, **kwargs) # noqa
182
+ return func.__get__(instance)(*rest, **kwargs) # noqa
183
+
184
+
185
+ ##
186
+
187
+
188
+ @ta.overload
189
+ def method(func: ta.Callable[P, R], /, *, installable: bool = False) -> Method[P, R]: # noqa
190
+ ...
191
+
192
+
193
+ @ta.overload
194
+ def method(func: None = None, /, *, installable: bool = False) -> ta.Callable[[ta.Callable[P, R]], Method[P, R]]: # noqa
195
+ ...
180
196
 
181
197
 
182
198
  def method(func=None, /, *, installable=False): # noqa
@@ -186,6 +202,9 @@ def method(func=None, /, *, installable=False): # noqa
186
202
  return Method(func, **kw)
187
203
 
188
204
 
205
+ #
206
+
207
+
189
208
  def install_method(
190
209
  mth: ta.Any,
191
210
  *,
omlish/lang/__init__.py CHANGED
@@ -96,12 +96,10 @@ from .contextmanagers import ( # noqa
96
96
  NOP_CONTEXT_MANAGER,
97
97
  NopContextManager,
98
98
  Timer,
99
- a_defer,
100
99
  breakpoint_on_exception,
101
100
  context_var_setting,
102
101
  context_wrapped,
103
102
  default_lock,
104
- defer,
105
103
  disposing,
106
104
  maybe_managing,
107
105
  )
@@ -296,9 +294,11 @@ from .typing import ( # noqa
296
294
  ##
297
295
 
298
296
  from ..lite.contextmanagers import ( # noqa
299
- attr_setting,
300
297
  AsyncExitStacked,
301
298
  ExitStacked,
299
+ adefer,
300
+ attr_setting,
301
+ defer,
302
302
  )
303
303
 
304
304
  from ..lite.imports import ( # noqa
@@ -119,22 +119,6 @@ class AsyncContextManager(abc.ABC, ta.Generic[T]):
119
119
  ##
120
120
 
121
121
 
122
- @contextlib.contextmanager
123
- def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
124
- try:
125
- yield fn
126
- finally:
127
- fn()
128
-
129
-
130
- @contextlib.asynccontextmanager
131
- async def a_defer(fn: ta.Awaitable) -> ta.AsyncGenerator[ta.Awaitable, None]:
132
- try:
133
- yield fn
134
- finally:
135
- await fn
136
-
137
-
138
122
  @contextlib.contextmanager
139
123
  def maybe_managing(obj: T) -> ta.Iterator[T]:
140
124
  if isinstance(obj, ta.ContextManager):
@@ -1,5 +1,6 @@
1
1
  # ruff: noqa: UP007
2
2
  import contextlib
3
+ import functools
3
4
  import sys
4
5
  import typing as ta
5
6
 
@@ -146,7 +147,9 @@ class AsyncExitStacked:
146
147
 
147
148
 
148
149
  @contextlib.contextmanager
149
- def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
150
+ def defer(fn: ta.Callable, *args: ta.Any, **kwargs: ta.Any) -> ta.Generator[ta.Callable, None, None]:
151
+ if args or kwargs:
152
+ fn = functools.partial(fn, *args, **kwargs)
150
153
  try:
151
154
  yield fn
152
155
  finally:
@@ -154,11 +157,11 @@ def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
154
157
 
155
158
 
156
159
  @contextlib.asynccontextmanager
157
- async def adefer(fn: ta.Callable) -> ta.AsyncGenerator[ta.Callable, None]:
160
+ async def adefer(fn: ta.Awaitable) -> ta.AsyncGenerator[ta.Awaitable, None]:
158
161
  try:
159
162
  yield fn
160
163
  finally:
161
- await fn()
164
+ await fn
162
165
 
163
166
 
164
167
  ##
@@ -0,0 +1,97 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import dataclasses as dc
4
+ import os
5
+ import tempfile
6
+ import typing as ta
7
+
8
+ from ..lite.cached import cached_nullary
9
+ from ..lite.contextmanagers import ExitStacked
10
+ from ..lite.contextmanagers import defer
11
+ from .run import SubprocessRun
12
+ from .run import SubprocessRunnable
13
+ from .run import SubprocessRunOutput
14
+
15
+
16
+ ##
17
+
18
+
19
+ class EditTextWithUserEditor(SubprocessRunnable, ExitStacked):
20
+ def __init__(self, initial_text: str = '') -> None:
21
+ super().__init__()
22
+
23
+ self._initial_text = initial_text
24
+
25
+ @dc.dataclass(frozen=True)
26
+ class _TempFile:
27
+ path: str
28
+ before_mtime: float
29
+
30
+ @cached_nullary
31
+ def _temp_file(self) -> _TempFile:
32
+ with tempfile.NamedTemporaryFile(
33
+ mode='r+',
34
+ delete=False,
35
+ ) as ntf:
36
+ ntf.write(self._initial_text)
37
+ ntf.flush()
38
+ before_mtime = os.stat(ntf.name).st_mtime
39
+
40
+ self._enter_context(defer(os.unlink, ntf.name)) # noqa
41
+
42
+ return EditTextWithUserEditor._TempFile(
43
+ ntf.name,
44
+ before_mtime,
45
+ )
46
+
47
+ def make_run(self) -> SubprocessRun:
48
+ tf = self._temp_file()
49
+
50
+ editor = os.environ.get('EDITOR', 'vi')
51
+
52
+ return SubprocessRun.of(
53
+ editor,
54
+ tf.path,
55
+ )
56
+
57
+ def handle_run_output(self, output: SubprocessRunOutput) -> ta.Optional[str]:
58
+ tf = self._temp_file()
59
+
60
+ if output.returncode != 0:
61
+ return None
62
+
63
+ after_mtime = os.stat(tf.path).st_mtime
64
+
65
+ if after_mtime == tf.before_mtime:
66
+ # No changes made; assuming cancel.
67
+ return None
68
+
69
+ with open(tf.path) as f:
70
+ content = f.read().strip()
71
+ if not content:
72
+ # Empty file; assuming cancel.
73
+ return None
74
+
75
+ return content
76
+
77
+
78
+ def edit_text_with_user_editor(
79
+ initial_text: str = '',
80
+ subprocesses: ta.Optional[ta.Any] = None, # AbstractSubprocesses
81
+ ) -> ta.Optional[str]:
82
+ with EditTextWithUserEditor(initial_text) as cmd:
83
+ return cmd.run(subprocesses)
84
+
85
+
86
+ ##
87
+
88
+
89
+ if __name__ == '__main__':
90
+ def _main() -> None:
91
+ text = edit_text_with_user_editor('# Write your message here.\n')
92
+ if text is not None:
93
+ print('User submitted:\n', text)
94
+ else:
95
+ print('Operation canceled.')
96
+
97
+ _main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev290
3
+ Version: 0.0.0.dev292
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=pjGUyLHaoWpPqRP3jz2u1fC1qoRc2lvrEcpU_Ax2tdg,8253
2
- omlish/__about__.py,sha256=oeR_9krsJobU57yaBP1YUrwkXI9RXjfl3IONZ25CSmw,3444
2
+ omlish/__about__.py,sha256=35DcIUR8xZ1fV59-t4ejDVrAHFLqGSDxuBoLBDriBvA,3444
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=rer-TPOFDU6fYq_AWio_AmA-ckZ8JDY5shIzQ_yXfzA,8414
5
5
  omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
@@ -292,7 +292,7 @@ omlish/dispatch/_dispatch3.py,sha256=9Zjd7bINAC3keiaBdssc4v5dY0-8OI6XooV2DR9U7Z0
292
292
  omlish/dispatch/dispatch.py,sha256=KA5l49AiGLRjp4J7RDJW9RiDp9WUD1ewR1AOPEF8g38,3062
293
293
  omlish/dispatch/functions.py,sha256=cwNzGIg2ZIalEgn9I03cnJVbMTHjWloyDTaowlO3UPs,1524
294
294
  omlish/dispatch/impls.py,sha256=K_okKvpZml4NkTHJmTVyMQSrIaIJcqTEgkreGwukaOw,1895
295
- omlish/dispatch/methods.py,sha256=K5w9Bb4jjCEpz3H95VMsv8ITXSO_7F6Jp5K5Fcd4gjQ,6955
295
+ omlish/dispatch/methods.py,sha256=CeGVwiUdeadzyOe0xQVY_jegyj0tdHLQZpaIlLkJNnY,7330
296
296
  omlish/docker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
297
297
  omlish/docker/all.py,sha256=xXRgJgLGPwAtr7bDMJ_Dp9jTfOwfGvohNhc6LsoELJc,514
298
298
  omlish/docker/cli.py,sha256=gtb9kitVfGnd4cr587NsVVk8D5Ok5y5SAsqD_SwGrSA,2565
@@ -460,12 +460,12 @@ omlish/iterators/iterators.py,sha256=RxW35yQ5ed8vBQ22IqpDXFx-i5JiLQdp7-pkMZXhJJ8
460
460
  omlish/iterators/recipes.py,sha256=wOwOZg-zWG9Zc3wcAxJFSe2rtavVBYwZOfG09qYEx_4,472
461
461
  omlish/iterators/tools.py,sha256=c4hArZEVV8y9_dFfmRwakusv1cWJLT4MkTkGRjnGN5U,2556
462
462
  omlish/iterators/unique.py,sha256=Nw0pSaNEcHAkve0ugfLPvJcirDOn9ECyC5wIL8JlJKI,1395
463
- omlish/lang/__init__.py,sha256=hv6BlnJfD7gHFyOGXl1lgbo3vHkmsivqy462JwA04tM,5316
463
+ omlish/lang/__init__.py,sha256=KCzbT9IMWi2TNldAlDZ6b8Rr-7hyV9Ne6kIKJLXNAxg,5315
464
464
  omlish/lang/attrs.py,sha256=i7euRF81uNF8QDmUVXSK_BtqLGshaMi4VVdUnMjiMwg,5050
465
465
  omlish/lang/clsdct.py,sha256=HAGIvBSbCefzRjXriwYSBLO7QHKRv2UsE78jixOb-fA,1828
466
466
  omlish/lang/collections.py,sha256=aGi0j6VzVe2nz4l357Y4RD5_XNl8OJbmM5qM6BclrrY,1895
467
467
  omlish/lang/comparison.py,sha256=MOwEG0Yny-jBPHO9kQto9FSRyeNpQW24UABsghkrHxY,1356
468
- omlish/lang/contextmanagers.py,sha256=UPH6daYwSP9cH5AfSVsJyEHk1UURMGhVPM5ZRhp_Hvw,7576
468
+ omlish/lang/contextmanagers.py,sha256=pN8X4ZCagqU9_xWumi8gZPdMIWlInA-_zQrkl7o5VP0,7258
469
469
  omlish/lang/datetimes.py,sha256=mrTtA67JYpfQwSlzdPcBtvm6dAyYM_dXNnlxFwFQH0M,228
470
470
  omlish/lang/descriptors.py,sha256=zBtgO9LjdSTGHNUgiIqswh78WOVoGH6KzS0NbgB1Wls,6572
471
471
  omlish/lang/enums.py,sha256=F9tflHfaAoV2MpyuhZzpfX9-H55M3zNa9hCszsngEo8,111
@@ -502,7 +502,7 @@ omlish/lite/__init__.py,sha256=ISLhM4q0LR1XXTCaHdZOZxBRyIsoZqYm4u0bf1BPcVk,148
502
502
  omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
503
503
  omlish/lite/check.py,sha256=OLwtE2x6nlbGx4vS3Rda7zMHpgqzDSLJminTAX2lqLA,13529
504
504
  omlish/lite/configs.py,sha256=Ev_19sbII67pTWzInYjYqa9VyTiZBvyjhZqyG8TtufE,908
505
- omlish/lite/contextmanagers.py,sha256=XSCwr9GpPBJxXR9Vr07M4A_BH3uLpZettyoSE5KqJu8,5566
505
+ omlish/lite/contextmanagers.py,sha256=WrL2NPT7OA5JvHp4H-opwsCpYTHod27EJ4qB1cJ9Mjc,5691
506
506
  omlish/lite/dataclasses.py,sha256=t1G5-xOuvE6o6w9RyqHzLT9wHD0HkqBh5P8HUZWxGzs,1912
507
507
  omlish/lite/imports.py,sha256=o9WWrNrWg0hKeMvaj91giaovED_9VFanN2MyEHBGekY,1346
508
508
  omlish/lite/inject.py,sha256=-tTsOqqef-Ix5Tgl2DP_JAsNWJQDFUptERl3lk14Uzs,29007
@@ -769,6 +769,7 @@ omlish/sql/tabledefs/tabledefs.py,sha256=lIhvlt0pk6G7RZAtDFsFXm5j0l9BvRfnP7vNGey
769
769
  omlish/subprocesses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
770
770
  omlish/subprocesses/async_.py,sha256=hPQTWFa3k5CE_s9p1JTY4KdTPOsqLJtq3lGMRznrVpY,2373
771
771
  omlish/subprocesses/base.py,sha256=W6El-PUKKF9KLAks5LB6kzqs_n3FfkblJ-JOv6NFQbY,6133
772
+ omlish/subprocesses/editor.py,sha256=nLrudPayAZxv0u5LtZFecR_zdSEk0bd8G3XFjbOD81M,2386
772
773
  omlish/subprocesses/run.py,sha256=3jwSnQJvFMDMHmJvtAkrrK5D-i7_8cw12vX84EWTuJo,3668
773
774
  omlish/subprocesses/sync.py,sha256=HKmKM99_Y7tkJRg_n5onXrw41IZt5M5fqU0281LY-mo,3671
774
775
  omlish/subprocesses/utils.py,sha256=MJb6hvKhZceTmBeFVqlc5oM7rDxWkUzSzK9nKvbIvM8,396
@@ -831,9 +832,9 @@ omlish/typedvalues/holder.py,sha256=4SwRezsmuDDEO5gENGx8kTm30pblF5UktoEAu02i-Gk,
831
832
  omlish/typedvalues/marshal.py,sha256=Rr-4DZ90BoD5Z9gT18QhZH2yMA3-gPJBK8GUrGkp8VA,4245
832
833
  omlish/typedvalues/reflect.py,sha256=y_7IY8_4cLVRvD3ug-_-cDaO5RtzC1rLVFzkeAPALf8,683
833
834
  omlish/typedvalues/values.py,sha256=Q_5IiQM3Vka4wGVd-scaslb4-oCMjFcIOksIrKE-JIM,1229
834
- omlish-0.0.0.dev290.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
835
- omlish-0.0.0.dev290.dist-info/METADATA,sha256=mlzTXMgNxL2crv8buBrhFsKzvguDXk_sMGiWLJEKHZc,4316
836
- omlish-0.0.0.dev290.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
837
- omlish-0.0.0.dev290.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
838
- omlish-0.0.0.dev290.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
839
- omlish-0.0.0.dev290.dist-info/RECORD,,
835
+ omlish-0.0.0.dev292.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
836
+ omlish-0.0.0.dev292.dist-info/METADATA,sha256=kDZfh7WmEgxzVyOJP7bSmYSh1RzTqJOv4VdFbKI55fk,4316
837
+ omlish-0.0.0.dev292.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
838
+ omlish-0.0.0.dev292.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
839
+ omlish-0.0.0.dev292.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
840
+ omlish-0.0.0.dev292.dist-info/RECORD,,