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

Issue 27 #565

Merged
merged 37 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2e0388e
Check that event is included in parsing
niccokunzmann Aug 30, 2023
55879e3
Add documentation about parsing
niccokunzmann Aug 30, 2023
078ae71
Add changelog entry
niccokunzmann Aug 30, 2023
fe2e5df
Add changelog entry
niccokunzmann Aug 30, 2023
8fb3353
Merge pull request #545 from niccokunzmann/issue-165
jacadzaca Aug 31, 2023
088eea7
fix #526
jacadzaca Sep 1, 2023
4f00286
dont repeat parameter list in test_comparing_calendars
jacadzaca Sep 1, 2023
2dfd51c
dont treat components with a subset of other a larger components' sub…
jacadzaca Sep 1, 2023
16d2e85
Merge pull request #550 from jacadzaca/fix-526
niccokunzmann Sep 2, 2023
403ca84
Merge pull request #547 from niccokunzmann/issue-152
jacadzaca Sep 6, 2023
c152733
Update about.rst
bobflorian Sep 15, 2023
e8c6f8b
Update CHANGES.rst
bobflorian Sep 15, 2023
923666a
Merge pull request #553 from bobflorian/master
niccokunzmann Sep 16, 2023
c13af2b
Fix `vText.__repr__` `BytesWarning`
scop Sep 17, 2023
52d5cea
Merge pull request #554 from scop/patch-1
jacadzaca Sep 17, 2023
a102685
version 5.0.8
niccokunzmann Sep 18, 2023
7079fe1
Merge pull request #555 from niccokunzmann/release
niccokunzmann Sep 18, 2023
df769f8
Add new CHANGELOG section for future release
niccokunzmann Sep 18, 2023
4c055a6
Add timezone to period value types
niccokunzmann Sep 19, 2023
5ab1846
Merge pull request #556 from niccokunzmann/period_timezone
jacadzaca Sep 22, 2023
98fe960
version 5.0.9
niccokunzmann Sep 24, 2023
1623e63
Merge pull request #558 from niccokunzmann/release
niccokunzmann Sep 24, 2023
4d6aacb
Add new CHANGELOG section for future release
niccokunzmann Sep 24, 2023
0111be3
Component._encode: convert to staticmethod
Zocker1999NET Sep 24, 2023
392deb6
add test cases for Component._encoding concerning #557
Zocker1999NET Sep 24, 2023
61ed4d7
Component._encoding: only skip factory for natives
Zocker1999NET Sep 24, 2023
07f3c53
Component._encode: merge parameters
Zocker1999NET Sep 24, 2023
4042ba8
add changelog entry & credits for fixing #557
Zocker1999NET Sep 24, 2023
6b9d794
Merge pull request #559 from Zocker1999NET/fix-issue-557
jacadzaca Sep 24, 2023
48e2a68
version 5.0.10
jacadzaca Sep 26, 2023
ed2c8cc
Merge pull request #560 from jacadzaca/release-5.0.10
jacadzaca Sep 26, 2023
1e0c78f
cli: Display datetimes in local timezone
vimpostor Sep 27, 2023
0fdbdfb
Merge pull request #561 from vimpostor/localdatetime
niccokunzmann Sep 29, 2023
ccc3810
Merge branch 'master' into issue-27
jacadzaca Sep 30, 2023
1b44560
improve test for issue #27
jacadzaca Sep 30, 2023
f359682
add vPeriod,__eq__
jacadzaca Sep 30, 2023
8fab650
multivalue FREEBUSY parses properly
jacadzaca Sep 30, 2023
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
50 changes: 44 additions & 6 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Changelog
=========

5.0.8 (unreleased)
------------------
5.0.11 (unreleased)
-------------------

Minor changes:

- Update build configuration to build readthedocs. #538
- No longer run the ``plone.app.event`` tests.
- Move pip caching into Python setup action.
- The cli utility now displays start and end datetimes in the user's local timezone.
Ref: #561
[vimpostor]

Breaking changes:

Expand All @@ -20,7 +20,45 @@ New features:

Bug fixes:

- ...
- Multivalue FREEBUSY property is now parsed properly
Ref: #27
[jacadzaca]

5.0.10 (unreleased)
-------------------

Bug fixes:

- Component._encode stops ignoring parameters argument on native values, now merges them
Fixes: #557
[zocker1999net]

5.0.9 (2023-09-24)
------------------

Bug fixes:

- PERIOD values now set the timezone of their start and end. #556

5.0.8 (2023-09-18)
------------------

Minor changes:

- Update build configuration to build readthedocs. #538
- No longer run the ``plone.app.event`` tests.
- Add documentation on how to parse ``.ics`` files. #152
- Move pip caching into Python setup action.
- Check that issue #165 can be closed.
- Updated about.rst for issue #527
- Avoid ``vText.__repr__`` BytesWarning.

Bug fixes:

- Calendar components are now properly compared
Ref: #550
Fixes: #526
[jacadzaca]

5.0.7 (2023-05-29)
------------------
Expand Down
21 changes: 21 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ files.
.. _`pytz`: https://pypi.org/project/pytz/
.. _`BSD`: https://github.com/collective/icalendar/issues/2

Quick Guide
-----------

To **install** the package, run::

pip install icalendar

You can open an ``.ics`` file and see all the events::

>>> import icalendar
>>> path_to_ics_file = "src/icalendar/tests/calendars/example.ics"
>>> with open(path_to_ics_file) as f:
... calendar = icalendar.Calendar.from_ical(f.read())
>>> for event in calendar.walk('VEVENT'):
... print(event.get("SUMMARY"))
New Year's Day
Orthodox Christmas
International Women's Day

Using this package, you can also create calendars from scratch or edit existing ones.

Versions and Compatibility
--------------------------

Expand Down
6 changes: 2 additions & 4 deletions docs/about.rst
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
About
=====

`Max M`_ had often needed to parse and generate iCalendar files. Finally he got
`Max M`_ had often needed to parse and generate iCalendar files. Finally, he got
tired of writing ad-hoc tools. This package is his attempt at making an
iCalendar package for Python. The inspiration has come from the email package
in the standard lib, which he thinks is pretty simple, yet efficient and
powerful.

At the time of writing this, last version was released more then 2 years ago.
Since then many things have changes. For one, `RFC 2445`_ was updated by `RFC
5545`_ which makes this package. So in some sense this package became outdated.
The icalendar package is an RFC 5545-compatible parser/generator for iCalendar files.

.. _`Max M`: http://www.mxm.dk
.. _`RFC 2445`: https://tools.ietf.org/html/rfc2445
Expand Down
2 changes: 2 additions & 0 deletions docs/credits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ icalendar contributors
- Thomas Bruederli <thomas@roundcube.net>
- Thomas Weißschuh <thomas@t-8ch.de>
- Victor Varvaryuk <victor.varvariuc@gmail.com>
- Ville Skyttä <ville.skytta@iki.fi>
- Wichert Akkerman <wichert@wiggy.net>
- cillianderoiste <cillian.deroiste@gmail.com>
- fitnr <fitnr@fakeisthenewreal>
Expand All @@ -69,6 +70,7 @@ icalendar contributors
- `Natasha Mattson <https://github.com/natashamm`_
- `NikEasY <https://github.com/NikEasY>`_
- Matt Lewis <git@semiprime.com>
- Felix Stupp <felix.stupp@banananet.work>

Find out who contributed::

Expand Down
2 changes: 1 addition & 1 deletion docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Try it out:
Type "help", "copyright", "credits" or "license" for more information.
>>> import icalendar
>>> icalendar.__version__
'5.0.7'
'5.0.10'

Building the documentation locally
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -342,5 +342,5 @@ Print out the calendar::
More documentation
==================

Have a look at the tests of this package to get more examples.
Have a look at the `tests <https://github.com/collective/icalendar/tree/master/src/icalendar/tests>`__ of this package to get more examples.
All modules and classes docstrings, which document how they work.
2 changes: 1 addition & 1 deletion src/icalendar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '5.0.7'
__version__ = '5.0.10'

from icalendar.cal import (
Calendar,
Expand Down
63 changes: 46 additions & 17 deletions src/icalendar/cal.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ def is_broken(self):
#############################
# handling of property values

def _encode(self, name, value, parameters=None, encode=1):
@staticmethod
def _encode(name, value, parameters=None, encode=1):
"""Encode values to icalendar property values.

:param name: Name of the property.
Expand All @@ -138,17 +139,19 @@ def _encode(self, name, value, parameters=None, encode=1):
return value
if isinstance(value, types_factory.all_types):
# Don't encode already encoded values.
return value
klass = types_factory.for_property(name)
obj = klass(value)
obj = value
else:
klass = types_factory.for_property(name)
obj = klass(value)
if parameters:
if isinstance(parameters, dict):
params = Parameters()
for key, item in parameters.items():
params[key] = item
parameters = params
assert isinstance(parameters, Parameters)
obj.params = parameters
if not hasattr(obj, "params"):
obj.params = Parameters()
for key, item in parameters.items():
if item is None:
if key in obj.params:
del obj.params[key]
else:
obj.params[key] = item
return obj

def add(self, name, value, parameters=None, encode=1):
Expand Down Expand Up @@ -372,19 +375,26 @@ def from_ical(cls, st, multiple=False):
if not component:
raise ValueError(f'Property "{name}" does not have a parent component.')
datetime_names = ('DTSTART', 'DTEND', 'RECURRENCE-ID', 'DUE',
'FREEBUSY', 'RDATE', 'EXDATE')
'RDATE', 'EXDATE')
try:
if name in datetime_names and 'TZID' in params:
vals = factory(factory.from_ical(vals, params['TZID']))
if name == 'FREEBUSY':
vals = vals.split(',')
if 'TZID' in params:
parsed_components = [factory(factory.from_ical(val, params['TZID'])) for val in vals]
else:
parsed_components = [factory(factory.from_ical(val)) for val in vals]
elif name in datetime_names and 'TZID' in params:
parsed_components = [factory(factory.from_ical(vals, params['TZID']))]
else:
vals = factory(factory.from_ical(vals))
parsed_components = [factory(factory.from_ical(vals))]
except ValueError as e:
if not component.ignore_exceptions:
raise
component.errors.append((uname, str(e)))
else:
vals.params = params
component.add(name, vals, encode=0)
for parsed_component in parsed_components:
parsed_component.params = params
component.add(name, parsed_component, encode=0)

if multiple:
return comps
Expand Down Expand Up @@ -436,6 +446,25 @@ def __repr__(self):
subs = ', '.join(str(it) for it in self.subcomponents)
return f"{self.name or type(self).__name__}({dict(self)}{', ' + subs if subs else ''})"

def __eq__(self, other):
if not len(self.subcomponents) == len(other.subcomponents):
return False

properties_equal = super().__eq__(other)
if not properties_equal:
return False

# The subcomponents might not be in the same order,
# neither there's a natural key we can sort the subcomponents by nor
# are the subcomponent types hashable, so we cant put them in a set to
# check for set equivalence. We have to iterate over the subcomponents
# and look for each of them in the list.
for subcomponent in self.subcomponents:
if subcomponent not in other.subcomponents:
return False

return True


#######################################
# components defined in RFC 5545
Expand Down
4 changes: 2 additions & 2 deletions src/icalendar/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ def view(event):
end = event.decoded('dtend', default=start)
duration = event.decoded('duration', default=end - start)
if isinstance(start, datetime):
start = start.astimezone(start.tzinfo)
start = start.astimezone()
start = start.strftime('%c')
if isinstance(end, datetime):
end = end.astimezone(end.tzinfo)
end = end.astimezone()
end = end.strftime('%c')

return f""" Organizer: {organizer}
Expand Down
15 changes: 10 additions & 5 deletions src/icalendar/prop.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ def from_ical(cls, ical, timezone=None):
if u.startswith(('P', '-P', '+P')):
return vDuration.from_ical(ical)
if '/' in u:
return vPeriod.from_ical(ical)
return vPeriod.from_ical(ical, timezone=timezone)

if len(ical) in (15, 16):
return vDatetime.from_ical(ical, timezone=timezone)
Expand Down Expand Up @@ -533,6 +533,11 @@ def __cmp__(self, other):
f'Cannot compare vPeriod with {other!r}')
return cmp((self.start, self.end), (other.start, other.end))

def __eq__(self, other):
if not isinstance(other, vPeriod):
return False
return (self.start, self.end) == (other.start, other.end)

def overlaps(self, other):
if self.start > other.start:
return other.overlaps(self)
Expand All @@ -548,11 +553,11 @@ def to_ical(self):
+ vDatetime(self.end).to_ical())

@staticmethod
def from_ical(ical):
def from_ical(ical, timezone=None):
try:
start, end_or_duration = ical.split('/')
start = vDDDTypes.from_ical(start)
end_or_duration = vDDDTypes.from_ical(end_or_duration)
start = vDDDTypes.from_ical(start, timezone=timezone)
end_or_duration = vDDDTypes.from_ical(end_or_duration, timezone=timezone)
return (start, end_or_duration)
except Exception:
raise ValueError(f'Expected period format, got: {ical}')
Expand Down Expand Up @@ -719,7 +724,7 @@ def __new__(cls, value, encoding=DEFAULT_ENCODING):
return self

def __repr__(self):
return f"vText('{self.to_ical()}')"
return f"vText('{self.to_ical()!r}')"

def to_ical(self):
return escape_char(self).encode(self.encoding)
Expand Down
40 changes: 40 additions & 0 deletions src/icalendar/tests/calendars/example.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:collective/icalendar
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:Holidays
X-WR-TIMEZONE:Etc/GMT
BEGIN:VEVENT
SUMMARY:New Year's Day
DTSTART:20220101
DTEND:20220101
DESCRIPTION:Happy New Year!
UID:636a0cc1dbd5a1667894465@icalendar
DTSTAMP:20221108T080105Z
STATUS:CONFIRMED
TRANSP:TRANSPARENT
SEQUENCE:0
END:VEVENT
BEGIN:VEVENT
SUMMARY:Orthodox Christmas
DTSTART:20220107
DTEND:20220107
LOCATION:Russia
DESCRIPTION:It is Christmas again!
UID:636a0cc1dbfd91667894465@icalendar
STATUS:CONFIRMED
TRANSP:TRANSPARENT
SEQUENCE:0
END:VEVENT
BEGIN:VEVENT
SUMMARY:International Women's Day
DTSTART:20220308
DTEND:20220308
DESCRIPTION:May the feminine be honoured!
UID:636a0cc1dc0f11667894465@icalendar
STATUS:CONFIRMED
TRANSP:TRANSPARENT
SEQUENCE:0
END:VEVENT
END:VCALENDAR
28 changes: 28 additions & 0 deletions src/icalendar/tests/calendars/issue_165_missing_event.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:Microsoft CDO for Microsoft Exchange
VERSION:2.0
BEGIN:VTIMEZONE
TZID:GMT +0100 (Standard) / GMT +0200 (Daylight)
BEGIN:STANDARD
DTSTART:16010101T030000
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:16010101T020000
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20150703T071009Z
DTSTART;TZID="GMT +0100 (Standard) / GMT +0200 (Daylight)":20150703T100000
SUMMARY:Sprint 25 Daily Standup
DTEND;TZID="GMT +0100 (Standard) / GMT +0200 (Daylight)":20150703T103000
RRULE:FREQ=DAILY;UNTIL=20150722T080000Z;INTERVAL=1;BYDAY=MO, TU, WE, TH, FR
;WKST=SU
END:VEVENT
END:VCALENDAR
Loading