Skip to content

Commit

Permalink
Merge branch 'main' into vgeo
Browse files Browse the repository at this point in the history
  • Loading branch information
niccokunzmann authored Jan 17, 2025
2 parents b2a627e + 4f5130b commit 8146a21
Show file tree
Hide file tree
Showing 16 changed files with 50 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Minor changes:
- Document :class:`icalendar.prop.vRecur` property. See `Issue 758 <https://github.com/collective/icalendar/issues/758>`_.
- Print failure of doctest to aid debugging.
- Improve documentation of :class:`icalendar.prop.vGeo`
- Fix tests, improve code readability, fix typing. See `Issue 766 <https://github.com/collective/icalendar/issues/766>`_ and `Issue 765 <https://github.com/collective/icalendar/issues/765>`_.

Breaking changes:

Expand Down
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ files.
----

:Homepage: https://icalendar.readthedocs.io
:Community Discussions: https://github.com/collective/icalendar/discussions
:Issue Tracker: https://github.com/collective/icalendar/issues
:Code: https://github.com/collective/icalendar
:Mailing list: https://github.com/collective/icalendar/issues
:Dependencies: `python-dateutil`_ and `tzdata`_.
:License: `BSD`_

Expand Down
2 changes: 1 addition & 1 deletion bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@

def _final_version(parsed_version):
for part in parsed_version:
if (part[:1] == '*') and (part not in _final_parts):
if (part.startswith('*')) and (part not in _final_parts):
return False
return True
index = setuptools.package_index.PackageIndex(
Expand Down
1 change: 1 addition & 0 deletions src/icalendar/cal.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ def from_ical(cls, st, multiple=False):
'Found no components where exactly one is required', st))
return comps[0]

@staticmethod
def _format_error(error_description, bad_input, elipsis='[...]'):
# there's three character more in the error, ie. ' ' x2 and a ':'
max_error_length = 100 - 3
Expand Down
22 changes: 13 additions & 9 deletions src/icalendar/parser_tools.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Union
from typing import List, Union

SEQUENCE_TYPES = (list, tuple)
DEFAULT_ENCODING = 'utf-8'
Expand All @@ -13,13 +13,14 @@ def from_unicode(value: ICAL_TYPE, encoding='utf-8') -> bytes:
:return: The bytes representation of the value
"""
if isinstance(value, bytes):
value = value
return value
elif isinstance(value, str):
try:
value = value.encode(encoding)
return value.encode(encoding)
except UnicodeEncodeError:
value = value.encode('utf-8', 'replace')
return value
return value.encode('utf-8', 'replace')
else:
return value


def to_unicode(value: ICAL_TYPE, encoding='utf-8-sig') -> str:
Expand All @@ -29,13 +30,16 @@ def to_unicode(value: ICAL_TYPE, encoding='utf-8-sig') -> str:
return value
elif isinstance(value, bytes):
try:
value = value.decode(encoding)
return value.decode(encoding)
except UnicodeDecodeError:
value = value.decode('utf-8-sig', 'replace')
return value
return value.decode('utf-8-sig', 'replace')
else:
return value


def data_encode(data: Union[ICAL_TYPE, dict, list], encoding=DEFAULT_ENCODING) -> bytes:
def data_encode(
data: Union[ICAL_TYPE, dict, list], encoding=DEFAULT_ENCODING
) -> Union[bytes, List[bytes], dict]:
"""Encode all datastructures to the given encoding.
Currently unicode strings, dicts and lists are supported.
"""
Expand Down
2 changes: 1 addition & 1 deletion src/icalendar/prop.py
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ def __new__(cls, month:Union[str, int]):
month_index = int(month)
leap = False
else:
if not month[-1] == "L" and month[:-1].isdigit():
if month[-1] != "L" and month[:-1].isdigit():
raise ValueError(f"Invalid month: {month!r}")
month_index = int(month[:-1])
leap = True
Expand Down
4 changes: 2 additions & 2 deletions src/icalendar/tests/fuzzed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def fuzz_calendar_v1(
cal = [cal]
for c in cal:
if should_walk:
for event in cal.walk("VEVENT"):
for event in c.walk("VEVENT"):
event.to_ical()
else:
cal.to_ical()
c.to_ical()
10 changes: 5 additions & 5 deletions src/icalendar/tests/prop/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ def test_prop_vDDDLists(self):
from icalendar.prop import vDDDLists

dt_list = vDDDLists.from_ical("19960402T010000Z")
self.assertTrue(isinstance(dt_list, list))
self.assertIsInstance(dt_list, list)
self.assertEqual(len(dt_list), 1)
self.assertTrue(isinstance(dt_list[0], datetime))
self.assertIsInstance(dt_list[0], datetime)
self.assertEqual(str(dt_list[0]), "1996-04-02 01:00:00+00:00")

p = "19960402T010000Z,19960403T010000Z,19960404T010000Z"
Expand All @@ -45,7 +45,7 @@ def test_prop_vDDDLists(self):
self.assertEqual(dt_list.to_ical(), b"20000101T000000,20001111T000000")

instance = vDDDLists([])
self.assertFalse(instance == "value")
self.assertNotEqual(instance, "value")

def test_prop_vDate(self):
from icalendar.prop import vDate
Expand Down Expand Up @@ -149,7 +149,7 @@ def test_prop_vRecur(self):
self.assertEqual(vRecur(r).to_ical(), b"FREQ=DAILY;COUNT=10;INTERVAL=2")

r = vRecur.from_ical(
"FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=-SU;" "BYHOUR=8,9;BYMINUTE=30"
"FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=-SU;BYHOUR=8,9;BYMINUTE=30"
)
self.assertEqual(
r,
Expand All @@ -165,7 +165,7 @@ def test_prop_vRecur(self):

self.assertEqual(
vRecur(r).to_ical(),
b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=-SU;" b"BYMONTH=1",
b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=-SU;BYMONTH=1",
)

r = vRecur.from_ical("FREQ=WEEKLY;INTERVAL=1;BYWEEKDAY=TH")
Expand Down
2 changes: 1 addition & 1 deletion src/icalendar/tests/prop/test_windows_to_olson_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def test_windows_timezone(tzp):
"""Test that the timezone is mapped correctly to olson."""
dt = vDatetime.from_ical("20170507T181920", "Eastern Standard Time")
expected = tzp.localize(datetime(2017, 5, 7, 18, 19, 20), "America/New_York")
assert dt.tzinfo == dt.tzinfo
assert dt.tzinfo == expected.tzinfo
assert dt == expected


Expand Down
6 changes: 3 additions & 3 deletions src/icalendar/tests/test_icalendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_long_lines(self):
)
self.assertEqual(
Contentlines.from_ical(
"A faked\r\n long line\r\nAnd another " "lin\r\n\te that is folded\r\n"
"A faked\r\n long line\r\nAnd another lin\r\n\te that is folded\r\n"
),
["A faked long line", "And another line that is folded", ""],
)
Expand Down Expand Up @@ -112,7 +112,7 @@ def test_contentline_class(self):
)

c = Contentline(
"ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:" "MAILTO:[email protected]"
"ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:MAILTO:[email protected]"
)
self.assertEqual(
c.parts(),
Expand All @@ -124,7 +124,7 @@ def test_contentline_class(self):
)
self.assertEqual(
c.to_ical().decode("utf-8"),
"ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:" "MAILTO:[email protected]",
"ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:MAILTO:[email protected]",
)

# and back again
Expand Down
2 changes: 1 addition & 1 deletion src/icalendar/tests/test_issue_722_generate_vtimezone.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def test_conversion_converges(tzp, tzid):
tzinfo2 = generated1.to_tz()
generated2 = Timezone.from_tzinfo(tzinfo2, "test-generated")
tzinfo3 = generated2.to_tz()
generated3 = Timezone.from_tzinfo(tzinfo2, "test-generated")
generated3 = Timezone.from_tzinfo(tzinfo3, "test-generated")
# pprint(generated1.get_transitions())
# pprint(generated2.get_transitions())
assert_components_equal(generated1, generated2)
Expand Down
4 changes: 2 additions & 2 deletions src/icalendar/tests/test_unit_caselessdict.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ def test_CaselessDict(self):
self.assertEqual(ncd.get("key1"), "val1")
self.assertEqual(ncd.get("key3", "NOT FOUND"), "val3")
self.assertEqual(ncd.get("key4", "NOT FOUND"), "NOT FOUND")
self.assertTrue("key4" in ncd)
self.assertIn("key4", ncd)

del ncd["key4"]
self.assertFalse("key4" in ncd)
self.assertNotIn("key4", ncd)

ncd.update({"key5": "val5", "KEY6": "val6", "KEY5": "val7"})
self.assertEqual(ncd["key6"], "val6")
Expand Down
2 changes: 1 addition & 1 deletion src/icalendar/tests/test_unit_parser_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def test_parser_tools_to_unicode(self):
self.assertEqual(to_unicode(b"\xc6\xb5"), "\u01b5")
self.assertEqual(to_unicode(b"\xc6\xb5", encoding="ascii"), "\u01b5")
self.assertEqual(to_unicode(1), 1)
self.assertEqual(to_unicode(None), None)
self.assertIsNone(to_unicode(None))

def test_parser_tools_from_unicode(self):
self.assertEqual(from_unicode("\u01b5", encoding="ascii"), b"\xc6\xb5")
Expand Down
12 changes: 6 additions & 6 deletions src/icalendar/tests/test_unit_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ def test_tools_UIDGenerator(self):

txt = uid.to_ical()
length = 15 + 1 + 16 + 1 + 11
self.assertTrue(len(txt) == length)
self.assertTrue(b"@example.com" in txt)
self.assertEqual(len(txt), length)
self.assertIn(b"@example.com", txt)

# You should at least insert your own hostname to be more compliant
uid = g.uid("Example.ORG")
txt = uid.to_ical()
self.assertTrue(len(txt) == length)
self.assertTrue(b"@Example.ORG" in txt)
self.assertEqual(len(txt), length)
self.assertIn(b"@Example.ORG", txt)

# You can also insert a path or similar
uid = g.uid("Example.ORG", "/path/to/content")
txt = uid.to_ical()
self.assertTrue(len(txt) == length)
self.assertTrue(b"-/path/to/[email protected]" in txt)
self.assertEqual(len(txt), length)
self.assertIn(b"-/path/to/[email protected]", txt)


@pytest.mark.parametrize(
Expand Down
6 changes: 3 additions & 3 deletions src/icalendar/timezone/equivalent_timezone_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from pathlib import Path
from pprint import pprint
from time import time
from typing import Callable, NamedTuple, Optional
from typing import Callable, NamedTuple, Optional, Any, Tuple, List

from zoneinfo import ZoneInfo, available_timezones

Expand All @@ -30,7 +30,7 @@
def check(dt, tz:tzinfo):
return (dt, tz.utcoffset(dt))

def checks(tz:tzinfo) -> tuple:
def checks(tz:tzinfo) -> List[Tuple[Any, Optional[timedelta]]]:
result = []
for dt in DTS:
try:
Expand Down Expand Up @@ -123,7 +123,7 @@ def generate_tree(
with file.open("w") as f:
f.write(f"'''This file is automatically generated by {Path(__file__).name}'''\n")
f.write("import datetime\n\n")
f.write(f"\nlookup = ")
f.write("\nlookup = ")
pprint(lookup, stream=f)
f.write("\n\n__all__ = ['lookup']\n")

Expand Down
14 changes: 7 additions & 7 deletions src/icalendar/timezone/tzp.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,16 @@ def clean_timezone_id(self, tzid: str) -> str:
"""
return tzid.strip("/")

def timezone(self, id: str) -> Optional[datetime.tzinfo]:
def timezone(self, tz_id: str) -> Optional[datetime.tzinfo]:
"""Return a timezone with an id or None if we cannot find it."""
_unclean_id = id
id = self.clean_timezone_id(id)
tz = self.__provider.timezone(id)
_unclean_id = tz_id
tz_id = self.clean_timezone_id(tz_id)
tz = self.__provider.timezone(tz_id)
if tz is not None:
return tz
if id in WINDOWS_TO_OLSON:
tz = self.__provider.timezone(WINDOWS_TO_OLSON[id])
return tz or self.__provider.timezone(_unclean_id) or self.__tz_cache.get(id)
if tz_id in WINDOWS_TO_OLSON:
tz = self.__provider.timezone(WINDOWS_TO_OLSON[tz_id])
return tz or self.__provider.timezone(_unclean_id) or self.__tz_cache.get(tz_id)

def uses_pytz(self) -> bool:
"""Whether we use pytz at all."""
Expand Down

0 comments on commit 8146a21

Please sign in to comment.