Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-feedgenerator for 
openSUSE:Factory checked in at 2021-09-29 20:19:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-feedgenerator (Old)
 and      /work/SRC/openSUSE:Factory/.python-feedgenerator.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-feedgenerator"

Wed Sep 29 20:19:14 2021 rev:6 rq:922186 version:2.0.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-feedgenerator/python-feedgenerator.changes    
    2021-08-20 16:57:50.402876704 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-feedgenerator.new.1899/python-feedgenerator.changes
      2021-09-29 20:20:45.199148464 +0200
@@ -1,0 +2,13 @@
+Tue Sep 28 20:24:30 UTC 2021 - Beno??t Monin <[email protected]>
+
+- udpate to version 2.0.0:
+  * Add preliminary support for adding images to feeds
+  * Update code for Python 3.6+
+  * Drop support for Python 2.7
+  * Fix double subtitles if both description & subtitle are
+    provided
+- skip python2 build: support dropped from upstream
+- add pytest to the BuildRequires: needed for the tests now
+- run the tests with pytest but skip coverage generation
+
+-------------------------------------------------------------------

Old:
----
  feedgenerator-1.9.2.tar.gz

New:
----
  feedgenerator-2.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-feedgenerator.spec ++++++
--- /var/tmp/diff_new_pack.yZRKw0/_old  2021-09-29 20:20:45.775149299 +0200
+++ /var/tmp/diff_new_pack.yZRKw0/_new  2021-09-29 20:20:45.779149305 +0200
@@ -16,15 +16,17 @@
 #
 
 
+%define skip_python2 1
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-feedgenerator
-Version:        1.9.2
+Version:        2.0.0
 Release:        0
 Summary:        Standalone version of django.utilsfeedgenerator, compatible 
with Py3k
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
 URL:            https://github.com/getpelican/feedgenerator
 Source:         
https://files.pythonhosted.org/packages/source/f/feedgenerator/feedgenerator-%{version}.tar.gz
+BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module pytz}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module six}
@@ -51,7 +53,8 @@
 
 %check
 export LC_ALL=en_US.utf8
-%pyunittest discover -v
+# skip coverage by using an empty configuration file
+%pytest -c /dev/null
 
 %files %{python_files}
 %license LICENSE

++++++ feedgenerator-1.9.2.tar.gz -> feedgenerator-2.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/feedgenerator-1.9.2/PKG-INFO 
new/feedgenerator-2.0.0/PKG-INFO
--- old/feedgenerator-1.9.2/PKG-INFO    2021-08-18 10:57:37.331096400 +0200
+++ new/feedgenerator-2.0.0/PKG-INFO    2021-09-28 13:39:38.640296000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: feedgenerator
-Version: 1.9.2
+Version: 2.0.0
 Summary: Standalone version of django.utils.feedgenerator
 Home-page: https://github.com/getpelican/feedgenerator
 Author: Django Software Foundation
@@ -24,6 +24,7 @@
 Classifier: Topic :: Internet :: WWW/HTTP
 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=3.6
 License-File: LICENSE
 
 FeedGenerator
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/feedgenerator/django/utils/encoding.py 
new/feedgenerator-2.0.0/feedgenerator/django/utils/encoding.py
--- old/feedgenerator-1.9.2/feedgenerator/django/utils/encoding.py      
2020-02-09 09:40:59.000000000 +0100
+++ new/feedgenerator-2.0.0/feedgenerator/django/utils/encoding.py      
2021-09-28 13:03:34.000000000 +0200
@@ -1,17 +1,10 @@
-from __future__ import unicode_literals
-
 import codecs
 import datetime
 from decimal import Decimal
 import locale
-try:
-    from urllib.parse import quote
-except ImportError:     # Python 2
-    from urllib import quote
-import warnings
+from urllib.parse import quote
 
 from .functional import Promise
-from . import six
 
 class DjangoUnicodeDecodeError(UnicodeDecodeError):
     def __init__(self, obj, *args):
@@ -20,45 +13,9 @@
 
     def __str__(self):
         original = UnicodeDecodeError.__str__(self)
-        return '%s. You passed in %r (%s)' % (original, self.obj,
+        return '{}. You passed in {!r} ({})'.format(original, self.obj,
                 type(self.obj))
 
-class StrAndUnicode(object):
-    """
-    A class that derives __str__ from __unicode__.
-
-    On Python 2, __str__ returns the output of __unicode__ encoded as a UTF-8
-    bytestring. On Python 3, __str__ returns the output of __unicode__.
-
-    Useful as a mix-in. If you support Python 2 and 3 with a single code base,
-    you can inherit this mix-in and just define __unicode__.
-    """
-    def __init__(self, *args, **kwargs):
-        warnings.warn("StrAndUnicode is deprecated. Define a __str__ method "
-                      "and apply the @python_2_unicode_compatible decorator "
-                      "instead.", PendingDeprecationWarning, stacklevel=2)
-        super(StrAndUnicode, self).__init__(*args, **kwargs)
-
-    if six.PY3:
-        def __str__(self):
-            return self.__unicode__()
-    else:
-        def __str__(self):
-            return self.__unicode__().encode('utf-8')
-
-def python_2_unicode_compatible(klass):
-    """
-    A decorator that defines __unicode__ and __str__ methods under Python 2.
-    Under Python 3 it does nothing.
-
-    To support Python 2 and 3 with a single code base, define a __str__ method
-    returning text and apply this decorator to the class.
-    """
-    if not six.PY3:
-        klass.__unicode__ = klass.__str__
-        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
-    return klass
-
 def smart_text(s, encoding='utf-8', strings_only=False, errors='strict'):
     """
     Returns a text object representing 's' -- unicode on Python 2 and str on
@@ -77,7 +34,7 @@
     Objects of protected types are preserved as-is when passed to
     force_text(strings_only=True).
     """
-    return isinstance(obj, six.integer_types + (type(None), float, Decimal,
+    return isinstance(obj, (int, ) + (type(None), float, Decimal,
         datetime.datetime, datetime.date, datetime.time))
 
 def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
@@ -87,25 +44,22 @@
 
     If strings_only is True, don't convert (some) non-string-like objects.
     """
-    # Handle the common case first, saves 30-40% when s is an instance of
-    # six.text_type. This function gets called often in that setting.
-    if isinstance(s, six.text_type):
+    # Handle the common case first, saves 30-40% when s is an instance
+    # of str. This function gets called often in that setting.
+    if isinstance(s, str):
         return s
     if strings_only and is_protected_type(s):
         return s
     try:
-        if not isinstance(s, six.string_types):
+        if not isinstance(s, str):
             if hasattr(s, '__unicode__'):
                 s = s.__unicode__()
             else:
                 try:
-                    if six.PY3:
-                        if isinstance(s, bytes):
-                            s = six.text_type(s, encoding, errors)
-                        else:
-                            s = six.text_type(s)
+                    if isinstance(s, bytes):
+                        s = str(s, encoding, errors)
                     else:
-                        s = six.text_type(bytes(s), encoding, errors)
+                        s = str(s)
                 except UnicodeEncodeError:
                     if not isinstance(s, Exception):
                         raise
@@ -118,7 +72,7 @@
                     s = ' '.join([force_text(arg, encoding, strings_only,
                             errors) for arg in s])
         else:
-            # Note: We use .decode() here, instead of six.text_type(s, 
encoding,
+            # Note: We use .decode() here, instead of str(s, encoding,
             # errors), so that if s is a SafeBytes, it ends up being a
             # SafeText at the end.
             s = s.decode(encoding, errors)
@@ -162,13 +116,10 @@
     if strings_only and (s is None or isinstance(s, int)):
         return s
     if isinstance(s, Promise):
-        return six.text_type(s).encode(encoding, errors)
-    if not isinstance(s, six.string_types):
+        return str.encode(encoding, errors)
+    if not isinstance(s, str):
         try:
-            if six.PY3:
-                return six.text_type(s).encode(encoding)
-            else:
-                return bytes(s)
+            return str(s).encode(encoding)
         except UnicodeEncodeError:
             if isinstance(s, Exception):
                 # An Exception subclass containing non-ASCII data that doesn't
@@ -176,19 +127,13 @@
                 # further exception.
                 return ' '.join([smart_bytes(arg, encoding, strings_only,
                         errors) for arg in s])
-            return six.text_type(s).encode(encoding, errors)
+            return str(s).encode(encoding, errors)
     else:
         return s.encode(encoding, errors)
 
-if six.PY3:
-    smart_str = smart_text
-    force_str = force_text
-else:
-    smart_str = smart_bytes
-    force_str = force_bytes
-    # backwards compatibility for Python 2
-    smart_unicode = smart_text
-    force_unicode = force_text
+
+smart_str = smart_text
+force_str = force_text
 
 smart_str.__doc__ = """\
 Apply smart_text in Python 3 and smart_bytes in Python 2.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/feedgenerator/django/utils/feedgenerator.py 
new/feedgenerator-2.0.0/feedgenerator/django/utils/feedgenerator.py
--- old/feedgenerator-1.9.2/feedgenerator/django/utils/feedgenerator.py 
2021-08-18 10:07:21.000000000 +0200
+++ new/feedgenerator-2.0.0/feedgenerator/django/utils/feedgenerator.py 
2021-09-28 13:09:39.000000000 +0200
@@ -21,18 +21,12 @@
 For definitions of the different versions of RSS, see:
 
http://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004/02/04/incompatible-rss
 """
-from __future__ import unicode_literals
-
 import datetime
-try:
-    from urllib.parse import urlparse
-except ImportError:     # Python 2
-    from urlparse import urlparse
+from urllib.parse import urlparse
 from .xmlutils import SimplerXMLGenerator
 from .encoding import force_text, iri_to_uri
 from . import datetime_safe
-from . import six
-from .six import StringIO
+from io import StringIO
 from .timezone import is_aware
 
 def rfc2822_date(date):
@@ -45,9 +39,7 @@
     # We do this ourselves to be timezone aware, email.Utils is not tz aware.
     dow = days[date.weekday()]
     month = months[date.month - 1]
-    time_str = date.strftime('%s, %%d %s %%Y %%H:%%M:%%S ' % (dow, month))
-    if not six.PY3:             # strftime returns a byte string in Python 2
-        time_str = time_str.decode('utf-8')
+    time_str = date.strftime(f'{dow}, %d {month} %Y %H:%M:%S ')
     if is_aware(date):
         offset = date.tzinfo.utcoffset(date)
         timezone = (offset.days * 24 * 60) + (offset.seconds // 60)
@@ -60,8 +52,6 @@
     # Support datetime objects older than 1900
     date = datetime_safe.new_datetime(date)
     time_str = date.strftime('%Y-%m-%dT%H:%M:%S')
-    if not six.PY3:             # strftime returns a byte string in Python 2
-        time_str = time_str.decode('utf-8')
     if is_aware(date):
         offset = date.tzinfo.utcoffset(date)
         timezone = (offset.days * 24 * 60) + (offset.seconds // 60)
@@ -83,13 +73,13 @@
     fragment = ''
     if bits.fragment != '':
         fragment = '/%s' % (bits.fragment)
-    return 'tag:%s%s:%s%s' % (bits.hostname, d, bits.path, fragment)
+    return f'tag:{bits.hostname}{d}:{bits.path}{fragment}'
 
-class SyndicationFeed(object):
+class SyndicationFeed:
     "Base class for all syndication feeds. Subclasses should provide write()"
     def __init__(self, title, link, description, language=None, 
author_email=None,
             author_name=None, author_link=None, subtitle=None, categories=None,
-            feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, 
**kwargs):
+            feed_url=None, feed_copyright=None, image=None, feed_guid=None, 
ttl=None, **kwargs):
         to_unicode = lambda s: force_text(s, strings_only=True)
         if categories:
             categories = [force_text(c) for c in categories]
@@ -108,6 +98,7 @@
             'categories': categories or (),
             'feed_url': iri_to_uri(feed_url),
             'feed_copyright': to_unicode(feed_copyright),
+            'image': iri_to_uri(image),
             'id': feed_guid or link,
             'ttl': ttl,
         }
@@ -206,7 +197,7 @@
         else:
             return datetime.datetime.now()
 
-class Enclosure(object):
+class Enclosure:
     "Represents an RSS enclosure"
     def __init__(self, url, length, mime_type):
         "All args are expected to be Python Unicode objects"
@@ -238,6 +229,12 @@
         # Required Elements as per the specification
         handler.addQuickElement("title", self.feed['title'])
         handler.addQuickElement("link", self.feed['link'])
+        if self.feed['image'] is not None:
+            handler.startElement('image', {})
+            handler.addQuickElement("url", 
self.feed['link']+self.feed['image'])
+            handler.addQuickElement("title", self.feed['title'])
+            handler.addQuickElement("link", self.feed['link'])
+            handler.endElement('image')
         handler.addQuickElement("description", self.feed['description'])
 
         # Optional Channel Elements
@@ -335,10 +332,10 @@
             handler.endElement("author")
         # try to use description or subtitle if provided, subtitle has
         # precedence above description
-        if self.feed['description'] is not None:
-            handler.addQuickElement("subtitle", self.feed['description'])
-        if self.feed['subtitle'] is not None:
+        if self.feed['subtitle']:
             handler.addQuickElement("subtitle", self.feed['subtitle'])
+        elif self.feed['description']:
+            handler.addQuickElement("subtitle", self.feed['description'])
         for cat in self.feed['categories']:
             handler.addQuickElement("category", "", {"term": cat})
         if self.feed['feed_copyright'] is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/feedgenerator/django/utils/functional.py 
new/feedgenerator-2.0.0/feedgenerator/django/utils/functional.py
--- old/feedgenerator-1.9.2/feedgenerator/django/utils/functional.py    
2020-02-09 09:40:59.000000000 +0100
+++ new/feedgenerator-2.0.0/feedgenerator/django/utils/functional.py    
2021-09-28 13:03:34.000000000 +0200
@@ -3,8 +3,6 @@
 from functools import wraps, update_wrapper
 import sys
 
-from . import six
-
 # You can't trivially replace this `functools.partial` because this binds to
 # classes and returns bound instances, whereas functools.partial (on CPython)
 # is a type and its instances don't bind.
@@ -31,7 +29,7 @@
         return result
     return wrapper
 
-class cached_property(object):
+class cached_property:
     """
     Decorator that creates converts a method with a single
     self argument into a property cached on the instance.
@@ -43,7 +41,7 @@
         res = instance.__dict__[self.func.__name__] = self.func(instance)
         return res
 
-class Promise(object):
+class Promise:
     """
     This is just a base class for the proxy class created in
     the closure of the lazy function. It can be used to recognize
@@ -94,18 +92,12 @@
                             continue
                         setattr(cls, k, meth)
             cls._delegate_bytes = bytes in resultclasses
-            cls._delegate_text = six.text_type in resultclasses
+            cls._delegate_text = str in resultclasses
             assert not (cls._delegate_bytes and cls._delegate_text), "Cannot 
call lazy() with both bytes and text return types."
             if cls._delegate_text:
-                if six.PY3:
-                    cls.__str__ = cls.__text_cast
-                else:
-                    cls.__unicode__ = cls.__text_cast
+                cls.__str__ = cls.__text_cast
             elif cls._delegate_bytes:
-                if six.PY3:
-                    cls.__bytes__ = cls.__bytes_cast
-                else:
-                    cls.__str__ = cls.__bytes_cast
+                cls.__bytes__ = cls.__bytes_cast
         __prepare_class__ = classmethod(__prepare_class__)
 
         def __promise__(cls, klass, funcname, method):
@@ -153,10 +145,8 @@
         __hash__ = object.__hash__
 
         def __mod__(self, rhs):
-            if self._delegate_bytes and not six.PY3:
-                return bytes(self) % rhs
-            elif self._delegate_text:
-                return six.text_type(self) % rhs
+            if self._delegate_text:
+                return str(self) % rhs
             else:
                 raise AssertionError('__mod__ not supported for non-string 
types')
 
@@ -186,7 +176,7 @@
     """
     @wraps(func)
     def wrapper(*args, **kwargs):
-        for arg in list(args) + list(six.itervalues(kwargs)):
+        for arg in list(args) + list(kwargs.values()):
             if isinstance(arg, Promise):
                 break
         else:
@@ -202,7 +192,7 @@
         return func(self._wrapped, *args)
     return inner
 
-class LazyObject(object):
+class LazyObject:
     """
     A wrapper for another class that can be used to delay instantiation of the
     wrapped class.
@@ -266,12 +256,8 @@
     def _setup(self):
         self._wrapped = self._setupfunc()
 
-    if six.PY3:
-        __bytes__ = new_method_proxy(bytes)
-        __str__ = new_method_proxy(str)
-    else:
-        __str__ = new_method_proxy(str)
-        __unicode__ = new_method_proxy(unicode)
+    __bytes__ = new_method_proxy(bytes)
+    __str__ = new_method_proxy(str)
 
     def __deepcopy__(self, memo):
         if self._wrapped is empty:
@@ -335,36 +321,4 @@
         results[predicate(item)].append(item)
     return results
 
-if sys.version_info >= (2,7,2):
-    from functools import total_ordering
-else:
-    # For Python < 2.7.2. Python 2.6 does not have total_ordering, and
-    # total_ordering in 2.7 versions prior to 2.7.2 is buggy. See
-    # http://bugs.python.org/issue10042 for details. For these versions use
-    # code borrowed from Python 2.7.3.
-    def total_ordering(cls):
-        """Class decorator that fills in missing ordering methods"""
-        convert = {
-            '__lt__': [('__gt__', lambda self, other: not (self < other or 
self == other)),
-                       ('__le__', lambda self, other: self < other or self == 
other),
-                       ('__ge__', lambda self, other: not self < other)],
-            '__le__': [('__ge__', lambda self, other: not self <= other or 
self == other),
-                       ('__lt__', lambda self, other: self <= other and not 
self == other),
-                       ('__gt__', lambda self, other: not self <= other)],
-            '__gt__': [('__lt__', lambda self, other: not (self > other or 
self == other)),
-                       ('__ge__', lambda self, other: self > other or self == 
other),
-                       ('__le__', lambda self, other: not self > other)],
-            '__ge__': [('__le__', lambda self, other: (not self >= other) or 
self == other),
-                       ('__gt__', lambda self, other: self >= other and not 
self == other),
-                       ('__lt__', lambda self, other: not self >= other)]
-        }
-        roots = set(dir(cls)) & set(convert)
-        if not roots:
-            raise ValueError('must define at least one ordering operation: < > 
<= >=')
-        root = max(roots)       # prefer __lt__ to __le__ to __gt__ to __ge__
-        for opname, opfunc in convert[root]:
-            if opname not in roots:
-                opfunc.__name__ = opname
-                opfunc.__doc__ = getattr(int, opname).__doc__
-                setattr(cls, opname, opfunc)
-        return cls
+from functools import total_ordering
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/feedgenerator/django/utils/six.py 
new/feedgenerator-2.0.0/feedgenerator/django/utils/six.py
--- old/feedgenerator-1.9.2/feedgenerator/django/utils/six.py   2020-02-09 
09:40:59.000000000 +0100
+++ new/feedgenerator-2.0.0/feedgenerator/django/utils/six.py   1970-01-01 
01:00:00.000000000 +0100
@@ -1,370 +0,0 @@
-"""Utilities for writing code that runs on Python 2 and 3"""
-
-import operator
-import sys
-import types
-
-__author__ = "Benjamin Peterson <[email protected]>"
-__version__ = "1.1.0"
-
-
-# True if we are running on Python 3.
-PY3 = sys.version_info[0] == 3
-
-if PY3:
-    string_types = str,
-    integer_types = int,
-    class_types = type,
-    text_type = str
-    binary_type = bytes
-
-    MAXSIZE = sys.maxsize
-else:
-    string_types = basestring,
-    integer_types = (int, long)
-    class_types = (type, types.ClassType)
-    text_type = unicode
-    binary_type = str
-
-    # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
-    class X(object):
-        def __len__(self):
-            return 1 << 31
-    try:
-        len(X())
-    except OverflowError:
-        # 32-bit
-        MAXSIZE = int((1 << 31) - 1)
-    else:
-        # 64-bit
-        MAXSIZE = int((1 << 63) - 1)
-    del X
-
-
-def _add_doc(func, doc):
-    """Add documentation to a function."""
-    func.__doc__ = doc
-
-
-def _import_module(name):
-    """Import module, returning the module after the last dot."""
-    __import__(name)
-    return sys.modules[name]
-
-
-class _LazyDescr(object):
-
-    def __init__(self, name):
-        self.name = name
-
-    def __get__(self, obj, tp):
-        result = self._resolve()
-        setattr(obj, self.name, result)
-        # This is a bit ugly, but it avoids running this again.
-        delattr(tp, self.name)
-        return result
-
-
-class MovedModule(_LazyDescr):
-
-    def __init__(self, name, old, new=None):
-        super(MovedModule, self).__init__(name)
-        if PY3:
-            if new is None:
-                new = name
-            self.mod = new
-        else:
-            self.mod = old
-
-    def _resolve(self):
-        return _import_module(self.mod)
-
-
-class MovedAttribute(_LazyDescr):
-
-    def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
-        super(MovedAttribute, self).__init__(name)
-        if PY3:
-            if new_mod is None:
-                new_mod = name
-            self.mod = new_mod
-            if new_attr is None:
-                if old_attr is None:
-                    new_attr = name
-                else:
-                    new_attr = old_attr
-            self.attr = new_attr
-        else:
-            self.mod = old_mod
-            if old_attr is None:
-                old_attr = name
-            self.attr = old_attr
-
-    def _resolve(self):
-        module = _import_module(self.mod)
-        return getattr(module, self.attr)
-
-
-
-class _MovedItems(types.ModuleType):
-    """Lazy loading of moved objects"""
-
-
-_moved_attributes = [
-    MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
-    MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
-    MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
-    MovedAttribute("map", "itertools", "builtins", "imap", "map"),
-    MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
-    MovedAttribute("reduce", "__builtin__", "functools"),
-    MovedAttribute("StringIO", "StringIO", "io"),
-    MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
-    MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
-
-    MovedModule("builtins", "__builtin__"),
-    MovedModule("configparser", "ConfigParser"),
-    MovedModule("copyreg", "copy_reg"),
-    MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
-    MovedModule("http_cookies", "Cookie", "http.cookies"),
-    MovedModule("html_entities", "htmlentitydefs", "html.entities"),
-    MovedModule("html_parser", "HTMLParser", "html.parser"),
-    MovedModule("http_client", "httplib", "http.client"),
-    MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
-    MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
-    MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
-    MovedModule("cPickle", "cPickle", "pickle"),
-    MovedModule("queue", "Queue"),
-    MovedModule("reprlib", "repr"),
-    MovedModule("socketserver", "SocketServer"),
-    MovedModule("tkinter", "Tkinter"),
-    MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
-    MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
-    MovedModule("tkinter_scrolledtext", "ScrolledText", 
"tkinter.scrolledtext"),
-    MovedModule("tkinter_simpledialog", "SimpleDialog", 
"tkinter.simpledialog"),
-    MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
-    MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
-    MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
-    MovedModule("tkinter_colorchooser", "tkColorChooser",
-                "tkinter.colorchooser"),
-    MovedModule("tkinter_commondialog", "tkCommonDialog",
-                "tkinter.commondialog"),
-    MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
-    MovedModule("tkinter_font", "tkFont", "tkinter.font"),
-    MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
-    MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
-                "tkinter.simpledialog"),
-    MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
-    MovedModule("winreg", "_winreg"),
-]
-for attr in _moved_attributes:
-    setattr(_MovedItems, attr.name, attr)
-del attr
-
-moves = sys.modules["django.utils.six.moves"] = _MovedItems("moves")
-
-
-def add_move(move):
-    """Add an item to six.moves."""
-    setattr(_MovedItems, move.name, move)
-
-
-def remove_move(name):
-    """Remove item from six.moves."""
-    try:
-        delattr(_MovedItems, name)
-    except AttributeError:
-        try:
-            del moves.__dict__[name]
-        except KeyError:
-            raise AttributeError("no such move, %r" % (name,))
-
-
-if PY3:
-    _meth_func = "__func__"
-    _meth_self = "__self__"
-
-    _func_code = "__code__"
-    _func_defaults = "__defaults__"
-
-    _iterkeys = "keys"
-    _itervalues = "values"
-    _iteritems = "items"
-else:
-    _meth_func = "im_func"
-    _meth_self = "im_self"
-
-    _func_code = "func_code"
-    _func_defaults = "func_defaults"
-
-    _iterkeys = "iterkeys"
-    _itervalues = "itervalues"
-    _iteritems = "iteritems"
-
-
-if PY3:
-    def get_unbound_function(unbound):
-        return unbound
-
-
-    advance_iterator = next
-
-    def callable(obj):
-        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
-else:
-    def get_unbound_function(unbound):
-        return unbound.im_func
-
-
-    def advance_iterator(it):
-        return it.next()
-
-    callable = callable
-_add_doc(get_unbound_function,
-         """Get the function out of a possibly unbound function""")
-
-
-get_method_function = operator.attrgetter(_meth_func)
-get_method_self = operator.attrgetter(_meth_self)
-get_function_code = operator.attrgetter(_func_code)
-get_function_defaults = operator.attrgetter(_func_defaults)
-
-
-def iterkeys(d):
-    """Return an iterator over the keys of a dictionary."""
-    return getattr(d, _iterkeys)()
-
-def itervalues(d):
-    """Return an iterator over the values of a dictionary."""
-    return getattr(d, _itervalues)()
-
-def iteritems(d):
-    """Return an iterator over the (key, value) pairs of a dictionary."""
-    return getattr(d, _iteritems)()
-
-
-if PY3:
-    def b(s):
-        return s.encode("latin-1")
-    def u(s):
-        return s
-    if sys.version_info[1] <= 1:
-        def int2byte(i):
-            return bytes((i,))
-    else:
-        # This is about 2x faster than the implementation above on 3.2+
-        int2byte = operator.methodcaller("to_bytes", 1, "big")
-    import io
-    StringIO = io.StringIO
-    BytesIO = io.BytesIO
-else:
-    def b(s):
-        return s
-    def u(s):
-        return unicode(s, "unicode_escape")
-    int2byte = chr
-    import StringIO
-    StringIO = BytesIO = StringIO.StringIO
-_add_doc(b, """Byte literal""")
-_add_doc(u, """Text literal""")
-
-
-if PY3:
-    import builtins
-    exec_ = getattr(builtins, "exec")
-
-
-    def reraise(tp, value, tb=None):
-        if value.__traceback__ is not tb:
-            raise value.with_traceback(tb)
-        raise value
-
-
-    print_ = getattr(builtins, "print")
-    del builtins
-
-else:
-    def exec_(code, globs=None, locs=None):
-        """Execute code in a namespace."""
-        if globs is None:
-            frame = sys._getframe(1)
-            globs = frame.f_globals
-            if locs is None:
-                locs = frame.f_locals
-            del frame
-        elif locs is None:
-            locs = globs
-        exec("""exec code in globs, locs""")
-
-
-    exec_("""def reraise(tp, value, tb=None):
-    raise tp, value, tb
-""")
-
-
-    def print_(*args, **kwargs):
-        """The new-style print function."""
-        fp = kwargs.pop("file", sys.stdout)
-        if fp is None:
-            return
-        def write(data):
-            if not isinstance(data, basestring):
-                data = str(data)
-            fp.write(data)
-        want_unicode = False
-        sep = kwargs.pop("sep", None)
-        if sep is not None:
-            if isinstance(sep, unicode):
-                want_unicode = True
-            elif not isinstance(sep, str):
-                raise TypeError("sep must be None or a string")
-        end = kwargs.pop("end", None)
-        if end is not None:
-            if isinstance(end, unicode):
-                want_unicode = True
-            elif not isinstance(end, str):
-                raise TypeError("end must be None or a string")
-        if kwargs:
-            raise TypeError("invalid keyword arguments to print()")
-        if not want_unicode:
-            for arg in args:
-                if isinstance(arg, unicode):
-                    want_unicode = True
-                    break
-        if want_unicode:
-            newline = unicode("\n")
-            space = unicode(" ")
-        else:
-            newline = "\n"
-            space = " "
-        if sep is None:
-            sep = space
-        if end is None:
-            end = newline
-        for i, arg in enumerate(args):
-            if i:
-                write(sep)
-            write(arg)
-        write(end)
-
-_add_doc(reraise, """Reraise an exception.""")
-
-
-def with_metaclass(meta, base=object):
-    """Create a base class with a metaclass."""
-    return meta("NewBase", (base,), {})
-
-
-### Additional customizations for Django ###
-
-if PY3:
-    _iterlists = "lists"
-else:
-    _iterlists = "iterlists"
-
-def iterlists(d):
-    """Return an iterator over the values of a MultiValueDict."""
-    return getattr(d, _iterlists)()
-
-
-add_move(MovedModule("_dummy_thread", "dummy_thread"))
-add_move(MovedModule("_thread", "thread"))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/feedgenerator/django/utils/timezone.py 
new/feedgenerator-2.0.0/feedgenerator/django/utils/timezone.py
--- old/feedgenerator-1.9.2/feedgenerator/django/utils/timezone.py      
2020-02-09 09:40:59.000000000 +0100
+++ new/feedgenerator-2.0.0/feedgenerator/django/utils/timezone.py      
2021-09-28 13:03:34.000000000 +0200
@@ -13,8 +13,6 @@
     pytz = None
 
 # ### from django.conf import settings
-from . import six
-
 __all__ = [
     'utc', 'get_default_timezone', 'get_current_timezone',
     'activate', 'deactivate', 'override',
@@ -97,18 +95,18 @@
 # ### # In order to avoid accessing the settings at compile time,
 # ### # wrap the expression in a function and cache the result.
 # ### _localtime = None
-# ### 
+# ###
 # ### def get_default_timezone():
 # ###     """
 # ###     Returns the default time zone as a tzinfo instance.
-# ### 
+# ###
 # ###     This is the time zone defined by settings.TIME_ZONE.
-# ### 
+# ###
 # ###     See also :func:`get_current_timezone`.
 # ###     """
 # ###     global _localtime
 # ###     if _localtime is None:
-# ###         if isinstance(settings.TIME_ZONE, six.string_types) and pytz is 
not None:
+# ###         if isinstance(settings.TIME_ZONE, str) and pytz is not None:
 # ###             _localtime = pytz.timezone(settings.TIME_ZONE)
 # ###         else:
 # ###             _localtime = LocalTimezone()
@@ -161,7 +159,7 @@
     """
     if isinstance(timezone, tzinfo):
         _active.value = timezone
-    elif isinstance(timezone, six.string_types) and pytz is not None:
+    elif isinstance(timezone, (str, )) and pytz is not None:
         _active.value = pytz.timezone(timezone)
     else:
         raise ValueError("Invalid timezone: %r" % timezone)
@@ -175,7 +173,7 @@
     if hasattr(_active, "value"):
         del _active.value
 
-class override(object):
+class override:
     """
     Temporarily set the time zone for the current thread.
 
@@ -205,14 +203,14 @@
 
 
 # ### # Templates
-# ### 
+# ###
 # ### def template_localtime(value, use_tz=None):
 # ###     """
 # ###     Checks if value is a datetime and converts it to local time if 
necessary.
-# ### 
+# ###
 # ###     If use_tz is provided and is not None, that will force the value to
 # ###     be converted (or not), overriding the value of settings.USE_TZ.
-# ### 
+# ###
 # ###     This function is designed for use by the template engine.
 # ###     """
 # ###     should_convert = (isinstance(value, datetime)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/feedgenerator/django/utils/xmlutils.py 
new/feedgenerator-2.0.0/feedgenerator/django/utils/xmlutils.py
--- old/feedgenerator-1.9.2/feedgenerator/django/utils/xmlutils.py      
2020-02-09 09:40:59.000000000 +0100
+++ new/feedgenerator-2.0.0/feedgenerator/django/utils/xmlutils.py      
2021-09-28 13:03:34.000000000 +0200
@@ -2,8 +2,6 @@
 Utilities for XML generation/parsing.
 """
 
-import six
-
 from xml.sax.saxutils import XMLGenerator, quoteattr
 
 class SimplerXMLGenerator(XMLGenerator):
@@ -19,5 +17,5 @@
         self._write('<' + name)
         # sort attributes for consistent output
         for (name, value) in sorted(attrs.items()):
-            self._write(' %s=%s' % (name, quoteattr(value)))
-        self._write(six.u('>'))
+            self._write(f' {name}={quoteattr(value)}')
+        self._write('>')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/feedgenerator-1.9.2/feedgenerator.egg-info/PKG-INFO 
new/feedgenerator-2.0.0/feedgenerator.egg-info/PKG-INFO
--- old/feedgenerator-1.9.2/feedgenerator.egg-info/PKG-INFO     2021-08-18 
10:57:37.000000000 +0200
+++ new/feedgenerator-2.0.0/feedgenerator.egg-info/PKG-INFO     2021-09-28 
13:39:38.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: feedgenerator
-Version: 1.9.2
+Version: 2.0.0
 Summary: Standalone version of django.utils.feedgenerator
 Home-page: https://github.com/getpelican/feedgenerator
 Author: Django Software Foundation
@@ -24,6 +24,7 @@
 Classifier: Topic :: Internet :: WWW/HTTP
 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=3.6
 License-File: LICENSE
 
 FeedGenerator
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/feedgenerator.egg-info/SOURCES.txt 
new/feedgenerator-2.0.0/feedgenerator.egg-info/SOURCES.txt
--- old/feedgenerator-1.9.2/feedgenerator.egg-info/SOURCES.txt  2021-08-18 
10:57:37.000000000 +0200
+++ new/feedgenerator-2.0.0/feedgenerator.egg-info/SOURCES.txt  2021-09-28 
13:39:38.000000000 +0200
@@ -17,24 +17,12 @@
 feedgenerator/django/utils/encoding.py
 feedgenerator/django/utils/feedgenerator.py
 feedgenerator/django/utils/functional.py
-feedgenerator/django/utils/six.py
 feedgenerator/django/utils/timezone.py
 feedgenerator/django/utils/xmlutils.py
 tests_feedgenerator/__init__.py
 tests_feedgenerator/test_feedgenerator.py
 tests_feedgenerator/test_stringio.py
 tests_feedgenerator/usage_example.py
-tests_feedgenerator/__pycache__/__init__.cpython-36.pyc
-tests_feedgenerator/__pycache__/__init__.cpython-37.pyc
-tests_feedgenerator/__pycache__/__init__.cpython-38.pyc
 tests_feedgenerator/__pycache__/__init__.cpython-39.pyc
-tests_feedgenerator/__pycache__/test_feedgenerator.cpython-36-pytest-6.2.4.pyc
-tests_feedgenerator/__pycache__/test_feedgenerator.cpython-37-pytest-6.2.4.pyc
-tests_feedgenerator/__pycache__/test_feedgenerator.cpython-38-pytest-6.2.2.pyc
-tests_feedgenerator/__pycache__/test_feedgenerator.cpython-38-pytest-6.2.4.pyc
-tests_feedgenerator/__pycache__/test_feedgenerator.cpython-39-pytest-6.2.4.pyc
-tests_feedgenerator/__pycache__/test_stringio.cpython-36-pytest-6.2.4.pyc
-tests_feedgenerator/__pycache__/test_stringio.cpython-37-pytest-6.2.4.pyc
-tests_feedgenerator/__pycache__/test_stringio.cpython-38-pytest-6.2.2.pyc
-tests_feedgenerator/__pycache__/test_stringio.cpython-38-pytest-6.2.4.pyc
-tests_feedgenerator/__pycache__/test_stringio.cpython-39-pytest-6.2.4.pyc
\ No newline at end of file
+tests_feedgenerator/__pycache__/test_feedgenerator.cpython-39-pytest-6.2.5.pyc
+tests_feedgenerator/__pycache__/test_stringio.cpython-39-pytest-6.2.5.pyc
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/feedgenerator.egg-info/requires.txt 
new/feedgenerator-2.0.0/feedgenerator.egg-info/requires.txt
--- old/feedgenerator-1.9.2/feedgenerator.egg-info/requires.txt 2021-08-18 
10:57:37.000000000 +0200
+++ new/feedgenerator-2.0.0/feedgenerator.egg-info/requires.txt 2021-09-28 
13:39:38.000000000 +0200
@@ -1,2 +1 @@
 pytz>=0a
-six
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/feedgenerator-1.9.2/setup.cfg 
new/feedgenerator-2.0.0/setup.cfg
--- old/feedgenerator-1.9.2/setup.cfg   2021-08-18 10:57:37.332267000 +0200
+++ new/feedgenerator-2.0.0/setup.cfg   2021-09-28 13:39:38.641083200 +0200
@@ -1,6 +1,13 @@
 [sdist]
 force_manifest = 1
 
+[tool:pytest]
+addopts = 
+       --cov=feedgenerator
+       --cov=tests_feedgenerator
+       --cov-report=html
+       --cov-report=term-missing:skip-covered
+
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/feedgenerator-1.9.2/setup.py 
new/feedgenerator-2.0.0/setup.py
--- old/feedgenerator-1.9.2/setup.py    2021-08-18 10:46:33.000000000 +0200
+++ new/feedgenerator-2.0.0/setup.py    2021-09-28 13:34:59.000000000 +0200
@@ -1,6 +1,5 @@
 #!/usr/bin/env python
 
-from io import open
 
 # Using setuptools rather than distutils to get the `develop` command
 from setuptools import setup
@@ -35,11 +34,11 @@
 MAINTAINER = 'Pelican Dev Team'
 MAINTAINER_EMAIL = '[email protected]'
 KEYWORDS = "feed atom rss".split(' ')
-VERSION = '1.9.2'
+VERSION = '2.0.0'
 
 TEST_SUITE = 'tests_feedgenerator'
 
-REQUIRES = ['pytz >= 0a', 'six']
+REQUIRES = ['pytz >= 0a']
 
 setup(
     name=NAME,
@@ -47,6 +46,7 @@
     packages=PACKAGES,
     test_suite=TEST_SUITE,
     install_requires=REQUIRES,
+    python_requires='>=3.6',
     # metadata for upload to PyPI
     author=AUTHOR,
     author_email=AUTHOR_EMAIL,
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/__init__.cpython-36.pyc 
and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/__init__.cpython-36.pyc 
differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/__init__.cpython-37.pyc 
and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/__init__.cpython-37.pyc 
differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/__init__.cpython-38.pyc 
and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/__init__.cpython-38.pyc 
differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-36-pytest-6.2.4.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-36-pytest-6.2.4.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-37-pytest-6.2.4.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-37-pytest-6.2.4.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-38-pytest-6.2.2.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-38-pytest-6.2.2.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-38-pytest-6.2.4.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-38-pytest-6.2.4.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-39-pytest-6.2.4.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-39-pytest-6.2.4.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-39-pytest-6.2.5.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_feedgenerator.cpython-39-pytest-6.2.5.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_stringio.cpython-36-pytest-6.2.4.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_stringio.cpython-36-pytest-6.2.4.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_stringio.cpython-37-pytest-6.2.4.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_stringio.cpython-37-pytest-6.2.4.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_stringio.cpython-38-pytest-6.2.2.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_stringio.cpython-38-pytest-6.2.2.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_stringio.cpython-38-pytest-6.2.4.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_stringio.cpython-38-pytest-6.2.4.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_stringio.cpython-39-pytest-6.2.4.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_stringio.cpython-39-pytest-6.2.4.pyc
 differ
Binary files 
old/feedgenerator-1.9.2/tests_feedgenerator/__pycache__/test_stringio.cpython-39-pytest-6.2.5.pyc
 and 
new/feedgenerator-2.0.0/tests_feedgenerator/__pycache__/test_stringio.cpython-39-pytest-6.2.5.pyc
 differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/tests_feedgenerator/test_feedgenerator.py 
new/feedgenerator-2.0.0/tests_feedgenerator/test_feedgenerator.py
--- old/feedgenerator-1.9.2/tests_feedgenerator/test_feedgenerator.py   
2021-08-18 10:07:21.000000000 +0200
+++ new/feedgenerator-2.0.0/tests_feedgenerator/test_feedgenerator.py   
2021-09-28 13:03:34.000000000 +0200
@@ -1,17 +1,11 @@
-# -*- encoding: utf-8 -*-
+import unittest
 
-from __future__ import unicode_literals
-
-try:
-    import unittest2 as unittest
-except ImportError:
-    import unittest
-
-import six
 import datetime
 
 import feedgenerator
 
+import pytest
+
 FIXT_FEED = dict(
     title="Poynter E-Media Tidbits",
     link="http://www.poynter.org/column.asp?id=31";,
@@ -73,7 +67,7 @@
         self.maxDiff = None
 
     def test_000_types(self):
-        ty = six.text_type
+        ty = str
         for k, v in FIXT_FEED.items():
             self.assertEqual(type(v), ty)
         for k, v in FIXT_ITEM.items():
@@ -88,21 +82,9 @@
         feed = feedgenerator.Rss201rev2Feed(**FIXT_FEED)
         feed.add_item(**FIXT_ITEM)
         result = feed.writeString(ENCODING)
-        if six.PY3:
-            # On Python 3, result of feedgenerator is a unicode string!
-            # So do not encode our expected_result.
-            expected_result = build_expected_rss_result(feed, 
EXPECTED_RESULT_RSS, None)
-        else:
-            # On Python 2, result of feedgenerator is a str string!
-            # Expected_result must therefore encoded likewise.
-            expected_result = build_expected_rss_result(feed, 
EXPECTED_RESULT_RSS, ENCODING)
-        # The different result types of Python 2 (str=bytes) and Python 3
-        # (str=text=unicode) stems from a different implementation of StringIO.
-        # As I understand it, getvalue() in Python 2 returns the type you
-        # originally wrote into the buffer. In Python 3 getvalue() always
-        # returns a str (=text=unicode).
-        # See other test: test_stringio.py
-        #print type(result), type(expected_result)
+        # On Python 3, result of feedgenerator is a unicode string!
+        # So do not encode our expected_result.
+        expected_result = build_expected_rss_result(feed, EXPECTED_RESULT_RSS, 
None)
         self.assertEqual(type(result), type(expected_result))
         self.assertEqual(result, expected_result)
 
@@ -111,20 +93,48 @@
         feed = feedgenerator.Atom1Feed(**FIXT_FEED)
         feed.add_item(**FIXT_ITEM)
         result = feed.writeString(ENCODING)
-        if six.PY3:
-            # On Python 3, result of feedgenerator is a unicode string!
-            # So do not encode our expected_result.
-            expected_result = build_expected_atom_result(feed, 
EXPECTED_RESULT_ATOM, None)
-        else:
-            # On Python 2, result of feedgenerator is a str string!
-            # Expected_result must therefore encoded likewise.
-            expected_result = build_expected_atom_result(feed, 
EXPECTED_RESULT_ATOM, ENCODING)
-        # The different result types of Python 2 (str=bytes) and Python 3
-        # (str=text=unicode) stems from a different implementation of StringIO.
-        # As I understand it, getvalue() in Python 2 returns the type you
-        # originally wrote into the buffer. In Python 3 getvalue() always
-        # returns a str (=text=unicode).
-        # See other test: test_stringio.py
-        #print type(result), type(expected_result)
+        # On Python 3, result of feedgenerator is a unicode string!
+        # So do not encode our expected_result.
+        expected_result = build_expected_atom_result(feed, 
EXPECTED_RESULT_ATOM, None)
         self.assertEqual(type(result), type(expected_result))
         self.assertEqual(result, expected_result)
+
+
[email protected]("description, subtitle, fragment, nonfragment", [
+    # Neither description nor subtitle are provided
+    (None, None, None, "<subtitle></subtitle>"),
+    ("", "", None, "<subtitle></subtitle>"),
+    # Description is provided
+    ("description", None, "<subtitle>description</subtitle>", None),
+    ("description", "", "<subtitle>description</subtitle>", None),
+    # Subtitle is provided
+    (None, "subtitle", "<subtitle>subtitle</subtitle>", None),
+    ("", "subtitle", "<subtitle>subtitle</subtitle>", None),
+    # Both description & subtitle are provided; subtitle takes precedence
+    ("description", "subtitle", "<subtitle>subtitle</subtitle>", 
"<subtitle>description</subtitle>"),
+])
+def test_subtitle(description, subtitle, fragment, nonfragment):
+    """Test regression for 
https://github.com/getpelican/feedgenerator/issues/30.
+
+    We test against all four possible combinations of description x
+    subtitle parameters and additionally for None and "".
+
+    description, subtitle are the values for the respective
+    feed-parameters.
+
+    fragment and nonfragment are text fragments that should be in the
+    expected result or not.
+
+    """
+    FIXT_FEED = dict(
+        title="title",
+        link="https://example.com";,
+        description=description,
+        subtitle=subtitle,
+    )
+    feed = feedgenerator.Atom1Feed(**FIXT_FEED)
+    result = feed.writeString(ENCODING)
+    if fragment:
+        assert fragment in result
+    if nonfragment:
+        assert nonfragment not in result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/tests_feedgenerator/test_stringio.py 
new/feedgenerator-2.0.0/tests_feedgenerator/test_stringio.py
--- old/feedgenerator-1.9.2/tests_feedgenerator/test_stringio.py        
2020-02-09 09:40:59.000000000 +0100
+++ new/feedgenerator-2.0.0/tests_feedgenerator/test_stringio.py        
2021-09-28 13:03:34.000000000 +0200
@@ -1,14 +1,6 @@
-# -*- encoding: utf-8 -*-
+import unittest
 
-from __future__ import unicode_literals, print_function
-
-try:
-    import unittest2 as unittest
-except ImportError:
-    import unittest
-
-import six
-from six import StringIO
+from io import StringIO
 
 ENCODING = 'utf-8'
 
@@ -22,62 +14,51 @@
     def test_001_text(self):
         # If we throw unicode into the StringIO buffer, we'll
         # get unicode out of it.
-        # Thank god this is the same in Python 2 and 3.
-        self.assertEqual(type(S0), six.text_type)
+        self.assertEqual(type(S0), str)
         buf = StringIO()
         print(S0, file=buf, end="")
         s1 = buf.getvalue()
         self.assertEqual(type(S0), type(s1))
         self.assertEqual(S0, s1)
-        self.assertEqual(type(s1), six.text_type)
+        self.assertEqual(type(s1), str)
 
     def test_002_bytes(self):
         buf = StringIO()
         print(S0_BYTES, file=buf, end="")
         s1 = buf.getvalue()
-        
-        if six.PY3:
-            # In Python 3 StringIO *ALWAYS* returns str (=text=unicode) !
-            # Even if we originally write bytes into the buffer, the value
-            # we get out of it has type str!
-
-            # Input is bytes
-            self.assertEqual(type(S0_BYTES), bytes)
-            # Output is NOT bytes...
-            self.assertNotEqual(type(S0_BYTES), type(s1))
-            self.assertNotEqual(type(s1), bytes)
-            # ...but str!
-            self.assertEqual(type(s1), str)
-            # So the contents are not equal!
-            self.assertNotEqual(S0_BYTES, s1)
-            # StringIO coerced bytes into str:
-            # b'xyz' ---> "b'xyz'"
-            self.assertEqual(str(S0_BYTES), s1)
-            # See, the type info is literally present in the output str!
-            self.assertEqual("b'" + str(S0_BYTES, encoding=ENCODING) + "'", s1)
-            # Coercion is NOT decoding!
-            self.assertNotEqual(S0_BYTES.decode(ENCODING), s1)
-            self.assertNotEqual(str(S0_BYTES, encoding=ENCODING), s1)
-            # These are the same
-            self.assertEqual(S0_BYTES.decode(ENCODING), 
-                str(S0_BYTES, encoding=ENCODING))
-            # Additional note:
-            # If we do not specify an encoding when we create a StringIO
-            # buffer, Python 3 automatically uses the locale's preferred
-            # encoding: locale.getpreferredencoding()
-            # Cf. 
http://docs.python.org/release/3.0.1/library/io.html#io.TextIOWrapper
-            # In my case this is the same encoding as the encoding of this 
source file,
-            # namely UTF-8. If on your system both encodings are different, 
you may 
-            # encounter other results than the above.
-            #
-            # In Python 3.2 the signature of StringIO() has changed. It is no 
more
-            # possible to specify an encoding here.
-        else:
-            # In Python 2 StringIO returns the type that we originally
-            # wrote into the buffer.
-            # Here we see that if we write bytes into the buffer, we'll get
-            # bytes out of it.
-            self.assertEqual(type(S0_BYTES), str)
-            self.assertEqual(type(S0_BYTES), type(s1))
-            self.assertEqual(type(s1), str)
-            self.assertEqual(S0_BYTES, s1)
+
+        # In Python 3 StringIO *ALWAYS* returns str (=text=unicode) !
+        # Even if we originally write bytes into the buffer, the value
+        # we get out of it has type str!
+
+        # Input is bytes
+        self.assertEqual(type(S0_BYTES), bytes)
+        # Output is NOT bytes...
+        self.assertNotEqual(type(S0_BYTES), type(s1))
+        self.assertNotEqual(type(s1), bytes)
+        # ...but str!
+        self.assertEqual(type(s1), str)
+        # So the contents are not equal!
+        self.assertNotEqual(S0_BYTES, s1)
+        # StringIO coerced bytes into str:
+        # b'xyz' ---> "b'xyz'"
+        self.assertEqual(str(S0_BYTES), s1)
+        # See, the type info is literally present in the output str!
+        self.assertEqual("b'" + str(S0_BYTES, encoding=ENCODING) + "'", s1)
+        # Coercion is NOT decoding!
+        self.assertNotEqual(S0_BYTES.decode(ENCODING), s1)
+        self.assertNotEqual(str(S0_BYTES, encoding=ENCODING), s1)
+        # These are the same
+        self.assertEqual(S0_BYTES.decode(ENCODING),
+            str(S0_BYTES, encoding=ENCODING))
+        # Additional note:
+        # If we do not specify an encoding when we create a StringIO
+        # buffer, Python 3 automatically uses the locale's preferred
+        # encoding: locale.getpreferredencoding()
+        # Cf. 
http://docs.python.org/release/3.0.1/library/io.html#io.TextIOWrapper
+        # In my case this is the same encoding as the encoding of this source 
file,
+        # namely UTF-8. If on your system both encodings are different, you may
+        # encounter other results than the above.
+        #
+        # In Python 3.2 the signature of StringIO() has changed. It is no more
+        # possible to specify an encoding here.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/feedgenerator-1.9.2/tests_feedgenerator/usage_example.py 
new/feedgenerator-2.0.0/tests_feedgenerator/usage_example.py
--- old/feedgenerator-1.9.2/tests_feedgenerator/usage_example.py        
2020-02-09 09:40:59.000000000 +0100
+++ new/feedgenerator-2.0.0/tests_feedgenerator/usage_example.py        
2021-09-28 13:03:34.000000000 +0200
@@ -1,10 +1,5 @@
-# -*- encoding: utf-8 -*-
-
-from __future__ import unicode_literals
-
 import os
 import tempfile
-import six
 import feedgenerator
 
 feed = feedgenerator.Rss201rev2Feed(
@@ -23,10 +18,7 @@
     description="Testing."
 )
 
-if six.PY3:
-    FN_PREFIX = 'feed_py3-'
-else:
-    FN_PREFIX = 'feed_py2-'
+FN_PREFIX = 'feed_py3-'
 
 # Usage example in feedgenerator docs opens the file in text mode, not binary.
 # So we do this here likewise.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/feedgenerator-1.9.2/tox.ini 
new/feedgenerator-2.0.0/tox.ini
--- old/feedgenerator-1.9.2/tox.ini     2021-08-18 10:31:05.000000000 +0200
+++ new/feedgenerator-2.0.0/tox.ini     2021-09-28 13:03:34.000000000 +0200
@@ -12,3 +12,4 @@
     pytest
 deps =
     pytest
+    pytest-cov

Reply via email to