diff options
author | Dong-hee Na <donghee.na@python.org> | 2020-11-25 13:17:30 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-25 13:17:30 (GMT) |
commit | be319c0c108e308fb7ed6ec9522e969fdffd1253 (patch) | |
tree | 374255533809ed68cbd908a433c2a8550aa15c78 | |
parent | b9127dd6eedd693cfd716a4444648864e2e00186 (diff) | |
download | cpython-be319c0c108e308fb7ed6ec9522e969fdffd1253.zip cpython-be319c0c108e308fb7ed6ec9522e969fdffd1253.tar.gz cpython-be319c0c108e308fb7ed6ec9522e969fdffd1253.tar.bz2 |
bpo-42299: Remove formatter module (GH-23476)
-rw-r--r-- | Doc/library/formatter.rst | 351 | ||||
-rw-r--r-- | Doc/library/index.rst | 1 | ||||
-rw-r--r-- | Doc/library/misc.rst | 13 | ||||
-rw-r--r-- | Doc/whatsnew/3.10.rst | 6 | ||||
-rw-r--r-- | Lib/formatter.py | 452 | ||||
-rw-r--r-- | Lib/test/test_sundry.py | 2 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2020-11-23-23-42-08.bpo-42299.Fdn4Wf.rst | 5 |
7 files changed, 12 insertions, 818 deletions
diff --git a/Doc/library/formatter.rst b/Doc/library/formatter.rst deleted file mode 100644 index 6c10ac6..0000000 --- a/Doc/library/formatter.rst +++ /dev/null @@ -1,351 +0,0 @@ -:mod:`formatter` --- Generic output formatting -============================================== - -.. module:: formatter - :synopsis: Generic output formatter and device interface. - :deprecated: - -.. deprecated:: 3.4 - Due to lack of usage, the formatter module has been deprecated. - --------------- - -This module supports two interface definitions, each with multiple -implementations: The *formatter* interface, and the *writer* interface which is -required by the formatter interface. - -Formatter objects transform an abstract flow of formatting events into specific -output events on writer objects. Formatters manage several stack structures to -allow various properties of a writer object to be changed and restored; writers -need not be able to handle relative changes nor any sort of "change back" -operation. Specific writer properties which may be controlled via formatter -objects are horizontal alignment, font, and left margin indentations. A -mechanism is provided which supports providing arbitrary, non-exclusive style -settings to a writer as well. Additional interfaces facilitate formatting -events which are not reversible, such as paragraph separation. - -Writer objects encapsulate device interfaces. Abstract devices, such as file -formats, are supported as well as physical devices. The provided -implementations all work with abstract devices. The interface makes available -mechanisms for setting the properties which formatter objects manage and -inserting data into the output. - - -.. _formatter-interface: - -The Formatter Interface ------------------------ - -Interfaces to create formatters are dependent on the specific formatter class -being instantiated. The interfaces described below are the required interfaces -which all formatters must support once initialized. - -One data element is defined at the module level: - - -.. data:: AS_IS - - Value which can be used in the font specification passed to the ``push_font()`` - method described below, or as the new value to any other ``push_property()`` - method. Pushing the ``AS_IS`` value allows the corresponding ``pop_property()`` - method to be called without having to track whether the property was changed. - -The following attributes are defined for formatter instance objects: - - -.. attribute:: formatter.writer - - The writer instance with which the formatter interacts. - - -.. method:: formatter.end_paragraph(blanklines) - - Close any open paragraphs and insert at least *blanklines* before the next - paragraph. - - -.. method:: formatter.add_line_break() - - Add a hard line break if one does not already exist. This does not break the - logical paragraph. - - -.. method:: formatter.add_hor_rule(*args, **kw) - - Insert a horizontal rule in the output. A hard break is inserted if there is - data in the current paragraph, but the logical paragraph is not broken. The - arguments and keywords are passed on to the writer's :meth:`send_line_break` - method. - - -.. method:: formatter.add_flowing_data(data) - - Provide data which should be formatted with collapsed whitespace. Whitespace - from preceding and successive calls to :meth:`add_flowing_data` is considered as - well when the whitespace collapse is performed. The data which is passed to - this method is expected to be word-wrapped by the output device. Note that any - word-wrapping still must be performed by the writer object due to the need to - rely on device and font information. - - -.. method:: formatter.add_literal_data(data) - - Provide data which should be passed to the writer unchanged. Whitespace, - including newline and tab characters, are considered legal in the value of - *data*. - - -.. method:: formatter.add_label_data(format, counter) - - Insert a label which should be placed to the left of the current left margin. - This should be used for constructing bulleted or numbered lists. If the - *format* value is a string, it is interpreted as a format specification for - *counter*, which should be an integer. The result of this formatting becomes the - value of the label; if *format* is not a string it is used as the label value - directly. The label value is passed as the only argument to the writer's - :meth:`send_label_data` method. Interpretation of non-string label values is - dependent on the associated writer. - - Format specifications are strings which, in combination with a counter value, - are used to compute label values. Each character in the format string is copied - to the label value, with some characters recognized to indicate a transform on - the counter value. Specifically, the character ``'1'`` represents the counter - value formatter as an Arabic number, the characters ``'A'`` and ``'a'`` - represent alphabetic representations of the counter value in upper and lower - case, respectively, and ``'I'`` and ``'i'`` represent the counter value in Roman - numerals, in upper and lower case. Note that the alphabetic and roman - transforms require that the counter value be greater than zero. - - -.. method:: formatter.flush_softspace() - - Send any pending whitespace buffered from a previous call to - :meth:`add_flowing_data` to the associated writer object. This should be called - before any direct manipulation of the writer object. - - -.. method:: formatter.push_alignment(align) - - Push a new alignment setting onto the alignment stack. This may be - :const:`AS_IS` if no change is desired. If the alignment value is changed from - the previous setting, the writer's :meth:`new_alignment` method is called with - the *align* value. - - -.. method:: formatter.pop_alignment() - - Restore the previous alignment. - - -.. method:: formatter.push_font((size, italic, bold, teletype)) - - Change some or all font properties of the writer object. Properties which are - not set to :const:`AS_IS` are set to the values passed in while others are - maintained at their current settings. The writer's :meth:`new_font` method is - called with the fully resolved font specification. - - -.. method:: formatter.pop_font() - - Restore the previous font. - - -.. method:: formatter.push_margin(margin) - - Increase the number of left margin indentations by one, associating the logical - tag *margin* with the new indentation. The initial margin level is ``0``. - Changed values of the logical tag must be true values; false values other than - :const:`AS_IS` are not sufficient to change the margin. - - -.. method:: formatter.pop_margin() - - Restore the previous margin. - - -.. method:: formatter.push_style(*styles) - - Push any number of arbitrary style specifications. All styles are pushed onto - the styles stack in order. A tuple representing the entire stack, including - :const:`AS_IS` values, is passed to the writer's :meth:`new_styles` method. - - -.. method:: formatter.pop_style(n=1) - - Pop the last *n* style specifications passed to :meth:`push_style`. A tuple - representing the revised stack, including :const:`AS_IS` values, is passed to - the writer's :meth:`new_styles` method. - - -.. method:: formatter.set_spacing(spacing) - - Set the spacing style for the writer. - - -.. method:: formatter.assert_line_data(flag=1) - - Inform the formatter that data has been added to the current paragraph - out-of-band. This should be used when the writer has been manipulated - directly. The optional *flag* argument can be set to false if the writer - manipulations produced a hard line break at the end of the output. - - -.. _formatter-impls: - -Formatter Implementations -------------------------- - -Two implementations of formatter objects are provided by this module. Most -applications may use one of these classes without modification or subclassing. - - -.. class:: NullFormatter(writer=None) - - A formatter which does nothing. If *writer* is omitted, a :class:`NullWriter` - instance is created. No methods of the writer are called by - :class:`NullFormatter` instances. Implementations should inherit from this - class if implementing a writer interface but don't need to inherit any - implementation. - - -.. class:: AbstractFormatter(writer) - - The standard formatter. This implementation has demonstrated wide applicability - to many writers, and may be used directly in most circumstances. It has been - used to implement a full-featured World Wide Web browser. - - -.. _writer-interface: - -The Writer Interface --------------------- - -Interfaces to create writers are dependent on the specific writer class being -instantiated. The interfaces described below are the required interfaces which -all writers must support once initialized. Note that while most applications can -use the :class:`AbstractFormatter` class as a formatter, the writer must -typically be provided by the application. - - -.. method:: writer.flush() - - Flush any buffered output or device control events. - - -.. method:: writer.new_alignment(align) - - Set the alignment style. The *align* value can be any object, but by convention - is a string or ``None``, where ``None`` indicates that the writer's "preferred" - alignment should be used. Conventional *align* values are ``'left'``, - ``'center'``, ``'right'``, and ``'justify'``. - - -.. method:: writer.new_font(font) - - Set the font style. The value of *font* will be ``None``, indicating that the - device's default font should be used, or a tuple of the form ``(size, - italic, bold, teletype)``. Size will be a string indicating the size of - font that should be used; specific strings and their interpretation must be - defined by the application. The *italic*, *bold*, and *teletype* values are - Boolean values specifying which of those font attributes should be used. - - -.. method:: writer.new_margin(margin, level) - - Set the margin level to the integer *level* and the logical tag to *margin*. - Interpretation of the logical tag is at the writer's discretion; the only - restriction on the value of the logical tag is that it not be a false value for - non-zero values of *level*. - - -.. method:: writer.new_spacing(spacing) - - Set the spacing style to *spacing*. - - -.. method:: writer.new_styles(styles) - - Set additional styles. The *styles* value is a tuple of arbitrary values; the - value :const:`AS_IS` should be ignored. The *styles* tuple may be interpreted - either as a set or as a stack depending on the requirements of the application - and writer implementation. - - -.. method:: writer.send_line_break() - - Break the current line. - - -.. method:: writer.send_paragraph(blankline) - - Produce a paragraph separation of at least *blankline* blank lines, or the - equivalent. The *blankline* value will be an integer. Note that the - implementation will receive a call to :meth:`send_line_break` before this call - if a line break is needed; this method should not include ending the last line - of the paragraph. It is only responsible for vertical spacing between - paragraphs. - - -.. method:: writer.send_hor_rule(*args, **kw) - - Display a horizontal rule on the output device. The arguments to this method - are entirely application- and writer-specific, and should be interpreted with - care. The method implementation may assume that a line break has already been - issued via :meth:`send_line_break`. - - -.. method:: writer.send_flowing_data(data) - - Output character data which may be word-wrapped and re-flowed as needed. Within - any sequence of calls to this method, the writer may assume that spans of - multiple whitespace characters have been collapsed to single space characters. - - -.. method:: writer.send_literal_data(data) - - Output character data which has already been formatted for display. Generally, - this should be interpreted to mean that line breaks indicated by newline - characters should be preserved and no new line breaks should be introduced. The - data may contain embedded newline and tab characters, unlike data provided to - the :meth:`send_formatted_data` interface. - - -.. method:: writer.send_label_data(data) - - Set *data* to the left of the current left margin, if possible. The value of - *data* is not restricted; treatment of non-string values is entirely - application- and writer-dependent. This method will only be called at the - beginning of a line. - - -.. _writer-impls: - -Writer Implementations ----------------------- - -Three implementations of the writer object interface are provided as examples by -this module. Most applications will need to derive new writer classes from the -:class:`NullWriter` class. - - -.. class:: NullWriter() - - A writer which only provides the interface definition; no actions are taken on - any methods. This should be the base class for all writers which do not need to - inherit any implementation methods. - - -.. class:: AbstractWriter() - - A writer which can be used in debugging formatters, but not much else. Each - method simply announces itself by printing its name and arguments on standard - output. - - -.. class:: DumbWriter(file=None, maxcol=72) - - Simple writer class which writes output on the :term:`file object` passed - in as *file* or, if *file* is omitted, on standard output. The output is - simply word-wrapped to the number of columns specified by *maxcol*. This - class is suitable for reflowing a sequence of paragraphs. - diff --git a/Doc/library/index.rst b/Doc/library/index.rst index bebf7429..42f994f 100644 --- a/Doc/library/index.rst +++ b/Doc/library/index.rst @@ -72,7 +72,6 @@ the `Python Package Index <https://pypi.org>`_. custominterp.rst modules.rst language.rst - misc.rst windows.rst unix.rst superseded.rst diff --git a/Doc/library/misc.rst b/Doc/library/misc.rst deleted file mode 100644 index 0943235..0000000 --- a/Doc/library/misc.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _misc: - -********************** -Miscellaneous Services -********************** - -The modules described in this chapter provide miscellaneous services that are -available in all Python versions. Here's an overview: - - -.. toctree:: - - formatter.rst diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 704de815..f96a3bc 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -449,6 +449,12 @@ Removed :c:func:`PyParser_SimpleParseFileFlags` and :c:func:`PyNode_Compile` that were deprecated in 3.9 due to the switch to the new PEG parser. +* Removed the ``formatter`` module, which was deprecated in Python 3.4. + It is somewhat obsolete, little used, and not tested. It was originally + scheduled to be removed in Python 3.6, but such removals were delayed until + after Python 2.7 EOL. Existing users should copy whatever classes they use + into their code. + (Contributed by Dong-hee Na and Terry J. Reedy in :issue:`42299`.) Porting to Python 3.10 ====================== diff --git a/Lib/formatter.py b/Lib/formatter.py deleted file mode 100644 index e2394de..0000000 --- a/Lib/formatter.py +++ /dev/null @@ -1,452 +0,0 @@ -"""Generic output formatting. - -Formatter objects transform an abstract flow of formatting events into -specific output events on writer objects. Formatters manage several stack -structures to allow various properties of a writer object to be changed and -restored; writers need not be able to handle relative changes nor any sort -of ``change back'' operation. Specific writer properties which may be -controlled via formatter objects are horizontal alignment, font, and left -margin indentations. A mechanism is provided which supports providing -arbitrary, non-exclusive style settings to a writer as well. Additional -interfaces facilitate formatting events which are not reversible, such as -paragraph separation. - -Writer objects encapsulate device interfaces. Abstract devices, such as -file formats, are supported as well as physical devices. The provided -implementations all work with abstract devices. The interface makes -available mechanisms for setting the properties which formatter objects -manage and inserting data into the output. -""" - -import sys -import warnings -warnings.warn('the formatter module is deprecated', DeprecationWarning, - stacklevel=2) - - -AS_IS = None - - -class NullFormatter: - """A formatter which does nothing. - - If the writer parameter is omitted, a NullWriter instance is created. - No methods of the writer are called by NullFormatter instances. - - Implementations should inherit from this class if implementing a writer - interface but don't need to inherit any implementation. - - """ - - def __init__(self, writer=None): - if writer is None: - writer = NullWriter() - self.writer = writer - def end_paragraph(self, blankline): pass - def add_line_break(self): pass - def add_hor_rule(self, *args, **kw): pass - def add_label_data(self, format, counter, blankline=None): pass - def add_flowing_data(self, data): pass - def add_literal_data(self, data): pass - def flush_softspace(self): pass - def push_alignment(self, align): pass - def pop_alignment(self): pass - def push_font(self, x): pass - def pop_font(self): pass - def push_margin(self, margin): pass - def pop_margin(self): pass - def set_spacing(self, spacing): pass - def push_style(self, *styles): pass - def pop_style(self, n=1): pass - def assert_line_data(self, flag=1): pass - - -class AbstractFormatter: - """The standard formatter. - - This implementation has demonstrated wide applicability to many writers, - and may be used directly in most circumstances. It has been used to - implement a full-featured World Wide Web browser. - - """ - - # Space handling policy: blank spaces at the boundary between elements - # are handled by the outermost context. "Literal" data is not checked - # to determine context, so spaces in literal data are handled directly - # in all circumstances. - - def __init__(self, writer): - self.writer = writer # Output device - self.align = None # Current alignment - self.align_stack = [] # Alignment stack - self.font_stack = [] # Font state - self.margin_stack = [] # Margin state - self.spacing = None # Vertical spacing state - self.style_stack = [] # Other state, e.g. color - self.nospace = 1 # Should leading space be suppressed - self.softspace = 0 # Should a space be inserted - self.para_end = 1 # Just ended a paragraph - self.parskip = 0 # Skipped space between paragraphs? - self.hard_break = 1 # Have a hard break - self.have_label = 0 - - def end_paragraph(self, blankline): - if not self.hard_break: - self.writer.send_line_break() - self.have_label = 0 - if self.parskip < blankline and not self.have_label: - self.writer.send_paragraph(blankline - self.parskip) - self.parskip = blankline - self.have_label = 0 - self.hard_break = self.nospace = self.para_end = 1 - self.softspace = 0 - - def add_line_break(self): - if not (self.hard_break or self.para_end): - self.writer.send_line_break() - self.have_label = self.parskip = 0 - self.hard_break = self.nospace = 1 - self.softspace = 0 - - def add_hor_rule(self, *args, **kw): - if not self.hard_break: - self.writer.send_line_break() - self.writer.send_hor_rule(*args, **kw) - self.hard_break = self.nospace = 1 - self.have_label = self.para_end = self.softspace = self.parskip = 0 - - def add_label_data(self, format, counter, blankline = None): - if self.have_label or not self.hard_break: - self.writer.send_line_break() - if not self.para_end: - self.writer.send_paragraph((blankline and 1) or 0) - if isinstance(format, str): - self.writer.send_label_data(self.format_counter(format, counter)) - else: - self.writer.send_label_data(format) - self.nospace = self.have_label = self.hard_break = self.para_end = 1 - self.softspace = self.parskip = 0 - - def format_counter(self, format, counter): - label = '' - for c in format: - if c == '1': - label = label + ('%d' % counter) - elif c in 'aA': - if counter > 0: - label = label + self.format_letter(c, counter) - elif c in 'iI': - if counter > 0: - label = label + self.format_roman(c, counter) - else: - label = label + c - return label - - def format_letter(self, case, counter): - label = '' - while counter > 0: - counter, x = divmod(counter-1, 26) - # This makes a strong assumption that lowercase letters - # and uppercase letters form two contiguous blocks, with - # letters in order! - s = chr(ord(case) + x) - label = s + label - return label - - def format_roman(self, case, counter): - ones = ['i', 'x', 'c', 'm'] - fives = ['v', 'l', 'd'] - label, index = '', 0 - # This will die of IndexError when counter is too big - while counter > 0: - counter, x = divmod(counter, 10) - if x == 9: - label = ones[index] + ones[index+1] + label - elif x == 4: - label = ones[index] + fives[index] + label - else: - if x >= 5: - s = fives[index] - x = x-5 - else: - s = '' - s = s + ones[index]*x - label = s + label - index = index + 1 - if case == 'I': - return label.upper() - return label - - def add_flowing_data(self, data): - if not data: return - prespace = data[:1].isspace() - postspace = data[-1:].isspace() - data = " ".join(data.split()) - if self.nospace and not data: - return - elif prespace or self.softspace: - if not data: - if not self.nospace: - self.softspace = 1 - self.parskip = 0 - return - if not self.nospace: - data = ' ' + data - self.hard_break = self.nospace = self.para_end = \ - self.parskip = self.have_label = 0 - self.softspace = postspace - self.writer.send_flowing_data(data) - - def add_literal_data(self, data): - if not data: return - if self.softspace: - self.writer.send_flowing_data(" ") - self.hard_break = data[-1:] == '\n' - self.nospace = self.para_end = self.softspace = \ - self.parskip = self.have_label = 0 - self.writer.send_literal_data(data) - - def flush_softspace(self): - if self.softspace: - self.hard_break = self.para_end = self.parskip = \ - self.have_label = self.softspace = 0 - self.nospace = 1 - self.writer.send_flowing_data(' ') - - def push_alignment(self, align): - if align and align != self.align: - self.writer.new_alignment(align) - self.align = align - self.align_stack.append(align) - else: - self.align_stack.append(self.align) - - def pop_alignment(self): - if self.align_stack: - del self.align_stack[-1] - if self.align_stack: - self.align = align = self.align_stack[-1] - self.writer.new_alignment(align) - else: - self.align = None - self.writer.new_alignment(None) - - def push_font(self, font): - size, i, b, tt = font - if self.softspace: - self.hard_break = self.para_end = self.softspace = 0 - self.nospace = 1 - self.writer.send_flowing_data(' ') - if self.font_stack: - csize, ci, cb, ctt = self.font_stack[-1] - if size is AS_IS: size = csize - if i is AS_IS: i = ci - if b is AS_IS: b = cb - if tt is AS_IS: tt = ctt - font = (size, i, b, tt) - self.font_stack.append(font) - self.writer.new_font(font) - - def pop_font(self): - if self.font_stack: - del self.font_stack[-1] - if self.font_stack: - font = self.font_stack[-1] - else: - font = None - self.writer.new_font(font) - - def push_margin(self, margin): - self.margin_stack.append(margin) - fstack = [m for m in self.margin_stack if m] - if not margin and fstack: - margin = fstack[-1] - self.writer.new_margin(margin, len(fstack)) - - def pop_margin(self): - if self.margin_stack: - del self.margin_stack[-1] - fstack = [m for m in self.margin_stack if m] - if fstack: - margin = fstack[-1] - else: - margin = None - self.writer.new_margin(margin, len(fstack)) - - def set_spacing(self, spacing): - self.spacing = spacing - self.writer.new_spacing(spacing) - - def push_style(self, *styles): - if self.softspace: - self.hard_break = self.para_end = self.softspace = 0 - self.nospace = 1 - self.writer.send_flowing_data(' ') - for style in styles: - self.style_stack.append(style) - self.writer.new_styles(tuple(self.style_stack)) - - def pop_style(self, n=1): - del self.style_stack[-n:] - self.writer.new_styles(tuple(self.style_stack)) - - def assert_line_data(self, flag=1): - self.nospace = self.hard_break = not flag - self.para_end = self.parskip = self.have_label = 0 - - -class NullWriter: - """Minimal writer interface to use in testing & inheritance. - - A writer which only provides the interface definition; no actions are - taken on any methods. This should be the base class for all writers - which do not need to inherit any implementation methods. - - """ - def __init__(self): pass - def flush(self): pass - def new_alignment(self, align): pass - def new_font(self, font): pass - def new_margin(self, margin, level): pass - def new_spacing(self, spacing): pass - def new_styles(self, styles): pass - def send_paragraph(self, blankline): pass - def send_line_break(self): pass - def send_hor_rule(self, *args, **kw): pass - def send_label_data(self, data): pass - def send_flowing_data(self, data): pass - def send_literal_data(self, data): pass - - -class AbstractWriter(NullWriter): - """A writer which can be used in debugging formatters, but not much else. - - Each method simply announces itself by printing its name and - arguments on standard output. - - """ - - def new_alignment(self, align): - print("new_alignment(%r)" % (align,)) - - def new_font(self, font): - print("new_font(%r)" % (font,)) - - def new_margin(self, margin, level): - print("new_margin(%r, %d)" % (margin, level)) - - def new_spacing(self, spacing): - print("new_spacing(%r)" % (spacing,)) - - def new_styles(self, styles): - print("new_styles(%r)" % (styles,)) - - def send_paragraph(self, blankline): - print("send_paragraph(%r)" % (blankline,)) - - def send_line_break(self): - print("send_line_break()") - - def send_hor_rule(self, *args, **kw): - print("send_hor_rule()") - - def send_label_data(self, data): - print("send_label_data(%r)" % (data,)) - - def send_flowing_data(self, data): - print("send_flowing_data(%r)" % (data,)) - - def send_literal_data(self, data): - print("send_literal_data(%r)" % (data,)) - - -class DumbWriter(NullWriter): - """Simple writer class which writes output on the file object passed in - as the file parameter or, if file is omitted, on standard output. The - output is simply word-wrapped to the number of columns specified by - the maxcol parameter. This class is suitable for reflowing a sequence - of paragraphs. - - """ - - def __init__(self, file=None, maxcol=72): - self.file = file or sys.stdout - self.maxcol = maxcol - NullWriter.__init__(self) - self.reset() - - def reset(self): - self.col = 0 - self.atbreak = 0 - - def send_paragraph(self, blankline): - self.file.write('\n'*blankline) - self.col = 0 - self.atbreak = 0 - - def send_line_break(self): - self.file.write('\n') - self.col = 0 - self.atbreak = 0 - - def send_hor_rule(self, *args, **kw): - self.file.write('\n') - self.file.write('-'*self.maxcol) - self.file.write('\n') - self.col = 0 - self.atbreak = 0 - - def send_literal_data(self, data): - self.file.write(data) - i = data.rfind('\n') - if i >= 0: - self.col = 0 - data = data[i+1:] - data = data.expandtabs() - self.col = self.col + len(data) - self.atbreak = 0 - - def send_flowing_data(self, data): - if not data: return - atbreak = self.atbreak or data[0].isspace() - col = self.col - maxcol = self.maxcol - write = self.file.write - for word in data.split(): - if atbreak: - if col + len(word) >= maxcol: - write('\n') - col = 0 - else: - write(' ') - col = col + 1 - write(word) - col = col + len(word) - atbreak = 1 - self.col = col - self.atbreak = data[-1].isspace() - - -def test(file = None): - w = DumbWriter() - f = AbstractFormatter(w) - if file is not None: - fp = open(file) - elif sys.argv[1:]: - fp = open(sys.argv[1]) - else: - fp = sys.stdin - try: - for line in fp: - if line == '\n': - f.end_paragraph(1) - else: - f.add_flowing_data(line) - finally: - if fp is not sys.stdin: - fp.close() - f.end_paragraph(0) - - -if __name__ == '__main__': - test() diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py index 04e572c..aab074b 100644 --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -9,7 +9,7 @@ import unittest class TestUntestedModules(unittest.TestCase): def test_untested_modules_can_be_imported(self): - untested = ('encodings', 'formatter') + untested = ('encodings',) with warnings_helper.check_warnings(quiet=True): for name in untested: try: diff --git a/Misc/NEWS.d/next/Library/2020-11-23-23-42-08.bpo-42299.Fdn4Wf.rst b/Misc/NEWS.d/next/Library/2020-11-23-23-42-08.bpo-42299.Fdn4Wf.rst new file mode 100644 index 0000000..a8e156c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-23-23-42-08.bpo-42299.Fdn4Wf.rst @@ -0,0 +1,5 @@ +Removed the ``formatter`` module, which was deprecated in Python 3.4. +It is somewhat obsolete, little used, and not tested. It was originally +scheduled to be removed in Python 3.6, but such removals were delayed until +after Python 2.7 EOL. Existing users should copy whatever classes they use +into their code. Patch by Dong-hee Na and and Terry J. Reedy. |