Merge branch 'master' into doctest

pull/445/head
Nicco Kunzmann 2022-10-19 12:26:37 +01:00 zatwierdzone przez GitHub
commit dc2c280f12
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
27 zmienionych plików z 491 dodań i 205 usunięć

Wyświetl plik

@ -0,0 +1,39 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG] "
labels: ''
assignees: ''
---
<!-- This template is there to guide you and help us. If you can not complete everything here, that is fine. -->
## Describe the bug
<!-- A clear and concise description of what the bug is. -->
## To Reproduce
<!-- Please add the neccesary code here to reproduce the problem on your machine. -->
```
import icalendar
...
```
Output:
<!-- If applicable, add logs or error outputs to help explain your problem. -->
```
```
## Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
## Environment
<!-- please complete the following information: -->
- [ ] OS: <!-- e.g. Ubuntu 22 or Windows 10 -->
- [ ] Python version: <!-- e.g. Python 3.10 -->
- [ ] `icalendar` version: <!-- python3 -c 'import icalendar; print(icalendar.__version__)' -->
## Additional context
<!-- Add any other context about the problem here, related issues and pull requests. -->
- [ ] I tested it with the latest version `pip3 install https://github.com/collective/icalendar.git`
- [ ] I attached the ICS source file or there is no ICS source file

Wyświetl plik

@ -0,0 +1,18 @@
---
name: empty issue
about: This is an unstructured issue template to use with issues that are not described,
yet.
title: ''
labels: ''
assignees: ''
---
<!-- This is an unstructured issue template to use if you do not need guidance.
Here are some hints though:
- add ICS example files if you can
- show code if possible
- show error output or output that differs from what you expect
- it is nice to connect to the value of this issue
Thanks for taking your time to report this!
-->

Wyświetl plik

@ -2,14 +2,17 @@ name: tests
on:
push:
branches: [ main ]
branches:
- main
tags:
- v*
pull_request:
schedule:
- cron: '14 7 * * 0' # run once a week on Sunday
workflow_dispatch:
jobs:
build:
run-tests:
strategy:
matrix:
config:
@ -20,6 +23,7 @@ jobs:
- ["3.10", "py310"]
- ["pypy-3.9", "pypy3"]
- ["3.10", "docs"]
- ["3.10", "plone"]
- ["3.11.0-rc.1", "py311"]
runs-on: ubuntu-latest
@ -50,3 +54,61 @@ jobs:
coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
deploy-tag-to-pypi:
# only deploy on tags, see https://stackoverflow.com/a/58478262/1320237
if: startsWith(github.ref, 'refs/tags/v')
needs:
- run-tests
runs-on: ubuntu-latest
# This environment stores the TWINE_USERNAME and TWINE_PASSWORD
# see https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment
environment:
name: PyPI
url: https://pypi.org/project/icalendar/
# after using the environment, we need to make the secrets available
# see https://docs.github.com/en/actions/security-guides/encrypted-secrets#example-using-bash
env:
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.9"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install wheel twine
- name: Check the tag
run: |
PACKAGE_VERSION=`python setup.py --version`
TAG_NAME=v$PACKAGE_VERSION
echo "Package version $PACKAGE_VERSION with possible tag name $TAG_NAME on $GITHUB_REF_NAME"
# test that the tag represents the version
# see https://docs.github.com/en/actions/learn-github-actions/environment-variables
if [ "$TAG_NAME" != "$GITHUB_REF_NAME" ]; then
echo "ERROR: This tag is for the wrong version. Got \"$GITHUB_REF_NAME\" expected \"$TAG_NAME\"."
exit 1
fi
- name: remove old files
run: rm -rf dist/*
- name: build distribution files
run: python setup.py bdist_wheel sdist
- name: deploy to pypi
run: |
# You will have to set the variables TWINE_USERNAME and TWINE_PASSWORD
# You can use a token specific to your project by setting the user name to
# __token__ and the password to the token given to you by the PyPI project.
# sources:
# - https://shambu2k.hashnode.dev/gitlab-to-pypi
# - http://blog.octomy.org/2020/11/deploying-python-pacakges-to-pypi-using.html?m=1
if [ -z "$TWINE_USERNAME" ]; then
echo "WARNING: TWINE_USERNAME not set!"
fi
if [ -z "$TWINE_PASSWORD" ]; then
echo "WARNING: TWINE_PASSWORD not set!"
fi
twine check dist/*
twine upload dist/*

Wyświetl plik

@ -1,21 +1,42 @@
Changelog
=========
5.0.1 (unreleased)
------------------
5.0.0a2 (unreleased)
--------------------
Minor changes:
- fixed setuptools deprecation warnings [mgorny]
Breaking changes:
- ...
New features:
- ...
Bug fixes:
- ...
5.0.0 (2022-10-17)
------------------
Minor changes:
- removed deprecated test checks [tuergeist]
- Fix: cli does not support DURATION #354 [mamico]
- Add changelog and contributing to readthedocs documentation #428 [peleccom]
- fixed small typos #323 [rohnsha0]
- unittest to parametrized pytest refactoring [jacadzaca]
Breaking changes:
- Require Python 3.7 as minimum Python version. [maurits] [niccokunzmann]
- icalenar now takes a ics file directly as an input
- icalendar's output is different
- Drop Support for Python 3.6. Versions 3.7 - 3.11 are supported and tested.
New features:
@ -36,6 +57,8 @@ Bug fixes:
Ref: #338
Fixes: #335
[tobixen]
- add ``__eq__`` to ``icalendar.prop.vDDDTypes`` #391 [jacadzaca]
- Refactor deprecated unittest aliases for Python 3.11 compatibility #330 [tirkarthi]
5.0.0a1 (2022-07-11)
--------------------

Wyświetl plik

@ -63,6 +63,7 @@ icalendar contributors
- jacadzaca <vitouejj@gmail.com>
- Mauro Amico <mauro.amico@gmail.com>
- Alexander Pitkin <peleccom@gmail.com>
- Michał Górny <mgorny@gentoo.org>
Find out who contributed::

Wyświetl plik

@ -25,6 +25,9 @@ Maintainers need this:
- ``Maintainer`` access to the `Read The Docs project <https://readthedocs.org/projects/icalendar/>`_.
This can be given by existing maintainers listed on the project's page.
TODO: link to the settings
- ``PyPI environment access for GitHub Actions`` grant new releases from tags.
This access can be granted in `Settings → Environments → PyPI <https://github.com/collective/icalendar/settings/environments/674266024/edit>`__
by adding the GitHub username to the list of "Required Reviewers".
Contributors
@ -42,37 +45,79 @@ Nobody should merge their own pull requests.
If you like to review or merge pull requests of other people and you have shown that you know how to contribute,
you can ask for becoming a contributor or a maintainer asks you if you would like to become one.
New Releases
------------
This explains how to create a new release on PyPI.
You will need write access to the `PyPI project`_.
This explains how to create a new release on `PyPI <https://pypi.org/project/icalendar/>`_.
1. Check that the ``CHANGES.rst`` is up to date with the latest merges and the version you want to release is correctly named.
Since contributors and maintainers have write access the the repository, they can start the release process.
However, only people with ``PyPI environment access for GitHub Actions`` can approve an automated release to PyPI.
1. Check that the ``CHANGES.rst`` is up to date with the `latest merged pull requests <https://github.com/collective/icalendar/pulls?q=is%3Apr+is%3Amerged>`__
and the version you want to release is correctly named.
2. Change the ``__version__`` variable in
- the ``src/icalendar/__init__.py`` file and
- in the ``docs/usage.rst`` file (look for ``icalendar.__version__``)
3. Create a commit on the ``master`` branch to release this version.
3. Create a commit on the ``release-5.0.0`` branch (or equivalent) to release this version.
.. code-block:: bash
.. code-block:: bash
git checkout master
git commit -am"version 5.0.0a2"
4. Push the commit and see if the `CI-tests <https://github.com/collective/icalendar/actions?query=branch%3Amaster>`__ are running on it.
git checkout master
git pull
git checkout -b release master
git add CHANGES.rst src/icalendar/__init__.py
git commit -m"version 5.0.0"
.. code-block:: bash
4. Push the commit and `create a pull request <https://github.com/collective/icalendar/compare?expand=1>`__
Here is an `example pull request #457 <https://github.com/collective/icalendar/pull/457>`__.
git push
5. Create a tag for the release and see if the `CI-tests <https://github.com/collective/icalendar/actions>`__ are running.
.. code-block:: bash
.. code-block:: bash
git push -u origin release-5.0.0
git tag v5.0.0a2
git push origin v5.0.0a2
6. TODO: how to release new version to PyPI.
5. See if the `CI-tests <https://github.com/collective/icalendar/actions>`_ are running on the pull request.
If they are not running, no new release can be issued.
If the tests are running, merge the pull request.
6. Create a tag for the release and see if the `CI-tests`_ are running.
.. code-block:: bash
git checkout master
git pull
git tag v5.0.0
git push upstream v5.0.0 # could be origin or whatever reference
7. Once the tag is pushed and its `CI-tests`_ are passing, maintainers will get an e-mail::
Subject: Deployment review in collective/icalendar
tests: PyPI is waiting for your review
8. If the release is approved by a maintainer. It will be pushed to `PyPI`_.
If that happens, notify the issues that were fixed about this release.
9. Copy this to the start of ``CHANGES.rst`` and create a new commit with this on the ``master`` branch::
5.0.1 (unreleased)
------------------
Minor changes:
- ...
Breaking changes:
- ...
New features:
- ...
Bug fixes:
- ...
Links
-----
@ -82,6 +127,7 @@ This section contains useful links for maintainers and contributors:
- `Future of icalendar, looking for maintainer #360 <https://github.com/collective/icalendar/discussions/360>`__
- `Team icalendar-admin <https://github.com/orgs/collective/teams/icalendar-admin>`__
- `Team icalendar-contributor <https://github.com/orgs/collective/teams/icalendar-contributor>`__
- `Comment on the Plone tests running with icalendar <https://github.com/collective/icalendar/pull/447#issuecomment-1277643634>`__

Wyświetl plik

@ -13,7 +13,7 @@ create-wheel = yes
universal = 1
[metadata]
license_file = LICENSE.rst
license_files = LICENSE.rst
[tool:pytest]
norecursedirs = .* env* docs *.egg src/icalendar/tests/hypothesis

Wyświetl plik

@ -42,6 +42,7 @@ setuptools.setup(
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
],
@ -51,7 +52,7 @@ setuptools.setup(
author_email='plone-developers@lists.sourceforge.net',
url='https://github.com/collective/icalendar',
license='BSD',
packages=setuptools.find_packages('src'),
packages=setuptools.find_namespace_packages('src'),
package_dir={'': 'src'},
include_package_data=True,
zip_safe=False,

Wyświetl plik

@ -1,4 +1,4 @@
__version__ = '5.0.0a2.dev0'
__version__ = '5.0.0'
from icalendar.cal import (
Calendar,

Wyświetl plik

@ -0,0 +1,7 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
SUMMARY:An Event with too many semicolons
DTSTART;;VALUE=DATE-TIME:20140409T093000
UID:abc
END:VEVENT
END:VCALENDAR

Wyświetl plik

@ -0,0 +1,25 @@
BEGIN:VCALENDAR
X-SOURCE-URL:https://github.com/pimutils/khal/issues/152#issuecomment-387410353
VERSION:2.0
PRODID:-//PIMUTILS.ORG//NONSGML khal / icalendar //EN
BEGIN:VEVENT
SUMMARY:Event
DTSTART;TZID=America/Chicago;VALUE=DATE-TIME:20180327T080000
DTEND;TZID=America/Chicago;VALUE=DATE-TIME:20180327T090000
DTSTAMP:20180323T200333Z
RECURRENCE-ID;RANGE=THISANDFUTURE:20180327T130000Z
SEQUENCE:10
RDATE;TZID="Central Standard Time";VALUE=PERIOD:20180327T080000/20180327T0
90000,20180403T080000/20180403T090000,20180410T080000/20180410T090000,2018
0417T080000/20180417T090000,20180424T080000/20180424T090000,20180501T08000
0/20180501T090000,20180508T080000/20180508T090000,20180515T080000/20180515
T090000,20180522T080000/20180522T090000,20180529T080000/20180529T090000,20
180605T080000/20180605T090000,20180612T080000/20180612T090000,20180619T080
000/20180619T090000,20180626T080000/20180626T090000,20180703T080000/201807
03T090000,20180710T080000/20180710T090000,20180717T080000/20180717T090000,
20180724T080000/20180724T090000,20180731T080000/20180731T090000
ATTENDEE;CN="XYZ";PARTSTAT=ACCEPTED;ROLE=CHAIR;RSVP=
FALSE:mailto:xyz@xyz.com
CLASS:PUBLIC
END:VEVENT
END:VCALENDAR

Wyświetl plik

@ -0,0 +1,55 @@
BEGIN:VCALENDAR
X-SOURCE-URL:https://github.com/pimutils/khal/issues/152#issuecomment-933635248
VERSION:2.0
PRODID:-//PIMUTILS.ORG//NONSGML khal / icalendar //EN
BEGIN:VTIMEZONE
TZID:Western/Central Europe
BEGIN:STANDARD
DTSTART:19501029T020000
RRULE:FREQ=YEARLY;BYMINUTE=0;BYHOUR=2;BYDAY=-1SU;BYMONTH=10
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19500326T020000
RRULE:FREQ=YEARLY;BYMINUTE=0;BYHOUR=2;BYDAY=-1SU;BYMONTH=3
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:(omitted)
DTSTART;TZID="Western/Central Europe";VALUE=DATE-TIME:20211101T160000
DTEND;TZID="Western/Central Europe";VALUE=DATE-TIME:20211101T163000
DTSTAMP:20211004T150245Z
UID:BF5109494E67AAE20025875100566D31-Lotus_Notes_Generated
RECURRENCE-ID;RANGE=THISANDFUTURE:20211101T150000Z
SEQUENCE:0
RDATE;TZID="Western/Central Europe";VALUE=PERIOD:20211101T160000/20211101T
163000,20211206T160000/20211206T163000,20220103T160000/20220103T163000,202
20207T160000/20220207T163000
ATTENDEE;CN="(omitted)";PARTSTAT=ACCEPTED;ROLE=CHAIR;RSVP=FAL
SE:mailto:omitted@example.com
CLASS:PUBLIC
TRANSP:OPAQUE
X-LOTUS-APPTTYPE:3
X-LOTUS-AUDIOVIDEOFLAGS:0
X-LOTUS-BROADCAST:FALSE
X-LOTUS-CHANGE-INST-DATES:20211101T150000Z\,20211206T150000Z\,20220103T150
000Z\,20220207T150000Z
X-LOTUS-CHILD-UID:567EFBAF6CBD07FC0025875100566D3B
X-LOTUS-INITIAL-RDATES:20211101T150000Z\,20211206T150000Z\,20220103T150000
Z\,20220207T150000Z
X-LOTUS-LASTALL-RDATES;TZID="Western/Central Europe":20211101T160000\,2021
1206T160000\,20220103T160000\,20220207T160000
X-LOTUS-NOTESVERSION:2
X-LOTUS-NOTICETYPE:I
X-LOTUS-RECURID;RANGE=THISANDFUTURE:20211101T150000Z
X-LOTUS-UPDATE-SEQ:2
X-LOTUS-UPDATE-WISL:$W:1\;$O:1\;$M:1\;RequiredAttendees:1\;INetRequiredNam
es:1\;AltRequiredNames:1\;StorageRequiredNames:1\;OptionalAttendees:1\;INe
tOptionalNames:1\;AltOptionalNames:1\;StorageOptionalNames:1\;ApptUNIDURL:
1\;STUnyteConferenceURL:1\;STUnyteConferenceID:1\;SametimeType:1\;WhiteBoa
rdContent:1\;STRoomName:1\;$S:2\;$B:2\;$L:2\;$E:2\;$R:2
END:VEVENT
END:VCALENDAR

Wyświetl plik

@ -0,0 +1,23 @@
BEGIN:VCALENDAR
BEGIN:VTIMEZONE
TZID:(UTC-03:00) Brasília
BEGIN:STANDARD
TZNAME:Brasília standard
DTSTART:16010101T235959
TZOFFSETFROM:-0200
TZOFFSETTO:-0300
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SA;BYMONTH=2
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:Brasília daylight
DTSTART:16010101T235959
TZOFFSETFROM:-0300
TZOFFSETTO:-0200
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SA;BYMONTH=10
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID="(UTC-03:00) Brasília":20170511T133000
DTEND;TZID="(UTC-03:00) Brasília":20170511T140000
END:VEVENT
END:VCALENDAR

Wyświetl plik

@ -1,5 +1,4 @@
import os
import logging
import pytest
import icalendar
import pytz
@ -10,7 +9,6 @@ try:
except ModuleNotFoundError:
from backports import zoneinfo
class DataSource:
'''A collection of parsed ICS elements (e.g calendars, timezones, events)'''
def __init__(self, data_source_folder, parser):
@ -24,7 +22,8 @@ class DataSource:
with open(source_path, 'rb') as f:
raw_ics = f.read()
source = self._parser(raw_ics)
source.raw_ics = raw_ics
if not isinstance(source, list):
source.raw_ics = raw_ics
self.__dict__[attribute] = source
return source
@ -34,10 +33,19 @@ class DataSource:
def __repr__(self):
return repr(self.__dict__)
@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))
HERE = os.path.dirname(__file__)
CALENDARS_FOLDER = os.path.join(HERE, 'calendars')
TIMEZONES_FOLDER = os.path.join(HERE, 'timezones')
EVENTS_FOLDER = os.path.join(HERE, 'events')
CALENDARS_FOLDER = os.path.join(HERE, 'calendars')
@pytest.fixture
def calendars():
return DataSource(CALENDARS_FOLDER, icalendar.Calendar.from_ical)
@pytest.fixture
def timezones():
@ -56,6 +64,10 @@ def events():
def utc(request):
return request.param
@pytest.fixture
def calendars():
return DataSource(CALENDARS_FOLDER, icalendar.Calendar.from_ical)
@pytest.fixture(params=[
lambda dt, tzname: pytz.timezone(tzname).localize(dt),
lambda dt, tzname: dt.replace(tzinfo=tz.gettz(tzname)),
lambda dt, tzname: dt.replace(tzinfo=zoneinfo.ZoneInfo(tzname))
])
def in_timezone(request):
return request.param

Wyświetl plik

@ -0,0 +1,7 @@
BEGIN:VEVENT
SUMMARY:RDATE period
DTSTART:19961230T020000Z
DTEND:19961230T060000Z
UID:rdate_period
RDATE;VALUE=PERIOD:19970101T180000Z/19970102T070000Z
END:VEVENT

Wyświetl plik

@ -0,0 +1,8 @@
BEGIN:VEVENT
SUMMARY:RDATE period
DTSTART:19961230T020000Z
DTEND:19961230T060000Z
UID:rdate_period
RDATE;VALUE=PERIOD:19970101T180000Z/19970102T070000Z,19970109T180000Z/PT5H
30M
END:VEVENT

Wyświetl plik

@ -1,78 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Meetup//RemoteApi//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-ORIGINAL-URL:http://www.meetup.com/DevOpsDC/events/ical/DevOpsDC/
X-WR-CALNAME:Events - DevOpsDC
BEGIN:VTIMEZONE
TZID:America/New_York
TZURL:http://tzurl.org/zoneinfo-outlook/America/New_York
X-LIC-LOCATION:America/New_York
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20120605T003759Z
DTSTART;TZID=America/New_York:20120712T183000
DTEND;TZID=America/New_York:20120712T213000
STATUS:CONFIRMED
SUMMARY:DevOps DC Meetup
DESCRIPTION:DevOpsDC\nThursday\, July 12 at 6:30 PM\n\nThis will be a joi
nt meetup / hack night with the DC jQuery Users Group. The idea behind
the hack night: Small teams consisting of at least 1 member...\n\nDeta
ils: http://www.meetup.com/DevOpsDC/events/47635522/
CLASS:PUBLIC
CREATED:20120111T120339Z
GEO:38.90;-77.01
LOCATION:Fathom Creative\, Inc. (1333 14th Street Northwest\, Washington
D.C.\, DC 20005)
URL:http://www.meetup.com/DevOpsDC/events/47635522/
LAST-MODIFIED:20120522T174406Z
UID:event_qtkfrcyqkbnb@meetup.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120605T003759Z
DTSTART;TZID=America/New_York:20120911T183000
DTEND;TZID=America/New_York:20120911T213000
STATUS:CONFIRMED
SUMMARY:DevOps DC Meetup
DESCRIPTION:DevOpsDC\nTuesday\, September 11 at 6:30 PM\n\n \n\nDetails:
http://www.meetup.com/DevOpsDC/events/47635532/
CLASS:PUBLIC
CREATED:20120111T120352Z
GEO:38.90;-77.01
LOCATION:CustomInk\, LLC (7902 Westpark Drive\, McLean\, VA 22102)
URL:http://www.meetup.com/DevOpsDC/events/47635532/
LAST-MODIFIED:20120316T202210Z
UID:event_qtkfrcyqmbpb@meetup.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120605T003759Z
DTSTART;TZID=America/New_York:20121113T183000
DTEND;TZID=America/New_York:20121113T213000
STATUS:CONFIRMED
SUMMARY:DevOps DC Meetup
DESCRIPTION:DevOpsDC\nTuesday\, November 13 at 6:30 PM\n\n \n\nDetails: h
ttp://www.meetup.com/DevOpsDC/events/47635552/
CLASS:PUBLIC
CREATED:20120111T120402Z
GEO:38.90;-77.01
LOCATION:CustomInk\, LLC (7902 Westpark Drive\, McLean\, VA 22102)
URL:http://www.meetup.com/DevOpsDC/events/47635552/
LAST-MODIFIED:20120316T202210Z
UID:event_qtkfrcyqpbrb@meetup.com
END:VEVENT
END:VCALENDAR

Wyświetl plik

@ -1,4 +1,5 @@
import pytest
import datetime
@pytest.mark.parametrize('field, expected_value', [
('PRODID', '-//Plönë.org//NONSGML plone.app.event//EN'),
@ -27,3 +28,41 @@ def test_events_parameter_unicoded(events):
https://github.com/collective/icalendar/issues/101
'''
assert events.issue_101_icalendar_chokes_on_umlauts_in_organizer['ORGANIZER'].params['CN'] == 'acme, ädmin'
def test_parses_event_with_non_ascii_tzid_issue_237(calendars, in_timezone):
"""Issue #237 - Fail to parse timezone with non-ascii TZID
see https://github.com/collective/icalendar/issues/237
"""
start = calendars.issue_237_fail_to_parse_timezone_with_non_ascii_tzid.walk('VEVENT')[0].decoded('DTSTART')
expected = in_timezone(datetime.datetime(2017, 5, 11, 13, 30), 'America/Sao_Paulo')
assert not calendars.issue_237_fail_to_parse_timezone_with_non_ascii_tzid.errors
assert start == expected
def test_parses_timezone_with_non_ascii_tzid_issue_237(timezones):
"""Issue #237 - Fail to parse timezone with non-ascii TZID
see https://github.com/collective/icalendar/issues/237
"""
assert timezones.issue_237_brazilia_standard['tzid'] == '(UTC-03:00) Brasília'
@pytest.mark.parametrize('timezone_name', ['standard', 'daylight'])
def test_parses_timezone_with_non_ascii_tzname_issue_273(timezones, timezone_name):
"""Issue #237 - Fail to parse timezone with non-ascii TZID
see https://github.com/collective/icalendar/issues/237
"""
assert timezones.issue_237_brazilia_standard.walk(timezone_name)[0]['TZNAME'] == f'Brasília {timezone_name}'
def test_broken_property(calendars):
"""
Test if error messages are encoded properly.
"""
for event in calendars.broken_ical.walk('vevent'):
assert len(event.errors) == 1, 'Not the right amount of errors.'
error = event.errors[0][1]
assert error.startswith('Content line could not be parsed into parts')
def test_apple_xlocation(calendars):
"""
Test if we support base64 encoded binary data in parameter values.
"""
for event in calendars.x_location.walk('vevent'):
assert len(event.errors) == 0, 'Got too many errors'

Wyświetl plik

@ -42,47 +42,3 @@ class TestIssues(unittest.TestCase):
event.to_ical(),
icalendar.Event.from_ical(event.to_ical()).to_ical()
)
def test_issue_237(self):
"""Issue #237 - Fail to parse timezone with non-ascii TZID"""
ical_str = ['BEGIN:VCALENDAR',
'BEGIN:VTIMEZONE',
'TZID:(UTC-03:00) Brasília',
'BEGIN:STANDARD',
'TZNAME:Brasília standard',
'DTSTART:16010101T235959',
'TZOFFSETFROM:-0200',
'TZOFFSETTO:-0300',
'RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SA;BYMONTH=2',
'END:STANDARD',
'BEGIN:DAYLIGHT',
'TZNAME:Brasília daylight',
'DTSTART:16010101T235959',
'TZOFFSETFROM:-0300',
'TZOFFSETTO:-0200',
'RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SA;BYMONTH=10',
'END:DAYLIGHT',
'END:VTIMEZONE',
'BEGIN:VEVENT',
'DTSTART;TZID=\"(UTC-03:00) Brasília\":20170511T133000',
'DTEND;TZID=\"(UTC-03:00) Brasília\":20170511T140000',
'END:VEVENT',
'END:VCALENDAR',
]
cal = icalendar.Calendar.from_ical('\r\n'.join(ical_str))
self.assertEqual(cal.errors, [])
dtstart = cal.walk(name='VEVENT')[0].decoded("DTSTART")
expected = pytz.timezone('America/Sao_Paulo').localize(datetime.datetime(2017, 5, 11, 13, 30))
self.assertEqual(dtstart, expected)
try:
expected_zone = '(UTC-03:00) Brasília'
expected_tzname = 'Brasília standard'
except UnicodeEncodeError:
expected_zone = '(UTC-03:00) Brasília'.encode('ascii', 'replace')
expected_tzname = 'Brasília standard'.encode('ascii', 'replace')
self.assertEqual(dtstart.tzinfo.zone, expected_zone)
self.assertEqual(dtstart.tzname(), expected_tzname)

Wyświetl plik

@ -291,34 +291,3 @@ class IcalendarTestCase (unittest.TestCase):
'Max,Moller,"Rasmussen, Max"')
class TestEncoding(unittest.TestCase):
def test_broken_property(self):
"""
Test if error messages are encode properly.
"""
broken_ical = textwrap.dedent("""
BEGIN:VCALENDAR
BEGIN:VEVENT
SUMMARY:An Event with too many semicolons
DTSTART;;VALUE=DATE-TIME:20140409T093000
UID:abc
END:VEVENT
END:VCALENDAR
""")
cal = icalendar.Calendar.from_ical(broken_ical)
for event in cal.walk('vevent'):
self.assertEqual(len(event.errors), 1, 'Not the right amount of errors.')
error = event.errors[0][1]
self.assertTrue(error.startswith('Content line could not be parsed into parts'))
def test_apple_xlocation(self):
"""
Test if we support base64 encoded binary data in parameter values.
"""
directory = os.path.dirname(__file__)
with open(os.path.join(directory, 'x_location.ics'), 'rb') as fp:
data = fp.read()
cal = icalendar.Calendar.from_ical(data)
for event in cal.walk('vevent'):
self.assertEqual(len(event.errors), 0, 'Got too many errors')

Wyświetl plik

@ -1,27 +1,15 @@
"""An example with multiple VCALENDAR components"""
from icalendar import Calendar
from icalendar.prop import vText
import unittest
import os
class TestMultiple(unittest.TestCase):
"""A example with multiple VCALENDAR components"""
def test_multiple(self):
def test_multiple(calendars):
"""Check opening multiple calendars."""
directory = os.path.dirname(__file__)
with open(os.path.join(directory, 'multiple.ics'), 'rb') as fp:
data = fp.read()
cals = Calendar.from_ical(data, multiple=True)
cals = calendars.multiple.multiple_calendar_components
self.assertEqual(len(cals), 2)
self.assertSequenceEqual([comp.name for comp in cals[0].walk()],
['VCALENDAR', 'VEVENT'])
self.assertSequenceEqual([comp.name for comp in cals[1].walk()],
['VCALENDAR', 'VEVENT', 'VEVENT'])
self.assertEqual(
cals[0]['prodid'],
vText('-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN')
)
assert len(cals) == 2
assert [comp.name for comp in cals[0].walk()] == ['VCALENDAR', 'VEVENT']
assert [comp.name for comp in cals[1].walk()] == ['VCALENDAR', 'VEVENT', 'VEVENT']
assert cals[0]['prodid'] == vText('-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN')

Wyświetl plik

@ -15,9 +15,11 @@ from icalendar.parser import Contentline, Parameters
# Nonstandard component inside other components, also has properties
'issue_178_custom_component_inside_other',
# Nonstandard component is able to contain other components
'issue_178_custom_component_contains_other'])
'issue_178_custom_component_contains_other',
])
def test_calendar_to_ical_is_inverse_of_from_ical(calendars, calendar_name):
calendar = getattr(calendars, calendar_name)
assert calendar.to_ical().splitlines() == calendar.raw_ics.splitlines()
assert calendar.to_ical() == calendar.raw_ics
@pytest.mark.parametrize('raw_content_line, expected_output', [
@ -74,10 +76,14 @@ def test_issue_157_removes_trailing_semicolon(events):
# https://github.com/collective/icalendar/pull/100
('issue_100_transformed_doctests_into_unittests'),
('issue_184_broken_representation_of_period'),
# PERIOD should be put back into shape
'issue_156_RDATE_with_PERIOD',
'issue_156_RDATE_with_PERIOD_list',
])
def test_event_to_ical_is_inverse_of_from_ical(events, event_name):
"""Make sure that an event's ICS is equal to the ICS it was made from."""
event = events[event_name]
assert event.to_ical().splitlines() == event.raw_ics.splitlines()
assert event.to_ical() == event.raw_ics
def test_decode_rrule_attribute_error_issue_70(events):

Wyświetl plik

@ -0,0 +1,48 @@
"""These tests make sure that we have some coverage on the usage of the PERIOD value type.
See
- https://github.com/collective/icalendar/issues/156
- https://github.com/pimutils/khal/issues/152#issuecomment-933635248
"""
import pytest
import pytz
from icalendar.prop import vDDDTypes
@pytest.mark.parametrize("calname,tzname,index,period_string", [
("issue_156_RDATE_with_PERIOD_TZID_khal_2", "Europe/Berlin", 0, "20211101T160000/20211101T163000"),
("issue_156_RDATE_with_PERIOD_TZID_khal_2", "Europe/Berlin", 1, "20211206T160000/20211206T163000"),
("issue_156_RDATE_with_PERIOD_TZID_khal_2", "Europe/Berlin", 2, "20220103T160000/20220103T163000"),
("issue_156_RDATE_with_PERIOD_TZID_khal_2", "Europe/Berlin", 3, "20220207T160000/20220207T163000"),
] + [
("issue_156_RDATE_with_PERIOD_TZID_khal", "America/Chicago", i, period)
for i, period in enumerate(("20180327T080000/20180327T0"
"90000,20180403T080000/20180403T090000,20180410T080000/20180410T090000,2018"
"0417T080000/20180417T090000,20180424T080000/20180424T090000,20180501T08000"
"0/20180501T090000,20180508T080000/20180508T090000,20180515T080000/20180515"
"T090000,20180522T080000/20180522T090000,20180529T080000/20180529T090000,20"
"180605T080000/20180605T090000,20180612T080000/20180612T090000,20180619T080"
"000/20180619T090000,20180626T080000/20180626T090000,20180703T080000/201807"
"03T090000,20180710T080000/20180710T090000,20180717T080000/20180717T090000,"
"20180724T080000/20180724T090000,20180731T080000/20180731T090000").split(","))
])
def test_issue_156_period_list_in_rdate(calendars, calname, tzname, index, period_string):
"""Check items in a list of period values."""
calendar = calendars[calname]
rdate = calendar.walk("vevent")[0]["rdate"]
period = rdate.dts[index]
assert period.dt == vDDDTypes.from_ical(period_string, timezone=pytz.timezone(tzname))
def test_duration_properly_parsed(events):
"""This checks the duration PT5H30M."""
start = vDDDTypes.from_ical("19970109T180000Z")
duration = vDDDTypes.from_ical("PT5H30M")
rdate = events.issue_156_RDATE_with_PERIOD_list["RDATE"]
print(rdate)
period = rdate.dts[1].dt
print(dir(duration))
assert period[0] == start
assert period[1].days == 0
assert period[1].seconds == (5 * 60 + 30) * 60
assert period[1] == duration

Wyświetl plik

@ -0,0 +1,17 @@
BEGIN:VTIMEZONE
TZID:(UTC-03:00) Brasília
BEGIN:STANDARD
TZNAME:Brasília standard
DTSTART:16010101T235959
TZOFFSETFROM:-0200
TZOFFSETTO:-0300
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SA;BYMONTH=2
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:Brasília daylight
DTSTART:16010101T235959
TZOFFSETFROM:-0300
TZOFFSETTO:-0200
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SA;BYMONTH=10
END:DAYLIGHT
END:VTIMEZONE

16
tox.ini
Wyświetl plik

@ -1,6 +1,6 @@
# to run for a specific environment, use ``tox -e ENVNAME``
[tox]
envlist = py37,py38,py39,py310,pypy3,docs
envlist = py37,py38,py39,py310,pypy3,docs,plone
# Note: the 'docs' env creates a 'build' directory which may interfere in strange ways
# with the other environments. You might see this when you run the tests in parallel.
# See https://github.com/collective/icalendar/pull/359#issuecomment-1214150269
@ -23,3 +23,17 @@ changedir = docs
allowlist_externals = make
commands =
make html
[testenv:plone]
usedevelop = False
install = False
python = 3.10
commands_pre =
# Install Plone and explicitly the single package that uses icalendar, plus the test runner.
pip install Plone plone.app.event[test] zope.testrunner -c https://dist.plone.org/release/6.0-dev/constraints.txt
# Install the dev version of the package, mostly so we can safely point to the path with the tests.
pip install -e "git+https://github.com/plone/plone.app.event.git#egg=plone.app.event"
# icalendar is pinned in the constraints, but we want the current dev version.
pip install -e {toxinidir}
commands =
zope-testrunner --test-path={envdir}/src/plone-app-event {posargs:-vc}