omdev 0.0.0.dev486__py3-none-any.whl → 0.0.0.dev506__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 omdev might be problematic. Click here for more details.

Files changed (50) hide show
  1. omdev/.omlish-manifests.json +2 -2
  2. omdev/README.md +51 -0
  3. omdev/__about__.py +4 -2
  4. omdev/ci/cli.py +1 -1
  5. omdev/cli/clicli.py +37 -7
  6. omdev/dataclasses/cli.py +1 -1
  7. omdev/interp/cli.py +1 -1
  8. omdev/interp/types.py +3 -2
  9. omdev/interp/uv/provider.py +36 -0
  10. omdev/manifests/main.py +1 -1
  11. omdev/markdown/incparse.py +392 -0
  12. omdev/packaging/revisions.py +1 -1
  13. omdev/py/tools/pipdepup.py +150 -93
  14. omdev/pyproject/cli.py +2 -36
  15. omdev/pyproject/configs.py +1 -1
  16. omdev/pyproject/pkg.py +1 -1
  17. omdev/pyproject/reqs.py +8 -7
  18. omdev/pyproject/tools/aboutdeps.py +5 -0
  19. omdev/pyproject/tools/pyversions.py +47 -0
  20. omdev/pyproject/versions.py +40 -0
  21. omdev/scripts/ci.py +369 -26
  22. omdev/scripts/interp.py +51 -9
  23. omdev/scripts/lib/inject.py +8 -1
  24. omdev/scripts/lib/logs.py +117 -21
  25. omdev/scripts/pyproject.py +479 -76
  26. omdev/tools/git/cli.py +43 -13
  27. omdev/tools/json/formats.py +2 -0
  28. omdev/tools/jsonview/cli.py +19 -61
  29. omdev/tools/jsonview/resources/jsonview.html.j2 +43 -0
  30. omdev/tools/pawk/README.md +195 -0
  31. omdev/tools/sqlrepl.py +189 -78
  32. omdev/tui/apps/edit/main.py +5 -1
  33. omdev/tui/apps/irc/app.py +28 -20
  34. omdev/tui/apps/irc/commands.py +1 -1
  35. omdev/tui/rich/__init__.py +12 -0
  36. omdev/tui/rich/markdown2.py +219 -18
  37. omdev/tui/textual/__init__.py +41 -2
  38. omdev/tui/textual/app2.py +6 -1
  39. omdev/tui/textual/debug/__init__.py +10 -0
  40. omdev/tui/textual/debug/dominfo.py +151 -0
  41. omdev/tui/textual/debug/screen.py +24 -0
  42. omdev/tui/textual/devtools.py +187 -0
  43. omdev/tui/textual/logging2.py +20 -0
  44. omdev/tui/textual/types.py +45 -0
  45. {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev506.dist-info}/METADATA +10 -6
  46. {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev506.dist-info}/RECORD +50 -39
  47. {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev506.dist-info}/WHEEL +0 -0
  48. {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev506.dist-info}/entry_points.txt +0 -0
  49. {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev506.dist-info}/licenses/LICENSE +0 -0
  50. {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev506.dist-info}/top_level.txt +0 -0
@@ -94,13 +94,14 @@ def __omlish_amalg__(): # noqa
94
94
  dict(path='../../omlish/formats/toml/parser.py', sha1='73dac82289350ab951c4bcdbfe61167fa221f26f'),
95
95
  dict(path='../../omlish/formats/toml/writer.py', sha1='6ea41d7e724bb1dcf6bd84b88993ff4e8798e021'),
96
96
  dict(path='../../omlish/lite/abstract.py', sha1='a2fc3f3697fa8de5247761e9d554e70176f37aac'),
97
+ dict(path='../../omlish/lite/asyncs.py', sha1='b3f2251c56617ce548abf9c333ac996b63edb23e'),
97
98
  dict(path='../../omlish/lite/cached.py', sha1='0c33cf961ac8f0727284303c7a30c5ea98f714f2'),
98
99
  dict(path='../../omlish/lite/check.py', sha1='bb6b6b63333699b84462951a854d99ae83195b94'),
99
100
  dict(path='../../omlish/lite/json.py', sha1='57eeddc4d23a17931e00284ffa5cb6e3ce089486'),
100
101
  dict(path='../../omlish/lite/objects.py', sha1='9566bbf3530fd71fcc56321485216b592fae21e9'),
101
102
  dict(path='../../omlish/lite/reflect.py', sha1='c4fec44bf144e9d93293c996af06f6c65fc5e63d'),
102
103
  dict(path='../../omlish/lite/strings.py', sha1='89831ecbc34ad80e118a865eceb390ed399dc4d6'),
103
- dict(path='../../omlish/lite/typing.py', sha1='deaaa560b63d9a0e40991ec0006451f5f0df04c1'),
104
+ dict(path='../../omlish/lite/typing.py', sha1='048bb5fb8ecad5be101516f8f3b7996707f5bc42'),
104
105
  dict(path='../../omlish/logs/levels.py', sha1='91405563d082a5eba874da82aac89d83ce7b6152'),
105
106
  dict(path='../../omlish/logs/std/filters.py', sha1='f36aab646d84d31e295b33aaaaa6f8b67ff38b3d'),
106
107
  dict(path='../../omlish/logs/std/proxy.py', sha1='3e7301a2aa351127f9c85f61b2f85dcc3f15aafb'),
@@ -108,43 +109,45 @@ def __omlish_amalg__(): # noqa
108
109
  dict(path='../cexts/magic.py', sha1='4e5ce6732454f75c9dd27352959708d8fa7b1666'),
109
110
  dict(path='../magic/find.py', sha1='436228a9cf1d8bab6b9234d09f72913b0960382f'),
110
111
  dict(path='../packaging/specifiers.py', sha1='a56ab4e8c9b174adb523921f6280ac41e0fce749'),
112
+ dict(path='versions.py', sha1='99aa1788f4eccb1901f21f2265862716d7580192'),
111
113
  dict(path='../../omlish/argparse/cli.py', sha1='f4dc3cd353d14386b5da0306768700e396afd2b3'),
112
114
  dict(path='../../omlish/lite/marshal.py', sha1='96348f5f2a26dc27d842d33cc3927e9da163436b'),
113
- dict(path='../../omlish/lite/maybes.py', sha1='bdf5136654ccd14b6a072588cad228925bdfbabd'),
115
+ dict(path='../../omlish/lite/maybes.py', sha1='04d2fcbea17028a5e6b8e7a7fb742375495ed233'),
114
116
  dict(path='../../omlish/lite/runtime.py', sha1='2e752a27ae2bf89b1bb79b4a2da522a3ec360c70'),
115
117
  dict(path='../../omlish/lite/timeouts.py', sha1='a0f673033a6943f242e35848d78a41892b9c62a1'),
116
118
  dict(path='../../omlish/logs/infos.py', sha1='4dd104bd468a8c438601dd0bbda619b47d2f1620'),
117
119
  dict(path='../../omlish/logs/protocols.py', sha1='05ca4d1d7feb50c4e3b9f22ee371aa7bf4b3dbd1'),
118
120
  dict(path='../../omlish/logs/std/json.py', sha1='2a75553131e4d5331bb0cedde42aa183f403fc3b'),
119
- dict(path='../interp/types.py', sha1='cfc14929777fb19f723c875bcafc8f7c66593d6d'),
121
+ dict(path='../interp/types.py', sha1='caf068a6e81fb6e221d777b341ac5777d92b8091'),
120
122
  dict(path='../packaging/requires.py', sha1='5818353abd45135e0e638e28fa6247b24122231b'),
121
123
  dict(path='../../omlish/asyncs/asyncio/timeouts.py', sha1='4d31b02b3c39b8f2fa7e94db36552fde6942e36a'),
122
124
  dict(path='../../omlish/lite/inject.py', sha1='6f097e3170019a34ff6834d36fcc9cbeed3a7ab4'),
123
- dict(path='../../omlish/logs/contexts.py', sha1='7456964ade9ac66460e9ade4e242dbdc24b39501'),
124
- dict(path='../../omlish/logs/standard.py', sha1='818b674f7d15012f25b79f52f6e8e7368b633038'),
125
+ dict(path='../../omlish/logs/contexts.py', sha1='1000a6d5ddfb642865ca532e34b1d50759781cf0'),
126
+ dict(path='../../omlish/logs/std/standard.py', sha1='5c97c1b9f7ead58d6127d047b873398f708f288d'),
125
127
  dict(path='../../omlish/subprocesses/run.py', sha1='8200e48f0c49d164df3503cd0143038d0c4d30aa'),
126
128
  dict(path='../../omlish/subprocesses/wrap.py', sha1='8a9b7d2255481fae15c05f5624b0cdc0766f4b3f'),
127
129
  dict(path='../interp/providers/base.py', sha1='f5d068c21f230d742e9015b033cd6320f4c68898'),
128
- dict(path='../../omlish/logs/base.py', sha1='a376460b11b9dc0555fd4ead5437af62c2109a4b'),
130
+ dict(path='../../omlish/logs/base.py', sha1='8d06faee05fead6b1dd98c9035a5b042af4aebb1'),
129
131
  dict(path='../../omlish/logs/std/records.py', sha1='8bbf6ef9eccb3a012c6ca416ddf3969450fd8fc9'),
130
132
  dict(path='../../omlish/subprocesses/base.py', sha1='cb9f668be5422fecb27222caabb67daac6c1bab9'),
131
133
  dict(path='../interp/resolvers.py', sha1='817b8e76401cd7a19eb43ca54d65272e4c8a4b0e'),
132
- dict(path='../../omlish/logs/std/loggers.py', sha1='daa35bdc4adea5006e442688017f0de3392579b7'),
134
+ dict(path='../../omlish/logs/asyncs.py', sha1='ab11b70033d9f2e9a4e70254185aa1c6130c6077'),
135
+ dict(path='../../omlish/logs/std/loggers.py', sha1='a569179445d6a8a942b5dcfad1d1f77702868803'),
133
136
  dict(path='../../omlish/subprocesses/asyncs.py', sha1='bba44d524c24c6ac73168aee6343488414e5bf48'),
134
137
  dict(path='../../omlish/subprocesses/sync.py', sha1='8434919eba4da67825773d56918fdc0cb2f1883b'),
135
138
  dict(path='../git/revisions.py', sha1='a26b5afa568313e034b6b2d3a5d2dd0b065979d4'),
136
139
  dict(path='../../omlish/asyncs/asyncio/subprocesses.py', sha1='b6b5f9ae3fd0b9c83593bad2e04a08f726e5904d'),
137
- dict(path='../../omlish/logs/modules.py', sha1='99e73cde6872fd5eda6af3dbf0fc9322bdeb641a'),
140
+ dict(path='../../omlish/logs/modules.py', sha1='dd7d5f8e63fe8829dfb49460f3929ab64b68ee14'),
138
141
  dict(path='../interp/inspect.py', sha1='736287b4ec8d14a8c30afa0ba23996fdc0662caa'),
139
142
  dict(path='../interp/pyenv/pyenv.py', sha1='d1f6e657c671c1b1a5b0e627284df656fe2d10d3'),
140
143
  dict(path='../interp/uv/uv.py', sha1='8c6515cd6755efab3972da92a285e94ccb255515'),
141
- dict(path='../packaging/revisions.py', sha1='4ea4ac3006ae5b0bdc0c5a6c587cfed8fbad87b3'),
142
- dict(path='reqs.py', sha1='822e265b0d2e6d9548ee24d3ac60c81066e40ee8'),
144
+ dict(path='../packaging/revisions.py', sha1='9ba90e4a93b1bfcc93f6ca65dbaaf38f79929677'),
145
+ dict(path='reqs.py', sha1='65ac743653c455a5015a1a0ce2317ee5372a0c7c'),
143
146
  dict(path='../interp/providers/running.py', sha1='85c9cc69ff6fbd6c8cf78ed6262619a30856c2f1'),
144
147
  dict(path='../interp/providers/system.py', sha1='9638a154475ca98775159d27739563ac7fb2eb16'),
145
148
  dict(path='../interp/pyenv/install.py', sha1='4a10a19717364b4ba9f3b8bf1d12621cf21ba8b8'),
146
- dict(path='../interp/uv/provider.py', sha1='997dc9453589a4cee0658d2fa0893c4ec60b5a0d'),
147
- dict(path='pkg.py', sha1='a7b64fcf267ba385442393b90c9711af08ba9ac3'),
149
+ dict(path='../interp/uv/provider.py', sha1='3c3980878ad2b9fd2cd02172f9424954759c7f06'),
150
+ dict(path='pkg.py', sha1='e2acb40b17d75b6deb78056e6726d114a7aef2e4'),
148
151
  dict(path='../interp/providers/inject.py', sha1='7cc9ebf58cf2ec09545321456bd9da9f9a3a79fb'),
149
152
  dict(path='../interp/pyenv/provider.py', sha1='377542ce01a35849e2a5b4a4dbafedc26882f983'),
150
153
  dict(path='../interp/uv/inject.py', sha1='e95d058c2340baa5a3155ec3440f311d1daa10a8'),
@@ -152,9 +155,9 @@ def __omlish_amalg__(): # noqa
152
155
  dict(path='../interp/inject.py', sha1='b039abbadf0b096d2724182af2e0ebda2a230852'),
153
156
  dict(path='../interp/default.py', sha1='a799969a0d3f4b57538587b13ceb08f6334ebc16'),
154
157
  dict(path='../interp/venvs.py', sha1='9ba8f2c3131d7d519d5cf36ca69b75f9c6fe2b27'),
155
- dict(path='configs.py', sha1='7b1c1ed034ecb728d67ff15e3bb2b21a218773c9'),
158
+ dict(path='configs.py', sha1='28d20c0288eef4a5c61dd9b95071b7b15958b575'),
156
159
  dict(path='venvs.py', sha1='9f1935171017aeb802da56e14d7f41d632a7aa25'),
157
- dict(path='cli.py', sha1='e2f06505bb59793af3a2779bfa2c15aefb308539'),
160
+ dict(path='cli.py', sha1='ecf31ccef6b0e1d1505b46d24faf076b6be32760'),
158
161
  ],
159
162
  )
160
163
 
@@ -2179,6 +2182,150 @@ class Abstract:
2179
2182
  update_abstracts(cls, force=True)
2180
2183
 
2181
2184
 
2185
+ ########################################
2186
+ # ../../../omlish/lite/asyncs.py
2187
+
2188
+
2189
+ ##
2190
+
2191
+
2192
+ async def opt_await(aw: ta.Optional[ta.Awaitable[T]]) -> ta.Optional[T]:
2193
+ return (await aw if aw is not None else None)
2194
+
2195
+
2196
+ async def async_list(ai: ta.AsyncIterable[T]) -> ta.List[T]:
2197
+ return [v async for v in ai]
2198
+
2199
+
2200
+ async def async_enumerate(ai: ta.AsyncIterable[T]) -> ta.AsyncIterable[ta.Tuple[int, T]]:
2201
+ i = 0
2202
+ async for e in ai:
2203
+ yield (i, e)
2204
+ i += 1
2205
+
2206
+
2207
+ ##
2208
+
2209
+
2210
+ def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[..., ta.Awaitable[T]]:
2211
+ async def inner(*args, **kwargs):
2212
+ return fn(*args, **kwargs)
2213
+
2214
+ return functools.wraps(fn)(inner) if wrap else inner
2215
+
2216
+
2217
+ ##
2218
+
2219
+
2220
+ class SyncAwaitCoroutineNotTerminatedError(Exception):
2221
+ pass
2222
+
2223
+
2224
+ def sync_await(aw: ta.Awaitable[T]) -> T:
2225
+ """
2226
+ Allows for the synchronous execution of async functions which will never actually *externally* await anything. These
2227
+ functions are allowed to await any number of other functions - including contextmanagers and generators - so long as
2228
+ nothing ever actually 'leaks' out of the function, presumably to an event loop.
2229
+ """
2230
+
2231
+ ret = missing = object()
2232
+
2233
+ async def thunk():
2234
+ nonlocal ret
2235
+
2236
+ ret = await aw
2237
+
2238
+ cr = thunk()
2239
+ try:
2240
+ try:
2241
+ cr.send(None)
2242
+ except StopIteration:
2243
+ pass
2244
+
2245
+ if ret is missing or cr.cr_await is not None or cr.cr_running:
2246
+ raise SyncAwaitCoroutineNotTerminatedError('Not terminated')
2247
+
2248
+ finally:
2249
+ cr.close()
2250
+
2251
+ return ta.cast(T, ret)
2252
+
2253
+
2254
+ #
2255
+
2256
+
2257
+ def sync_aiter(ai: ta.AsyncIterator[T]) -> ta.Iterator[T]:
2258
+ while True:
2259
+ try:
2260
+ o = sync_await(ai.__anext__())
2261
+ except StopAsyncIteration:
2262
+ break
2263
+ yield o
2264
+
2265
+
2266
+ def sync_async_list(ai: ta.AsyncIterable[T]) -> ta.List[T]:
2267
+ """
2268
+ Uses `sync_await` to synchronously read the full contents of a function call returning an async iterator, given that
2269
+ the function never externally awaits anything.
2270
+ """
2271
+
2272
+ lst: ta.Optional[ta.List[T]] = None
2273
+
2274
+ async def inner():
2275
+ nonlocal lst
2276
+
2277
+ lst = [v async for v in ai]
2278
+
2279
+ sync_await(inner())
2280
+
2281
+ if not isinstance(lst, list):
2282
+ raise TypeError(lst)
2283
+
2284
+ return lst
2285
+
2286
+
2287
+ #
2288
+
2289
+
2290
+ @ta.final
2291
+ class SyncAwaitContextManager(ta.Generic[T]):
2292
+ def __init__(self, acm: ta.AsyncContextManager[T]) -> None:
2293
+ self._acm = acm
2294
+
2295
+ def __repr__(self) -> str:
2296
+ return f'{self.__class__.__name__}({self._acm!r})'
2297
+
2298
+ def __enter__(self) -> T:
2299
+ return sync_await(self._acm.__aenter__())
2300
+
2301
+ def __exit__(self, exc_type, exc_val, exc_tb):
2302
+ return sync_await(self._acm.__aexit__(exc_type, exc_val, exc_tb))
2303
+
2304
+
2305
+ sync_async_with = SyncAwaitContextManager
2306
+
2307
+
2308
+ ##
2309
+
2310
+
2311
+ @ta.final
2312
+ class SyncToAsyncContextManager(ta.Generic[T]):
2313
+ def __init__(self, cm: ta.ContextManager[T]) -> None:
2314
+ self._cm = cm
2315
+
2316
+ def __repr__(self) -> str:
2317
+ return f'{self.__class__.__name__}({self._cm!r})'
2318
+
2319
+ async def __aenter__(self) -> T:
2320
+ return self._cm.__enter__()
2321
+
2322
+ async def __aexit__(self, exc_type, exc_value, traceback, /):
2323
+ return self._cm.__exit__(exc_type, exc_value, traceback)
2324
+
2325
+
2326
+ as_async_context_manager = SyncToAsyncContextManager
2327
+
2328
+
2182
2329
  ########################################
2183
2330
  # ../../../omlish/lite/cached.py
2184
2331
 
@@ -3131,6 +3278,39 @@ class Func3(ta.Generic[A0, A1, A2, T]):
3131
3278
  ##
3132
3279
 
3133
3280
 
3281
+ @dc.dataclass(frozen=True)
3282
+ class CachedFunc0(ta.Generic[T]):
3283
+ fn: ta.Callable[[], T]
3284
+
3285
+ def __call__(self) -> T:
3286
+ try:
3287
+ return object.__getattribute__(self, '_value')
3288
+ except AttributeError:
3289
+ pass
3290
+
3291
+ value = self.fn()
3292
+ object.__setattr__(self, '_value', value)
3293
+ return value
3294
+
3295
+
3296
+ @dc.dataclass(frozen=True)
3297
+ class AsyncCachedFunc0(ta.Generic[T]):
3298
+ fn: ta.Callable[[], ta.Awaitable[T]]
3299
+
3300
+ async def __call__(self) -> T:
3301
+ try:
3302
+ return object.__getattribute__(self, '_value')
3303
+ except AttributeError:
3304
+ pass
3305
+
3306
+ value = await self.fn()
3307
+ object.__setattr__(self, '_value', value)
3308
+ return value
3309
+
3310
+
3311
+ ##
3312
+
3313
+
3134
3314
  _TYPING_ANNOTATIONS_ATTR = '__annotate__' if sys.version_info >= (3, 14) else '__annotations__'
3135
3315
 
3136
3316
 
@@ -4125,6 +4305,44 @@ class SpecifierSet(BaseSpecifier):
4125
4305
  return iter(filtered)
4126
4306
 
4127
4307
 
4308
+ ########################################
4309
+ # ../versions.py
4310
+
4311
+
4312
+ ##
4313
+
4314
+
4315
+ @dc.dataclass(frozen=True)
4316
+ class VersionsFile:
4317
+ name: ta.Optional[str] = '.versions'
4318
+
4319
+ @staticmethod
4320
+ def parse(s: str) -> ta.Mapping[str, str]:
4321
+ return {
4322
+ k: v
4323
+ for l in s.splitlines()
4324
+ if (sl := l.split('#')[0].strip())
4325
+ for k, _, v in (sl.partition('='),)
4326
+ }
4327
+
4328
+ @cached_nullary
4329
+ def contents(self) -> ta.Mapping[str, str]:
4330
+ if not self.name or not os.path.exists(self.name):
4331
+ return {}
4332
+ with open(self.name) as f:
4333
+ s = f.read()
4334
+ return self.parse(s)
4335
+
4336
+ @staticmethod
4337
+ def get_pythons(d: ta.Mapping[str, str]) -> ta.Mapping[str, str]:
4338
+ pfx = 'PYTHON_'
4339
+ return {k[len(pfx):].lower(): v for k, v in d.items() if k.startswith(pfx)}
4340
+
4341
+ @cached_nullary
4342
+ def pythons(self) -> ta.Mapping[str, str]:
4343
+ return self.get_pythons(self.contents())
4344
+
4345
+
4128
4346
  ########################################
4129
4347
  # ../../../omlish/argparse/cli.py
4130
4348
  """
@@ -5302,6 +5520,13 @@ class Maybe(ta.Generic[T]):
5302
5520
  else:
5303
5521
  return other
5304
5522
 
5523
+ @ta.final
5524
+ def or_none(self) -> ta.Optional[T]:
5525
+ if self.present:
5526
+ return self.must()
5527
+ else:
5528
+ return None
5529
+
5305
5530
  @ta.final
5306
5531
  def or_else_get(self, supplier: ta.Callable[[], ta.Union[T, U]]) -> ta.Union[T, U]:
5307
5532
  if self.present:
@@ -6166,9 +6391,10 @@ class InterpSpecifier:
6166
6391
  def parse(cls, s: str) -> 'InterpSpecifier':
6167
6392
  s, o = InterpOpts.parse_suffix(s)
6168
6393
  if not any(s.startswith(o) for o in Specifier.OPERATORS):
6169
- s = '~=' + s
6170
6394
  if s.count('.') < 2:
6171
- s += '.0'
6395
+ s = '~=' + s + '.0'
6396
+ else:
6397
+ s = '==' + s
6172
6398
  return cls(
6173
6399
  specifier=Specifier(s),
6174
6400
  opts=o,
@@ -7879,6 +8105,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
7879
8105
  self._infos[type(info)] = info
7880
8106
  return self
7881
8107
 
8108
+ def get_infos(self) -> ta.Mapping[ta.Type[LoggingContextInfo], LoggingContextInfo]:
8109
+ return self._infos
8110
+
7882
8111
  def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
7883
8112
  return self._infos.get(ty)
7884
8113
 
@@ -7901,7 +8130,7 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
7901
8130
  _stack_offset: int
7902
8131
  _stack_info: bool
7903
8132
 
7904
- def inc_stack_offset(self, ofs: int = 1) -> 'CaptureLoggingContext':
8133
+ def inc_stack_offset(self, ofs: int = 1) -> 'CaptureLoggingContextImpl':
7905
8134
  if hasattr(self, '_stack_offset'):
7906
8135
  self._stack_offset += ofs
7907
8136
  return self
@@ -7933,10 +8162,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
7933
8162
 
7934
8163
 
7935
8164
  ########################################
7936
- # ../../../omlish/logs/standard.py
8165
+ # ../../../omlish/logs/std/standard.py
7937
8166
  """
7938
8167
  TODO:
7939
- - !! move to std !!
7940
8168
  - structured
7941
8169
  - prefixed
7942
8170
  - debug
@@ -8306,6 +8534,11 @@ class AnyLogger(Abstract, ta.Generic[T]):
8306
8534
 
8307
8535
  ##
8308
8536
 
8537
+ # This will be 1 for [Sync]Logger and 0 for AsyncLogger - in sync loggers these methods remain present on the stack,
8538
+ # in async loggers they return a coroutine to be awaited and thus aren't actually present when said coroutine is
8539
+ # awaited.
8540
+ _level_proxy_method_stack_offset: int
8541
+
8309
8542
  @ta.overload
8310
8543
  def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
8311
8544
  ...
@@ -8320,7 +8553,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
8320
8553
 
8321
8554
  @ta.final
8322
8555
  def log(self, level: LogLevel, *args, **kwargs):
8323
- return self._log(CaptureLoggingContextImpl(level, stack_offset=1), *args, **kwargs)
8556
+ return self._log(
8557
+ CaptureLoggingContextImpl(
8558
+ level,
8559
+ stack_offset=self._level_proxy_method_stack_offset,
8560
+ ),
8561
+ *args,
8562
+ **kwargs,
8563
+ )
8324
8564
 
8325
8565
  #
8326
8566
 
@@ -8338,7 +8578,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
8338
8578
 
8339
8579
  @ta.final
8340
8580
  def debug(self, *args, **kwargs):
8341
- return self._log(CaptureLoggingContextImpl(NamedLogLevel.DEBUG, stack_offset=1), *args, **kwargs)
8581
+ return self._log(
8582
+ CaptureLoggingContextImpl(
8583
+ NamedLogLevel.DEBUG,
8584
+ stack_offset=self._level_proxy_method_stack_offset,
8585
+ ),
8586
+ *args,
8587
+ **kwargs,
8588
+ )
8342
8589
 
8343
8590
  #
8344
8591
 
@@ -8356,7 +8603,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
8356
8603
 
8357
8604
  @ta.final
8358
8605
  def info(self, *args, **kwargs):
8359
- return self._log(CaptureLoggingContextImpl(NamedLogLevel.INFO, stack_offset=1), *args, **kwargs)
8606
+ return self._log(
8607
+ CaptureLoggingContextImpl(
8608
+ NamedLogLevel.INFO,
8609
+ stack_offset=self._level_proxy_method_stack_offset,
8610
+ ),
8611
+ *args,
8612
+ **kwargs,
8613
+ )
8360
8614
 
8361
8615
  #
8362
8616
 
@@ -8374,7 +8628,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
8374
8628
 
8375
8629
  @ta.final
8376
8630
  def warning(self, *args, **kwargs):
8377
- return self._log(CaptureLoggingContextImpl(NamedLogLevel.WARNING, stack_offset=1), *args, **kwargs)
8631
+ return self._log(
8632
+ CaptureLoggingContextImpl(
8633
+ NamedLogLevel.WARNING,
8634
+ stack_offset=self._level_proxy_method_stack_offset,
8635
+ ),
8636
+ *args,
8637
+ **kwargs,
8638
+ )
8378
8639
 
8379
8640
  #
8380
8641
 
@@ -8392,7 +8653,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
8392
8653
 
8393
8654
  @ta.final
8394
8655
  def error(self, *args, **kwargs):
8395
- return self._log(CaptureLoggingContextImpl(NamedLogLevel.ERROR, stack_offset=1), *args, **kwargs)
8656
+ return self._log(
8657
+ CaptureLoggingContextImpl(
8658
+ NamedLogLevel.ERROR,
8659
+ stack_offset=self._level_proxy_method_stack_offset,
8660
+ ),
8661
+ *args,
8662
+ **kwargs,
8663
+ )
8396
8664
 
8397
8665
  #
8398
8666
 
@@ -8410,7 +8678,15 @@ class AnyLogger(Abstract, ta.Generic[T]):
8410
8678
 
8411
8679
  @ta.final
8412
8680
  def exception(self, *args, exc_info: LoggingExcInfoArg = True, **kwargs):
8413
- return self._log(CaptureLoggingContextImpl(NamedLogLevel.ERROR, exc_info=exc_info, stack_offset=1), *args, **kwargs) # noqa
8681
+ return self._log(
8682
+ CaptureLoggingContextImpl(
8683
+ NamedLogLevel.ERROR,
8684
+ exc_info=exc_info,
8685
+ stack_offset=self._level_proxy_method_stack_offset,
8686
+ ),
8687
+ *args,
8688
+ **kwargs,
8689
+ )
8414
8690
 
8415
8691
  #
8416
8692
 
@@ -8428,24 +8704,53 @@ class AnyLogger(Abstract, ta.Generic[T]):
8428
8704
 
8429
8705
  @ta.final
8430
8706
  def critical(self, *args, **kwargs):
8431
- return self._log(CaptureLoggingContextImpl(NamedLogLevel.CRITICAL, stack_offset=1), *args, **kwargs)
8707
+ return self._log(
8708
+ CaptureLoggingContextImpl(
8709
+ NamedLogLevel.CRITICAL,
8710
+ stack_offset=self._level_proxy_method_stack_offset,
8711
+ ),
8712
+ *args,
8713
+ **kwargs,
8714
+ )
8432
8715
 
8433
8716
  ##
8434
8717
 
8435
8718
  @abc.abstractmethod
8436
- def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> T: # noqa
8719
+ def _log(
8720
+ self,
8721
+ ctx: CaptureLoggingContext,
8722
+ msg: ta.Union[str, tuple, LoggingMsgFn],
8723
+ *args: ta.Any,
8724
+ **kwargs: ta.Any,
8725
+ ) -> T:
8437
8726
  raise NotImplementedError
8438
8727
 
8439
8728
 
8440
8729
  class Logger(AnyLogger[None], Abstract):
8730
+ _level_proxy_method_stack_offset: int = 1
8731
+
8441
8732
  @abc.abstractmethod
8442
- def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
8733
+ def _log(
8734
+ self,
8735
+ ctx: CaptureLoggingContext,
8736
+ msg: ta.Union[str, tuple, LoggingMsgFn],
8737
+ *args: ta.Any,
8738
+ **kwargs: ta.Any,
8739
+ ) -> None:
8443
8740
  raise NotImplementedError
8444
8741
 
8445
8742
 
8446
8743
  class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
8744
+ _level_proxy_method_stack_offset: int = 0
8745
+
8447
8746
  @abc.abstractmethod
8448
- def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> ta.Awaitable[None]: # noqa
8747
+ def _log(
8748
+ self,
8749
+ ctx: CaptureLoggingContext,
8750
+ msg: ta.Union[str, tuple, LoggingMsgFn],
8751
+ *args: ta.Any,
8752
+ **kwargs: ta.Any,
8753
+ ) -> ta.Awaitable[None]:
8449
8754
  raise NotImplementedError
8450
8755
 
8451
8756
 
@@ -8460,13 +8765,25 @@ class AnyNopLogger(AnyLogger[T], Abstract):
8460
8765
 
8461
8766
  @ta.final
8462
8767
  class NopLogger(AnyNopLogger[None], Logger):
8463
- def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
8768
+ def _log(
8769
+ self,
8770
+ ctx: CaptureLoggingContext,
8771
+ msg: ta.Union[str, tuple, LoggingMsgFn],
8772
+ *args: ta.Any,
8773
+ **kwargs: ta.Any,
8774
+ ) -> None:
8464
8775
  pass
8465
8776
 
8466
8777
 
8467
8778
  @ta.final
8468
8779
  class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
8469
- async def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
8780
+ async def _log(
8781
+ self,
8782
+ ctx: CaptureLoggingContext,
8783
+ msg: ta.Union[str, tuple, LoggingMsgFn],
8784
+ *args: ta.Any,
8785
+ **kwargs: ta.Any,
8786
+ ) -> None:
8470
8787
  pass
8471
8788
 
8472
8789
 
@@ -9432,6 +9749,70 @@ class InterpResolver:
9432
9749
  print(f' {si}')
9433
9750
 
9434
9751
 
9752
+ ########################################
9753
+ # ../../../omlish/logs/asyncs.py
9754
+
9755
+
9756
+ ##
9757
+
9758
+
9759
+ class AsyncLoggerToLogger(Logger):
9760
+ def __init__(self, u: AsyncLogger) -> None:
9761
+ super().__init__()
9762
+
9763
+ self._u = u
9764
+
9765
+ def get_effective_level(self) -> LogLevel:
9766
+ return self._u.get_effective_level()
9767
+
9768
+ def _log(
9769
+ self,
9770
+ ctx: CaptureLoggingContext,
9771
+ msg: ta.Union[str, tuple, LoggingMsgFn],
9772
+ *args: ta.Any,
9773
+ **kwargs: ta.Any,
9774
+ ) -> None:
9775
+ # Nope out early to avoid sync_await if possible - don't bother in the LoggerToAsyncLogger.
9776
+ if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
9777
+ return
9778
+
9779
+ # Note: we hardcode the stack offset of sync_await (which is 2 - sync_await + sync_await.thunk). In non-lite
9780
+ # code, lang.sync_await uses a cext if present to avoid being on the py stack, which would obviously complicate
9781
+ # this, but this is lite code so we will always have the non-c version.
9782
+ sync_await(
9783
+ self._u._log( # noqa
9784
+ check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(3),
9785
+ msg,
9786
+ *args,
9787
+ **kwargs,
9788
+ ),
9789
+ )
9790
+
9791
+
9792
+ class LoggerToAsyncLogger(AsyncLogger):
9793
+ def __init__(self, u: Logger) -> None:
9794
+ super().__init__()
9795
+
9796
+ self._u = u
9797
+
9798
+ def get_effective_level(self) -> LogLevel:
9799
+ return self._u.get_effective_level()
9800
+
9801
+ async def _log(
9802
+ self,
9803
+ ctx: CaptureLoggingContext,
9804
+ msg: ta.Union[str, tuple, LoggingMsgFn],
9805
+ *args: ta.Any,
9806
+ **kwargs: ta.Any,
9807
+ ) -> None:
9808
+ return self._u._log( # noqa
9809
+ check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(),
9810
+ msg,
9811
+ *args,
9812
+ **kwargs,
9813
+ )
9814
+
9815
+
9435
9816
  ########################################
9436
9817
  # ../../../omlish/logs/std/loggers.py
9437
9818
 
@@ -9455,7 +9836,12 @@ class StdLogger(Logger):
9455
9836
  def get_effective_level(self) -> LogLevel:
9456
9837
  return self._std.getEffectiveLevel()
9457
9838
 
9458
- def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any) -> None:
9839
+ def _log(
9840
+ self,
9841
+ ctx: CaptureLoggingContext,
9842
+ msg: ta.Union[str, tuple, LoggingMsgFn],
9843
+ *args: ta.Any,
9844
+ ) -> None:
9459
9845
  if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
9460
9846
  return
9461
9847
 
@@ -9974,8 +10360,23 @@ asyncio_subprocesses = AsyncioSubprocesses()
9974
10360
  ##
9975
10361
 
9976
10362
 
10363
+ def _get_module_std_logger(mod_globals: ta.Mapping[str, ta.Any]) -> logging.Logger:
10364
+ return logging.getLogger(mod_globals.get('__name__'))
10365
+
10366
+
9977
10367
  def get_module_logger(mod_globals: ta.Mapping[str, ta.Any]) -> Logger:
9978
- return StdLogger(logging.getLogger(mod_globals.get('__name__'))) # noqa
10368
+ return StdLogger(_get_module_std_logger(mod_globals))
10369
+
10370
+
10371
+ def get_module_async_logger(mod_globals: ta.Mapping[str, ta.Any]) -> AsyncLogger:
10372
+ return LoggerToAsyncLogger(get_module_logger(mod_globals))
10373
+
10374
+
10375
+ def get_module_loggers(mod_globals: ta.Mapping[str, ta.Any]) -> ta.Tuple[Logger, AsyncLogger]:
10376
+ return (
10377
+ log := get_module_logger(mod_globals),
10378
+ LoggerToAsyncLogger(log),
10379
+ )
9979
10380
 
9980
10381
 
9981
10382
  ########################################
@@ -10395,13 +10796,14 @@ class RequirementsRewriter:
10395
10796
  if self.VENV_MAGIC in l:
10396
10797
  lp, _, rp = l.partition(self.VENV_MAGIC)
10397
10798
  rp = rp.partition('#')[0]
10398
- for v in rp.split():
10399
- if v[0] == '!':
10400
- if self._venv is not None and self._venv == v[1:]:
10401
- omit = True
10402
- break
10403
- else:
10404
- raise NotImplementedError
10799
+ vs = set(rp.split())
10800
+ nvs = {v[1:] for v in vs if v.startswith('!')}
10801
+ pvs = {v for v in vs if not v.startswith('!')}
10802
+ if (
10803
+ (nvs and self._venv in nvs) or
10804
+ (pvs and self._venv not in pvs)
10805
+ ):
10806
+ omit = True
10405
10807
 
10406
10808
  if (
10407
10809
  not omit and
@@ -10872,12 +11274,41 @@ uv run --python 3.11.6 pip
10872
11274
  uv venv --python 3.11.6 --seed barf
10873
11275
  python3 -m venv barf && barf/bin/pip install uv && barf/bin/uv venv --python 3.11.6 --seed barf2
10874
11276
  uv python find '3.13.10'
11277
+ uv python list --output-format=json
10875
11278
  """
10876
11279
 
10877
11280
 
10878
11281
  ##
10879
11282
 
10880
11283
 
11284
+ @dc.dataclass(frozen=True)
11285
+ class UvPythonListOutput:
11286
+ key: str
11287
+ version: str
11288
+
11289
+ @dc.dataclass(frozen=True)
11290
+ class VersionParts:
11291
+ major: int
11292
+ minor: int
11293
+ patch: int
11294
+
11295
+ version_parts: VersionParts
11296
+
11297
+ path: ta.Optional[str]
11298
+ symlink: ta.Optional[str]
11299
+
11300
+ url: str
11301
+
11302
+ os: str # emscripten linux macos
11303
+ variant: str # default freethreaded
11304
+ implementation: str # cpython graalpy pyodide pypy
11305
+ arch: str # aarch64 wasm32 x86_64
11306
+ libc: str # gnu musl none
11307
+
11308
+
11309
+ ##
11310
+
11311
+
10881
11312
  class UvInterpProvider(InterpProvider):
10882
11313
  def __init__(
10883
11314
  self,
@@ -10898,6 +11329,12 @@ class UvInterpProvider(InterpProvider):
10898
11329
  async def get_installed_version(self, version: InterpVersion) -> Interp:
10899
11330
  raise NotImplementedError
10900
11331
 
11332
+ # async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
11333
+ # return []
11334
+
11335
+ # async def install_version(self, version: InterpVersion) -> Interp:
11336
+ # raise TypeError
11337
+
10901
11338
 
10902
11339
  ########################################
10903
11340
  # ../pkg.py
@@ -11468,7 +11905,7 @@ class _PyprojectRsPackageGenerator(_PyprojectExtensionPackageGenerator):
11468
11905
  # `sdist.add_defaults` as an unbound function, not a bound method:
11469
11906
  # https://github.com/pypa/setuptools/blob/9c4d383631d3951fcae0afd73b5d08ff5a262976/setuptools/command/egg_info.py#L581
11470
11907
  from setuptools.command.sdist import sdist # noqa
11471
- sdist.add_defaults = (lambda old: lambda sdist: _sdist_add_defaults(old, sdist))(sdist.add_defaults) # noqa
11908
+ setattr(sdist, 'add_defaults', (lambda old: lambda sdist: _sdist_add_defaults(old, sdist))(sdist.add_defaults)) # noqa
11472
11909
 
11473
11910
  _patch_sdist()
11474
11911
 
@@ -11979,7 +12416,7 @@ class PyprojectConfig:
11979
12416
  venvs: ta.Mapping[str, VenvConfig] = dc.field(default_factory=dict)
11980
12417
 
11981
12418
  venvs_dir: str = '.venvs'
11982
- versions_file: ta.Optional[str] = '.versions'
12419
+ # versions_file: ta.Optional[str] = '.versions' # FIXME:
11983
12420
 
11984
12421
 
11985
12422
  class PyprojectConfigPreparer:
@@ -12142,40 +12579,6 @@ class Venv:
12142
12579
  ##
12143
12580
 
12144
12581
 
12145
- @dc.dataclass(frozen=True)
12146
- class VersionsFile:
12147
- name: ta.Optional[str] = '.versions'
12148
-
12149
- @staticmethod
12150
- def parse(s: str) -> ta.Mapping[str, str]:
12151
- return {
12152
- k: v
12153
- for l in s.splitlines()
12154
- if (sl := l.split('#')[0].strip())
12155
- for k, _, v in (sl.partition('='),)
12156
- }
12157
-
12158
- @cached_nullary
12159
- def contents(self) -> ta.Mapping[str, str]:
12160
- if not self.name or not os.path.exists(self.name):
12161
- return {}
12162
- with open(self.name) as f:
12163
- s = f.read()
12164
- return self.parse(s)
12165
-
12166
- @staticmethod
12167
- def get_pythons(d: ta.Mapping[str, str]) -> ta.Mapping[str, str]:
12168
- pfx = 'PYTHON_'
12169
- return {k[len(pfx):].lower(): v for k, v in d.items() if k.startswith(pfx)}
12170
-
12171
- @cached_nullary
12172
- def pythons(self) -> ta.Mapping[str, str]:
12173
- return self.get_pythons(self.contents())
12174
-
12175
-
12176
- ##
12177
-
12178
-
12179
12582
  @cached_nullary
12180
12583
  def _script_rel_path() -> str:
12181
12584
  cwd = os.getcwd()