1from collections.abc import Sequence
2from datetime import date, datetime
3from typing import Any, ClassVar
4
5from icalendar.compatibility import Self
6from icalendar.error import JCalParsingError
7from icalendar.parser import Parameters
8from icalendar.parser_tools import from_unicode
9
10from .base import TimeBase
11from .types import vDDDTypes
12
13
14class vDDDLists:
15 """A list of vDDDTypes values."""
16
17 default_value: ClassVar[str] = "DATE-TIME"
18 params: Parameters
19 dts: list[vDDDTypes]
20
21 def __init__(self, dt_list, params: dict[str, Any] | None = None) -> None:
22 if params is None:
23 params = {}
24 if not hasattr(dt_list, "__iter__") or (
25 isinstance(dt_list, Sequence) and len(dt_list) == 2 and dt_list[1] is None
26 ):
27 # A ``(dt, None)`` pair (tuple or list) is the rdates form of a single
28 # date, not a list of two values, so don't iterate it element-wise (#1439).
29 dt_list = [dt_list]
30 vddd = []
31 tzid = None
32 for dt_l in dt_list:
33 dt = vDDDTypes(dt_l) if not isinstance(dt_l, vDDDTypes) else dt_l
34 vddd.append(dt)
35 if "TZID" in dt.params:
36 tzid = dt.params["TZID"]
37
38 if tzid:
39 # NOTE: no support for multiple timezones here!
40 params["TZID"] = tzid
41 self.params = Parameters(params)
42 self.dts = vddd
43
44 def to_ical(self):
45 dts_ical = (from_unicode(dt.to_ical()) for dt in self.dts)
46 return b",".join(dts_ical)
47
48 @staticmethod
49 def from_ical(ical, timezone=None):
50 out = []
51 ical_dates = ical.split(",")
52 for ical_dt in ical_dates:
53 out.append(vDDDTypes.from_ical(ical_dt, timezone=timezone))
54 return out
55
56 def __eq__(self, other):
57 if isinstance(other, vDDDLists):
58 return self.dts == other.dts
59 if isinstance(other, (TimeBase, date)):
60 return self.dts == [other]
61 return False
62
63 def __repr__(self):
64 """String representation."""
65 return f"{self.__class__.__name__}({self.dts})"
66
67 @classmethod
68 def examples(cls) -> list[Self]:
69 """Examples of vDDDLists."""
70 return [vDDDLists([datetime(2025, 11, 10, 16, 50)])]
71
72 def to_jcal(self, name: str) -> list:
73 """The jCal representation of this property according to :rfc:`7265`."""
74 return [
75 name,
76 self.params.to_jcal(),
77 self.VALUE.lower(),
78 *[dt.to_jcal(name)[3] for dt in self.dts],
79 ]
80
81 def _get_value(self) -> str | None:
82 return None if not self.dts else self.dts[0].VALUE
83
84 from icalendar.param import VALUE
85
86 @classmethod
87 def from_jcal(cls, jcal_property: list) -> Self:
88 """Parse jCal from :rfc:`7265`.
89
90 Parameters:
91 jcal_property: The jCal property to parse.
92
93 Raises:
94 ~error.JCalParsingError: If the jCal provided is invalid.
95 """
96 JCalParsingError.validate_property(jcal_property, cls)
97 values = jcal_property[3:]
98 prop = jcal_property[:3]
99 dts = []
100 for value in values:
101 dts.append(vDDDTypes.from_jcal(prop + [value]))
102 return cls(
103 dts,
104 params=Parameters.from_jcal_property(jcal_property),
105 )
106
107 __hash__ = None
108
109
110__all__ = ["vDDDLists"]