kopia lustrzana https://github.com/collective/icalendar
Modify doctests and add more examples
rodzic
4583615b7e
commit
96b4e76cb5
99
README.rst
99
README.rst
|
@ -45,15 +45,23 @@ files.
|
|||
Quick Guide
|
||||
-----------
|
||||
|
||||
``icalendar`` enables you to **create**, **inspect** and **modify**
|
||||
calendaring information with Python.
|
||||
|
||||
To **install** the package, run::
|
||||
|
||||
pip install icalendar
|
||||
|
||||
|
||||
Inspect Files
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
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:
|
||||
>>> from pathlib import Path
|
||||
>>> ics_path = Path("src/icalendar/tests/calendars/example.ics")
|
||||
>>> with ics_path.open() as f:
|
||||
... calendar = icalendar.Calendar.from_ical(f.read())
|
||||
>>> for event in calendar.walk('VEVENT'):
|
||||
... print(event.get("SUMMARY"))
|
||||
|
@ -61,7 +69,74 @@ You can open an ``.ics`` file and see all the events::
|
|||
Orthodox Christmas
|
||||
International Women's Day
|
||||
|
||||
Using this package, you can also create calendars from scratch or edit existing ones.
|
||||
Modify Content
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Such a calendar can then be edited and saved again.
|
||||
|
||||
.. code:: python
|
||||
|
||||
>>> calendar["X-WR-CALNAME"] = "My Modified Calendar" # modify
|
||||
>>> print(calendar.to_ical()[:129]) # save modification
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:collective/icalendar
|
||||
CALSCALE:GREGORIAN
|
||||
METHOD:PUBLISH
|
||||
X-WR-CALNAME:My Modified Calendar
|
||||
|
||||
|
||||
Create Events, TODOs, Journals, Alarms, ...
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``icalendar`` supports the creation and parsing of all kinds of objects
|
||||
in the standard.
|
||||
|
||||
.. code:: python
|
||||
|
||||
>>> icalendar.Event() # events
|
||||
VEVENT({})
|
||||
>>> icalendar.FreeBusy() # free/busy times
|
||||
VFREEBUSY({})
|
||||
>>> icalendar.Todo() # Todo list entries
|
||||
VTODO({})
|
||||
>>> icalendar.Alarm() # Alarms e.g. for events
|
||||
VALARM({})
|
||||
>>> icalendar.Journal() # Journal entries
|
||||
VJOURNAL({})
|
||||
|
||||
|
||||
Have a look at `more examples
|
||||
<https://icalendar.readthedocs.io/en/latest/usage.html>`_.
|
||||
|
||||
Use Timezones of your choice
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
With ``icalendar``, you can localize your events to take place in different
|
||||
timezones.
|
||||
``zoneinfo``, ``dateutil.tz`` and ``pytz`` are compatible with ``icalendar``.
|
||||
This example creates an event that uses all of the timezone implementations
|
||||
with the same result:
|
||||
|
||||
.. code:: python
|
||||
|
||||
>>> import pytz, zoneinfo, dateutil.tz # timezone libraries
|
||||
>>> import datetime, icalendar
|
||||
>>> e = icalendar.Event()
|
||||
>>> tz = dateutil.tz.tzstr("Europe/London")
|
||||
>>> e["X-DT-DATEUTIL"] = icalendar.vDatetime(datetime.datetime(2024, 6, 19, 10, 1, tzinfo=tz))
|
||||
>>> tz = pytz.timezone("Europe/London")
|
||||
>>> e["X-DT-USE-PYTZ"] = icalendar.vDatetime(datetime.datetime(2024, 6, 19, 10, 1, tzinfo=tz))
|
||||
>>> tz = zoneinfo.ZoneInfo("Europe/London")
|
||||
>>> e["X-DT-ZONEINFO"] = icalendar.vDatetime(datetime.datetime(2024, 6, 19, 10, 1, tzinfo=tz))
|
||||
>>> print(e.to_ical()) # the libraries yield the same result
|
||||
BEGIN:VEVENT
|
||||
X-DT-DATEUTIL;TZID=Europe/London:20240619T100100
|
||||
X-DT-USE-PYTZ;TZID=Europe/London:20240619T100100
|
||||
X-DT-ZONEINFO;TZID=Europe/London:20240619T100100
|
||||
END:VEVENT
|
||||
|
||||
|
||||
|
||||
Versions and Compatibility
|
||||
--------------------------
|
||||
|
@ -70,20 +145,30 @@ Versions and Compatibility
|
|||
long-term compatibility with projects conflicts partially with providing and using the features that
|
||||
the latest Python versions bring.
|
||||
|
||||
Since we pour more `effort into maintaining and developing icalendar <https://github.com/collective/icalendar/discussions/360>`__,
|
||||
this is an overview of the versions:
|
||||
Volunteers pour `effort into maintaining and developing icalendar
|
||||
<https://github.com/collective/icalendar/discussions/360>`__.
|
||||
Below, you can find an overview of the versions and how we maintain them.
|
||||
|
||||
Version 6
|
||||
~~~~~~~~~
|
||||
|
||||
Version 6 of ``icalendar`` switches the timezone implementation to ``zoneinfo``.
|
||||
This only affects you if you parse ``icalendar`` objects with ``from_ical()``.
|
||||
The functionality is extended and is tested since 6.0.0 with both timezone
|
||||
implementations: ``pytz`` and ``zoneinfo``.
|
||||
|
||||
By default and since 6.0.0, ``zoneinfo`` timezones are created.
|
||||
|
||||
.. code:: python
|
||||
|
||||
>>> dt = icalendar.Calendar.example("timezoned").walk("VEVENT")[0]["DTSTART"].dt
|
||||
>>> dt.tzinfo
|
||||
ZoneInfo(key='Europe/Vienna')
|
||||
|
||||
If you would like to continue to use ``pytz`` and receive the latest updates, you
|
||||
can switch back:
|
||||
If you would like to continue to receive ``pytz`` timezones in as parse results,
|
||||
you can receive all the latest updates, and switch back to version 5.x behavior:
|
||||
|
||||
.. code:: python
|
||||
|
||||
>>> icalendar.use_pytz()
|
||||
>>> dt = icalendar.Calendar.example("timezoned").walk("VEVENT")[0]["DTSTART"].dt
|
||||
|
|
|
@ -2,11 +2,6 @@ try:
|
|||
from backports import zoneinfo
|
||||
except ImportError:
|
||||
import zoneinfo
|
||||
# we make it nicer for doctests
|
||||
class ZoneInfo(zoneinfo.ZoneInfo):
|
||||
def __repr__(self):
|
||||
return f"ZoneInfo(key={repr(self.key)})"
|
||||
zoneinfo.ZoneInfo = ZoneInfo
|
||||
import pytest
|
||||
import icalendar
|
||||
import pytz
|
||||
|
@ -17,6 +12,7 @@ from icalendar.timezone import tzp as _tzp
|
|||
from icalendar.timezone import TZP
|
||||
from pathlib import Path
|
||||
import itertools
|
||||
import sys
|
||||
|
||||
|
||||
class DataSource:
|
||||
|
@ -240,3 +236,26 @@ def pytest_generate_tests(metafunc):
|
|||
tzp_names.remove("zoneinfo")
|
||||
assert tzp_names, "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)})"
|
||||
|
||||
|
||||
def test_print(obj):
|
||||
"""doctest print"""
|
||||
if isinstance(obj, bytes):
|
||||
obj = obj.decode("UTF-8")
|
||||
print(str(obj).strip().replace("\r\n", "\n").replace("\r", "\n"))
|
||||
|
||||
|
||||
@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": test_print}
|
||||
|
|
|
@ -60,9 +60,19 @@ except FileNotFoundError:
|
|||
def test_files_is_included(filename):
|
||||
assert any(path.endswith(filename) for path in DOCUMENT_PATHS)
|
||||
|
||||
@pytest.mark.parametrize("document", DOCUMENT_PATHS)
|
||||
def test_documentation_file(document, zoneinfo_only):
|
||||
"""This test runs doctest on a documentation file."""
|
||||
|
||||
test_result = doctest.testfile(document, module_relative=False)
|
||||
@pytest.mark.parametrize("document", DOCUMENT_PATHS)
|
||||
def test_documentation_file(document, zoneinfo_only, env_for_doctest):
|
||||
"""This test runs doctest on a documentation file.
|
||||
|
||||
functions are also replaced to work.
|
||||
"""
|
||||
test_result = doctest.testfile(document, module_relative=False, globs=env_for_doctest)
|
||||
assert test_result.failed == 0, f"{test_result.failed} errors in {os.path.basename(document)}"
|
||||
|
||||
|
||||
def test_can_import_zoneinfo(env_for_doctest):
|
||||
"""Allow importing zoneinfo for tests."""
|
||||
import pytz
|
||||
import zoneinfo
|
||||
from dateutil import tz
|
||||
|
|
Ładowanie…
Reference in New Issue