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

Ruff format tests #719

Merged
merged 5 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Changelog

Minor changes:

- ...
- Ruff format test code, see `Issue 672 <https://github.com/collective/icalendar/issues/672>`_
niccokunzmann marked this conversation as resolved.
Show resolved Hide resolved

Breaking changes:

Expand Down
141 changes: 87 additions & 54 deletions src/icalendar/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@
except ImportError:
import zoneinfo
import pytest

import icalendar

try:
import pytz
except ImportError:
pytz = None
from datetime import datetime
from dateutil import tz
from icalendar.cal import Component, Calendar
from icalendar.timezone import tzp as _tzp
from icalendar.timezone import TZP
from pathlib import Path
import itertools
import sys
from pathlib import Path

from dateutil import tz

from icalendar.cal import Calendar, Component
from icalendar.timezone import TZP
from icalendar.timezone import tzp as _tzp

HAS_PYTZ = pytz is not None
if HAS_PYTZ:
PYTZ_UTC = [
pytz.utc,
pytz.timezone('UTC'),
pytz.timezone("UTC"),
]
PYTZ_IN_TIMEZONE = [
lambda dt, tzname: pytz.timezone(tzname).localize(dt),
Expand All @@ -34,26 +37,31 @@


class DataSource:
'''A collection of parsed ICS elements (e.g calendars, timezones, events)'''
def __init__(self, data_source_folder:Path, parser):
"""A collection of parsed ICS elements (e.g calendars, timezones, events)"""

def __init__(self, data_source_folder: Path, parser):
self._parser = parser
self._data_source_folder = data_source_folder

def keys(self):
"""Return all the files that could be used."""
return [p.stem for p in self._data_source_folder.iterdir() if p.suffix.lower() == ".ics"]
return [
p.stem
for p in self._data_source_folder.iterdir()
if p.suffix.lower() == ".ics"
]

def __getitem__(self, attribute):
"""Parse a file and return the result stored in the attribute."""
if attribute.endswith(".ics"):
source_file = attribute
attribute = attribute[:-4]
else:
source_file = attribute + '.ics'
source_file = attribute + ".ics"
source_path = self._data_source_folder / source_file
if not source_path.is_file():
raise AttributeError(f"{source_path} does not exist.")
with source_path.open('rb') as f:
with source_path.open("rb") as f:
raw_ics = f.read()
source = self._parser(raw_ics)
if not isinstance(source, list):
Expand All @@ -76,51 +84,67 @@ def __repr__(self):
@property
def multiple(self):
"""Return a list of all components parsed."""
return self.__class__(self._data_source_folder, lambda data: self._parser(data, multiple=True))
return self.__class__(
self._data_source_folder, lambda data: self._parser(data, multiple=True)
)


HERE = Path(__file__).parent
CALENDARS_FOLDER = HERE / 'calendars'
TIMEZONES_FOLDER = HERE / 'timezones'
EVENTS_FOLDER = HERE / 'events'
CALENDARS_FOLDER = HERE / "calendars"
TIMEZONES_FOLDER = HERE / "timezones"
EVENTS_FOLDER = HERE / "events"


@pytest.fixture(scope="module")
def calendars(tzp):
return DataSource(CALENDARS_FOLDER, icalendar.Calendar.from_ical)


@pytest.fixture(scope="module")
def timezones(tzp):
return DataSource(TIMEZONES_FOLDER, icalendar.Timezone.from_ical)


@pytest.fixture(scope="module")
def events(tzp):
return DataSource(EVENTS_FOLDER, icalendar.Event.from_ical)

@pytest.fixture(params=PYTZ_UTC + [
zoneinfo.ZoneInfo('UTC'),
tz.UTC,
tz.gettz('UTC')])

@pytest.fixture(params=PYTZ_UTC + [zoneinfo.ZoneInfo("UTC"), tz.UTC, tz.gettz("UTC")])
def utc(request, tzp):
return request.param

@pytest.fixture(params=PYTZ_IN_TIMEZONE + [
lambda dt, tzname: dt.replace(tzinfo=tz.gettz(tzname)),
lambda dt, tzname: dt.replace(tzinfo=zoneinfo.ZoneInfo(tzname))
])

@pytest.fixture(
params=PYTZ_IN_TIMEZONE
+ [
lambda dt, tzname: dt.replace(tzinfo=tz.gettz(tzname)),
lambda dt, tzname: dt.replace(tzinfo=zoneinfo.ZoneInfo(tzname)),
]
)
def in_timezone(request, tzp):
return request.param


# exclude broken calendars here
ICS_FILES_EXCLUDE = (
"big_bad_calendar.ics", "issue_104_broken_calendar.ics", "small_bad_calendar.ics",
"multiple_calendar_components.ics", "pr_480_summary_with_colon.ics",
"parsing_error_in_UTC_offset.ics", "parsing_error.ics",
"big_bad_calendar.ics",
"issue_104_broken_calendar.ics",
"small_bad_calendar.ics",
"multiple_calendar_components.ics",
"pr_480_summary_with_colon.ics",
"parsing_error_in_UTC_offset.ics",
"parsing_error.ics",
)
ICS_FILES = [
file.name for file in
itertools.chain(CALENDARS_FOLDER.iterdir(), TIMEZONES_FOLDER.iterdir(), EVENTS_FOLDER.iterdir())
file.name
for file in itertools.chain(
CALENDARS_FOLDER.iterdir(), TIMEZONES_FOLDER.iterdir(), EVENTS_FOLDER.iterdir()
)
if file.name not in ICS_FILES_EXCLUDE
]


@pytest.fixture(params=ICS_FILES)
def ics_file(tzp, calendars, timezones, events, request):
"""An example ICS file."""
Expand All @@ -133,71 +157,76 @@ def ics_file(tzp, calendars, timezones, events, request):


FUZZ_V1 = [key for key in CALENDARS_FOLDER.iterdir() if "fuzz-testcase" in str(key)]


@pytest.fixture(params=FUZZ_V1)
def fuzz_v1_calendar(request):
"""Clusterfuzz calendars."""
return request.param


@pytest.fixture()
@pytest.fixture
def x_sometime():
"""Map x_sometime to time"""
icalendar.cal.types_factory.types_map['X-SOMETIME'] = 'time'
icalendar.cal.types_factory.types_map["X-SOMETIME"] = "time"
yield
icalendar.cal.types_factory.types_map.pop('X-SOMETIME')
icalendar.cal.types_factory.types_map.pop("X-SOMETIME")


@pytest.fixture()
@pytest.fixture
def factory():
"""Return a new component factory."""
return icalendar.ComponentFactory()


@pytest.fixture()
@pytest.fixture
def vUTCOffset_ignore_exceptions():
icalendar.vUTCOffset.ignore_exceptions = True
yield
icalendar.vUTCOffset.ignore_exceptions = False


@pytest.fixture()
@pytest.fixture
def event_component(tzp):
"""Return an event component."""
c = Component()
c.name = 'VEVENT'
c.name = "VEVENT"
return c


@pytest.fixture()
@pytest.fixture
def c(tzp):
"""Return an empty component."""
c = Component()
return c


comp = c

@pytest.fixture()

@pytest.fixture
def calendar_component(tzp):
"""Return an empty component."""
c = Component()
c.name = 'VCALENDAR'
c.name = "VCALENDAR"
return c


@pytest.fixture()
@pytest.fixture
def filled_event_component(c, calendar_component):
"""Return an event with some values and add it to calendar_component."""
e = Component(summary='A brief history of time')
e.name = 'VEVENT'
e.add('dtend', '20000102T000000', encode=0)
e.add('dtstart', '20000101T000000', encode=0)
e = Component(summary="A brief history of time")
e.name = "VEVENT"
e.add("dtend", "20000102T000000", encode=0)
e.add("dtstart", "20000101T000000", encode=0)
calendar_component.add_component(e)
return e


@pytest.fixture()
@pytest.fixture
def calendar_with_resources(tzp):
c = Calendar()
c['resources'] = 'Chair, Table, "Room: 42"'
c["resources"] = 'Chair, Table, "Room: 42"'
return c


Expand All @@ -220,13 +249,13 @@ def other_tzp(request, tzp):
return tzp


@pytest.fixture()
@pytest.fixture
def pytz_only(tzp):
"""Skip tests that are not running under pytz."""
assert tzp.uses_pytz()


@pytest.fixture()
@pytest.fixture
def zoneinfo_only(tzp, request, tzp_name):
"""Skip tests that are not running under zoneinfo."""
assert tzp.uses_zoneinfo()
Expand All @@ -247,14 +276,18 @@ def pytest_generate_tests(metafunc):
tzp_names = ["zoneinfo"]
if "pytz_only" in metafunc.fixturenames:
tzp_names = PYTZ_TZP
assert not ("zoneinfo_only" in metafunc.fixturenames and "pytz_only" in metafunc.fixturenames), "Use pytz_only or zoneinfo_only but not both!"
assert not (
"zoneinfo_only" in metafunc.fixturenames
and "pytz_only" in metafunc.fixturenames
), "Use pytz_only or zoneinfo_only but not both!"
metafunc.parametrize("tzp_name", tzp_names, scope="module")


class DoctestZoneInfo(zoneinfo.ZoneInfo):
"""Constent ZoneInfo representation for tests."""

def __repr__(self):
return f"ZoneInfo(key={repr(self.key)})"
return f"ZoneInfo(key={self.key!r})"


def doctest_print(obj):
Expand All @@ -270,13 +303,13 @@ def doctest_import(name, *args, **kw):
return pytz
return __import__(name, *args, **kw)

@pytest.fixture()

@pytest.fixture
def env_for_doctest(monkeypatch):
"""Modify the environment to make doctests run."""
monkeypatch.setitem(sys.modules, "zoneinfo", zoneinfo)
monkeypatch.setattr(zoneinfo, "ZoneInfo", DoctestZoneInfo)
from icalendar.timezone.zoneinfo import ZONEINFO

monkeypatch.setattr(ZONEINFO, "utc", zoneinfo.ZoneInfo("UTC"))
return {
"print": doctest_print
}
return {"print": doctest_print}
7 changes: 5 additions & 2 deletions src/icalendar/tests/fuzzed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
Some more tests can be added to make sure that the behavior works properly.
"""

def fuzz_calendar_v1(from_ical, calendar_string: str, multiple: bool, should_walk: bool):

def fuzz_calendar_v1(
from_ical, calendar_string: str, multiple: bool, should_walk: bool
):
"""Take a from_ical function and reproduce the error.

The calendar_string is a fuzzed input.
Expand All @@ -16,7 +19,7 @@ def fuzz_calendar_v1(from_ical, calendar_string: str, multiple: bool, should_wal
cal = [cal]
for c in cal:
if should_walk:
for event in cal.walk('VEVENT'):
for event in cal.walk("VEVENT"):
event.to_ical()
else:
cal.to_ical()
9 changes: 4 additions & 5 deletions src/icalendar/tests/fuzzed/test_fuzzed_calendars.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
"""This test tests all fuzzed calendars."""
from icalendar.tests.fuzzed import fuzz_calendar_v1

import icalendar
from icalendar.tests.fuzzed import fuzz_calendar_v1


def test_fuzz_v1(fuzz_v1_calendar):
"""Test a calendar."""
with open(fuzz_v1_calendar, "rb") as f:
fuzz_calendar_v1(
icalendar.Calendar.from_ical,
f.read(),
multiple=True,
should_walk=True
icalendar.Calendar.from_ical, f.read(), multiple=True, should_walk=True
)
Loading
Loading