Chromite 0.6.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.
@@ -0,0 +1,24 @@
1
+ """
2
+
3
+ Copyright (C) 2026 NastyaNoTamashii.
4
+
5
+ """
6
+
7
+ __title__ = "Chromite"
8
+ __author__ = "NastyaNoTamashii"
9
+ __license__ = "MIT"
10
+ __copyright__ = "Copyright 2026-present NastyaNoTamashii"
11
+ __version__ = "0.6.0"
12
+
13
+ from .formatting import color as _color, color_bg as _color_bg, style as _style
14
+ from .io import (
15
+ Write, Catch, clear, sjoin
16
+ )
17
+
18
+ from .table import Table
19
+
20
+ Color = _color
21
+ ColorBG = _color_bg
22
+ Style = _style
23
+
24
+ __all__ = ["Write", "Catch", "Color", "ColorBG", "Style", "Table", "clear", "sjoin"]
@@ -0,0 +1,43 @@
1
+ """
2
+
3
+ Copyright (C) 2026 NastyaNoTamashii.
4
+
5
+ """
6
+
7
+ import os
8
+
9
+ # Инициализируем поддержку ANSI в Windows-консолях
10
+ os.system("")
11
+
12
+ CSI = "\033["
13
+
14
+ class ANSIElement(str):
15
+ """
16
+ Custom string for ANSI codes.
17
+ """
18
+ pass
19
+
20
+ def make_ansi(code: int) -> ANSIElement:
21
+ return ANSIElement(f"{CSI}{code}m")
22
+
23
+ # --- Новые функции для работы с курсором ---
24
+
25
+ def move_cursor(x: int, y: int) -> ANSIElement:
26
+ """Перемещает курсор на позицию (x, y) / (col, row). Нумерация с 1,1."""
27
+ return ANSIElement(f"{CSI}{y};{x}H")
28
+
29
+ def hide_cursor() -> ANSIElement:
30
+ """Скрывает курсор"""
31
+ return ANSIElement(f"{CSI}?25l")
32
+
33
+ def show_cursor() -> ANSIElement:
34
+ """Показывает курсор"""
35
+ return ANSIElement(f"{CSI}?25h")
36
+
37
+ def save_cursor() -> ANSIElement:
38
+ """Сохраняет текущую позицию курсора"""
39
+ return ANSIElement(f"{CSI}s")
40
+
41
+ def restore_cursor() -> ANSIElement:
42
+ """Восстанавливает сохраненную позицию курсора"""
43
+ return ANSIElement(f"{CSI}u")
@@ -0,0 +1,75 @@
1
+ """
2
+
3
+ Copyright (C) 2026 NastyaNoTamashii.
4
+
5
+ """
6
+
7
+ import random
8
+ from .codes import ANSIElement, make_ansi
9
+
10
+ __all__ = ['color', 'color_bg', 'style']
11
+
12
+ class BaseCodes:
13
+ RESET = make_ansi(0)
14
+
15
+ class Color(BaseCodes):
16
+ black = make_ansi(30)
17
+ red = make_ansi(31)
18
+ green = make_ansi(32)
19
+ yellow = make_ansi(33)
20
+ blue = make_ansi(34)
21
+ violet = make_ansi(35)
22
+ cyan = make_ansi(36)
23
+ white = make_ansi(37)
24
+ pink = make_ansi('38;5;206')
25
+
26
+ light_red = make_ansi(91)
27
+ light_green = make_ansi(92)
28
+ light_yellow = make_ansi(93)
29
+ light_blue = make_ansi(94)
30
+ light_violet = make_ansi(95)
31
+ light_cyan = make_ansi(96)
32
+ light_yellow = make_ansi(97)
33
+
34
+ @property
35
+ def random(self) -> ANSIElement:
36
+ """Returns a random text color each time."""
37
+ return make_ansi(random.randint(30, 37))
38
+
39
+ class ColorBG(BaseCodes):
40
+ black = make_ansi(40)
41
+ red = make_ansi(41)
42
+ green = make_ansi(42)
43
+ yellow = make_ansi(43)
44
+ blue = make_ansi(44)
45
+ violet = make_ansi(45)
46
+ cyan = make_ansi(46)
47
+ white = make_ansi(47)
48
+
49
+ light_red = make_ansi(101)
50
+ light_green = make_ansi(102)
51
+ light_yellow = make_ansi(103)
52
+ light_blue = make_ansi(104)
53
+ light_violet = make_ansi(105)
54
+ light_cyan = make_ansi(106)
55
+ light_yellow = make_ansi(107)
56
+
57
+ @property
58
+ def random(self) -> ANSIElement:
59
+ """Returns a random background color each time."""
60
+ return make_ansi(random.randint(40, 47))
61
+
62
+ class Style(BaseCodes):
63
+ bold = make_ansi(1)
64
+ dim = make_ansi(2)
65
+ italic = make_ansi(3)
66
+ underline = make_ansi(4)
67
+ blink = make_ansi(5)
68
+ # blink = make_ansi(6) Also blink
69
+ inversed = make_ansi(7)
70
+ hide = make_ansi(8)
71
+ strike = make_ansi(9)
72
+
73
+ color = Color()
74
+ color_bg = ColorBG()
75
+ style = Style()
@@ -0,0 +1,233 @@
1
+ """
2
+
3
+ Copyright (C) 2026 NastyaNoTamashii.
4
+
5
+ """
6
+
7
+ __all__ = ['Write', 'Catch', 'sjoin', 'clear']
8
+
9
+ import sys
10
+ from typing import Union, List, Tuple, Optional
11
+ from .codes import ANSIElement, move_cursor, show_cursor
12
+ from .formatting import BaseCodes
13
+
14
+ # Тип-хинт для стилей: один элемент или список/кортеж элементов
15
+ StyleType = Union[ANSIElement, List[ANSIElement], Tuple[ANSIElement, ...]]
16
+
17
+ PosType = Tuple[int, int] # (x, y) или (col, row)
18
+
19
+ try:
20
+ import msvcrt
21
+ WINDOWS = True
22
+ except ImportError:
23
+ import tty
24
+ import termios
25
+ WINDOWS = False
26
+
27
+ def _read_masked_input(mask_char: str) -> str:
28
+ """Считывает ввод с маскировкой символов без стандартного эха терминала."""
29
+ buf = []
30
+ while True:
31
+ if WINDOWS:
32
+ ch = msvcrt.getch()
33
+ if ch in (b"\r", b"\n"):
34
+ print()
35
+ break
36
+ elif ch == b"\x08": # Backspace
37
+ if buf:
38
+ buf.pop()
39
+ sys.stdout.write("\b \b")
40
+ sys.stdout.flush()
41
+ elif ch not in (b"\x00", b"\xe0"):
42
+ try:
43
+ char_str = ch.decode("utf-8")
44
+ buf.append(char_str)
45
+ sys.stdout.write(mask_char)
46
+ sys.stdout.flush()
47
+ except UnicodeDecodeError:
48
+ pass
49
+ else:
50
+ fd = sys.stdin.fileno()
51
+ old_settings = termios.tcgetattr(fd)
52
+ try:
53
+ tty.setraw(fd)
54
+ ch = sys.stdin.read(1)
55
+ finally:
56
+ termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
57
+
58
+ if ch in ("\r", "\n"):
59
+ print()
60
+ break
61
+ elif ch in ("\x7f", "\x08"): # Backspace
62
+ if buf:
63
+ buf.pop()
64
+ sys.stdout.write("\b \b")
65
+ sys.stdout.flush()
66
+ elif ch == "\x03": # Ctrl+C
67
+ raise KeyboardInterrupt
68
+ else:
69
+ buf.append(ch)
70
+ sys.stdout.write(mask_char)
71
+ sys.stdout.flush()
72
+
73
+ return "".join(buf)
74
+
75
+ class Write:
76
+ __slots__ = ("text", "compose", "pos",)
77
+
78
+ def __init__(
79
+ self,
80
+ text: str,
81
+ *,
82
+ compose: StyleType = None,
83
+ pos: Optional[PosType] = None
84
+ ):
85
+ """
86
+ :param text: Text
87
+ :param compose: Set style for text.
88
+ :param pos: Set position (x, y).
89
+ """
90
+ self.text = str(text)
91
+ self.pos = pos
92
+
93
+ if compose:
94
+ # 1. Если передан один правильный ANSI-стиль
95
+ if isinstance(compose, ANSIElement):
96
+ self.text = f"{compose}{self.text}{BaseCodes.RESET}"
97
+
98
+ # 2. Если передана коллекция стилей (например: style=[color.red, style.bold])
99
+ elif isinstance(compose, (list, tuple)) and all(isinstance(comp, ANSIElement) for comp in compose):
100
+ ansi_sequence = "".join(compose)
101
+ self.text = f"{ansi_sequence}{self.text}{BaseCodes.RESET}"
102
+
103
+ # 3. Если подсунули левую строку или не тот объект
104
+ else:
105
+ raise TypeError("Style must be an ANSIElement or a collection of ANSIElements (from Chromite).")
106
+
107
+ def render_list(self, items: list) -> None:
108
+ """Красиво выводит нумерованный список в консоль"""
109
+ for index, item in enumerate(items):
110
+ print(f"{index}. {item}")
111
+
112
+ def flush(self) -> str:
113
+ """Возвращает строку с учетом позиционирования курсора"""
114
+ if self.pos is not None:
115
+ x, y = self.pos
116
+ # Приводим к 1-based координатам терминала (1, 1 — верхний левый угол)
117
+ ansi_pos = move_cursor(max(1, x + 1), max(1, y + 1))
118
+ return f"{ansi_pos}{self.text}"
119
+ return self.text
120
+
121
+ def display(self) -> None:
122
+ """Сразу выводит текст в консоль"""
123
+ print(self.flush(), end="", flush=True)
124
+
125
+ def __str__(self) -> str:
126
+ return self.flush()
127
+
128
+ class Catch:
129
+ __slots__ = ("prompt", "compose", "catch_compose", "pos", "type")
130
+
131
+ def __init__(
132
+ self,
133
+ prompt: str = "> ",
134
+ *,
135
+ compose: StyleType = None,
136
+ catch_compose: StyleType = None,
137
+ pos: Optional[PosType] = None,
138
+ type: str = "text",
139
+ ):
140
+ """
141
+ :param prompt: Prompt text.
142
+ :param compose: Set style for prompt text.
143
+ :param catch_compose: Стиль для вводимого текста и возвращаемого Write.
144
+ :param pos: Позиция (x, y) для отрисовки поля ввода.
145
+ :param type: Тип ввода ("text", "password", "pin", "hidden", "int").
146
+ :param mask_char: Символ маскировки при type="password".
147
+ """
148
+ self.prompt = str(prompt)
149
+ self.compose = compose
150
+ self.catch_compose = catch_compose
151
+ self.pos = pos
152
+ self.type = type.lower()
153
+
154
+ # Применяем стили к промпту
155
+ if self.compose:
156
+ if isinstance(self.compose, ANSIElement):
157
+ self.prompt = f"{self.compose}{self.prompt}{BaseCodes.RESET}"
158
+ elif isinstance(self.compose, (list, tuple)) and all(isinstance(comp, ANSIElement) for comp in self.compose):
159
+ ansi_seq = "".join(str(comp) for comp in self.compose)
160
+ self.prompt = f"{ansi_seq}{self.prompt}{BaseCodes.RESET}"
161
+
162
+ def up(self) -> Write:
163
+ """
164
+ Перемещает курсор (если задан pos), активирует style для ввода,
165
+ считывает текст с учетом type и сбрасывает стили.
166
+ """
167
+ formatted_prompt = self.prompt
168
+
169
+ # 1. Если заданы координаты, добавляем перемещение курсора
170
+ if self.pos is not None:
171
+ x, y = self.pos
172
+ ansi_pos = move_cursor(max(1, x + 1), max(1, y + 1))
173
+ formatted_prompt = f"{ansi_pos}{self.prompt}"
174
+
175
+ # 2. Подготавливаем ANSI-код для стиля ввода
176
+ input_ansi_start = ""
177
+ if self.catch_compose:
178
+ if isinstance(self.catch_compose, ANSIElement):
179
+ input_ansi_start = str(self.catch_compose)
180
+ elif isinstance(self.catch_compose, (list, tuple)) and all(isinstance(s, ANSIElement) for s in self.catch_compose):
181
+ input_ansi_start = "".join(str(s) for s in self.catch_compose)
182
+
183
+ # 3. Включаем отображение курсора и накладываем стиль на сам ввод
184
+ full_prompt = f"{show_cursor()}{formatted_prompt}{input_ansi_start}"
185
+
186
+ try:
187
+ # 4. Обработка ввода в зависимости от type
188
+ if self.type == "password":
189
+ sys.stdout.write(full_prompt)
190
+ sys.stdout.flush()
191
+ user_input = _read_masked_input(mask_char='*')
192
+
193
+ elif self.type == "pin":
194
+ sys.stdout.write(full_prompt)
195
+ sys.stdout.flush()
196
+ user_input = _read_masked_input(mask_char='•')
197
+
198
+ elif self.type == "hidden":
199
+ sys.stdout.write(full_prompt)
200
+ sys.stdout.flush()
201
+ user_input = _read_masked_input(mask_char="")
202
+
203
+ elif self.type in ("int", "number"):
204
+ while True:
205
+ raw = input(full_prompt)
206
+ if raw.strip().isdigit():
207
+ user_input = raw
208
+ break
209
+ # Если введено не число — очищаем строку и повторяем
210
+ sys.stdout.write(f"\033[1A\033[2K")
211
+ sys.stdout.flush()
212
+
213
+ else:
214
+ # Стандартный текстовый ввод
215
+ user_input = input(full_prompt)
216
+
217
+ finally:
218
+ # Сбрасываем стили терминала
219
+ sys.stdout.write(str(BaseCodes.RESET))
220
+ sys.stdout.flush()
221
+
222
+ # Возвращаем объект Write, сохраняя в нем catch_compose
223
+ return Write(user_input, compose=self.catch_compose)
224
+
225
+ def __call__(self) -> Write:
226
+ return self.up()
227
+
228
+ def sjoin(text: str, compose: StyleType) -> str:
229
+ return f"{compose}{text}{BaseCodes.RESET}"
230
+
231
+ def clear() -> None:
232
+ """Clears the terminal screen."""
233
+ print('\x1b[2J\x1b[H')
@@ -0,0 +1,64 @@
1
+ """
2
+
3
+ Copyright (C) 2026 NastyaNoTamashii.
4
+
5
+ """
6
+
7
+ class Table:
8
+
9
+ def createTable(
10
+ data,
11
+ *,
12
+ cellUpper: str = None,
13
+ cellSep: str = None,
14
+ header_separator = None
15
+ ) -> str:
16
+ """
17
+ An example of creating tables:
18
+ >>> import Chromite
19
+ >>> data = [["Product", "Cost"],{"Strawberry": "2$","Blueberry":"2,71$","Banana":"1,63$","Apple":"30¢","Limon":"2$",}]
20
+ >>> tableCreate = Chromite.Table()
21
+ >>> print (tableCreate.createTable(data = data))
22
+
23
+ Product | Cost
24
+ -----------+------
25
+ Strawberry | 2$
26
+ Blueberry | 2,71$
27
+ Banana | 1,63$
28
+ Apple | 30¢
29
+ Limon | 2$
30
+ """
31
+ dataСount = [
32
+ data[0]
33
+ ]
34
+ dataСount += [(k, v) for k, v in data[1].items()]
35
+
36
+ rows = len(dataСount)
37
+ cols = len(dataСount[0])
38
+
39
+ cellU = "-" if cellUpper is None else cellUpper
40
+ cellS = " | " if cellSep is None else " {} ".format(cellSep)
41
+
42
+ col_width = []
43
+ for col in range(cols):
44
+ columns = [str(dataСount[row][col]) for row in range(rows)]
45
+ col_width.append(len(max(columns, key=len)))
46
+
47
+ separator = "{}+{}".format(cellU, cellU).join(cellU * n for n in col_width)
48
+
49
+ lines = []
50
+
51
+ for i, row in enumerate(range(rows)):
52
+ result = []
53
+ for col in range(cols):
54
+ item = str(dataСount[row][col]).rjust(col_width[col])
55
+ result.append(item)
56
+
57
+ lines.append(cellS.join(result))
58
+
59
+ if i == 0 and header_separator:
60
+ lines.append(separator)
61
+
62
+ return (
63
+ "\n".join(lines)
64
+ )
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 - Present Chromite
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,71 @@
1
+ Metadata-Version: 2.5
2
+ Name: Chromite
3
+ Version: 0.6.0
4
+ Summary: Chromite is a framework for text and ASCI formatting in Python.
5
+ Project-URL: Documentation (GitHub), https://github.com/NastyaNoTamashii/Chromite/blob/main/README.md
6
+ Project-URL: Source (GitHub), https://github.com/NastyaNoTamashii/Chromite
7
+ Author: NastyaNoTamashii
8
+ License: MIT
9
+ License-File: LICENSE.txt
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Natural Language :: English
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Classifier: Topic :: Communications :: Chat
22
+ Classifier: Topic :: Internet
23
+ Classifier: Topic :: Internet :: WWW/HTTP
24
+ Classifier: Topic :: Software Development :: Libraries
25
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Topic :: Utilities
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.10
30
+ Description-Content-Type: text/markdown
31
+
32
+ <p align="center">
33
+ <h1>
34
+ Chromite
35
+ </h1>
36
+ </p>
37
+
38
+ <h3 align="center">
39
+ This library is currently under development.
40
+ </h3>
41
+
42
+ ## About
43
+ <strong>Chromite</strong> Chromite is a framework for text and ASCI formatting in Python.
44
+
45
+ An optimized library that simplifies writing code and helps with the tasks provided.
46
+
47
+ ---
48
+ ## Install Chromite
49
+
50
+ ### Installing from PyPi:
51
+ ```commandline
52
+ pip install Chromite
53
+ ```
54
+ ### Installing from Git:
55
+ ```commandline
56
+ pip install git+https://github.com/NastyaNoTamashii/Chromite
57
+ ```
58
+
59
+ ---
60
+
61
+ <a href="https://github.com/NastyaNoTamashii/Chromite/graphs/contributors">
62
+ <img src="https://contrib.rocks/image?repo=NastyaNoTamashii/Chromite" />
63
+ </a>
64
+
65
+ ---
66
+ ### If a feature doesn't work, check if your console supports it.
67
+ ---
68
+
69
+ ## Do you have any questions?
70
+
71
+ Сontact [me](https://discord.gg/). For help with Chromite.
@@ -0,0 +1,40 @@
1
+ <p align="center">
2
+ <h1>
3
+ Chromite
4
+ </h1>
5
+ </p>
6
+
7
+ <h3 align="center">
8
+ This library is currently under development.
9
+ </h3>
10
+
11
+ ## About
12
+ <strong>Chromite</strong> Chromite is a framework for text and ASCI formatting in Python.
13
+
14
+ An optimized library that simplifies writing code and helps with the tasks provided.
15
+
16
+ ---
17
+ ## Install Chromite
18
+
19
+ ### Installing from PyPi:
20
+ ```commandline
21
+ pip install Chromite
22
+ ```
23
+ ### Installing from Git:
24
+ ```commandline
25
+ pip install git+https://github.com/NastyaNoTamashii/Chromite
26
+ ```
27
+
28
+ ---
29
+
30
+ <a href="https://github.com/NastyaNoTamashii/Chromite/graphs/contributors">
31
+ <img src="https://contrib.rocks/image?repo=NastyaNoTamashii/Chromite" />
32
+ </a>
33
+
34
+ ---
35
+ ### If a feature doesn't work, check if your console supports it.
36
+ ---
37
+
38
+ ## Do you have any questions?
39
+
40
+ Сontact [me](https://discord.gg/). For help with Chromite.
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "Chromite"
7
+ dynamic = ["version"]
8
+ description = "Chromite is a framework for text and ASCI formatting in Python."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "NastyaNoTamashii" }
14
+ ]
15
+ classifiers = [
16
+ "License :: OSI Approved :: MIT License",
17
+ "Intended Audience :: Developers",
18
+ "Natural Language :: English",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
26
+ "Programming Language :: Python :: Implementation :: CPython",
27
+ "Topic :: Communications :: Chat",
28
+ "Topic :: Internet :: WWW/HTTP",
29
+ "Topic :: Internet",
30
+ "Topic :: Software Development :: Libraries",
31
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
32
+ "Topic :: Software Development :: Libraries :: Python Modules",
33
+ "Topic :: Utilities",
34
+ "Typing :: Typed",
35
+ ]
36
+
37
+ [project.urls]
38
+ "Documentation (GitHub)" = "https://github.com/NastyaNoTamashii/Chromite/blob/main/README.md"
39
+ "Source (GitHub)" = "https://github.com/NastyaNoTamashii/Chromite"
40
+
41
+ [tool.hatch.version]
42
+ path = "Chromite/__init__.py"