summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDong-hee Na <donghee.na@python.org>2020-11-25 22:17:30 +0900
committerGitHub <noreply@github.com>2020-11-25 22:17:30 +0900
commitbe319c0c108e308fb7ed6ec9522e969fdffd1253 (patch)
tree374255533809ed68cbd908a433c2a8550aa15c78
parentb9127dd6eedd693cfd716a4444648864e2e00186 (diff)
downloadcpython-git-be319c0c108e308fb7ed6ec9522e969fdffd1253.tar.gz
bpo-42299: Remove formatter module (GH-23476)
-rw-r--r--Doc/library/formatter.rst351
-rw-r--r--Doc/library/index.rst1
-rw-r--r--Doc/library/misc.rst13
-rw-r--r--Doc/whatsnew/3.10.rst6
-rw-r--r--Lib/formatter.py452
-rw-r--r--Lib/test/test_sundry.py2
-rw-r--r--Misc/NEWS.d/next/Library/2020-11-23-23-42-08.bpo-42299.Fdn4Wf.rst5
7 files changed, 12 insertions, 818 deletions
diff --git a/Doc/library/formatter.rst b/Doc/library/formatter.rst
deleted file mode 100644
index 6c10ac6fab..0000000000
--- 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 bebf7429b0..42f994f8b8 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 0943235246..0000000000
--- 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 704de8156f..f96a3bcbca 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 e2394de8c2..0000000000
--- 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 04e572c00a..aab074b8a9 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 0000000000..a8e156c100
--- /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.