kopia lustrzana https://github.com/collective/icalendar
Merge branch 'master' into niccokunzmann-patch-3
commit
defbfc2efe
|
@ -122,8 +122,4 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: create release
|
- name: create release
|
||||||
uses: elgohr/Github-Release-Action@v5
|
uses: ncipollo/release-action@v1
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
with:
|
|
||||||
title: ${{ github.ref_name }}
|
|
||||||
|
|
24
CHANGES.rst
24
CHANGES.rst
|
@ -1,12 +1,32 @@
|
||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
5.0.12 (unreleased)
|
5.0.13 (unreleased)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Minor changes:
|
Minor changes:
|
||||||
|
|
||||||
- Add funding information
|
- Add funding information
|
||||||
|
|
||||||
|
Breaking changes:
|
||||||
|
|
||||||
|
- ...
|
||||||
|
|
||||||
|
New features:
|
||||||
|
|
||||||
|
- Create GitHub releases for each tag.
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
- ...
|
||||||
|
|
||||||
|
|
||||||
|
5.0.12 (2024-03-19)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Minor changes:
|
||||||
|
|
||||||
|
- Analyse code coverage of test files
|
||||||
- Added corpus to fuzzing directory
|
- Added corpus to fuzzing directory
|
||||||
- Added exclusion of fuzzing corpus in MANIFEST.in
|
- Added exclusion of fuzzing corpus in MANIFEST.in
|
||||||
- Augmented fuzzer to optionally convert multiple calendars from a source string
|
- Augmented fuzzer to optionally convert multiple calendars from a source string
|
||||||
|
@ -16,6 +36,8 @@ Minor changes:
|
||||||
- Rename "contributor" to "collaborator" in documentation
|
- Rename "contributor" to "collaborator" in documentation
|
||||||
- Correct the outdated "icalendar view myfile.ics" command in documentation. #588
|
- Correct the outdated "icalendar view myfile.ics" command in documentation. #588
|
||||||
- Update GitHub Actions steps versions
|
- Update GitHub Actions steps versions
|
||||||
|
- Keep GitHub Actions up to date with GitHub's Dependabot
|
||||||
|
|
||||||
|
|
||||||
Breaking changes:
|
Breaking changes:
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ Try it out:
|
||||||
Type "help", "copyright", "credits" or "license" for more information.
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
>>> import icalendar
|
>>> import icalendar
|
||||||
>>> icalendar.__version__
|
>>> icalendar.__version__
|
||||||
'5.0.11'
|
'5.0.12'
|
||||||
|
|
||||||
Building the documentation locally
|
Building the documentation locally
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Keep GitHub Actions up to date with GitHub's Dependabot
|
|
|
@ -1,4 +1,4 @@
|
||||||
__version__ = '5.0.11'
|
__version__ = '5.0.12'
|
||||||
|
|
||||||
from icalendar.cal import (
|
from icalendar.cal import (
|
||||||
Calendar,
|
Calendar,
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
VERSION:2.0
|
||||||
|
PRODID://RESEARCH IN MOTION//BIS 3.0
|
||||||
|
METHOD:REQUEST
|
||||||
|
BEGIN:VEVENT
|
||||||
|
SEQUENCE:2
|
||||||
|
X-RIM-REVISION:0
|
||||||
|
SUMMARY:Test meeting from BB
|
||||||
|
X-MICROSOFT-CDO-ALLDAYEVENT:TRUE
|
||||||
|
CLASS:PUBLIC
|
||||||
|
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="RembrandXS":MAILTO:rembrand@xs4all.nl
|
||||||
|
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="RembrandDX":MAILTO:rembrand@daxlab.com
|
||||||
|
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="RembrandSB":MAILTO:rembspam@xs4all.nl
|
||||||
|
UID:XRIMCAL-628059586-522954492-9750559
|
||||||
|
DTSTART;VALUE=DATE:20120814
|
||||||
|
DTEND;VALUE=DATE:20120815
|
||||||
|
DESCRIPTION:Test meeting from BB
|
||||||
|
DTSTAMP:20120813T151458Z
|
||||||
|
ORGANIZER:mailto:rembrand@daxlab.com
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
|
@ -109,6 +109,14 @@ def fuzz_v1_calendar(request):
|
||||||
return request.param
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def x_sometime():
|
||||||
|
"""Map x_sometime to time"""
|
||||||
|
icalendar.cal.types_factory.types_map['X-SOMETIME'] = 'time'
|
||||||
|
yield
|
||||||
|
icalendar.cal.types_factory.types_map.pop('X-SOMETIME')
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def factory():
|
def factory():
|
||||||
"""Return a new component factory."""
|
"""Return a new component factory."""
|
||||||
|
|
|
@ -38,17 +38,21 @@ def test_parameter_to_ical_is_inverse_of_from_ical(parameter, expected):
|
||||||
assert parameter.to_ical() == expected
|
assert parameter.to_ical() == expected
|
||||||
assert Parameters.from_ical(expected.decode('utf-8')) == parameter
|
assert Parameters.from_ical(expected.decode('utf-8')) == parameter
|
||||||
|
|
||||||
|
|
||||||
def test_parse_parameter_string_without_quotes():
|
def test_parse_parameter_string_without_quotes():
|
||||||
assert Parameters.from_ical('PARAM1=Value 1;PARA2=Value 2') == Parameters({'PARAM1': 'Value 1', 'PARA2': 'Value 2'})
|
assert Parameters.from_ical('PARAM1=Value 1;PARA2=Value 2') == Parameters({'PARAM1': 'Value 1', 'PARA2': 'Value 2'})
|
||||||
|
|
||||||
|
|
||||||
def test_parametr_is_case_insensitive():
|
def test_parametr_is_case_insensitive():
|
||||||
parameter = Parameters(parameter1='Value1')
|
parameter = Parameters(parameter1='Value1')
|
||||||
assert parameter['parameter1'] == parameter['PARAMETER1'] == parameter['PaRaMeTer1']
|
assert parameter['parameter1'] == parameter['PARAMETER1'] == parameter['PaRaMeTer1']
|
||||||
|
|
||||||
|
|
||||||
def test_parameter_keys_are_uppercase():
|
def test_parameter_keys_are_uppercase():
|
||||||
parameter = Parameters(parameter1='Value1')
|
parameter = Parameters(parameter1='Value1')
|
||||||
assert list(parameter.keys()) == ['PARAMETER1']
|
assert list(parameter.keys()) == ['PARAMETER1']
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('cn_param, cn_quoted', [
|
@pytest.mark.parametrize('cn_param, cn_quoted', [
|
||||||
# not double-quoted
|
# not double-quoted
|
||||||
('Aramis', 'Aramis'),
|
('Aramis', 'Aramis'),
|
||||||
|
@ -67,68 +71,41 @@ def test_quoting(cn_param, cn_quoted):
|
||||||
event.add('ATTENDEE', attendee)
|
event.add('ATTENDEE', attendee)
|
||||||
assert f'ATTENDEE;CN={cn_quoted}:test@example.com' in event.to_ical().decode('utf-8')
|
assert f'ATTENDEE;CN={cn_quoted}:test@example.com' in event.to_ical().decode('utf-8')
|
||||||
|
|
||||||
class TestPropertyParams(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_property_params(self):
|
def test_property_params():
|
||||||
# Property parameters with values containing a COLON character, a
|
"""Property parameters with values containing a COLON character, a
|
||||||
# SEMICOLON character or a COMMA character MUST be placed in quoted
|
SEMICOLON character or a COMMA character MUST be placed in quoted
|
||||||
# text.
|
text."""
|
||||||
cal_address = vCalAddress('mailto:john.doe@example.org')
|
cal_address = vCalAddress('mailto:john.doe@example.org')
|
||||||
cal_address.params["CN"] = "Doe, John"
|
cal_address.params["CN"] = "Doe, John"
|
||||||
ical = Calendar()
|
ical = Calendar()
|
||||||
ical.add('organizer', cal_address)
|
ical.add('organizer', cal_address)
|
||||||
|
|
||||||
ical_str = Calendar.to_ical(ical)
|
ical_str = Calendar.to_ical(ical)
|
||||||
exp_str = b"""BEGIN:VCALENDAR\r\nORGANIZER;CN="Doe, John":"""\
|
exp_str = b"""BEGIN:VCALENDAR\r\nORGANIZER;CN="Doe, John":"""\
|
||||||
b"""mailto:john.doe@example.org\r\nEND:VCALENDAR\r\n"""
|
b"""mailto:john.doe@example.org\r\nEND:VCALENDAR\r\n"""
|
||||||
|
|
||||||
self.assertEqual(ical_str, exp_str)
|
assert ical_str == exp_str
|
||||||
|
|
||||||
# other way around: ensure the property parameters can be restored from
|
# other way around: ensure the property parameters can be restored from
|
||||||
# an icalendar string.
|
# an icalendar string.
|
||||||
ical2 = Calendar.from_ical(ical_str)
|
ical2 = Calendar.from_ical(ical_str)
|
||||||
self.assertEqual(ical2.get('ORGANIZER').params.get('CN'), 'Doe, John')
|
assert ical2.get('ORGANIZER').params.get('CN') == 'Doe, John'
|
||||||
|
|
||||||
def test_parse_and_access_property_params(self):
|
|
||||||
"""Parse an ics string and access some property parameters then.
|
|
||||||
This is a follow-up of a question received per email.
|
|
||||||
|
|
||||||
"""
|
def test_parse_and_access_property_params(calendars):
|
||||||
ics = """BEGIN:VCALENDAR
|
"""Parse an ics string and access some property parameters then.
|
||||||
VERSION:2.0
|
This is a follow-up of a question received per email.
|
||||||
PRODID://RESEARCH IN MOTION//BIS 3.0
|
|
||||||
METHOD:REQUEST
|
|
||||||
BEGIN:VEVENT
|
|
||||||
SEQUENCE:2
|
|
||||||
X-RIM-REVISION:0
|
|
||||||
SUMMARY:Test meeting from BB
|
|
||||||
X-MICROSOFT-CDO-ALLDAYEVENT:TRUE
|
|
||||||
CLASS:PUBLIC
|
|
||||||
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="RembrandXS":MAILTO:rembrand@xs4all.nl
|
|
||||||
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="RembrandDX":MAILTO:rembrand@daxlab.com
|
|
||||||
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="RembrandSB":MAILTO:rembspam@xs4all.nl
|
|
||||||
UID:XRIMCAL-628059586-522954492-9750559
|
|
||||||
DTSTART;VALUE=DATE:20120814
|
|
||||||
DTEND;VALUE=DATE:20120815
|
|
||||||
DESCRIPTION:Test meeting from BB
|
|
||||||
DTSTAMP:20120813T151458Z
|
|
||||||
ORGANIZER:mailto:rembrand@daxlab.com
|
|
||||||
END:VEVENT
|
|
||||||
END:VCALENDAR"""
|
|
||||||
|
|
||||||
cal = icalendar.Calendar.from_ical(ics)
|
"""
|
||||||
event = cal.walk("VEVENT")[0]
|
event = calendars.property_params.walk("VEVENT")[0]
|
||||||
event['attendee'][0]
|
attendee = event['attendee'][0]
|
||||||
self.assertEqual(event['attendee'][0].to_ical(),
|
assert attendee.to_ical() == b'MAILTO:rembrand@xs4all.nl'
|
||||||
b'MAILTO:rembrand@xs4all.nl')
|
assert attendee.params.to_ical() == b'CN=RembrandXS;PARTSTAT=NEEDS-ACTION;RSVP=TRUE'
|
||||||
self.assertEqual(event['attendee'][0].params.to_ical(),
|
assert attendee.params['cn'] == 'RembrandXS'
|
||||||
b'CN=RembrandXS;PARTSTAT=NEEDS-ACTION;RSVP=TRUE')
|
|
||||||
self.assertEqual(event['attendee'][0].params['cn'], 'RembrandXS')
|
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr():
|
||||||
"""Test correct class representation.
|
"""Test correct class representation.
|
||||||
"""
|
"""
|
||||||
it = Parameters(parameter1='Value1')
|
it = Parameters(parameter1='Value1')
|
||||||
self.assertTrue(
|
assert re.match(r"Parameters\({u?'PARAMETER1': u?'Value1'}\)", str(it))
|
||||||
re.match(r"Parameters\({u?'PARAMETER1': u?'Value1'}\)", str(it))
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,29 +1,28 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import icalendar
|
import icalendar
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
def test_value_type_is_not_mapped():
|
||||||
|
"""Usually, the value should be absent."""
|
||||||
|
assert 'X-SOMETIME' not in icalendar.cal.types_factory.types_map
|
||||||
|
|
||||||
class TestTime(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
def test_value_type_is_mapped(x_sometime):
|
||||||
icalendar.cal.types_factory.types_map['X-SOMETIME'] = 'time'
|
"""The value is mapped for the test."""
|
||||||
|
assert 'X-SOMETIME' in icalendar.cal.types_factory.types_map
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
icalendar.cal.types_factory.types_map.pop('X-SOMETIME')
|
|
||||||
|
|
||||||
def test_create_from_ical(self):
|
def test_create_from_ical(x_sometime):
|
||||||
directory = os.path.dirname(__file__)
|
directory = os.path.dirname(__file__)
|
||||||
ics = open(os.path.join(directory, 'calendars', 'time.ics'), 'rb')
|
ics = open(os.path.join(directory, 'calendars', 'time.ics'), 'rb')
|
||||||
cal = icalendar.Calendar.from_ical(ics.read())
|
cal = icalendar.Calendar.from_ical(ics.read())
|
||||||
ics.close()
|
ics.close()
|
||||||
|
|
||||||
self.assertEqual(cal['X-SOMETIME'].dt, datetime.time(17, 20, 10))
|
assert cal['X-SOMETIME'].dt == datetime.time(17, 20, 10)
|
||||||
self.assertEqual(cal['X-SOMETIME'].to_ical(), '172010')
|
assert cal['X-SOMETIME'].to_ical() == '172010'
|
||||||
|
|
||||||
def test_create_to_ical(self):
|
|
||||||
cal = icalendar.Calendar()
|
def test_create_to_ical(x_sometime):
|
||||||
cal.add('X-SOMETIME', datetime.time(17, 20, 10))
|
cal = icalendar.Calendar()
|
||||||
self.assertTrue(b'X-SOMETIME;VALUE=TIME:172010' in
|
cal.add('X-SOMETIME', datetime.time(17, 20, 10))
|
||||||
cal.to_ical().splitlines())
|
assert b'X-SOMETIME;VALUE=TIME:172010' in cal.to_ical().splitlines()
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -12,7 +12,7 @@ deps =
|
||||||
coverage
|
coverage
|
||||||
hypothesis
|
hypothesis
|
||||||
commands =
|
commands =
|
||||||
coverage run --source=src/icalendar --omit=*/tests/* --module pytest []
|
coverage run --source=src/icalendar --omit=*/tests/hypothesis/* --omit=*/tests/fuzzed/* --module pytest []
|
||||||
coverage report
|
coverage report
|
||||||
coverage html
|
coverage html
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue