diff --git a/.gitignore b/.gitignore index 49eadd6..03b0761 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ PySolFC-2.0.tar.bz2 /PySolFC-2.10.0.tar.xz /PySolFC-2.12.0.tar.xz /PySolFC-Cardsets--Minimal-2.0.2.tar.xz +/PySolFC-2.14.0.tar.xz diff --git a/06d2fd5b90c29cbfe9b938676cc85c514cbbcca1.patch b/06d2fd5b90c29cbfe9b938676cc85c514cbbcca1.patch deleted file mode 100644 index d558b6c..0000000 --- a/06d2fd5b90c29cbfe9b938676cc85c514cbbcca1.patch +++ /dev/null @@ -1,657 +0,0 @@ -From 06d2fd5b90c29cbfe9b938676cc85c514cbbcca1 Mon Sep 17 00:00:00 2001 -From: Shlomi Fish -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() diff --git a/PySolFC.spec b/PySolFC.spec index 7943ca7..8d97c83 100644 --- a/PySolFC.spec +++ b/PySolFC.spec @@ -1,5 +1,5 @@ Name: PySolFC -Version: 2.12.0 +Version: 2.14.0 Release: 1%{?dist} Summary: A collection of solitaire card games License: GPLv2+ @@ -8,7 +8,6 @@ Source0: https://downloads.sourceforge.net/pysolfc/%{name}-%{version}.tar Source1: pysol-start-script Source2: https://downloads.sourceforge.net/pysolfc/PySolFC-Cardsets--Minimal-2.0.2.tar.xz Patch0: PySolFC-desktop-exec.patch -Patch1: 06d2fd5b90c29cbfe9b938676cc85c514cbbcca1.patch BuildArch: noarch BuildRequires: python%{python3_pkgversion}-devel @@ -54,9 +53,6 @@ written plug-ins, an integrated HTML help browser, and lots of documentation. %py3_install # install desktop file desktop-file-install \ -%if 0%{?fedora} && 0%{?fedora} < 19 - --vendor="fedora" \ -%endif --delete-original \ --dir=$RPM_BUILD_ROOT/%{_datadir}/applications \ $RPM_BUILD_ROOT/%{_datadir}/applications/pysol.desktop @@ -82,6 +78,9 @@ pathfix.py -pni "%{__python3} %{py3_shbang_opts}" $RPM_BUILD_ROOT%{_bindir}/* %changelog +* Sun Sep 19 2021 Fedora Release Monitoring - 2.14.0-1 +- Update to 2.14.0 (#2005720) + * Thu Aug 12 2021 Sérgio Basto - 2.12.0-1 - Update to 2.12.0 diff --git a/sources b/sources index 4213dd8..5d88c5b 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (PySolFC-2.12.0.tar.xz) = 893012e93ca1cba72fac5f9f428c548af3aa59fa094aa9d027ed6740c91b34c5be62972e6522fb89264d1eb0f887234ddb07fa67a765573e105dbc25d885d1c5 +SHA512 (PySolFC-2.14.0.tar.xz) = 0215276e5cc8caaefa0d7212d675af32e935b3ae4d4839624b34e8d68f0fc7e09accedf3b8e6428b349fe5c2ee7b4c128cd209d074b2c24311fa54f1c7b0c68f SHA512 (PySolFC-Cardsets--Minimal-2.0.2.tar.xz) = 5317866d6259b154219ec6efea349af3f9cb0fe9309a895ee55f7be87ebc8c34df12b81a08e1dee907a3f475f4e623c3609fdbd7e357890c2ade418ec5d68cb2