Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update khal to Follow PEP495 Removing Deprecation Warnings #1093

Draft
wants to merge 23 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
89d2413
Changed locale to use the method suggested by the deprecation warning…
pjkaufman Oct 22, 2021
5cd5ede
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 23, 2021
78d8121
updated setup requirements
pjkaufman Oct 23, 2021
3f418f3
fix setup dependency
pjkaufman Oct 24, 2021
7ed5d7a
preliminary setup for the changes which still needs TZID value fix an…
pjkaufman Nov 3, 2021
c5bcc14
fixed an issue with incorrectly using a module to initialize a zone i…
pjkaufman Nov 3, 2021
c934868
Changed locale to use the method suggested by the deprecation warning…
pjkaufman Oct 22, 2021
1fc2a33
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 23, 2021
30d913a
updated setup requirements
pjkaufman Oct 23, 2021
e1b7732
fix setup dependency
pjkaufman Oct 24, 2021
fa43f9b
preliminary setup for the changes which still needs TZID value fix an…
pjkaufman Nov 3, 2021
76a2e1f
fixed an issue with incorrectly using a module to initialize a zone i…
pjkaufman Nov 3, 2021
775218c
adding rebased info to fix merge conflicts
pjkaufman Jun 1, 2022
a0dc1c7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 1, 2022
d9db0bb
updated the way we get the transition times, but have no way to verif…
pjkaufman Jun 1, 2022
e7221c9
some import cleanup and a revert of logic to get back to the old logi…
pjkaufman Jun 1, 2022
a800bb7
add pytz to hopefully get rid of code complaint
pjkaufman Jun 1, 2022
51b3f5b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 1, 2022
22b6df6
updated imports as per comments on the PR and it will hopefully fix s…
pjkaufman Jun 1, 2022
87bf616
updated imports as per comments on the PR and it will hopefully fix s…
pjkaufman Jun 1, 2022
2bfa4e6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 1, 2022
79f69d8
updated imports as per precommit and fixed a line length issue
pjkaufman Jun 1, 2022
8590bcb
udoing a line length issue fix due to indentation error
pjkaufman Jun 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ Simon Crespeau - simon [at] art-e-toile [dot] com - https://www.art-e-toile.com
Fred Thomsen - me [at] fredthomsen [dot] net - http://fredthomsen.net
Robin Schubert
Axel Gschaider - axel.gschaider [at] posteo [dot] de
Peter Kaufman
19 changes: 12 additions & 7 deletions khal/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
from shutil import get_terminal_size
from typing import Iterable, List, Tuple

import pytz
try:
import zoneinfo as ZoneInfo
from zoneinfo import ZoneInfoNotFoundError
except ImportError: # I am not sure if this is correct for the backport
from backports.zoneinfo import ZoneInfo
from backports.zoneinfo import ZoneInfoNotFoundError
from click import confirm, echo, prompt, style

from khal import (__productname__, __version__, calendar_display,
Expand Down Expand Up @@ -188,8 +193,8 @@ def get_events_between(
env = {}
assert start
assert end
start_local = locale['local_timezone'].localize(start)
end_local = locale['local_timezone'].localize(end)
start_local = start.replace(tzinfo=ZoneInfo.ZoneInfo(str(locale['local_timezone'])))
end_local = end.replace(tzinfo=ZoneInfo.ZoneInfo(str(locale['local_timezone'])))

start = start_local.replace(tzinfo=None)
end = end_local.replace(tzinfo=None)
Expand Down Expand Up @@ -278,7 +283,7 @@ def khal_list(
if env is None:
env = {}

original_start = conf['locale']['local_timezone'].localize(start)
original_start = start.replace(tzinfo=ZoneInfo.ZoneInfo(str(conf['locale']['local_timezone'])))
while start < end:
if start.date() == end.date():
day_end = end
Expand Down Expand Up @@ -343,10 +348,10 @@ def new_interactive(collection, calendar_name, conf, info, location=None,
tz = info.get('timezone') or conf['locale']['default_timezone']
timezone = prompt("timezone", default=str(tz))
try:
tz = pytz.timezone(timezone)
tz = ZoneInfo.ZoneInfo(str(timezone))
info['timezone'] = tz
break
except pytz.UnknownTimeZoneError:
except ZoneInfoNotFoundError:
echo("unknown timezone")

info['description'] = prompt("description (or 'None')", default=info.get('description'))
Expand Down Expand Up @@ -552,7 +557,7 @@ def edit(collection, search_string, locale, format=None, allow_past=False, conf=
format = conf['view']['event_format']

term_width, _ = get_terminal_size()
now = conf['locale']['local_timezone'].localize(dt.datetime.now())
now = dt.datetime.now(tz=ZoneInfo.ZoneInfo(str(conf['locale']['local_timezone'])))

events = sorted(collection.search(search_string))
for event in events:
Expand Down
25 changes: 15 additions & 10 deletions khal/icalendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,18 @@
"""collection of icalendar helper functions"""

import datetime as dt

try:
from zoneinfo import ZoneInfo
except ImportError:
from backports.zoneinfo import ZoneInfo

import logging
from collections import defaultdict
from hashlib import sha256

import dateutil.rrule
import icalendar
import pytz

from .exceptions import UnsupportedRecurrence
from .parse_datetime import guesstimedeltafstr, rrulefstr
Expand Down Expand Up @@ -109,8 +114,9 @@ def new_event(locale, dtstart=None, dtend=None, summary=None, timezone=None,
raise ValueError("no summary given")

if not allday and timezone is not None:
dtstart = timezone.localize(dtstart)
dtend = timezone.localize(dtend)
timezone_info = ZoneInfo(str(timezone))
dtstart = dtstart.replace(tzinfo=timezone_info)
dtend = dtend.replace(tzinfo=timezone_info)

event = icalendar.Event()
event.add('dtstart', dtstart)
Expand Down Expand Up @@ -190,7 +196,7 @@ def ics_from_list(events, tzs, random_uid=False, default_timezone=None):
"using default timezone. This can lead to erroneous time shifts"
)
missing_tz.add(item.params['TZID'])
elif datetime_.tzinfo and datetime_.tzinfo != pytz.UTC and \
elif datetime_.tzinfo and datetime_.tzinfo != ZoneInfo("UTC") and \
datetime_.tzinfo not in needed_tz:
needed_tz.add(datetime_.tzinfo)

Expand Down Expand Up @@ -242,7 +248,7 @@ def sanitize_datetime(date):
if allday and isinstance(date, dt.datetime):
date = date.date()
if events_tz is not None:
date = events_tz.localize(date)
date = date.replace(tzinfo=ZoneInfo(str(events_tz)))
return date

rrule_param = vevent.get('RRULE')
Expand Down Expand Up @@ -271,8 +277,7 @@ def sanitize_datetime(date):
rrule._until = dt.datetime(2037, 12, 31)
else:
if events_tz and 'Z' in rrule_param.to_ical().decode():
rrule._until = pytz.UTC.localize(
rrule._until).astimezone(events_tz).replace(tzinfo=None)
rrule._until = rrule._until.replace(tzinfo=ZoneInfo("UTC")).astimezone(events_tz).replace(tzinfo=None)

# rrule._until and dtstart could be dt.date or dt.datetime. They
# need to be the same for comparison
Expand Down Expand Up @@ -376,7 +381,7 @@ def sanitize(vevent, default_timezone, href='', calendar=''):
for prop in ['DTSTART', 'DTEND', 'DUE', 'RECURRENCE-ID']:
if prop in vevent and invalid_timezone(vevent[prop]):
timezone = vevent[prop].params.get('TZID')
value = default_timezone.localize(vevent.pop(prop).dt)
value = vevent.pop(prop).dt.replace(tzinfo=default_timezone)
vevent.add(prop, value)
logger.warning(
f"{prop} localized in invalid or incomprehensible timezone "
Expand Down Expand Up @@ -411,13 +416,13 @@ def sanitize_timerange(dtstart, dtend, duration=None):
"Event end time has no timezone. "
"Assuming it's the same timezone as the start time"
)
dtend = dtstart.tzinfo.localize(dtend)
dtend = dtend.replace(tzinfo=ZoneInfo(str(dtstart.tzinfo)))
if not dtstart.tzinfo and dtend.tzinfo:
logger.warning(
"Event start time has no timezone. "
"Assuming it's the same timezone as the end time"
)
dtstart = dtend.tzinfo.localize(dtstart)
dtstart = dtstart.replace(tzinfo=ZoneInfo(str(dtend.tzinfo)))

if dtend is None and duration is None:
if isinstance(dtstart, dt.datetime):
Expand Down
17 changes: 12 additions & 5 deletions khal/khalendar/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,19 @@

import contextlib
import datetime as dt

try:
from zoneinfo import ZoneInfo
except ImportError:
from backports.zoneinfo import ZoneInfo

import logging
import sqlite3
from enum import IntEnum
from os import makedirs, path
from typing import Any, Dict, Iterable, List, Optional, Tuple

import icalendar
import pytz
from dateutil import parser

from .. import utils
Expand Down Expand Up @@ -509,9 +514,10 @@ def get_localized(self, start, end) \
'ORDER BY dtstart')
stuple = tuple([start, end, start, end, start, end] + list(self.calendars))
result = self.sql_ex(sql_s.format(','.join(["?"] * len(self.calendars))), stuple)
utc = ZoneInfo('UTC')
for item, href, start, end, ref, etag, _dtype, calendar in result:
start = pytz.UTC.localize(dt.datetime.utcfromtimestamp(start))
end = pytz.UTC.localize(dt.datetime.utcfromtimestamp(end))
start = dt.datetime.utcfromtimestamp(start).replace(tzinfo=utc)
end = dt.datetime.utcfromtimestamp(end).replace(tzinfo=utc)
yield item, href, start, end, ref, etag, calendar

def get_floating_calendars(self, start: dt.datetime, end: dt.datetime) -> Iterable[str]:
Expand Down Expand Up @@ -584,9 +590,10 @@ def search(self, search_string: str) \
)
stuple = tuple([f'%{search_string}%'] + list(self.calendars))
result = self.sql_ex(sql_s.format(','.join(["?"] * len(self.calendars))), stuple)
utc = ZoneInfo('UTC')
for item, href, start, end, ref, etag, dtype, calendar in result:
start = pytz.UTC.localize(dt.datetime.utcfromtimestamp(start))
end = pytz.UTC.localize(dt.datetime.utcfromtimestamp(end))
start = dt.datetime.utcfromtimestamp(start).replace(tzinfo=utc)
end = dt.datetime.utcfromtimestamp(end).replace(tzinfo=utc)
if dtype == EventType.DATE:
start = start.date()
end = end.date()
Expand Down
72 changes: 36 additions & 36 deletions khal/khalendar/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@
helper functions."""

import datetime as dt

try:
from zoneinfo import ZoneInfo
except ImportError:
from backports.zoneinfo import ZoneInfo

import logging
import os

import icalendar
import pytz
from click import style

from ..exceptions import FatalError
Expand Down Expand Up @@ -126,7 +131,8 @@ def fromVEvents(cls, events_list, ref=None, **kwargs):
if 'RECURRENCE-ID' in event:
if invalid_timezone(event['RECURRENCE-ID']):
default_timezone = kwargs['locale']['default_timezone']
recur_id = default_timezone.localize(event['RECURRENCE-ID'].dt)
recur_id = event['RECURRENCE-ID'].dt.replace(
tzinfo=ZoneInfo(str(default_timezone)))
ident = str(to_unix_time(recur_id))
else:
ident = str(to_unix_time(event['RECURRENCE-ID'].dt))
Expand Down Expand Up @@ -257,7 +263,7 @@ def recurrence_id(self):
if self.ref == 'PROTO':
return self.start
else:
return pytz.UTC.localize(dt.datetime.utcfromtimestamp(int(self.ref)))
return dt.datetime.utcfromtimestamp(int(self.ref)).replace(tzinfo=ZoneInfo("UTC"))

def increment_sequence(self):
"""update the SEQUENCE number, call before saving this event"""
Expand Down Expand Up @@ -377,7 +383,7 @@ def raw(self):
tzs.append(vevent['DTEND'].dt.tzinfo)

for tzinfo in tzs:
if tzinfo == pytz.UTC:
if tzinfo == ZoneInfo("UTC"):
continue
timezone = create_timezone(tzinfo, self.start)
calendar.add_component(timezone)
Expand Down Expand Up @@ -566,6 +572,7 @@ def format(self, format_string, relative_to, env=None, colors=True):
except TypeError:
relative_to_start = relative_to_end = relative_to

local_locale = ZoneInfo(str(self._locale['local_timezone']))
if isinstance(relative_to_end, dt.datetime):
relative_to_end = relative_to_end.date()
if isinstance(relative_to_start, dt.datetime):
Expand All @@ -575,17 +582,11 @@ def format(self, format_string, relative_to, env=None, colors=True):
start_local_datetime = self.start_local
end_local_datetime = self.end_local
else:
start_local_datetime = self._locale['local_timezone'].localize(
dt.datetime.combine(self.start, dt.time.min))
end_local_datetime = self._locale['local_timezone'].localize(
dt.datetime.combine(self.end, dt.time.min))
start_local_datetime = dt.datetime.combine(self.start, dt.time.min, local_locale)
WhyNotHugo marked this conversation as resolved.
Show resolved Hide resolved
end_local_datetime = dt.datetime.combine(self.end, dt.time.min, local_locale)

day_start = self._locale['local_timezone'].localize(
dt.datetime.combine(relative_to_start, dt.time.min),
)
day_end = self._locale['local_timezone'].localize(
dt.datetime.combine(relative_to_end, dt.time.max),
)
day_start = dt.datetime.combine(relative_to_start, dt.time.min, local_locale)
day_end = dt.datetime.combine(relative_to_end, dt.time.max, local_locale)
next_day_start = day_start + dt.timedelta(days=1)

allday = isinstance(self, AllDayEvent)
Expand Down Expand Up @@ -792,12 +793,12 @@ def __init__(self, *args, **kwargs):
if is_aware(self._start):
self._start = self._start.astimezone(starttz)
else:
self._start = starttz.localize(self._start)
self._start = self._start.replace(tzinfo=ZoneInfo(str(starttz)))

if is_aware(self._end):
self._end = self._end.astimezone(endtz)
else:
self._end = endtz.localize(self._end)
self._end = self._end.replace(tzinfo=ZoneInfo(str(endtz)))

@property
def start_local(self):
Expand All @@ -821,11 +822,11 @@ class FloatingEvent(DatetimeEvent):

@property
def start_local(self):
return self._locale['local_timezone'].localize(self.start)
return self.start.replace(tzinfo=ZoneInfo(str(self._locale['local_timezone'])))

@property
def end_local(self):
return self._locale['local_timezone'].localize(self.end)
return self.end.replace(tzinfo=ZoneInfo(str(self._locale['local_timezone'])))


class AllDayEvent(Event):
Expand Down Expand Up @@ -881,16 +882,9 @@ def create_timezone(tz, first_date=None, last_date=None):
easy solution, we'd really need to ship another version of the OLSON DB.

"""
if isinstance(tz, pytz.tzinfo.StaticTzInfo):
return _create_timezone_static(tz)

# TODO last_date = None, recurring to infinity

first_date = dt.datetime.today() if not first_date else to_naive_utc(first_date)
last_date = dt.datetime.today() if not last_date else to_naive_utc(last_date)
timezone = icalendar.Timezone()
timezone.add('TZID', tz)

dst = {
one[2]: 'DST' in two.__repr__()
for one, two in iter(tz._tzinfos.items())
Expand All @@ -900,11 +894,17 @@ def create_timezone(tz, first_date=None, last_date=None):
for one, two in iter(tz._tzinfos.items())
}

# looking for the first and last transition time we need to include
first_num, last_num = 0, len(tz._utc_transition_times) - 1
first_tt = tz._utc_transition_times[0]
last_tt = tz._utc_transition_times[-1]
for num, transtime in enumerate(tz._utc_transition_times):
if first_date.dst() == dt.timedelta(0) and first_date.replace(fold=1).dst() == dt.timedelta(0):
return _create_timezone_static(tz)

last_date = dt.datetime.today() if not last_date else to_naive_utc(last_date)
timezone = icalendar.Timezone()
timezone.add('TZID', tz)

first_num, last_num = 0, len(tz._trans_utc) - 1
first_tt = tz._trans_utc[0]
last_tt = tz._trans_utc[-1]
for num, transtime in enumerate(tz._trans_utc):
if transtime > first_tt and transtime < first_date:
first_num = num
first_tt = transtime
Expand All @@ -914,9 +914,9 @@ def create_timezone(tz, first_date=None, last_date=None):

timezones = {}
for num in range(first_num, last_num + 1):
name = tz._transition_info[num][2]
name = tz._ttinfos[num][2]
if name in timezones:
ttime = tz.fromutc(tz._utc_transition_times[num]).replace(tzinfo=None)
ttime = tz.fromutc(tz._trans_utc[num]).replace(tzinfo=None)
if 'RDATE' in timezones[name]:
timezones[name]['RDATE'].dts.append(
icalendar.prop.vDDDTypes(ttime))
Expand All @@ -929,12 +929,12 @@ def create_timezone(tz, first_date=None, last_date=None):
else:
subcomp = icalendar.TimezoneStandard()

subcomp.add('TZNAME', tz._transition_info[num][2])
subcomp.add('TZNAME', tz._ttinfos[num][2])
subcomp.add(
'DTSTART',
tz.fromutc(tz._utc_transition_times[num]).replace(tzinfo=None))
subcomp.add('TZOFFSETTO', tz._transition_info[num][0])
subcomp.add('TZOFFSETFROM', tz._transition_info[num - 1][0])
tz.fromutc(tz._trans_utc[num]).replace(tzinfo=None))
subcomp.add('TZOFFSETTO', tz._ttinfos[num][0])
subcomp.add('TZOFFSETFROM', tz._ttinfos[num - 1][0])
timezones[name] = subcomp

for subcomp in timezones.values():
Expand Down
Loading