steboxing 1.0.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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stefano Mazzuka
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,109 @@
1
+ Metadata-Version: 2.4
2
+ Name: steboxing
3
+ Version: 1.0.0
4
+ Summary: Put your text in a stylish box.
5
+ Author: Cangreho
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/StefanoMazzuka/steboxing
8
+ Project-URL: Repository, https://github.com/StefanoMazzuka/steboxing
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Dynamic: license-file
16
+
17
+ # steboxing
18
+
19
+ A Python library for drawing Unicode text boxes around strings — supports 36 border styles using thin, bold, double, and round line characters.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install steboxing
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```python
30
+ from steboxing import boxing
31
+
32
+ print(boxing("Hello, World!", box_type="thin"))
33
+ ```
34
+
35
+ ```
36
+ ┌───────────────┐
37
+ │ Hello, World! │
38
+ └───────────────┘
39
+ ```
40
+
41
+ Multi-line strings are supported:
42
+
43
+ ```python
44
+ print(boxing("Line one\nLine two\nLine three", box_type="double"))
45
+ ```
46
+
47
+ ```
48
+ ╔════════════╗
49
+ ║ Line one ║
50
+ ║ Line two ║
51
+ ║ Line three ║
52
+ ╚════════════╝
53
+ ```
54
+
55
+ `box_type` defaults to `"thin"` if omitted.
56
+
57
+ ## Box styles
58
+
59
+ | `box_type` | Preview |
60
+ |---------------------------|------------------------------------------------|
61
+ | `thin` | `┌───────┐`<br>`│ lines │`<br>`└───────┘` |
62
+ | `double` | `╔═══════╗`<br>`║ lines ║`<br>`╚═══════╝` |
63
+ | `bold` | `┏━━━━━━━┓`<br>`┃ lines ┃`<br>`┗━━━━━━━┛` |
64
+ | `round` | `╭───────╮`<br>`│ lines │`<br>`╰───────╯` |
65
+ | `bold_top_and_bottom` | `┍━━━━━━━┑`<br>`│ lines │`<br>`┕━━━━━━━┙` |
66
+ | `double_top_and_bottom` | `╒═══════╕`<br>`│ lines │`<br>`╘═══════╛` |
67
+ | `bold_left_and_right` | `┎───────┒`<br>`┃ lines ┃`<br>`┖───────┚` |
68
+ | `double_left_and_right` | `╓───────╖`<br>`║ lines ║`<br>`╙───────╜` |
69
+ | `bold_top_only` | `┍━━━━━━━┑`<br>`│ lines │`<br>`└───────┘` |
70
+ | `double_top_only` | `╒═══════╕`<br>`│ lines │`<br>`└───────┘` |
71
+ | `bold_bottom_only` | `┌───────┐`<br>`│ lines │`<br>`┕━━━━━━━┙` |
72
+ | `double_bottom_only` | `┌───────┐`<br>`│ lines │`<br>`╘═══════╛` |
73
+ | `bold_right_only` | `┌───────┒`<br>`│ lines ┃`<br>`└───────┚` |
74
+ | `double_right_only` | `┌───────╖`<br>`│ lines ║`<br>`└───────╜` |
75
+ | `bold_left_only` | `┎───────┐`<br>`┃ lines │`<br>`┖───────┘` |
76
+ | `double_left_only` | `╓───────┐`<br>`║ lines │`<br>`╙───────┘` |
77
+ | `bold_left_and_top` | `┏━━━━━━━┑`<br>`┃ lines │`<br>`┖───────┘` |
78
+ | `double_left_and_top` | `╔═══════╕`<br>`║ lines │`<br>`╙───────┘` |
79
+ | `bold_right_and_top` | `┍━━━━━━━┓`<br>`│ lines ┃`<br>`└───────┚` |
80
+ | `double_right_and_top` | `╒═══════╗`<br>`│ lines ║`<br>`└───────╜` |
81
+ | `bold_right_and_bottom` | `┌───────┒`<br>`│ lines ┃`<br>`┕━━━━━━━┛` |
82
+ | `double_right_and_bottom` | `┌───────╖`<br>`│ lines ║`<br>`╘═══════╝` |
83
+ | `bold_left_and_bottom` | `┎───────┐`<br>`┃ lines │`<br>`┗━━━━━━━┙` |
84
+ | `double_left_and_bottom` | `╓───────┐`<br>`║ lines │`<br>`╚═══════╛` |
85
+ | `bold_but_bottom` | `┏━━━━━━━┓`<br>`┃ lines ┃`<br>`┖───────┚` |
86
+ | `double_but_bottom` | `╔═══════╗`<br>`║ lines ║`<br>`╙───────╜` |
87
+ | `bold_but_left` | `┍━━━━━━━┓`<br>`│ lines ┃`<br>`┕━━━━━━━┛` |
88
+ | `double_but_left` | `╒═══════╗`<br>`│ lines ║`<br>`╘═══════╝` |
89
+ | `bold_but_top` | `┎───────┒`<br>`┃ lines ┃`<br>`┗━━━━━━━┛` |
90
+ | `double_but_top` | `╓───────╖`<br>`║ lines ║`<br>`╚═══════╝` |
91
+ | `bold_but_right` | `┏━━━━━━━┑`<br>`┃ lines │`<br>`┗━━━━━━━┙` |
92
+ | `double_but_right` | `╔═══════╕`<br>`║ lines │`<br>`╚═══════╛` |
93
+ | `bold_corners_only` | `┏───────┓`<br>`│ lines │`<br>`┗───────┛` |
94
+ | `double_corners_only` | `╔───────╗`<br>`│ lines │`<br>`╚───────╝` |
95
+ | `bold_chain` | `┏─━─━─━─┓`<br>`│ lines │`<br>`┗─━─━─━─┛` |
96
+ | `double_chain` | `╔─═─═─═─╗`<br>`│ lines │`<br>`╚─═─═─═─╝` |
97
+
98
+ ## Error handling
99
+
100
+ Passing an invalid `box_type` raises a `ValueError` listing all valid options:
101
+
102
+ ```python
103
+ boxing("text", box_type="unknown")
104
+ # ValueError: box_type not supported: unknown. Use one of: thin, double, bold, ...
105
+ ```
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,93 @@
1
+ # steboxing
2
+
3
+ A Python library for drawing Unicode text boxes around strings — supports 36 border styles using thin, bold, double, and round line characters.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install steboxing
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ from steboxing import boxing
15
+
16
+ print(boxing("Hello, World!", box_type="thin"))
17
+ ```
18
+
19
+ ```
20
+ ┌───────────────┐
21
+ │ Hello, World! │
22
+ └───────────────┘
23
+ ```
24
+
25
+ Multi-line strings are supported:
26
+
27
+ ```python
28
+ print(boxing("Line one\nLine two\nLine three", box_type="double"))
29
+ ```
30
+
31
+ ```
32
+ ╔════════════╗
33
+ ║ Line one ║
34
+ ║ Line two ║
35
+ ║ Line three ║
36
+ ╚════════════╝
37
+ ```
38
+
39
+ `box_type` defaults to `"thin"` if omitted.
40
+
41
+ ## Box styles
42
+
43
+ | `box_type` | Preview |
44
+ |---------------------------|------------------------------------------------|
45
+ | `thin` | `┌───────┐`<br>`│ lines │`<br>`└───────┘` |
46
+ | `double` | `╔═══════╗`<br>`║ lines ║`<br>`╚═══════╝` |
47
+ | `bold` | `┏━━━━━━━┓`<br>`┃ lines ┃`<br>`┗━━━━━━━┛` |
48
+ | `round` | `╭───────╮`<br>`│ lines │`<br>`╰───────╯` |
49
+ | `bold_top_and_bottom` | `┍━━━━━━━┑`<br>`│ lines │`<br>`┕━━━━━━━┙` |
50
+ | `double_top_and_bottom` | `╒═══════╕`<br>`│ lines │`<br>`╘═══════╛` |
51
+ | `bold_left_and_right` | `┎───────┒`<br>`┃ lines ┃`<br>`┖───────┚` |
52
+ | `double_left_and_right` | `╓───────╖`<br>`║ lines ║`<br>`╙───────╜` |
53
+ | `bold_top_only` | `┍━━━━━━━┑`<br>`│ lines │`<br>`└───────┘` |
54
+ | `double_top_only` | `╒═══════╕`<br>`│ lines │`<br>`└───────┘` |
55
+ | `bold_bottom_only` | `┌───────┐`<br>`│ lines │`<br>`┕━━━━━━━┙` |
56
+ | `double_bottom_only` | `┌───────┐`<br>`│ lines │`<br>`╘═══════╛` |
57
+ | `bold_right_only` | `┌───────┒`<br>`│ lines ┃`<br>`└───────┚` |
58
+ | `double_right_only` | `┌───────╖`<br>`│ lines ║`<br>`└───────╜` |
59
+ | `bold_left_only` | `┎───────┐`<br>`┃ lines │`<br>`┖───────┘` |
60
+ | `double_left_only` | `╓───────┐`<br>`║ lines │`<br>`╙───────┘` |
61
+ | `bold_left_and_top` | `┏━━━━━━━┑`<br>`┃ lines │`<br>`┖───────┘` |
62
+ | `double_left_and_top` | `╔═══════╕`<br>`║ lines │`<br>`╙───────┘` |
63
+ | `bold_right_and_top` | `┍━━━━━━━┓`<br>`│ lines ┃`<br>`└───────┚` |
64
+ | `double_right_and_top` | `╒═══════╗`<br>`│ lines ║`<br>`└───────╜` |
65
+ | `bold_right_and_bottom` | `┌───────┒`<br>`│ lines ┃`<br>`┕━━━━━━━┛` |
66
+ | `double_right_and_bottom` | `┌───────╖`<br>`│ lines ║`<br>`╘═══════╝` |
67
+ | `bold_left_and_bottom` | `┎───────┐`<br>`┃ lines │`<br>`┗━━━━━━━┙` |
68
+ | `double_left_and_bottom` | `╓───────┐`<br>`║ lines │`<br>`╚═══════╛` |
69
+ | `bold_but_bottom` | `┏━━━━━━━┓`<br>`┃ lines ┃`<br>`┖───────┚` |
70
+ | `double_but_bottom` | `╔═══════╗`<br>`║ lines ║`<br>`╙───────╜` |
71
+ | `bold_but_left` | `┍━━━━━━━┓`<br>`│ lines ┃`<br>`┕━━━━━━━┛` |
72
+ | `double_but_left` | `╒═══════╗`<br>`│ lines ║`<br>`╘═══════╝` |
73
+ | `bold_but_top` | `┎───────┒`<br>`┃ lines ┃`<br>`┗━━━━━━━┛` |
74
+ | `double_but_top` | `╓───────╖`<br>`║ lines ║`<br>`╚═══════╝` |
75
+ | `bold_but_right` | `┏━━━━━━━┑`<br>`┃ lines │`<br>`┗━━━━━━━┙` |
76
+ | `double_but_right` | `╔═══════╕`<br>`║ lines │`<br>`╚═══════╛` |
77
+ | `bold_corners_only` | `┏───────┓`<br>`│ lines │`<br>`┗───────┛` |
78
+ | `double_corners_only` | `╔───────╗`<br>`│ lines │`<br>`╚───────╝` |
79
+ | `bold_chain` | `┏─━─━─━─┓`<br>`│ lines │`<br>`┗─━─━─━─┛` |
80
+ | `double_chain` | `╔─═─═─═─╗`<br>`│ lines │`<br>`╚─═─═─═─╝` |
81
+
82
+ ## Error handling
83
+
84
+ Passing an invalid `box_type` raises a `ValueError` listing all valid options:
85
+
86
+ ```python
87
+ boxing("text", box_type="unknown")
88
+ # ValueError: box_type not supported: unknown. Use one of: thin, double, bold, ...
89
+ ```
90
+
91
+ ## License
92
+
93
+ MIT
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "steboxing"
7
+ version = "1.0.0"
8
+ description = "Put your text in a stylish box."
9
+ readme = { file = "README.md", content-type = "text/markdown" }
10
+ requires-python = ">=3.6"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Cangreho" }
14
+ ]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: OS Independent",
19
+ ]
20
+
21
+ [project.urls]
22
+ Homepage = "https://github.com/StefanoMazzuka/steboxing"
23
+ Repository = "https://github.com/StefanoMazzuka/steboxing"
24
+
25
+ [tool.setuptools.packages.find]
26
+ include = ["steboxing", "steboxing.*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ """Public package exports for steboxing."""
2
+
3
+ from .core import boxing
4
+
5
+ __all__ = ["boxing"]
@@ -0,0 +1,235 @@
1
+ from typing import Dict, List, Tuple
2
+
3
+ _HORIZONTAL_CHARS = {
4
+ "thin": "─",
5
+ "bold": "━",
6
+ "double": "═",
7
+ }
8
+
9
+ _VERTICAL_CHARS = {
10
+ "thin": "│",
11
+ "bold": "┃",
12
+ "double": "║",
13
+ }
14
+
15
+ _CORNER_CHARS = {
16
+ "top_left": {
17
+ ("thin", "thin"): "┌",
18
+ ("bold", "bold"): "┏",
19
+ ("double", "double"): "╔",
20
+ ("bold", "thin"): "┍",
21
+ ("thin", "bold"): "┎",
22
+ ("double", "thin"): "╒",
23
+ ("thin", "double"): "╓",
24
+ },
25
+ "top_right": {
26
+ ("thin", "thin"): "┐",
27
+ ("bold", "bold"): "┓",
28
+ ("double", "double"): "╗",
29
+ ("bold", "thin"): "┑",
30
+ ("thin", "bold"): "┒",
31
+ ("double", "thin"): "╕",
32
+ ("thin", "double"): "╖",
33
+ },
34
+ "bottom_left": {
35
+ ("thin", "thin"): "└",
36
+ ("bold", "bold"): "┗",
37
+ ("double", "double"): "╚",
38
+ ("bold", "thin"): "┕",
39
+ ("thin", "bold"): "┖",
40
+ ("double", "thin"): "╘",
41
+ ("thin", "double"): "╙",
42
+ },
43
+ "bottom_right": {
44
+ ("thin", "thin"): "┘",
45
+ ("bold", "bold"): "┛",
46
+ ("double", "double"): "╝",
47
+ ("bold", "thin"): "┙",
48
+ ("thin", "bold"): "┚",
49
+ ("double", "thin"): "╛",
50
+ ("thin", "double"): "╜",
51
+ },
52
+ }
53
+
54
+ _ROUND_CORNERS = {
55
+ "top_left": "╭",
56
+ "top_right": "╮",
57
+ "bottom_left": "╰",
58
+ "bottom_right": "╯",
59
+ }
60
+
61
+ _SUPPORTED_BOX_TYPES = (
62
+ "thin",
63
+ "double",
64
+ "bold",
65
+ "round",
66
+ "bold_top_and_bottom",
67
+ "double_top_and_bottom",
68
+ "bold_left_and_right",
69
+ "double_left_and_right",
70
+ "bold_top_only",
71
+ "double_top_only",
72
+ "bold_bottom_only",
73
+ "double_bottom_only",
74
+ "bold_right_only",
75
+ "double_right_only",
76
+ "bold_left_only",
77
+ "double_left_only",
78
+ "bold_left_and_top",
79
+ "double_left_and_top",
80
+ "bold_right_and_top",
81
+ "double_right_and_top",
82
+ "bold_right_and_bottom",
83
+ "double_right_and_bottom",
84
+ "bold_left_and_bottom",
85
+ "double_left_and_bottom",
86
+ "bold_but_bottom",
87
+ "double_but_bottom",
88
+ "bold_but_left",
89
+ "double_but_left",
90
+ "bold_but_top",
91
+ "double_but_top",
92
+ "bold_but_right",
93
+ "double_but_right",
94
+ "bold_corners_only",
95
+ "double_corners_only",
96
+ "bold_chain",
97
+ "double_chain"
98
+ )
99
+
100
+
101
+ def _repeat_pattern(pattern: str, width: int) -> str:
102
+ if width <= 0:
103
+ return ""
104
+
105
+ repeats = (width // len(pattern)) + 1
106
+ return (pattern * repeats)[:width]
107
+
108
+
109
+ def _resolve_sides(box_type: str) -> Dict[str, str]:
110
+ if box_type in {"thin", "round"}:
111
+ return {"top": "thin", "right": "thin", "bottom": "thin", "left": "thin"}
112
+
113
+ if box_type.startswith("bold"):
114
+ variant = "bold"
115
+ elif box_type.startswith("double"):
116
+ variant = "double"
117
+ else:
118
+ raise ValueError(f"box_type not supported: {box_type}")
119
+
120
+ if box_type == variant:
121
+ return {"top": variant, "right": variant, "bottom": variant, "left": variant}
122
+
123
+ suffix = box_type[len(variant) + 1 :]
124
+ sides = {"top": "thin", "right": "thin", "bottom": "thin", "left": "thin"}
125
+
126
+ if suffix == "top_and_bottom":
127
+ sides["top"] = variant
128
+ sides["bottom"] = variant
129
+ elif suffix == "left_and_right":
130
+ sides["left"] = variant
131
+ sides["right"] = variant
132
+ elif suffix == "top_only":
133
+ sides["top"] = variant
134
+ elif suffix == "bottom_only":
135
+ sides["bottom"] = variant
136
+ elif suffix == "right_only":
137
+ sides["right"] = variant
138
+ elif suffix == "left_only":
139
+ sides["left"] = variant
140
+ elif suffix == "left_and_top":
141
+ sides["left"] = variant
142
+ sides["top"] = variant
143
+ elif suffix == "right_and_top":
144
+ sides["right"] = variant
145
+ sides["top"] = variant
146
+ elif suffix == "right_and_bottom":
147
+ sides["right"] = variant
148
+ sides["bottom"] = variant
149
+ elif suffix == "left_and_bottom":
150
+ sides["left"] = variant
151
+ sides["bottom"] = variant
152
+ elif suffix == "but_bottom":
153
+ sides = {"top": variant, "right": variant, "bottom": "thin", "left": variant}
154
+ elif suffix == "but_left":
155
+ sides = {"top": variant, "right": variant, "bottom": variant, "left": "thin"}
156
+ elif suffix == "but_top":
157
+ sides = {"top": "thin", "right": variant, "bottom": variant, "left": variant}
158
+ elif suffix == "but_right":
159
+ sides = {"top": variant, "right": "thin", "bottom": variant, "left": variant}
160
+ elif suffix in {"corners_only", "chain"}:
161
+ pass
162
+ else:
163
+ raise ValueError(f"box_type not supported: {box_type}")
164
+
165
+ return sides
166
+
167
+
168
+ def _build_standard_box(lines: List[str], max_len: int, box_type: str) -> Tuple[str, str, List[str]]:
169
+ width = max_len + 2
170
+ sides = _resolve_sides(box_type)
171
+
172
+ if box_type == "round":
173
+ top_left = _ROUND_CORNERS["top_left"]
174
+ top_right = _ROUND_CORNERS["top_right"]
175
+ bottom_left = _ROUND_CORNERS["bottom_left"]
176
+ bottom_right = _ROUND_CORNERS["bottom_right"]
177
+ elif box_type.endswith("corners_only"):
178
+ variant = "bold" if box_type.startswith("bold") else "double"
179
+ top_left = _CORNER_CHARS["top_left"][(variant, variant)]
180
+ top_right = _CORNER_CHARS["top_right"][(variant, variant)]
181
+ bottom_left = _CORNER_CHARS["bottom_left"][(variant, variant)]
182
+ bottom_right = _CORNER_CHARS["bottom_right"][(variant, variant)]
183
+ else:
184
+ top_left = _CORNER_CHARS["top_left"][(sides["top"], sides["left"])]
185
+ top_right = _CORNER_CHARS["top_right"][(sides["top"], sides["right"])]
186
+ bottom_left = _CORNER_CHARS["bottom_left"][(sides["bottom"], sides["left"])]
187
+ bottom_right = _CORNER_CHARS["bottom_right"][(sides["bottom"], sides["right"])]
188
+
189
+ top_border = top_left + (_HORIZONTAL_CHARS[sides["top"]] * width) + top_right
190
+ bottom_border = bottom_left + (_HORIZONTAL_CHARS[sides["bottom"]] * width) + bottom_right
191
+ boxed_lines = [
192
+ f"{_VERTICAL_CHARS[sides['left']]} {line.ljust(max_len)} {_VERTICAL_CHARS[sides['right']]}"
193
+ for line in lines
194
+ ]
195
+
196
+ return top_border, bottom_border, boxed_lines
197
+
198
+
199
+ def _build_chain_box(lines: List[str], max_len: int, box_type: str) -> Tuple[str, str, List[str]]:
200
+ width = max_len + 2
201
+ variant = "bold" if box_type.startswith("bold") else "double"
202
+ top_border = (
203
+ _CORNER_CHARS["top_left"][(variant, variant)]
204
+ + _repeat_pattern(_HORIZONTAL_CHARS["thin"] + _HORIZONTAL_CHARS[variant], width)
205
+ + _CORNER_CHARS["top_right"][(variant, variant)]
206
+ )
207
+ bottom_border = (
208
+ _CORNER_CHARS["bottom_left"][(variant, variant)]
209
+ + _repeat_pattern(_HORIZONTAL_CHARS["thin"] + _HORIZONTAL_CHARS[variant], width)
210
+ + _CORNER_CHARS["bottom_right"][(variant, variant)]
211
+ )
212
+ boxed_lines = []
213
+
214
+ for index, line in enumerate(lines):
215
+ side_type = variant if index % 2 else "thin"
216
+ vertical = _VERTICAL_CHARS[side_type]
217
+ boxed_lines.append(f"{vertical} {line.ljust(max_len)} {vertical}")
218
+
219
+ return top_border, bottom_border, boxed_lines
220
+
221
+
222
+ def boxing(string: str, box_type: str = "thin") -> str:
223
+ if box_type not in _SUPPORTED_BOX_TYPES:
224
+ supported = ", ".join(_SUPPORTED_BOX_TYPES)
225
+ raise ValueError(f"box_type not supported: {box_type}. Use one of: {supported}")
226
+
227
+ lines = string.splitlines() or [""]
228
+ max_len = max(len(line) for line in lines)
229
+
230
+ if box_type.endswith("chain"):
231
+ top_border, bottom_border, boxed_lines = _build_chain_box(lines, max_len, box_type)
232
+ else:
233
+ top_border, bottom_border, boxed_lines = _build_standard_box(lines, max_len, box_type)
234
+
235
+ return "\n".join([top_border] + boxed_lines + [bottom_border])
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.4
2
+ Name: steboxing
3
+ Version: 1.0.0
4
+ Summary: Put your text in a stylish box.
5
+ Author: Cangreho
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/StefanoMazzuka/steboxing
8
+ Project-URL: Repository, https://github.com/StefanoMazzuka/steboxing
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Dynamic: license-file
16
+
17
+ # steboxing
18
+
19
+ A Python library for drawing Unicode text boxes around strings — supports 36 border styles using thin, bold, double, and round line characters.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install steboxing
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```python
30
+ from steboxing import boxing
31
+
32
+ print(boxing("Hello, World!", box_type="thin"))
33
+ ```
34
+
35
+ ```
36
+ ┌───────────────┐
37
+ │ Hello, World! │
38
+ └───────────────┘
39
+ ```
40
+
41
+ Multi-line strings are supported:
42
+
43
+ ```python
44
+ print(boxing("Line one\nLine two\nLine three", box_type="double"))
45
+ ```
46
+
47
+ ```
48
+ ╔════════════╗
49
+ ║ Line one ║
50
+ ║ Line two ║
51
+ ║ Line three ║
52
+ ╚════════════╝
53
+ ```
54
+
55
+ `box_type` defaults to `"thin"` if omitted.
56
+
57
+ ## Box styles
58
+
59
+ | `box_type` | Preview |
60
+ |---------------------------|------------------------------------------------|
61
+ | `thin` | `┌───────┐`<br>`│ lines │`<br>`└───────┘` |
62
+ | `double` | `╔═══════╗`<br>`║ lines ║`<br>`╚═══════╝` |
63
+ | `bold` | `┏━━━━━━━┓`<br>`┃ lines ┃`<br>`┗━━━━━━━┛` |
64
+ | `round` | `╭───────╮`<br>`│ lines │`<br>`╰───────╯` |
65
+ | `bold_top_and_bottom` | `┍━━━━━━━┑`<br>`│ lines │`<br>`┕━━━━━━━┙` |
66
+ | `double_top_and_bottom` | `╒═══════╕`<br>`│ lines │`<br>`╘═══════╛` |
67
+ | `bold_left_and_right` | `┎───────┒`<br>`┃ lines ┃`<br>`┖───────┚` |
68
+ | `double_left_and_right` | `╓───────╖`<br>`║ lines ║`<br>`╙───────╜` |
69
+ | `bold_top_only` | `┍━━━━━━━┑`<br>`│ lines │`<br>`└───────┘` |
70
+ | `double_top_only` | `╒═══════╕`<br>`│ lines │`<br>`└───────┘` |
71
+ | `bold_bottom_only` | `┌───────┐`<br>`│ lines │`<br>`┕━━━━━━━┙` |
72
+ | `double_bottom_only` | `┌───────┐`<br>`│ lines │`<br>`╘═══════╛` |
73
+ | `bold_right_only` | `┌───────┒`<br>`│ lines ┃`<br>`└───────┚` |
74
+ | `double_right_only` | `┌───────╖`<br>`│ lines ║`<br>`└───────╜` |
75
+ | `bold_left_only` | `┎───────┐`<br>`┃ lines │`<br>`┖───────┘` |
76
+ | `double_left_only` | `╓───────┐`<br>`║ lines │`<br>`╙───────┘` |
77
+ | `bold_left_and_top` | `┏━━━━━━━┑`<br>`┃ lines │`<br>`┖───────┘` |
78
+ | `double_left_and_top` | `╔═══════╕`<br>`║ lines │`<br>`╙───────┘` |
79
+ | `bold_right_and_top` | `┍━━━━━━━┓`<br>`│ lines ┃`<br>`└───────┚` |
80
+ | `double_right_and_top` | `╒═══════╗`<br>`│ lines ║`<br>`└───────╜` |
81
+ | `bold_right_and_bottom` | `┌───────┒`<br>`│ lines ┃`<br>`┕━━━━━━━┛` |
82
+ | `double_right_and_bottom` | `┌───────╖`<br>`│ lines ║`<br>`╘═══════╝` |
83
+ | `bold_left_and_bottom` | `┎───────┐`<br>`┃ lines │`<br>`┗━━━━━━━┙` |
84
+ | `double_left_and_bottom` | `╓───────┐`<br>`║ lines │`<br>`╚═══════╛` |
85
+ | `bold_but_bottom` | `┏━━━━━━━┓`<br>`┃ lines ┃`<br>`┖───────┚` |
86
+ | `double_but_bottom` | `╔═══════╗`<br>`║ lines ║`<br>`╙───────╜` |
87
+ | `bold_but_left` | `┍━━━━━━━┓`<br>`│ lines ┃`<br>`┕━━━━━━━┛` |
88
+ | `double_but_left` | `╒═══════╗`<br>`│ lines ║`<br>`╘═══════╝` |
89
+ | `bold_but_top` | `┎───────┒`<br>`┃ lines ┃`<br>`┗━━━━━━━┛` |
90
+ | `double_but_top` | `╓───────╖`<br>`║ lines ║`<br>`╚═══════╝` |
91
+ | `bold_but_right` | `┏━━━━━━━┑`<br>`┃ lines │`<br>`┗━━━━━━━┙` |
92
+ | `double_but_right` | `╔═══════╕`<br>`║ lines │`<br>`╚═══════╛` |
93
+ | `bold_corners_only` | `┏───────┓`<br>`│ lines │`<br>`┗───────┛` |
94
+ | `double_corners_only` | `╔───────╗`<br>`│ lines │`<br>`╚───────╝` |
95
+ | `bold_chain` | `┏─━─━─━─┓`<br>`│ lines │`<br>`┗─━─━─━─┛` |
96
+ | `double_chain` | `╔─═─═─═─╗`<br>`│ lines │`<br>`╚─═─═─═─╝` |
97
+
98
+ ## Error handling
99
+
100
+ Passing an invalid `box_type` raises a `ValueError` listing all valid options:
101
+
102
+ ```python
103
+ boxing("text", box_type="unknown")
104
+ # ValueError: box_type not supported: unknown. Use one of: thin, double, bold, ...
105
+ ```
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,10 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ steboxing/__init__.py
5
+ steboxing/core.py
6
+ steboxing.egg-info/PKG-INFO
7
+ steboxing.egg-info/SOURCES.txt
8
+ steboxing.egg-info/dependency_links.txt
9
+ steboxing.egg-info/top_level.txt
10
+ tests/test_core.py
@@ -0,0 +1 @@
1
+ steboxing
@@ -0,0 +1,695 @@
1
+ import unittest
2
+ from unittest import result
3
+ from steboxing.core import boxing
4
+
5
+ class TestBoxing(unittest.TestCase):
6
+ def test_wrong_box_type(self):
7
+ self.assertRaises(ValueError, lambda: boxing("hello\nworld!", box_type="wrong"))
8
+
9
+ def test_thin(self):
10
+ result_empty = boxing("", box_type="thin")
11
+ result_correct = boxing("hello\nworld!", box_type="thin")
12
+
13
+ expected_empty = (
14
+ "┌──┐\n"
15
+ "│ │\n"
16
+ "└──┘"
17
+ )
18
+ expected_correct = (
19
+ "┌────────┐\n"
20
+ "│ hello │\n"
21
+ "│ world! │\n"
22
+ "└────────┘"
23
+ )
24
+
25
+ self.assertTrue(result_empty == expected_empty)
26
+ self.assertTrue(result_correct == expected_correct)
27
+
28
+ def test_double(self):
29
+ result_empty = boxing("", box_type="double")
30
+ result_correct = boxing("hello\nworld!", box_type="double")
31
+
32
+ expected_empty = (
33
+ "╔══╗\n"
34
+ "║ ║\n"
35
+ "╚══╝"
36
+ )
37
+ expected_correct = (
38
+ "╔════════╗\n"
39
+ "║ hello ║\n"
40
+ "║ world! ║\n"
41
+ "╚════════╝"
42
+ )
43
+
44
+ self.assertTrue(result_empty == expected_empty)
45
+ self.assertTrue(result_correct == expected_correct)
46
+
47
+ def test_bold(self):
48
+ result_empty = boxing("", box_type="bold")
49
+ result_correct = boxing("hello\nworld!", box_type="bold")
50
+
51
+ expected_empty = (
52
+ "┏━━┓\n"
53
+ "┃ ┃\n"
54
+ "┗━━┛"
55
+ )
56
+ expected_correct = (
57
+ "┏━━━━━━━━┓\n"
58
+ "┃ hello ┃\n"
59
+ "┃ world! ┃\n"
60
+ "┗━━━━━━━━┛"
61
+ )
62
+
63
+ self.assertTrue(result_empty == expected_empty)
64
+ self.assertTrue(result_correct == expected_correct)
65
+
66
+ def test_round(self):
67
+ result_empty = boxing("", box_type="round")
68
+ result_correct = boxing("hello\nworld!", box_type="round")
69
+
70
+ expected_empty = (
71
+ "╭──╮\n"
72
+ "│ │\n"
73
+ "╰──╯"
74
+ )
75
+ expected_correct = (
76
+ "╭────────╮\n"
77
+ "│ hello │\n"
78
+ "│ world! │\n"
79
+ "╰────────╯"
80
+ )
81
+
82
+ self.assertTrue(result_empty == expected_empty)
83
+ self.assertTrue(result_correct == expected_correct)
84
+
85
+ def test_bold_top_and_bottom(self):
86
+ result_empty = boxing("", box_type="bold_top_and_bottom")
87
+ result_correct = boxing("hello\nworld!", box_type="bold_top_and_bottom")
88
+
89
+ expected_empty = (
90
+ "┍━━┑\n"
91
+ "│ │\n"
92
+ "┕━━┙"
93
+ )
94
+ expected_correct = (
95
+ "┍━━━━━━━━┑\n"
96
+ "│ hello │\n"
97
+ "│ world! │\n"
98
+ "┕━━━━━━━━┙"
99
+ )
100
+
101
+ self.assertTrue(result_empty == expected_empty)
102
+ self.assertTrue(result_correct == expected_correct)
103
+
104
+ def test_double_top_and_bottom(self):
105
+ result_empty = boxing("", box_type="double_top_and_bottom")
106
+ result_correct = boxing("hello\nworld!", box_type="double_top_and_bottom")
107
+
108
+ expected_empty = (
109
+ "╒══╕\n"
110
+ "│ │\n"
111
+ "╘══╛"
112
+ )
113
+ expected_correct = (
114
+ "╒════════╕\n"
115
+ "│ hello │\n"
116
+ "│ world! │\n"
117
+ "╘════════╛"
118
+ )
119
+
120
+ self.assertTrue(result_empty == expected_empty)
121
+ self.assertTrue(result_correct == expected_correct)
122
+
123
+ def test_bold_left_and_right(self):
124
+ result_empty = boxing("", box_type="bold_left_and_right")
125
+ result_correct = boxing("hello\nworld!", box_type="bold_left_and_right")
126
+
127
+ expected_empty = (
128
+ "┎──┒\n"
129
+ "┃ ┃\n"
130
+ "┖──┚"
131
+ )
132
+ expected_correct = (
133
+ "┎────────┒\n"
134
+ "┃ hello ┃\n"
135
+ "┃ world! ┃\n"
136
+ "┖────────┚"
137
+ )
138
+
139
+ self.assertTrue(result_empty == expected_empty)
140
+ self.assertTrue(result_correct == expected_correct)
141
+
142
+ def test_double_left_and_right(self):
143
+ result_empty = boxing("", box_type="double_left_and_right")
144
+ result_correct = boxing("hello\nworld!", box_type="double_left_and_right")
145
+
146
+ expected_empty = (
147
+ "╓──╖\n"
148
+ "║ ║\n"
149
+ "╙──╜"
150
+ )
151
+ expected_correct = (
152
+ "╓────────╖\n"
153
+ "║ hello ║\n"
154
+ "║ world! ║\n"
155
+ "╙────────╜"
156
+ )
157
+
158
+ self.assertTrue(result_empty == expected_empty)
159
+ self.assertTrue(result_correct == expected_correct)
160
+
161
+ def test_bold_top_only(self):
162
+ result_empty = boxing("", box_type="bold_top_only")
163
+ result_correct = boxing("hello\nworld!", box_type="bold_top_only")
164
+
165
+ expected_empty = (
166
+ "┍━━┑\n"
167
+ "│ │\n"
168
+ "└──┘"
169
+ )
170
+ expected_correct = (
171
+ "┍━━━━━━━━┑\n"
172
+ "│ hello │\n"
173
+ "│ world! │\n"
174
+ "└────────┘"
175
+ )
176
+
177
+ self.assertTrue(result_empty == expected_empty)
178
+ self.assertTrue(result_correct == expected_correct)
179
+
180
+ def test_double_top_only(self):
181
+ result_empty = boxing("", box_type="double_top_only")
182
+ result_correct = boxing("hello\nworld!", box_type="double_top_only")
183
+
184
+ expected_empty = (
185
+ "╒══╕\n"
186
+ "│ │\n"
187
+ "└──┘"
188
+ )
189
+ expected_correct = (
190
+ "╒════════╕\n"
191
+ "│ hello │\n"
192
+ "│ world! │\n"
193
+ "└────────┘"
194
+ )
195
+
196
+ self.assertTrue(result_empty == expected_empty)
197
+ self.assertTrue(result_correct == expected_correct)
198
+
199
+ def test_bold_bottom_only(self):
200
+ result_empty = boxing("", box_type="bold_bottom_only")
201
+ result_correct = boxing("hello\nworld!", box_type="bold_bottom_only")
202
+
203
+ expected_empty = (
204
+ "┌──┐\n"
205
+ "│ │\n"
206
+ "┕━━┙"
207
+ )
208
+ expected_correct = (
209
+ "┌────────┐\n"
210
+ "│ hello │\n"
211
+ "│ world! │\n"
212
+ "┕━━━━━━━━┙"
213
+ )
214
+
215
+ self.assertTrue(result_empty == expected_empty)
216
+ self.assertTrue(result_correct == expected_correct)
217
+
218
+ def test_double_bottom_only(self):
219
+ result_empty = boxing("", box_type="double_bottom_only")
220
+ result_correct = boxing("hello\nworld!", box_type="double_bottom_only")
221
+
222
+ expected_empty = (
223
+ "┌──┐\n"
224
+ "│ │\n"
225
+ "╘══╛"
226
+ )
227
+ expected_correct = (
228
+ "┌────────┐\n"
229
+ "│ hello │\n"
230
+ "│ world! │\n"
231
+ "╘════════╛"
232
+ )
233
+
234
+ self.assertTrue(result_empty == expected_empty)
235
+ self.assertTrue(result_correct == expected_correct)
236
+
237
+ def test_bold_right_only(self):
238
+ result_empty = boxing("", box_type="bold_right_only")
239
+ result_correct = boxing("hello\nworld!", box_type="bold_right_only")
240
+
241
+ expected_empty = (
242
+ "┌──┒\n"
243
+ "│ ┃\n"
244
+ "└──┚"
245
+ )
246
+ expected_correct = (
247
+ "┌────────┒\n"
248
+ "│ hello ┃\n"
249
+ "│ world! ┃\n"
250
+ "└────────┚"
251
+ )
252
+
253
+ self.assertTrue(result_empty == expected_empty)
254
+ self.assertTrue(result_correct == expected_correct)
255
+
256
+ def test_double_right_only(self):
257
+ result_empty = boxing("", box_type="double_right_only")
258
+ result_correct = boxing("hello\nworld!", box_type="double_right_only")
259
+
260
+ expected_empty = (
261
+ "┌──╖\n"
262
+ "│ ║\n"
263
+ "└──╜"
264
+ )
265
+ expected_correct = (
266
+ "┌────────╖\n"
267
+ "│ hello ║\n"
268
+ "│ world! ║\n"
269
+ "└────────╜"
270
+ )
271
+
272
+ self.assertTrue(result_empty == expected_empty)
273
+ self.assertTrue(result_correct == expected_correct)
274
+
275
+ def test_bold_left_only(self):
276
+ result_empty = boxing("", box_type="bold_left_only")
277
+ result_correct = boxing("hello\nworld!", box_type="bold_left_only")
278
+
279
+ expected_empty = (
280
+ "┎──┐\n"
281
+ "┃ │\n"
282
+ "┖──┘"
283
+ )
284
+ expected_correct = (
285
+ "┎────────┐\n"
286
+ "┃ hello │\n"
287
+ "┃ world! │\n"
288
+ "┖────────┘"
289
+ )
290
+
291
+ self.assertTrue(result_empty == expected_empty)
292
+ self.assertTrue(result_correct == expected_correct)
293
+
294
+ def test_double_left_only(self):
295
+ result_empty = boxing("", box_type="double_left_only")
296
+ result_correct = boxing("hello\nworld!", box_type="double_left_only")
297
+
298
+ expected_empty = (
299
+ "╓──┐\n"
300
+ "║ │\n"
301
+ "╙──┘"
302
+ )
303
+ expected_correct = (
304
+ "╓────────┐\n"
305
+ "║ hello │\n"
306
+ "║ world! │\n"
307
+ "╙────────┘"
308
+ )
309
+
310
+ self.assertTrue(result_empty == expected_empty)
311
+ self.assertTrue(result_correct == expected_correct)
312
+
313
+ def test_bold_left_and_top(self):
314
+ result_empty = boxing("", box_type="bold_left_and_top")
315
+ result_correct = boxing("hello\nworld!", box_type="bold_left_and_top")
316
+
317
+ expected_empty = (
318
+ "┏━━┑\n"
319
+ "┃ │\n"
320
+ "┖──┘"
321
+ )
322
+ expected_correct = (
323
+ "┏━━━━━━━━┑\n"
324
+ "┃ hello │\n"
325
+ "┃ world! │\n"
326
+ "┖────────┘"
327
+ )
328
+
329
+ self.assertTrue(result_empty == expected_empty)
330
+ self.assertTrue(result_correct == expected_correct)
331
+
332
+ def test_double_left_and_top(self):
333
+ result_empty = boxing("", box_type="double_left_and_top")
334
+ result_correct = boxing("hello\nworld!", box_type="double_left_and_top")
335
+
336
+ expected_empty = (
337
+ "╔══╕\n"
338
+ "║ │\n"
339
+ "╙──┘"
340
+ )
341
+ expected_correct = (
342
+ "╔════════╕\n"
343
+ "║ hello │\n"
344
+ "║ world! │\n"
345
+ "╙────────┘"
346
+ )
347
+
348
+ self.assertTrue(result_empty == expected_empty)
349
+ self.assertTrue(result_correct == expected_correct)
350
+
351
+ def test_bold_right_and_top(self):
352
+ result_empty = boxing("", box_type="bold_right_and_top")
353
+ result_correct = boxing("hello\nworld!", box_type="bold_right_and_top")
354
+
355
+ expected_empty = (
356
+ "┍━━┓\n"
357
+ "│ ┃\n"
358
+ "└──┚"
359
+ )
360
+ expected_correct = (
361
+ "┍━━━━━━━━┓\n"
362
+ "│ hello ┃\n"
363
+ "│ world! ┃\n"
364
+ "└────────┚"
365
+ )
366
+
367
+ self.assertTrue(result_empty == expected_empty)
368
+ self.assertTrue(result_correct == expected_correct)
369
+
370
+ def test_double_right_and_top(self):
371
+ result_empty = boxing("", box_type="double_right_and_top")
372
+ result_correct = boxing("hello\nworld!", box_type="double_right_and_top")
373
+
374
+ expected_empty = (
375
+ "╒══╗\n"
376
+ "│ ║\n"
377
+ "└──╜"
378
+ )
379
+ expected_correct = (
380
+ "╒════════╗\n"
381
+ "│ hello ║\n"
382
+ "│ world! ║\n"
383
+ "└────────╜"
384
+ )
385
+
386
+ self.assertTrue(result_empty == expected_empty)
387
+ self.assertTrue(result_correct == expected_correct)
388
+
389
+ def test_bold_right_and_bottom(self):
390
+ result_empty = boxing("", box_type="bold_right_and_bottom")
391
+ result_correct = boxing("hello\nworld!", box_type="bold_right_and_bottom")
392
+
393
+ expected_empty = (
394
+ "┌──┒\n"
395
+ "│ ┃\n"
396
+ "┕━━┛"
397
+ )
398
+ expected_correct = (
399
+ "┌────────┒\n"
400
+ "│ hello ┃\n"
401
+ "│ world! ┃\n"
402
+ "┕━━━━━━━━┛"
403
+ )
404
+
405
+ self.assertTrue(result_empty == expected_empty)
406
+ self.assertTrue(result_correct == expected_correct)
407
+
408
+ def test_double_right_and_bottom(self):
409
+ result_empty = boxing("", box_type="double_right_and_bottom")
410
+ result_correct = boxing("hello\nworld!", box_type="double_right_and_bottom")
411
+
412
+ expected_empty = (
413
+ "┌──╖\n"
414
+ "│ ║\n"
415
+ "╘══╝"
416
+ )
417
+ expected_correct = (
418
+ "┌────────╖\n"
419
+ "│ hello ║\n"
420
+ "│ world! ║\n"
421
+ "╘════════╝"
422
+ )
423
+
424
+ self.assertTrue(result_empty == expected_empty)
425
+ self.assertTrue(result_correct == expected_correct)
426
+
427
+ def test_bold_left_and_bottom(self):
428
+ result_empty = boxing("", box_type="bold_left_and_bottom")
429
+ result_correct = boxing("hello\nworld!", box_type="bold_left_and_bottom")
430
+
431
+ expected_empty = (
432
+ "┎──┐\n"
433
+ "┃ │\n"
434
+ "┗━━┙"
435
+ )
436
+ expected_correct = (
437
+ "┎────────┐\n"
438
+ "┃ hello │\n"
439
+ "┃ world! │\n"
440
+ "┗━━━━━━━━┙"
441
+ )
442
+
443
+ self.assertTrue(result_empty == expected_empty)
444
+ self.assertTrue(result_correct == expected_correct)
445
+
446
+ def test_double_left_and_bottom(self):
447
+ result_empty = boxing("", box_type="double_left_and_bottom")
448
+ result_correct = boxing("hello\nworld!", box_type="double_left_and_bottom")
449
+
450
+ expected_empty = (
451
+ "╓──┐\n"
452
+ "║ │\n"
453
+ "╚══╛"
454
+ )
455
+ expected_correct = (
456
+ "╓────────┐\n"
457
+ "║ hello │\n"
458
+ "║ world! │\n"
459
+ "╚════════╛"
460
+ )
461
+
462
+ self.assertTrue(result_empty == expected_empty)
463
+ self.assertTrue(result_correct == expected_correct)
464
+
465
+ def test_bold_but_bottom(self):
466
+ result_empty = boxing("", box_type="bold_but_bottom")
467
+ result_correct = boxing("hello\nworld!", box_type="bold_but_bottom")
468
+
469
+ expected_empty = (
470
+ "┏━━┓\n"
471
+ "┃ ┃\n"
472
+ "┖──┚"
473
+ )
474
+ expected_correct = (
475
+ "┏━━━━━━━━┓\n"
476
+ "┃ hello ┃\n"
477
+ "┃ world! ┃\n"
478
+ "┖────────┚"
479
+ )
480
+
481
+ self.assertTrue(result_empty == expected_empty)
482
+ self.assertTrue(result_correct == expected_correct)
483
+
484
+ def test_double_but_bottom(self):
485
+ result_empty = boxing("", box_type="double_but_bottom")
486
+ result_correct = boxing("hello\nworld!", box_type="double_but_bottom")
487
+
488
+ expected_empty = (
489
+ "╔══╗\n"
490
+ "║ ║\n"
491
+ "╙──╜"
492
+ )
493
+ expected_correct = (
494
+ "╔════════╗\n"
495
+ "║ hello ║\n"
496
+ "║ world! ║\n"
497
+ "╙────────╜"
498
+ )
499
+
500
+ self.assertTrue(result_empty == expected_empty)
501
+ self.assertTrue(result_correct == expected_correct)
502
+
503
+ def test_bold_but_left(self):
504
+ result_empty = boxing("", box_type="bold_but_left")
505
+ result_correct = boxing("hello\nworld!", box_type="bold_but_left")
506
+
507
+ expected_empty = (
508
+ "┍━━┓\n"
509
+ "│ ┃\n"
510
+ "┕━━┛"
511
+ )
512
+ expected_correct = (
513
+ "┍━━━━━━━━┓\n"
514
+ "│ hello ┃\n"
515
+ "│ world! ┃\n"
516
+ "┕━━━━━━━━┛"
517
+ )
518
+
519
+ self.assertTrue(result_empty == expected_empty)
520
+ self.assertTrue(result_correct == expected_correct)
521
+
522
+ def test_double_but_left(self):
523
+ result_empty = boxing("", box_type="double_but_left")
524
+ result_correct = boxing("hello\nworld!", box_type="double_but_left")
525
+
526
+ expected_empty = (
527
+ "╒══╗\n"
528
+ "│ ║\n"
529
+ "╘══╝"
530
+ )
531
+ expected_correct = (
532
+ "╒════════╗\n"
533
+ "│ hello ║\n"
534
+ "│ world! ║\n"
535
+ "╘════════╝"
536
+ )
537
+
538
+ self.assertTrue(result_empty == expected_empty)
539
+ self.assertTrue(result_correct == expected_correct)
540
+
541
+ def test_bold_but_top(self):
542
+ result_empty = boxing("", box_type="bold_but_top")
543
+ result_correct = boxing("hello\nworld!", box_type="bold_but_top")
544
+
545
+ expected_empty = (
546
+ "┎──┒\n"
547
+ "┃ ┃\n"
548
+ "┗━━┛"
549
+ )
550
+ expected_correct = (
551
+ "┎────────┒\n"
552
+ "┃ hello ┃\n"
553
+ "┃ world! ┃\n"
554
+ "┗━━━━━━━━┛"
555
+ )
556
+
557
+ self.assertTrue(result_empty == expected_empty)
558
+ self.assertTrue(result_correct == expected_correct)
559
+
560
+ def test_double_but_top(self):
561
+ result_empty = boxing("", box_type="double_but_top")
562
+ result_correct = boxing("hello\nworld!", box_type="double_but_top")
563
+
564
+ expected_empty = (
565
+ "╓──╖\n"
566
+ "║ ║\n"
567
+ "╚══╝"
568
+ )
569
+ expected_correct = (
570
+ "╓────────╖\n"
571
+ "║ hello ║\n"
572
+ "║ world! ║\n"
573
+ "╚════════╝"
574
+ )
575
+
576
+ self.assertTrue(result_empty == expected_empty)
577
+ self.assertTrue(result_correct == expected_correct)
578
+
579
+ def test_bold_but_right(self):
580
+ result_empty = boxing("", box_type="bold_but_right")
581
+ result_correct = boxing("hello\nworld!", box_type="bold_but_right")
582
+
583
+ expected_empty = (
584
+ "┏━━┑\n"
585
+ "┃ │\n"
586
+ "┗━━┙"
587
+ )
588
+ expected_correct = (
589
+ "┏━━━━━━━━┑\n"
590
+ "┃ hello │\n"
591
+ "┃ world! │\n"
592
+ "┗━━━━━━━━┙"
593
+ )
594
+
595
+ self.assertTrue(result_empty == expected_empty)
596
+ self.assertTrue(result_correct == expected_correct)
597
+
598
+ def test_double_but_right(self):
599
+ result_empty = boxing("", box_type="double_but_right")
600
+ result_correct = boxing("hello\nworld!", box_type="double_but_right")
601
+
602
+ expected_empty = (
603
+ "╔══╕\n"
604
+ "║ │\n"
605
+ "╚══╛"
606
+ )
607
+ expected_correct = (
608
+ "╔════════╕\n"
609
+ "║ hello │\n"
610
+ "║ world! │\n"
611
+ "╚════════╛"
612
+ )
613
+
614
+ self.assertTrue(result_empty == expected_empty)
615
+ self.assertTrue(result_correct == expected_correct)
616
+
617
+ def test_bold_corners_only(self):
618
+ result_empty = boxing("", box_type="bold_corners_only")
619
+ result_correct = boxing("hello\nworld!", box_type="bold_corners_only")
620
+
621
+ expected_empty = (
622
+ "┏──┓\n"
623
+ "│ │\n"
624
+ "┗──┛"
625
+ )
626
+ expected_correct = (
627
+ "┏────────┓\n"
628
+ "│ hello │\n"
629
+ "│ world! │\n"
630
+ "┗────────┛"
631
+ )
632
+
633
+ self.assertTrue(result_empty == expected_empty)
634
+ self.assertTrue(result_correct == expected_correct)
635
+
636
+ def test_double_corners_only(self):
637
+ result_empty = boxing("", box_type="double_corners_only")
638
+ result_correct = boxing("hello\nworld!", box_type="double_corners_only")
639
+
640
+ expected_empty = (
641
+ "╔──╗\n"
642
+ "│ │\n"
643
+ "╚──╝"
644
+ )
645
+ expected_correct = (
646
+ "╔────────╗\n"
647
+ "│ hello │\n"
648
+ "│ world! │\n"
649
+ "╚────────╝"
650
+ )
651
+
652
+ self.assertTrue(result_empty == expected_empty)
653
+ self.assertTrue(result_correct == expected_correct)
654
+
655
+ def test_bold_chain(self):
656
+ result_empty = boxing("", box_type="bold_chain")
657
+ result_correct = boxing("hello\nworld!", box_type="bold_chain")
658
+
659
+ expected_empty = (
660
+ "┏─━┓\n"
661
+ "│ │\n"
662
+ "┗─━┛"
663
+ )
664
+ expected_correct = (
665
+ "┏─━─━─━─━┓\n"
666
+ "│ hello │\n"
667
+ "┃ world! ┃\n"
668
+ "┗─━─━─━─━┛"
669
+ )
670
+
671
+ self.assertTrue(result_empty == expected_empty)
672
+ self.assertTrue(result_correct == expected_correct)
673
+
674
+ def test_double_chain(self):
675
+ result_empty = boxing("", box_type="double_chain")
676
+ result_correct = boxing("hello\nworld!", box_type="double_chain")
677
+
678
+ expected_empty = (
679
+ "╔─═╗\n"
680
+ "│ │\n"
681
+ "╚─═╝"
682
+ )
683
+ expected_correct = (
684
+ "╔─═─═─═─═╗\n"
685
+ "│ hello │\n"
686
+ "║ world! ║\n"
687
+ "╚─═─═─═─═╝"
688
+ )
689
+
690
+ self.assertTrue(result_empty == expected_empty)
691
+ self.assertTrue(result_correct == expected_correct)
692
+
693
+
694
+ if __name__ == "__main__":
695
+ unittest.main()