omdev 0.0.0.dev103__py3-none-any.whl → 0.0.0.dev112__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.
omdev/.manifests.json CHANGED
@@ -123,7 +123,7 @@
123
123
  "module": ".ptk.apps.ncdu",
124
124
  "attr": "_CLI_MODULE",
125
125
  "file": "omdev/ptk/apps/ncdu.py",
126
- "line": 155,
126
+ "line": 159,
127
127
  "value": {
128
128
  "$.cli.types.CliModule": {
129
129
  "cmd_name": "ptk/ncdu",
@@ -131,6 +131,18 @@
131
131
  }
132
132
  }
133
133
  },
134
+ {
135
+ "module": ".pycharm.__main__",
136
+ "attr": "_CLI_MODULE",
137
+ "file": "omdev/pycharm/__main__.py",
138
+ "line": 4,
139
+ "value": {
140
+ "$.cli.types.CliModule": {
141
+ "cmd_name": "pycharm",
142
+ "mod_name": "omdev.pycharm.__main__"
143
+ }
144
+ }
145
+ },
134
146
  {
135
147
  "module": ".pyproject.__main__",
136
148
  "attr": "_CLI_MODULE",
@@ -191,6 +203,18 @@
191
203
  }
192
204
  }
193
205
  },
206
+ {
207
+ "module": ".scripts.tmpexec",
208
+ "attr": "_CLI_MODULE",
209
+ "file": "omdev/scripts/tmpexec.py",
210
+ "line": 50,
211
+ "value": {
212
+ "$.cli.types.CliModule": {
213
+ "cmd_name": "tmpexec",
214
+ "mod_name": "omdev.scripts.tmpexec"
215
+ }
216
+ }
217
+ },
194
218
  {
195
219
  "module": ".tools.doc",
196
220
  "attr": "_CLI_MODULE",
@@ -219,7 +243,7 @@
219
243
  "module": ".tools.git",
220
244
  "attr": "_CLI_MODULE",
221
245
  "file": "omdev/tools/git.py",
222
- "line": 124,
246
+ "line": 128,
223
247
  "value": {
224
248
  "$.cli.types.CliModule": {
225
249
  "cmd_name": "git",
@@ -282,7 +306,7 @@
282
306
  "module": ".tools.pip",
283
307
  "attr": "_CLI_MODULE",
284
308
  "file": "omdev/tools/pip.py",
285
- "line": 88,
309
+ "line": 164,
286
310
  "value": {
287
311
  "$.cli.types.CliModule": {
288
312
  "cmd_name": "pip",
@@ -302,6 +326,18 @@
302
326
  }
303
327
  }
304
328
  },
329
+ {
330
+ "module": ".tools.qr",
331
+ "attr": "_CLI_MODULE",
332
+ "file": "omdev/tools/qr.py",
333
+ "line": 74,
334
+ "value": {
335
+ "$.cli.types.CliModule": {
336
+ "cmd_name": "qr",
337
+ "mod_name": "omdev.tools.qr"
338
+ }
339
+ }
340
+ },
305
341
  {
306
342
  "module": ".tools.sqlrepl",
307
343
  "attr": "_CLI_MODULE",
omdev/__about__.py CHANGED
@@ -41,6 +41,10 @@ class Project(ProjectBase):
41
41
  'prompt-toolkit ~= 3.0',
42
42
  ],
43
43
 
44
+ 'qr': [
45
+ 'segno ~= 1.6',
46
+ ],
47
+
44
48
  'tokens': [
45
49
  'tokenize-rt ~= 6.1',
46
50
  ],
omdev/clipboard/darwin.py CHANGED
@@ -1,4 +1,31 @@
1
1
  # ruff: noqa: N802 N816
2
+ """
3
+ imageProperties = dict(
4
+ ColorModel = "RGB"
5
+ DPIHeight = 144
6
+ DPIWidth = 144
7
+ Depth = 8
8
+ PixelHeight = 1236
9
+ PixelWidth = 602
10
+ ProfileName = "Color LCD"
11
+ kCGImageDestinationAllowAlpha = true
12
+ {Exif} = dict(
13
+ PixelXDimension = 602
14
+ PixelYDimension = 1236
15
+ UserComment = "Screenshot"
16
+ )
17
+ {PNG} = dict(
18
+ InterlaceType = 0
19
+ XPixelsPerMeter = 5669
20
+ YPixelsPerMeter = 5669
21
+ )
22
+ {TIFF} = dict(
23
+ ResolutionUnit = 2
24
+ XResolution = 144
25
+ YResolution = 144
26
+ )
27
+ )
28
+ """
2
29
  import ctypes as ct
3
30
  import ctypes.util
4
31
  import dataclasses as dc
@@ -114,7 +141,7 @@ def cfstring_to_string(cf_string: CFStringRef) -> str:
114
141
  max_size = cf.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1
115
142
  buffer = ct.create_string_buffer(max_size)
116
143
 
117
- if success := cf.CFStringGetCString(cf_string, buffer, max_size, kCFStringEncodingUTF8): # noqa
144
+ if not (success := cf.CFStringGetCString(cf_string, buffer, max_size, kCFStringEncodingUTF8)): # noqa
118
145
  return ''
119
146
 
120
147
  return buffer.value.decode('utf-8')
@@ -142,6 +169,7 @@ class DarwinClipboardItem:
142
169
  def get_darwin_clipboard_data(
143
170
  *,
144
171
  types: ta.Container[str | None] | None = None,
172
+ skip_types: ta.Container[str | None] | None = None,
145
173
  strict: bool = False,
146
174
  types_only: bool = False,
147
175
  ) -> list[DarwinClipboardItem]:
@@ -179,6 +207,8 @@ def get_darwin_clipboard_data(
179
207
 
180
208
  if types is not None and data_type_str not in types:
181
209
  continue
210
+ if skip_types is not None and data_type_str in skip_types:
211
+ continue
182
212
 
183
213
  if types_only:
184
214
  lst.append(DarwinClipboardItem(
@@ -188,10 +218,14 @@ def get_darwin_clipboard_data(
188
218
  continue
189
219
 
190
220
  data = CFDataRef()
221
+
222
+ # FIXME: dumps to stderr lol:
223
+ # data_type_str = 'public.heics'
191
224
  if status := aps.PasteboardCopyItemFlavorData(pasteboard, item_id, data_type, ct.byref(data)):
192
225
  if not strict:
193
226
  continue
194
227
  raise StatusDarwinClipboardError('PasteboardCopyItemFlavorData', status)
228
+
195
229
  if not data:
196
230
  continue
197
231
 
@@ -221,8 +255,8 @@ def get_darwin_clipboard_data(
221
255
 
222
256
 
223
257
  def _main() -> None:
224
- for i in get_darwin_clipboard_data():
225
- print(i)
258
+ for i in get_darwin_clipboard_data(skip_types={'public.heics'}):
259
+ print(f'type: {i.type}, len: {len(i.data) if i.data is not None else None}')
226
260
 
227
261
 
228
262
  if __name__ == '__main__':
@@ -1 +0,0 @@
1
- # @omlish-lite
@@ -0,0 +1,82 @@
1
+ """
2
+ NOTE: This cannot be auto-imported as @omlish-lite usage of other modules in this package requires it be importable on
3
+ 8.
4
+ """
5
+ import dataclasses as dc
6
+ import typing as ta
7
+
8
+ from omlish import lang
9
+ from omlish import marshal as msh
10
+ from omlish import matchfns as mfs
11
+ from omlish import reflect as rfl
12
+
13
+ from .requires import RequiresMarkerItem
14
+ from .requires import RequiresMarkerList
15
+ from .requires import RequiresNode
16
+ from .requires import RequiresOp
17
+ from .requires import RequiresValue
18
+ from .requires import RequiresVariable
19
+
20
+
21
+ ##
22
+
23
+
24
+ class MarshalRequiresMarkerList(lang.NotInstantiable, lang.Final):
25
+ pass
26
+
27
+
28
+ @dc.dataclass(frozen=True)
29
+ class RequiresMarkerListMarshaler(msh.Marshaler):
30
+ item_m: msh.Marshaler
31
+ node_m: msh.Marshaler
32
+
33
+ def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
34
+ def inner(c: ta.Any) -> ta.Any:
35
+ if isinstance(c, str):
36
+ return c
37
+ elif isinstance(c, RequiresMarkerItem):
38
+ return self.item_m.marshal(ctx, c)
39
+ elif isinstance(c, ta.Iterable):
40
+ return [inner(e) for e in c]
41
+ else:
42
+ raise TypeError(c)
43
+ return [inner(e) for e in o]
44
+
45
+
46
+ class RequiresMarkerListMarshalerFactory(msh.MarshalerFactoryMatchClass):
47
+ @mfs.simple(lambda _, ctx, rty: rty is MarshalRequiresMarkerList)
48
+ def _build(self, ctx: msh.MarshalContext, rty: rfl.Type) -> msh.Marshaler:
49
+ return RequiresMarkerListMarshaler(
50
+ ctx.make(RequiresMarkerItem),
51
+ ctx.make(RequiresNode),
52
+ )
53
+
54
+
55
+ ##
56
+
57
+
58
+ @lang.static_init
59
+ def _install_standard_marshalling() -> None:
60
+ requires_node_poly = msh.Polymorphism(
61
+ RequiresNode,
62
+ [
63
+ msh.Impl(RequiresVariable, 'variable'),
64
+ msh.Impl(RequiresValue, 'value'),
65
+ msh.Impl(RequiresOp, 'op'),
66
+ ],
67
+ )
68
+ msh.STANDARD_MARSHALER_FACTORIES[0:0] = [
69
+ msh.PolymorphismMarshalerFactory(requires_node_poly),
70
+ msh.PolymorphismUnionMarshalerFactory(requires_node_poly.impls, allow_partial=True),
71
+ RequiresMarkerListMarshalerFactory(),
72
+
73
+ ]
74
+ msh.STANDARD_UNMARSHALER_FACTORIES[0:0] = [
75
+ msh.PolymorphismUnmarshalerFactory(requires_node_poly),
76
+ ]
77
+
78
+ msh.GLOBAL_REGISTRY.register(
79
+ RequiresMarkerList,
80
+ msh.ReflectOverride(MarshalRequiresMarkerList),
81
+ identity=True,
82
+ )
omdev/packaging/names.py CHANGED
@@ -1,3 +1,4 @@
1
+ # @omlish-lite
1
2
  # Copyright (c) Donald Stufft and individual contributors.
2
3
  # All rights reserved.
3
4
  #
@@ -1,3 +1,4 @@
1
+ # @omlish-lite
1
2
  # Copyright (c) Donald Stufft and individual contributors.
2
3
  # All rights reserved.
3
4
  #
@@ -194,10 +195,9 @@ class RequiresTokenizer:
194
195
  self.read()
195
196
 
196
197
 
198
+ @dc.dataclass(frozen=True)
197
199
  class RequiresNode:
198
- def __init__(self, value: str) -> None:
199
- super().__init__()
200
- self.value = value
200
+ value: str
201
201
 
202
202
  def __str__(self) -> str:
203
203
  return self.value
@@ -209,27 +209,36 @@ class RequiresNode:
209
209
  raise NotImplementedError
210
210
 
211
211
 
212
+ @dc.dataclass(frozen=True)
212
213
  class RequiresVariable(RequiresNode):
213
214
  def serialize(self) -> str:
214
215
  return str(self)
215
216
 
216
217
 
218
+ @dc.dataclass(frozen=True)
217
219
  class RequiresValue(RequiresNode):
218
220
  def serialize(self) -> str:
219
221
  return f'"{self}"'
220
222
 
221
223
 
224
+ @dc.dataclass(frozen=True)
222
225
  class RequiresOp(RequiresNode):
223
226
  def serialize(self) -> str:
224
227
  return str(self)
225
228
 
226
229
 
227
230
  RequiresMarkerVar = ta.Union['RequiresVariable', 'RequiresValue']
228
- RequiresMarkerItem = ta.Tuple['RequiresMarkerVar', 'RequiresOp', 'RequiresMarkerVar']
231
+
229
232
  RequiresMarkerAtom = ta.Union['RequiresMarkerItem', ta.Sequence['RequiresMarkerAtom']]
230
233
  RequiresMarkerList = ta.Sequence[ta.Union['RequiresMarkerList', 'RequiresMarkerAtom', str]]
231
234
 
232
235
 
236
+ class RequiresMarkerItem(ta.NamedTuple):
237
+ l: ta.Union[RequiresVariable, RequiresValue]
238
+ op: RequiresOp
239
+ r: ta.Union[RequiresVariable, RequiresValue]
240
+
241
+
233
242
  class ParsedRequirement(ta.NamedTuple):
234
243
  name: str
235
244
  url: str
@@ -441,7 +450,7 @@ def _parse_requires_marker_item(tokenizer: RequiresTokenizer) -> RequiresMarkerI
441
450
  tokenizer.consume('WS')
442
451
  marker_var_right = _parse_requires_marker_var(tokenizer)
443
452
  tokenizer.consume('WS')
444
- return (marker_var_left, marker_op, marker_var_right)
453
+ return RequiresMarkerItem(marker_var_left, marker_op, marker_var_right)
445
454
 
446
455
 
447
456
  def _parse_requires_marker_var(tokenizer: RequiresTokenizer) -> RequiresMarkerVar:
@@ -1,3 +1,4 @@
1
+ # @omlish-lite
1
2
  # Copyright (c) Donald Stufft and individual contributors.
2
3
  # All rights reserved.
3
4
  #
@@ -1,3 +1,4 @@
1
+ # @omlish-lite
1
2
  # Copyright (c) Donald Stufft and individual contributors.
2
3
  # All rights reserved.
3
4
  #
omdev/ptk/apps/ncdu.py CHANGED
@@ -69,10 +69,14 @@ class NcduApp:
69
69
 
70
70
  self._kb = ptk.KeyBindings()
71
71
  self._kb.add('q')(self.exit_app)
72
- self._kb.add('up', 'p')(self.move_up)
73
- self._kb.add('down', 'n')(self.move_down)
74
- self._kb.add('right', 'enter')(self.enter_directory)
75
- self._kb.add('left', 'backspace')(self.go_back)
72
+ for k in ['up', 'p']:
73
+ self._kb.add(k)(self.move_up)
74
+ for k in ['down', 'n']:
75
+ self._kb.add(k)(self.move_down)
76
+ for k in ['right', 'enter']:
77
+ self._kb.add(k)(self.enter_directory)
78
+ for k in ['left', 'backspace']:
79
+ self._kb.add(k)(self.go_back)
76
80
 
77
81
  self._layout = ptk.Layout(ptk.Frame(self._text_area))
78
82
 
File without changes
@@ -0,0 +1,11 @@
1
+ from ..cli import CliModule
2
+
3
+
4
+ # @omlish-manifest
5
+ _CLI_MODULE = CliModule('pycharm', __name__)
6
+
7
+
8
+ if __name__ == '__main__':
9
+ from .cli import _main
10
+
11
+ _main()
omdev/pycharm/cli.py ADDED
@@ -0,0 +1,94 @@
1
+ import inspect
2
+ import os.path
3
+ import subprocess
4
+ import sys
5
+ import tempfile
6
+
7
+ from omlish import argparse as ap
8
+ from omlish.diag.pycharm import get_pycharm_version
9
+
10
+
11
+ _DARWIN_OPEN_SCRIPT = """
12
+ tell application "PyCharm"
13
+ activate
14
+ open "{dir}"
15
+ end tell
16
+ return
17
+ """
18
+
19
+
20
+ _LINUX_OPEN_SCRIPT = """
21
+ # Check if PyCharm is already running
22
+ if pgrep -x "pycharm.sh" > /dev/null; then
23
+ echo "PyCharm is already running. Opening project..."
24
+
25
+ # Bring PyCharm to the foreground
26
+ wmctrl -a "PyCharm"
27
+
28
+ # Simulate the keyboard shortcut to open a new project
29
+ xdotool key --delay 100 ctrl+shift+a
30
+ xdotool type "$PROJECT_PATH"
31
+ xdotool key Return
32
+
33
+ else
34
+ echo "Starting PyCharm with project..."
35
+ nohup pycharm.sh "$PROJECT_PATH" > /dev/null 2>&1 &
36
+ fi
37
+ """
38
+
39
+
40
+ class Cli(ap.Cli):
41
+ @ap.command()
42
+ def version(self) -> None:
43
+ print(get_pycharm_version())
44
+
45
+ @ap.command(
46
+ ap.arg('python-exe'),
47
+ ap.arg('args', nargs=ap.REMAINDER),
48
+ )
49
+ def runhack(self) -> int:
50
+ if not os.path.isfile(exe := self.args.python_exe):
51
+ raise FileNotFoundError(exe)
52
+
53
+ from omlish.diag._pycharm import runhack # noqa
54
+ src = inspect.getsource(runhack)
55
+
56
+ src_file = tempfile.mktemp(__package__ + '-runhack') # noqa
57
+ with open(src_file, 'w') as f:
58
+ f.write(src)
59
+
60
+ proc = subprocess.run([exe, src_file, *self.args.args], check=False)
61
+ return proc.returncode
62
+
63
+ @ap.command(
64
+ ap.arg('dir', nargs='?'),
65
+ )
66
+ def open(self) -> None:
67
+ dir = os.path.abspath(self.args.dir or '.') # noqa
68
+
69
+ if (plat := sys.platform) == 'darwin':
70
+ if '"' in dir:
71
+ raise ValueError(dir)
72
+
73
+ scpt_src = _DARWIN_OPEN_SCRIPT.format(dir=dir)
74
+
75
+ scpt_file = tempfile.mktemp(__package__ + '-pycharm-open') # noqa
76
+ with open(scpt_file, 'w') as f:
77
+ f.write(scpt_src)
78
+
79
+ subprocess.check_call(['osascript', scpt_file])
80
+
81
+ elif plat == 'linux':
82
+ # FIXME:
83
+ raise NotImplementedError
84
+
85
+ else:
86
+ raise OSError(plat)
87
+
88
+
89
+ def _main() -> None:
90
+ Cli().call_and_exit()
91
+
92
+
93
+ if __name__ == '__main__':
94
+ _main()
omdev/scripts/execrss.py CHANGED
@@ -16,7 +16,17 @@ _CLI_MODULE = {'$omdev.cli.types.CliModule': {
16
16
 
17
17
 
18
18
  def _main() -> None:
19
- [src] = sys.argv[1:]
19
+ if len(sys.argv) == 2:
20
+ pre = None
21
+ [src] = sys.argv[1:]
22
+ elif len(sys.argv) == 3:
23
+ [pre, src] = sys.argv[1:]
24
+ else:
25
+ raise Exception('Invalid arguments')
26
+
27
+ if pre:
28
+ exec(pre)
29
+
20
30
  start = _get_rss()
21
31
  exec(src)
22
32
  end = _get_rss()
omdev/scripts/exectime.py CHANGED
@@ -12,7 +12,17 @@ _CLI_MODULE = {'$omdev.cli.types.CliModule': {
12
12
 
13
13
 
14
14
  def _main() -> None:
15
- [src] = sys.argv[1:]
15
+ if len(sys.argv) == 2:
16
+ pre = None
17
+ [src] = sys.argv[1:]
18
+ elif len(sys.argv) == 3:
19
+ [pre, src] = sys.argv[1:]
20
+ else:
21
+ raise Exception('Invalid arguments')
22
+
23
+ if pre:
24
+ exec(pre)
25
+
16
26
  co = compile(src, '<string>', 'exec')
17
27
  start = time.time_ns()
18
28
  exec(co)
@@ -3299,7 +3299,10 @@ class UuidObjMarshaler(ObjMarshaler):
3299
3299
  return uuid.UUID(o)
3300
3300
 
3301
3301
 
3302
- _OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = {
3302
+ ##
3303
+
3304
+
3305
+ _DEFAULT_OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = {
3303
3306
  **{t: NopObjMarshaler() for t in (type(None),)},
3304
3307
  **{t: CastObjMarshaler(t) for t in (int, float, str, bool)},
3305
3308
  **{t: Base64ObjMarshaler(t) for t in (bytes, bytearray)},
@@ -3328,20 +3331,19 @@ _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES: ta.Dict[ta.Any, type] = {
3328
3331
  }
3329
3332
 
3330
3333
 
3331
- def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
3332
- if ty in _OBJ_MARSHALERS:
3333
- raise KeyError(ty)
3334
- _OBJ_MARSHALERS[ty] = m
3335
-
3336
-
3337
- def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
3334
+ def _make_obj_marshaler(
3335
+ ty: ta.Any,
3336
+ rec: ta.Callable[[ta.Any], ObjMarshaler],
3337
+ *,
3338
+ nonstrict_dataclasses: bool = False,
3339
+ ) -> ObjMarshaler:
3338
3340
  if isinstance(ty, type):
3339
3341
  if abc.ABC in ty.__bases__:
3340
3342
  impls = [ # type: ignore
3341
3343
  PolymorphicObjMarshaler.Impl(
3342
3344
  ity,
3343
3345
  ity.__qualname__,
3344
- get_obj_marshaler(ity),
3346
+ rec(ity),
3345
3347
  )
3346
3348
  for ity in deep_subclasses(ty)
3347
3349
  if abc.ABC not in ity.__bases__
@@ -3357,7 +3359,8 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
3357
3359
  if dc.is_dataclass(ty):
3358
3360
  return DataclassObjMarshaler(
3359
3361
  ty,
3360
- {f.name: get_obj_marshaler(f.type) for f in dc.fields(ty)},
3362
+ {f.name: rec(f.type) for f in dc.fields(ty)},
3363
+ nonstrict=nonstrict_dataclasses,
3361
3364
  )
3362
3365
 
3363
3366
  if is_generic_alias(ty):
@@ -3367,7 +3370,7 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
3367
3370
  pass
3368
3371
  else:
3369
3372
  k, v = ta.get_args(ty)
3370
- return MappingObjMarshaler(mt, get_obj_marshaler(k), get_obj_marshaler(v))
3373
+ return MappingObjMarshaler(mt, rec(k), rec(v))
3371
3374
 
3372
3375
  try:
3373
3376
  st = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES[ta.get_origin(ty)]
@@ -3375,33 +3378,71 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
3375
3378
  pass
3376
3379
  else:
3377
3380
  [e] = ta.get_args(ty)
3378
- return IterableObjMarshaler(st, get_obj_marshaler(e))
3381
+ return IterableObjMarshaler(st, rec(e))
3379
3382
 
3380
3383
  if is_union_alias(ty):
3381
- return OptionalObjMarshaler(get_obj_marshaler(get_optional_alias_arg(ty)))
3384
+ return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
3382
3385
 
3383
3386
  raise TypeError(ty)
3384
3387
 
3385
3388
 
3386
- def get_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
3387
- try:
3388
- return _OBJ_MARSHALERS[ty]
3389
- except KeyError:
3390
- pass
3389
+ ##
3391
3390
 
3392
- p = ProxyObjMarshaler()
3393
- _OBJ_MARSHALERS[ty] = p
3394
- try:
3395
- m = _make_obj_marshaler(ty)
3396
- except Exception:
3397
- del _OBJ_MARSHALERS[ty]
3398
- raise
3399
- else:
3400
- p.m = m
3391
+
3392
+ _OBJ_MARSHALERS_LOCK = threading.RLock()
3393
+
3394
+ _OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = dict(_DEFAULT_OBJ_MARSHALERS)
3395
+
3396
+ _OBJ_MARSHALER_PROXIES: ta.Dict[ta.Any, ProxyObjMarshaler] = {}
3397
+
3398
+
3399
+ def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
3400
+ with _OBJ_MARSHALERS_LOCK:
3401
+ if ty in _OBJ_MARSHALERS:
3402
+ raise KeyError(ty)
3401
3403
  _OBJ_MARSHALERS[ty] = m
3404
+
3405
+
3406
+ def get_obj_marshaler(
3407
+ ty: ta.Any,
3408
+ *,
3409
+ no_cache: bool = False,
3410
+ **kwargs: ta.Any,
3411
+ ) -> ObjMarshaler:
3412
+ with _OBJ_MARSHALERS_LOCK:
3413
+ if not no_cache:
3414
+ try:
3415
+ return _OBJ_MARSHALERS[ty]
3416
+ except KeyError:
3417
+ pass
3418
+
3419
+ try:
3420
+ return _OBJ_MARSHALER_PROXIES[ty]
3421
+ except KeyError:
3422
+ pass
3423
+
3424
+ rec = functools.partial(
3425
+ get_obj_marshaler,
3426
+ no_cache=no_cache,
3427
+ **kwargs,
3428
+ )
3429
+
3430
+ p = ProxyObjMarshaler()
3431
+ _OBJ_MARSHALER_PROXIES[ty] = p
3432
+ try:
3433
+ m = _make_obj_marshaler(ty, rec, **kwargs)
3434
+ finally:
3435
+ del _OBJ_MARSHALER_PROXIES[ty]
3436
+ p.m = m
3437
+
3438
+ if not no_cache:
3439
+ _OBJ_MARSHALERS[ty] = m
3402
3440
  return m
3403
3441
 
3404
3442
 
3443
+ ##
3444
+
3445
+
3405
3446
  def marshal_obj(o: ta.Any, ty: ta.Any = None) -> ta.Any:
3406
3447
  return get_obj_marshaler(ty if ty is not None else type(o)).marshal(o)
3407
3448
 
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+ # @omlish-script
3
+ """
4
+ TODO:
5
+ - can xargs just do this lol
6
+ """
7
+ import argparse
8
+ import os
9
+ import subprocess
10
+ import sys
11
+ import tempfile
12
+
13
+
14
+ def _main() -> None:
15
+ parser = argparse.ArgumentParser()
16
+ parser.add_argument('-I', '--replstr', default='%')
17
+ parser.add_argument('-Q', '--stdout-silenced', action='store_true')
18
+ parser.add_argument('-E', '--stdout-to-stderr', action='store_true')
19
+ parser.add_argument('-c', '--cat', action='store_true')
20
+ parser.add_argument('-k', '--keep', action='store_true')
21
+ parser.add_argument('--read-size', type=int, default=0x4000)
22
+ args, rest = parser.parse_known_args()
23
+
24
+ fd, tmp_file = tempfile.mkstemp()
25
+ os.close(fd)
26
+
27
+ argv = [tmp_file if a == args.replstr else a for a in rest]
28
+
29
+ kw: dict = {}
30
+ if args.stdout_silenced:
31
+ kw.update(stdout=open('/dev/null', 'wb')) # noqa
32
+ elif args.stdout_to_stderr:
33
+ kw.update(stdout=sys.stderr)
34
+
35
+ subprocess.check_call(argv, **kw)
36
+
37
+ if args.cat:
38
+ try:
39
+ with open(tmp_file, 'rb') as f:
40
+ while buf := f.read(args.read_size):
41
+ sys.stdout.buffer.write(buf)
42
+ finally:
43
+ if not args.keep:
44
+ os.unlink(tmp_file)
45
+
46
+ else:
47
+ print(tmp_file)
48
+
49
+
50
+ # @omlish-manifest
51
+ _CLI_MODULE = {'$omdev.cli.types.CliModule': {
52
+ 'cmd_name': 'tmpexec',
53
+ 'mod_name': __name__,
54
+ }}
55
+
56
+
57
+ if __name__ == '__main__':
58
+ _main()
omdev/tools/git.py CHANGED
@@ -61,38 +61,42 @@ class Cli(ap.Cli):
61
61
  accepts_unknown=True,
62
62
  )
63
63
  def clone(self) -> None:
64
- out_dir: str
65
-
66
- if (m := self._GITHUB_PAT.fullmatch(self.args.repo)):
67
- user = m.group('user')
68
- repo = m.group('repo')
69
-
70
- os.makedirs(user, 0o755, exist_ok=True)
71
-
72
- subprocess.check_call([
73
- 'git',
74
- 'clone',
75
- *self.unknown_args,
76
- *self.args.args,
77
- f'https://github.com/{user}/{repo}.git',
78
- os.path.join(user, repo),
79
- ])
80
-
81
- out_dir = os.path.join(user, repo)
82
-
83
- else:
84
- parsed = urllib.parse.urlparse(self.args.repo)
85
- out_dir = parsed.path.split('/')[-1]
86
-
87
- subprocess.check_call([
88
- 'git',
89
- 'clone',
90
- *self.unknown_args,
91
- *self.args.args,
92
- self.args.repo,
93
- ])
94
-
95
- print(out_dir)
64
+ # And expected usage is `cd $(om git clone foo/bar)` and an empty cd arg will return to the previous directory,
65
+ # so always output at least a . so it'll cd to the current dir at least lol - it still runs even if the proc
66
+ # fails.
67
+ out_dir = '.'
68
+ try:
69
+ if (m := self._GITHUB_PAT.fullmatch(self.args.repo)):
70
+ user = m.group('user')
71
+ repo = m.group('repo')
72
+
73
+ os.makedirs(user, 0o755, exist_ok=True)
74
+
75
+ subprocess.check_call([
76
+ 'git',
77
+ 'clone',
78
+ *self.unknown_args,
79
+ *self.args.args,
80
+ f'git@github.com:{user}/{repo}.git',
81
+ os.path.join(user, repo),
82
+ ])
83
+
84
+ out_dir = os.path.join(user, repo)
85
+
86
+ else:
87
+ parsed = urllib.parse.urlparse(self.args.repo)
88
+ out_dir = parsed.path.split('/')[-1]
89
+
90
+ subprocess.check_call([
91
+ 'git',
92
+ 'clone',
93
+ *self.unknown_args,
94
+ *self.args.args,
95
+ self.args.repo,
96
+ ])
97
+
98
+ finally:
99
+ print(out_dir)
96
100
 
97
101
  @ap.command(
98
102
  ap.arg('rev', nargs='?', default='HEAD'),
omdev/tools/pip.py CHANGED
@@ -1,18 +1,35 @@
1
+ """
2
+ TODO:
3
+ - https://github.com/pypa/pip/blob/420435903ff2fc694d6950a47b896427ecaed78f/src/pip/_internal/req/req_file.py ?
4
+ """
5
+ import contextlib
1
6
  import importlib.metadata
2
7
  import io
8
+ import os.path
3
9
  import sys
10
+ import typing as ta
4
11
  import urllib.request
5
- import xml.etree.ElementTree as ET # noqa
6
12
 
7
13
  from omlish import argparse as ap
8
14
  from omlish import check
15
+ from omlish import lang
16
+ from omlish import marshal as msh
17
+ from omlish.formats import json
9
18
 
10
19
  from ..cli import CliModule
20
+ from ..packaging import marshal as _ # noqa
11
21
  from ..packaging.names import canonicalize_name
22
+ from ..packaging.requires import ParsedRequirement
12
23
  from ..packaging.requires import RequiresVariable
13
24
  from ..packaging.requires import parse_requirement
14
25
 
15
26
 
27
+ if ta.TYPE_CHECKING:
28
+ import xml.etree.ElementTree as ET # noqa
29
+ else:
30
+ ET = lang.proxy_import('xml.etree.ElementTree')
31
+
32
+
16
33
  PYPI_URL = 'https://pypi.org/'
17
34
 
18
35
 
@@ -84,6 +101,65 @@ class Cli(ap.Cli):
84
101
  if not uses_by_req.get(d):
85
102
  print(d)
86
103
 
104
+ @ap.command(
105
+ ap.arg('files', nargs='*'),
106
+ ap.arg('-r', '--follow-requirements', action='store_true'),
107
+ ap.arg('-j', '--json', action='store_true'),
108
+ ap.arg('-b', '--bare', action='store_true'),
109
+ )
110
+ def parse(self) -> None:
111
+ def print_req(req: ParsedRequirement) -> None:
112
+ if self.args.json:
113
+ req_m = msh.marshal(req)
114
+ print(json.dumps(req_m))
115
+
116
+ elif self.args.bare:
117
+ print(req.name)
118
+
119
+ else:
120
+ print(f'{req.name}{req.specifier or ""}')
121
+
122
+ #
123
+
124
+ seen_files: set[str] = set()
125
+
126
+ def do_file(file: ta.TextIO | str) -> None:
127
+ if isinstance(file, str) and file in seen_files:
128
+ return
129
+
130
+ with contextlib.ExitStack() as es:
131
+ f: ta.TextIO
132
+ if isinstance(file, str):
133
+ f = es.enter_context(open(file))
134
+ else:
135
+ f = file
136
+
137
+ for l in f:
138
+ if '#' in l:
139
+ l = l.partition('#')[0]
140
+
141
+ if not (l := l.strip()):
142
+ continue
143
+
144
+ if l.startswith('git+'):
145
+ continue # FIXME
146
+
147
+ elif l.startswith('-r'): # noqa
148
+ if self.args.follow_requirements:
149
+ base_dir = os.path.dirname(file) if isinstance(file, str) else '.'
150
+ r_file = os.path.join(base_dir, l[2:].strip())
151
+ do_file(r_file)
152
+
153
+ else:
154
+ req = parse_requirement(l)
155
+ print_req(req)
156
+
157
+ if self.args.files:
158
+ for file in self.args.files:
159
+ do_file(file)
160
+ else:
161
+ do_file(sys.stdin)
162
+
87
163
 
88
164
  # @omlish-manifest
89
165
  _CLI_MODULE = CliModule('pip', __name__)
omdev/tools/qr.py ADDED
@@ -0,0 +1,79 @@
1
+ """
2
+ https://segno.readthedocs.io/en/stable/comparison-qrcode-libs.html
3
+ - https://github.com/nayuki/QR-Code-generator
4
+ - https://github.com/heuer/segno/
5
+ - https://github.com/lincolnloop/python-qrcode
6
+ """
7
+ import argparse
8
+ import os
9
+ import subprocess
10
+ import sys
11
+ import tempfile
12
+ import typing as ta
13
+
14
+ from omlish import lang
15
+
16
+ from ..cli import CliModule
17
+
18
+
19
+ if ta.TYPE_CHECKING:
20
+ import segno
21
+ else:
22
+ segno = lang.proxy_import('segno')
23
+
24
+
25
+ def _main() -> None:
26
+ parser = argparse.ArgumentParser()
27
+ parser.add_argument('content', nargs='?')
28
+
29
+ parser.add_argument('-x', '--target-size', type=int)
30
+
31
+ parser.add_argument('-o', '--output')
32
+ parser.add_argument('-O', '--open', action='store_true')
33
+
34
+ parser.add_argument(
35
+ '--error', '-e',
36
+ help=(
37
+ 'Error correction level: '
38
+ '"L": 7%% (default), '
39
+ '"M": 15%%, '
40
+ '"Q": 25%%, '
41
+ '"H": 30%%, '
42
+ '"-": no error correction (used for M1 symbols)'
43
+ ),
44
+ choices=('L', 'M', 'Q', 'H', '-'),
45
+ )
46
+ args = parser.parse_args()
47
+
48
+ if (content := args.content) is None:
49
+ content = sys.stdin.read()
50
+
51
+ qr = segno.make(content)
52
+
53
+ if (tx := args.target_size) is not None:
54
+ sz = max(*qr.symbol_size())
55
+ sc = max(float(tx) / sz, 1)
56
+ else:
57
+ sc = 1
58
+
59
+ if args.output is not None:
60
+ out_file = args.output
61
+ else:
62
+ fd, out_file = tempfile.mkstemp(suffix='-qrcode.png')
63
+ os.close(fd)
64
+
65
+ qr.save(out_file, scale=sc)
66
+
67
+ if args.output is None:
68
+ print(out_file)
69
+
70
+ if args.open:
71
+ subprocess.check_call(['open', out_file])
72
+
73
+
74
+ # @omlish-manifest
75
+ _CLI_MODULE = CliModule('qr', __name__)
76
+
77
+
78
+ if __name__ == '__main__':
79
+ _main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omdev
3
- Version: 0.0.0.dev103
3
+ Version: 0.0.0.dev112
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omlish ==0.0.0.dev103
15
+ Requires-Dist: omlish ==0.0.0.dev112
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black ~=24.10 ; extra == 'all'
18
18
  Requires-Dist: pycparser ~=2.22 ; extra == 'all'
@@ -23,6 +23,7 @@ Requires-Dist: markdown ~=3.7 ; extra == 'all'
23
23
  Requires-Dist: mypy ~=1.11 ; extra == 'all'
24
24
  Requires-Dist: gprof2dot ~=2024.6 ; extra == 'all'
25
25
  Requires-Dist: prompt-toolkit ~=3.0 ; extra == 'all'
26
+ Requires-Dist: segno ~=1.6 ; extra == 'all'
26
27
  Requires-Dist: tokenize-rt ~=6.1 ; extra == 'all'
27
28
  Requires-Dist: wheel ~=0.44 ; extra == 'all'
28
29
  Provides-Extra: black
@@ -40,6 +41,8 @@ Provides-Extra: prof
40
41
  Requires-Dist: gprof2dot ~=2024.6 ; extra == 'prof'
41
42
  Provides-Extra: ptk
42
43
  Requires-Dist: prompt-toolkit ~=3.0 ; extra == 'ptk'
44
+ Provides-Extra: qr
45
+ Requires-Dist: segno ~=1.6 ; extra == 'qr'
43
46
  Provides-Extra: tokens
44
47
  Requires-Dist: tokenize-rt ~=6.1 ; extra == 'tokens'
45
48
  Provides-Extra: wheel
@@ -1,5 +1,5 @@
1
- omdev/.manifests.json,sha256=6bX1vHV-8UNBIU0fZFolH1APIB10SV3edD3Mejk3-R4,6713
2
- omdev/__about__.py,sha256=ON7EnhbxbwLsMj60wkd9OEYPloXZ7jmnMMzeLg44LXY,1225
1
+ omdev/.manifests.json,sha256=CttiykwDkNVtWsqk7xCLY0o7eUxPVTJvfS5enx6xg5g,7479
2
+ omdev/__about__.py,sha256=n5x-SO70OgbDQFzQ1d7sZDVMsnkQc4PxQZPFaIQFa0E,1281
3
3
  omdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  omdev/bracepy.py,sha256=I8EdqtDvxzAi3I8TuMEW-RBfwXfqKbwp06CfOdj3L1o,2743
5
5
  omdev/classdot.py,sha256=YOvgy6x295I_8NKBbBlRVd3AN7Osirm_Lqt4Wj0j9rY,1631
@@ -67,7 +67,7 @@ omdev/cli/managers.py,sha256=BV98_n30Jj63OJrFgRoVZRfICxMLXEZKoEn4rMj9LV4,1160
67
67
  omdev/cli/types.py,sha256=bqKw9SbtBtAip2vF9v4khh0CqKG6LBr6n9VzWBz7AJE,474
68
68
  omdev/clipboard/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
69
  omdev/clipboard/clipboard.py,sha256=CmnozkRljJ9UQDHLfCS8wKU0Xg-HfbsAkagAfMEias0,567
70
- omdev/clipboard/darwin.py,sha256=Nq4SsAEJdIof_mgMTderdeQyuiyI0hlHUxVuom4YAcE,6415
70
+ omdev/clipboard/darwin.py,sha256=zKPmI4mdTTo5ixbOVIBt6OnZE6BrpXgTPf0Tgz_-ds0,7556
71
71
  omdev/interp/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
72
72
  omdev/interp/__main__.py,sha256=GMCqeGYltgt5dlJzHxY9gqisa8cRkrPfmZYuZnjg4WI,162
73
73
  omdev/interp/cli.py,sha256=sh7PZQoLletUViw1Y9OXNr9ekyNZ6YyxYuOQ_n9hyqU,2072
@@ -89,11 +89,12 @@ omdev/manifests/load.py,sha256=LtEsluDdd8CkNGj0QGBxee3twBn095Fru0xz2mtr7uk,4788
89
89
  omdev/manifests/types.py,sha256=Jv6PAdVLPb9Hh4y6vDhPlWuMNBBViin1bC_u83jfsH4,234
90
90
  omdev/mypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
91
  omdev/mypy/debug.py,sha256=WcZw-3Z1njg_KFGqi3DB6RuqbBa3dLArJnjVCuY1Mn0,3003
92
- omdev/packaging/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
93
- omdev/packaging/names.py,sha256=lwws9dgClio0_-w6fZcihOKxx4FPkrHUxum918KjZO8,2513
94
- omdev/packaging/requires.py,sha256=VQ-rRDK4_w2R-0xMTbLCwhvZwkO-qgS8uEMbRhNmfOw,15598
95
- omdev/packaging/specifiers.py,sha256=6Odf9e6farwlPRsD_YqwTfYKG-BXn_dIcKtqfkhfodI,17432
96
- omdev/packaging/versions.py,sha256=ei2eopEsJq3zSMJmezK1nzZgikgCdxFtnF3f69nCRZQ,12246
92
+ omdev/packaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
93
+ omdev/packaging/marshal.py,sha256=mWRuZ_okYxRJXylKFQLQpC8Pp7xjkUEfWYNzQIS5A2c,2376
94
+ omdev/packaging/names.py,sha256=-a7AykFPVR1i6EYJepbe3ABRrZQ_tPPmK5olzbn9HLI,2528
95
+ omdev/packaging/requires.py,sha256=kyyVCM0RyaKqmXd6tU5zf0QjWvCLQMNV_ev5hvOee_o,15731
96
+ omdev/packaging/specifiers.py,sha256=X8xOcwRLXTQYx5mYAS3ijqoTLlCtYESyUu4fX9bvblY,17447
97
+ omdev/packaging/versions.py,sha256=K4eUOUvLmYcR4aeUywekeWTBqAvZchrIxLf7dl07MS4,12261
97
98
  omdev/precheck/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
99
  omdev/precheck/__main__.py,sha256=UEuS4z5-heIrwTtB-ONe1KeXJdqj8tYXMqWMpuO10so,165
99
100
  omdev/precheck/base.py,sha256=a_lGoFM-QhL8u8XDUYFhb-feEyfPbP4j8lcmNO51sHY,732
@@ -104,7 +105,10 @@ omdev/precheck/manifests.py,sha256=YfXqt6u0hlFXY0QkBMec6V_6Y9T4eCVAmrJDkQkB13U,7
104
105
  omdev/precheck/scripts.py,sha256=Xw9kkQzlDd_2V9av9qlaNpNZG9jZdy3TTo7x60MeR2I,1273
105
106
  omdev/ptk/__init__.py,sha256=StAwXQ96e8Xkkg7ciR9oBBhcSgqHT76vhoZML82BuY0,447
106
107
  omdev/ptk/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
107
- omdev/ptk/apps/ncdu.py,sha256=m66lMUGuvmFSdpt1tLflvugSHUz-yWbIAKtTLSCcxow,4444
108
+ omdev/ptk/apps/ncdu.py,sha256=dOkEJoc2Wjv1u_Uge7Vpei_LvXldoPP5833Eia355tc,4548
109
+ omdev/pycharm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
110
+ omdev/pycharm/__main__.py,sha256=hUPp11D024eMdT86BxXiRVtF7AGBk5W6Zn8_mEHSksY,163
111
+ omdev/pycharm/cli.py,sha256=XDR3fYUnGdK2oys3IKs7QrGbYwXUiMba16DNXdMVlAA,2209
108
112
  omdev/pyproject/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
109
113
  omdev/pyproject/__main__.py,sha256=gn3Rl1aYPYdiTtEqa9ifi0t-e4ZwPY0vhJ4UXvYdJDY,165
110
114
  omdev/pyproject/cexts.py,sha256=x13piOOnNrYbA17qZLDVuR0p1sqhgEwpk4FtImX-klM,4281
@@ -114,31 +118,33 @@ omdev/pyproject/pkg.py,sha256=WB9k3zEpHSAR24H09kikgAnLMWUz-bk9f0aB-2L_ITw,14560
114
118
  omdev/pyproject/reqs.py,sha256=8feZ71YnGzwKbLK4zO28CDQeNcZIIuq6cnkBhs6M-7E,2406
115
119
  omdev/scripts/__init__.py,sha256=MKCvUAEQwsIvwLixwtPlpBqmkMXLCnjjXyAXvVpDwVk,91
116
120
  omdev/scripts/bumpversion.py,sha256=Kn7fo73Hs8uJh3Hi3EIyLOlzLPWAC6dwuD_lZ3cIzuY,1064
117
- omdev/scripts/execrss.py,sha256=hJTWBig_-XqKIj1DphYTfeVDtdQTM1XUl-Hvzs2x9iY,451
118
- omdev/scripts/exectime.py,sha256=dBdn3KV2jR6tCrzGvb9dTl2uGe2vNpLxmHMtExmnaiM,410
121
+ omdev/scripts/execrss.py,sha256=mR0G0wERBYtQmVIn63lCIIFb5zkCM6X_XOENDFYDBKc,651
122
+ omdev/scripts/exectime.py,sha256=sFb376GflU6s9gNX-2-we8hgH6w5MuQNS9g6i4SqJIo,610
119
123
  omdev/scripts/importtrace.py,sha256=Jbo3Yk2RAbE8_tJ97iTcVNpoxCJxrRb2tl1W_CV3NG0,14067
120
124
  omdev/scripts/interp.py,sha256=U6mU2RPZjwcBhn4Vl4SrAyDUFcf7bBxBnPY5FHCxosw,72496
121
- omdev/scripts/pyproject.py,sha256=pRQuKcHasQjnO5_Pmx6hLDagujWxJ7de8Ux7Ml4mYpE,164742
125
+ omdev/scripts/pyproject.py,sha256=RNWsO9-cu6MUXuWFT1Y200euUu6WcAC4orwGEUoGVWA,165526
122
126
  omdev/scripts/slowcat.py,sha256=lssv4yrgJHiWfOiHkUut2p8E8Tq32zB-ujXESQxFFHY,2728
127
+ omdev/scripts/tmpexec.py,sha256=WTYcf56Tj2qjYV14AWmV8SfT0u6Y8eIU6cKgQRvEK3c,1442
123
128
  omdev/toml/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
124
129
  omdev/toml/parser.py,sha256=84bn09uhYHwQGyfww6Rw6y1RxPAE_HDltODOSakcqDM,29186
125
130
  omdev/toml/writer.py,sha256=lk3on3YXVbWuLJa-xsOzOhs1bBAT1vXqw4mBbluZl_w,3040
126
131
  omdev/tools/__init__.py,sha256=iVJAOQ0viGTQOm0DLX4uZLro-9jOioYJGLg9s0kDx1A,78
127
132
  omdev/tools/doc.py,sha256=mv9XfitzqXl3vFHSenv01xHCxWf8g03rUAb_sqoty98,2556
128
133
  omdev/tools/docker.py,sha256=k2BrVvFYwyGov064CPHd_HWo9aqR1zHc2UeEsVwPth4,6827
129
- omdev/tools/git.py,sha256=1Oa2AgdZIJZ2eusso9yFzkd9zLWH3d4lTiVFzwg0uDM,3808
134
+ omdev/tools/git.py,sha256=IARrfL9R9BHpmTBia3svbPeCzf_4qlCCbOsLpohsfUI,4184
130
135
  omdev/tools/importscan.py,sha256=QeGjR3UGcuuuDUiisFuAXWHlcKJScGxGEcU6tfOh2CM,4069
131
136
  omdev/tools/mkrelimp.py,sha256=wsJAjTIf3nqcSfnT9TkDpS1VUOoM9W2Az5tZdWuzyLM,4054
132
137
  omdev/tools/notebook.py,sha256=M8Xi_gfZdlahnyFLtp0RBgYZPSHWQStMMDYZc71Zync,3494
133
- omdev/tools/pip.py,sha256=-jR5q3w4sHqntxCLExFCBNIARB788FUsAbJ62PK2sBU,2774
138
+ omdev/tools/pip.py,sha256=_O7WAACQ1F1ffH4ogZHcppT4P8VQxWQchJMLn9FvsJc,5073
134
139
  omdev/tools/prof.py,sha256=8ZU9x_Dq8eT2ZFwU9sJpDIvxcIn9qBc8y2ELKPb5e5M,1382
140
+ omdev/tools/qr.py,sha256=tm68lPwEAkEwIL2sUKPKBYfwwPtjVWG1DBZwur8_jY8,1737
135
141
  omdev/tools/sqlrepl.py,sha256=tmFZh80-xsGM62dyQ7_UGLebChrj7IHbIPYBWDJMgVk,5741
136
142
  omdev/tools/pawk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
143
  omdev/tools/pawk/__main__.py,sha256=VCqeRVnqT1RPEoIrqHFSu4PXVMg4YEgF4qCQm90-eRI,66
138
144
  omdev/tools/pawk/pawk.py,sha256=Eckymn22GfychCQcQi96BFqRo_LmiJ-EPhC8TTUJdB4,11446
139
- omdev-0.0.0.dev103.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
140
- omdev-0.0.0.dev103.dist-info/METADATA,sha256=-uMabB38BqYSy4Z2f78X6mYDUIkzwGM-0pLcTc-L7fc,1704
141
- omdev-0.0.0.dev103.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
142
- omdev-0.0.0.dev103.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
143
- omdev-0.0.0.dev103.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
144
- omdev-0.0.0.dev103.dist-info/RECORD,,
145
+ omdev-0.0.0.dev112.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
146
+ omdev-0.0.0.dev112.dist-info/METADATA,sha256=VeCQ5RyISLmbtXUOxqiBvvzJW3kHbcsb8l6KjNrg0C8,1810
147
+ omdev-0.0.0.dev112.dist-info/WHEEL,sha256=a7TGlA-5DaHMRrarXjVbQagU3Man_dCnGIWMJr5kRWo,91
148
+ omdev-0.0.0.dev112.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
149
+ omdev-0.0.0.dev112.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
150
+ omdev-0.0.0.dev112.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5