omdev 0.0.0.dev89__py3-none-any.whl → 0.0.0.dev91__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.

omdev/__about__.py CHANGED
@@ -34,8 +34,12 @@ class Project(ProjectBase):
34
34
  'gprof2dot ~= 2024.6',
35
35
  ],
36
36
 
37
+ 'prompttoolkit': [
38
+ 'prompt-toolkit ~= 3.0',
39
+ ],
40
+
37
41
  'tokens': [
38
- 'tokenize_rt ~= 6.1',
42
+ 'tokenize-rt ~= 6.1',
39
43
  ],
40
44
 
41
45
  'wheel': [
omdev/cli/_pathhack.py CHANGED
@@ -7,20 +7,33 @@ problematic empty string is added, so a sys.meta_path hook is prepended.
7
7
 
8
8
  See:
9
9
  https://github.com/python/cpython/blob/da1e5526aee674bb33c17a498aa3781587b9850c/Python/sysmodule.c#L3939
10
+ https://github.com/python/cpython/blob/db0a1b8c1291bf1aa9e016e43bc2f7ed0acf83bd/Modules/getpath.py
11
+ https://github.com/python/cpython/blob/db0a1b8c1291bf1aa9e016e43bc2f7ed0acf83bd/Modules/getpath.c
12
+ https://github.com/python/cpython/blob/db0a1b8c1291bf1aa9e016e43bc2f7ed0acf83bd/Doc/library/sys_path_init.rst
10
13
  """
11
14
  import os.path
12
15
  import site
13
16
  import sys
14
17
 
15
18
 
16
- def _remove_empty_from_sys_path() -> None:
17
- while '' in sys.path:
18
- sys.path.remove('')
19
-
20
-
21
19
  class _PathHackMetaFinder:
20
+ def __init__(
21
+ self,
22
+ removed_paths=None, # type: list[str] | None
23
+ ) -> None:
24
+ super().__init__()
25
+ if removed_paths is None:
26
+ removed_paths = ['', '.', os.getcwd()]
27
+ self._removed_paths = removed_paths
28
+ self.remove_paths()
29
+
30
+ def remove_paths(self) -> None:
31
+ for p in self._removed_paths:
32
+ while p in sys.path:
33
+ sys.path.remove(p)
34
+
22
35
  def find_spec(self, fullname, path, target=None):
23
- _remove_empty_from_sys_path()
36
+ self.remove_paths()
24
37
  return None # noqa
25
38
 
26
39
 
@@ -0,0 +1,11 @@
1
+ # ruff: noqa: F401
2
+ # flake8: noqa: F401
3
+
4
+ from prompt_toolkit import Application
5
+ from prompt_toolkit.key_binding import KeyBindings
6
+ from prompt_toolkit.key_binding import KeyPressEvent
7
+ from prompt_toolkit.layout import Layout
8
+ from prompt_toolkit.layout.containers import Window
9
+ from prompt_toolkit.styles import Style
10
+ from prompt_toolkit.widgets import Frame
11
+ from prompt_toolkit.widgets import TextArea
File without changes
@@ -0,0 +1,140 @@
1
+ import dataclasses as dc
2
+ import os
3
+ import typing as ta
4
+
5
+ from omlish.lite.strings import format_num_bytes
6
+
7
+ from ... import prompttoolkit as ptk
8
+
9
+
10
+ def get_directory_size(path: str) -> int:
11
+ total_size = 0
12
+ for dirpath, _, filenames in os.walk(path):
13
+ for f in filenames:
14
+ fp = os.path.join(dirpath, f)
15
+ try:
16
+ total_size += os.path.getsize(fp)
17
+ except OSError:
18
+ pass
19
+ return total_size
20
+
21
+
22
+ @dc.dataclass(frozen=True)
23
+ class Entry:
24
+ name: str
25
+ size: int
26
+ type: ta.Literal['dir', 'file']
27
+
28
+
29
+ def scan_directory(path: str) -> list[Entry]:
30
+ entries: list[Entry] = []
31
+
32
+ with os.scandir(path) as it:
33
+ for entry in it:
34
+ if entry.is_dir(follow_symlinks=False):
35
+ size = get_directory_size(entry.path)
36
+ entries.append(Entry(entry.name + '/', size, 'dir'))
37
+
38
+ elif entry.is_file(follow_symlinks=False):
39
+ size = entry.stat().st_size
40
+ entries.append(Entry(entry.name, size, 'file'))
41
+
42
+ entries.sort(key=lambda x: x.size, reverse=True)
43
+ return entries
44
+
45
+
46
+ class NcduApp:
47
+ def __init__(self, root_path: str) -> None:
48
+ super().__init__()
49
+
50
+ self._root_path = root_path
51
+ self._current_path = root_path
52
+ self._entries = scan_directory(root_path)
53
+ self._cursor = 0
54
+
55
+ self._text_area = ptk.TextArea(focusable=True)
56
+ self.update_display()
57
+
58
+ self._kb = ptk.KeyBindings()
59
+ self._kb.add('q')(self.exit_app)
60
+ for k in ['up', 'p']:
61
+ self._kb.add(k)(self.move_up)
62
+ for k in ['down', 'n']:
63
+ self._kb.add(k)(self.move_down)
64
+ self._kb.add('enter')(self.enter_directory)
65
+ self._kb.add('backspace')(self.go_back)
66
+
67
+ self._layout = ptk.Layout(ptk.Frame(self._text_area))
68
+
69
+ self._style = ptk.Style.from_dict({
70
+ 'frame': 'bg:#008800 bold',
71
+ 'text-area': 'bg:#000000 fg:#ffffff',
72
+ })
73
+
74
+ self._app: ptk.Application = ptk.Application(
75
+ layout=self._layout,
76
+ key_bindings=self._kb,
77
+ style=self._style,
78
+ full_screen=True,
79
+ )
80
+
81
+ #
82
+
83
+ def update_display(self) -> None:
84
+ display_text = f'Current Directory: {self._current_path}\n\n'
85
+ for i, e in enumerate(self._entries):
86
+ indicator = '>' if i == self._cursor else ' '
87
+ display_text += f'{indicator} {e.name:<40} {format_num_bytes(e.size):>10}\n'
88
+ self._text_area.text = display_text
89
+
90
+ #
91
+
92
+ def move_up(self, event: ptk.KeyPressEvent) -> None:
93
+ if self._cursor > 0:
94
+ self._cursor -= 1
95
+ self.update_display()
96
+
97
+ def move_down(self, event: ptk.KeyPressEvent) -> None:
98
+ if self._cursor < len(self._entries) - 1:
99
+ self._cursor += 1
100
+ self.update_display()
101
+
102
+ def enter_directory(self, event: ptk.KeyPressEvent) -> None:
103
+ selected_entry = self._entries[self._cursor]
104
+ if selected_entry.type == 'dir':
105
+ self._current_path = os.path.join(self._current_path, selected_entry.name[:-1])
106
+ self._entries = scan_directory(self._current_path)
107
+ self._cursor = 0
108
+ self.update_display()
109
+
110
+ def go_back(self, event: ptk.KeyPressEvent) -> None:
111
+ if self._current_path != self._root_path:
112
+ self._current_path = os.path.dirname(self._current_path)
113
+ self._entries = scan_directory(self._current_path)
114
+ self._cursor = 0
115
+ self.update_display()
116
+
117
+ def exit_app(self, event: ptk.KeyPressEvent) -> None:
118
+ event.app.exit()
119
+
120
+ #
121
+
122
+ def run(self) -> None:
123
+ self._app.run()
124
+
125
+
126
+ def _main() -> None:
127
+ import argparse
128
+
129
+ parser = argparse.ArgumentParser()
130
+
131
+ parser.add_argument('dir', default='.', nargs='?')
132
+
133
+ args = parser.parse_args()
134
+
135
+ ncdu_app = NcduApp(args.dir)
136
+ ncdu_app.run()
137
+
138
+
139
+ if __name__ == '__main__':
140
+ _main()
omdev/scripts/interp.py CHANGED
@@ -626,6 +626,9 @@ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
626
626
  # ../../../omlish/lite/strings.py
627
627
 
628
628
 
629
+ ##
630
+
631
+
629
632
  def camel_case(name: str, lower: bool = False) -> str:
630
633
  if not name:
631
634
  return ''
@@ -640,6 +643,9 @@ def snake_case(name: str) -> str:
640
643
  return '_'.join([name[l:r].lower() for l, r in zip([None, *uppers], [*uppers, None])]).strip('_')
641
644
 
642
645
 
646
+ ##
647
+
648
+
643
649
  def is_dunder(name: str) -> bool:
644
650
  return (
645
651
  name[:2] == name[-2:] == '__' and
@@ -658,10 +664,31 @@ def is_sunder(name: str) -> bool:
658
664
  )
659
665
 
660
666
 
667
+ ##
668
+
669
+
661
670
  def attr_repr(obj: ta.Any, *attrs: str) -> str:
662
671
  return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
663
672
 
664
673
 
674
+ ##
675
+
676
+
677
+ FORMAT_NUM_BYTES_SUFFIXES: ta.Sequence[str] = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB']
678
+
679
+
680
+ def format_num_bytes(num_bytes: int) -> str:
681
+ for i, suffix in enumerate(FORMAT_NUM_BYTES_SUFFIXES):
682
+ value = num_bytes / 1024 ** i
683
+ if num_bytes < 1024 ** (i + 1):
684
+ if value.is_integer():
685
+ return f'{int(value)}{suffix}'
686
+ else:
687
+ return f'{value:.2f}{suffix}'
688
+
689
+ return f'{num_bytes / 1024 ** (len(FORMAT_NUM_BYTES_SUFFIXES) - 1):.2f}{FORMAT_NUM_BYTES_SUFFIXES[-1]}'
690
+
691
+
665
692
  ########################################
666
693
  # ../../packaging/specifiers.py
667
694
  # Copyright (c) Donald Stufft and individual contributors.
@@ -2014,6 +2014,9 @@ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
2014
2014
  # ../../../omlish/lite/strings.py
2015
2015
 
2016
2016
 
2017
+ ##
2018
+
2019
+
2017
2020
  def camel_case(name: str, lower: bool = False) -> str:
2018
2021
  if not name:
2019
2022
  return ''
@@ -2028,6 +2031,9 @@ def snake_case(name: str) -> str:
2028
2031
  return '_'.join([name[l:r].lower() for l, r in zip([None, *uppers], [*uppers, None])]).strip('_')
2029
2032
 
2030
2033
 
2034
+ ##
2035
+
2036
+
2031
2037
  def is_dunder(name: str) -> bool:
2032
2038
  return (
2033
2039
  name[:2] == name[-2:] == '__' and
@@ -2046,10 +2052,31 @@ def is_sunder(name: str) -> bool:
2046
2052
  )
2047
2053
 
2048
2054
 
2055
+ ##
2056
+
2057
+
2049
2058
  def attr_repr(obj: ta.Any, *attrs: str) -> str:
2050
2059
  return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
2051
2060
 
2052
2061
 
2062
+ ##
2063
+
2064
+
2065
+ FORMAT_NUM_BYTES_SUFFIXES: ta.Sequence[str] = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB']
2066
+
2067
+
2068
+ def format_num_bytes(num_bytes: int) -> str:
2069
+ for i, suffix in enumerate(FORMAT_NUM_BYTES_SUFFIXES):
2070
+ value = num_bytes / 1024 ** i
2071
+ if num_bytes < 1024 ** (i + 1):
2072
+ if value.is_integer():
2073
+ return f'{int(value)}{suffix}'
2074
+ else:
2075
+ return f'{value:.2f}{suffix}'
2076
+
2077
+ return f'{num_bytes / 1024 ** (len(FORMAT_NUM_BYTES_SUFFIXES) - 1):.2f}{FORMAT_NUM_BYTES_SUFFIXES[-1]}'
2078
+
2079
+
2053
2080
  ########################################
2054
2081
  # ../../packaging/specifiers.py
2055
2082
  # Copyright (c) Donald Stufft and individual contributors.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omdev
3
- Version: 0.0.0.dev89
3
+ Version: 0.0.0.dev91
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -10,9 +10,9 @@ Classifier: Development Status :: 2 - Pre-Alpha
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
- Requires-Python: ~=3.12
13
+ Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omlish ==0.0.0.dev89
15
+ Requires-Dist: omlish ==0.0.0.dev91
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black ~=24.10 ; extra == 'all'
18
18
  Requires-Dist: pycparser ~=2.22 ; extra == 'all'
@@ -21,6 +21,7 @@ Requires-Dist: pcpp ~=1.30 ; extra == 'all'
21
21
  Requires-Dist: docutils ~=0.21 ; extra == 'all'
22
22
  Requires-Dist: mypy ~=1.11 ; extra == 'all'
23
23
  Requires-Dist: gprof2dot ~=2024.6 ; extra == 'all'
24
+ Requires-Dist: prompt-toolkit ~=3.0 ; extra == 'all'
24
25
  Requires-Dist: tokenize-rt ~=6.1 ; extra == 'all'
25
26
  Requires-Dist: wheel ~=0.44 ; extra == 'all'
26
27
  Provides-Extra: black
@@ -35,6 +36,8 @@ Provides-Extra: mypy
35
36
  Requires-Dist: mypy ~=1.11 ; extra == 'mypy'
36
37
  Provides-Extra: prof
37
38
  Requires-Dist: gprof2dot ~=2024.6 ; extra == 'prof'
39
+ Provides-Extra: prompttoolkit
40
+ Requires-Dist: prompt-toolkit ~=3.0 ; extra == 'prompttoolkit'
38
41
  Provides-Extra: tokens
39
42
  Requires-Dist: tokenize-rt ~=6.1 ; extra == 'tokens'
40
43
  Provides-Extra: wheel
@@ -1,5 +1,5 @@
1
1
  omdev/.manifests.json,sha256=juVlULcmZOz0t66Qf-GhpG_-4NGQU0XDmd7EjaRygxk,6257
2
- omdev/__about__.py,sha256=do_MjpnIpB_DX4GL4VV9gFQzs6bkoyDIYu29yB3rYxw,1131
2
+ omdev/__about__.py,sha256=5MidJkdjpvZISIof4d7vMN7HhC7h5aUfl-FL0IpbY0A,1207
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
@@ -60,7 +60,7 @@ omdev/cexts/_distutils/compilers/options.py,sha256=H7r5IcLvga5Fs3jjXWIT-6ap3JBdu
60
60
  omdev/cexts/_distutils/compilers/unixccompiler.py,sha256=o1h8QuyupLntv4F21_XjzAZmCiwwxJuTmOirvBSL-Qw,15419
61
61
  omdev/cli/__init__.py,sha256=V_l6VP1SZMlJbO-8CJwSuO9TThOy2S_oaPepNYgIrbE,37
62
62
  omdev/cli/__main__.py,sha256=mOJpgc07o0r5luQ1DlX4tk2PqZkgmbwPbdzJ3KmtjgQ,138
63
- omdev/cli/_pathhack.py,sha256=MCkajFbzP55Nak4DAy2s-4WH_ol15ejyTatvhLfne90,1478
63
+ omdev/cli/_pathhack.py,sha256=kxqb2kHap68Lkh8b211rDbcgj06hidBiAKA3f9posyc,2119
64
64
  omdev/cli/clicli.py,sha256=ShTlK2vjFPqnyF9SPTwXd4nRyb6XjCVPQIT4PTGdTL4,2879
65
65
  omdev/cli/install.py,sha256=C-W171YlIHt4Cfok-nWSMbHwWhqF_PFqq2HixFttYx8,4460
66
66
  omdev/cli/main.py,sha256=nD3bW3MkI0KuDSLpX_PTnl-lBnm4hIxVqczvvMHtupo,7058
@@ -98,6 +98,9 @@ omdev/precheck/lite.py,sha256=d8D-BY-Z0rqQigQ_aR9QXxdB3EBCHJc7WgBJngGiEiE,3871
98
98
  omdev/precheck/main.py,sha256=2YizDZSDhMeQaZKVH83s99pBmtOUL9B-8dXwIcw6fQQ,2674
99
99
  omdev/precheck/manifests.py,sha256=YfXqt6u0hlFXY0QkBMec6V_6Y9T4eCVAmrJDkQkB13U,774
100
100
  omdev/precheck/scripts.py,sha256=qq6MXkxgrYngPg5pWnXH4uRSuRkP3mFqbeml1UmvGBc,1265
101
+ omdev/prompttoolkit/__init__.py,sha256=C4pFxNoIVo7cOH_jZ7-ruaYYd6DxEvuJr5ZGDrMFwXo,402
102
+ omdev/prompttoolkit/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
+ omdev/prompttoolkit/apps/ncdu.py,sha256=V2jZ-h3HN23KC5FB5gFjeMVZZbj-2j6zxyMca3O8OM0,3950
101
104
  omdev/pyproject/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
102
105
  omdev/pyproject/__main__.py,sha256=gn3Rl1aYPYdiTtEqa9ifi0t-e4ZwPY0vhJ4UXvYdJDY,165
103
106
  omdev/pyproject/cexts.py,sha256=x13piOOnNrYbA17qZLDVuR0p1sqhgEwpk4FtImX-klM,4281
@@ -110,8 +113,8 @@ omdev/scripts/bumpversion.py,sha256=Kn7fo73Hs8uJh3Hi3EIyLOlzLPWAC6dwuD_lZ3cIzuY,
110
113
  omdev/scripts/execrss.py,sha256=hJTWBig_-XqKIj1DphYTfeVDtdQTM1XUl-Hvzs2x9iY,451
111
114
  omdev/scripts/exectime.py,sha256=dBdn3KV2jR6tCrzGvb9dTl2uGe2vNpLxmHMtExmnaiM,410
112
115
  omdev/scripts/importtrace.py,sha256=Jbo3Yk2RAbE8_tJ97iTcVNpoxCJxrRb2tl1W_CV3NG0,14067
113
- omdev/scripts/interp.py,sha256=2poCQ_45tO0-X16KeoxiAyuTfltSjnPETejlYEm9VY4,71527
114
- omdev/scripts/pyproject.py,sha256=wtmF5ji8fHw2qzc1aEve09Ozv0ncuZmTQ8IbKCJVAQ0,158223
116
+ omdev/scripts/interp.py,sha256=ls04OE3g_TpiK5_inRfOzUvBGUtBgSt5vnkqC3eZhTM,72076
117
+ omdev/scripts/pyproject.py,sha256=g5f0AyRii_DSY-D6mMDUVqKNPNxWXAQJoWrYi1F2KGM,158772
115
118
  omdev/scripts/slowcat.py,sha256=lssv4yrgJHiWfOiHkUut2p8E8Tq32zB-ujXESQxFFHY,2728
116
119
  omdev/toml/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
117
120
  omdev/toml/parser.py,sha256=84bn09uhYHwQGyfww6Rw6y1RxPAE_HDltODOSakcqDM,29186
@@ -126,9 +129,9 @@ omdev/tools/piptools.py,sha256=-jR5q3w4sHqntxCLExFCBNIARB788FUsAbJ62PK2sBU,2774
126
129
  omdev/tools/proftools.py,sha256=8ZU9x_Dq8eT2ZFwU9sJpDIvxcIn9qBc8y2ELKPb5e5M,1382
127
130
  omdev/tools/rsttool.py,sha256=suwsfseUf8GH8rYmYygTUdif-Jk_bX1g9fYRLXaKkmM,1340
128
131
  omdev/tools/sqlrepl.py,sha256=tmFZh80-xsGM62dyQ7_UGLebChrj7IHbIPYBWDJMgVk,5741
129
- omdev-0.0.0.dev89.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
130
- omdev-0.0.0.dev89.dist-info/METADATA,sha256=ggKYANKyxuGye1kE1NguXiXgE5AOe9kGgHwA-v5woFE,1492
131
- omdev-0.0.0.dev89.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
132
- omdev-0.0.0.dev89.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
133
- omdev-0.0.0.dev89.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
134
- omdev-0.0.0.dev89.dist-info/RECORD,,
132
+ omdev-0.0.0.dev91.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
133
+ omdev-0.0.0.dev91.dist-info/METADATA,sha256=ETMAeQT2JIuqgfINKZYliLmHBYc5jW3pkOg09nSsmaY,1638
134
+ omdev-0.0.0.dev91.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
135
+ omdev-0.0.0.dev91.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
136
+ omdev-0.0.0.dev91.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
137
+ omdev-0.0.0.dev91.dist-info/RECORD,,