kopia lustrzana https://github.com/collective/icalendar
rodzic
eb0348676b
commit
cb2ccaa049
|
@ -6,7 +6,7 @@ Changelog
|
|||
|
||||
Minor changes:
|
||||
|
||||
- Refactored parser.py. Ref: #483 [pronoym99]
|
||||
- Refactored prop.py. Ref: #482 [pronoym99]
|
||||
|
||||
- Calendar.from_ical no longer throws long errors
|
||||
Ref: #473
|
||||
|
|
|
@ -90,6 +90,7 @@ DSTDIFF = DSTOFFSET - STDOFFSET
|
|||
class FixedOffset(tzinfo):
|
||||
"""Fixed offset in minutes east from UTC.
|
||||
"""
|
||||
|
||||
def __init__(self, offset, name):
|
||||
self.__offset = timedelta(minutes=offset)
|
||||
self.__name = name
|
||||
|
@ -107,17 +108,12 @@ class FixedOffset(tzinfo):
|
|||
class LocalTimezone(tzinfo):
|
||||
"""Timezone of the machine where the code is running.
|
||||
"""
|
||||
|
||||
def utcoffset(self, dt):
|
||||
if self._isdst(dt):
|
||||
return DSTOFFSET
|
||||
else:
|
||||
return STDOFFSET
|
||||
return DSTOFFSET if self._isdst(dt) else STDOFFSET
|
||||
|
||||
def dst(self, dt):
|
||||
if self._isdst(dt):
|
||||
return DSTDIFF
|
||||
else:
|
||||
return ZERO
|
||||
return DSTDIFF if self._isdst(dt) else ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return _time.tzname[self._isdst(dt)]
|
||||
|
@ -140,7 +136,7 @@ class vBinary:
|
|||
self.params = Parameters(encoding='BASE64', value="BINARY")
|
||||
|
||||
def __repr__(self):
|
||||
return "vBinary('%s')" % self.to_ical()
|
||||
return f"vBinary('{self.to_ical()}')"
|
||||
|
||||
def to_ical(self):
|
||||
return binascii.b2a_base64(self.obj.encode('utf-8'))[:-1]
|
||||
|
@ -164,16 +160,14 @@ class vBoolean(int):
|
|||
return self
|
||||
|
||||
def to_ical(self):
|
||||
if self:
|
||||
return b'TRUE'
|
||||
return b'FALSE'
|
||||
return b'TRUE' if self else b'FALSE'
|
||||
|
||||
@classmethod
|
||||
def from_ical(cls, ical):
|
||||
try:
|
||||
return cls.BOOL_MAP[ical]
|
||||
except Exception:
|
||||
raise ValueError("Expected 'TRUE' or 'FALSE'. Got %s" % ical)
|
||||
raise ValueError(f"Expected 'TRUE' or 'FALSE'. Got {ical}")
|
||||
|
||||
|
||||
class vCalAddress(str):
|
||||
|
@ -186,7 +180,7 @@ class vCalAddress(str):
|
|||
return self
|
||||
|
||||
def __repr__(self):
|
||||
return "vCalAddress('%s')" % self.to_ical()
|
||||
return f"vCalAddress('{self.to_ical()}')"
|
||||
|
||||
def to_ical(self):
|
||||
return self.encode(DEFAULT_ENCODING)
|
||||
|
@ -212,7 +206,7 @@ class vFloat(float):
|
|||
try:
|
||||
return cls(ical)
|
||||
except Exception:
|
||||
raise ValueError('Expected float value, got: %s' % ical)
|
||||
raise ValueError(f'Expected float value, got: {ical}')
|
||||
|
||||
|
||||
class vInt(int):
|
||||
|
@ -231,12 +225,13 @@ class vInt(int):
|
|||
try:
|
||||
return cls(ical)
|
||||
except Exception:
|
||||
raise ValueError('Expected int, got: %s' % ical)
|
||||
raise ValueError(f'Expected int, got: {ical}')
|
||||
|
||||
|
||||
class vDDDLists:
|
||||
"""A list of vDDDTypes values.
|
||||
"""
|
||||
|
||||
def __init__(self, dt_list):
|
||||
if not hasattr(dt_list, '__iter__'):
|
||||
dt_list = [dt_list]
|
||||
|
@ -265,6 +260,7 @@ class vDDDLists:
|
|||
out.append(vDDDTypes.from_ical(ical_dt, timezone=timezone))
|
||||
return out
|
||||
|
||||
|
||||
class vCategory:
|
||||
|
||||
def __init__(self, c_list):
|
||||
|
@ -287,6 +283,7 @@ class vDDDTypes:
|
|||
cannot be confused, and often values can be of either types.
|
||||
So this is practical.
|
||||
"""
|
||||
|
||||
def __init__(self, dt):
|
||||
if not isinstance(dt, (datetime, date, timedelta, time, tuple)):
|
||||
raise ValueError('You must use datetime, date, timedelta, '
|
||||
|
@ -346,13 +343,14 @@ class vDDDTypes:
|
|||
return vTime.from_ical(ical)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Expected datetime, date, or time, got: '%s'" % ical
|
||||
f"Expected datetime, date, or time, got: '{ical}'"
|
||||
)
|
||||
|
||||
|
||||
class vDate:
|
||||
"""Render and generates iCalendar date format.
|
||||
"""
|
||||
|
||||
def __init__(self, dt):
|
||||
if not isinstance(dt, date):
|
||||
raise ValueError('Value MUST be a date instance')
|
||||
|
@ -360,7 +358,7 @@ class vDate:
|
|||
self.params = Parameters({'value': 'DATE'})
|
||||
|
||||
def to_ical(self):
|
||||
s = "%04d%02d%02d" % (self.dt.year, self.dt.month, self.dt.day)
|
||||
s = f"{self.dt.year:04}{self.dt.month:02}{self.dt.day:02}"
|
||||
return s.encode('utf-8')
|
||||
|
||||
@staticmethod
|
||||
|
@ -373,7 +371,7 @@ class vDate:
|
|||
)
|
||||
return date(*timetuple)
|
||||
except Exception:
|
||||
raise ValueError('Wrong date format %s' % ical)
|
||||
raise ValueError(f'Wrong date format {ical}')
|
||||
|
||||
|
||||
class vDatetime:
|
||||
|
@ -387,6 +385,7 @@ class vDatetime:
|
|||
created. Be aware that there are certain limitations with timezone naive
|
||||
DATE-TIME components in the icalendar standard.
|
||||
"""
|
||||
|
||||
def __init__(self, dt):
|
||||
self.dt = dt
|
||||
self.params = Parameters()
|
||||
|
@ -395,14 +394,7 @@ class vDatetime:
|
|||
dt = self.dt
|
||||
tzid = tzid_from_dt(dt)
|
||||
|
||||
s = "%04d%02d%02dT%02d%02d%02d" % (
|
||||
dt.year,
|
||||
dt.month,
|
||||
dt.day,
|
||||
dt.hour,
|
||||
dt.minute,
|
||||
dt.second
|
||||
)
|
||||
s = f"{dt.year:04}{dt.month:02}{dt.day:02}T{dt.hour:02}{dt.minute:02}{dt.second:02}"
|
||||
if tzid == 'UTC':
|
||||
s += "Z"
|
||||
elif tzid:
|
||||
|
@ -417,7 +409,8 @@ class vDatetime:
|
|||
tzinfo = pytz.timezone(timezone.strip('/'))
|
||||
except pytz.UnknownTimeZoneError:
|
||||
if timezone in WINDOWS_TO_OLSON:
|
||||
tzinfo = pytz.timezone(WINDOWS_TO_OLSON.get(timezone.strip('/')))
|
||||
tzinfo = pytz.timezone(
|
||||
WINDOWS_TO_OLSON.get(timezone.strip('/')))
|
||||
else:
|
||||
tzinfo = _timezone_cache.get(timezone, None)
|
||||
|
||||
|
@ -439,7 +432,7 @@ class vDatetime:
|
|||
else:
|
||||
raise ValueError(ical)
|
||||
except Exception:
|
||||
raise ValueError('Wrong datetime format: %s' % ical)
|
||||
raise ValueError(f'Wrong datetime format: {ical}')
|
||||
|
||||
|
||||
class vDuration:
|
||||
|
@ -466,18 +459,18 @@ class vDuration:
|
|||
minutes = td.seconds % 3600 // 60
|
||||
seconds = td.seconds % 60
|
||||
if hours:
|
||||
timepart += "%dH" % hours
|
||||
timepart += f"{hours}H"
|
||||
if minutes or (hours and seconds):
|
||||
timepart += "%dM" % minutes
|
||||
timepart += f"{minutes}M"
|
||||
if seconds:
|
||||
timepart += "%dS" % seconds
|
||||
timepart += f"{seconds}S"
|
||||
if td.days == 0 and timepart:
|
||||
return (str(sign).encode('utf-8') + b'P' +
|
||||
str(timepart).encode('utf-8'))
|
||||
return (str(sign).encode('utf-8') + b'P'
|
||||
+ str(timepart).encode('utf-8'))
|
||||
else:
|
||||
return (str(sign).encode('utf-8') + b'P' +
|
||||
str(abs(td.days)).encode('utf-8') +
|
||||
b'D' + str(timepart).encode('utf-8'))
|
||||
return (str(sign).encode('utf-8') + b'P'
|
||||
+ str(abs(td.days)).encode('utf-8')
|
||||
+ b'D' + str(timepart).encode('utf-8'))
|
||||
|
||||
@staticmethod
|
||||
def from_ical(ical):
|
||||
|
@ -495,19 +488,20 @@ class vDuration:
|
|||
value = -value
|
||||
return value
|
||||
except Exception:
|
||||
raise ValueError('Invalid iCalendar duration: %s' % ical)
|
||||
raise ValueError(f'Invalid iCalendar duration: {ical}')
|
||||
|
||||
|
||||
class vPeriod:
|
||||
"""A precise period of time.
|
||||
"""
|
||||
|
||||
def __init__(self, per):
|
||||
start, end_or_duration = per
|
||||
if not (isinstance(start, datetime) or isinstance(start, date)):
|
||||
raise ValueError('Start value MUST be a datetime or date instance')
|
||||
if not (isinstance(end_or_duration, datetime) or
|
||||
isinstance(end_or_duration, date) or
|
||||
isinstance(end_or_duration, timedelta)):
|
||||
if not (isinstance(end_or_duration, datetime)
|
||||
or isinstance(end_or_duration, date)
|
||||
or isinstance(end_or_duration, timedelta)):
|
||||
raise ValueError('end_or_duration MUST be a datetime, '
|
||||
'date or timedelta instance')
|
||||
by_duration = 0
|
||||
|
@ -535,7 +529,8 @@ class vPeriod:
|
|||
|
||||
def __cmp__(self, other):
|
||||
if not isinstance(other, vPeriod):
|
||||
raise NotImplementedError('Cannot compare vPeriod with %r' % other)
|
||||
raise NotImplementedError(
|
||||
f'Cannot compare vPeriod with {other!r}')
|
||||
return cmp((self.start, self.end), (other.start, other.end))
|
||||
|
||||
def overlaps(self, other):
|
||||
|
@ -547,10 +542,10 @@ class vPeriod:
|
|||
|
||||
def to_ical(self):
|
||||
if self.by_duration:
|
||||
return (vDatetime(self.start).to_ical() + b'/' +
|
||||
vDuration(self.duration).to_ical())
|
||||
return (vDatetime(self.start).to_ical() + b'/' +
|
||||
vDatetime(self.end).to_ical())
|
||||
return (vDatetime(self.start).to_ical() + b'/'
|
||||
+ vDuration(self.duration).to_ical())
|
||||
return (vDatetime(self.start).to_ical() + b'/'
|
||||
+ vDatetime(self.end).to_ical())
|
||||
|
||||
@staticmethod
|
||||
def from_ical(ical):
|
||||
|
@ -560,7 +555,7 @@ class vPeriod:
|
|||
end_or_duration = vDDDTypes.from_ical(end_or_duration)
|
||||
return (start, end_or_duration)
|
||||
except Exception:
|
||||
raise ValueError('Expected period format, got: %s' % ical)
|
||||
raise ValueError(f'Expected period format, got: {ical}')
|
||||
|
||||
def __repr__(self):
|
||||
if self.by_duration:
|
||||
|
@ -582,13 +577,13 @@ class vWeekday(str):
|
|||
self = super().__new__(cls, value)
|
||||
match = WEEKDAY_RULE.match(self)
|
||||
if match is None:
|
||||
raise ValueError('Expected weekday abbrevation, got: %s' % self)
|
||||
raise ValueError(f'Expected weekday abbrevation, got: {self}')
|
||||
match = match.groupdict()
|
||||
sign = match['signal']
|
||||
weekday = match['weekday']
|
||||
relative = match['relative']
|
||||
if weekday not in vWeekday.week_days or sign not in '+-':
|
||||
raise ValueError('Expected weekday abbrevation, got: %s' % self)
|
||||
raise ValueError(f'Expected weekday abbrevation, got: {self}')
|
||||
self.relative = relative and int(relative) or None
|
||||
self.params = Parameters()
|
||||
return self
|
||||
|
@ -601,7 +596,7 @@ class vWeekday(str):
|
|||
try:
|
||||
return cls(ical.upper())
|
||||
except Exception:
|
||||
raise ValueError('Expected weekday abbrevation, got: %s' % ical)
|
||||
raise ValueError(f'Expected weekday abbrevation, got: {ical}')
|
||||
|
||||
|
||||
class vFrequency(str):
|
||||
|
@ -622,7 +617,7 @@ class vFrequency(str):
|
|||
value = to_unicode(value, encoding=encoding)
|
||||
self = super().__new__(cls, value)
|
||||
if self not in vFrequency.frequencies:
|
||||
raise ValueError('Expected frequency, got: %s' % self)
|
||||
raise ValueError(f'Expected frequency, got: {self}')
|
||||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
|
@ -634,7 +629,7 @@ class vFrequency(str):
|
|||
try:
|
||||
return cls(ical.upper())
|
||||
except Exception:
|
||||
raise ValueError('Expected frequency, got: %s' % ical)
|
||||
raise ValueError(f'Expected frequency, got: {ical}')
|
||||
|
||||
|
||||
class vRecur(CaselessDict):
|
||||
|
@ -708,7 +703,7 @@ class vRecur(CaselessDict):
|
|||
recur[key] = cls.parse_type(key, vals)
|
||||
return dict(recur)
|
||||
except Exception:
|
||||
raise ValueError('Error in recurrence rule: %s' % ical)
|
||||
raise ValueError(f'Error in recurrence rule: {ical}')
|
||||
|
||||
|
||||
class vText(str):
|
||||
|
@ -723,7 +718,7 @@ class vText(str):
|
|||
return self
|
||||
|
||||
def __repr__(self):
|
||||
return "vText('%s')" % self.to_ical()
|
||||
return f"vText('{self.to_ical()}')"
|
||||
|
||||
def to_ical(self):
|
||||
return escape_char(self).encode(self.encoding)
|
||||
|
@ -741,7 +736,7 @@ class vTime:
|
|||
def __init__(self, *args):
|
||||
if len(args) == 1:
|
||||
if not isinstance(args[0], (time, datetime)):
|
||||
raise ValueError('Expected a datetime.time, got: %s' % args[0])
|
||||
raise ValueError(f'Expected a datetime.time, got: {args[0]}')
|
||||
self.dt = args[0]
|
||||
else:
|
||||
self.dt = time(*args)
|
||||
|
@ -757,7 +752,7 @@ class vTime:
|
|||
timetuple = (int(ical[:2]), int(ical[2:4]), int(ical[4:6]))
|
||||
return time(*timetuple)
|
||||
except Exception:
|
||||
raise ValueError('Expected time, got: %s' % ical)
|
||||
raise ValueError(f'Expected time, got: {ical}')
|
||||
|
||||
|
||||
class vUri(str):
|
||||
|
@ -778,7 +773,7 @@ class vUri(str):
|
|||
try:
|
||||
return cls(ical)
|
||||
except Exception:
|
||||
raise ValueError('Expected , got: %s' % ical)
|
||||
raise ValueError(f'Expected , got: {ical}')
|
||||
|
||||
|
||||
class vGeo:
|
||||
|
@ -806,7 +801,7 @@ class vGeo:
|
|||
latitude, longitude = ical.split(';')
|
||||
return (float(latitude), float(longitude))
|
||||
except Exception:
|
||||
raise ValueError("Expected 'float;float' , got: %s" % ical)
|
||||
raise ValueError(f"Expected 'float;float' , got: {ical}")
|
||||
|
||||
|
||||
class vUTCOffset:
|
||||
|
@ -814,9 +809,9 @@ class vUTCOffset:
|
|||
"""
|
||||
|
||||
ignore_exceptions = False # if True, and we cannot parse this
|
||||
# component, we will silently ignore
|
||||
# it, rather than let the exception
|
||||
# propagate upwards
|
||||
# component, we will silently ignore
|
||||
# it, rather than let the exception
|
||||
# propagate upwards
|
||||
|
||||
def __init__(self, td):
|
||||
if not isinstance(td, timedelta):
|
||||
|
@ -840,9 +835,9 @@ class vUTCOffset:
|
|||
minutes = abs((seconds % 3600) // 60)
|
||||
seconds = abs(seconds % 60)
|
||||
if seconds:
|
||||
duration = '%02i%02i%02i' % (hours, minutes, seconds)
|
||||
duration = f'{hours:02}{minutes:02}{seconds:02}'
|
||||
else:
|
||||
duration = '%02i%02i' % (hours, minutes)
|
||||
duration = f'{hours:02}{minutes:02}'
|
||||
return sign % duration
|
||||
|
||||
@classmethod
|
||||
|
@ -856,10 +851,10 @@ class vUTCOffset:
|
|||
int(ical[5:7] or 0))
|
||||
offset = timedelta(hours=hours, minutes=minutes, seconds=seconds)
|
||||
except Exception:
|
||||
raise ValueError('Expected utc offset, got: %s' % ical)
|
||||
raise ValueError(f'Expected utc offset, got: {ical}')
|
||||
if not cls.ignore_exceptions and offset >= timedelta(hours=24):
|
||||
raise ValueError(
|
||||
'Offset must be less than 24 hours, was %s' % ical)
|
||||
f'Offset must be less than 24 hours, was {ical}')
|
||||
if sign == '-':
|
||||
return -offset
|
||||
return offset
|
||||
|
|
Ładowanie…
Reference in New Issue