ttykit 0.3.7__tar.gz → 0.4.0__tar.gz
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.
- {ttykit-0.3.7/src/ttykit.egg-info → ttykit-0.4.0}/PKG-INFO +51 -39
- ttykit-0.4.0/README.md +78 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/pyproject.toml +2 -2
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit/__init__.py +5 -1
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit/_state.py +49 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit/console/TUI.py +3 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit/console/console.py +43 -64
- {ttykit-0.3.7/src/ttykit → ttykit-0.4.0/src/ttykit/examples}/spinner.py +2 -2
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit/progress.py +19 -3
- ttykit-0.4.0/src/ttykit/segmentation.py +97 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit/status.py +4 -4
- ttykit-0.4.0/src/ttykit/tree.py +58 -0
- {ttykit-0.3.7 → ttykit-0.4.0/src/ttykit.egg-info}/PKG-INFO +51 -39
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit.egg-info/SOURCES.txt +4 -2
- ttykit-0.4.0/src/ttykit.egg-info/entry_points.txt +2 -0
- ttykit-0.3.7/README.md +0 -66
- ttykit-0.3.7/src/ttykit.egg-info/entry_points.txt +0 -2
- {ttykit-0.3.7 → ttykit-0.4.0}/LICENSE +0 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/setup.cfg +0 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit/console/const.py +0 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit.egg-info/dependency_links.txt +0 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit.egg-info/requires.txt +0 -0
- {ttykit-0.3.7 → ttykit-0.4.0}/src/ttykit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ttykit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Helping made beatiful out in terminal
|
|
5
5
|
Author: He-STALIN
|
|
6
6
|
Author-email: hene.stalin@gmail.com
|
|
@@ -46,60 +46,72 @@ Dynamic: license-file
|
|
|
46
46
|
[](https://python.org)
|
|
47
47
|
[](LICENSE)
|
|
48
48
|
[](https://github.com/He-STALIN/ttykit)
|
|
49
|
+
[](https://pypi.org/project/ttykit/)
|
|
49
50
|
|
|
50
51
|
</div>
|
|
51
52
|
|
|
53
|
+
##### Вы из России? Смотрите [русскую версию](/docs/ru/README.ru.md)
|
|
54
|
+
|
|
52
55
|
---
|
|
53
56
|
|
|
54
|
-
##
|
|
57
|
+
## For Start
|
|
55
58
|
### Manually:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
git clone https://github.com/He-STALIN/ttykit.git
|
|
59
|
-
```
|
|
59
|
+
- Clone repository
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/He-STALIN/ttykit.git
|
|
62
|
+
```
|
|
60
63
|
|
|
61
64
|
- Change dir and exec
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
65
|
+
```bash
|
|
66
|
+
pip install .
|
|
67
|
+
```
|
|
66
68
|
### Auto
|
|
67
69
|
- exec `pip install ttykit`
|
|
68
70
|
|
|
69
71
|
- And use in your projects!
|
|
70
72
|
|
|
71
|
-
##
|
|
72
|
-
-
|
|
73
|
+
## Support the project
|
|
74
|
+
- If you would like the project to continue developing, you can make a [donation](https://yoomoney.ru/to/4100118618732284/100).
|
|
75
|
+
- Account: `4100 1186 1873 2284` (YouMoney)
|
|
76
|
+
- or
|
|
77
|
+
- Find bugs in the library and report them in the `issues` section on GitHub.
|
|
73
78
|
|
|
74
79
|
## Code Examples
|
|
75
80
|
|
|
76
|
-
### Status
|
|
77
|
-
```python
|
|
78
|
-
from ttykit import Status, TaskState
|
|
79
|
-
|
|
80
|
-
with Status("Something unit", spinner="line") as status:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Progress
|
|
86
|
-
```python
|
|
87
|
-
from ttykit import Progress
|
|
88
|
-
|
|
89
|
-
with Progress(100, "Some desc", 40) as progress:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
with Progress(100, "Some desc", 40) as progress:
|
|
98
|
-
while not progress.finished:
|
|
99
|
-
<some actions>
|
|
100
|
-
progress.advance(<step>)
|
|
101
|
-
<maybe action again>
|
|
102
|
-
```
|
|
81
|
+
- ### Status
|
|
82
|
+
```python
|
|
83
|
+
from ttykit import Status, TaskState
|
|
84
|
+
|
|
85
|
+
with Status("Something unit", spinner="line") as status:
|
|
86
|
+
<some action>
|
|
87
|
+
status.set_state(TaskState.SUCCESS)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- ### Progress
|
|
91
|
+
```python
|
|
92
|
+
from ttykit import Progress
|
|
93
|
+
|
|
94
|
+
with Progress(100, "Some desc", 40) as progress:
|
|
95
|
+
<some action>
|
|
96
|
+
progress.update(<value>)
|
|
97
|
+
<some action again>
|
|
98
|
+
progress.finish()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- **for more code examples see** [CODE USE](docs/en/CODE_USE.md)
|
|
103
102
|
|
|
104
103
|
## Also
|
|
105
104
|
- also you can use prepared colors in this lib
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
- This lib uploading with MIT License. [See License](LICENSE)
|
|
108
|
+
|
|
109
|
+
## Versions
|
|
110
|
+
- You interesting see versions? You can see [CHANGELOG](docs/en/CHANGELOG.md)
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
<div align="center">
|
|
114
|
+
|
|
115
|
+
*ttykit by He_STALIN. All right reserved*
|
|
116
|
+
|
|
117
|
+
</div>
|
ttykit-0.4.0/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# TTYKit
|
|
4
|
+
|
|
5
|
+
> **Helping made beautiful out in terminal**
|
|
6
|
+
|
|
7
|
+
[](https://python.org)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://github.com/He-STALIN/ttykit)
|
|
10
|
+
[](https://pypi.org/project/ttykit/)
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
##### Вы из России? Смотрите [русскую версию](/docs/ru/README.ru.md)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## For Start
|
|
19
|
+
### Manually:
|
|
20
|
+
- Clone repository
|
|
21
|
+
```bash
|
|
22
|
+
git clone https://github.com/He-STALIN/ttykit.git
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- Change dir and exec
|
|
26
|
+
```bash
|
|
27
|
+
pip install .
|
|
28
|
+
```
|
|
29
|
+
### Auto
|
|
30
|
+
- exec `pip install ttykit`
|
|
31
|
+
|
|
32
|
+
- And use in your projects!
|
|
33
|
+
|
|
34
|
+
## Support the project
|
|
35
|
+
- If you would like the project to continue developing, you can make a [donation](https://yoomoney.ru/to/4100118618732284/100).
|
|
36
|
+
- Account: `4100 1186 1873 2284` (YouMoney)
|
|
37
|
+
- or
|
|
38
|
+
- Find bugs in the library and report them in the `issues` section on GitHub.
|
|
39
|
+
|
|
40
|
+
## Code Examples
|
|
41
|
+
|
|
42
|
+
- ### Status
|
|
43
|
+
```python
|
|
44
|
+
from ttykit import Status, TaskState
|
|
45
|
+
|
|
46
|
+
with Status("Something unit", spinner="line") as status:
|
|
47
|
+
<some action>
|
|
48
|
+
status.set_state(TaskState.SUCCESS)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- ### Progress
|
|
52
|
+
```python
|
|
53
|
+
from ttykit import Progress
|
|
54
|
+
|
|
55
|
+
with Progress(100, "Some desc", 40) as progress:
|
|
56
|
+
<some action>
|
|
57
|
+
progress.update(<value>)
|
|
58
|
+
<some action again>
|
|
59
|
+
progress.finish()
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **for more code examples see** [CODE USE](docs/en/CODE_USE.md)
|
|
63
|
+
|
|
64
|
+
## Also
|
|
65
|
+
- also you can use prepared colors in this lib
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
- This lib uploading with MIT License. [See License](LICENSE)
|
|
69
|
+
|
|
70
|
+
## Versions
|
|
71
|
+
- You interesting see versions? You can see [CHANGELOG](docs/en/CHANGELOG.md)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
<div align="center">
|
|
75
|
+
|
|
76
|
+
*ttykit by He_STALIN. All right reserved*
|
|
77
|
+
|
|
78
|
+
</div>
|
|
@@ -8,7 +8,7 @@ include = ["ttykit*"]
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "ttykit"
|
|
11
|
-
version = "0.
|
|
11
|
+
version = "0.4.0"
|
|
12
12
|
description = "Helping made beatiful out in terminal"
|
|
13
13
|
requires-python = ">=3.13"
|
|
14
14
|
authors = [
|
|
@@ -21,7 +21,7 @@ keywords = ['tty', 'terminal', 'formatting']
|
|
|
21
21
|
dependencies = ["keyboard"]
|
|
22
22
|
|
|
23
23
|
[project.scripts]
|
|
24
|
-
ttykit-spinner = "ttykit.spinner:main"
|
|
24
|
+
ttykit-spinner = "ttykit.examples.spinner:main"
|
|
25
25
|
|
|
26
26
|
[project.optional-dependencies]
|
|
27
27
|
test = ["pytest"]
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from .progress import Progress
|
|
4
4
|
from .status import Status
|
|
5
5
|
from ._state import TaskState, Colors, Styles, RESET
|
|
6
|
+
from .tree import Tree
|
|
6
7
|
from .console.console import Console
|
|
7
8
|
from .console.TUI import TUI
|
|
8
9
|
import traceback
|
|
@@ -19,6 +20,7 @@ __all__ = [
|
|
|
19
20
|
'Status',
|
|
20
21
|
'TaskState',
|
|
21
22
|
'Console',
|
|
23
|
+
'Tree',
|
|
22
24
|
'TUI',
|
|
23
25
|
'get_console',
|
|
24
26
|
'set_custom_hook'
|
|
@@ -59,11 +61,13 @@ def set_custom_hook(Traceback: bool= False) -> None:
|
|
|
59
61
|
Traceback (bool): replace Traceback on custom or not. Default `False`
|
|
60
62
|
"""
|
|
61
63
|
|
|
64
|
+
print("[WARNING] this method 'set_custom_hook' unstable and may not working")
|
|
65
|
+
|
|
62
66
|
if Traceback:
|
|
63
67
|
print('set custom excepthook...')
|
|
64
68
|
sys.excepthook = custom_excepthook
|
|
65
69
|
|
|
66
70
|
__name__ = 'ttykit'
|
|
67
71
|
__author__ = 'He-STALIN'
|
|
68
|
-
__version__ = '0.
|
|
72
|
+
__version__ = '0.4.0'
|
|
69
73
|
__license__ = 'MIT'
|
|
@@ -21,6 +21,34 @@ class Colors:
|
|
|
21
21
|
LIGHT_WHITE = "\033[97m"
|
|
22
22
|
RESET = "\033[0m"
|
|
23
23
|
|
|
24
|
+
def get(name: str = None, default: str = None) -> str:
|
|
25
|
+
"""Return the color ANSI code from color name
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
name (str): name of color
|
|
29
|
+
default (str | None): what will be return if color not found
|
|
30
|
+
Returns:
|
|
31
|
+
color (str): ANSi code of color
|
|
32
|
+
"""
|
|
33
|
+
match name.lower():
|
|
34
|
+
case "black": return Colors.BLACK
|
|
35
|
+
case "red": return Colors.RED
|
|
36
|
+
case "green": return Colors.GREEN
|
|
37
|
+
case "yellow": return Colors.YELLOW
|
|
38
|
+
case "blue": return Colors.BLUE
|
|
39
|
+
case "purple": return Colors.PURPLE
|
|
40
|
+
case "cyan": return Colors.CYAN
|
|
41
|
+
case "white": return Colors.WHITE
|
|
42
|
+
case "dark_grey": return Colors.DARK_GREY
|
|
43
|
+
case "light_red": return Colors.LIGHT_RED
|
|
44
|
+
case "light_green": return Colors.LIGHT_GREEN
|
|
45
|
+
case "light_yellow": return Colors.LIGHT_YELLOW
|
|
46
|
+
case "light_blue": return Colors.LIGHT_BLUE
|
|
47
|
+
case "light_purple": return Colors.LIGHT_PURPLE
|
|
48
|
+
case "light_cyan": return Colors.LIGHT_CYAN
|
|
49
|
+
case "light_white": return Colors.LIGHT_WHITE
|
|
50
|
+
case _: return default
|
|
51
|
+
|
|
24
52
|
class Styles:
|
|
25
53
|
"""Applied styles for text in the terminal. Can be mixed with `class Colors`"""
|
|
26
54
|
RESET = "\033[0m"
|
|
@@ -33,6 +61,27 @@ class Styles:
|
|
|
33
61
|
REVERSE = "\033[7m"
|
|
34
62
|
STRIKETHROUGH = "\033[9m"
|
|
35
63
|
|
|
64
|
+
def get(name: str = None, default: str = None) -> str:
|
|
65
|
+
"""Return the style ANSI code from style name
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
name (str): name of style
|
|
69
|
+
default (str | None): what will be return if style not found
|
|
70
|
+
Returns:
|
|
71
|
+
style (str): ANSi code of style
|
|
72
|
+
"""
|
|
73
|
+
match name.lower():
|
|
74
|
+
case "bold": return Styles.BOLD
|
|
75
|
+
case "dim": return Styles.DIM
|
|
76
|
+
case "italic": return Styles.ITALIC
|
|
77
|
+
case "underline": return Styles.UNDERLINE
|
|
78
|
+
case "blink": return Styles.BLINK
|
|
79
|
+
case "rapid_blink": return Styles.RAPID_BLINK
|
|
80
|
+
case "reverse": return Styles.REVERSE
|
|
81
|
+
case "strikethrough": return Styles.STRIKETHROUGH
|
|
82
|
+
case "reset": return Styles.RESET
|
|
83
|
+
case _: return default
|
|
84
|
+
|
|
36
85
|
RESET = "\033[0m"
|
|
37
86
|
|
|
38
87
|
class TaskState(Enum):
|
|
@@ -41,6 +41,9 @@ class TUI:
|
|
|
41
41
|
"""
|
|
42
42
|
def __init__(self, title: str):
|
|
43
43
|
super().__init__()
|
|
44
|
+
|
|
45
|
+
print("[WARNING] Class 'TUI' not fully completed and may contain errors.")
|
|
46
|
+
|
|
44
47
|
self.TITLE: str = title if title else "Text UI"
|
|
45
48
|
self.FOOTER: str = "For control use arrows Up/Down and Enter to select"
|
|
46
49
|
self.DEFAULT_SPACE = " "
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
import os
|
|
3
|
-
from typing import Optional, Literal, Mapping
|
|
4
|
-
from ttykit import
|
|
3
|
+
from typing import Optional, Literal, Mapping
|
|
4
|
+
from ttykit.segmentation import Segmentation
|
|
5
|
+
from getpass import getpass
|
|
5
6
|
|
|
6
7
|
from .const import ColorSystem, WINDOWS
|
|
7
8
|
|
|
@@ -35,8 +36,8 @@ class Console:
|
|
|
35
36
|
self._force_terminal = None
|
|
36
37
|
self.stderr = stderr
|
|
37
38
|
self.no_color = no_color
|
|
38
|
-
self.height =
|
|
39
|
-
self.width =
|
|
39
|
+
self.height = width
|
|
40
|
+
self.width = height
|
|
40
41
|
|
|
41
42
|
if color_system is None:
|
|
42
43
|
self._color_system = None
|
|
@@ -46,21 +47,21 @@ class Console:
|
|
|
46
47
|
if force_terminal is not None:
|
|
47
48
|
self._force_terminal = force_terminal
|
|
48
49
|
|
|
49
|
-
if width is None:
|
|
50
|
+
if self.width is None:
|
|
50
51
|
try:
|
|
51
52
|
size = os.get_terminal_size()
|
|
52
|
-
width = size.columns
|
|
53
|
+
self.width = size.columns
|
|
53
54
|
except OSError:
|
|
54
55
|
print('Error calculating width of the terminal. Use default value (80)')
|
|
55
|
-
width = 80
|
|
56
|
+
self.width = 80
|
|
56
57
|
|
|
57
|
-
if height is None:
|
|
58
|
+
if self.height is None:
|
|
58
59
|
try:
|
|
59
60
|
size = os.get_terminal_size()
|
|
60
|
-
height = size.lines
|
|
61
|
+
self.height = size.lines
|
|
61
62
|
except OSError:
|
|
62
63
|
print('Error calculating height of the terminal. Use default value (24)')
|
|
63
|
-
height
|
|
64
|
+
self.height
|
|
64
65
|
|
|
65
66
|
def _print_error(self, msg: str=None):
|
|
66
67
|
if msg is None:
|
|
@@ -130,49 +131,17 @@ class Console:
|
|
|
130
131
|
return ColorSystem.EIGHT_BIT
|
|
131
132
|
return ColorSystem.STANDARD
|
|
132
133
|
|
|
133
|
-
def _get_style_code(self, style: str) -> str:
|
|
134
|
-
styles = {
|
|
135
|
-
'bold': Styles.BOLD,
|
|
136
|
-
'dim': Styles.DIM,
|
|
137
|
-
'italic': Styles.ITALIC,
|
|
138
|
-
'underline': Styles.UNDERLINE,
|
|
139
|
-
'blink': Styles.BLINK,
|
|
140
|
-
'rapid_blink': Styles.RAPID_BLINK,
|
|
141
|
-
'reverse': Styles.REVERSE
|
|
142
|
-
}
|
|
143
|
-
return styles.get(style, '')
|
|
144
|
-
|
|
145
|
-
def _get_color_code(self, color: str) -> str:
|
|
146
|
-
colors = {
|
|
147
|
-
"black": Colors.BLACK,
|
|
148
|
-
"red": Colors.RED,
|
|
149
|
-
"green": Colors.GREEN,
|
|
150
|
-
"yellow": Colors.YELLOW,
|
|
151
|
-
"blue": Colors.BLUE,
|
|
152
|
-
"purple": Colors.PURPLE,
|
|
153
|
-
"cyan": Colors.CYAN,
|
|
154
|
-
"white": Colors.WHITE,
|
|
155
|
-
"dark_grey": Colors.DARK_GREY,
|
|
156
|
-
"light_red": Colors.LIGHT_RED,
|
|
157
|
-
"light_green": Colors.LIGHT_GREEN,
|
|
158
|
-
"light_yellow": Colors.LIGHT_YELLOW,
|
|
159
|
-
"light_blue": Colors.LIGHT_BLUE,
|
|
160
|
-
"light_purple": Colors.LIGHT_PURPLE,
|
|
161
|
-
"light_cyan": Colors.LIGHT_CYAN,
|
|
162
|
-
"light_white": Colors.LIGHT_WHITE
|
|
163
|
-
}
|
|
164
|
-
return colors.get(color, "")
|
|
165
|
-
|
|
166
134
|
def bell(self):
|
|
167
135
|
sys.stdout.write("\a")
|
|
168
136
|
sys.stdout.flush()
|
|
169
137
|
|
|
170
138
|
def print(self,
|
|
171
139
|
*args,
|
|
172
|
-
sep: str
|
|
173
|
-
end: str
|
|
174
|
-
|
|
175
|
-
|
|
140
|
+
sep: Optional[str] =" ",
|
|
141
|
+
end: Optional[str] ="\n",
|
|
142
|
+
justify: str = "left",
|
|
143
|
+
fillchar: str = " "
|
|
144
|
+
) -> None:
|
|
176
145
|
"""
|
|
177
146
|
Print the args to a stream
|
|
178
147
|
|
|
@@ -180,10 +149,17 @@ class Console:
|
|
|
180
149
|
*args (Any): args to write to a stream
|
|
181
150
|
sep (str | None): string inserted between values, default a space.
|
|
182
151
|
end (str | None): string appended after the last value, default a newline.
|
|
183
|
-
|
|
184
|
-
|
|
152
|
+
justify (str): justify of text in the terminal. Avaliable: "left", "center", "right".
|
|
153
|
+
fillchar (str): char for fill free space in line. Default " ".
|
|
185
154
|
Returns:
|
|
186
155
|
None: write in `stdout`
|
|
156
|
+
|
|
157
|
+
### Example
|
|
158
|
+
code:
|
|
159
|
+
print("[blue] This is test string")
|
|
160
|
+
|
|
161
|
+
output:
|
|
162
|
+
<div style="color: blue;"> This is test string</div>
|
|
187
163
|
"""
|
|
188
164
|
if not self.isTerminal or self.no_color:
|
|
189
165
|
#? Just out, without colors or styles
|
|
@@ -194,42 +170,45 @@ class Console:
|
|
|
194
170
|
|
|
195
171
|
#? Apply the style with color to args
|
|
196
172
|
text = sep.join(str(a) for a in args)
|
|
197
|
-
if color and self.color_system:
|
|
198
|
-
color_code = self._get_color_code(color.lower())
|
|
199
|
-
text = f"{color_code}{text}{Colors.RESET}"
|
|
200
|
-
|
|
201
|
-
if style:
|
|
202
|
-
style_code = self._get_style_code(style.lower())
|
|
203
|
-
text = f"{style_code}{text}"
|
|
204
173
|
|
|
174
|
+
text = Segmentation(text).auto_compile()
|
|
175
|
+
|
|
176
|
+
match justify:
|
|
177
|
+
case "left":
|
|
178
|
+
text = text.ljust(self.width, fillchar)
|
|
179
|
+
case "center":
|
|
180
|
+
text = text.center(self.width, fillchar)
|
|
181
|
+
case "right":
|
|
182
|
+
text = text.rjust(self.width, fillchar)
|
|
183
|
+
case unknown:
|
|
184
|
+
raise ValueError(f"Unknown type '{unknown}' for text justify")
|
|
185
|
+
|
|
205
186
|
sys.stdout.write(text + end)
|
|
206
187
|
sys.stdout.flush()
|
|
207
188
|
|
|
208
189
|
|
|
209
190
|
def input(self,
|
|
210
|
-
prompt = '',
|
|
191
|
+
prompt: str = '',
|
|
211
192
|
*,
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
193
|
+
password: bool = False,
|
|
194
|
+
justify: str = "left",
|
|
195
|
+
fillchar: str = " ") -> str:
|
|
215
196
|
"""
|
|
216
197
|
Displays a prompt if have and waits for input from user.
|
|
217
198
|
|
|
218
199
|
Args:
|
|
219
200
|
prompt: text to render in prompt
|
|
220
|
-
style (str | None): style for prompt render. Required prompt
|
|
221
|
-
color (str | None): color for prompt render. Required prompt
|
|
222
201
|
password (bool): if `True`, hide typed text. Default `False`
|
|
223
202
|
Returns:
|
|
224
203
|
result (str): typed text from user from stdin
|
|
225
204
|
"""
|
|
226
205
|
|
|
227
206
|
if prompt:
|
|
228
|
-
self.print(prompt,
|
|
207
|
+
self.print(prompt, end='', justify=justify, fillchar=fillchar)
|
|
229
208
|
|
|
230
209
|
if password:
|
|
231
210
|
# TODO: realize text hidding
|
|
232
|
-
|
|
211
|
+
result = getpass(prompt='')
|
|
233
212
|
else:
|
|
234
213
|
result = input()
|
|
235
214
|
return result
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from ._state import *
|
|
3
|
+
import time
|
|
3
4
|
|
|
4
5
|
class Progress:
|
|
5
6
|
"""
|
|
@@ -10,7 +11,8 @@ class Progress:
|
|
|
10
11
|
prefix (str): some description of bar. Can be empty
|
|
11
12
|
bar_length (int): how many characters in bar length. Default: 30
|
|
12
13
|
bar_style: bar performance style. Default: `line`. Avaliable styles: `line`, `points`, `blocks`, `arrow`.
|
|
13
|
-
frames (bool): use bracket or not. Default: False
|
|
14
|
+
frames (bool): use bracket or not. Default: `False`
|
|
15
|
+
show_ETA (bool): show ETA (Estimated Time of Arrival). Default: `True`
|
|
14
16
|
Returns:
|
|
15
17
|
None: write in the terminal
|
|
16
18
|
Examples:
|
|
@@ -30,7 +32,7 @@ class Progress:
|
|
|
30
32
|
Loading ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 40%
|
|
31
33
|
```
|
|
32
34
|
"""
|
|
33
|
-
def __init__(self, total: int=100, prefix: str=None, bar_length: int=30, bar_style='line', frames: bool=False):
|
|
35
|
+
def __init__(self, total: int=100, prefix: str=None, bar_length: int=30, bar_style='line', frames: bool=False, show_ETA: bool = True):
|
|
34
36
|
self.total = total
|
|
35
37
|
self.prefix = prefix if prefix else ""
|
|
36
38
|
self.bar_length = bar_length
|
|
@@ -40,6 +42,10 @@ class Progress:
|
|
|
40
42
|
self.bar_bg = temp['bg']
|
|
41
43
|
self.current = 0
|
|
42
44
|
self.finished = False
|
|
45
|
+
self.show_ETA = show_ETA
|
|
46
|
+
|
|
47
|
+
if self.show_ETA:
|
|
48
|
+
self.start_time = time.time()
|
|
43
49
|
|
|
44
50
|
def __enter__(self):
|
|
45
51
|
return self
|
|
@@ -66,7 +72,17 @@ class Progress:
|
|
|
66
72
|
percent = int(self.current / self.total * 100)
|
|
67
73
|
filled = int(self.current / self.total * self.bar_length)
|
|
68
74
|
bar = str(self.bar_filled) * filled + str(self.bar_bg) * (self.bar_length - filled)
|
|
69
|
-
|
|
75
|
+
|
|
76
|
+
eta: str = " ETA: --:--:--" if self.show_ETA else ""
|
|
77
|
+
if self.show_ETA and self.current > 0:
|
|
78
|
+
elapsed = time.time() - self.start_time
|
|
79
|
+
rate = self.current / elapsed
|
|
80
|
+
seconds = (self.total - self.current) / rate
|
|
81
|
+
minutes, seconds = divmod(seconds, 60)
|
|
82
|
+
hours, minutes = divmod(minutes, 60)
|
|
83
|
+
eta = f" ETA: {int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
|
|
84
|
+
|
|
85
|
+
sys.stdout.write(f"\r{self.prefix} {"[ " if self.frames else ""}{bar}{" ]" if self.frames else ""} {percent}%{eta}")
|
|
70
86
|
sys.stdout.flush()
|
|
71
87
|
|
|
72
88
|
def stop(self):
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from ._state import Styles, Colors
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Segmentation:
|
|
6
|
+
"""Split text into non-empty pieces using a regular expression."""
|
|
7
|
+
|
|
8
|
+
def __init__(self, text: str, separator: str = r"\s+"):
|
|
9
|
+
if not isinstance(text, str):
|
|
10
|
+
raise TypeError("text must be a string")
|
|
11
|
+
|
|
12
|
+
if not isinstance(separator, str):
|
|
13
|
+
raise TypeError("separator must be a regular expression string")
|
|
14
|
+
|
|
15
|
+
re.compile(separator)
|
|
16
|
+
self.text = text
|
|
17
|
+
self.separator = separator
|
|
18
|
+
|
|
19
|
+
def segment(self) -> list[str]:
|
|
20
|
+
"""Return text pieces separated by the configured regular expression."""
|
|
21
|
+
return [
|
|
22
|
+
piece.strip()
|
|
23
|
+
for piece in re.split(self.separator, self.text)
|
|
24
|
+
if piece.strip()
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
def __call__(self) -> list[str]:
|
|
28
|
+
"""Segment the stored text."""
|
|
29
|
+
return self.segment()
|
|
30
|
+
|
|
31
|
+
def _apply_tag(self, tag: str, stack: list):
|
|
32
|
+
clean = tag.strip("[]").split()
|
|
33
|
+
for t in clean:
|
|
34
|
+
if t == "/":
|
|
35
|
+
stack.clear()
|
|
36
|
+
elif t.startswith("/"):
|
|
37
|
+
name = t[1:]
|
|
38
|
+
if name in stack:
|
|
39
|
+
stack.remove(name)
|
|
40
|
+
else:
|
|
41
|
+
stack.append(t)
|
|
42
|
+
|
|
43
|
+
def _get_ansi_from_stack(self, stack: list) -> str:
|
|
44
|
+
ansi = ""
|
|
45
|
+
for style in stack:
|
|
46
|
+
ansi += Colors.get(style, "") + Styles.get(style, "")
|
|
47
|
+
return ansi
|
|
48
|
+
|
|
49
|
+
def auto_compile(self) -> str:
|
|
50
|
+
result = ""
|
|
51
|
+
style_stack = []
|
|
52
|
+
pos = 0
|
|
53
|
+
last_ansi = ""
|
|
54
|
+
|
|
55
|
+
for match in re.finditer(r"\[/?\w*(?:\s+\w+)*\]", self.text):
|
|
56
|
+
# Текст до тега
|
|
57
|
+
if match.start() > pos:
|
|
58
|
+
result += self.text[pos:match.start()]
|
|
59
|
+
|
|
60
|
+
# Обработка тега
|
|
61
|
+
tag = match.group()
|
|
62
|
+
self._apply_tag(tag, style_stack)
|
|
63
|
+
|
|
64
|
+
# Сброс предыдущих ANSI и применение новых
|
|
65
|
+
new_ansi = self._get_ansi_from_stack(style_stack)
|
|
66
|
+
if new_ansi != last_ansi:
|
|
67
|
+
result += Styles.RESET + new_ansi
|
|
68
|
+
last_ansi = new_ansi
|
|
69
|
+
|
|
70
|
+
pos = match.end()
|
|
71
|
+
|
|
72
|
+
# Остаток текста
|
|
73
|
+
if pos < len(self.text):
|
|
74
|
+
result += self.text[pos:]
|
|
75
|
+
|
|
76
|
+
result += Styles.RESET
|
|
77
|
+
return result
|
|
78
|
+
|
|
79
|
+
def clean_tag(self, tag: str) -> list:
|
|
80
|
+
"""
|
|
81
|
+
Очищает тег от лишних символов и возвращает список стилей.
|
|
82
|
+
|
|
83
|
+
Пример:
|
|
84
|
+
"[blue bold]" -> ["blue", "bold"]
|
|
85
|
+
"[/red]" -> ["/red"]
|
|
86
|
+
"[/]" -> ["/"]
|
|
87
|
+
"""
|
|
88
|
+
# Убираем квадратные скобки
|
|
89
|
+
tag = tag.strip("[]")
|
|
90
|
+
|
|
91
|
+
# Разбиваем по пробелам
|
|
92
|
+
parts = tag.split()
|
|
93
|
+
|
|
94
|
+
# Убираем пустые строки
|
|
95
|
+
parts = [p for p in parts if p]
|
|
96
|
+
|
|
97
|
+
return parts
|
|
@@ -16,9 +16,9 @@ class Status:
|
|
|
16
16
|
Examples:
|
|
17
17
|
### Realization:
|
|
18
18
|
```python
|
|
19
|
-
from ttykit import
|
|
19
|
+
from ttykit import Status, TaskState
|
|
20
20
|
|
|
21
|
-
with
|
|
21
|
+
with Status("Unit Test 8", spinner="dots12") as status:
|
|
22
22
|
# <task1>
|
|
23
23
|
status.set_message("Unit Test 9")
|
|
24
24
|
# <task2>
|
|
@@ -37,7 +37,7 @@ class Status:
|
|
|
37
37
|
[ OK ] Loading Unit Test 9
|
|
38
38
|
```
|
|
39
39
|
"""
|
|
40
|
-
def __init__(self, message: str, spinner="bar", color="CYAN"):
|
|
40
|
+
def __init__(self, message: str, spinner: str="bar", color="CYAN"):
|
|
41
41
|
self.message = message
|
|
42
42
|
self.color = color
|
|
43
43
|
self.spinner = spinner
|
|
@@ -73,7 +73,7 @@ class Status:
|
|
|
73
73
|
self.animation_thread.start()
|
|
74
74
|
|
|
75
75
|
def _get_color(self):
|
|
76
|
-
return
|
|
76
|
+
return Colors.get(self.color, Colors.get('cyan'))
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
def set_message(self, new_message: str):
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from ttykit.console.console import Console
|
|
3
|
+
|
|
4
|
+
class Tree:
|
|
5
|
+
"""Build tree and render in terminal
|
|
6
|
+
|
|
7
|
+
Args:
|
|
8
|
+
label (str): name of current node.
|
|
9
|
+
Returns:
|
|
10
|
+
instance (self): instance of this class
|
|
11
|
+
|
|
12
|
+
### Methods
|
|
13
|
+
add (label)
|
|
14
|
+
adding child tree in main
|
|
15
|
+
print ():
|
|
16
|
+
render tree in terminal
|
|
17
|
+
"""
|
|
18
|
+
def __init__(self, label: str):
|
|
19
|
+
self.label = label
|
|
20
|
+
self.children: List["Tree"] = []
|
|
21
|
+
self.console = Console()
|
|
22
|
+
|
|
23
|
+
def add(self, label: str) -> "Tree":
|
|
24
|
+
"""Adding child tree in current tree"""
|
|
25
|
+
child = Tree(label)
|
|
26
|
+
self.children.append(child)
|
|
27
|
+
return child
|
|
28
|
+
|
|
29
|
+
def _render(self, prefix: str = "", is_last: bool = True, is_root: bool = True) -> list:
|
|
30
|
+
"""Rendering tree nodes with lines
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
prefix (str): name of node
|
|
34
|
+
is_last (bool): if `True`, use final line
|
|
35
|
+
is_root (bool): if `True`, node have root access
|
|
36
|
+
Returns:
|
|
37
|
+
lines (list): list of tree lines
|
|
38
|
+
"""
|
|
39
|
+
lines = []
|
|
40
|
+
|
|
41
|
+
if is_root:
|
|
42
|
+
lines.append(self.label)
|
|
43
|
+
child_prefix = ""
|
|
44
|
+
else:
|
|
45
|
+
connector = "└── " if is_last else "├── "
|
|
46
|
+
lines.append(prefix + connector + self.label)
|
|
47
|
+
child_prefix = prefix + (" " if is_last else "│ ")
|
|
48
|
+
|
|
49
|
+
for i, child in enumerate(self.children):
|
|
50
|
+
is_last_child = (i == len(self.children) - 1)
|
|
51
|
+
lines.extend(child._render(child_prefix, is_last_child, is_root=False))
|
|
52
|
+
|
|
53
|
+
return lines
|
|
54
|
+
|
|
55
|
+
def print(self):
|
|
56
|
+
"""Render tree in terminal stream"""
|
|
57
|
+
for line in self._render():
|
|
58
|
+
self.console.print(line)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ttykit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Helping made beatiful out in terminal
|
|
5
5
|
Author: He-STALIN
|
|
6
6
|
Author-email: hene.stalin@gmail.com
|
|
@@ -46,60 +46,72 @@ Dynamic: license-file
|
|
|
46
46
|
[](https://python.org)
|
|
47
47
|
[](LICENSE)
|
|
48
48
|
[](https://github.com/He-STALIN/ttykit)
|
|
49
|
+
[](https://pypi.org/project/ttykit/)
|
|
49
50
|
|
|
50
51
|
</div>
|
|
51
52
|
|
|
53
|
+
##### Вы из России? Смотрите [русскую версию](/docs/ru/README.ru.md)
|
|
54
|
+
|
|
52
55
|
---
|
|
53
56
|
|
|
54
|
-
##
|
|
57
|
+
## For Start
|
|
55
58
|
### Manually:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
git clone https://github.com/He-STALIN/ttykit.git
|
|
59
|
-
```
|
|
59
|
+
- Clone repository
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/He-STALIN/ttykit.git
|
|
62
|
+
```
|
|
60
63
|
|
|
61
64
|
- Change dir and exec
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
65
|
+
```bash
|
|
66
|
+
pip install .
|
|
67
|
+
```
|
|
66
68
|
### Auto
|
|
67
69
|
- exec `pip install ttykit`
|
|
68
70
|
|
|
69
71
|
- And use in your projects!
|
|
70
72
|
|
|
71
|
-
##
|
|
72
|
-
-
|
|
73
|
+
## Support the project
|
|
74
|
+
- If you would like the project to continue developing, you can make a [donation](https://yoomoney.ru/to/4100118618732284/100).
|
|
75
|
+
- Account: `4100 1186 1873 2284` (YouMoney)
|
|
76
|
+
- or
|
|
77
|
+
- Find bugs in the library and report them in the `issues` section on GitHub.
|
|
73
78
|
|
|
74
79
|
## Code Examples
|
|
75
80
|
|
|
76
|
-
### Status
|
|
77
|
-
```python
|
|
78
|
-
from ttykit import Status, TaskState
|
|
79
|
-
|
|
80
|
-
with Status("Something unit", spinner="line") as status:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Progress
|
|
86
|
-
```python
|
|
87
|
-
from ttykit import Progress
|
|
88
|
-
|
|
89
|
-
with Progress(100, "Some desc", 40) as progress:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
with Progress(100, "Some desc", 40) as progress:
|
|
98
|
-
while not progress.finished:
|
|
99
|
-
<some actions>
|
|
100
|
-
progress.advance(<step>)
|
|
101
|
-
<maybe action again>
|
|
102
|
-
```
|
|
81
|
+
- ### Status
|
|
82
|
+
```python
|
|
83
|
+
from ttykit import Status, TaskState
|
|
84
|
+
|
|
85
|
+
with Status("Something unit", spinner="line") as status:
|
|
86
|
+
<some action>
|
|
87
|
+
status.set_state(TaskState.SUCCESS)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- ### Progress
|
|
91
|
+
```python
|
|
92
|
+
from ttykit import Progress
|
|
93
|
+
|
|
94
|
+
with Progress(100, "Some desc", 40) as progress:
|
|
95
|
+
<some action>
|
|
96
|
+
progress.update(<value>)
|
|
97
|
+
<some action again>
|
|
98
|
+
progress.finish()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- **for more code examples see** [CODE USE](docs/en/CODE_USE.md)
|
|
103
102
|
|
|
104
103
|
## Also
|
|
105
104
|
- also you can use prepared colors in this lib
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
- This lib uploading with MIT License. [See License](LICENSE)
|
|
108
|
+
|
|
109
|
+
## Versions
|
|
110
|
+
- You interesting see versions? You can see [CHANGELOG](docs/en/CHANGELOG.md)
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
<div align="center">
|
|
114
|
+
|
|
115
|
+
*ttykit by He_STALIN. All right reserved*
|
|
116
|
+
|
|
117
|
+
</div>
|
|
@@ -4,8 +4,9 @@ pyproject.toml
|
|
|
4
4
|
src/ttykit/__init__.py
|
|
5
5
|
src/ttykit/_state.py
|
|
6
6
|
src/ttykit/progress.py
|
|
7
|
-
src/ttykit/
|
|
7
|
+
src/ttykit/segmentation.py
|
|
8
8
|
src/ttykit/status.py
|
|
9
|
+
src/ttykit/tree.py
|
|
9
10
|
src/ttykit.egg-info/PKG-INFO
|
|
10
11
|
src/ttykit.egg-info/SOURCES.txt
|
|
11
12
|
src/ttykit.egg-info/dependency_links.txt
|
|
@@ -14,4 +15,5 @@ src/ttykit.egg-info/requires.txt
|
|
|
14
15
|
src/ttykit.egg-info/top_level.txt
|
|
15
16
|
src/ttykit/console/TUI.py
|
|
16
17
|
src/ttykit/console/console.py
|
|
17
|
-
src/ttykit/console/const.py
|
|
18
|
+
src/ttykit/console/const.py
|
|
19
|
+
src/ttykit/examples/spinner.py
|
ttykit-0.3.7/README.md
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
# TTYKit
|
|
4
|
-
|
|
5
|
-
> **Helping made beautiful out in terminal**
|
|
6
|
-
|
|
7
|
-
[](https://python.org)
|
|
8
|
-
[](LICENSE)
|
|
9
|
-
[](https://github.com/He-STALIN/ttykit)
|
|
10
|
-
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 📦 For Start
|
|
16
|
-
### Manually:
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
git clone https://github.com/He-STALIN/ttykit.git
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
- Change dir and exec
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
pip install .
|
|
26
|
-
```
|
|
27
|
-
### Auto
|
|
28
|
-
- exec `pip install ttykit`
|
|
29
|
-
|
|
30
|
-
- And use in your projects!
|
|
31
|
-
|
|
32
|
-
## License
|
|
33
|
-
- This lib uploading with MIT License [See License](LICENSE)
|
|
34
|
-
|
|
35
|
-
## Code Examples
|
|
36
|
-
|
|
37
|
-
### Status
|
|
38
|
-
```python
|
|
39
|
-
from ttykit import Status, TaskState
|
|
40
|
-
|
|
41
|
-
with Status("Something unit", spinner="line") as status:
|
|
42
|
-
<some action>
|
|
43
|
-
status.set_state(TaskState.SUCCESS)
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Progress
|
|
47
|
-
```python
|
|
48
|
-
from ttykit import Progress
|
|
49
|
-
|
|
50
|
-
with Progress(100, "Some desc", 40) as progress:
|
|
51
|
-
<some action>
|
|
52
|
-
progress.update(<value>)
|
|
53
|
-
<some action again>
|
|
54
|
-
progress.finish()
|
|
55
|
-
```
|
|
56
|
-
or
|
|
57
|
-
```python
|
|
58
|
-
with Progress(100, "Some desc", 40) as progress:
|
|
59
|
-
while not progress.finished:
|
|
60
|
-
<some actions>
|
|
61
|
-
progress.advance(<step>)
|
|
62
|
-
<maybe action again>
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Also
|
|
66
|
-
- also you can use prepared colors in this lib
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|