Improve error message if wrong provider is used

pull/737/head
Nicco Kunzmann 2024-10-23 13:41:41 +01:00
rodzic 30472097f5
commit 914b204535
7 zmienionych plików z 71 dodań i 39 usunięć

Wyświetl plik

@ -99,7 +99,6 @@ def create_utc_property(name:str, docs:str):
return None
dt = self.get(name)
value = getattr(dt, "dt", None)
print(value)
if value is None or not isinstance(value, date):
raise InvalidCalendar(f"{name} must be a datetime in UTC, not {value}")
return value
@ -109,7 +108,7 @@ def create_utc_property(name:str, docs:str):
if not isinstance(value, date):
raise TypeError(f"{name} takes a datetime in UTC, not {value}")
self.pop(name)
self.add(name, tzp.localize_utc(to_datetime(value)))
self.add(name, tzp.localize_utc(value))
return property(p_get, p_set, doc=docs)

Wyświetl plik

@ -35,28 +35,25 @@ primitive Python datatype. So it should always be true that:
These types are mainly used for parsing and file generation. But you can set
them directly.
"""
from datetime import date
from datetime import datetime
from datetime import time
from datetime import timedelta
from datetime import tzinfo
from icalendar.caselessdict import CaselessDict
from icalendar.parser import Parameters
from icalendar.parser import escape_char
from icalendar.parser import unescape_char
from icalendar.parser_tools import (
DEFAULT_ENCODING, SEQUENCE_TYPES, to_unicode, from_unicode, ICAL_TYPE
)
import base64
import binascii
from .timezone import tzp
import re
import time as _time
from typing import Optional, Union
from datetime import date, datetime, time, timedelta, tzinfo
from enum import Enum, auto
from typing import Optional, Union
from icalendar.caselessdict import CaselessDict
from icalendar.parser import Parameters, escape_char, unescape_char
from icalendar.parser_tools import (
DEFAULT_ENCODING,
ICAL_TYPE,
SEQUENCE_TYPES,
from_unicode,
to_unicode,
)
from . import timezone as _timezone
DURATION_REGEX = re.compile(r'([-+]?)P(?:(\d+)W)?(?:(\d+)D)?'
r'(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$')
@ -410,7 +407,7 @@ class vDatetime(TimeBase):
def from_ical(ical, timezone=None):
tzinfo = None
if timezone:
tzinfo = tzp.timezone(timezone)
tzinfo = _timezone.tzp.timezone(timezone)
try:
timetuple = (
@ -422,11 +419,11 @@ class vDatetime(TimeBase):
int(ical[13:15]), # second
)
if tzinfo:
return tzp.localize(datetime(*timetuple), tzinfo)
return _timezone.tzp.localize(datetime(*timetuple), tzinfo)
elif not ical[15:]:
return datetime(*timetuple)
elif ical[15:16] == 'Z':
return tzp.localize_utc(datetime(*timetuple))
return _timezone.tzp.localize_utc(datetime(*timetuple))
else:
raise ValueError(ical)
except Exception:

Wyświetl plik

@ -5,7 +5,7 @@ from datetime import date, datetime, timedelta
import pytest
from icalendar import Event, FreeBusy, Journal, Todo, vDDDTypes
from icalendar.cal import InvalidCalendar
from icalendar.cal import Component, InvalidCalendar
@pytest.fixture(params=[Event, Todo, Journal, FreeBusy])
@ -19,6 +19,20 @@ def test_no_dtstamp(dtstamp_comp):
assert dtstamp_comp.DTSTAMP is None
def set_dtstamp_attribute(component:Component, value:date):
"""Use the setter."""
component.DTSTAMP = value
def set_dtstamp_item(component: Component, value:date):
"""Use setitem."""
component["DTSTAMP"] = vDDDTypes(value)
def set_dtstamp_add(component: Component, value:date):
"""Use add."""
component.add("DTSTAMP", value)
@pytest.mark.parametrize(
("value", "timezone", "expected"),
[
@ -28,10 +42,13 @@ def test_no_dtstamp(dtstamp_comp):
(date(2024, 10, 10), None, datetime(2024, 10, 10)),
]
)
def test_set_value_and_get_it(dtstamp_comp, value, timezone, expected, tzp):
@pytest.mark.parametrize(
"set_dtstamp", [set_dtstamp_add, set_dtstamp_attribute, set_dtstamp_item]
)
def test_set_value_and_get_it(dtstamp_comp, value, timezone, expected, tzp, set_dtstamp):
"""Set and get the DTSTAMP value."""
dtstamp = value if timezone is None else tzp.localize(value, timezone)
dtstamp_comp.DTSTAMP = dtstamp
set_dtstamp(dtstamp_comp, dtstamp)
in_utc = tzp.localize_utc(expected)
get_value = dtstamp_comp.get("DTSTAMP").dt
assert in_utc == get_value

Wyświetl plik

@ -90,3 +90,15 @@ def test_cache_is_emptied_when_tzp_is_switched(tzp, timezones, new_tzp_name):
tzp.cache_timezone_component(timezones.pacific_fiji)
tz2 = tzp.timezone("custom_Pacific/Fiji")
assert tz1 is not tz2
def test_invalid_name(tzp):
"""Check that the provider name is ok."""
provider = "invalid_provider"
with pytest.raises(ValueError) as e:
tzp.use(provider)
# f"Unknown provider {provider}. Use 'pytz' or 'zoneinfo'."
message = e.value.args[0]
assert f"Unknown provider {provider}." in message
assert "zoneinfo" in message
assert "pytz" in message

Wyświetl plik

@ -13,4 +13,4 @@ def use_zoneinfo():
tzp.use_zoneinfo()
__all__ = ["tzp", "use_pytz", "use_zoneinfo", "normalize_pytz"]
__all__ = ["tzp", "use_pytz", "use_zoneinfo"]

Wyświetl plik

@ -1,12 +1,19 @@
from __future__ import annotations
import datetime
from .. import cal
from typing import Optional, Union
from .windows_to_olson import WINDOWS_TO_OLSON
from .provider import TZProvider
from icalendar import prop
from dateutil.rrule import rrule
from typing import TYPE_CHECKING, Optional, Union
from icalendar.tools import to_datetime
from .windows_to_olson import WINDOWS_TO_OLSON
if TYPE_CHECKING:
import datetime
from dateutil.rrule import rrule
from icalendar import cal, prop
from .provider import TZProvider
DEFAULT_TIMEZONE_PROVIDER = "zoneinfo"
@ -41,10 +48,10 @@ class TZP:
def use(self, provider:Union[str, TZProvider]):
"""Switch to a different timezone provider."""
if isinstance(provider, str):
provider = getattr(self, f"use_{provider}", None)
if provider is None:
raise ValueError(f"Unknown provider {provider_name}. Use 'pytz' or 'zoneinfo'.")
provider()
use_provider = getattr(self, f"use_{provider}", None)
if use_provider is None:
raise ValueError(f"Unknown provider {provider}. Use 'pytz' or 'zoneinfo'.")
use_provider()
else:
self._use(provider)
@ -52,12 +59,12 @@ class TZP:
"""Use the default timezone provider."""
self.use(DEFAULT_TIMEZONE_PROVIDER)
def localize_utc(self, dt: datetime.datetime) -> datetime.datetime:
def localize_utc(self, dt: datetime.date) -> datetime.datetime:
"""Return the datetime in UTC.
If the datetime has no timezone, set UTC as its timezone.
"""
return self.__provider.localize_utc(dt)
return self.__provider.localize_utc(to_datetime(dt))
def localize(self, dt: datetime.datetime, tz: Union[datetime.tzinfo, str]) -> datetime.datetime:
"""Localize a datetime to a timezone."""

Wyświetl plik

@ -4,7 +4,6 @@ from datetime import date, datetime, tzinfo
from string import ascii_letters, digits
from icalendar.parser_tools import to_unicode
from icalendar.prop import vDatetime, vText
class UIDGenerator:
@ -26,6 +25,7 @@ class UIDGenerator:
Like:
20050105T225746Z-HKtJMqUgdO0jDUwm@example.com
"""
from icalendar.prop import vDatetime, vText
host_name = to_unicode(host_name)
unique = unique or UIDGenerator.rnd_string()
today = to_unicode(vDatetime(datetime.today()).to_ical())