Actually, we can work around needing dateutil.
If dateutil is present, we'll use that. If not, we'll use some regexes from the fixed_datetime module.
This commit is contained in:
parent
6eac0606cf
commit
4d8933abdf
8 changed files with 310 additions and 54 deletions
31
LICENSE
31
LICENSE
|
@ -25,6 +25,7 @@ Licences of Bundled Third Pary Code
|
|||
-----------------------------------
|
||||
|
||||
dateutil - Extensions to the standard python 2.3+ datetime module.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright (c) 2003-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
|
||||
|
@ -55,9 +56,38 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
fixed_datetime
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Copyright (c) 2008, Red Innovation Ltd., Finland
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Red Innovation nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY RED INNOVATION ``AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RED INNOVATION BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
|
||||
OrderedDict - A port of the Python 2.7+ OrderedDict to Python 2.6
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright (c) 2009 Raymond Hettinger
|
||||
|
||||
|
@ -85,6 +115,7 @@ subject to the following conditions:
|
|||
|
||||
|
||||
SUELTA – A PURE-PYTHON SASL CLIENT LIBRARY
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This software is subject to "The MIT License"
|
||||
|
||||
|
|
3
README
3
README
|
@ -9,9 +9,6 @@ We try to keep requirements to a minimum, but we suggest that you install http:/
|
|||
If you do not install this library, you may need to specify the server/port for services that use SRV records (like GTalk).
|
||||
"sudo pip install dnspython" on a *nix system with pip installed.
|
||||
|
||||
Two time related plugins (XEP-0082 and XEP-0202) also require the dateutil package, but that is not a hard requirement if you
|
||||
don't need those plugins.
|
||||
|
||||
SleekXMPP has several design goals/philosophies:
|
||||
- Low number of dependencies.
|
||||
- Every XEP as a plugin.
|
||||
|
|
|
@ -6,20 +6,6 @@
|
|||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
__all__ = ['xep_0004', 'xep_0009', 'xep_0012', 'xep_0030', 'xep_0033',
|
||||
'xep_0045', 'xep_0050', 'xep_0060', 'xep_0066', 'xep_0085',
|
||||
'xep_0086', 'xep_0092', 'xep_0128', 'xep_0199', 'xep_0203',
|
||||
'xep_0224', 'xep_0249', 'gmail_notify']
|
||||
|
||||
# Some plugins may require external dependencies beyond what the
|
||||
# core SleekXMPP installation requires. Thus they should only by
|
||||
# imported automatically if those dependecies are met.
|
||||
|
||||
HAVE_DATEUTIL = True
|
||||
try:
|
||||
import dateutil
|
||||
except:
|
||||
HAVE_DATEUTIL = False
|
||||
|
||||
if HAVE_DATEUTIL:
|
||||
__all__.append('xep_0082')
|
||||
__all__.append('xep_0202')
|
||||
'xep_0045', 'xep_0050', 'xep_0060', 'xep_0066', 'xep_0082',
|
||||
'xep_0085', 'xep_0086', 'xep_0092', 'xep_0128', 'xep_0199',
|
||||
'xep_0082', 'xep_0203', 'xep_0224', 'xep_0249', 'gmail_notify']
|
||||
|
|
|
@ -10,13 +10,7 @@ import logging
|
|||
import datetime as dt
|
||||
|
||||
from sleekxmpp.plugins.base import base_plugin
|
||||
|
||||
try:
|
||||
from dateutil import parser
|
||||
from dateutil.tz import tzoffset, tzutc
|
||||
except e:
|
||||
log = logging.getLogger(__name__)
|
||||
log.warning("XEP-0082 plugin requires dateutil")
|
||||
from sleekxmpp.thirdparty import tzutc, tzoffset, parse_iso
|
||||
|
||||
|
||||
# =====================================================================
|
||||
|
@ -31,7 +25,8 @@ def parse(time_str):
|
|||
Arguments:
|
||||
time_str -- A formatted timestamp string.
|
||||
"""
|
||||
return parser.parse(time_str)
|
||||
return parse_iso(time_str)
|
||||
|
||||
|
||||
def format_date(time_obj):
|
||||
"""
|
||||
|
@ -52,7 +47,7 @@ def format_time(time_obj):
|
|||
Return a formatted string version of a time object.
|
||||
|
||||
format:
|
||||
hh:mm:ss[.sss][TZD
|
||||
hh:mm:ss[.sss][TZD]
|
||||
|
||||
arguments:
|
||||
time_obj -- A time or datetime object.
|
||||
|
|
|
@ -6,23 +6,7 @@
|
|||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sleekxmpp
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
HAVE_DATEUTIL = True
|
||||
try:
|
||||
import dateutil
|
||||
except:
|
||||
HAVE_DATEUTIL = False
|
||||
|
||||
|
||||
if HAVE_DATEUTIL:
|
||||
from sleekxmpp.plugins.xep_0202 import stanza
|
||||
from sleekxmpp.plugins.xep_0202.stanza import EntityTime
|
||||
from sleekxmpp.plugins.xep_0202.time import xep_0202
|
||||
else:
|
||||
log.warning("XEP-0202 requires the dateutil package")
|
||||
from sleekxmpp.plugins.xep_0202 import stanza
|
||||
from sleekxmpp.plugins.xep_0202.stanza import EntityTime
|
||||
from sleekxmpp.plugins.xep_0202.time import xep_0202
|
||||
|
|
|
@ -11,12 +11,7 @@ import datetime as dt
|
|||
|
||||
from sleekxmpp.xmlstream import ElementBase
|
||||
from sleekxmpp.plugins import xep_0082
|
||||
|
||||
try:
|
||||
from dateutil.tz import tzutc
|
||||
except:
|
||||
log = logging.getLogger(__name__)
|
||||
log.warning("XEP-0202 plugin requies dateutil package")
|
||||
from sleekxmpp.thirdparty import tzutc, tzoffset
|
||||
|
||||
|
||||
class EntityTime(ElementBase):
|
||||
|
|
1
sleekxmpp/thirdparty/__init__.py
vendored
1
sleekxmpp/thirdparty/__init__.py
vendored
|
@ -4,3 +4,4 @@ except:
|
|||
from sleekxmpp.thirdparty.ordereddict import OrderedDict
|
||||
|
||||
from sleekxmpp.thirdparty import suelta
|
||||
from sleekxmpp.thirdparty.mini_dateutil import tzutc, tzoffset, parse_iso
|
||||
|
|
267
sleekxmpp/thirdparty/mini_dateutil.py
vendored
Normal file
267
sleekxmpp/thirdparty/mini_dateutil.py
vendored
Normal file
|
@ -0,0 +1,267 @@
|
|||
# This module is a very stripped down version of the dateutil
|
||||
# package for when dateutil has not been installed. As a replacement
|
||||
# for dateutil.parser.parse, the parsing methods from
|
||||
# http://blog.mfabrik.com/2008/06/30/relativity-of-time-shortcomings-in-python-datetime-and-workaround/
|
||||
|
||||
#As such, the following copyrights and licenses applies:
|
||||
|
||||
|
||||
# dateutil - Extensions to the standard python 2.3+ datetime module.
|
||||
#
|
||||
# Copyright (c) 2003-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
# fixed_dateime
|
||||
#
|
||||
# Copyright (c) 2008, Red Innovation Ltd., Finland
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of Red Innovation nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY RED INNOVATION ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL RED INNOVATION BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
|
||||
import re
|
||||
import datetime
|
||||
|
||||
|
||||
ZERO = datetime.timedelta(0)
|
||||
|
||||
|
||||
try:
|
||||
from dateutil.parser import parse as parse_iso
|
||||
from dateutil.tz import tzoffset, tzutc
|
||||
except:
|
||||
# As a stopgap, define the two timezones here based
|
||||
# on the dateutil code.
|
||||
|
||||
class tzutc(datetime.tzinfo):
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return ZERO
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return "UTC"
|
||||
|
||||
def __eq__(self, other):
|
||||
return (isinstance(other, tzutc) or
|
||||
(isinstance(other, tzoffset) and other._offset == ZERO))
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s()" % self.__class__.__name__
|
||||
|
||||
__reduce__ = object.__reduce__
|
||||
|
||||
class tzoffset(datetime.tzinfo):
|
||||
|
||||
def __init__(self, name, offset):
|
||||
self._name = name
|
||||
self._offset = datetime.timedelta(seconds=offset)
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self._offset
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return self._name
|
||||
|
||||
def __eq__(self, other):
|
||||
return (isinstance(other, tzoffset) and
|
||||
self._offset == other._offset)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%s, %s)" % (self.__class__.__name__,
|
||||
repr(self._name),
|
||||
self._offset.days*86400+self._offset.seconds)
|
||||
|
||||
__reduce__ = object.__reduce__
|
||||
|
||||
|
||||
_fixed_offset_tzs = { }
|
||||
UTC = tzutc()
|
||||
|
||||
def _get_fixed_offset_tz(offsetmins):
|
||||
"""For internal use only: Returns a tzinfo with
|
||||
the given fixed offset. This creates only one instance
|
||||
for each offset; the zones are kept in a dictionary"""
|
||||
|
||||
if offsetmins == 0:
|
||||
return UTC
|
||||
|
||||
if not _fixed_offset_tzs.has_key(offsetmins):
|
||||
if offsetmins < 0:
|
||||
sign = '-'
|
||||
absoff = -offsetmins
|
||||
else:
|
||||
sign = '+'
|
||||
absoff = offsetmins
|
||||
|
||||
name = "UTC%s%02d:%02d" % (sign, int(absoff / 60), absoff % 60)
|
||||
inst = tzoffset(offsetmins, name)
|
||||
_fixed_offset_tzs[offsetmins] = inst
|
||||
|
||||
return _fixed_offset_tzs[offsetmins]
|
||||
|
||||
|
||||
_iso8601_parser = re.compile("""
|
||||
^
|
||||
(?P<year> [0-9]{4})?(?P<ymdsep>-?)?
|
||||
(?P<month>[0-9]{2})?(?P=ymdsep)?
|
||||
(?P<day> [0-9]{2})?
|
||||
|
||||
(?: # time part... optional... at least hour must be specified
|
||||
(?:T|\s+)?
|
||||
(?P<hour>[0-9]{2})
|
||||
(?:
|
||||
# minutes, separated with :, or none, from hours
|
||||
(?P<hmssep>[:]?)
|
||||
(?P<minute>[0-9]{2})
|
||||
(?:
|
||||
# same for seconds, separated with :, or none, from hours
|
||||
(?P=hmssep)
|
||||
(?P<second>[0-9]{2})
|
||||
)?
|
||||
)?
|
||||
|
||||
# fractions
|
||||
(?: [,.] (?P<frac>[0-9]{1,10}))?
|
||||
|
||||
# timezone, Z, +-hh or +-hh:?mm. MUST BE, but complain if not there.
|
||||
(
|
||||
(?P<tzempty>Z)
|
||||
|
|
||||
(?P<tzh>[+-][0-9]{2})
|
||||
(?: :? # optional separator
|
||||
(?P<tzm>[0-9]{2})
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
$
|
||||
""", re.X) # """
|
||||
|
||||
def parse_iso(timestamp):
|
||||
"""Internal function for parsing a timestamp in
|
||||
ISO 8601 format"""
|
||||
|
||||
timestamp = timestamp.strip()
|
||||
|
||||
m = _iso8601_parser.match(timestamp)
|
||||
if not m:
|
||||
raise ValueError("Not a proper ISO 8601 timestamp!: %s" % timestamp)
|
||||
|
||||
vals = m.groupdict()
|
||||
def_vals = {'year': 1970, 'month': 1, 'day': 1}
|
||||
for key in vals:
|
||||
if vals[key] is None:
|
||||
vals[key] = def_vals.get(key, 0)
|
||||
elif key not in ['ymdsep', 'hmssep', 'tzempty']:
|
||||
vals[key] = int(vals[key])
|
||||
|
||||
year = vals['year']
|
||||
month = vals['month']
|
||||
day = vals['day']
|
||||
|
||||
h, min, s, us = None, None, None, 0
|
||||
frac = 0
|
||||
if m.group('tzempty') == None and m.group('tzh') == None:
|
||||
raise ValueError("Not a proper ISO 8601 timestamp: " +
|
||||
"missing timezone (Z or +hh[:mm])!")
|
||||
|
||||
if m.group('frac'):
|
||||
frac = m.group('frac')
|
||||
power = len(frac)
|
||||
frac = long(frac) / 10.0 ** power
|
||||
|
||||
if m.group('hour'):
|
||||
h = vals['hour']
|
||||
|
||||
if m.group('minute'):
|
||||
min = vals['minute']
|
||||
|
||||
if m.group('second'):
|
||||
s = vals['second']
|
||||
|
||||
if frac != None:
|
||||
# ok, fractions of hour?
|
||||
if min == None:
|
||||
frac, min = _math.modf(frac * 60.0)
|
||||
min = int(min)
|
||||
|
||||
# fractions of second?
|
||||
if s == None:
|
||||
frac, s = _math.modf(frac * 60.0)
|
||||
s = int(s)
|
||||
|
||||
# and extract microseconds...
|
||||
us = int(frac * 1000000)
|
||||
|
||||
if m.group('tzempty') == 'Z':
|
||||
offsetmins = 0
|
||||
else:
|
||||
# timezone: hour diff with sign
|
||||
offsetmins = vals['tzh'] * 60
|
||||
tzm = m.group('tzm')
|
||||
|
||||
# add optional minutes
|
||||
if tzm != None:
|
||||
tzm = long(tzm)
|
||||
offsetmins += tzm if offsetmins > 0 else -tzm
|
||||
|
||||
tz = _get_fixed_offset_tz(offsetmins)
|
||||
return datetime.datetime(year, month, day, h, min, s, us, tz)
|
Loading…
Reference in a new issue