ics-query 0.0.1a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ics_query/__init__.py ADDED
@@ -0,0 +1,11 @@
1
+ from .cli import main
2
+ from .version import __version__, __version_tuple__, version, version_tuple
3
+
4
+ __all__ = [
5
+ "main",
6
+ "app",
7
+ "__version__",
8
+ "version",
9
+ "__version_tuple__",
10
+ "version_tuple",
11
+ ]
ics_query/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ from .cli import main
4
+
5
+ sys.exit(main())
ics_query/_version.py ADDED
@@ -0,0 +1,16 @@
1
+ # file generated by setuptools_scm
2
+ # don't change, don't track in version control
3
+ TYPE_CHECKING = False
4
+ if TYPE_CHECKING:
5
+ from typing import Tuple, Union
6
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
7
+ else:
8
+ VERSION_TUPLE = object
9
+
10
+ version: str
11
+ __version__: str
12
+ __version_tuple__: VERSION_TUPLE
13
+ version_tuple: VERSION_TUPLE
14
+
15
+ __version__ = version = '0.0.1a0'
16
+ __version_tuple__ = version_tuple = (0, 0, 1)
ics_query/cli.py ADDED
@@ -0,0 +1,92 @@
1
+ """The command line interface."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ import os # noqa: TCH003
7
+ import sys
8
+ import typing as t
9
+
10
+ import click
11
+ import recurring_ical_events
12
+ from icalendar import Calendar
13
+ from recurring_ical_events import CalendarQuery
14
+
15
+ from . import parse
16
+
17
+ if t.TYPE_CHECKING:
18
+ from io import FileIO
19
+
20
+ from icalendar.cal import Component
21
+
22
+ from .parse import DateArgument
23
+
24
+ print = functools.partial(print, file=sys.stderr) # noqa: A001
25
+
26
+
27
+ class ComponentsResult:
28
+ """Output interface for components."""
29
+
30
+ def __init__(self, output: FileIO):
31
+ """Create a new result."""
32
+ self._file = output
33
+
34
+ def add_component(self, component: Component):
35
+ """Return a component."""
36
+ self._file.write(component.to_ical())
37
+
38
+
39
+ class ComponentsResultArgument(click.File):
40
+ """Argument for the result."""
41
+
42
+ def convert(
43
+ self,
44
+ value: str | os.PathLike[str] | t.IO[t.Any],
45
+ param: click.Parameter | None,
46
+ ctx: click.Context | None,
47
+ ) -> ComponentsResult:
48
+ """Return a ComponentsResult."""
49
+ file = super().convert(value, param, ctx)
50
+ return ComponentsResult(file)
51
+
52
+
53
+ class CalendarQueryInputArgument(click.File):
54
+ """Argument for the result."""
55
+
56
+ def convert(
57
+ self,
58
+ value: str | os.PathLike[str] | t.IO[t.Any],
59
+ param: click.Parameter | None,
60
+ ctx: click.Context | None,
61
+ ) -> recurring_ical_events.CalendarQuery:
62
+ """Return a CalendarQuery."""
63
+ file = super().convert(value, param, ctx)
64
+ calendar = Calendar.from_ical(file.read())
65
+ return recurring_ical_events.of(calendar)
66
+
67
+
68
+ arg_calendar = click.argument("calendar", type=CalendarQueryInputArgument("rb"))
69
+ arg_output = click.argument("output", type=ComponentsResultArgument("wb"))
70
+
71
+
72
+ @click.group()
73
+ def main():
74
+ """Simple program that greets NAME for a total of COUNT times."""
75
+ # sys.stdout = sys.stderr # remove accidential print impact
76
+
77
+
78
+ pass_datetime = click.make_pass_decorator(parse.to_time)
79
+
80
+
81
+ @main.command()
82
+ @click.argument("date", type=parse.to_time)
83
+ @arg_calendar
84
+ @arg_output
85
+ def at(calendar: CalendarQuery, output: ComponentsResult, date: DateArgument):
86
+ """Get the components at a certain time."""
87
+ for event in calendar.at(date):
88
+ print("debug")
89
+ output.add_component(event)
90
+
91
+
92
+ __all__ = ["main"]
ics_query/parse.py ADDED
@@ -0,0 +1,13 @@
1
+ """Functions for parsing the content."""
2
+
3
+ from __future__ import annotations
4
+
5
+ DateArgument = tuple[int]
6
+
7
+
8
+ def to_time(dt: str) -> DateArgument:
9
+ """Parse the time and date."""
10
+ return tuple(map(int, dt.split("-")))
11
+
12
+
13
+ __all__ = ["to_time", "DateArgument"]
File without changes
@@ -0,0 +1,78 @@
1
+ """Configure the tests."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import subprocess
6
+ from copy import deepcopy
7
+ from pathlib import Path
8
+ from typing import NamedTuple
9
+
10
+ import pytest
11
+
12
+ HERE = Path(__file__).parent
13
+ IO_DIRECTORY = HERE / "runs"
14
+
15
+
16
+ class TestRun(NamedTuple):
17
+ """The result from a test run."""
18
+
19
+ exit_code: int
20
+ output: str
21
+ error: str
22
+
23
+ @classmethod
24
+ def from_completed_process(
25
+ cls, completed_process: subprocess.CompletedProcess
26
+ ) -> TestRun:
27
+ """Create a new run result."""
28
+ stdout = completed_process.stdout.decode("UTF-8").replace("\r\n", "\n")
29
+ print(stdout)
30
+ return cls(
31
+ completed_process.returncode,
32
+ stdout,
33
+ completed_process.stderr.decode("UTF-8"),
34
+ )
35
+
36
+
37
+ class IOTestCase(NamedTuple):
38
+ """An example test case."""
39
+
40
+ name: str
41
+ command: list[str]
42
+ cwd: Path
43
+ expected_output: str
44
+
45
+ @classmethod
46
+ def from_path(cls, path: Path) -> IOTestCase:
47
+ """Create a new testcase from the files."""
48
+ expected_output = path.read_text(encoding="UTF-8").replace("\r\n", "\n")
49
+ return cls(path.name, path.stem.split(), path.parent, expected_output)
50
+
51
+ def run(self) -> TestRun:
52
+ """Run this test case and return the result."""
53
+ command = ["ics-query", *self.command]
54
+ print(" ".join(command))
55
+ completed_process = subprocess.run( # noqa: S603, RUF100
56
+ command, # noqa: S603, RUF100
57
+ capture_output=True,
58
+ timeout=3,
59
+ check=False,
60
+ cwd=self.cwd / "calendars",
61
+ )
62
+ return TestRun.from_completed_process(completed_process)
63
+
64
+
65
+ io_test_cases = [
66
+ IOTestCase.from_path(test_case_path)
67
+ for test_case_path in IO_DIRECTORY.iterdir()
68
+ if test_case_path.is_file()
69
+ ]
70
+
71
+
72
+ @pytest.fixture(params=io_test_cases)
73
+ def io_testcase(request) -> IOTestCase:
74
+ """Go though all the IO test cases."""
75
+ return deepcopy(request.param)
76
+
77
+
78
+ __all__ = ["IOTestCase", "TestRun"]
@@ -0,0 +1,9 @@
1
+ BEGIN:VEVENT
2
+ SUMMARY:test1
3
+ DTSTART;TZID=Europe/Berlin:20190304T080000
4
+ DTEND;TZID=Europe/Berlin:20190304T083000
5
+ DTSTAMP:20190303T111937
6
+ UID:UYDQSG9TH4DE0WM3QFL2J
7
+ CREATED:20190303T111937
8
+ LAST-MODIFIED:20190303T111937
9
+ END:VEVENT
@@ -0,0 +1,34 @@
1
+ BEGIN:VCALENDAR
2
+ VERSION:2.0
3
+ PRODID:-//SabreDAV//SabreDAV//EN
4
+ CALSCALE:GREGORIAN
5
+ X-WR-CALNAME:test
6
+ X-APPLE-CALENDAR-COLOR:#e78074
7
+ BEGIN:VTIMEZONE
8
+ TZID:Europe/Berlin
9
+ X-LIC-LOCATION:Europe/Berlin
10
+ BEGIN:DAYLIGHT
11
+ TZOFFSETFROM:+0100
12
+ TZOFFSETTO:+0200
13
+ TZNAME:CEST
14
+ DTSTART:19700329T020000
15
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
16
+ END:DAYLIGHT
17
+ BEGIN:STANDARD
18
+ TZOFFSETFROM:+0200
19
+ TZOFFSETTO:+0100
20
+ TZNAME:CET
21
+ DTSTART:19701025T030000
22
+ RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
23
+ END:STANDARD
24
+ END:VTIMEZONE
25
+ BEGIN:VEVENT
26
+ CREATED:20190303T111937
27
+ DTSTAMP:20190303T111937
28
+ LAST-MODIFIED:20190303T111937
29
+ UID:UYDQSG9TH4DE0WM3QFL2J
30
+ SUMMARY:test1
31
+ DTSTART;TZID=Europe/Berlin:20190304T080000
32
+ DTEND;TZID=Europe/Berlin:20190304T083000
33
+ END:VEVENT
34
+ END:VCALENDAR
@@ -0,0 +1,10 @@
1
+ """Test the commmand line."""
2
+
3
+ from .conftest import IOTestCase
4
+
5
+
6
+ def test_check_program_output(io_testcase: IOTestCase):
7
+ """Run the test case and check the output."""
8
+ result = io_testcase.run()
9
+ print(result.error)
10
+ assert result.output == io_testcase.expected_output
ics_query/version.py ADDED
@@ -0,0 +1,16 @@
1
+ # SPDX-FileCopyrightText: 2024 Nicco Kunzmann and Open Web Calendar Contributors <https://open-web-calendar.quelltext.eu/>
2
+ #
3
+ # SPDX-License-Identifier: GPL-2.0-only
4
+
5
+ try:
6
+ from ._version import __version__, __version_tuple__, version, version_tuple
7
+ except ModuleNotFoundError:
8
+ __version__ = version = "0.0dev0"
9
+ __version_tuple__ = version_tuple = (0, 0, "dev0")
10
+
11
+ __all__ = [
12
+ "__version__",
13
+ "version",
14
+ "__version_tuple__",
15
+ "version_tuple",
16
+ ]