khard.contacts
**************

Classes and logic to handle vCards in khard.

This module explicitly supports the vCard specifications version 3.0
and 4.0 which can be found here: - version 3.0:
https://tools.ietf.org/html/rfc2426 - version 4.0:
https://tools.ietf.org/html/rfc6350

For further details about the application and device values for the
kind field see: - application: https://tools.ietf.org/html/rfc6473 -
device: https://tools.ietf.org/html/rfc6869


Attributes
==========

+------------+--------------------------------------------------------------------------------------------+
| "logger"   |                                                                                            |
+------------+--------------------------------------------------------------------------------------------+
| "T"        |                                                                                            |
+------------+--------------------------------------------------------------------------------------------+
| "LabeledSt |                                                                                            |
| rs"        |                                                                                            |
+------------+--------------------------------------------------------------------------------------------+


Classes
=======

+------------+--------------------------------------------------------------------------------------------+
| "VCardWrap | Wrapper class around a vobject.vCard object.                                               |
| per"       |                                                                                            |
+------------+--------------------------------------------------------------------------------------------+
| "YAMLEdita | Conversion of vcards to YAML and updating the vcard from YAML                              |
| ble"       |                                                                                            |
+------------+--------------------------------------------------------------------------------------------+
| "Contact"  | Conversion of vcards to YAML and updating the vcard from YAML                              |
+------------+--------------------------------------------------------------------------------------------+


Functions
=========

+------------+--------------------------------------------------------------------------------------------+
| "multi_pro | Key function to pass to sorted(), allowing sorting of dicts with lists                     |
| perty_key" |                                                                                            |
| (…)        |                                                                                            |
+------------+--------------------------------------------------------------------------------------------+
| "atomic_wr | Atomically write to the destination file.                                                  |
| ite"(→ Ite |                                                                                            |
| rator[IO[s |                                                                                            |
| tr]])      |                                                                                            |
+------------+--------------------------------------------------------------------------------------------+


Module Contents
===============

khard.contacts.logger

khard.contacts.T

khard.contacts.LabeledStrs

khard.contacts.multi_property_key(item: str) -> tuple[Literal[0], str]
khard.contacts.multi_property_key(item: dict[T, Any]) -> tuple[Literal[1], T]
khard.contacts.multi_property_key(item: str | dict[T, Any]) -> tuple[Literal[0, 1], T | str]

   Key function to pass to sorted(), allowing sorting of dicts with
   lists and strings. Dicts will be sorted by their label, after other
   types.

   Parameters:
      **item** (*a dict with a single entry** or **any sortable type*)
      -- member of the list being sorted

   Returns:
      a pair, the first item is int(isinstance(item, dict). The second
      is either the key from the dict or the unchanged item if it is
      not a dict.

class khard.contacts.VCardWrapper(vcard: vobject.base.Component, version: str | None = None)

   Wrapper class around a vobject.vCard object.

   This class can wrap a single vCard and presents its data in a
   manner suitable for khard.  Additionally some details of the vCard
   specifications in RFC 2426 (version 3.0) and RFC 6350 (version 4.0)
   that are not enforced by the vobject library are enforced here.

   _default_version = '3.0'

   _supported_versions = ('3.0', '4.0')

   _default_kind = 'individual'

   _supported_kinds = ('individual', 'group', 'org', 'location', 'application', 'device')

   phone_types_v3 = ('bbs', 'car', 'cell', 'fax', 'home', 'isdn', 'msg', 'modem', 'pager', 'pcs', 'video', 'voice', 'work')

   email_types_v3 = ('home', 'internet', 'work', 'x400')

   address_types_v3 = ('dom', 'intl', 'home', 'parcel', 'postal', 'work')

   phone_types_v4 = ('text', 'voice', 'fax', 'cell', 'video', 'pager', 'textphone', 'home', 'work')

   email_types_v4 = ('home', 'internet', 'work')

   address_types_v4 = ('home', 'work')

   vcard

   __str__() -> str

   get_first(property: Literal['n']) -> vobject.vcard.Name | None
   get_first(property: Literal['adr']) -> vobject.vcard.Address | None
   get_first(property: str) -> str | None

      Get a property from the underlying vCard.

      This method should only be called for properties with
      cardinality *1 (zero or one).  Otherwise only the first value
      will be returned. If the property is not present None will be
      retuned.

      The type annotation for the return value is str but this is not
      enforced so it is up to the caller to make sure to only call
      this method for properties where the underlying vobject library
      returns a str.

      Parameters:
         **property** -- the field value to get

      Returns:
         the property value or None

   get_all(name: str) -> list

      Get all values of the given vCard property.

      It does not matter what the individual vcard properties store as
      their value.  This function returns them untouched inside an
      aggregating list.

      If the property is part of a group containing exactly two items,
      with exactly one ABLABEL. the property will be prefixed with
      that ABLABEL.

      Parameters:
         **name** -- the name of the property (should be UPPER case)

      Returns:
         the values from all occurrences of the named property

   _delete_vcard_object(name: str) -> None

      Delete all fields with the given name from the underlying vCard.

      If a field that will be deleted is in a group with an X-ABLABEL
      field, that X-ABLABEL field will also be deleted.  These fields
      are commonly added by the Apple address book to attach custom
      labels to some fields.

      Parameters:
         **name** -- the name of the fields to delete

   static _parse_type_value(types: Sequence[str], supported_types: Sequence[str]) -> tuple[list[str], list[str], int]

      Parse type value of phone numbers, email and post addresses.

      Parameters:
         * **types** -- list of type values

         * **supported_types** -- all allowed standard types

      Returns:
         tuple of standard and custom types and pref integer

   _get_types_for_vcard_object(object: vobject.base.ContentLine, default_type: str) -> list[str]

      get list of types for phone number, email or post address

      Parameters:
         * **object** -- vcard class object

         * **default_type** -- use if the object contains no type

      Returns:
         list of type labels

   property version: str | None

   property uid: str | None

   _update_revision() -> None

      Generate a new REV field for the vCard, replace any existing

      All vCards should only always have one revision, this is a
      requirement for version 4 but also makes sense for all other
      versions.

   property birthday: khard.helpers.typing.Date | None

      Return the birthday as a datetime object or a string depending
      on whether it is of type text or not.  If no birthday is present
      in the vcard None is returned.

      Returns:
         contacts birthday or None if not available

   property anniversary: khard.helpers.typing.Date | None

      Returns:
         contacts anniversary or None if not available

   _get_ablabel(item: vobject.base.ContentLine) -> str

      Get an ABLABEL for a specified item in the vCard. Will return
      the ABLABEL only if the item is part of a group with exactly two
      items, exactly one of which is an ABLABEL.

      Parameters:
         **item** -- the item to be labelled

      Returns:
         the ABLABEL in the circumstances above or an empty string

   _get_new_group(group_type: str = '') -> str

      Get an unused group name for adding new groups. Uses the form
      item123 or itemgroup_type123 if a grouptype is specified.

      Parameters:
         **group_type** -- (Optional) a string to add between "item"
         and the number

      Returns:
         the name of the first unused group of the specified form

   _add_labelled_property(property: str, value: khard.helpers.typing.StrList, label: str | None = None, name_groups: bool = False, allowed_object_type: None | type[str] | type[list] = str) -> None

      Add an object to the VCARD. If a label is given it will be added
      to a group with an ABLABEL.

      Parameters:
         * **property** -- type of object to add to the VCARD.

         * **value** -- Contents of the object to add.

         * **label** -- an optional label to add to the property

         * **name_groups** -- (Optional) If True, use the property in
           the group name for labelled objects.

         * **allowed_object_type** -- (Optional) set the accepted
           return type for vcard attribute

   _prepare_birthday_value(date: khard.helpers.typing.Date) -> tuple[str | None, bool]

      Prepare a value to be stored in a BDAY or ANNIVERSARY attribute.

      Parameters:
         **date** -- the date like value to be stored

      Returns:
         the object to set as the .value for the attribute and whether
         it should be stored as plain text

   property kind: str

   _kind_attribute_name() -> str

   property formatted_name: str

   _get_names_part(part: str) -> list[str]

      Get some part of the "N" entry in the vCard as a list

      Parameters:
         **part** -- the name to get e.g. "prefix" or "given"

      Returns:
         a list of entries for this name part

   _get_name_prefixes() -> list[str]

   _get_first_names() -> list[str]

   _get_additional_names() -> list[str]

   _get_last_names() -> list[str]

   _get_name_suffixes() -> list[str]

   get_first_name_last_name() -> str

      Compute the full name of the contact by joining first,
      additional and last names together

   get_last_name_first_name() -> str

      Compute the full name of the contact by joining the last names
      and then after a comma the first and additional names together

   property first_name: str | None

   property last_name: str | None

   _add_name(prefix: khard.helpers.typing.StrList, first_name: khard.helpers.typing.StrList, additional_name: khard.helpers.typing.StrList, last_name: khard.helpers.typing.StrList, suffix: khard.helpers.typing.StrList) -> None

      Add an N entry to the vCard. No old entries are affected.

      Parameters:
         * **prefix**

         * **first_name**

         * **additional_name**

         * **last_name**

         * **suffix**

   property organisations: list[list[str] | dict[str, list[str]]]

      Returns:
         list of organisations, sorted alphabetically

   _add_organisation(organisation: khard.helpers.typing.StrList, label: str | None = None) -> None

      Add one ORG entry to the underlying vcard

      Parameters:
         * **organisation** -- the value to add

         * **label** -- an optional label to add

   property titles: LabeledStrs

   _add_title(title: str, label: str | None = None) -> None

   property roles: LabeledStrs

   _add_role(role: str, label: str | None = None) -> None

   property nicknames: LabeledStrs

   _add_nickname(nickname: str, label: str | None = None) -> None

   property notes: LabeledStrs

   _add_note(note: str, label: str | None = None) -> None

   property webpages: LabeledStrs

   _add_webpage(webpage: str, label: str | None = None) -> None

   property categories: list[str] | list[list[str]]

   _add_category(categories: list[str]) -> None

      Add categories to the vCard

      Parameters:
         **categories**

   property phone_numbers: dict[str, list[str]]

      Returns:
         dict of type and phone number list

   _add_phone_number(type: str, number: str) -> None

   property emails: dict[str, list[str]]

      Returns:
         dict of type and email address list

   add_email(type: str, address: str) -> None

   property post_addresses: dict[str, list[khard.helpers.typing.PostAddress]]

      Returns:
         dict of type and post address list

   get_formatted_post_addresses() -> dict[str, list[str]]

   _add_post_address(type: str, box: khard.helpers.typing.StrList, extended: khard.helpers.typing.StrList, street: khard.helpers.typing.StrList, code: khard.helpers.typing.StrList, city: khard.helpers.typing.StrList, region: khard.helpers.typing.StrList, country: khard.helpers.typing.StrList) -> None

class khard.contacts.YAMLEditable(vcard: vobject.base.Component, supported_private_objects: list[str] | None = None, version: str | None = None, localize_dates: bool = False)

   Bases: "VCardWrapper"

   Conversion of vcards to YAML and updating the vcard from YAML

   supported_private_objects = []

   localize_dates = False

   _get_private_objects() -> dict[str, LabeledStrs]

   _add_private_object(key: str, value: str) -> None

   get_formatted_anniversary() -> str

   get_formatted_birthday() -> str

   static _format_date_object(date: khard.helpers.typing.Date | None, localize: bool) -> str

   static _filter_invalid_tags(contents: str) -> str

   static _parse_yaml(input: str) -> dict

      Parse a YAML document into a dictionary and validate the data to
      some degree.

      Parameters:
         **input** -- the YAML document to parse

      Returns:
         the parsed data structure

   static _set_string_list(setter: Callable[[str, str | None], None], key: str, data: dict[str, str | list[str]]) -> None

      Pre-process a string or list and set each value with the given
      setter

      Parameters:
         * **setter** -- the setter method to add a value to a card

         * **key**

         * **data**

   _set_date(target: str, key: str, data: dict) -> None

   update(input: str) -> None

      Update this vcard with some yaml input

      Parameters:
         **input** -- a yaml string to parse and then use to update
         self

   to_yaml() -> str

      Convert this contact to a YAML string

      The conversion follows the implicit schema that is given by the
      internal YAML template of khard.

      Returns:
         a YAML representation of this contact

khard.contacts.atomic_write(dest: str, overwrite: bool = False) -> Iterator[IO[str]]

   Atomically write to the destination file.

   Optionally overwrite the path (using rename) rather than using
   *os.link*.

class khard.contacts.Contact(vcard: vobject.base.Component, address_book: Contact.__init__.address_book, filename: str, supported_private_objects: list[str] | None = None, vcard_version: str | None = None, localize_dates: bool = False)

   Bases: "YAMLEditable"

   Conversion of vcards to YAML and updating the vcard from YAML

   address_book

   filename

   classmethod new(address_book: Contact.new.address_book, supported_private_objects: list[str] | None = None, version: str | None = None, localize_dates: bool = False) -> Contact

      Create a new Contact from scratch

   classmethod from_file(address_book: Contact.from_file.address_book, filename: str, query: khard.query.Query = AnyQuery(), supported_private_objects: list[str] | None = None, localize_dates: bool = False) -> Contact | None

      Load a Contact object from a .vcf file if the plain file matches
      the query.

      Parameters:
         * **address_book** -- the address book where this contact is
           stored

         * **filename** -- the file name of the .vcf file

         * **query** -- the query to search in the source file or None
           to load the file unconditionally

         * **supported_private_objects** -- the list of private
           property names that will be loaded from the actual vcard
           and represented in this object

         * **localize_dates** -- should the formatted output of
           anniversary and birthday be localized or should the iso
           format be used instead

      Returns:
         the loaded Contact or None if the file didn't match

   classmethod from_yaml(address_book: Contact.from_yaml.address_book, yaml: str, supported_private_objects: list[str] | None = None, version: str | None = None, localize_dates: bool = False) -> Contact

      Use this if you want to create a new contact from user input.

   classmethod clone_with_yaml_update(contact: Contact, yaml: str, localize_dates: bool = False) -> Contact

      Use this if you want to clone an existing contact and replace
      its data with new user input in one step.

   __eq__(other: object) -> bool

   __ne__(other: object) -> bool

   pretty(verbose: bool = True) -> str

   write_to_file(overwrite: bool = False) -> None

   delete_vcard_file() -> None

   classmethod get_properties() -> list[str]

      Return the property names that are defined on this class.
