diff options
| author | Barry Warsaw | 2011-03-17 16:34:57 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2011-03-17 16:34:57 -0400 |
| commit | ef3a4a87e2c0f4b640e31afc4828d2edbd005846 (patch) | |
| tree | 6cdb98233fecee5e351bc2e593ab6cc7e145205c | |
| parent | 4943fba2eb4d812c20dbae1a61ce5e3b56d9a4d7 (diff) | |
| parent | 4a8a833f14d93a9916e5b2181fdfff24ffd57477 (diff) | |
| download | mailman-ef3a4a87e2c0f4b640e31afc4828d2edbd005846.tar.gz mailman-ef3a4a87e2c0f4b640e31afc4828d2edbd005846.tar.zst mailman-ef3a4a87e2c0f4b640e31afc4828d2edbd005846.zip | |
| -rw-r--r-- | src/mailman/Archiver/HyperArch.py | 1 | ||||
| -rw-r--r-- | src/mailman/Archiver/pipermail.py | 2 | ||||
| -rw-r--r-- | src/mailman/Utils.py | 134 | ||||
| -rw-r--r-- | src/mailman/app/moderator.py | 1 | ||||
| -rw-r--r-- | src/mailman/app/notifications.py | 2 | ||||
| -rw-r--r-- | src/mailman/bin/config_list.py | 10 | ||||
| -rw-r--r-- | src/mailman/bin/import.py | 2 | ||||
| -rw-r--r-- | src/mailman/bin/set_members.py | 1 | ||||
| -rw-r--r-- | src/mailman/chains/hold.py | 3 | ||||
| -rw-r--r-- | src/mailman/pipeline/calculate_recipients.py | 4 | ||||
| -rw-r--r-- | src/mailman/pipeline/replybot.py | 5 | ||||
| -rw-r--r-- | src/mailman/queue/archive.py | 2 | ||||
| -rw-r--r-- | src/mailman/queue/bounce.py | 2 | ||||
| -rw-r--r-- | src/mailman/queue/digest.py | 3 | ||||
| -rw-r--r-- | src/mailman/queue/maildir.py | 4 | ||||
| -rw-r--r-- | src/mailman/utilities/i18n.py | 6 | ||||
| -rw-r--r-- | src/mailman/utilities/string.py | 93 | ||||
| -rw-r--r-- | src/mailman/utilities/tests/test_templates.py | 10 | ||||
| -rw-r--r-- | src/mailman/utilities/tests/test_wrap.py | 151 |
19 files changed, 263 insertions, 173 deletions
diff --git a/src/mailman/Archiver/HyperArch.py b/src/mailman/Archiver/HyperArch.py index 92b9de2f0..646608590 100644 --- a/src/mailman/Archiver/HyperArch.py +++ b/src/mailman/Archiver/HyperArch.py @@ -44,7 +44,6 @@ from lazr.config import as_boolean from string import Template from zope.component import getUtility -from mailman import Utils from mailman.Archiver import HyperDatabase from mailman.Archiver import pipermail from mailman.config import config diff --git a/src/mailman/Archiver/pipermail.py b/src/mailman/Archiver/pipermail.py index f47600eb1..e11cb7173 100644 --- a/src/mailman/Archiver/pipermail.py +++ b/src/mailman/Archiver/pipermail.py @@ -10,7 +10,7 @@ import mailbox import cPickle as pickle from cStringIO import StringIO -from email.Utils import parseaddr, parsedate_tz, mktime_tz, formatdate +from email.utils import parseaddr, parsedate_tz, mktime_tz, formatdate from string import lowercase __version__ = '0.11 (Mailman edition)' diff --git a/src/mailman/Utils.py b/src/mailman/Utils.py deleted file mode 100644 index cfd61eb7a..000000000 --- a/src/mailman/Utils.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright (C) 1998-2011 by the Free Software Foundation, Inc. -# -# This file is part of GNU Mailman. -# -# GNU Mailman is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free -# Software Foundation, either version 3 of the License, or (at your option) -# any later version. -# -# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. - -"""Miscellaneous essential routines. - -This includes actual message transmission routines, address checking and -message and address munging, a handy-dandy routine to map a function on all -the mailing lists, and whatever else doesn't belong elsewhere. -""" - -from __future__ import absolute_import, unicode_literals - -__metaclass__ = type -__all__ = [ - ] - - -import os -import re -import logging - -# pylint: disable-msg=E0611,W0403 -from string import ascii_letters, digits, whitespace - -import mailman.templates - - -AT = '@' -CR = '\r' -DOT = '.' -EMPTYSTRING = '' -IDENTCHARS = ascii_letters + digits + '_' -NL = '\n' -UEMPTYSTRING = u'' -TEMPLATE_DIR = os.path.dirname(mailman.templates.__file__) - -# Search for $(identifier)s strings, except that the trailing s is optional, -# since that's a common mistake -cre = re.compile(r'%\(([_a-z]\w*?)\)s?', re.IGNORECASE) -# Search for $$, $identifier, or ${identifier} -dre = re.compile(r'(\${2})|\$([_a-z]\w*)|\${([_a-z]\w*)}', re.IGNORECASE) - -log = logging.getLogger('mailman.error') - - - -# A much more naive implementation than say, Emacs's fill-paragraph! -# pylint: disable-msg=R0912 -def wrap(text, column=70, honor_leading_ws=True): - """Wrap and fill the text to the specified column. - - Wrapping is always in effect, although if it is not possible to wrap a - line (because some word is longer than `column' characters) the line is - broken at the next available whitespace boundary. Paragraphs are also - always filled, unless honor_leading_ws is true and the line begins with - whitespace. This is the algorithm that the Python FAQ wizard uses, and - seems like a good compromise. - - """ - wrapped = '' - # first split the text into paragraphs, defined as a blank line - paras = re.split('\n\n', text) - for para in paras: - # fill - lines = [] - fillprev = False - for line in para.split(NL): - if not line: - lines.append(line) - continue - if honor_leading_ws and line[0] in whitespace: - fillthis = False - else: - fillthis = True - if fillprev and fillthis: - # if the previous line should be filled, then just append a - # single space, and the rest of the current line - lines[-1] = lines[-1].rstrip() + ' ' + line - else: - # no fill, i.e. retain newline - lines.append(line) - fillprev = fillthis - # wrap each line - for text in lines: - while text: - if len(text) <= column: - line = text - text = '' - else: - bol = column - # find the last whitespace character - while bol > 0 and text[bol] not in whitespace: - bol -= 1 - # now find the last non-whitespace character - eol = bol - while eol > 0 and text[eol] in whitespace: - eol -= 1 - # watch out for text that's longer than the column width - if eol == 0: - # break on whitespace after column - eol = column - while eol < len(text) and text[eol] not in whitespace: - eol += 1 - bol = eol - while bol < len(text) and text[bol] in whitespace: - bol += 1 - bol -= 1 - line = text[:eol+1] + '\n' - # find the next non-whitespace character - bol += 1 - while bol < len(text) and text[bol] in whitespace: - bol += 1 - text = text[bol:] - wrapped += line - wrapped += '\n' - # end while text - wrapped += '\n' - # end for text in lines - # the last two newlines are bogus - return wrapped[:-2] diff --git a/src/mailman/app/moderator.py b/src/mailman/app/moderator.py index 50a03c833..a2f838934 100644 --- a/src/mailman/app/moderator.py +++ b/src/mailman/app/moderator.py @@ -35,7 +35,6 @@ from datetime import datetime from email.utils import formataddr, formatdate, getaddresses, make_msgid from zope.component import getUtility -from mailman import Utils from mailman.app.membership import add_member, delete_member from mailman.app.notifications import ( send_admin_subscription_notice, send_welcome_message) diff --git a/src/mailman/app/notifications.py b/src/mailman/app/notifications.py index d7e64a020..8bfbd0934 100644 --- a/src/mailman/app/notifications.py +++ b/src/mailman/app/notifications.py @@ -30,12 +30,12 @@ __all__ = [ from email.utils import formataddr from lazr.config import as_boolean -from mailman.Utils import wrap from mailman.config import config from mailman.core.i18n import _ from mailman.email.message import OwnerNotification, UserNotification from mailman.interfaces.member import DeliveryMode from mailman.utilities.i18n import make +from mailman.utilities.string import wrap diff --git a/src/mailman/bin/config_list.py b/src/mailman/bin/config_list.py index 845a1371d..a40f4ee52 100644 --- a/src/mailman/bin/config_list.py +++ b/src/mailman/bin/config_list.py @@ -22,10 +22,10 @@ import optparse from mailman import MailList from mailman import errors -from mailman.Utils import wrap from mailman.configuration import config from mailman.core.i18n import _ from mailman.initialize import initialize +from mailman.utilities.string import wrap from mailman.version import MAILMAN_VERSION @@ -140,7 +140,7 @@ def do_list_categories(mlist, k, subcat, outfp): # triple-quoted string nonsense in the source code. desc = NL.join([s.lstrip() for s in info[0].splitlines()]) # Print out the category description - desc = Utils.wrap(desc) + desc = wrap(desc) for line in desc.splitlines(): print >> outfp, '#', line print >> outfp @@ -162,7 +162,7 @@ def do_list_categories(mlist, k, subcat, outfp): desc = re.sub('<', '<', desc) desc = re.sub('>', '>', desc) # Print out the variable description. - desc = Utils.wrap(desc) + desc = wrap(desc) for line in desc.split('\n'): print >> outfp, '#', line # munge the value based on its type @@ -246,8 +246,8 @@ def do_input(listname, infile, checkonly, verbose, parser): # Open the specified list locked, unless checkonly is set try: mlist = MailList.MailList(listname, lock=not checkonly) - except errors.MMListError, e: - parser.error(_('No such list "$listname"\n$e')) + except errors.MMListError as error: + parser.error(_('No such list "$listname"\n$error')) savelist = False guibyprop = getPropertyMap(mlist) try: diff --git a/src/mailman/bin/import.py b/src/mailman/bin/import.py index d4173aef2..7ed2d830e 100644 --- a/src/mailman/bin/import.py +++ b/src/mailman/bin/import.py @@ -18,7 +18,6 @@ """Import the XML representation of a mailing list.""" import sys -import codecs import optparse import traceback @@ -27,7 +26,6 @@ from xml.parsers.expat import ExpatError from mailman import Defaults from mailman import MemberAdaptor -from mailman import Utils from mailman import passwords from mailman.MailList import MailList from mailman.core.i18n import _ diff --git a/src/mailman/bin/set_members.py b/src/mailman/bin/set_members.py index 15ebeb29a..ef65d1b45 100644 --- a/src/mailman/bin/set_members.py +++ b/src/mailman/bin/set_members.py @@ -20,7 +20,6 @@ import optparse from zope.component import getUtility -from mailman import Message from mailman import Utils from mailman import passwords from mailman.app.membership import add_member diff --git a/src/mailman/chains/hold.py b/src/mailman/chains/hold.py index fcd11ca72..7b78f118e 100644 --- a/src/mailman/chains/hold.py +++ b/src/mailman/chains/hold.py @@ -35,7 +35,6 @@ from zope.component import getUtility from zope.event import notify from zope.interface import implements -from mailman.Utils import wrap from mailman.app.moderator import hold_message from mailman.app.replybot import can_acknowledge from mailman.chains.base import ChainNotification, TerminalChainBase @@ -47,7 +46,7 @@ from mailman.interfaces.languages import ILanguageManager from mailman.interfaces.pending import IPendable, IPendings from mailman.interfaces.usermanager import IUserManager from mailman.utilities.i18n import make -from mailman.utilities.string import oneline +from mailman.utilities.string import oneline, wrap log = logging.getLogger('mailman.vette') diff --git a/src/mailman/pipeline/calculate_recipients.py b/src/mailman/pipeline/calculate_recipients.py index 36f391fd0..d2527e608 100644 --- a/src/mailman/pipeline/calculate_recipients.py +++ b/src/mailman/pipeline/calculate_recipients.py @@ -32,12 +32,12 @@ __all__ = [ from zope.interface import implements -from mailman import Utils from mailman.config import config from mailman.core import errors from mailman.core.i18n import _ from mailman.interfaces.handler import IHandler from mailman.interfaces.member import DeliveryStatus +from mailman.utilities.string import wrap @@ -89,7 +89,7 @@ class CalculateRecipients: Your urgent message to the $realname mailing list was not authorized for delivery. The original message as received by Mailman is attached. """) - raise errors.RejectMessage(Utils.wrap(text)) + raise errors.RejectMessage(wrap(text)) # Calculate the regular recipients of the message recipients = set(member.address.email for member in mlist.regular_members.members diff --git a/src/mailman/pipeline/replybot.py b/src/mailman/pipeline/replybot.py index 5f17160c1..dffffbf47 100644 --- a/src/mailman/pipeline/replybot.py +++ b/src/mailman/pipeline/replybot.py @@ -30,7 +30,6 @@ import logging from zope.component import getUtility from zope.interface import implements -from mailman import Utils from mailman.core.i18n import _ from mailman.email.message import UserNotification from mailman.interfaces.autorespond import ( @@ -38,7 +37,7 @@ from mailman.interfaces.autorespond import ( from mailman.interfaces.handler import IHandler from mailman.interfaces.usermanager import IUserManager from mailman.utilities.datetime import today -from mailman.utilities.string import expand +from mailman.utilities.string import expand, wrap log = logging.getLogger('mailman.error') @@ -113,7 +112,7 @@ class Replybot: owneremail = mlist.owner_address, ) # Interpolation and Wrap the response text. - text = Utils.wrap(expand(response_text, d)) + text = wrap(expand(response_text, d)) outmsg = UserNotification(msg.sender, mlist.bounces_address, subject, text, mlist.preferred_language) outmsg['X-Mailer'] = _('The Mailman Replybot') diff --git a/src/mailman/queue/archive.py b/src/mailman/queue/archive.py index 24dab34f5..99682f310 100644 --- a/src/mailman/queue/archive.py +++ b/src/mailman/queue/archive.py @@ -27,7 +27,7 @@ import os import logging from datetime import datetime -from email.Utils import parsedate_tz, mktime_tz, formatdate +from email.utils import parsedate_tz, mktime_tz, formatdate from flufl.lock import Lock from lazr.config import as_timedelta diff --git a/src/mailman/queue/bounce.py b/src/mailman/queue/bounce.py index a53b2d072..968659352 100644 --- a/src/mailman/queue/bounce.py +++ b/src/mailman/queue/bounce.py @@ -23,7 +23,7 @@ import cPickle import logging import datetime -from email.Utils import parseaddr +from email.utils import parseaddr from lazr.config import as_timedelta from mailman.config import config diff --git a/src/mailman/queue/digest.py b/src/mailman/queue/digest.py index 2541e14ed..075335158 100644 --- a/src/mailman/queue/digest.py +++ b/src/mailman/queue/digest.py @@ -38,7 +38,6 @@ from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formatdate, getaddresses, make_msgid -from mailman.Utils import wrap from mailman.config import config from mailman.core.errors import DiscardMessage from mailman.core.i18n import _ @@ -48,7 +47,7 @@ from mailman.pipeline.scrubber import process as scrubber from mailman.queue import Runner from mailman.utilities.i18n import make from mailman.utilities.mailbox import Mailbox -from mailman.utilities.string import oneline +from mailman.utilities.string import oneline, wrap diff --git a/src/mailman/queue/maildir.py b/src/mailman/queue/maildir.py index 3d0b9497c..fe4dc9da1 100644 --- a/src/mailman/queue/maildir.py +++ b/src/mailman/queue/maildir.py @@ -53,8 +53,8 @@ import os import errno import logging -from email.Parser import Parser -from email.Utils import parseaddr +from email.parser import Parser +from email.utils import parseaddr from mailman.config import config from mailman.message import Message diff --git a/src/mailman/utilities/i18n.py b/src/mailman/utilities/i18n.py index afaf26bc0..8e769329c 100644 --- a/src/mailman/utilities/i18n.py +++ b/src/mailman/utilities/i18n.py @@ -31,15 +31,11 @@ import os import errno from itertools import product -from zope.component import getUtility from mailman.config import config from mailman.core.constants import system_preferences from mailman.core.i18n import _ -from mailman.interfaces.languages import ILanguageManager -from mailman.utilities.string import expand - -from mailman.Utils import wrap as wrap_text +from mailman.utilities.string import expand, wrap as wrap_text diff --git a/src/mailman/utilities/string.py b/src/mailman/utilities/string.py index 3eda0dc39..9054ed076 100644 --- a/src/mailman/utilities/string.py +++ b/src/mailman/utilities/string.py @@ -25,6 +25,7 @@ __all__ = [ 'oneline', 'uncanonstr', 'websafe', + 'wrap', ] @@ -33,14 +34,15 @@ import logging from email.errors import HeaderParseError from email.header import decode_header, make_header -from string import Template +from string import Template, whitespace +from textwrap import TextWrapper, dedent from zope.component import getUtility from mailman.interfaces.languages import ILanguageManager EMPTYSTRING = '' -UEMPTYSTRING = u'' +NL = '\n' log = logging.getLogger('mailman.error') @@ -91,7 +93,7 @@ def oneline(s, cset='us-ascii', in_unicode=False): try: h = make_header(decode_header(s)) ustr = h.__unicode__() - line = UEMPTYSTRING.join(ustr.splitlines()) + line = EMPTYSTRING.join(ustr.splitlines()) if in_unicode: return line else: @@ -138,3 +140,88 @@ def uncanonstr(s, lang=None): a.append(c) # Join characters together and coerce to byte string return str(EMPTYSTRING.join(a)) + + + +def wrap(text, column=70, honor_leading_ws=True): + """Wrap and fill the text to the specified column. + + The input text is wrapped and filled as done by the standard library + textwrap module. The differences here being that this function is capable + of filling multiple paragraphs (as defined by text separated by blank + lines). Also, when `honor_leading_ws` is True (the default), paragraphs + that being with whitespace are not wrapped. This is the algorithm that + the Python FAQ wizard used. + """ + # First, split the original text into paragraph, keeping all blank lines + # between them. + paragraphs = [] + paragraph = [] + last_indented = False + for line in text.splitlines(True): + is_indented = (len(line) > 0 and line[0] in whitespace) + if line == NL: + if len(paragraph) > 0: + paragraphs.append(EMPTYSTRING.join(paragraph)) + paragraphs.append(line) + last_indented = False + paragraph = [] + elif last_indented != is_indented: + # The indentation level changed. We treat this as a paragraph + # break but no blank line will be issued between paragraphs. + if len(paragraph) > 0: + paragraphs.append(EMPTYSTRING.join(paragraph)) + # The next paragraph starts with this line. + paragraph = [line] + last_indented = is_indented + else: + # This line does not constitute a paragraph break. + paragraph.append(line) + # We've consumed all the lines in the original text. Transfer the last + # paragraph we were collecting to the full set of paragraphs. + paragraphs.append(EMPTYSTRING.join(paragraph)) + # Now iterate through all paragraphs, wrapping as necessary. + wrapped_paragraphs = [] + # The dedented wrapper. + wrapper = TextWrapper(width=column, + fix_sentence_endings=True) + # The indented wrapper. For this one, we'll clobber initial_indent and + # subsequent_indent as needed per indented chunk of text. + iwrapper = TextWrapper(width=column, + fix_sentence_endings=True, + ) + add_paragraph_break = False + for paragraph in paragraphs: + if add_paragraph_break: + wrapped_paragraphs.append(NL) + add_paragraph_break = False + paragraph_text = EMPTYSTRING.join(paragraph) + # Just copy the blank lines to the final set of paragraphs. + if paragraph == NL: + wrapped_paragraphs.append(NL) + # Choose the wrapper based on whether the paragraph is indented or + # not. Also, do not wrap indented paragraphs if honor_leading_ws is + # set. + elif paragraph[0] in whitespace: + if honor_leading_ws: + # Leave the indented paragraph verbatim. + wrapped_paragraphs.append(paragraph_text) + else: + # The paragraph should be wrapped, but it must first be + # dedented. The leading whitespace on the first line of the + # original text will be used as the indentation for all lines + # in the wrapped text. + for i, ch in enumerate(paragraph_text): + if ch not in whitespace: + break + leading_ws = paragraph[:i] + iwrapper.initial_indent=leading_ws + iwrapper.subsequent_indent=leading_ws + paragraph_text = dedent(paragraph_text) + wrapped_paragraphs.append(iwrapper.fill(paragraph_text)) + add_paragraph_break = True + else: + # Fill this paragraph. fill() consumes the trailing newline. + wrapped_paragraphs.append(wrapper.fill(paragraph_text)) + add_paragraph_break = True + return EMPTYSTRING.join(wrapped_paragraphs) diff --git a/src/mailman/utilities/tests/test_templates.py b/src/mailman/utilities/tests/test_templates.py index 2de43ae3c..e21b44544 100644 --- a/src/mailman/utilities/tests/test_templates.py +++ b/src/mailman/utilities/tests/test_templates.py @@ -258,17 +258,15 @@ It will not be wrapped. def test_no_substitutions(self): self.assertEqual(make('nosub.txt', self.mlist), """\ -This is a global template. It has no substitutions. It will be -wrapped. -""") +This is a global template. It has no substitutions. It will be +wrapped.""") def test_substitutions(self): self.assertEqual(make('subs.txt', self.mlist, kind='very nice', howmany='a few'), """\ -This is a very nice template. It has a few substitutions. It will be -wrapped. -""") +This is a very nice template. It has a few substitutions. It will be +wrapped.""") def test_substitutions_no_wrap(self): self.assertEqual(make('nowrap.txt', self.mlist, wrap=False, diff --git a/src/mailman/utilities/tests/test_wrap.py b/src/mailman/utilities/tests/test_wrap.py new file mode 100644 index 000000000..2fc6c6ccf --- /dev/null +++ b/src/mailman/utilities/tests/test_wrap.py @@ -0,0 +1,151 @@ +# Copyright (C) 2011 by the Free Software Foundation, Inc. +# +# This file is part of GNU Mailman. +# +# GNU Mailman is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# GNU Mailman. If not, see <http://www.gnu.org/licenses/>. + +"""Test text wrapping.""" + +from __future__ import absolute_import, unicode_literals + +__metaclass__ = type +__all__ = [ + 'test_suite', + ] + + +import unittest + +from mailman.utilities.string import wrap + + + +class TestWrap(unittest.TestCase): + """Test text wrapping.""" + + def test_simple_wrap(self): + text = """\ +This is a single +paragraph. It consists +of several sentences +none of +which are +very long. +""" + self.assertEqual(wrap(text), """\ +This is a single paragraph. It consists of several sentences none of +which are very long.""") + + def test_two_paragraphs(self): + text = """\ +This is a single +paragraph. It consists +of several sentences +none of +which are +very long. + +And here is a second paragraph which +also consists +of several sentences. None of +these are very long +either. +""" + self.assertEqual(wrap(text), """\ +This is a single paragraph. It consists of several sentences none of +which are very long. + +And here is a second paragraph which also consists of several +sentences. None of these are very long either.""") + + def test_honor_ws(self): + text = """\ +This is a single +paragraph. It consists +of several sentences +none of +which are +very long. + + This paragraph is + indented so it + won't be filled. + +And here is a second paragraph which +also consists +of several sentences. None of +these are very long +either. +""" + self.assertEqual(wrap(text), """\ +This is a single paragraph. It consists of several sentences none of +which are very long. + + This paragraph is + indented so it + won't be filled. + +And here is a second paragraph which also consists of several +sentences. None of these are very long either.""") + + def test_dont_honor_ws(self): + text = """\ +This is a single +paragraph. It consists +of several sentences +none of +which are +very long. + + This paragraph is + indented but we don't + honor whitespace so it + will be filled. + +And here is a second paragraph which +also consists +of several sentences. None of +these are very long +either. +""" + self.assertEqual(wrap(text, honor_leading_ws=False), """\ +This is a single paragraph. It consists of several sentences none of +which are very long. + + This paragraph is indented but we don't honor whitespace so it + will be filled. + +And here is a second paragraph which also consists of several +sentences. None of these are very long either.""") + + def test_indentation_boundary(self): + text = """\ +This is a single paragraph +that consists of one sentence. + And another one that breaks + because it is indented. +Followed by one more paragraph. +""" + self.assertEqual(wrap(text), """\ +This is a single paragraph that consists of one sentence. + And another one that breaks + because it is indented. +Followed by one more paragraph.""") + + + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestWrap)) + return suite |
