Source code for icalendar.attr.property_list

"""A list-like view for :rfc:`5545#section-3.8` component property values."""

from __future__ import annotations

import contextlib
from collections.abc import MutableSequence, Sequence
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from collections.abc import Iterator

    from icalendar.cal.component import Component


[docs] class PropertyListView(MutableSequence): """A list-like view of an :rfc:`5545#section-3.8` property within a component. This view synchronizes modifications, such as ``append``, ``extend``, ``insert``, ``clear``, and ``delete``, with the underlying component dictionary. """ __hash__ = None def __init__(self, component: Component, name: str) -> None: """Initialize the property list view for a given component and property name. Parameters: component: The component to view. name: The name of the property to view. """ self._component = component self._name = name @contextlib.contextmanager def _values(self) -> Iterator[list[Any]]: """Synchronize the value list with the component.""" raw = self._component.get(self._name, []) values = [raw] if not isinstance(raw, list) else list(raw) try: yield values finally: if not values: self._component.pop(self._name, None) else: self._component[self._name] = values def __getitem__(self, index: Any) -> Any: """Get an item or slice from the property list.""" with self._values() as values: return values[index] def __setitem__(self, index: Any, value: Any) -> None: """Set an item or slice in the property list.""" with self._values() as values: values[index] = value def __delitem__(self, index: Any) -> None: """Delete an item or slice from the property list.""" with self._values() as values: del values[index] def __len__(self) -> int: """Return the number of items in the property list.""" raw = self._component.get(self._name, []) if not raw: return 0 if not isinstance(raw, list): return 1 return len(raw)
[docs] def insert(self, index: int, value: Any) -> None: """Insert an item into the property list at a given index. Parameters: index: The position at which to insert the item into the property list. value: The value to insert in the property list at the given index. """ with self._values() as values: values.insert(index, value)
[docs] def clear(self) -> None: """Remove all values and the property from the component.""" self._component.pop(self._name, None)
[docs] def replace_with(self, values: Any) -> None: """Replace all values in the property with ``values``. The values are added with :meth:`Component.add <icalendar.cal.component.Component.add>`, so they are converted to the correct types. Parameters: values: The values to replace in the property list. ``None`` removes all values from the property, whereas a single string value or any sequence type replaces all values in the property and is stored as a list. """ if values is None: new_values = [] elif isinstance(values, Sequence) and not isinstance(values, (str, bytes)): # copy first: ``values`` could be this view or a view of this property new_values = list(values) else: new_values = [values] self.clear() for value in new_values: self._component.add(self._name, value)
def __eq__(self, other: object) -> bool: """Check equality against another sequence.""" if isinstance(other, PropertyListView): return list(self) == list(other) if hasattr(other, "__iter__"): return list(self) == list(other) return False def __repr__(self) -> str: """Return the string representation of the property list view.""" return f"PropertyListView({list(self)!r})" def __add__(self, other: Any) -> list[Any]: """Concatenate this list with a sequence and return a new list.""" if isinstance(other, Sequence) and not isinstance(other, (str, bytes)): return list(self) + list(other) return NotImplemented def __radd__(self, other: Any) -> list[Any]: """Concatenate a sequence with this list and return a new list.""" if isinstance(other, Sequence) and not isinstance(other, (str, bytes)): return list(other) + list(self) return NotImplemented def __mul__(self, n: int) -> list[Any]: """Multiply the property list by an integer to return a new repeated list.""" if isinstance(n, int): return list(self) * n return NotImplemented def __rmul__(self, n: int) -> list[Any]: """Multiply the property list by an integer to return a new repeated list.""" if isinstance(n, int): return list(self) * n return NotImplemented
[docs] def copy(self) -> list[Any]: """Return a shallow copy of the property list as a regular list.""" return list(self)
__all__ = ["PropertyListView"]