CI_CD updates
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,89 @@
|
||||
# Python's datetime strftime doesn't handle dates before 1900.
|
||||
# These classes override date and datetime to support the formatting of a date
|
||||
# through its full "proleptic Gregorian" date range.
|
||||
#
|
||||
# Based on code submitted to comp.lang.python by Andrew Dalke
|
||||
#
|
||||
# >>> datetime_safe.date(1850, 8, 2).strftime("%Y/%m/%d was a %A")
|
||||
# '1850/08/02 was a Friday'
|
||||
|
||||
from datetime import date as real_date, datetime as real_datetime
|
||||
import re
|
||||
import time
|
||||
|
||||
class date(real_date):
|
||||
def strftime(self, fmt):
|
||||
return strftime(self, fmt)
|
||||
|
||||
class datetime(real_datetime):
|
||||
def strftime(self, fmt):
|
||||
return strftime(self, fmt)
|
||||
|
||||
def combine(self, date, time):
|
||||
return datetime(date.year, date.month, date.day, time.hour, time.minute, time.microsecond, time.tzinfo)
|
||||
|
||||
def date(self):
|
||||
return date(self.year, self.month, self.day)
|
||||
|
||||
def new_date(d):
|
||||
"Generate a safe date from a datetime.date object."
|
||||
return date(d.year, d.month, d.day)
|
||||
|
||||
def new_datetime(d):
|
||||
"""
|
||||
Generate a safe datetime from a datetime.date or datetime.datetime object.
|
||||
"""
|
||||
kw = [d.year, d.month, d.day]
|
||||
if isinstance(d, real_datetime):
|
||||
kw.extend([d.hour, d.minute, d.second, d.microsecond, d.tzinfo])
|
||||
return datetime(*kw)
|
||||
|
||||
# This library does not support strftime's "%s" or "%y" format strings.
|
||||
# Allowed if there's an even number of "%"s because they are escaped.
|
||||
_illegal_formatting = re.compile(r"((^|[^%])(%%)*%[sy])")
|
||||
|
||||
def _findall(text, substr):
|
||||
# Also finds overlaps
|
||||
sites = []
|
||||
i = 0
|
||||
while 1:
|
||||
j = text.find(substr, i)
|
||||
if j == -1:
|
||||
break
|
||||
sites.append(j)
|
||||
i=j+1
|
||||
return sites
|
||||
|
||||
def strftime(dt, fmt):
|
||||
if dt.year >= 1900:
|
||||
return super(type(dt), dt).strftime(fmt)
|
||||
illegal_formatting = _illegal_formatting.search(fmt)
|
||||
if illegal_formatting:
|
||||
raise TypeError("strftime of dates before 1900 does not handle" + illegal_formatting.group(0))
|
||||
|
||||
year = dt.year
|
||||
# For every non-leap year century, advance by
|
||||
# 6 years to get into the 28-year repeat cycle
|
||||
delta = 2000 - year
|
||||
off = 6 * (delta // 100 + delta // 400)
|
||||
year = year + off
|
||||
|
||||
# Move to around the year 2000
|
||||
year = year + ((2000 - year) // 28) * 28
|
||||
timetuple = dt.timetuple()
|
||||
s1 = time.strftime(fmt, (year,) + timetuple[1:])
|
||||
sites1 = _findall(s1, str(year))
|
||||
|
||||
s2 = time.strftime(fmt, (year+28,) + timetuple[1:])
|
||||
sites2 = _findall(s2, str(year+28))
|
||||
|
||||
sites = []
|
||||
for site in sites1:
|
||||
if site in sites2:
|
||||
sites.append(site)
|
||||
|
||||
s = s1
|
||||
syear = "%04d" % (dt.year,)
|
||||
for site in sites:
|
||||
s = s[:site] + syear + s[site+4:]
|
||||
return s
|
||||
@@ -0,0 +1,201 @@
|
||||
import codecs
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
import locale
|
||||
from urllib.parse import quote
|
||||
|
||||
from .functional import Promise
|
||||
|
||||
class DjangoUnicodeDecodeError(UnicodeDecodeError):
|
||||
def __init__(self, obj, *args):
|
||||
self.obj = obj
|
||||
UnicodeDecodeError.__init__(self, *args)
|
||||
|
||||
def __str__(self):
|
||||
original = UnicodeDecodeError.__str__(self)
|
||||
return '{}. You passed in {!r} ({})'.format(original, self.obj,
|
||||
type(self.obj))
|
||||
|
||||
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_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_text(strings_only=True).
|
||||
"""
|
||||
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'):
|
||||
"""
|
||||
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% 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, str):
|
||||
if hasattr(s, '__unicode__'):
|
||||
s = s.__unicode__()
|
||||
else:
|
||||
try:
|
||||
if isinstance(s, bytes):
|
||||
s = str(s, encoding, errors)
|
||||
else:
|
||||
s = str(s)
|
||||
except UnicodeEncodeError:
|
||||
if not isinstance(s, Exception):
|
||||
raise
|
||||
# If we get to here, the caller has passed in an Exception
|
||||
# subclass populated with non-ASCII data without special
|
||||
# handling to display as a string. We need to handle this
|
||||
# without raising a further exception. We do an
|
||||
# approximation to what the Exception's standard str()
|
||||
# output should be.
|
||||
s = ' '.join([force_text(arg, encoding, strings_only,
|
||||
errors) for arg in s])
|
||||
else:
|
||||
# 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)
|
||||
except UnicodeDecodeError as e:
|
||||
if not isinstance(s, Exception):
|
||||
raise DjangoUnicodeDecodeError(s, *e.args)
|
||||
else:
|
||||
# If we get to here, the caller has passed in an Exception
|
||||
# subclass populated with non-ASCII bytestring data without a
|
||||
# working unicode method. Try to handle this without raising a
|
||||
# further exception by individually forcing the exception args
|
||||
# to unicode.
|
||||
s = ' '.join([force_text(arg, encoding, strings_only,
|
||||
errors) for arg in s])
|
||||
return s
|
||||
|
||||
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 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 str.encode(encoding, errors)
|
||||
if not isinstance(s, str):
|
||||
try:
|
||||
return str(s).encode(encoding)
|
||||
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_bytes(arg, encoding, strings_only,
|
||||
errors) for arg in s])
|
||||
return str(s).encode(encoding, errors)
|
||||
else:
|
||||
return s.encode(encoding, errors)
|
||||
|
||||
|
||||
smart_str = smart_text
|
||||
force_str = 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):
|
||||
"""
|
||||
Convert an Internationalized Resource Identifier (IRI) portion to a URI
|
||||
portion that is suitable for inclusion in a URL.
|
||||
|
||||
This is the algorithm from section 3.1 of RFC 3987. However, since we are
|
||||
assuming input is either UTF-8 or unicode already, we can simplify things a
|
||||
little from the full method.
|
||||
|
||||
Returns an ASCII string containing the encoded result.
|
||||
"""
|
||||
# The list of safe characters here is constructed from the "reserved" and
|
||||
# "unreserved" characters specified in sections 2.2 and 2.3 of RFC 3986:
|
||||
# reserved = gen-delims / sub-delims
|
||||
# gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
# / "*" / "+" / "," / ";" / "="
|
||||
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
# Of the unreserved characters, urllib.quote already considers all but
|
||||
# the ~ safe.
|
||||
# The % character is also added to the list of safe characters here, as the
|
||||
# end of section 3.1 of RFC 3987 specifically mentions that % must not be
|
||||
# converted.
|
||||
if iri is None:
|
||||
return iri
|
||||
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
|
||||
inclusion in a URL.
|
||||
|
||||
We are assuming input is either UTF-8 or unicode already.
|
||||
|
||||
This method will encode certain chars that would normally be recognized as
|
||||
special chars for URIs. Note that this method does not encode the '
|
||||
character, as it is a valid character within URIs. See
|
||||
encodeURIComponent() JavaScript function for more details.
|
||||
|
||||
Returns an ASCII string containing the encoded result.
|
||||
"""
|
||||
if path is None:
|
||||
return path
|
||||
# I know about `os.sep` and `os.altsep` but I want to leave
|
||||
# some flexibility for hardcoding separators.
|
||||
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
|
||||
# not be determined. See tickets #10335 and #5846
|
||||
try:
|
||||
DEFAULT_LOCALE_ENCODING = locale.getlocale()[1] or 'ascii'
|
||||
codecs.lookup(DEFAULT_LOCALE_ENCODING)
|
||||
except:
|
||||
DEFAULT_LOCALE_ENCODING = 'ascii'
|
||||
@@ -0,0 +1,405 @@
|
||||
"""
|
||||
Syndication feed generation library -- used for generating RSS, etc.
|
||||
|
||||
Sample usage:
|
||||
|
||||
>>> from django.utils import feedgenerator
|
||||
>>> feed = feedgenerator.Rss201rev2Feed(
|
||||
... 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="http://www.holovaty.com/test/",
|
||||
... description="Testing."
|
||||
... )
|
||||
>>> with open('test.rss', 'w') as fp:
|
||||
... feed.write(fp, 'utf-8')
|
||||
|
||||
For definitions of the different versions of RSS, see:
|
||||
http://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004/02/04/incompatible-rss
|
||||
"""
|
||||
import datetime
|
||||
from urllib.parse import urlparse
|
||||
from .xmlutils import SimplerXMLGenerator
|
||||
from .encoding import force_text, iri_to_uri
|
||||
from . import datetime_safe
|
||||
from io import StringIO
|
||||
from .timezone import is_aware
|
||||
|
||||
def rfc2822_date(date):
|
||||
# We can't use strftime() because it produces locale-dependent results, so
|
||||
# we have to map english month and day names manually
|
||||
months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',)
|
||||
days = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
|
||||
# Support datetime objects older than 1900
|
||||
date = datetime_safe.new_datetime(date)
|
||||
# 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(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)
|
||||
hour, minute = divmod(timezone, 60)
|
||||
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 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)
|
||||
else:
|
||||
return time_str + 'Z'
|
||||
|
||||
def get_tag_uri(url, date):
|
||||
"""
|
||||
Creates a TagURI.
|
||||
|
||||
See http://web.archive.org/web/20110514113830/http://diveintomark.org/archives/2004/05/28/howto-atom-id
|
||||
"""
|
||||
bits = urlparse(url)
|
||||
d = ''
|
||||
if date is not None:
|
||||
d = ',%s' % datetime_safe.new_datetime(date).strftime('%Y-%m-%d')
|
||||
fragment = ''
|
||||
if bits.fragment != '':
|
||||
fragment = '/%s' % (bits.fragment)
|
||||
return f'tag:{bits.hostname}{d}:{bits.path}{fragment}'
|
||||
|
||||
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, 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]
|
||||
if ttl is not None:
|
||||
# Force ints to unicode
|
||||
ttl = force_text(ttl)
|
||||
self.feed = {
|
||||
'title': to_unicode(title),
|
||||
'link': iri_to_uri(link),
|
||||
'description': to_unicode(description),
|
||||
'language': to_unicode(language),
|
||||
'author_email': to_unicode(author_email),
|
||||
'author_name': to_unicode(author_name),
|
||||
'author_link': iri_to_uri(author_link),
|
||||
'subtitle': to_unicode(subtitle),
|
||||
'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,
|
||||
}
|
||||
self.feed.update(kwargs)
|
||||
self.items = []
|
||||
|
||||
def add_item(self, title, link, description, author_email=None,
|
||||
author_name=None, author_link=None, pubdate=None, comments=None,
|
||||
unique_id=None, enclosure=None, categories=(), item_copyright=None,
|
||||
ttl=None, content=None, updateddate=None, **kwargs):
|
||||
"""
|
||||
Adds an item to the feed. All args are expected to be Python Unicode
|
||||
objects except pubdate and updateddate, which are datetime.datetime
|
||||
objects, and enclosure, which is an instance of the Enclosure class.
|
||||
"""
|
||||
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_text(ttl)
|
||||
item = {
|
||||
'title': to_unicode(title),
|
||||
'link': iri_to_uri(link),
|
||||
'description': to_unicode(description),
|
||||
'content': to_unicode(content),
|
||||
'author_email': to_unicode(author_email),
|
||||
'author_name': to_unicode(author_name),
|
||||
'author_link': iri_to_uri(author_link),
|
||||
'pubdate': pubdate,
|
||||
'updateddate': updateddate,
|
||||
'comments': to_unicode(comments),
|
||||
'unique_id': to_unicode(unique_id),
|
||||
'enclosure': enclosure,
|
||||
'categories': categories or (),
|
||||
'item_copyright': to_unicode(item_copyright),
|
||||
'ttl': ttl,
|
||||
}
|
||||
item.update(kwargs)
|
||||
self.items.append(item)
|
||||
|
||||
def num_items(self):
|
||||
return len(self.items)
|
||||
|
||||
def root_attributes(self):
|
||||
"""
|
||||
Return extra attributes to place on the root (i.e. feed/channel) element.
|
||||
Called from write().
|
||||
"""
|
||||
return {}
|
||||
|
||||
def add_root_elements(self, handler):
|
||||
"""
|
||||
Add elements in the root (i.e. feed/channel) element. Called
|
||||
from write().
|
||||
"""
|
||||
pass
|
||||
|
||||
def item_attributes(self, item):
|
||||
"""
|
||||
Return extra attributes to place on each item (i.e. item/entry) element.
|
||||
"""
|
||||
return {}
|
||||
|
||||
def add_item_elements(self, handler, item):
|
||||
"""
|
||||
Add elements on each item (i.e. item/entry) element.
|
||||
"""
|
||||
pass
|
||||
|
||||
def write(self, outfile, encoding):
|
||||
"""
|
||||
Outputs the feed in the given encoding to outfile, which is a file-like
|
||||
object. Subclasses should override this.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def writeString(self, encoding):
|
||||
"""
|
||||
Returns the feed in the given encoding as a string.
|
||||
"""
|
||||
s = StringIO()
|
||||
self.write(s, encoding)
|
||||
return s.getvalue()
|
||||
|
||||
def latest_post_date(self):
|
||||
"""
|
||||
Returns the latest item's pubdate or updateddate. If no item has either
|
||||
date, returns the current date/time.
|
||||
"""
|
||||
updates = [i['pubdate'] for i in self.items if i['pubdate'] is not None]
|
||||
updates.extend(i['updateddate'] for i in self.items if i['updateddate'] is not None)
|
||||
if len(updates) > 0:
|
||||
updates.sort()
|
||||
return updates[-1]
|
||||
else:
|
||||
return datetime.datetime.now()
|
||||
|
||||
class Enclosure:
|
||||
"Represents an RSS enclosure"
|
||||
def __init__(self, url, length, mime_type):
|
||||
"All args are expected to be Python Unicode objects"
|
||||
self.length, self.mime_type = length, mime_type
|
||||
self.url = iri_to_uri(url)
|
||||
|
||||
class RssFeed(SyndicationFeed):
|
||||
mime_type = 'application/rss+xml; charset=utf-8'
|
||||
def write(self, outfile, encoding):
|
||||
handler = SimplerXMLGenerator(outfile, encoding)
|
||||
handler.startDocument()
|
||||
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("rss")
|
||||
|
||||
def rss_attributes(self):
|
||||
return {'version': self._version}
|
||||
|
||||
def write_items(self, handler):
|
||||
for item in self.items:
|
||||
handler.startElement('item', self.item_attributes(item))
|
||||
self.add_item_elements(handler, item)
|
||||
handler.endElement("item")
|
||||
|
||||
def add_root_elements(self, handler):
|
||||
# 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
|
||||
if self.feed['language'] is not None:
|
||||
handler.addQuickElement("language", self.feed['language'])
|
||||
for cat in self.feed['categories']:
|
||||
handler.addQuickElement("category", cat)
|
||||
if self.feed['feed_copyright'] is not None:
|
||||
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("ttl", self.feed['ttl'])
|
||||
|
||||
def endChannelElement(self, handler):
|
||||
handler.endElement("channel")
|
||||
|
||||
class RssUserland091Feed(RssFeed):
|
||||
_version = "0.91"
|
||||
def add_item_elements(self, handler, item):
|
||||
handler.addQuickElement("title", item['title'])
|
||||
handler.addQuickElement("link", item['link'])
|
||||
if item['description'] is not None:
|
||||
handler.addQuickElement("description", item['description'])
|
||||
|
||||
class Rss201rev2Feed(RssFeed):
|
||||
# Spec: http://blogs.law.harvard.edu/tech/rss
|
||||
_version = "2.0"
|
||||
def add_item_elements(self, handler, item):
|
||||
handler.addQuickElement("title", item['title'])
|
||||
handler.addQuickElement("link", item['link'])
|
||||
if item['description'] is not None:
|
||||
handler.addQuickElement("description", item['description'])
|
||||
|
||||
# Author information.
|
||||
if item["author_name"] and item["author_email"]:
|
||||
handler.addQuickElement("author", "%s (%s)" % \
|
||||
(item['author_email'], item['author_name']))
|
||||
elif item["author_email"]:
|
||||
handler.addQuickElement("author", item["author_email"])
|
||||
elif item["author_name"]:
|
||||
handler.addQuickElement("dc:creator", item["author_name"], {"xmlns:dc": "http://purl.org/dc/elements/1.1/"})
|
||||
|
||||
if item['pubdate'] is not None:
|
||||
handler.addQuickElement("pubDate", rfc2822_date(item['pubdate']))
|
||||
if item['comments'] is not None:
|
||||
handler.addQuickElement("comments", item['comments'])
|
||||
if item['unique_id'] is not None:
|
||||
handler.addQuickElement("guid", item['unique_id'], attrs={'isPermaLink': 'false'})
|
||||
if item['ttl'] is not None:
|
||||
handler.addQuickElement("ttl", item['ttl'])
|
||||
|
||||
# Enclosure.
|
||||
if item['enclosure'] is not None:
|
||||
handler.addQuickElement("enclosure", '',
|
||||
{"url": item['enclosure'].url, "length": item['enclosure'].length,
|
||||
"type": item['enclosure'].mime_type})
|
||||
|
||||
# Categories.
|
||||
for cat in item['categories']:
|
||||
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 = "http://www.w3.org/2005/Atom"
|
||||
|
||||
def write(self, outfile, encoding):
|
||||
handler = SimplerXMLGenerator(outfile, encoding)
|
||||
handler.startDocument()
|
||||
handler.startElement('feed', self.root_attributes())
|
||||
self.add_root_elements(handler)
|
||||
self.write_items(handler)
|
||||
handler.endElement("feed")
|
||||
|
||||
def root_attributes(self):
|
||||
if self.feed['language'] is not None:
|
||||
return {"xmlns": self.ns, "xml:lang": self.feed['language']}
|
||||
else:
|
||||
return {"xmlns": self.ns}
|
||||
|
||||
def add_root_elements(self, handler):
|
||||
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("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("author", {})
|
||||
handler.addQuickElement("name", self.feed['author_name'])
|
||||
if self.feed['author_email'] is not None:
|
||||
handler.addQuickElement("email", self.feed['author_email'])
|
||||
if self.feed['author_link'] is not None:
|
||||
handler.addQuickElement("uri", self.feed['author_link'])
|
||||
handler.endElement("author")
|
||||
# try to use description or subtitle if provided, subtitle has
|
||||
# precedence above description
|
||||
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:
|
||||
handler.addQuickElement("rights", self.feed['feed_copyright'])
|
||||
|
||||
def write_items(self, handler):
|
||||
for item in self.items:
|
||||
handler.startElement("entry", self.item_attributes(item))
|
||||
self.add_item_elements(handler, item)
|
||||
handler.endElement("entry")
|
||||
|
||||
def add_item_elements(self, handler, item):
|
||||
handler.addQuickElement("title", item['title'])
|
||||
handler.addQuickElement("link", "", {"href": item['link'], "rel": "alternate"})
|
||||
|
||||
updateddate = datetime.datetime.now()
|
||||
if item['pubdate'] is not None:
|
||||
handler.addQuickElement("published", rfc3339_date(item['pubdate']))
|
||||
updateddate = item['pubdate']
|
||||
if item['updateddate'] is not None:
|
||||
updateddate = item['updateddate']
|
||||
handler.addQuickElement("updated", rfc3339_date(updateddate))
|
||||
|
||||
# Author information.
|
||||
if item['author_name'] is not None:
|
||||
handler.startElement("author", {})
|
||||
handler.addQuickElement("name", item['author_name'])
|
||||
if item['author_email'] is not None:
|
||||
handler.addQuickElement("email", item['author_email'])
|
||||
if item['author_link'] is not None:
|
||||
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("id", unique_id)
|
||||
|
||||
# Summary.
|
||||
if item['description'] is not None:
|
||||
handler.addQuickElement("summary", item['description'], {"type": "html"})
|
||||
|
||||
# Full content.
|
||||
if item['content'] is not None:
|
||||
handler.addQuickElement("content", item['content'], {"type": "html"})
|
||||
|
||||
# Enclosure.
|
||||
if item['enclosure'] is not None:
|
||||
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("category", "", {"term": cat})
|
||||
|
||||
# Rights.
|
||||
if item['item_copyright'] is not None:
|
||||
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".
|
||||
DefaultFeed = Rss201rev2Feed
|
||||
@@ -0,0 +1,324 @@
|
||||
import copy
|
||||
import operator
|
||||
from functools import wraps, update_wrapper
|
||||
import sys
|
||||
|
||||
# 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.
|
||||
def curry(_curried_func, *args, **kwargs):
|
||||
def _curried(*moreargs, **morekwargs):
|
||||
return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
|
||||
return _curried
|
||||
|
||||
def memoize(func, cache, num_args):
|
||||
"""
|
||||
Wrap a function so that results for any argument tuple are stored in
|
||||
'cache'. Note that the args to the function must be usable as dictionary
|
||||
keys.
|
||||
|
||||
Only the first num_args are considered when creating the key.
|
||||
"""
|
||||
@wraps(func)
|
||||
def wrapper(*args):
|
||||
mem_args = args[:num_args]
|
||||
if mem_args in cache:
|
||||
return cache[mem_args]
|
||||
result = func(*args)
|
||||
cache[mem_args] = result
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
class cached_property:
|
||||
"""
|
||||
Decorator that creates converts a method with a single
|
||||
self argument into a property cached on the instance.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
|
||||
def __get__(self, instance, type):
|
||||
res = instance.__dict__[self.func.__name__] = self.func(instance)
|
||||
return res
|
||||
|
||||
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
|
||||
promises in code.
|
||||
"""
|
||||
pass
|
||||
|
||||
def lazy(func, *resultclasses):
|
||||
"""
|
||||
Turns any callable into a lazy evaluated callable. You need to give result
|
||||
classes or types -- at least one is needed so that the automatic forcing of
|
||||
the lazy evaluation code is triggered. Results are not memoized; the
|
||||
function is evaluated on every access.
|
||||
"""
|
||||
|
||||
@total_ordering
|
||||
class __proxy__(Promise):
|
||||
"""
|
||||
Encapsulate a function call and act as a proxy for methods that are
|
||||
called on the result of that function. The function is not evaluated
|
||||
until one of the methods on the result is called.
|
||||
"""
|
||||
__dispatch = None
|
||||
|
||||
def __init__(self, args, kw):
|
||||
self.__args = args
|
||||
self.__kw = kw
|
||||
if self.__dispatch is None:
|
||||
self.__prepare_class__()
|
||||
|
||||
def __reduce__(self):
|
||||
return (
|
||||
_lazy_proxy_unpickle,
|
||||
(func, self.__args, self.__kw) + resultclasses
|
||||
)
|
||||
|
||||
def __prepare_class__(cls):
|
||||
cls.__dispatch = {}
|
||||
for resultclass in resultclasses:
|
||||
cls.__dispatch[resultclass] = {}
|
||||
for type_ in reversed(resultclass.mro()):
|
||||
for (k, v) in type_.__dict__.items():
|
||||
# All __promise__ return the same wrapper method, but they
|
||||
# also do setup, inserting the method into the dispatch
|
||||
# dict.
|
||||
meth = cls.__promise__(resultclass, k, v)
|
||||
if hasattr(cls, k):
|
||||
continue
|
||||
setattr(cls, k, meth)
|
||||
cls._delegate_bytes = bytes 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:
|
||||
cls.__str__ = cls.__text_cast
|
||||
elif cls._delegate_bytes:
|
||||
cls.__bytes__ = cls.__bytes_cast
|
||||
__prepare_class__ = classmethod(__prepare_class__)
|
||||
|
||||
def __promise__(cls, klass, funcname, method):
|
||||
# Builds a wrapper around some magic method and registers that magic
|
||||
# method for the given type and method name.
|
||||
def __wrapper__(self, *args, **kw):
|
||||
# Automatically triggers the evaluation of a lazy value and
|
||||
# applies the given magic method of the result type.
|
||||
res = func(*self.__args, **self.__kw)
|
||||
for t in type(res).mro():
|
||||
if t in self.__dispatch:
|
||||
return self.__dispatch[t][funcname](res, *args, **kw)
|
||||
raise TypeError("Lazy object returned unexpected type.")
|
||||
|
||||
if klass not in cls.__dispatch:
|
||||
cls.__dispatch[klass] = {}
|
||||
cls.__dispatch[klass][funcname] = method
|
||||
return __wrapper__
|
||||
__promise__ = classmethod(__promise__)
|
||||
|
||||
def __text_cast(self):
|
||||
return func(*self.__args, **self.__kw)
|
||||
|
||||
def __bytes_cast(self):
|
||||
return bytes(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:
|
||||
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_text:
|
||||
return str(self) % rhs
|
||||
else:
|
||||
raise AssertionError('__mod__ not supported for non-string types')
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
# Instances of this class are effectively immutable. It's just a
|
||||
# collection of functions. So we don't need to do anything
|
||||
# complicated for copying.
|
||||
memo[id(self)] = self
|
||||
return self
|
||||
|
||||
@wraps(func)
|
||||
def __wrapper__(*args, **kw):
|
||||
# Creates the proxy object, instead of the actual value.
|
||||
return __proxy__(args, kw)
|
||||
|
||||
return __wrapper__
|
||||
|
||||
def _lazy_proxy_unpickle(func, args, kwargs, *resultclasses):
|
||||
return lazy(func, *resultclasses)(*args, **kwargs)
|
||||
|
||||
def allow_lazy(func, *resultclasses):
|
||||
"""
|
||||
A decorator that allows a function to be called with one or more lazy
|
||||
arguments. If none of the args are lazy, the function is evaluated
|
||||
immediately, otherwise a __proxy__ is returned that will evaluate the
|
||||
function when needed.
|
||||
"""
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
for arg in list(args) + list(kwargs.values()):
|
||||
if isinstance(arg, Promise):
|
||||
break
|
||||
else:
|
||||
return func(*args, **kwargs)
|
||||
return lazy(func, *resultclasses)(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
empty = object()
|
||||
def new_method_proxy(func):
|
||||
def inner(self, *args):
|
||||
if self._wrapped is empty:
|
||||
self._setup()
|
||||
return func(self._wrapped, *args)
|
||||
return inner
|
||||
|
||||
class LazyObject:
|
||||
"""
|
||||
A wrapper for another class that can be used to delay instantiation of the
|
||||
wrapped class.
|
||||
|
||||
By subclassing, you have the opportunity to intercept and alter the
|
||||
instantiation. If you don't need to do that, use SimpleLazyObject.
|
||||
"""
|
||||
def __init__(self):
|
||||
self._wrapped = empty
|
||||
|
||||
__getattr__ = new_method_proxy(getattr)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name == "_wrapped":
|
||||
# Assign to __dict__ to avoid infinite __setattr__ loops.
|
||||
self.__dict__["_wrapped"] = value
|
||||
else:
|
||||
if self._wrapped is empty:
|
||||
self._setup()
|
||||
setattr(self._wrapped, name, value)
|
||||
|
||||
def __delattr__(self, name):
|
||||
if name == "_wrapped":
|
||||
raise TypeError("can't delete _wrapped.")
|
||||
if self._wrapped is empty:
|
||||
self._setup()
|
||||
delattr(self._wrapped, name)
|
||||
|
||||
def _setup(self):
|
||||
"""
|
||||
Must be implemented by subclasses to initialise the wrapped object.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
# introspection support:
|
||||
__dir__ = new_method_proxy(dir)
|
||||
|
||||
|
||||
# Workaround for http://bugs.python.org/issue12370
|
||||
_super = super
|
||||
|
||||
class SimpleLazyObject(LazyObject):
|
||||
"""
|
||||
A lazy object initialised from any function.
|
||||
|
||||
Designed for compound objects of unknown type. For builtins or objects of
|
||||
known type, use django.utils.functional.lazy.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
"""
|
||||
Pass in a callable that returns the object to be wrapped.
|
||||
|
||||
If copies are made of the resulting SimpleLazyObject, which can happen
|
||||
in various circumstances within Django, then you must ensure that the
|
||||
callable can be safely run more than once and will return the same
|
||||
value.
|
||||
"""
|
||||
self.__dict__['_setupfunc'] = func
|
||||
_super(SimpleLazyObject, self).__init__()
|
||||
|
||||
def _setup(self):
|
||||
self._wrapped = self._setupfunc()
|
||||
|
||||
__bytes__ = new_method_proxy(bytes)
|
||||
__str__ = new_method_proxy(str)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
if self._wrapped is empty:
|
||||
# We have to use SimpleLazyObject, not self.__class__, because the
|
||||
# latter is proxied.
|
||||
result = SimpleLazyObject(self._setupfunc)
|
||||
memo[id(self)] = result
|
||||
return result
|
||||
else:
|
||||
return copy.deepcopy(self._wrapped, memo)
|
||||
|
||||
# Because we have messed with __class__ below, we confuse pickle as to what
|
||||
# class we are pickling. It also appears to stop __reduce__ from being
|
||||
# called. So, we define __getstate__ in a way that cooperates with the way
|
||||
# that pickle interprets this class. This fails when the wrapped class is a
|
||||
# builtin, but it is better than nothing.
|
||||
def __getstate__(self):
|
||||
if self._wrapped is empty:
|
||||
self._setup()
|
||||
return self._wrapped.__dict__
|
||||
|
||||
# Need to pretend to be the wrapped class, for the sake of objects that care
|
||||
# about this (especially in equality tests)
|
||||
__class__ = property(new_method_proxy(operator.attrgetter("__class__")))
|
||||
__eq__ = new_method_proxy(operator.eq)
|
||||
__hash__ = new_method_proxy(hash)
|
||||
__bool__ = new_method_proxy(bool) # Python 3
|
||||
__nonzero__ = __bool__ # Python 2
|
||||
|
||||
|
||||
class lazy_property(property):
|
||||
"""
|
||||
A property that works with subclasses by wrapping the decorated
|
||||
functions of the base class.
|
||||
"""
|
||||
def __new__(cls, fget=None, fset=None, fdel=None, doc=None):
|
||||
if fget is not None:
|
||||
@wraps(fget)
|
||||
def fget(instance, instance_type=None, name=fget.__name__):
|
||||
return getattr(instance, name)()
|
||||
if fset is not None:
|
||||
@wraps(fset)
|
||||
def fset(instance, value, name=fset.__name__):
|
||||
return getattr(instance, name)(value)
|
||||
if fdel is not None:
|
||||
@wraps(fdel)
|
||||
def fdel(instance, name=fdel.__name__):
|
||||
return getattr(instance, name)()
|
||||
return property(fget, fset, fdel, doc)
|
||||
|
||||
def partition(predicate, values):
|
||||
"""
|
||||
Splits the values into two sets, based on the return value of the function
|
||||
(True/False). e.g.:
|
||||
|
||||
>>> partition(lambda x: x > 3, range(5))
|
||||
[0, 1, 2, 3], [4]
|
||||
"""
|
||||
results = ([], [])
|
||||
for item in values:
|
||||
results[predicate(item)].append(item)
|
||||
return results
|
||||
|
||||
from functools import total_ordering
|
||||
@@ -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"))
|
||||
@@ -0,0 +1,290 @@
|
||||
"""Timezone helper functions.
|
||||
|
||||
This module uses pytz when it's available and fallbacks when it isn't.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
from threading import local
|
||||
import time as _time
|
||||
|
||||
try:
|
||||
import pytz
|
||||
except ImportError:
|
||||
pytz = None
|
||||
|
||||
# ### from django.conf import settings
|
||||
__all__ = [
|
||||
'utc', 'get_default_timezone', 'get_current_timezone',
|
||||
'activate', 'deactivate', 'override',
|
||||
'is_naive', 'is_aware', 'make_aware', 'make_naive',
|
||||
]
|
||||
|
||||
|
||||
# UTC and local time zones
|
||||
|
||||
ZERO = timedelta(0)
|
||||
|
||||
class UTC(tzinfo):
|
||||
"""
|
||||
UTC implementation taken from Python's docs.
|
||||
|
||||
Used only when pytz isn't available.
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return "<UTC>"
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return "UTC"
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
class LocalTimezone(tzinfo):
|
||||
"""
|
||||
Local time implementation taken from Python's docs.
|
||||
|
||||
Used only when pytz isn't available, and most likely inaccurate. If you're
|
||||
having trouble with this class, don't waste your time, just install pytz.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# This code is moved in __init__ to execute it as late as possible
|
||||
# See get_default_timezone().
|
||||
self.STDOFFSET = timedelta(seconds=-_time.timezone)
|
||||
if _time.daylight:
|
||||
self.DSTOFFSET = timedelta(seconds=-_time.altzone)
|
||||
else:
|
||||
self.DSTOFFSET = self.STDOFFSET
|
||||
self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET
|
||||
tzinfo.__init__(self)
|
||||
|
||||
def __repr__(self):
|
||||
return "<LocalTimezone>"
|
||||
|
||||
def utcoffset(self, dt):
|
||||
if self._isdst(dt):
|
||||
return self.DSTOFFSET
|
||||
else:
|
||||
return self.STDOFFSET
|
||||
|
||||
def dst(self, dt):
|
||||
if self._isdst(dt):
|
||||
return self.DSTDIFF
|
||||
else:
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return _time.tzname[self._isdst(dt)]
|
||||
|
||||
def _isdst(self, dt):
|
||||
tt = (dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.weekday(), 0, 0)
|
||||
stamp = _time.mktime(tt)
|
||||
tt = _time.localtime(stamp)
|
||||
return tt.tm_isdst > 0
|
||||
|
||||
|
||||
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.
|
||||
# ### _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, str) 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():
|
||||
"""
|
||||
Returns the name of the default time zone.
|
||||
"""
|
||||
return _get_timezone_name(get_default_timezone())
|
||||
|
||||
_active = local()
|
||||
|
||||
def get_current_timezone():
|
||||
"""
|
||||
Returns the currently active time zone as a tzinfo instance.
|
||||
"""
|
||||
return getattr(_active, "value", get_default_timezone())
|
||||
|
||||
def get_current_timezone_name():
|
||||
"""
|
||||
Returns the name of the currently active time zone.
|
||||
"""
|
||||
return _get_timezone_name(get_current_timezone())
|
||||
|
||||
def _get_timezone_name(timezone):
|
||||
"""
|
||||
Returns the name of ``timezone``.
|
||||
"""
|
||||
try:
|
||||
# for pytz timezones
|
||||
return timezone.zone
|
||||
except AttributeError:
|
||||
# for regular tzinfo objects
|
||||
local_now = datetime.now(timezone)
|
||||
return timezone.tzname(local_now)
|
||||
|
||||
# Timezone selection functions.
|
||||
|
||||
# These functions don't change os.environ['TZ'] and call time.tzset()
|
||||
# because it isn't thread safe.
|
||||
|
||||
def activate(timezone):
|
||||
"""
|
||||
Sets the time zone for the current thread.
|
||||
|
||||
The ``timezone`` argument must be an instance of a tzinfo subclass or a
|
||||
time zone name. If it is a time zone name, pytz is required.
|
||||
"""
|
||||
if isinstance(timezone, tzinfo):
|
||||
_active.value = timezone
|
||||
elif isinstance(timezone, (str, )) and pytz is not None:
|
||||
_active.value = pytz.timezone(timezone)
|
||||
else:
|
||||
raise ValueError("Invalid timezone: %r" % timezone)
|
||||
|
||||
def deactivate():
|
||||
"""
|
||||
Unsets the time zone for the current thread.
|
||||
|
||||
Django will then use the time zone defined by settings.TIME_ZONE.
|
||||
"""
|
||||
if hasattr(_active, "value"):
|
||||
del _active.value
|
||||
|
||||
class override:
|
||||
"""
|
||||
Temporarily set the time zone for the current thread.
|
||||
|
||||
This is a context manager that uses ``~django.utils.timezone.activate()``
|
||||
to set the timezone on entry, and restores the previously active timezone
|
||||
on exit.
|
||||
|
||||
The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a
|
||||
time zone name, or ``None``. If is it a time zone name, pytz is required.
|
||||
If it is ``None``, Django enables the default time zone.
|
||||
"""
|
||||
def __init__(self, timezone):
|
||||
self.timezone = timezone
|
||||
self.old_timezone = getattr(_active, 'value', None)
|
||||
|
||||
def __enter__(self):
|
||||
if self.timezone is None:
|
||||
deactivate()
|
||||
else:
|
||||
activate(self.timezone)
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if self.old_timezone is not None:
|
||||
_active.value = self.old_timezone
|
||||
else:
|
||||
del _active.value
|
||||
|
||||
|
||||
# ### # 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
|
||||
|
||||
|
||||
# Utilities
|
||||
|
||||
def localtime(value, timezone=None):
|
||||
"""
|
||||
Converts an aware datetime.datetime to local time.
|
||||
|
||||
Local time is defined by the current time zone, unless another time zone
|
||||
is specified.
|
||||
"""
|
||||
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)
|
||||
return value
|
||||
|
||||
# ### 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.
|
||||
|
||||
def is_aware(value):
|
||||
"""
|
||||
Determines if a given datetime.datetime is aware.
|
||||
|
||||
The logic is described in Python's docs:
|
||||
http://docs.python.org/library/datetime.html#datetime.tzinfo
|
||||
"""
|
||||
return value.tzinfo is not None and value.tzinfo.utcoffset(value) is not None
|
||||
|
||||
def is_naive(value):
|
||||
"""
|
||||
Determines if a given datetime.datetime is naive.
|
||||
|
||||
The logic is described in Python's docs:
|
||||
http://docs.python.org/library/datetime.html#datetime.tzinfo
|
||||
"""
|
||||
return value.tzinfo is None or value.tzinfo.utcoffset(value) is None
|
||||
|
||||
def make_aware(value, timezone):
|
||||
"""
|
||||
Makes a naive datetime.datetime in a given time zone aware.
|
||||
"""
|
||||
if hasattr(timezone, 'localize'):
|
||||
# available for pytz time zones
|
||||
return timezone.localize(value, is_dst=None)
|
||||
else:
|
||||
# may be wrong around DST changes
|
||||
return value.replace(tzinfo=timezone)
|
||||
|
||||
def make_naive(value, timezone):
|
||||
"""
|
||||
Makes an aware datetime.datetime naive in a given time zone.
|
||||
"""
|
||||
value = value.astimezone(timezone)
|
||||
if hasattr(timezone, 'normalize'):
|
||||
# available for pytz time zones
|
||||
value = timezone.normalize(value)
|
||||
return value.replace(tzinfo=None)
|
||||
@@ -0,0 +1,21 @@
|
||||
"""
|
||||
Utilities for XML generation/parsing.
|
||||
"""
|
||||
|
||||
from xml.sax.saxutils import XMLGenerator, quoteattr
|
||||
|
||||
class SimplerXMLGenerator(XMLGenerator):
|
||||
def addQuickElement(self, name, contents=None, attrs=None):
|
||||
"Convenience method for adding an element with no children"
|
||||
if attrs is None: attrs = {}
|
||||
self.startElement(name, attrs)
|
||||
if contents is not None:
|
||||
self.characters(contents)
|
||||
self.endElement(name)
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
self._write('<' + name)
|
||||
# sort attributes for consistent output
|
||||
for (name, value) in sorted(attrs.items()):
|
||||
self._write(f' {name}={quoteattr(value)}')
|
||||
self._write('>')
|
||||
Reference in New Issue
Block a user