txtwrap 2.3.0__tar.gz → 2.3.2__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,31 +1,47 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: txtwrap
3
- Version: 2.3.0
3
+ Version: 2.3.2
4
4
  Summary: A tool for wrapping and filling text.
5
5
  Home-page: https://github.com/azzammuhyala/txtwrap
6
6
  Author: azzammuhyala
7
7
  Author-email: azzammuhyala@gmail.com
8
8
  License: MIT
9
9
  Keywords: wrap,wrapper,wrapping,wrapped,text wrap,text wrapper,text wrapping,text wrapped
10
+ Classifier: Programming Language :: Python
10
11
  Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.3
11
13
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
12
- Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Topic :: Text Processing
15
+ Classifier: Topic :: Text Processing :: Filters
13
16
  Requires-Python: >=3.3
14
17
  Description-Content-Type: text/markdown
18
+ Dynamic: author
19
+ Dynamic: author-email
20
+ Dynamic: classifier
21
+ Dynamic: description
22
+ Dynamic: description-content-type
23
+ Dynamic: home-page
24
+ Dynamic: keywords
25
+ Dynamic: license
26
+ Dynamic: requires-python
27
+ Dynamic: summary
15
28
 
16
29
  # TxTWrap🔡
17
30
  A tool for wrapping and filling text.🔨
18
31
 
19
- - `LOREM_IPSUM_WORDS`
20
- - `LOREM_IPSUM_SENTENCES`
21
- - `LOREM_IPSUM_PARAGRAPHS`
22
- - `TextWrapper` (✅ Updated)
23
- - `sanitize` (➕ New)
24
- - `wrap` (✅ Updated)
25
- - `align` (✅ Updated)
26
- - `fillstr` ( Updated)
27
- - `printwrap` (✅ Updated)
28
- - `shorten` (✅ Updated)
32
+ Version: **2.3.2** <br>
33
+ Python requires version: **3.3.0+** <br>
34
+ Python stub file requires version: **3.8.0+**
35
+
36
+ - [`LOREM_IPSUM_WORDS`](#lorem-ipsum)
37
+ - [`LOREM_IPSUM_SENTENCES`](#lorem-ipsum)
38
+ - [`LOREM_IPSUM_PARAGRAPHS`](#lorem-ipsum)
39
+ - [`TextWrapper`](#textwrapper) (🔨 Fixed)
40
+ - [`sanitize`](#sanitizetext)
41
+ - [`wrap`](#wraptext-return_detailsfalse)
42
+ - [`align`](#aligntext-return_detailsfalse)
43
+ - [`fillstr`](#fillstrtext)
44
+ - [`shorten`](#shortentext)
29
45
 
30
46
  # Documents📄
31
47
  This module is inspired by the [`textwrap`](https://docs.python.org/3/library/textwrap.html) module, which provides
@@ -33,17 +49,18 @@ several useful functions, along with the [`TextWrapper`](#textwrapper), class th
33
49
 
34
50
  The difference between [`txtwrap`](https://pypi.org/project/txtwrap) and
35
51
  [`textwrap`](https://docs.python.org/3/library/textwrap.html) is that this module is designed not only for wrapping and
36
- filling monospace fonts but also for other font types, such as Arial, Times New Roman, and more.
52
+ filling _monospace fonts_ but also for other font types, such as _Arial_, _Times New Roman_, and more.
37
53
 
38
54
  <h1></h1>
39
55
 
56
+ ## Lorem ipsum
40
57
  ```py
41
58
  LOREM_IPSUM_WORDS
42
59
  LOREM_IPSUM_SENTENCES
43
60
  LOREM_IPSUM_PARAGRAPHS
44
61
  ```
45
- A collection of words, sentences, and paragraphs that can be used as examples.
46
- - `LOREM_IPSUM_WORDS` contains a short Lorem Ipsum sentence.
62
+ A _Lorem Ipsum_ collection of words, sentences, and paragraphs that can be used as examples.
63
+ - `LOREM_IPSUM_WORDS` contains a short sentence.
47
64
  - `LOREM_IPSUM_SENTENCES` contains a slightly longer paragraph.
48
65
  - `LOREM_IPSUM_PARAGRAPHS` contains several longer paragraphs.
49
66
 
@@ -100,15 +117,14 @@ as each attribute has type checking, which may reduce performance.
100
117
  <h1></h1>
101
118
 
102
119
  #### **`method`**
103
- (Default: `'word'`) The wrapping method. Available options: `'mono'` and `'word'`.
120
+ (Default: `'word'`) The wrapping method. Available options:
104
121
  - `'mono'` method wraps text character by character.
105
122
  - `'word'` method wraps text word by word.
106
123
 
107
124
  <h1></h1>
108
125
 
109
126
  #### **`alignment`**
110
- (Default: `'left'`) The alignment of the wrapped text. Available options: `'left'`, `'center'`, `'right'`,
111
- (`'fill'` or `'fill-left'`), `'fill-center'`, and `'fill-right'`.
127
+ (Default: `'left'`) The alignment of the wrapped text. Available options:
112
128
  - `'left'`: Aligns text to the start of the line.
113
129
  - `'center'`: Centers text within the line.
114
130
  - `'right'`: Aligns text to the end of the line.
@@ -133,7 +149,7 @@ as each attribute has type checking, which may reduce performance.
133
149
  (Default: `None`) The character used to separate words.
134
150
  - `None`: Uses whitespace as the separator.
135
151
  - `str`: Uses the specified character.
136
- - `Iterable`: Uses multiple specified characters.
152
+ - `Iterable[str]`: Uses multiple specified characters.
137
153
 
138
154
  <h1></h1>
139
155
 
@@ -180,6 +196,8 @@ If the function calculates only the width, it must return a single value of type
180
196
 
181
197
  ### Methods of [`TextWrapper`](#textwrapper):
182
198
 
199
+ > Note: All methods can be called outside the [`TextWrapper`](#textwrapper) like external functions.
200
+
183
201
  <h1></h1>
184
202
 
185
203
  #### **`copy`**
@@ -193,7 +211,7 @@ character.
193
211
 
194
212
  For example:
195
213
  ```py
196
- >>> TextWrapper().sanitize("\tHello World! ")
214
+ >>> TextWrapper().sanitize("\tHello \nWorld!\r ")
197
215
  'Hello World!'
198
216
  ```
199
217
 
@@ -202,7 +220,7 @@ For example:
202
220
  #### **`wrap(text, return_details=False)`**
203
221
  Returns a list of wrapped text strings. If `return_details=True`, returns a dictionary containing:
204
222
  - `'wrapped'`: A list of wrapped text fragments.
205
- - `'indiced'`: A set of indices marking line breaks (starting from `0`, like programming indices).
223
+ - `'indiced'`: A set of indices marking the end of line (starting from `0`, like programming indices).
206
224
 
207
225
  For example:
208
226
  ```py
@@ -215,7 +233,7 @@ For example:
215
233
  <h1></h1>
216
234
 
217
235
  #### **`align(text, return_details=False)`**
218
- Returns a list of tuples, where each tuple contains `(x, y, text)`, representing the wrapped text along with its
236
+ Returns a list of tuples, where each tuple contains `(xPosition, yPosition, text)`, representing the wrapped text along with its
219
237
  coordinates.
220
238
  > Note: [`sizefunc`](#sizefunc) must return both width and height.
221
239
 
@@ -238,7 +256,7 @@ For example:
238
256
 
239
257
  #### **`fillstr(text)`**
240
258
  Returns a string with wrapped text formatted for monospace fonts.
241
- > Note: [`width`](#width), [`line_padding`](#line_padding), and the output of [`sizefunc`](#sizefunc) must return `int`,
259
+ > Note: [`width`](#width), [`line_padding`](#line_padding), and the output of [`sizefunc`](#sizefunc) (size or just length) must return `int`,
242
260
  not `float`!
243
261
 
244
262
  For example:
@@ -1,16 +1,19 @@
1
1
  # TxTWrap🔡
2
2
  A tool for wrapping and filling text.🔨
3
3
 
4
- - `LOREM_IPSUM_WORDS`
5
- - `LOREM_IPSUM_SENTENCES`
6
- - `LOREM_IPSUM_PARAGRAPHS`
7
- - `TextWrapper` (✅ Updated)
8
- - `sanitize` (➕ New)
9
- - `wrap` (✅ Updated)
10
- - `align` (✅ Updated)
11
- - `fillstr` ( Updated)
12
- - `printwrap` (✅ Updated)
13
- - `shorten` (✅ Updated)
4
+ Version: **2.3.2** <br>
5
+ Python requires version: **3.3.0+** <br>
6
+ Python stub file requires version: **3.8.0+**
7
+
8
+ - [`LOREM_IPSUM_WORDS`](#lorem-ipsum)
9
+ - [`LOREM_IPSUM_SENTENCES`](#lorem-ipsum)
10
+ - [`LOREM_IPSUM_PARAGRAPHS`](#lorem-ipsum)
11
+ - [`TextWrapper`](#textwrapper) (🔨 Fixed)
12
+ - [`sanitize`](#sanitizetext)
13
+ - [`wrap`](#wraptext-return_detailsfalse)
14
+ - [`align`](#aligntext-return_detailsfalse)
15
+ - [`fillstr`](#fillstrtext)
16
+ - [`shorten`](#shortentext)
14
17
 
15
18
  # Documents📄
16
19
  This module is inspired by the [`textwrap`](https://docs.python.org/3/library/textwrap.html) module, which provides
@@ -18,17 +21,18 @@ several useful functions, along with the [`TextWrapper`](#textwrapper), class th
18
21
 
19
22
  The difference between [`txtwrap`](https://pypi.org/project/txtwrap) and
20
23
  [`textwrap`](https://docs.python.org/3/library/textwrap.html) is that this module is designed not only for wrapping and
21
- filling monospace fonts but also for other font types, such as Arial, Times New Roman, and more.
24
+ filling _monospace fonts_ but also for other font types, such as _Arial_, _Times New Roman_, and more.
22
25
 
23
26
  <h1></h1>
24
27
 
28
+ ## Lorem ipsum
25
29
  ```py
26
30
  LOREM_IPSUM_WORDS
27
31
  LOREM_IPSUM_SENTENCES
28
32
  LOREM_IPSUM_PARAGRAPHS
29
33
  ```
30
- A collection of words, sentences, and paragraphs that can be used as examples.
31
- - `LOREM_IPSUM_WORDS` contains a short Lorem Ipsum sentence.
34
+ A _Lorem Ipsum_ collection of words, sentences, and paragraphs that can be used as examples.
35
+ - `LOREM_IPSUM_WORDS` contains a short sentence.
32
36
  - `LOREM_IPSUM_SENTENCES` contains a slightly longer paragraph.
33
37
  - `LOREM_IPSUM_PARAGRAPHS` contains several longer paragraphs.
34
38
 
@@ -85,15 +89,14 @@ as each attribute has type checking, which may reduce performance.
85
89
  <h1></h1>
86
90
 
87
91
  #### **`method`**
88
- (Default: `'word'`) The wrapping method. Available options: `'mono'` and `'word'`.
92
+ (Default: `'word'`) The wrapping method. Available options:
89
93
  - `'mono'` method wraps text character by character.
90
94
  - `'word'` method wraps text word by word.
91
95
 
92
96
  <h1></h1>
93
97
 
94
98
  #### **`alignment`**
95
- (Default: `'left'`) The alignment of the wrapped text. Available options: `'left'`, `'center'`, `'right'`,
96
- (`'fill'` or `'fill-left'`), `'fill-center'`, and `'fill-right'`.
99
+ (Default: `'left'`) The alignment of the wrapped text. Available options:
97
100
  - `'left'`: Aligns text to the start of the line.
98
101
  - `'center'`: Centers text within the line.
99
102
  - `'right'`: Aligns text to the end of the line.
@@ -118,7 +121,7 @@ as each attribute has type checking, which may reduce performance.
118
121
  (Default: `None`) The character used to separate words.
119
122
  - `None`: Uses whitespace as the separator.
120
123
  - `str`: Uses the specified character.
121
- - `Iterable`: Uses multiple specified characters.
124
+ - `Iterable[str]`: Uses multiple specified characters.
122
125
 
123
126
  <h1></h1>
124
127
 
@@ -165,6 +168,8 @@ If the function calculates only the width, it must return a single value of type
165
168
 
166
169
  ### Methods of [`TextWrapper`](#textwrapper):
167
170
 
171
+ > Note: All methods can be called outside the [`TextWrapper`](#textwrapper) like external functions.
172
+
168
173
  <h1></h1>
169
174
 
170
175
  #### **`copy`**
@@ -178,7 +183,7 @@ character.
178
183
 
179
184
  For example:
180
185
  ```py
181
- >>> TextWrapper().sanitize("\tHello World! ")
186
+ >>> TextWrapper().sanitize("\tHello \nWorld!\r ")
182
187
  'Hello World!'
183
188
  ```
184
189
 
@@ -187,7 +192,7 @@ For example:
187
192
  #### **`wrap(text, return_details=False)`**
188
193
  Returns a list of wrapped text strings. If `return_details=True`, returns a dictionary containing:
189
194
  - `'wrapped'`: A list of wrapped text fragments.
190
- - `'indiced'`: A set of indices marking line breaks (starting from `0`, like programming indices).
195
+ - `'indiced'`: A set of indices marking the end of line (starting from `0`, like programming indices).
191
196
 
192
197
  For example:
193
198
  ```py
@@ -200,7 +205,7 @@ For example:
200
205
  <h1></h1>
201
206
 
202
207
  #### **`align(text, return_details=False)`**
203
- Returns a list of tuples, where each tuple contains `(x, y, text)`, representing the wrapped text along with its
208
+ Returns a list of tuples, where each tuple contains `(xPosition, yPosition, text)`, representing the wrapped text along with its
204
209
  coordinates.
205
210
  > Note: [`sizefunc`](#sizefunc) must return both width and height.
206
211
 
@@ -223,7 +228,7 @@ For example:
223
228
 
224
229
  #### **`fillstr(text)`**
225
230
  Returns a string with wrapped text formatted for monospace fonts.
226
- > Note: [`width`](#width), [`line_padding`](#line_padding), and the output of [`sizefunc`](#sizefunc) must return `int`,
231
+ > Note: [`width`](#width), [`line_padding`](#line_padding), and the output of [`sizefunc`](#sizefunc) (size or just length) must return `int`,
227
232
  not `float`!
228
233
 
229
234
  For example:
@@ -5,7 +5,7 @@ with open('README.md', encoding='utf-8') as readme:
5
5
 
6
6
  setup(
7
7
  name='txtwrap',
8
- version='2.3.0',
8
+ version='2.3.2',
9
9
  description='A tool for wrapping and filling text.',
10
10
  long_description=long_description,
11
11
  long_description_content_type='text/markdown',
@@ -18,8 +18,11 @@ setup(
18
18
  include_package_data=True,
19
19
  keywords=['wrap', 'wrapper', 'wrapping', 'wrapped', 'text wrap', 'text wrapper', 'text wrapping', 'text wrapped'],
20
20
  classifiers=[
21
+ 'Programming Language :: Python',
21
22
  'Programming Language :: Python :: 3',
23
+ 'Programming Language :: Python :: 3.3',
22
24
  'Topic :: Software Development :: Libraries :: Python Modules',
23
- 'License :: OSI Approved :: MIT License'
25
+ 'Topic :: Text Processing',
26
+ 'Topic :: Text Processing :: Filters'
24
27
  ]
25
28
  )
@@ -1,4 +1,4 @@
1
- # This stub files supports in Python 3.9+, I guess..
1
+ # This stub file supports in Python 3.8+
2
2
 
3
3
  from typing import overload, Callable, Dict, Iterable, List, Literal, Optional, Set, Tuple, Union
4
4
 
@@ -35,7 +35,7 @@ class TextWrapper:
35
35
  minimum_width: bool = True,
36
36
  justify_last_line: bool = False,
37
37
  break_on_hyphens: bool = True,
38
- sizefunc: Optional[Callable[[str], Union[Tuple[Union[int, float], Union[int, float]], int, float]]] = None,
38
+ sizefunc: Optional[Callable[[str], Union[Tuple[Union[int, float], Union[int, float]], int, float]]] = None
39
39
  ) -> None: ...
40
40
  def __repr__(self) -> str: ...
41
41
  def __str__(self) -> str: ...
@@ -51,7 +51,7 @@ class TextWrapper:
51
51
  @property
52
52
  def method(self) -> Literal['mono', 'word']: ...
53
53
  @property
54
- def alignment(self) -> Literal['left', 'center', 'right', 'fill', 'fill-left', 'fill-center', 'fill-right']: ...
54
+ def alignment(self) -> Literal['left', 'center', 'right', 'fill-left', 'fill-center', 'fill-right']: ...
55
55
  @property
56
56
  def placeholder(self) -> str: ...
57
57
  @property
@@ -69,7 +69,8 @@ class TextWrapper:
69
69
  @property
70
70
  def break_on_hyphens(self) -> bool: ...
71
71
  @property
72
- def sizefunc(self) -> Callable[[str], Union[Tuple[Union[int, float], Union[int, float]], int, float]]: ...
72
+ def sizefunc(self) -> Union[Callable[[str], Union[Tuple[Union[int, float], Union[int, float]],
73
+ int, float]], None]: ...
73
74
 
74
75
  # Setters ----------------------------------------------------------------------------------------------------------
75
76
 
@@ -1,11 +1,22 @@
1
+ """
2
+ Internal txtwrap module
3
+ """
4
+
1
5
  from collections.abc import Iterable
2
6
  from re import compile, escape
3
7
 
4
8
  # Tools ----------------------------------------------------------------------------------------------------------------
5
9
 
10
+ pdict = type('pdict', (dict,), {
11
+ '__repr__': lambda self : '{}({})'.format(self.__class__.__name__, dict.__repr__(self)),
12
+ '__setattr__': dict.__setitem__,
13
+ '__getattr__': lambda self, key: self.get(key, None),
14
+ '__delattr__': dict.__delitem__
15
+ })
16
+
6
17
  split_hyphenated = compile(r'(?<=-)(?=(?!-).)').split
7
18
 
8
- def mono(text, width, fillchar, break_on_hyphens, lenfunc, sanitize, split_separator):
19
+ def mono(text, width, _0, _1, lenfunc, sanitize, _2):
9
20
  wrapped = []
10
21
  current_char = ''
11
22
 
@@ -38,8 +49,7 @@ def word(text, width, fillchar, break_on_hyphens, lenfunc, sanitize, split_separ
38
49
 
39
50
  if break_on_hyphens:
40
51
  for part in split_hyphenated(word):
41
- for wrapped_part in mono(part, width, fillchar, break_on_hyphens, lenfunc, sanitize,
42
- split_separator):
52
+ for wrapped_part in mono(part, width, None, None, lenfunc, sanitize, None):
43
53
  if lenfunc(current_line + wrapped_part) <= width:
44
54
  current_line += wrapped_part
45
55
  else:
@@ -47,7 +57,7 @@ def word(text, width, fillchar, break_on_hyphens, lenfunc, sanitize, split_separ
47
57
  wrapped.append(current_line)
48
58
  current_line = wrapped_part
49
59
  else:
50
- for part in mono(word, width, fillchar, break_on_hyphens, lenfunc, sanitize, split_separator):
60
+ for part in mono(word, width, None, None, lenfunc, sanitize, None):
51
61
  if lenfunc(current_line + part) <= width:
52
62
  current_line += part
53
63
  else:
@@ -60,7 +70,7 @@ def word(text, width, fillchar, break_on_hyphens, lenfunc, sanitize, split_separ
60
70
 
61
71
  return wrapped
62
72
 
63
- def jusitfy_align_left(aligned_positions, text, width, text_width, offset_y):
73
+ def jusitfy_align_left(aligned_positions, text, _0, _1, offset_y):
64
74
  aligned_positions.append((0, offset_y, text))
65
75
 
66
76
  def justify_align_center(aligned_positions, text, width, text_width, offset_y):
@@ -82,7 +92,7 @@ def justify_fillstr_right(justified_lines, text, width, text_width, fillchar):
82
92
 
83
93
  # Identities -----------------------------------------------------------------------------------------------------------
84
94
 
85
- __version__ = '2.3.0'
95
+ __version__ = '2.3.2'
86
96
  __author__ = 'azzammuhyala'
87
97
  __license__ = 'MIT'
88
98
 
@@ -123,7 +133,7 @@ LOREM_IPSUM_PARAGRAPHS = (
123
133
 
124
134
  class TextWrapper:
125
135
 
126
- """ A class for text wrapping. """
136
+ """ Text wrapper class """
127
137
 
128
138
  # Dunder / Magic Methods -------------------------------------------------------------------------------------------
129
139
 
@@ -138,13 +148,13 @@ class TextWrapper:
138
148
  [PyPi](https://pypi.org/project/txtwrap) for details.
139
149
  """
140
150
 
141
- self._d = {} # dictionary to store a metadata and private variables
151
+ # dictionary to store a metadata and private variables
152
+ self._d = pdict()
142
153
 
143
154
  self.width = width
144
155
  self.line_padding = line_padding
145
156
  self.method = method
146
157
  self.alignment = alignment
147
- self.sizefunc = sizefunc
148
158
  self.placeholder = placeholder
149
159
  self.fillchar = fillchar
150
160
  self.separator = separator
@@ -153,14 +163,24 @@ class TextWrapper:
153
163
  self.minimum_width = minimum_width
154
164
  self.justify_last_line = justify_last_line
155
165
  self.break_on_hyphens = break_on_hyphens
166
+ self.sizefunc = sizefunc
156
167
 
157
168
  def __repr__(self):
158
- return 'TextWrapper({})'.format(', '.join('{}={!r}'.format(name, self._d.get(name))
159
- for name in self.__init__.__code__.co_varnames
160
- if name != 'self'))
169
+ return '{}({})'.format(
170
+ self.__class__.__name__,
171
+ ', '.join(
172
+ '{}={!r}'.format(name, getattr(self, name))
173
+ for name in self.__init__.__code__.co_varnames
174
+ if name != 'self'
175
+ )
176
+ )
161
177
 
162
178
  def __str__(self):
163
- return '<{}.TextWrapper object at 0x{}>'.format(self.__class__.__module__, hex(id(self))[2:].upper().zfill(16))
179
+ return '<{}.{} object at 0x{}>'.format(
180
+ self.__class__.__module__,
181
+ self.__class__.__name__,
182
+ hex(id(self))[2:].upper().zfill(16)
183
+ )
164
184
 
165
185
  def __copy__(self):
166
186
  return self.copy()
@@ -172,55 +192,55 @@ class TextWrapper:
172
192
 
173
193
  @property
174
194
  def width(self):
175
- return self._d['width']
195
+ return self._d.width
176
196
 
177
197
  @property
178
198
  def line_padding(self):
179
- return self._d['line_padding']
199
+ return self._d.line_padding
180
200
 
181
201
  @property
182
202
  def method(self):
183
- return self._d['method']
203
+ return self._d.method
184
204
 
185
205
  @property
186
206
  def alignment(self):
187
- return self._d['alignment']
207
+ return self._d.alignment
188
208
 
189
209
  @property
190
210
  def placeholder(self):
191
- return self._d['placeholder']
211
+ return self._d.placeholder
192
212
 
193
213
  @property
194
214
  def fillchar(self):
195
- return self._d['fillchar']
215
+ return self._d.fillchar
196
216
 
197
217
  @property
198
218
  def separator(self):
199
- return self._d['separator']
219
+ return self._d.separator
200
220
 
201
221
  @property
202
222
  def max_lines(self):
203
- return self._d['max_lines']
223
+ return self._d.max_lines
204
224
 
205
225
  @property
206
226
  def preserve_empty(self):
207
- return self._d['preserve_empty']
227
+ return self._d.preserve_empty
208
228
 
209
229
  @property
210
230
  def minimum_width(self):
211
- return self._d['minimum_width']
231
+ return self._d.minimum_width
212
232
 
213
233
  @property
214
234
  def justify_last_line(self):
215
- return self._d['justify_last_line']
235
+ return self._d.justify_last_line
216
236
 
217
237
  @property
218
238
  def break_on_hyphens(self):
219
- return self._d['break_on_hyphens']
239
+ return self._d.break_on_hyphens
220
240
 
221
241
  @property
222
242
  def sizefunc(self):
223
- return self._d['sizefunc']
243
+ return self._d._sizefunc
224
244
 
225
245
  # Setters ----------------------------------------------------------------------------------------------------------
226
246
 
@@ -230,9 +250,7 @@ class TextWrapper:
230
250
  raise TypeError("width must be an integer or float")
231
251
  if new <= 0:
232
252
  raise ValueError("width must be greater than 0")
233
- if (self._d.get('max_lines', None) is not None and new < self._d.get('length_placeholder', new)):
234
- raise ValueError("width must be greater than length of the placeholder")
235
- self._d['width'] = new
253
+ self._d.width = new
236
254
 
237
255
  @line_padding.setter
238
256
  def line_padding(self, new):
@@ -240,7 +258,7 @@ class TextWrapper:
240
258
  raise TypeError("line_padding must be a integer or float")
241
259
  if new < 0:
242
260
  raise ValueError("line_padding must be equal to or greater than 0")
243
- self._d['line_padding'] = new
261
+ self._d.line_padding = new
244
262
 
245
263
  @method.setter
246
264
  def method(self, new):
@@ -249,11 +267,11 @@ class TextWrapper:
249
267
  new = new.strip().lower()
250
268
  if new not in {'mono', 'word'}:
251
269
  raise ValueError("method={!r} is invalid, must be 'mono' or 'word'".format(new))
252
- self._d['method'] = new
270
+ self._d.method = new
253
271
  if new == 'mono':
254
- self._d['wrapfunc'] = mono
272
+ self._d.wrapfunc = mono
255
273
  elif new == 'word':
256
- self._d['wrapfunc'] = word
274
+ self._d.wrapfunc = word
257
275
 
258
276
  @alignment.setter
259
277
  def alignment(self, new):
@@ -263,33 +281,30 @@ class TextWrapper:
263
281
  if new not in {'left', 'center', 'right', 'fill', 'fill-left', 'fill-center', 'fill-right'}:
264
282
  raise ValueError("alignment={!r} is invalid, must be 'left', 'center', 'right', 'fill', 'fill-left', "
265
283
  "'fill-center', or 'fill-right'".format(new))
266
- self._d['alignment'] = new = 'fill-left' if new == 'fill' else new
284
+ self._d.alignment = new = 'fill-left' if new == 'fill' else new
267
285
  if new.endswith('left'):
268
- self._d['align_justify'] = jusitfy_align_left
269
- self._d['fillstr_justify'] = justify_fillstr_left
286
+ self._d.align_justify = jusitfy_align_left
287
+ self._d.fillstr_justify = justify_fillstr_left
270
288
  elif new.endswith('center'):
271
- self._d['align_justify'] = justify_align_center
272
- self._d['fillstr_justify'] = justify_fillstr_center
289
+ self._d.align_justify = justify_align_center
290
+ self._d.fillstr_justify = justify_fillstr_center
273
291
  elif new.endswith('right'):
274
- self._d['align_justify'] = justify_align_right
275
- self._d['fillstr_justify'] = justify_fillstr_right
292
+ self._d.align_justify = justify_align_right
293
+ self._d.fillstr_justify = justify_fillstr_right
276
294
 
277
295
  @placeholder.setter
278
296
  def placeholder(self, new):
279
297
  if not isinstance(new, str):
280
298
  raise TypeError("placeholder must be a string")
281
- self._d['placeholder'] = new
282
- self._d['length_placeholder'] = length = self._d['lenfunc'](new)
283
- if self._d.get('max_lines', None) is not None and self._d['width'] < length:
284
- raise ValueError("width must be greater than length of the placeholder")
299
+ self._d.placeholder = new
285
300
 
286
301
  @fillchar.setter
287
302
  def fillchar(self, new):
288
303
  if not isinstance(new, str):
289
304
  raise TypeError("fillchar must be a string")
290
- self._d['fillchar'] = new
305
+ self._d.fillchar = new
291
306
  split = compile(escape(new)).split
292
- self._d['split_fillchar'] = lambda string : [s for s in split(string) if s]
307
+ self._d.split_fillchar = lambda string : [s for s in split(string) if s]
293
308
 
294
309
  @separator.setter
295
310
  def separator(self, new):
@@ -297,48 +312,46 @@ class TextWrapper:
297
312
  raise TypeError("separator must be a string, iterable, or None")
298
313
  if isinstance(new, Iterable) and not all(isinstance(s, str) for s in new):
299
314
  raise ValueError("separator must be an iterable containing of strings")
300
- self._d['separator'] = new
315
+ self._d.separator = new
301
316
  if new is None:
302
- self._d['split_separator'] = lambda s : s.split()
317
+ self._d.split_separator = lambda s : s.split()
303
318
  return
304
319
  elif isinstance(new, str):
305
320
  split = compile(escape(new)).split
306
321
  else:
307
322
  split = compile('|'.join(map(escape, new))).split
308
- self._d['split_separator'] = lambda string : [s for s in split(string) if s]
323
+ self._d.split_separator = lambda string : [s for s in split(string) if s]
309
324
 
310
325
  @max_lines.setter
311
326
  def max_lines(self, new):
312
327
  if not isinstance(new, (int, type(None))):
313
328
  raise TypeError("max_lines must be an integer or None")
314
- if new is not None:
315
- if new <= 0:
316
- raise ValueError("max_lines must be greater than 0")
317
- if self._d['width'] < self._d['length_placeholder']:
318
- raise ValueError("width must be greater than length of the placeholder")
319
- self._d['max_lines'] = new
329
+ if new is not None and new <= 0:
330
+ raise ValueError("max_lines must be greater than 0")
331
+ self._d.max_lines = new
320
332
 
321
333
  @preserve_empty.setter
322
334
  def preserve_empty(self, new):
323
- self._d['preserve_empty'] = new
335
+ self._d.preserve_empty = bool(new)
324
336
 
325
337
  @minimum_width.setter
326
338
  def minimum_width(self, new):
327
- self._d['minimum_width'] = new
339
+ self._d.minimum_width = bool(new)
328
340
 
329
341
  @justify_last_line.setter
330
342
  def justify_last_line(self, new):
331
- self._d['justify_last_line'] = new
343
+ self._d.justify_last_line = bool(new)
332
344
 
333
345
  @break_on_hyphens.setter
334
346
  def break_on_hyphens(self, new):
335
- self._d['break_on_hyphens'] = new
347
+ self._d.break_on_hyphens = bool(new)
336
348
 
337
349
  @sizefunc.setter
338
350
  def sizefunc(self, new):
351
+ self._d._sizefunc = new
339
352
  if new is None:
340
- self._d['sizefunc'] = lambda s : (len(s), 1)
341
- self._d['lenfunc'] = len
353
+ self._d.sizefunc = lambda s : (len(s), 1)
354
+ self._d.lenfunc = len
342
355
  return
343
356
  if not callable(new):
344
357
  raise TypeError("sizefunc must be a callable")
@@ -354,52 +367,55 @@ class TextWrapper:
354
367
  raise ValueError("sizefunc returned width must be equal to or greater than 0")
355
368
  if test[1] < 0:
356
369
  raise ValueError("sizefunc returned height must be equal to or greater than 0")
357
- self._d['sizefunc'] = new
358
- self._d['lenfunc'] = lambda s : new(s)[0]
370
+ self._d.sizefunc = new
371
+ self._d.lenfunc = lambda s : new(s)[0]
359
372
  elif isinstance(test, (int, float)):
360
373
  if test < 0:
361
374
  raise ValueError("sizefunc (length) must be equal to or greater than 0")
362
- self._d['sizefunc'] = None
363
- self._d['lenfunc'] = new
375
+ self._d.sizefunc = None
376
+ self._d.lenfunc = new
364
377
  else:
365
378
  raise TypeError("sizefunc must be returned a tuple for size or a single value for width (length)")
366
379
 
367
380
  # Methods ----------------------------------------------------------------------------------------------------------
368
381
 
369
382
  def copy(self):
370
- return TextWrapper(width=self._d['width'], line_padding=self._d['line_padding'], method=self._d['method'],
371
- alignment=self._d['alignment'], placeholder=self._d['placeholder'],
372
- fillchar=self._d['fillchar'], separator=self._d['separator'], max_lines=self._d['max_lines'],
373
- preserve_empty=self._d['preserve_empty'], minimum_width=self._d['minimum_width'],
374
- justify_last_line=self._d['justify_last_line'], break_on_hyphens=self._d['break_on_hyphens'],
375
- sizefunc=self._d['sizefunc'])
383
+ return TextWrapper(width=self._d.width, line_padding=self._d.line_padding, method=self._d.method,
384
+ alignment=self._d.alignment, placeholder=self._d.placeholder, fillchar=self._d.fillchar,
385
+ separator=self._d.separator, max_lines=self._d.max_lines,
386
+ preserve_empty=self._d.preserve_empty, minimum_width=self._d.minimum_width,
387
+ justify_last_line=self._d.justify_last_line, break_on_hyphens=self._d.break_on_hyphens,
388
+ sizefunc=self._d._sizefunc)
376
389
 
377
390
  def sanitize(self, text):
378
391
  if not isinstance(text, str):
379
392
  raise TypeError("text must be a string")
380
393
 
381
- return self._d['fillchar'].join(self._d['split_separator'](text))
394
+ return self._d.fillchar.join(self._d.split_separator(text))
382
395
 
383
396
  def wrap(self, text, return_details=False, *, _one_line=False):
384
397
  if not isinstance(text, str):
385
398
  raise TypeError("text must be a string")
386
399
 
387
- wrapfunc = self._d['wrapfunc']
388
- width = self._d['width']
389
- placeholder = self._d['placeholder']
390
- fillchar = self._d['fillchar']
391
- split_separator = self._d['split_separator']
392
- max_lines = self._d['max_lines']
393
- preserve_empty = self._d['preserve_empty']
394
- break_on_hyphens = self._d['break_on_hyphens']
395
- lenfunc = self._d['lenfunc']
400
+ wrapfunc = self._d.wrapfunc
401
+ width = self._d.width
402
+ placeholder = self._d.placeholder
403
+ fillchar = self._d.fillchar
404
+ split_separator = self._d.split_separator
405
+ max_lines = self._d.max_lines
406
+ preserve_empty = self._d.preserve_empty
407
+ break_on_hyphens = self._d.break_on_hyphens
408
+ lenfunc = self._d.lenfunc
396
409
 
397
410
  if _one_line:
398
411
  max_lines = 1
399
412
  else:
400
- max_lines = self._d['max_lines']
413
+ max_lines = self._d.max_lines
401
414
 
402
- set_max_lines = max_lines is not None
415
+ has_max_lines = max_lines is not None
416
+
417
+ if has_max_lines and width < lenfunc(placeholder):
418
+ raise ValueError("width must be greater than length of the placeholder")
403
419
 
404
420
  wrapped = []
405
421
  indiced = set()
@@ -411,15 +427,15 @@ class TextWrapper:
411
427
  wrapped.extend(wrapped_line)
412
428
  lines = len(wrapped)
413
429
 
414
- if set_max_lines and lines <= max_lines:
430
+ if has_max_lines and lines <= max_lines:
415
431
  indiced.add(lines - 1)
416
- elif not set_max_lines:
432
+ elif not has_max_lines:
417
433
  indiced.add(lines - 1)
418
434
 
419
435
  elif preserve_empty:
420
436
  wrapped.append('')
421
437
 
422
- if set_max_lines and len(wrapped) > max_lines:
438
+ if has_max_lines and len(wrapped) > max_lines:
423
439
  current_char = ''
424
440
 
425
441
  for part in wrapped[max_lines - 1]:
@@ -440,12 +456,12 @@ class TextWrapper:
440
456
  if not isinstance(text, str):
441
457
  raise TypeError("text must be a string")
442
458
 
443
- width = self._d['width']
444
- line_padding = self._d['line_padding']
445
- alignment = self._d['alignment']
446
- justify = self._d['align_justify']
447
- minimum_width = self._d['minimum_width']
448
- sizefunc = self._d['sizefunc']
459
+ width = self._d.width
460
+ line_padding = self._d.line_padding
461
+ alignment = self._d.alignment
462
+ justify = self._d.align_justify
463
+ minimum_width = self._d.minimum_width
464
+ sizefunc = self._d.sizefunc
449
465
 
450
466
  if sizefunc is None:
451
467
  raise TypeError("sizefunc must be a size")
@@ -471,14 +487,13 @@ class TextWrapper:
471
487
  offset_y += height_line + line_padding
472
488
 
473
489
  else:
474
- split_fillchar = self._d['split_fillchar']
475
- no_fill_last_line = not self._d['justify_last_line']
490
+ split_fillchar = self._d.split_fillchar
491
+ no_fill_last_line = not self._d.justify_last_line
476
492
  lines_word = [split_fillchar(line) for line in wrapped]
477
493
 
478
- if minimum_width and any(
479
- len(line) > 1 and not (no_fill_last_line and i in indiced)
480
- for i, line in enumerate(lines_word)
481
- ): use_width = width if wrapped else 0
494
+ if minimum_width and any(len(line) > 1 and not (no_fill_last_line and i in indiced)
495
+ for i, line in enumerate(lines_word)):
496
+ use_width = width if wrapped else 0
482
497
 
483
498
  for i, line in enumerate(wrapped):
484
499
  width_line, height_line = lines_size[i]
@@ -505,8 +520,8 @@ class TextWrapper:
505
520
  offset_y += height_line + line_padding
506
521
 
507
522
  if return_details:
508
- return {'aligned': aligned, 'wrapped': wrapped, 'indiced': indiced, 'size': (use_width,
509
- offset_y - line_padding)}
523
+ return {'aligned': aligned, 'wrapped': wrapped, 'indiced': indiced,
524
+ 'size': (use_width, offset_y - line_padding)}
510
525
 
511
526
  return aligned
512
527
 
@@ -514,13 +529,13 @@ class TextWrapper:
514
529
  if not isinstance(text, str):
515
530
  raise TypeError("text must be a string")
516
531
 
517
- width = self._d['width']
518
- line_padding = self._d['line_padding']
519
- alignment = self._d['alignment']
520
- fillchar = self._d['fillchar']
521
- justify = self._d['fillstr_justify']
522
- minimum_width = self._d['minimum_width']
523
- lenfunc = self._d['lenfunc']
532
+ width = self._d.width
533
+ line_padding = self._d.line_padding
534
+ alignment = self._d.alignment
535
+ fillchar = self._d.fillchar
536
+ justify = self._d.fillstr_justify
537
+ minimum_width = self._d.minimum_width
538
+ lenfunc = self._d.lenfunc
524
539
 
525
540
  wrapped_info = self.wrap(text, True)
526
541
  wrapped = wrapped_info['wrapped']
@@ -545,14 +560,13 @@ class TextWrapper:
545
560
  justified_lines.append(fill_line_padding)
546
561
 
547
562
  else:
548
- split_fillchar = self._d['split_fillchar']
549
- no_fill_last_line = not self._d['justify_last_line']
563
+ split_fillchar = self._d.split_fillchar
564
+ no_fill_last_line = not self._d.justify_last_line
550
565
  lines_word = [split_fillchar(line) for line in wrapped]
551
566
 
552
- if minimum_width and any(
553
- len(line) > 1 and not (no_fill_last_line and i in indiced)
554
- for i, line in enumerate(lines_word)
555
- ): use_width = width if wrapped else 0
567
+ if minimum_width and any(len(line) > 1 and not (no_fill_last_line and i in indiced)
568
+ for i, line in enumerate(lines_word)):
569
+ use_width = width if wrapped else 0
556
570
 
557
571
  fill_line_padding = '\n'.join(fillchar * use_width for _ in range(line_padding))
558
572
 
@@ -1,31 +1,47 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: txtwrap
3
- Version: 2.3.0
3
+ Version: 2.3.2
4
4
  Summary: A tool for wrapping and filling text.
5
5
  Home-page: https://github.com/azzammuhyala/txtwrap
6
6
  Author: azzammuhyala
7
7
  Author-email: azzammuhyala@gmail.com
8
8
  License: MIT
9
9
  Keywords: wrap,wrapper,wrapping,wrapped,text wrap,text wrapper,text wrapping,text wrapped
10
+ Classifier: Programming Language :: Python
10
11
  Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.3
11
13
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
12
- Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Topic :: Text Processing
15
+ Classifier: Topic :: Text Processing :: Filters
13
16
  Requires-Python: >=3.3
14
17
  Description-Content-Type: text/markdown
18
+ Dynamic: author
19
+ Dynamic: author-email
20
+ Dynamic: classifier
21
+ Dynamic: description
22
+ Dynamic: description-content-type
23
+ Dynamic: home-page
24
+ Dynamic: keywords
25
+ Dynamic: license
26
+ Dynamic: requires-python
27
+ Dynamic: summary
15
28
 
16
29
  # TxTWrap🔡
17
30
  A tool for wrapping and filling text.🔨
18
31
 
19
- - `LOREM_IPSUM_WORDS`
20
- - `LOREM_IPSUM_SENTENCES`
21
- - `LOREM_IPSUM_PARAGRAPHS`
22
- - `TextWrapper` (✅ Updated)
23
- - `sanitize` (➕ New)
24
- - `wrap` (✅ Updated)
25
- - `align` (✅ Updated)
26
- - `fillstr` ( Updated)
27
- - `printwrap` (✅ Updated)
28
- - `shorten` (✅ Updated)
32
+ Version: **2.3.2** <br>
33
+ Python requires version: **3.3.0+** <br>
34
+ Python stub file requires version: **3.8.0+**
35
+
36
+ - [`LOREM_IPSUM_WORDS`](#lorem-ipsum)
37
+ - [`LOREM_IPSUM_SENTENCES`](#lorem-ipsum)
38
+ - [`LOREM_IPSUM_PARAGRAPHS`](#lorem-ipsum)
39
+ - [`TextWrapper`](#textwrapper) (🔨 Fixed)
40
+ - [`sanitize`](#sanitizetext)
41
+ - [`wrap`](#wraptext-return_detailsfalse)
42
+ - [`align`](#aligntext-return_detailsfalse)
43
+ - [`fillstr`](#fillstrtext)
44
+ - [`shorten`](#shortentext)
29
45
 
30
46
  # Documents📄
31
47
  This module is inspired by the [`textwrap`](https://docs.python.org/3/library/textwrap.html) module, which provides
@@ -33,17 +49,18 @@ several useful functions, along with the [`TextWrapper`](#textwrapper), class th
33
49
 
34
50
  The difference between [`txtwrap`](https://pypi.org/project/txtwrap) and
35
51
  [`textwrap`](https://docs.python.org/3/library/textwrap.html) is that this module is designed not only for wrapping and
36
- filling monospace fonts but also for other font types, such as Arial, Times New Roman, and more.
52
+ filling _monospace fonts_ but also for other font types, such as _Arial_, _Times New Roman_, and more.
37
53
 
38
54
  <h1></h1>
39
55
 
56
+ ## Lorem ipsum
40
57
  ```py
41
58
  LOREM_IPSUM_WORDS
42
59
  LOREM_IPSUM_SENTENCES
43
60
  LOREM_IPSUM_PARAGRAPHS
44
61
  ```
45
- A collection of words, sentences, and paragraphs that can be used as examples.
46
- - `LOREM_IPSUM_WORDS` contains a short Lorem Ipsum sentence.
62
+ A _Lorem Ipsum_ collection of words, sentences, and paragraphs that can be used as examples.
63
+ - `LOREM_IPSUM_WORDS` contains a short sentence.
47
64
  - `LOREM_IPSUM_SENTENCES` contains a slightly longer paragraph.
48
65
  - `LOREM_IPSUM_PARAGRAPHS` contains several longer paragraphs.
49
66
 
@@ -100,15 +117,14 @@ as each attribute has type checking, which may reduce performance.
100
117
  <h1></h1>
101
118
 
102
119
  #### **`method`**
103
- (Default: `'word'`) The wrapping method. Available options: `'mono'` and `'word'`.
120
+ (Default: `'word'`) The wrapping method. Available options:
104
121
  - `'mono'` method wraps text character by character.
105
122
  - `'word'` method wraps text word by word.
106
123
 
107
124
  <h1></h1>
108
125
 
109
126
  #### **`alignment`**
110
- (Default: `'left'`) The alignment of the wrapped text. Available options: `'left'`, `'center'`, `'right'`,
111
- (`'fill'` or `'fill-left'`), `'fill-center'`, and `'fill-right'`.
127
+ (Default: `'left'`) The alignment of the wrapped text. Available options:
112
128
  - `'left'`: Aligns text to the start of the line.
113
129
  - `'center'`: Centers text within the line.
114
130
  - `'right'`: Aligns text to the end of the line.
@@ -133,7 +149,7 @@ as each attribute has type checking, which may reduce performance.
133
149
  (Default: `None`) The character used to separate words.
134
150
  - `None`: Uses whitespace as the separator.
135
151
  - `str`: Uses the specified character.
136
- - `Iterable`: Uses multiple specified characters.
152
+ - `Iterable[str]`: Uses multiple specified characters.
137
153
 
138
154
  <h1></h1>
139
155
 
@@ -180,6 +196,8 @@ If the function calculates only the width, it must return a single value of type
180
196
 
181
197
  ### Methods of [`TextWrapper`](#textwrapper):
182
198
 
199
+ > Note: All methods can be called outside the [`TextWrapper`](#textwrapper) like external functions.
200
+
183
201
  <h1></h1>
184
202
 
185
203
  #### **`copy`**
@@ -193,7 +211,7 @@ character.
193
211
 
194
212
  For example:
195
213
  ```py
196
- >>> TextWrapper().sanitize("\tHello World! ")
214
+ >>> TextWrapper().sanitize("\tHello \nWorld!\r ")
197
215
  'Hello World!'
198
216
  ```
199
217
 
@@ -202,7 +220,7 @@ For example:
202
220
  #### **`wrap(text, return_details=False)`**
203
221
  Returns a list of wrapped text strings. If `return_details=True`, returns a dictionary containing:
204
222
  - `'wrapped'`: A list of wrapped text fragments.
205
- - `'indiced'`: A set of indices marking line breaks (starting from `0`, like programming indices).
223
+ - `'indiced'`: A set of indices marking the end of line (starting from `0`, like programming indices).
206
224
 
207
225
  For example:
208
226
  ```py
@@ -215,7 +233,7 @@ For example:
215
233
  <h1></h1>
216
234
 
217
235
  #### **`align(text, return_details=False)`**
218
- Returns a list of tuples, where each tuple contains `(x, y, text)`, representing the wrapped text along with its
236
+ Returns a list of tuples, where each tuple contains `(xPosition, yPosition, text)`, representing the wrapped text along with its
219
237
  coordinates.
220
238
  > Note: [`sizefunc`](#sizefunc) must return both width and height.
221
239
 
@@ -238,7 +256,7 @@ For example:
238
256
 
239
257
  #### **`fillstr(text)`**
240
258
  Returns a string with wrapped text formatted for monospace fonts.
241
- > Note: [`width`](#width), [`line_padding`](#line_padding), and the output of [`sizefunc`](#sizefunc) must return `int`,
259
+ > Note: [`width`](#width), [`line_padding`](#line_padding), and the output of [`sizefunc`](#sizefunc) (size or just length) must return `int`,
242
260
  not `float`!
243
261
 
244
262
  For example:
File without changes
File without changes
File without changes