Make 'width' an instance attribute rather than an argument to the wrap()

and fill() methods.  Keep interface of existing wrap() and fill()
functions by going back to having them construct a new TextWrapper
instance on each call, with the preferred width passed to the
constructor.
This commit is contained in:
Greg Ward 2002-06-10 20:26:02 +00:00
parent 4f7829e185
commit d34c959140
1 changed files with 32 additions and 31 deletions

View File

@ -18,8 +18,10 @@ class TextWrapper:
If you want to completely replace the main wrapping algorithm,
you'll probably have to override _wrap_chunks().
Several boolean instance attributes control various aspects of
wrapping:
Several instance attributes control various aspects of wrapping:
width (default: 70)
the maximum width of wrapped lines (unless break_long_words
is false)
expand_tabs (default: true)
Expand tabs in input text to spaces before further processing.
Each tab will become 1 .. 8 spaces, depending on its position in
@ -34,9 +36,8 @@ class TextWrapper:
by two spaces. Off by default becaus the algorithm is
(unavoidably) imperfect.
break_long_words (default: true)
Break words longer than the line width constraint. If false,
those words will not be broken, and some lines might be longer
than the width constraint.
Break words longer than 'width'. If false, those words will not
be broken, and some lines might be longer than 'width'.
"""
whitespace_trans = string.maketrans(string.whitespace,
@ -61,10 +62,12 @@ class TextWrapper:
def __init__ (self,
width=70,
expand_tabs=True,
replace_whitespace=True,
fix_sentence_endings=False,
break_long_words=True):
self.width = width
self.expand_tabs = expand_tabs
self.replace_whitespace = replace_whitespace
self.fix_sentence_endings = fix_sentence_endings
@ -121,15 +124,15 @@ class TextWrapper:
else:
i += 1
def _handle_long_word(self, chunks, cur_line, cur_len, width):
def _handle_long_word(self, chunks, cur_line, cur_len):
"""_handle_long_word(chunks : [string],
cur_line : [string],
cur_len : int, width : int)
cur_len : int)
Handle a chunk of text (most likely a word, not whitespace) that
is too long to fit in any line.
"""
space_left = width - cur_len
space_left = self.width - cur_len
# If we're allowed to break long words, then do so: put as much
# of the next chunk onto the current line as will fit.
@ -149,20 +152,21 @@ class TextWrapper:
# cur_len will be zero, so the next line will be entirely
# devoted to the long word that we can't handle right now.
def _wrap_chunks(self, chunks, width):
"""_wrap_chunks(chunks : [string], width : int) -> [string]
def _wrap_chunks(self, chunks):
"""_wrap_chunks(chunks : [string]) -> [string]
Wrap a sequence of text chunks and return a list of lines of
length 'width' or less. (If 'break_long_words' is false, some
lines may be longer than 'width'.) Chunks correspond roughly to
words and the whitespace between them: each chunk is indivisible
(modulo 'break_long_words'), but a line break can come between
any two chunks. Chunks should not have internal whitespace;
ie. a chunk is either all whitespace or a "word". Whitespace
chunks will be removed from the beginning and end of lines, but
apart from that whitespace is preserved.
length 'self.width' or less. (If 'break_long_words' is false,
some lines may be longer than this.) Chunks correspond roughly
to words and the whitespace between them: each chunk is
indivisible (modulo 'break_long_words'), but a line break can
come between any two chunks. Chunks should not have internal
whitespace; ie. a chunk is either all whitespace or a "word".
Whitespace chunks will be removed from the beginning and end of
lines, but apart from that whitespace is preserved.
"""
lines = []
width = self.width
while chunks:
@ -188,7 +192,7 @@ class TextWrapper:
# The current line is full, and the next chunk is too big to
# fit on *any* line (not just this one).
if chunks and len(chunks[0]) > width:
self._handle_long_word(chunks, cur_line, cur_len, width)
self._handle_long_word(chunks, cur_line, cur_len)
# If the last chunk on this line is all whitespace, drop it.
if cur_line and cur_line[-1].strip() == '':
@ -204,26 +208,25 @@ class TextWrapper:
# -- Public interface ----------------------------------------------
def wrap(self, text, width):
"""wrap(text : string, width : int) -> [string]
def wrap(self, text):
"""wrap(text : string) -> [string]
Split 'text' into multiple lines of no more than 'width'
Split 'text' into multiple lines of no more than 'self.width'
characters each, and return the list of strings that results.
Tabs in 'text' are expanded with string.expandtabs(), and all
other whitespace characters (including newline) are converted to
space.
"""
text = self._munge_whitespace(text)
if len(text) <= width:
if len(text) <= self.width:
return [text]
chunks = self._split(text)
if self.fix_sentence_endings:
self._fix_sentence_endings(chunks)
return self._wrap_chunks(chunks, width)
return self._wrap_chunks(chunks)
def fill(self, text, width, initial_tab="", subsequent_tab=""):
def fill(self, text, initial_tab="", subsequent_tab=""):
"""fill(text : string,
width : int,
initial_tab : string = "",
subsequent_tab : string = "")
-> string
@ -234,17 +237,15 @@ class TextWrapper:
lengths of the tab strings are accounted for when wrapping lines
to fit in 'width' columns.
"""
lines = self.wrap(text, width)
lines = self.wrap(text)
sep = "\n" + subsequent_tab
return initial_tab + sep.join(lines)
# Convenience interface
_wrapper = TextWrapper()
def wrap(text, width):
return _wrapper.wrap(text, width)
return TextWrapper(width=width).wrap(text)
def fill(text, width, initial_tab="", subsequent_tab=""):
return _wrapper.fill(text, width, initial_tab, subsequent_tab)
return TextWrapper(width=width).fill(text, initial_tab, subsequent_tab)