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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ttykit
3
- Version: 0.3.7
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
  [![Python Version](https://img.shields.io/badge/python-3.13+-blue.svg)](https://python.org)
47
47
  [![GitHub license](https://img.shields.io/github/license/He-STALIN/ttykit)](LICENSE)
48
48
  [![Repository](https://img.shields.io/badge/Repository-GitHub-4b93ff?style=flat&logo=github&logoColor=white)](https://github.com/He-STALIN/ttykit)
49
+ [![Downloads](https://img.shields.io/pypi/dm/ttykit)](https://pypi.org/project/ttykit/)
49
50
 
50
51
  </div>
51
52
 
53
+ ##### Вы из России? Смотрите [русскую версию](/docs/ru/README.ru.md)
54
+
52
55
  ---
53
56
 
54
- ## 📦 For Start
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
- ```bash
64
- pip install .
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
- ## License
72
- - This lib uploading with MIT License [See License](LICENSE)
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
- <some action>
82
- status.set_state(TaskState.SUCCESS)
83
- ```
84
-
85
- ### Progress
86
- ```python
87
- from ttykit import Progress
88
-
89
- with Progress(100, "Some desc", 40) as progress:
90
- <some action>
91
- progress.update(<value>)
92
- <some action again>
93
- progress.finish()
94
- ```
95
- or
96
- ```python
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
+ [![Python Version](https://img.shields.io/badge/python-3.13+-blue.svg)](https://python.org)
8
+ [![GitHub license](https://img.shields.io/github/license/He-STALIN/ttykit)](LICENSE)
9
+ [![Repository](https://img.shields.io/badge/Repository-GitHub-4b93ff?style=flat&logo=github&logoColor=white)](https://github.com/He-STALIN/ttykit)
10
+ [![Downloads](https://img.shields.io/pypi/dm/ttykit)](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.3.7"
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.3.7'
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, Any
4
- from ttykit import Colors, Styles
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 = None
39
- self.width = None
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 | None=" ",
173
- end: str | None ="\n",
174
- style: str | None=None,
175
- color: str | None=None) -> None:
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
- style: style of args write to a steam, default `None`.
184
- color: color of args write to a stream, default `None`.
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
- style: str | None = None,
213
- color: str | None = None,
214
- password: bool = False) -> str:
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, style=style, color=color, end='')
207
+ self.print(prompt, end='', justify=justify, fillchar=fillchar)
229
208
 
230
209
  if password:
231
210
  # TODO: realize text hidding
232
- Warning("This attribute in developing. Please, set 'password=False'")
211
+ result = getpass(prompt='')
233
212
  else:
234
213
  result = input()
235
214
  return result
@@ -1,6 +1,6 @@
1
1
  import time
2
- from .status import Status, TaskState
3
- from ._state import STATUS_ANIMATION
2
+ from ttykit.status import Status, TaskState
3
+ from ttykit._state import STATUS_ANIMATION
4
4
 
5
5
  def show_all_spinners():
6
6
  for name in STATUS_ANIMATION.keys():
@@ -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
- sys.stdout.write(f"\r{self.prefix} {"[ " if self.frames else ""}{bar}{" ]" if self.frames else ""} {percent}%")
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 CustomStatus, TaskState
19
+ from ttykit import Status, TaskState
20
20
 
21
- with CustomStatus("Unit Test 8", spinner="dots12") as status:
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 (Colors.CYAN if self.color == "CYAN" else Colors.GREEN if self.color == "GREEN" else Colors.RED)
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.7
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
  [![Python Version](https://img.shields.io/badge/python-3.13+-blue.svg)](https://python.org)
47
47
  [![GitHub license](https://img.shields.io/github/license/He-STALIN/ttykit)](LICENSE)
48
48
  [![Repository](https://img.shields.io/badge/Repository-GitHub-4b93ff?style=flat&logo=github&logoColor=white)](https://github.com/He-STALIN/ttykit)
49
+ [![Downloads](https://img.shields.io/pypi/dm/ttykit)](https://pypi.org/project/ttykit/)
49
50
 
50
51
  </div>
51
52
 
53
+ ##### Вы из России? Смотрите [русскую версию](/docs/ru/README.ru.md)
54
+
52
55
  ---
53
56
 
54
- ## 📦 For Start
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
- ```bash
64
- pip install .
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
- ## License
72
- - This lib uploading with MIT License [See License](LICENSE)
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
- <some action>
82
- status.set_state(TaskState.SUCCESS)
83
- ```
84
-
85
- ### Progress
86
- ```python
87
- from ttykit import Progress
88
-
89
- with Progress(100, "Some desc", 40) as progress:
90
- <some action>
91
- progress.update(<value>)
92
- <some action again>
93
- progress.finish()
94
- ```
95
- or
96
- ```python
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/spinner.py
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
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ttykit-spinner = ttykit.examples.spinner:main
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
- [![Python Version](https://img.shields.io/badge/python-3.13+-blue.svg)](https://python.org)
8
- [![GitHub license](https://img.shields.io/github/license/He-STALIN/ttykit)](LICENSE)
9
- [![Repository](https://img.shields.io/badge/Repository-GitHub-4b93ff?style=flat&logo=github&logoColor=white)](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
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- ttykit-spinner = ttykit.spinner:main
File without changes
File without changes