Source code for icalendar.prop.adr

"""ADR property of :rfc:`6350`."""
from typing import Any, ClassVar, NamedTuple

from icalendar.compatibility import Self
from icalendar.error import JCalParsingError
from icalendar.parser import Parameters
from icalendar.parser_tools import DEFAULT_ENCODING, to_unicode


[docs] class AdrFields(NamedTuple): """Named fields for vCard ADR (Address) property per :rfc:`6350#section-6.3.1`. Provides named access to the seven address components. """ po_box: str """Post office box.""" extended: str """Extended address (e.g., apartment or suite number).""" street: str """Street address.""" locality: str """Locality (e.g., city).""" region: str """Region (e.g., state or province).""" postal_code: str """Postal code.""" country: str """Country name (full name)."""
[docs] class vAdr: """vCard ADR (Address) structured property per :rfc:`6350#section-6.3.1`. The ADR property represents a delivery address as a single text value. The structured type value consists of a sequence of seven address components. The component values must be specified in their corresponding position. - post office box - extended address (e.g., apartment or suite number) - street address - locality (e.g., city) - region (e.g., state or province) - postal code - country name (full name) When a component value is missing, the associated component separator MUST still be specified. Semicolons are field separators and are NOT escaped. Commas and backslashes within field values ARE escaped per :rfc:`6350`. Examples: .. code-block:: pycon >>> from icalendar.prop import vAdr >>> adr = vAdr(("", "", "123 Main St", "Springfield", "IL", "62701", "USA")) >>> adr.to_ical() b';;123 Main St;Springfield;IL;62701;USA' >>> vAdr.from_ical(";;123 Main St;Springfield;IL;62701;USA") AdrFields(po_box='', extended='', street='123 Main St', locality='Springfield', region='IL', postal_code='62701', country='USA') """ default_value: ClassVar[str] = "TEXT" params: Parameters fields: AdrFields
[docs] def __init__( self, fields: tuple[str, ...] | list[str] | str | AdrFields, /, params: dict[str, Any] | None = None, ): """Initialize ADR with seven fields or parse from vCard format string. Parameters: fields: Either an AdrFields, tuple, or list of seven strings, one per field, or a vCard format string with semicolon-separated fields params: Optional property parameters """ if isinstance(fields, str): fields = self.from_ical(fields) if isinstance(fields, AdrFields): self.fields = fields else: if len(fields) != 7: raise ValueError(f"ADR must have exactly 7 fields, got {len(fields)}") self.fields = AdrFields(*(str(f) for f in fields)) self.params = Parameters(params)
[docs] def to_ical(self) -> bytes: """Generate vCard format with semicolon-separated fields.""" # Each field is vText (handles comma/backslash escaping) # but we join with unescaped semicolons (field separators) from icalendar.prop.text import vText parts = [vText(f).to_ical().decode(DEFAULT_ENCODING) for f in self.fields] return ";".join(parts).encode(DEFAULT_ENCODING)
[docs] @staticmethod def from_ical(ical: str | bytes) -> AdrFields: """Parse vCard ADR format into an AdrFields named tuple. Parameters: ical: vCard format string with semicolon-separated fields Returns: AdrFields named tuple with seven field values. """ from icalendar.parser import split_on_unescaped_semicolon ical = to_unicode(ical) fields = split_on_unescaped_semicolon(ical) if len(fields) != 7: raise ValueError( f"ADR must have exactly 7 fields, got {len(fields)}: {ical}" ) return AdrFields(*fields)
def __eq__(self, other): """self == other""" return isinstance(other, vAdr) and self.fields == other.fields def __repr__(self): """String representation.""" return f"{self.__class__.__name__}({self.fields}, params={self.params})" @property def ical_value(self) -> AdrFields: """The address fields as a named tuple.""" return self.fields from icalendar.param import VALUE
[docs] def to_jcal(self, name: str) -> list: """The jCal representation of this property according to :rfc:`7265`.""" result = [name, self.params.to_jcal(), self.VALUE.lower()] result.extend(self.fields) return result
[docs] @classmethod def from_jcal(cls, jcal_property: list) -> Self: """Parse jCal from :rfc:`7265`. Parameters: jcal_property: The jCal property to parse. Raises: ~error.JCalParsingError: If the provided jCal is invalid. """ JCalParsingError.validate_property(jcal_property, cls) if len(jcal_property) != 10: # name, params, value_type, 7 fields raise JCalParsingError( f"ADR must have 10 elements (name, params, value_type, 7 fields), " f"got {len(jcal_property)}" ) for i, field in enumerate(jcal_property[3:], start=3): JCalParsingError.validate_value_type(field, str, cls, i) return cls( tuple(jcal_property[3:]), Parameters.from_jcal_property(jcal_property), )
[docs] @classmethod def examples(cls) -> list[Self]: """Examples of vAdr.""" return [cls(("", "", "123 Main St", "Springfield", "IL", "62701", "USA"))]
__all__ = ["AdrFields", "vAdr"]