summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastian Venthur <bastian.venthur@flixbus.com>2021-08-18 12:27:08 +0200
committerGitHub <noreply@github.com>2021-08-18 12:27:08 +0200
commit5e9e1af94ef810336360ff83872f36ae61465dbc (patch)
tree04a7d1abf131e8d4814683494ff2939f97b04ea1
parent4b9a12c9e30b69fc8c0fc05b126950ef1a64ae6c (diff)
downloadfeedgenerator-5e9e1af94ef810336360ff83872f36ae61465dbc.tar.gz
Remove Python 2 (#27)
* removed __future__ imports and explicit encodings * removed six dependency and code * fixed py2/3 specific imports * removed python2 specific code * don't mention unittest2 anymore
-rw-r--r--feedgenerator/django/utils/encoding.py89
-rw-r--r--feedgenerator/django/utils/feedgenerator.py14
-rw-r--r--feedgenerator/django/utils/functional.py64
-rw-r--r--feedgenerator/django/utils/six.py370
-rw-r--r--feedgenerator/django/utils/timezone.py18
-rw-r--r--feedgenerator/django/utils/xmlutils.py4
-rw-r--r--setup.py3
-rw-r--r--tests_feedgenerator/test_feedgenerator.py48
-rw-r--r--tests_feedgenerator/test_stringio.py97
-rw-r--r--tests_feedgenerator/usage_example.py10
10 files changed, 87 insertions, 630 deletions
diff --git a/feedgenerator/django/utils/encoding.py b/feedgenerator/django/utils/encoding.py
index f13412d..ce8334e 100644
--- a/feedgenerator/django/utils/encoding.py
+++ b/feedgenerator/django/utils/encoding.py
@@ -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):
@@ -23,42 +16,6 @@ class DjangoUnicodeDecodeError(UnicodeDecodeError):
return '%s. You passed in %r (%s)' % (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 @@ def is_protected_type(obj):
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 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
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 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
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 @@ def force_bytes(s, encoding='utf-8', strings_only=False, errors='strict'):
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 @@ def force_bytes(s, encoding='utf-8', strings_only=False, errors='strict'):
# 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 --git a/feedgenerator/django/utils/feedgenerator.py b/feedgenerator/django/utils/feedgenerator.py
index 8158d2a..bf33848 100644
--- a/feedgenerator/django/utils/feedgenerator.py
+++ b/feedgenerator/django/utils/feedgenerator.py
@@ -21,18 +21,12 @@ Sample usage:
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):
@@ -46,8 +40,6 @@ def rfc2822_date(date):
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')
if is_aware(date):
offset = date.tzinfo.utcoffset(date)
timezone = (offset.days * 24 * 60) + (offset.seconds // 60)
@@ -60,8 +52,6 @@ def rfc3339_date(date):
# 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)
diff --git a/feedgenerator/django/utils/functional.py b/feedgenerator/django/utils/functional.py
index 8d8f759..ba4d586 100644
--- a/feedgenerator/django/utils/functional.py
+++ b/feedgenerator/django/utils/functional.py
@@ -3,8 +3,6 @@ import operator
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.
@@ -94,18 +92,12 @@ def lazy(func, *resultclasses):
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 @@ def lazy(func, *resultclasses):
__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 @@ def allow_lazy(func, *resultclasses):
"""
@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:
@@ -266,12 +256,8 @@ class SimpleLazyObject(LazyObject):
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 @@ def partition(predicate, values):
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 --git a/feedgenerator/django/utils/six.py b/feedgenerator/django/utils/six.py
deleted file mode 100644
index 767fe0b..0000000
--- a/feedgenerator/django/utils/six.py
+++ /dev/null
@@ -1,370 +0,0 @@
-"""Utilities for writing code that runs on Python 2 and 3"""
-
-import operator
-import sys
-import types
-
-__author__ = "Benjamin Peterson <benjamin@python.org>"
-__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 --git a/feedgenerator/django/utils/timezone.py b/feedgenerator/django/utils/timezone.py
index c125487..3ad8517 100644
--- a/feedgenerator/django/utils/timezone.py
+++ b/feedgenerator/django/utils/timezone.py
@@ -13,8 +13,6 @@ except ImportError:
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 @@ utc = pytz.utc if pytz else UTC()
# ### # 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 @@ def activate(timezone):
"""
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)
@@ -205,14 +203,14 @@ class override(object):
# ### # 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 --git a/feedgenerator/django/utils/xmlutils.py b/feedgenerator/django/utils/xmlutils.py
index fc1be2b..d234708 100644
--- a/feedgenerator/django/utils/xmlutils.py
+++ b/feedgenerator/django/utils/xmlutils.py
@@ -2,8 +2,6 @@
Utilities for XML generation/parsing.
"""
-import six
-
from xml.sax.saxutils import XMLGenerator, quoteattr
class SimplerXMLGenerator(XMLGenerator):
@@ -20,4 +18,4 @@ class SimplerXMLGenerator(XMLGenerator):
# 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(str('>'))
diff --git a/setup.py b/setup.py
index 8ba6981..67b9a5d 100644
--- a/setup.py
+++ b/setup.py
@@ -39,7 +39,7 @@ VERSION = '1.9.2'
TEST_SUITE = 'tests_feedgenerator'
-REQUIRES = ['pytz >= 0a', 'six']
+REQUIRES = ['pytz >= 0a']
setup(
name=NAME,
@@ -47,6 +47,7 @@ setup(
packages=PACKAGES,
test_suite=TEST_SUITE,
install_requires=REQUIRES,
+ python_requires='>=3.6',
# metadata for upload to PyPI
author=AUTHOR,
author_email=AUTHOR_EMAIL,
diff --git a/tests_feedgenerator/test_feedgenerator.py b/tests_feedgenerator/test_feedgenerator.py
index 6399f9d..6ec28aa 100644
--- a/tests_feedgenerator/test_feedgenerator.py
+++ b/tests_feedgenerator/test_feedgenerator.py
@@ -1,13 +1,5 @@
-# -*- 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
@@ -73,7 +65,7 @@ class TestFeedGenerator(unittest.TestCase):
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 +80,9 @@ class TestFeedGenerator(unittest.TestCase):
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 +91,8 @@ class TestFeedGenerator(unittest.TestCase):
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)
diff --git a/tests_feedgenerator/test_stringio.py b/tests_feedgenerator/test_stringio.py
index 6689c2a..3791035 100644
--- a/tests_feedgenerator/test_stringio.py
+++ b/tests_feedgenerator/test_stringio.py
@@ -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 @@ class TestStringIO(unittest.TestCase):
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 --git a/tests_feedgenerator/usage_example.py b/tests_feedgenerator/usage_example.py
index 69f258b..043f8ce 100644
--- a/tests_feedgenerator/usage_example.py
+++ b/tests_feedgenerator/usage_example.py
@@ -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 @@ feed.add_item(
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.