Группа :: Игры/Карты
Пакет: PySolFC
Главная Изменения Спек Патчи Sources Загрузить Gear Bugs and FR Repocop
Патч: 06d2fd5b90c29cbfe9b938676cc85c514cbbcca1.patch
Скачать
Скачать
From 06d2fd5b90c29cbfe9b938676cc85c514cbbcca1 Mon Sep 17 00:00:00 2001
From: Shlomi Fish <shlomif@shlomifish.org>
Date: Wed, 11 Aug 2021 19:19:01 +0300
Subject: [PATCH] issue217 : formatting.py deprecated fix.
This file is derived from /usr/lib/python3.9/formatter.py . All changes
are placed under CC0.
See:
* https://github.com/shlomif/PySolFC/issues/217
* https://bugzilla.redhat.com/show_bug.cgi?id=1990043
---
pysollib/formatter.py | 474 +++++++++++++++++++++++++++++++++++
pysollib/htmllib2.py | 10 +-
pysollib/kivy/tkhtml.py | 8 +-
pysollib/pysolgtk/tkhtml.py | 8 +-
pysollib/ui/tktile/tkhtml.py | 8 +-
5 files changed, 492 insertions(+), 16 deletions(-)
create mode 100644 pysollib/formatter.py
diff --git a/pysollib/formatter.py b/pysollib/formatter.py
new file mode 100644
index 00000000..f572a7bb
--- /dev/null
+++ b/pysollib/formatter.py
@@ -0,0 +1,474 @@
+"""
+
+This file is derived from /usr/lib/python3.9/formatter.py . All changes
+are placed under CC0.
+
+See:
+
+* https://github.com/shlomif/PySolFC/issues/217
+
+* https://bugzilla.redhat.com/show_bug.cgi?id=1990043
+
+----
+
+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
+if False:
+ 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/pysollib/htmllib2.py b/pysollib/htmllib2.py
index 7ff6b2a9..dab753e7 100644
--- a/pysollib/htmllib2.py
+++ b/pysollib/htmllib2.py
@@ -4,7 +4,7 @@
http://www.w3.org/hypertext/WWW/MarkUp/html-spec/html-spec_toc.html
"""
-from formatter import AS_IS
+from pysollib.formatter import AS_IS
from six.moves import html_parser
@@ -483,7 +483,7 @@ def unknown_endtag(self, tag):
def test(args=None):
import sys
- import formatter
+ import pysollib.formatter
if not args:
args = sys.argv[1:]
@@ -508,9 +508,11 @@ def test(args=None):
sys.exit(1)
if silent:
- f = formatter.NullFormatter()
+ f = pysollib.formatter.NullFormatter()
else:
- f = formatter.AbstractFormatter(formatter.DumbWriter())
+ f = pysollib.formatter.AbstractFormatter(
+ pysollib.formatter.DumbWriter()
+ )
p = HTMLParser(f)
p.feed(data)
diff --git a/pysollib/kivy/tkhtml.py b/pysollib/kivy/tkhtml.py
index 152b281c..54c0db0e 100644
--- a/pysollib/kivy/tkhtml.py
+++ b/pysollib/kivy/tkhtml.py
@@ -21,7 +21,6 @@
#
# ---------------------------------------------------------------------------#
-import formatter
import os
import sys
@@ -29,6 +28,7 @@
from kivy.uix.button import Button
from kivy.uix.label import Label
+import pysollib.formatter
import pysollib.htmllib2 as htmllib
from pysollib.kivy.LApp import LPopCommander
from pysollib.kivy.LApp import LScrollView
@@ -84,9 +84,9 @@ def cmp2(a, b):
return (a > b) - (a < b)
-class tkHTMLWriter(formatter.NullWriter):
+class tkHTMLWriter(pysollib.formatter.NullWriter):
def __init__(self, text, viewer, app):
- formatter.NullWriter.__init__(self)
+ pysollib.formatter.NullWriter.__init__(self)
self.text = text
self.viewer = viewer
@@ -630,7 +630,7 @@ def display(self, url, add=1, relpath=1, xview=0, yview=0):
# self.images = {}
self.text.textbuffer = ''
writer = tkHTMLWriter(self.text, self, self.app)
- fmt = formatter.AbstractFormatter(writer)
+ fmt = pysollib.formatter.AbstractFormatter(writer)
parser = tkHTMLParser(fmt)
parser.feed(data)
parser.close()
diff --git a/pysollib/pysolgtk/tkhtml.py b/pysollib/pysolgtk/tkhtml.py
index 798efda2..f1c18659 100644
--- a/pysollib/pysolgtk/tkhtml.py
+++ b/pysollib/pysolgtk/tkhtml.py
@@ -21,7 +21,6 @@
#
# ---------------------------------------------------------------------------
-import formatter
import htmllib
import os
import sys
@@ -34,6 +33,7 @@
import pango
+import pysollib.formatter
from pysollib.mfxutil import Struct, openURL
from pysollib.mygettext import _
from pysollib.settings import TITLE
@@ -55,9 +55,9 @@
# *
# ************************************************************************
-class tkHTMLWriter(formatter.NullWriter):
+class tkHTMLWriter(pysollib.formatter.NullWriter):
def __init__(self, text, viewer, app):
- formatter.NullWriter.__init__(self)
+ pysollib.formatter.NullWriter.__init__(self)
self.text = text # gtk.TextBuffer
self.viewer = viewer # HTMLViewer
@@ -489,7 +489,7 @@ def display(self, url, add=1, relpath=1, position=(0, 0)):
self.textbuffer.delete(start, end)
writer = tkHTMLWriter(self.textbuffer, self, self.app)
- fmt = formatter.AbstractFormatter(writer)
+ fmt = pysollib.formatter.AbstractFormatter(writer)
parser = tkHTMLParser(fmt)
parser.feed(data)
parser.close()
diff --git a/pysollib/ui/tktile/tkhtml.py b/pysollib/ui/tktile/tkhtml.py
index acab5711..afcb7257 100644
--- a/pysollib/ui/tktile/tkhtml.py
+++ b/pysollib/ui/tktile/tkhtml.py
@@ -21,10 +21,10 @@
#
# ---------------------------------------------------------------------------
-import formatter
import os
import sys
+import pysollib.formatter
import pysollib.htmllib2 as htmllib
from pysollib.mfxutil import openURL
from pysollib.mygettext import _
@@ -40,9 +40,9 @@
# ************************************************************************
-class tkHTMLWriter(formatter.NullWriter):
+class tkHTMLWriter(pysollib.formatter.NullWriter):
def __init__(self, text, viewer, app):
- formatter.NullWriter.__init__(self)
+ pysollib.formatter.NullWriter.__init__(self)
self.text = text
self.viewer = viewer
@@ -379,7 +379,7 @@ def display(self, url, add=1, relpath=1, xview=0, yview=0):
self.text.delete("1.0", "end")
# self.images = {}
writer = tkHTMLWriter(self.text, self, self.app)
- fmt = formatter.AbstractFormatter(writer)
+ fmt = pysollib.formatter.AbstractFormatter(writer)
parser = tkHTMLParser(fmt)
parser.feed(data)
parser.close()