Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 691870 Details for
Bug 906160
Review Request: python-feedgenerator - Standalone version of django.utils.feedgenerator
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Changes between python-feedgenerator and DJango's feed generator system-wide
feedgenerator-changes.patch (text/plain), 52.31 KB, created by
Eduardo Echeverria
on 2013-02-02 04:49:29 UTC
(
hide
)
Description:
Changes between python-feedgenerator and DJango's feed generator system-wide
Filename:
MIME Type:
Creator:
Eduardo Echeverria
Created:
2013-02-02 04:49:29 UTC
Size:
52.31 KB
patch
obsolete
>diff -urP utils-orig/encoding.py utils/encoding.py >--- utils-orig/encoding.py 2013-01-31 02:47:46.906321993 -0430 >+++ utils/encoding.py 2013-01-08 18:24:48.000000000 -0430 >@@ -1,11 +1,17 @@ >-import types >-import urllib >-import locale >-import datetime >+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 django.utils.functional import Promise >+from .functional import Promise >+from . import six > > class DjangoUnicodeDecodeError(UnicodeDecodeError): > def __init__(self, obj, *args): >@@ -19,59 +25,87 @@ > > class StrAndUnicode(object): > """ >- A class whose __str__ returns its __unicode__ as a UTF-8 bytestring. >+ 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. >+ 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 __str__(self): >- return self.__unicode__().encode('utf-8') >+ 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 smart_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): >+def python_2_unicode_compatible(klass): > """ >- Returns a unicode object representing 's'. Treats bytestrings using the >- 'encoding' codec. >+ 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 >+ Python 3. Treats bytestrings using the 'encoding' codec. > > If strings_only is True, don't convert (some) non-string-like objects. > """ > if isinstance(s, Promise): > # The input is the result of a gettext_lazy() call. > return s >- return force_unicode(s, encoding, strings_only, errors) >+ return force_text(s, encoding, strings_only, errors) > > def is_protected_type(obj): > """Determine if the object instance is of a protected type. > > Objects of protected types are preserved as-is when passed to >- force_unicode(strings_only=True). >+ force_text(strings_only=True). > """ >- return isinstance(obj, ( >- types.NoneType, >- int, long, >- datetime.datetime, datetime.date, datetime.time, >- float, Decimal) >- ) >+ return isinstance(obj, six.integer_types + (type(None), float, Decimal, >+ datetime.datetime, datetime.date, datetime.time)) > >-def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): >+def force_text(s, encoding='utf-8', strings_only=False, errors='strict'): > """ >- Similar to smart_unicode, except that lazy instances are resolved to >+ Similar to smart_text, except that lazy instances are resolved to > strings, rather than kept as lazy objects. > > If strings_only is True, don't convert (some) non-string-like objects. > """ >- # Handle the common case first, saves 30-40% in performance when s >- # is an instance of unicode. This function gets called often in that >- # setting. >- if isinstance(s, unicode): >+ # 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): > return s > if strings_only and is_protected_type(s): > return s > try: >- if not isinstance(s, basestring,): >+ if not isinstance(s, six.string_types): > if hasattr(s, '__unicode__'): >- s = unicode(s) >+ s = s.__unicode__() > else: > try: >- s = unicode(str(s), encoding, errors) >+ if six.PY3: >+ if isinstance(s, bytes): >+ s = six.text_type(s, encoding, errors) >+ else: >+ s = six.text_type(s) >+ else: >+ s = six.text_type(bytes(s), encoding, errors) > except UnicodeEncodeError: > if not isinstance(s, Exception): > raise >@@ -81,14 +115,14 @@ > # without raising a further exception. We do an > # approximation to what the Exception's standard str() > # output should be. >- s = u' '.join([force_unicode(arg, encoding, strings_only, >+ s = ' '.join([force_text(arg, encoding, strings_only, > errors) for arg in s]) >- elif not isinstance(s, unicode): >- # Note: We use .decode() here, instead of unicode(s, encoding, >- # errors), so that if s is a SafeString, it ends up being a >- # SafeUnicode at the end. >+ else: >+ # Note: We use .decode() here, instead of six.text_type(s, encoding, >+ # errors), so that if s is a SafeBytes, it ends up being a >+ # SafeText at the end. > s = s.decode(encoding, errors) >- except UnicodeDecodeError, e: >+ except UnicodeDecodeError as e: > if not isinstance(s, Exception): > raise DjangoUnicodeDecodeError(s, *e.args) > else: >@@ -97,37 +131,74 @@ > # working unicode method. Try to handle this without raising a > # further exception by individually forcing the exception args > # to unicode. >- s = u' '.join([force_unicode(arg, encoding, strings_only, >+ s = ' '.join([force_text(arg, encoding, strings_only, > errors) for arg in s]) > return s > >-def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): >+def smart_bytes(s, encoding='utf-8', strings_only=False, errors='strict'): > """ > Returns a bytestring version of 's', encoded as specified in 'encoding'. > > If strings_only is True, don't convert (some) non-string-like objects. > """ >- if strings_only and isinstance(s, (types.NoneType, int)): >+ if isinstance(s, Promise): >+ # The input is the result of a gettext_lazy() call. >+ return s >+ return force_bytes(s, encoding, strings_only, errors) >+ >+ >+def force_bytes(s, encoding='utf-8', strings_only=False, errors='strict'): >+ """ >+ Similar to smart_bytes, except that lazy instances are resolved to >+ strings, rather than kept as lazy objects. >+ >+ If strings_only is True, don't convert (some) non-string-like objects. >+ """ >+ if isinstance(s, bytes): >+ if encoding == 'utf-8': >+ return s >+ else: >+ return s.decode('utf-8', errors).encode(encoding, errors) >+ if strings_only and (s is None or isinstance(s, int)): > return s > if isinstance(s, Promise): >- return unicode(s).encode(encoding, errors) >- elif not isinstance(s, basestring): >+ return six.text_type(s).encode(encoding, errors) >+ if not isinstance(s, six.string_types): > try: >- return str(s) >+ if six.PY3: >+ return six.text_type(s).encode(encoding) >+ else: >+ return bytes(s) > except UnicodeEncodeError: > if isinstance(s, Exception): > # An Exception subclass containing non-ASCII data that doesn't > # know how to print itself properly. We shouldn't raise a > # further exception. >- return ' '.join([smart_str(arg, encoding, strings_only, >+ return ' '.join([smart_bytes(arg, encoding, strings_only, > errors) for arg in s]) >- return unicode(s).encode(encoding, errors) >- elif isinstance(s, unicode): >- return s.encode(encoding, errors) >- elif s and encoding != 'utf-8': >- return s.decode('utf-8', errors).encode(encoding, errors) >+ return six.text_type(s).encode(encoding, errors) > else: >- return s >+ 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.__doc__ = """\ >+Apply smart_text in Python 3 and smart_bytes in Python 2. >+ >+This is suitable for writing to sys.stdout (for instance). >+""" >+ >+force_str.__doc__ = """\ >+Apply force_text in Python 3 and force_bytes in Python 2. >+""" > > def iri_to_uri(iri): > """ >@@ -154,7 +225,7 @@ > # converted. > if iri is None: > return iri >- return urllib.quote(smart_str(iri), safe="/#%[]=:;$&()+,!?*@'~") >+ return quote(smart_bytes(iri), safe=b"/#%[]=:;$&()+,!?*@'~") > > def filepath_to_uri(path): > """Convert an file system path to a URI portion that is suitable for >@@ -173,7 +244,7 @@ > return path > # I know about `os.sep` and `os.altsep` but I want to leave > # some flexibility for hardcoding separators. >- return urllib.quote(smart_str(path).replace("\\", "/"), safe="/~!*()'") >+ return quote(smart_bytes(path.replace("\\", "/")), safe=b"/~!*()'") > > # The encoding of the default system locale but falls back to the > # given fallback encoding if the encoding is unsupported by python or could >@@ -183,15 +254,3 @@ > codecs.lookup(DEFAULT_LOCALE_ENCODING) > except: > DEFAULT_LOCALE_ENCODING = 'ascii' >- >-# Forwards compatibility with Django 1.5 >- >-def python_2_unicode_compatible(klass): >- # Always use the Python 2 branch of the decorator here in Django 1.4 >- klass.__unicode__ = klass.__str__ >- klass.__str__ = lambda self: self.__unicode__().encode('utf-8') >- return klass >- >-smart_text = smart_unicode >-force_text = force_unicode >-smart_bytes = smart_str >diff -urP utils-orig/feedgenerator.py utils/feedgenerator.py >--- utils-orig/feedgenerator.py 2013-01-31 02:47:12.371319992 -0430 >+++ utils/feedgenerator.py 2013-01-08 18:24:48.000000000 -0430 >@@ -5,30 +5,35 @@ > > >>> from django.utils import feedgenerator > >>> feed = feedgenerator.Rss201rev2Feed( >-... title=u"Poynter E-Media Tidbits", >-... link=u"http://www.poynter.org/column.asp?id=31", >-... description=u"A group Weblog by the sharpest minds in online media/journalism/publishing.", >-... language=u"en", >+... title="Poynter E-Media Tidbits", >+... link="http://www.poynter.org/column.asp?id=31", >+... description="A group Weblog by the sharpest minds in online media/journalism/publishing.", >+... language="en", > ... ) > >>> feed.add_item( > ... title="Hello", >-... link=u"http://www.holovaty.com/test/", >+... link="http://www.holovaty.com/test/", > ... description="Testing." > ... ) >->>> fp = open('test.rss', 'w') >->>> feed.write(fp, 'utf-8') >->>> fp.close() >+>>> with open('test.rss', 'w') as fp: >+... feed.write(fp, 'utf-8') > > For definitions of the different versions of RSS, see: >-http://diveintomark.org/archives/2004/02/04/incompatible-rss >+http://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004/02/04/incompatible-rss > """ >+from __future__ import unicode_literals > > import datetime >-import urlparse >-from django.utils.xmlutils import SimplerXMLGenerator >-from django.utils.encoding import force_unicode, iri_to_uri >-from django.utils import datetime_safe >-from django.utils.timezone import is_aware >+try: >+ from urllib.parse import urlparse >+except ImportError: # Python 2 >+ from urlparse 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 .timezone import is_aware > > def rfc2822_date(date): > # We can't use strftime() because it produces locale-dependant results, so >@@ -41,49 +46,53 @@ > 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) > hour, minute = divmod(timezone, 60) >- return time_str + "%+03d%02d" % (hour, minute) >+ return time_str + '%+03d%02d' % (hour, minute) > else: > return time_str + '-0000' > > 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): >- time_str = date.strftime('%Y-%m-%dT%H:%M:%S') > offset = date.tzinfo.utcoffset(date) > timezone = (offset.days * 24 * 60) + (offset.seconds // 60) > hour, minute = divmod(timezone, 60) >- return time_str + "%+03d:%02d" % (hour, minute) >+ return time_str + '%+03d:%02d' % (hour, minute) > else: >- return date.strftime('%Y-%m-%dT%H:%M:%SZ') >+ return time_str + 'Z' > > def get_tag_uri(url, date): > """ > Creates a TagURI. > >- See http://diveintomark.org/archives/2004/05/28/howto-atom-id >+ See http://web.archive.org/web/20110514113830/http://diveintomark.org/archives/2004/05/28/howto-atom-id > """ >- bits = urlparse.urlparse(url) >+ bits = urlparse(url) > d = '' > if date is not None: > d = ',%s' % datetime_safe.new_datetime(date).strftime('%Y-%m-%d') >- return u'tag:%s%s:%s/%s' % (bits.hostname, d, bits.path, bits.fragment) >+ return 'tag:%s%s:%s/%s' % (bits.hostname, d, bits.path, bits.fragment) > > class SyndicationFeed(object): > "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): >- to_unicode = lambda s: force_unicode(s, strings_only=True) >+ to_unicode = lambda s: force_text(s, strings_only=True) > if categories: >- categories = [force_unicode(c) for c in categories] >+ categories = [force_text(c) for c in categories] > if ttl is not None: > # Force ints to unicode >- ttl = force_unicode(ttl) >+ ttl = force_text(ttl) > self.feed = { > 'title': to_unicode(title), > 'link': iri_to_uri(link), >@@ -111,12 +120,12 @@ > objects except pubdate, which is a datetime.datetime object, and > enclosure, which is an instance of the Enclosure class. > """ >- to_unicode = lambda s: force_unicode(s, strings_only=True) >+ to_unicode = lambda s: force_text(s, strings_only=True) > if categories: > categories = [to_unicode(c) for c in categories] > if ttl is not None: > # Force ints to unicode >- ttl = force_unicode(ttl) >+ ttl = force_text(ttl) > item = { > 'title': to_unicode(title), > 'link': iri_to_uri(link), >@@ -175,7 +184,6 @@ > """ > Returns the feed in the given encoding as a string. > """ >- from StringIO import StringIO > s = StringIO() > self.write(s, encoding) > return s.getvalue() >@@ -204,177 +212,177 @@ > def write(self, outfile, encoding): > handler = SimplerXMLGenerator(outfile, encoding) > handler.startDocument() >- handler.startElement(u"rss", self.rss_attributes()) >- handler.startElement(u"channel", self.root_attributes()) >+ handler.startElement("rss", self.rss_attributes()) >+ handler.startElement("channel", self.root_attributes()) > self.add_root_elements(handler) > self.write_items(handler) > self.endChannelElement(handler) >- handler.endElement(u"rss") >+ handler.endElement("rss") > > def rss_attributes(self): >- return {u"version": self._version, >- u"xmlns:atom": u"http://www.w3.org/2005/Atom"} >+ return {"version": self._version, >+ "xmlns:atom": "http://www.w3.org/2005/Atom"} > > def write_items(self, handler): > for item in self.items: >- handler.startElement(u'item', self.item_attributes(item)) >+ handler.startElement('item', self.item_attributes(item)) > self.add_item_elements(handler, item) >- handler.endElement(u"item") >+ handler.endElement("item") > > def add_root_elements(self, handler): >- handler.addQuickElement(u"title", self.feed['title']) >- handler.addQuickElement(u"link", self.feed['link']) >- handler.addQuickElement(u"description", self.feed['description']) >+ handler.addQuickElement("title", self.feed['title']) >+ handler.addQuickElement("link", self.feed['link']) >+ handler.addQuickElement("description", self.feed['description']) > if self.feed['feed_url'] is not None: >- handler.addQuickElement(u"atom:link", None, >- {u"rel": u"self", u"href": self.feed['feed_url']}) >+ handler.addQuickElement("atom:link", None, >+ {"rel": "self", "href": self.feed['feed_url']}) > if self.feed['language'] is not None: >- handler.addQuickElement(u"language", self.feed['language']) >+ handler.addQuickElement("language", self.feed['language']) > for cat in self.feed['categories']: >- handler.addQuickElement(u"category", cat) >+ handler.addQuickElement("category", cat) > if self.feed['feed_copyright'] is not None: >- handler.addQuickElement(u"copyright", self.feed['feed_copyright']) >- handler.addQuickElement(u"lastBuildDate", rfc2822_date(self.latest_post_date()).decode('utf-8')) >+ handler.addQuickElement("copyright", self.feed['feed_copyright']) >+ handler.addQuickElement("lastBuildDate", rfc2822_date(self.latest_post_date())) > if self.feed['ttl'] is not None: >- handler.addQuickElement(u"ttl", self.feed['ttl']) >+ handler.addQuickElement("ttl", self.feed['ttl']) > > def endChannelElement(self, handler): >- handler.endElement(u"channel") >+ handler.endElement("channel") > > class RssUserland091Feed(RssFeed): >- _version = u"0.91" >+ _version = "0.91" > def add_item_elements(self, handler, item): >- handler.addQuickElement(u"title", item['title']) >- handler.addQuickElement(u"link", item['link']) >+ handler.addQuickElement("title", item['title']) >+ handler.addQuickElement("link", item['link']) > if item['description'] is not None: >- handler.addQuickElement(u"description", item['description']) >+ handler.addQuickElement("description", item['description']) > > class Rss201rev2Feed(RssFeed): > # Spec: http://blogs.law.harvard.edu/tech/rss >- _version = u"2.0" >+ _version = "2.0" > def add_item_elements(self, handler, item): >- handler.addQuickElement(u"title", item['title']) >- handler.addQuickElement(u"link", item['link']) >+ handler.addQuickElement("title", item['title']) >+ handler.addQuickElement("link", item['link']) > if item['description'] is not None: >- handler.addQuickElement(u"description", item['description']) >+ handler.addQuickElement("description", item['description']) > > # Author information. > if item["author_name"] and item["author_email"]: >- handler.addQuickElement(u"author", "%s (%s)" % \ >+ handler.addQuickElement("author", "%s (%s)" % \ > (item['author_email'], item['author_name'])) > elif item["author_email"]: >- handler.addQuickElement(u"author", item["author_email"]) >+ handler.addQuickElement("author", item["author_email"]) > elif item["author_name"]: >- handler.addQuickElement(u"dc:creator", item["author_name"], {u"xmlns:dc": u"http://purl.org/dc/elements/1.1/"}) >+ handler.addQuickElement("dc:creator", item["author_name"], {"xmlns:dc": "http://purl.org/dc/elements/1.1/"}) > > if item['pubdate'] is not None: >- handler.addQuickElement(u"pubDate", rfc2822_date(item['pubdate']).decode('utf-8')) >+ handler.addQuickElement("pubDate", rfc2822_date(item['pubdate'])) > if item['comments'] is not None: >- handler.addQuickElement(u"comments", item['comments']) >+ handler.addQuickElement("comments", item['comments']) > if item['unique_id'] is not None: >- handler.addQuickElement(u"guid", item['unique_id']) >+ handler.addQuickElement("guid", item['unique_id']) > if item['ttl'] is not None: >- handler.addQuickElement(u"ttl", item['ttl']) >+ handler.addQuickElement("ttl", item['ttl']) > > # Enclosure. > if item['enclosure'] is not None: >- handler.addQuickElement(u"enclosure", '', >- {u"url": item['enclosure'].url, u"length": item['enclosure'].length, >- u"type": item['enclosure'].mime_type}) >+ handler.addQuickElement("enclosure", '', >+ {"url": item['enclosure'].url, "length": item['enclosure'].length, >+ "type": item['enclosure'].mime_type}) > > # Categories. > for cat in item['categories']: >- handler.addQuickElement(u"category", cat) >+ handler.addQuickElement("category", cat) > > class Atom1Feed(SyndicationFeed): > # Spec: http://atompub.org/2005/07/11/draft-ietf-atompub-format-10.html > mime_type = 'application/atom+xml; charset=utf-8' >- ns = u"http://www.w3.org/2005/Atom" >+ ns = "http://www.w3.org/2005/Atom" > > def write(self, outfile, encoding): > handler = SimplerXMLGenerator(outfile, encoding) > handler.startDocument() >- handler.startElement(u'feed', self.root_attributes()) >+ handler.startElement('feed', self.root_attributes()) > self.add_root_elements(handler) > self.write_items(handler) >- handler.endElement(u"feed") >+ handler.endElement("feed") > > def root_attributes(self): > if self.feed['language'] is not None: >- return {u"xmlns": self.ns, u"xml:lang": self.feed['language']} >+ return {"xmlns": self.ns, "xml:lang": self.feed['language']} > else: >- return {u"xmlns": self.ns} >+ return {"xmlns": self.ns} > > def add_root_elements(self, handler): >- handler.addQuickElement(u"title", self.feed['title']) >- handler.addQuickElement(u"link", "", {u"rel": u"alternate", u"href": self.feed['link']}) >+ handler.addQuickElement("title", self.feed['title']) >+ handler.addQuickElement("link", "", {"rel": "alternate", "href": self.feed['link']}) > if self.feed['feed_url'] is not None: >- handler.addQuickElement(u"link", "", {u"rel": u"self", u"href": self.feed['feed_url']}) >- handler.addQuickElement(u"id", self.feed['id']) >- handler.addQuickElement(u"updated", rfc3339_date(self.latest_post_date()).decode('utf-8')) >+ handler.addQuickElement("link", "", {"rel": "self", "href": self.feed['feed_url']}) >+ handler.addQuickElement("id", self.feed['id']) >+ handler.addQuickElement("updated", rfc3339_date(self.latest_post_date())) > if self.feed['author_name'] is not None: >- handler.startElement(u"author", {}) >- handler.addQuickElement(u"name", self.feed['author_name']) >+ handler.startElement("author", {}) >+ handler.addQuickElement("name", self.feed['author_name']) > if self.feed['author_email'] is not None: >- handler.addQuickElement(u"email", self.feed['author_email']) >+ handler.addQuickElement("email", self.feed['author_email']) > if self.feed['author_link'] is not None: >- handler.addQuickElement(u"uri", self.feed['author_link']) >- handler.endElement(u"author") >+ handler.addQuickElement("uri", self.feed['author_link']) >+ handler.endElement("author") > if self.feed['subtitle'] is not None: >- handler.addQuickElement(u"subtitle", self.feed['subtitle']) >+ handler.addQuickElement("subtitle", self.feed['subtitle']) > for cat in self.feed['categories']: >- handler.addQuickElement(u"category", "", {u"term": cat}) >+ handler.addQuickElement("category", "", {"term": cat}) > if self.feed['feed_copyright'] is not None: >- handler.addQuickElement(u"rights", self.feed['feed_copyright']) >+ handler.addQuickElement("rights", self.feed['feed_copyright']) > > def write_items(self, handler): > for item in self.items: >- handler.startElement(u"entry", self.item_attributes(item)) >+ handler.startElement("entry", self.item_attributes(item)) > self.add_item_elements(handler, item) >- handler.endElement(u"entry") >+ handler.endElement("entry") > > def add_item_elements(self, handler, item): >- handler.addQuickElement(u"title", item['title']) >- handler.addQuickElement(u"link", u"", {u"href": item['link'], u"rel": u"alternate"}) >+ handler.addQuickElement("title", item['title']) >+ handler.addQuickElement("link", "", {"href": item['link'], "rel": "alternate"}) > if item['pubdate'] is not None: >- handler.addQuickElement(u"updated", rfc3339_date(item['pubdate']).decode('utf-8')) >+ handler.addQuickElement("updated", rfc3339_date(item['pubdate'])) > > # Author information. > if item['author_name'] is not None: >- handler.startElement(u"author", {}) >- handler.addQuickElement(u"name", item['author_name']) >+ handler.startElement("author", {}) >+ handler.addQuickElement("name", item['author_name']) > if item['author_email'] is not None: >- handler.addQuickElement(u"email", item['author_email']) >+ handler.addQuickElement("email", item['author_email']) > if item['author_link'] is not None: >- handler.addQuickElement(u"uri", item['author_link']) >- handler.endElement(u"author") >+ handler.addQuickElement("uri", item['author_link']) >+ handler.endElement("author") > > # Unique ID. > if item['unique_id'] is not None: > unique_id = item['unique_id'] > else: > unique_id = get_tag_uri(item['link'], item['pubdate']) >- handler.addQuickElement(u"id", unique_id) >+ handler.addQuickElement("id", unique_id) > > # Summary. > if item['description'] is not None: >- handler.addQuickElement(u"summary", item['description'], {u"type": u"html"}) >+ handler.addQuickElement("summary", item['description'], {"type": "html"}) > > # Enclosure. > if item['enclosure'] is not None: >- handler.addQuickElement(u"link", '', >- {u"rel": u"enclosure", >- u"href": item['enclosure'].url, >- u"length": item['enclosure'].length, >- u"type": item['enclosure'].mime_type}) >+ handler.addQuickElement("link", '', >+ {"rel": "enclosure", >+ "href": item['enclosure'].url, >+ "length": item['enclosure'].length, >+ "type": item['enclosure'].mime_type}) > > # Categories. > for cat in item['categories']: >- handler.addQuickElement(u"category", u"", {u"term": cat}) >+ handler.addQuickElement("category", "", {"term": cat}) > > # Rights. > if item['item_copyright'] is not None: >- handler.addQuickElement(u"rights", item['item_copyright']) >+ handler.addQuickElement("rights", item['item_copyright']) > > # This isolates the decision of what the system default is, so calling code can > # do "feedgenerator.DefaultFeed" instead of "feedgenerator.Rss201rev2Feed". >diff -urP utils-orig/functional.py utils/functional.py >--- utils-orig/functional.py 2013-01-31 02:47:57.732322621 -0430 >+++ utils/functional.py 2013-01-08 18:24:48.000000000 -0430 >@@ -1,7 +1,9 @@ > import copy > 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) >@@ -57,6 +59,7 @@ > function is evaluated on every access. > """ > >+ @total_ordering > class __proxy__(Promise): > """ > Encapsulate a function call and act as a proxy for methods that are >@@ -90,13 +93,19 @@ > if hasattr(cls, k): > continue > setattr(cls, k, meth) >- cls._delegate_str = str in resultclasses >- cls._delegate_unicode = unicode in resultclasses >- assert not (cls._delegate_str and cls._delegate_unicode), "Cannot call lazy() with both str and unicode return types." >- if cls._delegate_unicode: >- cls.__unicode__ = cls.__unicode_cast >- elif cls._delegate_str: >- cls.__str__ = cls.__str_cast >+ cls._delegate_bytes = bytes in resultclasses >+ cls._delegate_text = six.text_type 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 >+ elif cls._delegate_bytes: >+ if six.PY3: >+ cls.__bytes__ = cls.__bytes_cast >+ else: >+ cls.__str__ = cls.__bytes_cast > __prepare_class__ = classmethod(__prepare_class__) > > def __promise__(cls, klass, funcname, method): >@@ -117,29 +126,37 @@ > return __wrapper__ > __promise__ = classmethod(__promise__) > >- def __unicode_cast(self): >+ def __text_cast(self): > return func(*self.__args, **self.__kw) > >- def __str_cast(self): >- return str(func(*self.__args, **self.__kw)) >+ def __bytes_cast(self): >+ return bytes(func(*self.__args, **self.__kw)) > >- def __cmp__(self, rhs): >- if self._delegate_str: >- s = str(func(*self.__args, **self.__kw)) >- elif self._delegate_unicode: >- s = unicode(func(*self.__args, **self.__kw)) >+ def __cast(self): >+ if self._delegate_bytes: >+ return self.__bytes_cast() >+ elif self._delegate_text: >+ return self.__text_cast() > else: >- s = func(*self.__args, **self.__kw) >- if isinstance(rhs, Promise): >- return -cmp(rhs, s) >- else: >- return cmp(s, rhs) >+ return func(*self.__args, **self.__kw) >+ >+ def __eq__(self, other): >+ if isinstance(other, Promise): >+ other = other.__cast() >+ return self.__cast() == other >+ >+ def __lt__(self, other): >+ if isinstance(other, Promise): >+ other = other.__cast() >+ return self.__cast() < other >+ >+ __hash__ = object.__hash__ > > def __mod__(self, rhs): >- if self._delegate_str: >- return str(self) % rhs >- elif self._delegate_unicode: >- return unicode(self) % rhs >+ if self._delegate_bytes and not six.PY3: >+ return bytes(self) % rhs >+ elif self._delegate_text: >+ return six.text_type(self) % rhs > else: > raise AssertionError('__mod__ not supported for non-string types') > >@@ -169,7 +186,7 @@ > """ > @wraps(func) > def wrapper(*args, **kwargs): >- for arg in list(args) + kwargs.values(): >+ for arg in list(args) + list(six.itervalues(kwargs)): > if isinstance(arg, Promise): > break > else: >@@ -221,10 +238,12 @@ > raise NotImplementedError > > # introspection support: >- __members__ = property(lambda self: self.__dir__()) > __dir__ = new_method_proxy(dir) > > >+# Workaround for http://bugs.python.org/issue12370 >+_super = super >+ > class SimpleLazyObject(LazyObject): > """ > A lazy object initialised from any function. >@@ -242,13 +261,17 @@ > value. > """ > self.__dict__['_setupfunc'] = func >- super(SimpleLazyObject, self).__init__() >+ _super(SimpleLazyObject, self).__init__() > > def _setup(self): > self._wrapped = self._setupfunc() > >- __str__ = new_method_proxy(str) >- __unicode__ = new_method_proxy(unicode) >+ if six.PY3: >+ __bytes__ = new_method_proxy(bytes) >+ __str__ = new_method_proxy(str) >+ else: >+ __str__ = new_method_proxy(str) >+ __unicode__ = new_method_proxy(unicode) > > def __deepcopy__(self, memo): > if self._wrapped is empty: >@@ -275,7 +298,8 @@ > __class__ = property(new_method_proxy(operator.attrgetter("__class__"))) > __eq__ = new_method_proxy(operator.eq) > __hash__ = new_method_proxy(hash) >- __nonzero__ = new_method_proxy(bool) >+ __bool__ = new_method_proxy(bool) # Python 3 >+ __nonzero__ = __bool__ # Python 2 > > > class lazy_property(property): >@@ -303,10 +327,44 @@ > Splits the values into two sets, based on the return value of the function > (True/False). e.g.: > >- >>> partition(lambda: x > 3, range(5)) >- [1, 2, 3], [4] >+ >>> partition(lambda x: x > 3, range(5)) >+ [0, 1, 2, 3], [4] > """ > results = ([], []) > for item in 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 >diff -urP utils-orig/six.py utils/six.py >--- utils-orig/six.py 1969-12-31 20:00:00.000000000 -0400 >+++ utils/six.py 2013-01-08 18:24:48.000000000 -0430 >@@ -0,0 +1,370 @@ >+"""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 -urP utils-orig/timezone.py utils/timezone.py >--- utils-orig/timezone.py 2013-01-31 02:47:26.419320806 -0430 >+++ utils/timezone.py 2013-01-08 18:24:48.000000000 -0430 >@@ -12,7 +12,8 @@ > except ImportError: > pytz = None > >-from django.conf import settings >+# ### from django.conf import settings >+from . import six > > __all__ = [ > 'utc', 'get_default_timezone', 'get_current_timezone', >@@ -93,26 +94,25 @@ > utc = pytz.utc if pytz else UTC() > """UTC time zone as a tzinfo instance.""" > >-# In order to avoid accessing the settings at compile time, >-# wrap the expression in a function and cache the result. >-# If you change settings.TIME_ZONE in tests, reset _localtime to None. >-_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, basestring) and pytz is not None: >- _localtime = pytz.timezone(settings.TIME_ZONE) >- else: >- _localtime = LocalTimezone() >- return _localtime >+# ### # 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: >+# ### _localtime = pytz.timezone(settings.TIME_ZONE) >+# ### else: >+# ### _localtime = LocalTimezone() >+# ### return _localtime > > # This function exists for consistency with get_current_timezone_name > def get_default_timezone_name(): >@@ -161,7 +161,7 @@ > """ > if isinstance(timezone, tzinfo): > _active.value = timezone >- elif isinstance(timezone, basestring) and pytz is not None: >+ elif isinstance(timezone, six.string_types) and pytz is not None: > _active.value = pytz.timezone(timezone) > else: > raise ValueError("Invalid timezone: %r" % timezone) >@@ -204,40 +204,50 @@ > del _active.value > > >-# Templates >+# ### # 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) >+# ### and (settings.USE_TZ if use_tz is None else use_tz) >+# ### and not is_naive(value) >+# ### and getattr(value, 'convert_to_local_time', True)) >+# ### return localtime(value) if should_convert else value > >-def 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. >+# Utilities >+ >+def localtime(value, timezone=None): >+ """ >+ Converts an aware datetime.datetime to local time. > >- This function is designed for use by the template engine. >+ Local time is defined by the current time zone, unless another time zone >+ is specified. > """ >- if (isinstance(value, datetime) >- and (settings.USE_TZ if use_tz is None else use_tz) >- and not is_naive(value) >- and getattr(value, 'convert_to_local_time', True)): >+ if timezone is None: > timezone = get_current_timezone() >- value = value.astimezone(timezone) >- if hasattr(timezone, 'normalize'): >- # available for pytz time zones >- value = timezone.normalize(value) >+ value = value.astimezone(timezone) >+ if hasattr(timezone, 'normalize'): >+ # available for pytz time zones >+ value = timezone.normalize(value) > return value > >- >-# Utilities >- >-def now(): >- """ >- Returns an aware or naive datetime.datetime, depending on settings.USE_TZ. >- """ >- if settings.USE_TZ: >- # timeit shows that datetime.now(tz=utc) is 24% slower >- return datetime.utcnow().replace(tzinfo=utc) >- else: >- return datetime.now() >+# ### def now(): >+# ### """ >+# ### Returns an aware or naive datetime.datetime, depending on settings.USE_TZ. >+# ### """ >+# ### if settings.USE_TZ: >+# ### # timeit shows that datetime.now(tz=utc) is 24% slower >+# ### return datetime.utcnow().replace(tzinfo=utc) >+# ### else: >+# ### return datetime.now() > > # By design, these four functions don't perform any checks on their arguments. > # The caller should ensure that they don't receive an invalid value like None.
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 906160
: 691870 |
693154