def run(self, backend_args, archive_args=None, resume=False):

args = backend_args.copy()<EOL>if archive_args:<EOL><INDENT>self.initialize_archive_manager(archive_args['<STR_LIT>'])<EOL><DEDENT>if not resume:<EOL><INDENT>max_date = backend_args.get('<STR_LIT>', None)<EOL>offset = backend_args.get('<STR_LIT>', None)<EOL>if max_date:<EOL><INDENT>max_date = datetime_to_utc(max_date).timestamp()<EOL><DEDENT>self._result = JobResult(self.job_id, self.task_id, self.backend, self.category,<EOL>None, max_date, <NUM_LIT:0>, offset=offset,<EOL>nresumed=<NUM_LIT:0>)<EOL><DEDENT>else:<EOL><INDENT>if self.result.max_date:<EOL><INDENT>args['<STR_LIT>'] = unixtime_to_datetime(self.result.max_date)<EOL><DEDENT>if self.result.offset:<EOL><INDENT>args['<STR_LIT>'] = self.result.offset<EOL><DEDENT>self._result.nresumed += <NUM_LIT:1><EOL><DEDENT>for item in self._execute(args, archive_args):<EOL><INDENT>self.conn.rpush(self.qitems, pickle.dumps(item))<EOL>self._result.nitems += <NUM_LIT:1><EOL>self._result.last_uuid = item['<STR_LIT>']<EOL>if not self.result.max_date or self.result.max_date < item['<STR_LIT>']:<EOL><INDENT>self._result.max_date = item['<STR_LIT>']<EOL><DEDENT>if '<STR_LIT>' in item:<EOL><INDENT>self._result.offset = item['<STR_LIT>']<EOL><DEDENT><DEDENT>

Run the backend with the given parameters.

        The method will run the backend assigned to this job,
        storing the fetched items in a Redis queue. The ongoing
        status of the job, can be accessed through the property
        `result`. When `resume` is set, the job will start from
        the last execution, overwriting 'from_date' and 'offset'
        parameters, if needed.

        Setting to `True` the parameter `fetch_from_archive`, items can
        be fetched from the archive assigned to this job.

        Any exception during the execution of the process will
        be raised.

        :param backend_args: parameters used to un the backend
        :param archive_args: archive arguments
        :param resume: fetch items starting where the last
            execution stopped


return self._bklass.has_archiving()<EOL>

Returns if the job supports items archiving


return self._bklass.has_resuming()<EOL>

Returns if the job can be resumed when it fails


@metadata<EOL><INDENT>def _execute(self, backend_args, archive_args):<DEDENT>

if not archive_args or not archive_args['<STR_LIT>']:<EOL><INDENT>return perceval.backend.fetch(self._bklass, backend_args, self.category,<EOL>manager=self.archive_manager)<EOL><DEDENT>else:<EOL><INDENT>return perceval.backend.fetch_from_archive(self._bklass, backend_args,<EOL>self.archive_manager, self.category,<EOL>archive_args['<STR_LIT>'])<EOL><DEDENT>

Execute a backend of Perceval.

        Run the backend of Perceval assigned to this job using the
        given arguments. It will raise an `AttributeError` when any of
        the required parameters to run the backend are not found.
        Other exceptions related to the execution of the backend
        will be raised too.

        This method will return an iterator of the items fetched
        by the backend. These items will include some metadata
        related to this job.

        It will also be possible to retrieve the items from the
        archive setting to `True` the parameter `fetch_from_archive`.

        :param backend_args: arguments to execute the backend
        :param archive_args: archive arguments

        :returns: iterator of items fetched by the backend

        :raises AttributeError: raised when any of the required
            parameters is not found


obj = cherrypy.serving.request._json_inner_handler(*args, **kwargs)<EOL>for chunk in JSONEncoder().iterencode(obj):<EOL><INDENT>yield chunk.encode('<STR_LIT:utf-8>')<EOL><DEDENT>


super().start()<EOL>if self.writer_th:<EOL><INDENT>self.writer_th.start()<EOL><DEDENT>


@classmethod<EOL><INDENT>def write_items(cls, writer, items_generator):<DEDENT>

while True:<EOL><INDENT>items = items_generator()<EOL>writer.write(items)<EOL>time.sleep(<NUM_LIT:1>)<EOL><DEDENT>

Write items to the queue

        :param writer: the writer object
        :param items_generator: items to be written in the queue


payload = cherrypy.request.json<EOL>logger.debug("<STR_LIT>")<EOL>for task_data in payload['<STR_LIT>']:<EOL><INDENT>try:<EOL><INDENT>category = task_data['<STR_LIT>']<EOL>backend_args = task_data['<STR_LIT>']<EOL>archive_args = task_data.get('<STR_LIT>', None)<EOL>sched_args = task_data.get('<STR_LIT>', None)<EOL><DEDENT>except KeyError as ex:<EOL><INDENT>logger.error("<STR_LIT>")<EOL>raise ex<EOL><DEDENT>from_date = backend_args.get('<STR_LIT>', None)<EOL>if from_date:<EOL><INDENT>backend_args['<STR_LIT>'] = str_to_datetime(from_date)<EOL><DEDENT>super().add_task(task_data['<STR_LIT>'],<EOL>task_data['<STR_LIT>'],<EOL>category,<EOL>backend_args,<EOL>archive_args=archive_args,<EOL>sched_args=sched_args)<EOL><DEDENT>logger.debug("<STR_LIT>")<EOL>return "<STR_LIT>"<EOL>


payload = cherrypy.request.json<EOL>logger.debug("<STR_LIT>")<EOL>task_ids = {}<EOL>for task_data in payload['<STR_LIT>']:<EOL><INDENT>task_id = task_data['<STR_LIT>']<EOL>removed = super().remove_task(task_id)<EOL>task_ids[task_id] = removed<EOL><DEDENT>result = {'<STR_LIT>': task_ids}<EOL>return result<EOL>


logger.debug("<STR_LIT>")<EOL>result = [task.to_dict() for task in self._tasks.tasks]<EOL>result = {'<STR_LIT>': result}<EOL>logger.debug("<STR_LIT>")<EOL>return result<EOL>


def add(self, task_id, backend, category, backend_args,<EOL>archiving_cfg=None, scheduling_cfg=None):

self._rwlock.writer_acquire()<EOL>if task_id in self._tasks:<EOL><INDENT>self._rwlock.writer_release()<EOL>raise AlreadyExistsError(element=str(task_id))<EOL><DEDENT>task = Task(task_id, backend, category, backend_args,<EOL>archiving_cfg=archiving_cfg,<EOL>scheduling_cfg=scheduling_cfg)<EOL>self._tasks[task_id] = task<EOL>self._rwlock.writer_release()<EOL>logger.debug("<STR_LIT>", str(task_id))<EOL>return task<EOL>

Add a task to the registry.

        This method adds task using `task_id` as identifier. If a task
        with the same identifier already exists on the registry, a
        `AlreadyExistsError` exception will be raised.

        :param task_id: identifier of the task to add
        :param backend: backend used to fetch data from the repository
        :param category: category of the items to fetch
        :param backend_args: dictionary of arguments required to run the backend
        :param archiving_cfg: archiving config for the task, if needed
        :param scheduling_cfg: scheduling config for the task, if needed

        :returns: the new task added to the registry

        :raises AlreadyExistsError: raised when the given task identifier
            exists on the registry


Remove a task from the registry.

        To remove it, pass its identifier with `taks_id` parameter.
        When the identifier is not found, a `NotFoundError` exception
        is raised.

        :param task_id: identifier of the task to remove

        :raises NotFoundError: raised when the given task identifier
            is not found on the registry


try:<EOL><INDENT>self._rwlock.reader_acquire()<EOL>task = self._tasks[task_id]<EOL><DEDENT>except KeyError:<EOL><INDENT>raise NotFoundError(element=str(task_id))<EOL><DEDENT>finally:<EOL><INDENT>self._rwlock.reader_release()<EOL><DEDENT>return task<EOL>

Get a task from the registry.

        Retrieve a task from the registry using its task identifier. When
        the task does not exist, a `NotFoundError` exception will be
        raised.

        :param task_id: task identifier

        :returns: a task object

        :raises NotFoundError: raised when the requested task is not
            found on the registry


self._rwlock.reader_acquire()<EOL>tl = [v for v in self._tasks.values()]<EOL>tl.sort(key=lambda x: x.task_id)<EOL>self._rwlock.reader_release()<EOL>return tl<EOL>


properties = find_class_properties(self.__class__)<EOL>config = {<EOL>name: self.__getattribute__(name) for name, _ in properties<EOL>}<EOL>return config<EOL>

Returns a dict with the representation of this task configuration object.


try:<EOL><INDENT>obj = cls(**config)<EOL><DEDENT>except TypeError as e:<EOL><INDENT>m = cls.KW_ARGS_ERROR_REGEX.match(str(e))<EOL>if m:<EOL><INDENT>raise ValueError("<STR_LIT>" % m.group(<NUM_LIT:1>))<EOL><DEDENT>else:<EOL><INDENT>raise e<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return obj<EOL><DEDENT>

Create an configuration object from a dictionary.

        Key,value pairs will be used to initialize a task configuration
        object. If 'config' contains invalid configuration parameters
        a `ValueError` exception will be raised.

        :param config: dictionary used to create an instance of this object

        :returns: a task config instance

        :raises ValueError: when an invalid configuration parameter is found


return self._archive_path<EOL>

Path where the archive for this task is or will be stored.


return self._fetch_from_archive<EOL>

Defines if the task will fetch items from the archive.


return self._archived_after<EOL>

Items archived after this date will be fetched.


return self._delay<EOL>

Number of seconds a recurring task will be waiting before being scheduled again


return self._max_retries<EOL>

Maximum  number of attempts this job can execute before failing.


def add_task(self, task_id, backend, category, backend_args,<EOL>archive_args=None, sched_args=None):

try:<EOL><INDENT>archiving_cfg = self.__parse_archive_args(archive_args)<EOL>scheduling_cfg = self.__parse_schedule_args(sched_args)<EOL>self.__validate_args(task_id, backend, category, backend_args)<EOL><DEDENT>except ValueError as e:<EOL><INDENT>raise e<EOL><DEDENT>try:<EOL><INDENT>task = self._tasks.add(task_id, backend, category, backend_args,<EOL>archiving_cfg=archiving_cfg,<EOL>scheduling_cfg=scheduling_cfg)<EOL><DEDENT>except AlreadyExistsError as e:<EOL><INDENT>raise e<EOL><DEDENT>self._scheduler.schedule_task(task.task_id)<EOL>return task<EOL>

Add and schedule a task.

        :param task_id: id of the task
        :param backend: name of the backend
        :param category: category of the items to fecth
        :param backend_args: args needed to initialize the backend
        :param archive_args: args needed to initialize the archive
        :param sched_args: scheduling args for this task

        :returns: the task created


try:<EOL><INDENT>self._scheduler.cancel_task(task_id)<EOL><DEDENT>except NotFoundError as e:<EOL><INDENT>logger.info("<STR_LIT>",<EOL>task_id)<EOL>return False<EOL><DEDENT>else:<EOL><INDENT>return True<EOL><DEDENT>

Remove and cancel a task.

        :param task_id: id of the task to be removed


<EOL>pipe = self.conn.pipeline()<EOL>pipe.lrange(Q_STORAGE_ITEMS, <NUM_LIT:0>, -<NUM_LIT:1>)<EOL>pipe.ltrim(Q_STORAGE_ITEMS, <NUM_LIT:1>, <NUM_LIT:0>)<EOL>items = pipe.execute()[<NUM_LIT:0>]<EOL>for item in items:<EOL><INDENT>item = pickle.loads(item)<EOL>yield item<EOL><DEDENT>


@staticmethod<EOL><INDENT>def __validate_args(task_id, backend, category, backend_args):<DEDENT>

if not task_id or task_id.strip() == "<STR_LIT>":<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg)<EOL><DEDENT>if not backend or backend.strip() == "<STR_LIT>":<EOL><INDENT>msg = "<STR_LIT>" % task_id<EOL>raise ValueError(msg)<EOL><DEDENT>if backend_args and not isinstance(backend_args, dict):<EOL><INDENT>msg = "<STR_LIT>" % task_id<EOL>raise ValueError(msg)<EOL><DEDENT>if not category or category.strip() == "<STR_LIT>":<EOL><INDENT>msg = "<STR_LIT>" % task_id<EOL>raise ValueError(msg)<EOL><DEDENT>

Check that the task arguments received are valid


if not archive_args:<EOL><INDENT>return None<EOL><DEDENT>archiving_args = copy.deepcopy(archive_args)<EOL>if self.archive_path:<EOL><INDENT>archiving_args['<STR_LIT>'] = self.archive_path<EOL><DEDENT>else:<EOL><INDENT>archiving_args['<STR_LIT>'] = os.path.expanduser(ARCHIVES_DEFAULT_PATH)<EOL><DEDENT>return ArchivingTaskConfig.from_dict(archiving_args)<EOL>


if not sched_args:<EOL><INDENT>return None<EOL><DEDENT>return SchedulingTaskConfig.from_dict(sched_args)<EOL>


self._order_mutex.acquire()<EOL>self._readers_mutex.acquire()<EOL>if self._readers == <NUM_LIT:0>:<EOL><INDENT>self._access_mutex.acquire()<EOL><DEDENT>self._readers += <NUM_LIT:1><EOL>self._order_mutex.release()<EOL>self._readers_mutex.release()<EOL>


self._readers_mutex.acquire()<EOL>self._readers -= <NUM_LIT:1><EOL>if self._readers == <NUM_LIT:0>:<EOL><INDENT>self._access_mutex.release()<EOL><DEDENT>self._readers_mutex.release()<EOL>


self._order_mutex.acquire()<EOL>self._access_mutex.acquire()<EOL>self._order_mutex.release()<EOL>


result = super().perform_job(job, queue)<EOL>job_status = job.get_status()<EOL>job_result = job.return_value if job_status == '<STR_LIT>' else None<EOL>data = {<EOL>'<STR_LIT>': job.id,<EOL>'<STR_LIT:status>': job_status,<EOL>'<STR_LIT:result>': job_result<EOL>}<EOL>msg = pickle.dumps(data)<EOL>self.connection.publish(self.pubsub_channel, msg)<EOL>return result<EOL>

Custom method to execute a job and notify of its result

        :param job: Job object
        :param queue: the queue containing the object


self.api_key = api_key<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key


def __init__(self, api_key, domain, start_month, end_month,<EOL>time_granularity="<STR_LIT>", main_domain_only=False):

self.domain = utils.domain_from_url(domain)<EOL>self.start_month = start_month<EOL>self.end_month = end_month<EOL>self.time_granularity = time_granularity<EOL>self.main_domain_only = main_domain_only<EOL>super(TrafficAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

domain: string
    Domain to query.

start_month: string
    Start Month in (M-YYYY) format

end_month: string
    End Month in (M-YYYY) format

time_granularity: string
    Time granularity of report. Can be: Daily, Weekly, Monthly

main_domain_only: boolean
    Get metrics on the Main Domain only (i.e. not including subdomains)


self.domain = utils.domain_from_url(domain)<EOL>super(RankAndReachAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

domain: string
    Domain to query.


def __init__(self, api_key, endpoint, domain, start_month, end_month,<EOL>time_granularity="<STR_LIT>", main_domain_only=False):

if endpoint not in ["<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]:<EOL><INDENT>raise InvalidEndpointException("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>self.endpoint = endpoint<EOL>self.domain = utils.domain_from_url(domain)<EOL>self.start_month = start_month<EOL>self.end_month = end_month<EOL>self.time_granularity = time_granularity<EOL>self.main_domain_only = main_domain_only<EOL>super(EngagementAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

endpoint: string
    Endpoint to use. Can be: pageviews, visitduration, bouncerate

domain: string
    Domain to query.

start_month: string
    Start Month in (M-YYYY) format

end_month: string
    End Month in (M-YYYY) format

time_granularity: string
    Time granularity of report. Can be: Daily, Weekly, Monthly

main_domain_only: boolean
    Get metrics on the Main Domain only (i.e. not including subdomains)


self.domain = utils.domain_from_url(domain)<EOL>super(SimilarWebsitesAPI, self).__init__(api_key)<EOL>


self.domain = utils.domain_from_url(domain)<EOL>super(AlsoVisitedAPI, self).__init__(api_key)<EOL>


self.domain = utils.domain_from_url(domain)<EOL>super(WebsiteTagsAPI, self).__init__(api_key)<EOL>


self.domain = utils.domain_from_url(domain)<EOL>super(WebsiteCategorizationAPI, self).__init__(api_key)<EOL>


self.domain = utils.domain_from_url(domain)<EOL>super(CategoryRankAPI, self).__init__(api_key)<EOL>


def __init__(self, api_key, category=None, country=None):

self.category = category<EOL>self.country = country<EOL>super(TopSitesAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

category: string
    If left blank, `All Categories` will be requested.
    Use `http://api.similarweb.com/v1/TopSites/categories` to get a list of available categories.

country: string
    If left blank, `Worldwide` will be requested.
    Use `http://api.similarweb.com/v1/TopSites/countries` to get a list of available categories.


self.domain = utils.domain_from_url(domain)<EOL>super(SocialReferralsAPI, self).__init__(api_key)<EOL>


def __init__(self, api_key, endpoint, domain, start_month, end_month,<EOL>main_domain_only=False, results_page=None):

if endpoint not in ["<STR_LIT>", "<STR_LIT>", ]:<EOL><INDENT>raise InvalidEndpointException("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>self.domain = utils.domain_from_url(domain)<EOL>self.endpoint = endpoint<EOL>self.start_month = start_month<EOL>self.end_month = end_month<EOL>self.main_domain_only = main_domain_only<EOL>self.results_page = results_page<EOL>super(SearchKeywordsAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

endpoint: string
    Endpoint to use. Can be: orgsearch, paidsearch

domain: string
    Domain to query.

start_month: string
    Start Month in (M-YYYY) format

end_month: string
    End Month in (M-YYYY) format

main_domain_only: boolean
    Get metrics on the Main Domain only (i.e. not including subdomains)

results_page: integer
    Enter for more than 10 results


self.domain = utils.domain_from_url(domain)<EOL>super(DestinationsAPI, self).__init__(api_key)<EOL>


def __init__(self, api_key, domain, start_month, end_month,<EOL>main_domain_only=False, results_page=None):

self.domain = utils.domain_from_url(domain)<EOL>self.start_month = start_month<EOL>self.end_month = end_month<EOL>self.main_domain_only = main_domain_only<EOL>self.results_page = results_page<EOL>super(ReferralsAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

domain: string
    Domain to query.

start_month: string
    Start Month in (M-YYYY) format

end_month: string
    End Month in (M-YYYY) format

main_domain_only: boolean
    Get metrics on the Main Domain only (i.e. not including subdomains)

results_page: integer
    Enter for more than 10 results


if endpoint not in ["<STR_LIT>", "<STR_LIT>", ]:<EOL><INDENT>raise InvalidEndpointException("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>self.domain = utils.domain_from_url(domain)<EOL>self.endpoint = endpoint<EOL>self.start_month = start_month<EOL>self.end_month = end_month<EOL>self.main_domain_only = main_domain_only<EOL>self.results_page = results_page<EOL>super(KeywordCompetitorsAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

endpoint: string
    Endpoint to use. Can be: orgkwcompetitor, paidkwcompetitor

domain: string
    Domain to query.

start_month: string
    Start Month in (M-YYYY) format

end_month: string
    End Month in (M-YYYY) format

main_domain_only: boolean
    Get metrics on the Main Domain only (i.e. not including subdomains)

results_page: integer
    Enter for more than 10 results


def __init__(self, api_key, app_id, app_store_id):

self.app_id = app_id<EOL>self.app_store_id = app_store_id<EOL>super(AppDetailsAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

app_id: string
    Enter the ID of the app (e.g. "com.yahoo.mobile.client.android.mail")

app_store_id: integer
    0 for Google Play Store, 1 for iOS AppStore


self.app_id = app_id<EOL>super(GoogleAppInstallsAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

app_id: string
    Enter the ID of the app (e.g. "com.yahoo.mobile.client.android.mail")


def __init__(self, api_key, domain, app_store_id):

self.domain = utils.domain_from_url(domain)<EOL>self.app_store_id = app_store_id<EOL>super(RelatedSiteAppsAPI, self).__init__(api_key)<EOL>

Parameters
----------
api_key: string
    SimilarWeb API key

domain: string
    Domain to query.

app_store_id: integer
    0 for Google Play Store, 1 for iOS AppStore


ext = tldextract.extract(url)<EOL>if not ext.suffix:<EOL><INDENT>raise InvalidURLException()<EOL><DEDENT>new_url = ext.domain + "<STR_LIT:.>" + ext.suffix<EOL>return new_url<EOL>

Get root domain from url.
Will prune away query strings, url paths, protocol prefix and sub-domains
Exceptions will be raised on invalid urls


if sys.version_info.major == major and sys.version_info.minor == minor:<EOL><INDENT>return unittest.expectedFailure<EOL><DEDENT>else:<EOL><INDENT>return lambda x: x<EOL><DEDENT>

A decorator to mark a test as an expected failure for one python version.


<EOL>return CarddavObject.from_user_input(<EOL>address_book=mock.Mock(path='<STR_LIT>'), user_input=yaml,<EOL>supported_private_objects=[], version='<STR_LIT>',<EOL>localize_dates=False)<EOL>

Parse some yaml string into a CarddavObject

        :param yaml: the yaml input string to parse
        :type yaml: str
        :returns: the parsed CarddavObject
        :rtype: CarddavObject


self._tmp = tempfile.TemporaryDirectory()<EOL>path = pathlib.Path(self._tmp.name)<EOL>self.abook1 = path / '<STR_LIT>'<EOL>self.abook2 = path / '<STR_LIT>'<EOL>self.abook1.mkdir()<EOL>self.abook2.mkdir()<EOL>self.contact = self.abook1 / '<STR_LIT>'<EOL>shutil.copy('<STR_LIT>', str(self.contact))<EOL>config = path / '<STR_LIT>'<EOL>with config.open('<STR_LIT:w>') as fh:<EOL><INDENT>fh.write(<EOL>"""<STR_LIT>""".format(self.abook1, self.abook2))<EOL><DEDENT>self._patch = mock.patch.dict('<STR_LIT>', KHARD_CONFIG=str(config))<EOL>self._patch.start()<EOL>

Create a temporary directory with two address books and a configfile.


print(prefix + message)<EOL>sys.exit(<NUM_LIT:3>)<EOL>

Exit with a message and a return code indicating an error in the config
    file.

    This function doesn't return, it calls sys.exit.

    :param message: the message to print
    :type message: str
    :param prefix: the prefix to put in front of the message
    :type prefix: str
    :returns: does not return


@staticmethod<EOL><INDENT>def _convert_boolean_config_value(config, name, default=True):<DEDENT>

if name not in config:<EOL><INDENT>config[name] = default<EOL><DEDENT>elif config[name] == "<STR_LIT:yes>":<EOL><INDENT>config[name] = True<EOL><DEDENT>elif config[name] == "<STR_LIT>":<EOL><INDENT>config[name] = False<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>" % name)<EOL><DEDENT>

Convert the named field to bool.

        The current value should be one of the strings "yes" or "no".  It will
        be replaced with its boolean counterpart.  If the field is not present
        in the config object, the default value is used.

        :param config: the config section where to set the option
        :type config: configobj.ConfigObj
        :param name: the name of the option to convert
        :type name: str
        :param default: the default value to use if the option was not
            previously set
        :type default: bool
        :returns: None


with NamedTemporaryFile(mode='<STR_LIT>', suffix='<STR_LIT>', delete=False)as tempfile:<EOL><INDENT>tempfile.write(text)<EOL>return tempfile.name<EOL><DEDENT>

Create a new temporary file and write some initial text to it.

    :param text: the text to write to the temp file
    :type text: str
    :returns: the file name of the newly created temp file
    :rtype: str


def get_contact_list_by_user_selection(address_books, search, strict_search):

return get_contacts(<EOL>address_books, search, "<STR_LIT:name>" if strict_search else "<STR_LIT:all>",<EOL>config.reverse(), config.group_by_addressbook(), config.sort)<EOL>

returns a list of CarddavObject objects
    :param address_books: list of selected address books
    :type address_books: list(address_book.AddressBook)
    :param search: filter contact list
    :type search: str
    :param strict_search: if True, search only in full name field
    :type strict_search: bool
    :returns: list of CarddavObject objects
    :rtype: list(CarddavObject)


def get_contacts(address_books, query, method="<STR_LIT:all>", reverse=False,<EOL>group=False, sort="<STR_LIT>"):

<EOL>contacts = []<EOL>for address_book in address_books:<EOL><INDENT>contacts.extend(address_book.search(query, method=method))<EOL><DEDENT>if group:<EOL><INDENT>if sort == "<STR_LIT>":<EOL><INDENT>return sorted(contacts, reverse=reverse, key=lambda x: (<EOL>unidecode(x.address_book.name).lower(),<EOL>unidecode(x.get_first_name_last_name()).lower()))<EOL><DEDENT>elif sort == "<STR_LIT>":<EOL><INDENT>return sorted(contacts, reverse=reverse, key=lambda x: (<EOL>unidecode(x.address_book.name).lower(),<EOL>unidecode(x.get_last_name_first_name()).lower()))<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>'<EOL>'<STR_LIT>'.format(sort))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if sort == "<STR_LIT>":<EOL><INDENT>return sorted(contacts, reverse=reverse, key=lambda x:<EOL>unidecode(x.get_first_name_last_name()).lower())<EOL><DEDENT>elif sort == "<STR_LIT>":<EOL><INDENT>return sorted(contacts, reverse=reverse, key=lambda x:<EOL>unidecode(x.get_last_name_first_name()).lower())<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>'<EOL>'<STR_LIT>'.format(sort))<EOL><DEDENT><DEDENT>

Get a list of contacts from one or more address books.

    :param address_books: the address books to search
    :type address_books: list(address_book.AddressBook)
    :param query: a search query to select contacts
    :type quer: str
    :param method: the search method, one of "all", "name" or "uid"
    :type method: str
    :param reverse: reverse the order of the returned contacts
    :type reverse: bool
    :param group: group results by address book
    :type group: bool
    :param sort: the field to use for sorting, one of "first_name", "last_name"
    :type sort: str
    :returns: contacts from the address_books that match the query
    :rtype: list(CarddavObject)


<EOL>if "<STR_LIT>" in args and args.display:<EOL><INDENT>config.set_display_by_name(args.display)<EOL><DEDENT>if "<STR_LIT>" in args and args.group_by_addressbook:<EOL><INDENT>config.set_group_by_addressbook(True)<EOL><DEDENT>if "<STR_LIT>" in args and args.reverse:<EOL><INDENT>config.set_reverse(True)<EOL><DEDENT>if "<STR_LIT>" in args and args.sort:<EOL><INDENT>config.sort = args.sort<EOL><DEDENT>if "<STR_LIT>" in args and args.vcard_version:<EOL><INDENT>config.set_preferred_vcard_version(args.vcard_version)<EOL><DEDENT>if "<STR_LIT>" in args and args.search_in_source_files:<EOL><INDENT>config.set_search_in_source_files(True)<EOL><DEDENT>if "<STR_LIT>" in args and args.skip_unparsable:<EOL><INDENT>config.set_skip_unparsable(True)<EOL><DEDENT>if "<STR_LIT>" in args and not args.addressbook:<EOL><INDENT>args.addressbook = [abook.name for abook in config.abooks]<EOL><DEDENT>if "<STR_LIT>" in args and not args.target_addressbook:<EOL><INDENT>args.target_addressbook = [abook.name for abook in config.abooks]<EOL><DEDENT>

Merge the parsed arguments from argparse into the config object.

    :param args: the parsed command line arguments
    :type args: argparse.Namespace
    :param config: the parsed config file
    :type config: config.Config
    :returns: the merged config object
    :rtype: config.Config


def load_address_books(names, config, search_queries):

all_names = {str(book) for book in config.abooks}<EOL>if not names:<EOL><INDENT>names = all_names<EOL><DEDENT>elif not all_names.issuperset(names):<EOL><INDENT>sys.exit('<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>'<STR_LIT>'.join(set(names) - all_names),<EOL>'<STR_LIT:U+002CU+0020>'.join(all_names)))<EOL><DEDENT>for name in names:<EOL><INDENT>address_book = config.abook.get_abook(name)<EOL>address_book.load(search_queries[address_book.name],<EOL>search_in_source_files=config.search_in_source_files())<EOL>yield address_book<EOL><DEDENT>

Load all address books with the given names from the config.

    :param names: the address books to load
    :type names: list(str)
    :param config: the config instance to use when looking up address books
    :type config: config.Config
    :param search_queries: a mapping of address book names to search queries
    :type search_queries: dict
    :yields: the loaded address books
    :ytype: addressbook.AddressBook


<EOL>source_queries = []<EOL>target_queries = []<EOL>if "<STR_LIT>" in args and args.source_search_terms:<EOL><INDENT>escaped_term = "<STR_LIT>".join(re.escape(x)<EOL>for x in args.source_search_terms)<EOL>source_queries.append(escaped_term)<EOL>args.source_search_terms = escaped_term<EOL><DEDENT>if "<STR_LIT>" in args and args.search_terms:<EOL><INDENT>escaped_term = "<STR_LIT>".join(re.escape(x) for x in args.search_terms)<EOL>source_queries.append(escaped_term)<EOL>args.search_terms = escaped_term<EOL><DEDENT>if "<STR_LIT>" in args and args.target_contact:<EOL><INDENT>escaped_term = re.escape(args.target_contact)<EOL>target_queries.append(escaped_term)<EOL>args.target_contact = escaped_term<EOL><DEDENT>if "<STR_LIT>" in args and args.uid:<EOL><INDENT>source_queries.append(args.uid)<EOL><DEDENT>if "<STR_LIT>" in args and args.target_uid:<EOL><INDENT>target_queries.append(args.target_uid)<EOL><DEDENT>source_queries = "<STR_LIT>" % '<STR_LIT>'.join(source_queries)if source_queries else None<EOL>target_queries = "<STR_LIT>" % '<STR_LIT>'.join(target_queries)if target_queries else None<EOL>logging.debug('<STR_LIT>', source_queries)<EOL>logging.debug('<STR_LIT>', target_queries)<EOL>queries = {abook.name: [] for abook in config.abook._abooks}<EOL>for name in queries:<EOL><INDENT>if "<STR_LIT>" in args and name in args.addressbook:<EOL><INDENT>queries[name].append(source_queries)<EOL><DEDENT>if "<STR_LIT>" in args and name in args.target_addressbook:<EOL><INDENT>queries[name].append(target_queries)<EOL><DEDENT>if None in queries[name]:<EOL><INDENT>queries[name] = None<EOL><DEDENT>else:<EOL><INDENT>queries[name] = "<STR_LIT>".format('<STR_LIT>'.join(queries[name]))<EOL><DEDENT><DEDENT>logging.debug('<STR_LIT>', queries)<EOL>return queries<EOL>

Prepare the search query string from the given command line args.

    Each address book can get a search query string to filter vcards befor
    loading them.  Depending on the question if the address book is used for
    source or target searches different regexes have to be combined into one
    search string.

    :param args: the parsed command line
    :type args: argparse.Namespace
    :returns: a dict mapping abook names to their loading queries, if the query
        is None it means that all cards should be loaded
    :rtype: dict(str:str or None)


<EOL>vcard_list = []<EOL>if "<STR_LIT>" in args and args.uid:<EOL><INDENT>logging.debug("<STR_LIT>", args.uid)<EOL>args.search_terms = "<STR_LIT>"<EOL>vcard_list = get_contacts(args.addressbook, args.uid, method="<STR_LIT>")<EOL>if not vcard_list:<EOL><INDENT>sys.exit("<STR_LIT>".format(<EOL>"<STR_LIT>" if args.action == "<STR_LIT>" else "<STR_LIT>", args.uid))<EOL><DEDENT>elif len(vcard_list) != <NUM_LIT:1>:<EOL><INDENT>print("<STR_LIT>".format(<EOL>"<STR_LIT>" if args.action == "<STR_LIT>" else "<STR_LIT>", args.uid))<EOL>for vcard in vcard_list:<EOL><INDENT>print("<STR_LIT>".format(vcard, vcard.get_uid()))<EOL><DEDENT>sys.exit(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if "<STR_LIT>" in args:<EOL><INDENT>if args.source_search_terms:<EOL><INDENT>args.search_terms = args.source_search_terms<EOL><DEDENT>else:<EOL><INDENT>args.search_terms = "<STR_LIT>"<EOL><DEDENT><DEDENT>elif "<STR_LIT>" in args:<EOL><INDENT>if args.search_terms:<EOL><INDENT>args.search_terms = args.search_terms<EOL><DEDENT>else:<EOL><INDENT>args.search_terms = "<STR_LIT>"<EOL><DEDENT><DEDENT>else:<EOL><INDENT>args.search_terms = "<STR_LIT>"<EOL><DEDENT>logging.debug("<STR_LIT>", args.search_terms)<EOL>vcard_list = get_contact_list_by_user_selection(<EOL>args.addressbook, args.search_terms,<EOL>args.strict_search if "<STR_LIT>" in args else False)<EOL><DEDENT>return vcard_list<EOL>

TODO: Docstring for generate_contact_list.

    :param config: the config object to use
    :type config: config.Config
    :param args: the command line arguments
    :type args: argparse.Namespace
    :returns: the contacts for further processing (TODO)
    :rtype: list(TODO)


<EOL>selected_address_book = choose_address_book_from_list(<EOL>"<STR_LIT>", selected_address_books)<EOL>if selected_address_book is None:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>if input_from_stdin_or_file:<EOL><INDENT>try:<EOL><INDENT>new_contact = CarddavObject.from_user_input(<EOL>selected_address_book, input_from_stdin_or_file,<EOL>config.get_supported_private_objects(),<EOL>config.get_preferred_vcard_version(),<EOL>config.localize_dates())<EOL><DEDENT>except ValueError as err:<EOL><INDENT>print(err)<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>else:<EOL><INDENT>new_contact.write_to_file()<EOL><DEDENT>if open_editor:<EOL><INDENT>modify_existing_contact(new_contact)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>" % new_contact.print_vcard())<EOL><DEDENT><DEDENT>else:<EOL><INDENT>create_new_contact(selected_address_book)<EOL><DEDENT>

Create a new contact.

    :param selected_address_books: a list of addressbooks that were selected on
        the command line
    :type selected_address_books: list of address_book.AddressBook
    :param input_from_stdin_or_file: the data for the new contact as a yaml
        formatted string
    :type input_from_stdin_or_file: str
    :param open_editor: whether to open the new contact in the edior after
        creation
    :type open_editor: bool
    :returns: None
    :rtype: None


<EOL>message = message_from_string(input_from_stdin_or_file, policy=SMTP_POLICY)<EOL>print("<STR_LIT>")<EOL>if not message['<STR_LIT>']or not message['<STR_LIT>'].addresses:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>email_address = message['<STR_LIT>'].addresses[<NUM_LIT:0>].addr_spec<EOL>name = message['<STR_LIT>'].addresses[<NUM_LIT:0>].display_name<EOL>print("<STR_LIT>" % email_address)<EOL>if not name:<EOL><INDENT>name = input("<STR_LIT>")<EOL><DEDENT>selected_vcard = choose_vcard_from_list(<EOL>"<STR_LIT>",<EOL>get_contact_list_by_user_selection(selected_address_books, name, True))<EOL>if selected_vcard is None:<EOL><INDENT>while True:<EOL><INDENT>input_string = input("<STR_LIT>"<EOL>"<STR_LIT>" % name)<EOL>if input_string.lower() in ["<STR_LIT>", "<STR_LIT:n>", "<STR_LIT:q>"]:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:0>)<EOL><DEDENT>if input_string.lower() == "<STR_LIT:y>":<EOL><INDENT>break<EOL><DEDENT><DEDENT>selected_address_book = choose_address_book_from_list(<EOL>"<STR_LIT>", config.abooks)<EOL>if selected_address_book is None:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>while True:<EOL><INDENT>first_name = input("<STR_LIT>")<EOL>last_name = input("<STR_LIT>")<EOL>organisation = input("<STR_LIT>")<EOL>if not first_name and not last_name and not organisation:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>selected_vcard = CarddavObject.from_user_input(<EOL>selected_address_book,<EOL>"<STR_LIT>" % (<EOL>first_name, last_name, organisation),<EOL>config.get_supported_private_objects(),<EOL>config.get_preferred_vcard_version(),<EOL>config.localize_dates())<EOL><DEDENT>for type, email_list in sorted(<EOL>selected_vcard.get_email_addresses().items(),<EOL>key=lambda k: k[<NUM_LIT:0>].lower()):<EOL><INDENT>for email in email_list:<EOL><INDENT>if email == email_address:<EOL><INDENT>print("<STR_LIT>" %<EOL>(selected_vcard, email_address))<EOL>sys.exit(<NUM_LIT:0>)<EOL><DEDENT><DEDENT><DEDENT>while True:<EOL><INDENT>input_string = input(<EOL>"<STR_LIT>"<EOL>% (email_address, selected_vcard))<EOL>if input_string.lower() in ["<STR_LIT>", "<STR_LIT:n>", "<STR_LIT:q>"]:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:0>)<EOL><DEDENT>if input_string.lower() == "<STR_LIT:y>":<EOL><INDENT>break<EOL><DEDENT><DEDENT>print("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" %<EOL>(email_address, selected_vcard))<EOL>while True:<EOL><INDENT>label = input("<STR_LIT>") or "<STR_LIT>"<EOL>try:<EOL><INDENT>selected_vcard.add_email_address(label, email_address)<EOL><DEDENT>except ValueError as err:<EOL><INDENT>print(err)<EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>selected_vcard.write_to_file(overwrite=True)<EOL>print("<STR_LIT>" % selected_vcard.print_vcard())<EOL>

Add a new email address to contacts, creating new contacts if necessary.

    :param input_from_stdin_or_file: the input text to search for the new email
    :type input_from_stdin_or_file: str
    :param selected_address_books: the addressbooks that were selected on the
        command line
    :type selected_address_books: list of address_book.AddressBook
    :returns: None
    :rtype: None


<EOL>vcard_list = [<EOL>vcard for vcard in vcard_list if vcard.get_birthday() is not None]<EOL>vcard_list.sort(<EOL>key=lambda x: (x.get_birthday().month, x.get_birthday().day)<EOL>if isinstance(x.get_birthday(), datetime.datetime)<EOL>else (<NUM_LIT:0>, <NUM_LIT:0>, x.get_birthday()))<EOL>birthday_list = []<EOL>for vcard in vcard_list:<EOL><INDENT>date = vcard.get_birthday()<EOL>if parsable:<EOL><INDENT>if config.display_by_name() == "<STR_LIT>":<EOL><INDENT>birthday_list.append("<STR_LIT>"<EOL>% (date.year, date.month, date.day,<EOL>vcard.get_first_name_last_name()))<EOL><DEDENT>else:<EOL><INDENT>birthday_list.append("<STR_LIT>"<EOL>% (date.year, date.month, date.day,<EOL>vcard.get_last_name_first_name()))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if config.display_by_name() == "<STR_LIT>":<EOL><INDENT>birthday_list.append("<STR_LIT>"<EOL>% (vcard.get_first_name_last_name(),<EOL>vcard.get_formatted_birthday()))<EOL><DEDENT>else:<EOL><INDENT>birthday_list.append("<STR_LIT>"<EOL>% (vcard.get_last_name_first_name(),<EOL>vcard.get_formatted_birthday()))<EOL><DEDENT><DEDENT><DEDENT>if birthday_list:<EOL><INDENT>if parsable:<EOL><INDENT>print('<STR_LIT:\n>'.join(birthday_list))<EOL><DEDENT>else:<EOL><INDENT>list_birthdays(birthday_list)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if not parsable:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>

Print birthday contact table.

    :param vcard_list: the vcards to search for matching entries which should
        be printed
    :type vcard_list: list of carddav_object.CarddavObject
    :param parsable: machine readable output: columns devided by tabulator (\t)
    :type parsable: bool
    :returns: None
    :rtype: None


def phone_subcommand(search_terms, vcard_list, parsable):

all_phone_numbers_list = []<EOL>matching_phone_number_list = []<EOL>for vcard in vcard_list:<EOL><INDENT>for type, number_list in sorted(vcard.get_phone_numbers().items(),<EOL>key=lambda k: k[<NUM_LIT:0>].lower()):<EOL><INDENT>for number in sorted(number_list):<EOL><INDENT>if config.display_by_name() == "<STR_LIT>":<EOL><INDENT>name = vcard.get_first_name_last_name()<EOL><DEDENT>else:<EOL><INDENT>name = vcard.get_last_name_first_name()<EOL><DEDENT>line_formatted = "<STR_LIT:\t>".join([name, type, number])<EOL>line_parsable = "<STR_LIT:\t>".join([number, name, type])<EOL>if parsable:<EOL><INDENT>phone_number_line = line_parsable<EOL><DEDENT>else:<EOL><INDENT>phone_number_line = line_formatted<EOL><DEDENT>if re.search(search_terms,<EOL>"<STR_LIT>" % (line_formatted, line_parsable),<EOL>re.IGNORECASE | re.DOTALL):<EOL><INDENT>matching_phone_number_list.append(phone_number_line)<EOL><DEDENT>elif len(re.sub("<STR_LIT>", "<STR_LIT>", search_terms)) >= <NUM_LIT:3>:<EOL><INDENT>if re.search(re.sub("<STR_LIT>", "<STR_LIT>", search_terms),<EOL>re.sub("<STR_LIT>", "<STR_LIT>", number), re.IGNORECASE):<EOL><INDENT>matching_phone_number_list.append(phone_number_line)<EOL><DEDENT><DEDENT>all_phone_numbers_list.append(phone_number_line)<EOL><DEDENT><DEDENT><DEDENT>if matching_phone_number_list:<EOL><INDENT>if parsable:<EOL><INDENT>print('<STR_LIT:\n>'.join(matching_phone_number_list))<EOL><DEDENT>else:<EOL><INDENT>list_phone_numbers(matching_phone_number_list)<EOL><DEDENT><DEDENT>elif all_phone_numbers_list:<EOL><INDENT>if parsable:<EOL><INDENT>print('<STR_LIT:\n>'.join(all_phone_numbers_list))<EOL><DEDENT>else:<EOL><INDENT>list_phone_numbers(all_phone_numbers_list)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if not parsable:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>

Print a phone application friendly contact table.

    :param search_terms: used as search term to filter the contacts before
        printing
    :type search_terms: str
    :param vcard_list: the vcards to search for matching entries which should
        be printed
    :type vcard_list: list of carddav_object.CarddavObject
    :param parsable: machine readable output: columns devided by tabulator (\t)
    :type parsable: bool
    :returns: None
    :rtype: None


def post_address_subcommand(search_terms, vcard_list, parsable):

all_post_address_list = []<EOL>matching_post_address_list = []<EOL>for vcard in vcard_list:<EOL><INDENT>if config.display_by_name() == "<STR_LIT>":<EOL><INDENT>name = vcard.get_first_name_last_name()<EOL><DEDENT>else:<EOL><INDENT>name = vcard.get_last_name_first_name()<EOL><DEDENT>post_address_line_list = []<EOL>if parsable:<EOL><INDENT>for type, post_address_list in sorted(vcard.get_post_addresses().items(),<EOL>key=lambda k: k[<NUM_LIT:0>].lower()):<EOL><INDENT>for post_address in post_address_list:<EOL><INDENT>post_address_line_list.append(<EOL>"<STR_LIT:\t>".join([str(post_address), name, type]))<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>for type, post_address_list in sorted(vcard.get_formatted_post_addresses().items(),<EOL>key=lambda k: k[<NUM_LIT:0>].lower()):<EOL><INDENT>for post_address in sorted(post_address_list):<EOL><INDENT>post_address_line_list.append(<EOL>"<STR_LIT:\t>".join([name, type, post_address]))<EOL><DEDENT><DEDENT><DEDENT>for post_address_line in post_address_line_list:<EOL><INDENT>if re.search(search_terms,<EOL>"<STR_LIT>" % (post_address_line, post_address_line),<EOL>re.IGNORECASE | re.DOTALL):<EOL><INDENT>matching_post_address_list.append(post_address_line)<EOL><DEDENT>all_post_address_list.append(post_address_line)<EOL><DEDENT><DEDENT>if matching_post_address_list:<EOL><INDENT>if parsable:<EOL><INDENT>print('<STR_LIT:\n>'.join(matching_post_address_list))<EOL><DEDENT>else:<EOL><INDENT>list_post_addresses(matching_post_address_list)<EOL><DEDENT><DEDENT>elif all_post_address_list:<EOL><INDENT>if parsable:<EOL><INDENT>print('<STR_LIT:\n>'.join(all_post_address_list))<EOL><DEDENT>else:<EOL><INDENT>list_post_addresses(all_post_address_list)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if not parsable:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>

Print a contact table. with all postal / mailing addresses

    :param search_terms: used as search term to filter the contacts before
        printing
    :type search_terms: str
    :param vcard_list: the vcards to search for matching entries which should
        be printed
    :type vcard_list: list of carddav_object.CarddavObject
    :param parsable: machine readable output: columns devided by tabulator (\t)
    :type parsable: bool
    :returns: None
    :rtype: None


def email_subcommand(search_terms, vcard_list, parsable, remove_first_line):

matching_email_address_list = []<EOL>all_email_address_list = []<EOL>for vcard in vcard_list:<EOL><INDENT>for type, email_list in sorted(vcard.get_email_addresses().items(),<EOL>key=lambda k: k[<NUM_LIT:0>].lower()):<EOL><INDENT>for email in sorted(email_list):<EOL><INDENT>if config.display_by_name() == "<STR_LIT>":<EOL><INDENT>name = vcard.get_first_name_last_name()<EOL><DEDENT>else:<EOL><INDENT>name = vcard.get_last_name_first_name()<EOL><DEDENT>line_formatted = "<STR_LIT:\t>".join([name, type, email])<EOL>line_parsable = "<STR_LIT:\t>".join([email, name, type])<EOL>if parsable:<EOL><INDENT>email_address_line = line_parsable<EOL><DEDENT>else:<EOL><INDENT>email_address_line = line_formatted<EOL><DEDENT>if re.search(search_terms,<EOL>"<STR_LIT>" % (line_formatted, line_parsable),<EOL>re.IGNORECASE | re.DOTALL):<EOL><INDENT>matching_email_address_list.append(email_address_line)<EOL><DEDENT>all_email_address_list.append(email_address_line)<EOL><DEDENT><DEDENT><DEDENT>if matching_email_address_list:<EOL><INDENT>if parsable:<EOL><INDENT>if not remove_first_line:<EOL><INDENT>print("<STR_LIT>" % search_terms)<EOL><DEDENT>print('<STR_LIT:\n>'.join(matching_email_address_list))<EOL><DEDENT>else:<EOL><INDENT>list_email_addresses(matching_email_address_list)<EOL><DEDENT><DEDENT>elif all_email_address_list:<EOL><INDENT>if parsable:<EOL><INDENT>if not remove_first_line:<EOL><INDENT>print("<STR_LIT>" % search_terms)<EOL><DEDENT>print('<STR_LIT:\n>'.join(all_email_address_list))<EOL><DEDENT>else:<EOL><INDENT>list_email_addresses(all_email_address_list)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if not parsable:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>elif not remove_first_line:<EOL><INDENT>print("<STR_LIT>" % search_terms)<EOL><DEDENT>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>

Print a mail client friendly contacts table that is compatible with the
    default format used by mutt.
    Output format:
        single line of text
        email_address\tname\ttype
        email_address\tname\ttype
        [...]

    :param search_terms: used as search term to filter the contacts before
        printing
    :type search_terms: str
    :param vcard_list: the vcards to search for matching entries which should
        be printed
    :type vcard_list: list of carddav_object.CarddavObject
    :param parsable: machine readable output: columns devided by tabulator (\t)
    :type parsable: bool
    :param remove_first_line: remove first line (searching for '' ...)
    :type remove_first_line: bool
    :returns: None
    :rtype: None


if not vcard_list:<EOL><INDENT>if not parsable:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>elif parsable:<EOL><INDENT>contact_line_list = []<EOL>for vcard in vcard_list:<EOL><INDENT>if config.display_by_name() == "<STR_LIT>":<EOL><INDENT>name = vcard.get_first_name_last_name()<EOL><DEDENT>else:<EOL><INDENT>name = vcard.get_last_name_first_name()<EOL><DEDENT>contact_line_list.append('<STR_LIT:\t>'.join([vcard.get_uid(), name,<EOL>vcard.address_book.name]))<EOL><DEDENT>print('<STR_LIT:\n>'.join(contact_line_list))<EOL><DEDENT>else:<EOL><INDENT>list_contacts(vcard_list)<EOL><DEDENT>

Print a user friendly contacts table.

    :param vcard_list: the vcards to print
    :type vcard_list: list of carddav_object.CarddavObject
    :param parsable: machine readable output: columns devided by tabulator (\t)
    :type parsable: bool
    :returns: None
    :rtype: None


def modify_subcommand(selected_vcard, input_from_stdin_or_file, open_editor):

<EOL>if selected_vcard.get_version() not in config.supported_vcard_versions:<EOL><INDENT>print("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>% (selected_vcard.get_version(),<EOL>config.get_preferred_vcard_version()))<EOL>while True:<EOL><INDENT>input_string = input("<STR_LIT>")<EOL>if input_string.lower() in ["<STR_LIT>", "<STR_LIT:n>", "<STR_LIT:q>"]:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:0>)<EOL><DEDENT>if input_string.lower() == "<STR_LIT:y>":<EOL><INDENT>break<EOL><DEDENT><DEDENT><DEDENT>if input_from_stdin_or_file:<EOL><INDENT>try:<EOL><INDENT>new_contact =CarddavObject.from_existing_contact_with_new_user_input(<EOL>selected_vcard, input_from_stdin_or_file,<EOL>config.localize_dates())<EOL><DEDENT>except ValueError as err:<EOL><INDENT>print(err)<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>if selected_vcard == new_contact:<EOL><INDENT>print("<STR_LIT>" % new_contact.print_vcard())<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>" % new_contact.print_vcard())<EOL>while True:<EOL><INDENT>input_string = input("<STR_LIT>")<EOL>if input_string.lower() in ["<STR_LIT>", "<STR_LIT:n>", "<STR_LIT:q>"]:<EOL><INDENT>print("<STR_LIT>")<EOL>break<EOL><DEDENT>if input_string.lower() == "<STR_LIT:y>":<EOL><INDENT>new_contact.write_to_file(overwrite=True)<EOL>if open_editor:<EOL><INDENT>modify_existing_contact(new_contact)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>break<EOL><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>modify_existing_contact(selected_vcard)<EOL><DEDENT>

Modify a contact in an external editor.

    :param selected_vcard: the contact to modify
    :type selected_vcard: carddav_object.CarddavObject
    :param input_from_stdin_or_file: new data from stdin (or a file) that
        should be incorperated into the contact, this should be a yaml
        formatted string
    :type input_from_stdin_or_file: str
    :param open_editor: whether to open the new contact in the edior after
        creation
    :type open_editor: bool
    :returns: None
    :rtype: None


if not force:<EOL><INDENT>while True:<EOL><INDENT>input_string = input(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" % (selected_vcard, selected_vcard.address_book))<EOL>if input_string.lower() in ["<STR_LIT>", "<STR_LIT:n>", "<STR_LIT:q>"]:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:0>)<EOL><DEDENT>if input_string.lower() == "<STR_LIT:y>":<EOL><INDENT>break<EOL><DEDENT><DEDENT><DEDENT>selected_vcard.delete_vcard_file()<EOL>print("<STR_LIT>" % selected_vcard.get_full_name())<EOL>

Remove a contact from the addressbook.

    :param selected_vcard: the contact to delete
    :type selected_vcard: carddav_object.CarddavObject
    :param force: delete without confirmation
    :type force: bool
    :returns: None
    :rtype: None


child = subprocess.Popen([editor, selected_vcard.filename])<EOL>child.communicate()<EOL>

Open the vcard file for a contact in an external editor.

    :param selected_vcard: the contact to edit
    :type selected_vcard: carddav_object.CarddavObject
    :param editor: the eitor command to use
    :type editor: str
    :returns: None
    :rtype: None


def merge_subcommand(vcard_list, selected_address_books, search_terms,<EOL>target_uid):

<EOL>if target_uid != "<STR_LIT>" and search_terms != "<STR_LIT>":<EOL><INDENT>print("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>if target_uid != "<STR_LIT>":<EOL><INDENT>target_vcards = get_contacts(selected_address_books, target_uid,<EOL>method="<STR_LIT>")<EOL>if len(target_vcards) != <NUM_LIT:1>:<EOL><INDENT>if not target_vcards:<EOL><INDENT>print("<STR_LIT>" % target_uid)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>" % target_uid)<EOL>for vcard in target_vcards:<EOL><INDENT>print("<STR_LIT>" % (vcard, vcard.get_uid()))<EOL><DEDENT><DEDENT>sys.exit(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>target_vcards = get_contact_list_by_user_selection(<EOL>selected_address_books, search_terms, False)<EOL><DEDENT>source_vcard = choose_vcard_from_list("<STR_LIT>",<EOL>vcard_list)<EOL>if source_vcard is None:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>"<EOL>% (source_vcard, source_vcard.address_book))<EOL><DEDENT>target_vcard = choose_vcard_from_list("<STR_LIT>",<EOL>target_vcards)<EOL>if target_vcard is None:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>"<EOL>% (target_vcard, target_vcard.address_book))<EOL><DEDENT>if source_vcard == target_vcard:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>merge_existing_contacts(source_vcard, target_vcard, True)<EOL><DEDENT>

Merge two contacts into one.

    :param vcard_list: the vcards from which to choose contacts for mergeing
    :type vcard_list: list of carddav_object.CarddavObject
    :param selected_address_books: the addressbooks to use to find the target
        contact
    :type selected_address_books: list(addressbook.AddressBook)
    :param search_terms: the search terms to find the target contact
    :type search_terms: str
    :param target_uid: the uid of the target contact or empty
    :type target_uid: str
    :returns: None
    :rtype: None


def copy_or_move_subcommand(action, vcard_list, target_address_book_list):

<EOL>source_vcard = choose_vcard_from_list(<EOL>"<STR_LIT>" % action.title(), vcard_list)<EOL>if source_vcard is None:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>"<EOL>% (action.title(), source_vcard, source_vcard.address_book))<EOL><DEDENT>if len(target_address_book_list) == <NUM_LIT:1>and target_address_book_list[<NUM_LIT:0>] == source_vcard.address_book:<EOL><INDENT>print("<STR_LIT>"<EOL>% (target_address_book_list[<NUM_LIT:0>], source_vcard))<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>else:<EOL><INDENT>available_address_books = [abook for abook in target_address_book_list<EOL>if abook != source_vcard.address_book]<EOL>selected_target_address_book = choose_address_book_from_list(<EOL>"<STR_LIT>", available_address_books)<EOL>if selected_target_address_book is None:<EOL><INDENT>print("<STR_LIT>")<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>target_vcard = choose_vcard_from_list(<EOL>"<STR_LIT>",<EOL>get_contact_list_by_user_selection([selected_target_address_book],<EOL>source_vcard.get_full_name(), True))<EOL>if target_vcard is None:<EOL><INDENT>copy_contact(source_vcard, selected_target_address_book,<EOL>action == "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>if source_vcard == target_vcard:<EOL><INDENT>print("<STR_LIT>" % target_vcard)<EOL>if action == "<STR_LIT>":<EOL><INDENT>copy_contact(source_vcard, selected_target_address_book, True)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT><DEDENT>else:<EOL><INDENT>print("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>" % (<EOL>target_vcard.address_book, source_vcard,<EOL>source_vcard.print_vcard(), target_vcard.print_vcard(),<EOL>"<STR_LIT>" if action == "<STR_LIT>" else "<STR_LIT>"))<EOL>while True:<EOL><INDENT>input_string = input("<STR_LIT>")<EOL>if input_string.lower() == "<STR_LIT:a>":<EOL><INDENT>copy_contact(source_vcard, selected_target_address_book,<EOL>action == "<STR_LIT>")<EOL>break<EOL><DEDENT>if input_string.lower() == "<STR_LIT:o>":<EOL><INDENT>copy_contact(source_vcard, selected_target_address_book,<EOL>action == "<STR_LIT>")<EOL>target_vcard.delete_vcard_file()<EOL>break<EOL><DEDENT>if input_string.lower() == "<STR_LIT:m>":<EOL><INDENT>merge_existing_contacts(source_vcard, target_vcard,<EOL>action == "<STR_LIT>")<EOL>break<EOL><DEDENT>if input_string.lower() in ["<STR_LIT>", "<STR_LIT:q>"]:<EOL><INDENT>print("<STR_LIT>")<EOL>break<EOL><DEDENT><DEDENT><DEDENT><DEDENT>

Copy or move a contact to a different address book.

    :action: the string "copy" or "move" to indicate what to do
    :type action: str
    :param vcard_list: the contact list from which to select one for the action
    :type vcard_list: list of carddav_object.CarddavObject
    :param target_address_book_list: the list of target address books
    :type target_address_book_list: list(addressbook.AddressBook)
    :returns: None
    :rtype: None


<EOL>base = argparse.ArgumentParser(<EOL>description="<STR_LIT>",<EOL>formatter_class=argparse.RawTextHelpFormatter, add_help=False)<EOL>base.add_argument("<STR_LIT:-c>", "<STR_LIT>", default="<STR_LIT>", help="<STR_LIT>")<EOL>base.add_argument("<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>base.add_argument("<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>base.add_argument("<STR_LIT>", "<STR_LIT>", action="<STR_LIT:version>",<EOL>version="<STR_LIT>" % khard_version)<EOL>first_parser = argparse.ArgumentParser(parents=[base])<EOL>first_parser.add_argument('<STR_LIT>', nargs=argparse.REMAINDER)<EOL>parser = argparse.ArgumentParser(parents=[base])<EOL>default_addressbook_parser = argparse.ArgumentParser(add_help=False)<EOL>default_addressbook_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default=[],<EOL>type=lambda x: [y.strip() for y in x.split("<STR_LIT:U+002C>")],<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>new_addressbook_parser = argparse.ArgumentParser(add_help=False)<EOL>new_addressbook_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default=[],<EOL>type=lambda x: [y.strip() for y in x.split("<STR_LIT:U+002C>")],<EOL>help="<STR_LIT>")<EOL>copy_move_addressbook_parser = argparse.ArgumentParser(add_help=False)<EOL>copy_move_addressbook_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default=[],<EOL>type=lambda x: [y.strip() for y in x.split("<STR_LIT:U+002C>")],<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>copy_move_addressbook_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default=[],<EOL>type=lambda x: [y.strip() for y in x.split("<STR_LIT:U+002C>")],<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>merge_addressbook_parser = argparse.ArgumentParser(add_help=False)<EOL>merge_addressbook_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default=[],<EOL>type=lambda x: [y.strip() for y in x.split("<STR_LIT:U+002C>")],<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>merge_addressbook_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default=[],<EOL>type=lambda x: [y.strip() for y in x.split("<STR_LIT:U+002C>")],<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>email_header_input_file_parser = argparse.ArgumentParser(add_help=False)<EOL>email_header_input_file_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default="<STR_LIT:->",<EOL>help="<STR_LIT>")<EOL>template_input_file_parser = argparse.ArgumentParser(add_help=False)<EOL>template_input_file_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default="<STR_LIT:->",<EOL>help="<STR_LIT>")<EOL>template_input_file_parser.add_argument(<EOL>"<STR_LIT>", action="<STR_LIT:store_true>", help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>sort_parser = argparse.ArgumentParser(add_help=False)<EOL>sort_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", choices=("<STR_LIT>", "<STR_LIT>"),<EOL>help="<STR_LIT>")<EOL>sort_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>sort_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>sort_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", choices=("<STR_LIT>", "<STR_LIT>"),<EOL>help="<STR_LIT>")<EOL>default_search_parser = argparse.ArgumentParser(add_help=False)<EOL>default_search_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL>default_search_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>default_search_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default="<STR_LIT>", help="<STR_LIT>")<EOL>default_search_parser.add_argument(<EOL>"<STR_LIT>", nargs="<STR_LIT:*>", metavar="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>merge_search_parser = argparse.ArgumentParser(add_help=False)<EOL>merge_search_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL>merge_search_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>merge_search_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", "<STR_LIT>", default="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>merge_search_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default="<STR_LIT>", help="<STR_LIT>")<EOL>merge_search_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default="<STR_LIT>", help="<STR_LIT>")<EOL>merge_search_parser.add_argument(<EOL>"<STR_LIT>", nargs="<STR_LIT:*>", metavar="<STR_LIT:source>",<EOL>help="<STR_LIT>")<EOL>subparsers = parser.add_subparsers(dest="<STR_LIT:action>")<EOL>list_parser = subparsers.add_parser(<EOL>"<STR_LIT:list>",<EOL>aliases=Actions.get_aliases("<STR_LIT:list>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>list_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>export_parser = subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>"<EOL>"<STR_LIT>",<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>export_parser.add_argument(<EOL>"<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>export_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", default=sys.stdout,<EOL>type=argparse.FileType("<STR_LIT:w>"),<EOL>help="<STR_LIT>")<EOL>birthdays_parser = subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[default_addressbook_parser, default_search_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>birthdays_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", choices=("<STR_LIT>", "<STR_LIT>"),<EOL>help="<STR_LIT>")<EOL>birthdays_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>email_parser = subparsers.add_parser(<EOL>"<STR_LIT:email>",<EOL>aliases=Actions.get_aliases("<STR_LIT:email>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>email_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>email_parser.add_argument(<EOL>"<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>phone_parser = subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>phone_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>post_address_parser = subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>post_address_parser.add_argument(<EOL>"<STR_LIT>", "<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>subparsers.add_parser(<EOL>"<STR_LIT:source>",<EOL>aliases=Actions.get_aliases("<STR_LIT:source>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>new_parser = subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[new_addressbook_parser, template_input_file_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>new_parser.add_argument(<EOL>"<STR_LIT>", choices=("<STR_LIT>", "<STR_LIT>"),<EOL>help="<STR_LIT>")<EOL>add_email_parser = subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[default_addressbook_parser, email_header_input_file_parser,<EOL>default_search_parser, sort_parser],<EOL>description="<STR_LIT>"<EOL>"<STR_LIT>",<EOL>help="<STR_LIT>"<EOL>"<STR_LIT>")<EOL>add_email_parser.add_argument(<EOL>"<STR_LIT>", choices=("<STR_LIT>", "<STR_LIT>"),<EOL>help="<STR_LIT>")<EOL>subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[merge_addressbook_parser, merge_search_parser, sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[default_addressbook_parser, template_input_file_parser,<EOL>default_search_parser, sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[copy_move_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[copy_move_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>remove_parser = subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>remove_parser.add_argument(<EOL>"<STR_LIT>", action="<STR_LIT:store_true>",<EOL>help="<STR_LIT>")<EOL>subparsers.add_parser(<EOL>"<STR_LIT>",<EOL>aliases=Actions.get_aliases("<STR_LIT>"),<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>subparsers.add_parser(<EOL>"<STR_LIT:filename>",<EOL>aliases=Actions.get_aliases("<STR_LIT:filename>"),<EOL>parents=[default_addressbook_parser, default_search_parser,<EOL>sort_parser],<EOL>description="<STR_LIT>",<EOL>help="<STR_LIT>")<EOL>first_parser.print_help = parser.print_help<EOL>args = first_parser.parse_args(argv)<EOL>remainder = args.remainder<EOL>if "<STR_LIT>" in args and args.debug:<EOL><INDENT>logging.basicConfig(level=logging.DEBUG)<EOL><DEDENT>global config<EOL>config = Config(args.config)<EOL>if ("<STR_LIT>" in args and args.debug) or config.debug:<EOL><INDENT>logging.basicConfig(level=logging.DEBUG)<EOL><DEDENT>logging.debug("<STR_LIT>", args)<EOL>logging.debug("<STR_LIT>", remainder)<EOL>if not remainder or remainder[<NUM_LIT:0>] not in Actions.get_all():<EOL><INDENT>remainder.insert(<NUM_LIT:0>, config.default_action)<EOL>logging.debug("<STR_LIT>", remainder)<EOL><DEDENT>skip = args.skip_unparsable<EOL>args = parser.parse_args(remainder)<EOL>args.skip_unparsable = skip<EOL>logging.debug("<STR_LIT>", args)<EOL>if "<STR_LIT>" in args and args.uid and (<EOL>("<STR_LIT>" in args and args.search_terms) or<EOL>("<STR_LIT>" in args and args.source_search_terms)):<EOL><INDENT>parser.error("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>return args<EOL>

Parse the command line arguments and return the namespace that was
    creates by argparse.ArgumentParser.parse_args().

    :returns: the namespace parsed from the command line
    :rtype: argparse.Namespace


def __init__(self, address_book, filename, supported_private_objects,<EOL>vcard_version, localize_dates):

self.vcard = None<EOL>self.address_book = address_book<EOL>self.filename = filename<EOL>self.supported_private_objects = supported_private_objects<EOL>self.localize_dates = localize_dates<EOL>if self.filename is None:<EOL><INDENT>self.vcard = vobject.vCard()<EOL>self.add_uid(helpers.get_random_uid())<EOL>self.filename = os.path.join(address_book.path,<EOL>self.get_uid() + "<STR_LIT>")<EOL>self._add_version(vcard_version)<EOL><DEDENT>else:<EOL><INDENT>with open(self.filename, "<STR_LIT:r>") as file:<EOL><INDENT>contents = file.read()<EOL><DEDENT>try:<EOL><INDENT>self.vcard = vobject.readOne(contents)<EOL><DEDENT>except Exception:<EOL><INDENT>self.vcard = vobject.readOne(self._filter_invalid_tags(contents))<EOL><DEDENT><DEDENT>

Initialize the vcard object.

        :param address_book: a reference to the address book where this vcard
            is stored
        :type address_book: khard.address_book.AddressBook
        :param filename: the path to the file where this vcard is stored or
            None
        :type filename: str or NoneType
        :param supported_private_objects: the list of private property names
            that will be loaded from the actual vcard and represented in this
            pobject
        :type supported_private_objects: list(str)
        :param vcard_version: str or None
        :type vcard_version: str
        :param localize_dates: should the formatted output of anniversary and
            birthday be localized or should the isoformat be used instead
        :type localize_dates: bool


@classmethod<EOL><INDENT>def new_contact(cls, address_book, supported_private_objects, version,<EOL>localize_dates):<DEDENT>

return cls(address_book, None, supported_private_objects, version,<EOL>localize_dates)<EOL>

Use this to create a new and empty contact.


@classmethod<EOL><INDENT>def from_file(cls, address_book, filename, supported_private_objects,<EOL>localize_dates):<DEDENT>

return cls(address_book, filename, supported_private_objects, None,<EOL>localize_dates)<EOL>

Use this if you want to create a new contact from an existing .vcf
file.


@classmethod<EOL><INDENT>def from_user_input(cls, address_book, user_input,<EOL>supported_private_objects, version, localize_dates):<DEDENT>

contact = cls(address_book, None, supported_private_objects, version,<EOL>localize_dates)<EOL>contact._process_user_input(user_input)<EOL>return contact<EOL>

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


contact = cls(contact.address_book, contact.filename,<EOL>contact.supported_private_objects, None, localize_dates)<EOL>contact._process_user_input(user_input)<EOL>return contact<EOL>

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


try:<EOL><INDENT>return getattr(self.vcard, field).value<EOL><DEDENT>except AttributeError:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>

Get a string field from the underlying vCard.

        :param field: the field value to get
        :type field: str
        :returns: the field value or the empty string
        :rtype: str


try:<EOL><INDENT>the_list = getattr(self.vcard.n.value, part)<EOL><DEDENT>except AttributeError:<EOL><INDENT>return []<EOL><DEDENT>else:<EOL><INDENT>if not '<STR_LIT>'.join(the_list):<EOL><INDENT>return []<EOL><DEDENT><DEDENT>return the_list if isinstance(the_list, list) else [the_list]<EOL>

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

        :param part: the name to get e.g. "prefix" or "given"
        :type part: str
        :returns: a list of entries for this name part
        :rtype: list(str)


names = []<EOL>if self._get_first_names():<EOL><INDENT>names += self._get_first_names()<EOL><DEDENT>if self._get_additional_names():<EOL><INDENT>names += self._get_additional_names()<EOL><DEDENT>if self._get_last_names():<EOL><INDENT>names += self._get_last_names()<EOL><DEDENT>if names:<EOL><INDENT>return helpers.list_to_string(names, "<STR_LIT:U+0020>")<EOL><DEDENT>else:<EOL><INDENT>return self.get_full_name()<EOL><DEDENT>


last_names = []<EOL>if self._get_last_names():<EOL><INDENT>last_names += self._get_last_names()<EOL><DEDENT>first_and_additional_names = []<EOL>if self._get_first_names():<EOL><INDENT>first_and_additional_names += self._get_first_names()<EOL><DEDENT>if self._get_additional_names():<EOL><INDENT>first_and_additional_names += self._get_additional_names()<EOL><DEDENT>if last_names and first_and_additional_names:<EOL><INDENT>return "<STR_LIT>".format(<EOL>helpers.list_to_string(last_names, "<STR_LIT:U+0020>"),<EOL>helpers.list_to_string(first_and_additional_names, "<STR_LIT:U+0020>"))<EOL><DEDENT>elif last_names:<EOL><INDENT>return helpers.list_to_string(last_names, "<STR_LIT:U+0020>")<EOL><DEDENT>elif first_and_additional_names:<EOL><INDENT>return helpers.list_to_string(first_and_additional_names, "<STR_LIT:U+0020>")<EOL><DEDENT>else:<EOL><INDENT>return self.get_full_name()<EOL><DEDENT>


organisations = []<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>organisations.append(child.value)<EOL><DEDENT><DEDENT>return sorted(organisations)<EOL>

:returns: list of organisations, sorted alphabetically
:rtype: list(list(str))


titles = []<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>titles.append(child.value)<EOL><DEDENT><DEDENT>return sorted(titles)<EOL>


roles = []<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>roles.append(child.value)<EOL><DEDENT><DEDENT>return sorted(roles)<EOL>


phone_dict = {}<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>type = helpers.list_to_string(<EOL>self._get_types_for_vcard_object(child, "<STR_LIT>"), "<STR_LIT:U+002CU+0020>")<EOL>if type not in phone_dict:<EOL><INDENT>phone_dict[type] = []<EOL><DEDENT>if child.value.lower().startswith("<STR_LIT>"):<EOL><INDENT>phone_dict[type].append(child.value[<NUM_LIT:4>:])<EOL><DEDENT>else:<EOL><INDENT>phone_dict[type].append(child.value)<EOL><DEDENT><DEDENT><DEDENT>for number_list in phone_dict.values():<EOL><INDENT>number_list.sort()<EOL><DEDENT>return phone_dict<EOL>

: returns: dict of type and phone number list
:rtype: dict(str, list(str))


email_dict = {}<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>type = helpers.list_to_string(<EOL>self._get_types_for_vcard_object(child, "<STR_LIT>"), "<STR_LIT:U+002CU+0020>")<EOL>if type not in email_dict:<EOL><INDENT>email_dict[type] = []<EOL><DEDENT>email_dict[type].append(child.value)<EOL><DEDENT><DEDENT>for email_list in email_dict.values():<EOL><INDENT>email_list.sort()<EOL><DEDENT>return email_dict<EOL>

: returns: dict of type and email address list
:rtype: dict(str, list(str))


post_adr_dict = {}<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>type = helpers.list_to_string(<EOL>self._get_types_for_vcard_object(child, "<STR_LIT>"), "<STR_LIT:U+002CU+0020>")<EOL>if type not in post_adr_dict:<EOL><INDENT>post_adr_dict[type] = []<EOL><DEDENT>post_adr_dict[type].append(<EOL>{<EOL>"<STR_LIT>": child.value.box,<EOL>"<STR_LIT>": child.value.extended,<EOL>"<STR_LIT>": child.value.street,<EOL>"<STR_LIT:code>": child.value.code,<EOL>"<STR_LIT>": child.value.city,<EOL>"<STR_LIT>": child.value.region,<EOL>"<STR_LIT>": child.value.country<EOL>})<EOL><DEDENT><DEDENT>for post_adr_list in post_adr_dict.values():<EOL><INDENT>post_adr_list.sort(key=lambda x: (<EOL>helpers.list_to_string(x['<STR_LIT>'], "<STR_LIT:U+0020>").lower(),<EOL>helpers.list_to_string(x['<STR_LIT>'], "<STR_LIT:U+0020>").lower()))<EOL><DEDENT>return post_adr_dict<EOL>

: returns: dict of type and post address list
:rtype: dict(str, list(dict(str,list|str)))


category_list = []<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>value = child.value<EOL>category_list.append(<EOL>value if isinstance(value, list) else [value])<EOL><DEDENT><DEDENT>if len(category_list) == <NUM_LIT:1>:<EOL><INDENT>return category_list[<NUM_LIT:0>]<EOL><DEDENT>return sorted(category_list)<EOL>


categories_obj = self.vcard.add('<STR_LIT>')<EOL>categories_obj.value = helpers.convert_to_vcard(<EOL>"<STR_LIT>", categories, ObjectType.list_with_strings)<EOL>


nicknames = []<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>nicknames.append(child.value)<EOL><DEDENT><DEDENT>return sorted(nicknames)<EOL>


notes = []<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>notes.append(child.value)<EOL><DEDENT><DEDENT>return sorted(notes)<EOL>


private_objects = {}<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name.lower().startswith("<STR_LIT>"):<EOL><INDENT>try:<EOL><INDENT>key_index = [<EOL>x.lower() for x in self.supported_private_objects<EOL>].index(child.name[<NUM_LIT:2>:].lower())<EOL><DEDENT>except ValueError:<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>key = self.supported_private_objects[key_index]<EOL>if key not in private_objects:<EOL><INDENT>private_objects[key] = []<EOL><DEDENT>private_objects[key].append(child.value)<EOL><DEDENT><DEDENT><DEDENT>for value in private_objects.values():<EOL><INDENT>value.sort()<EOL><DEDENT>return private_objects<EOL>


urls = []<EOL>for child in self.vcard.getChildren():<EOL><INDENT>if child.name == "<STR_LIT>":<EOL><INDENT>urls.append(child.value)<EOL><DEDENT><DEDENT>return sorted(urls)<EOL>


<EOL>try:<EOL><INDENT>if self.vcard.anniversary.params.get("<STR_LIT>")[<NUM_LIT:0>] == "<STR_LIT:text>":<EOL><INDENT>return self.vcard.anniversary.value<EOL><DEDENT><DEDENT>except (AttributeError, IndexError, TypeError):<EOL><INDENT>pass<EOL><DEDENT>try:<EOL><INDENT>return helpers.string_to_date(self.vcard.anniversary.value)<EOL><DEDENT>except (AttributeError, ValueError):<EOL><INDENT>try:<EOL><INDENT>return helpers.string_to_date(self.vcard.x_anniversary.value)<EOL><DEDENT>except (AttributeError, ValueError):<EOL><INDENT>pass<EOL><DEDENT><DEDENT>return None<EOL>

:returns: contacts anniversary or None if not available
            :rtype: datetime.datetime or str


<EOL>try:<EOL><INDENT>if self.vcard.bday.params.get("<STR_LIT>")[<NUM_LIT:0>] == "<STR_LIT:text>":<EOL><INDENT>return self.vcard.bday.value<EOL><DEDENT><DEDENT>except (AttributeError, IndexError, TypeError):<EOL><INDENT>pass<EOL><DEDENT>try:<EOL><INDENT>return helpers.string_to_date(self.vcard.bday.value)<EOL><DEDENT>except (AttributeError, ValueError):<EOL><INDENT>pass<EOL><DEDENT>return None<EOL>

:returns: contacts birthday or None if not available
            :rtype: datetime.datetime or str


def _get_types_for_vcard_object(self, object, default_type):

type_list = []<EOL>if object.group:<EOL><INDENT>for label in self.vcard.getChildren():<EOL><INDENT>if label.name == "<STR_LIT>" and label.group == object.group:<EOL><INDENT>custom_type = label.value.strip()<EOL>if custom_type:<EOL><INDENT>type_list.append(custom_type)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>standard_types = object.params.get("<STR_LIT>")<EOL>if standard_types is not None:<EOL><INDENT>if not isinstance(standard_types, list):<EOL><INDENT>standard_types = [standard_types]<EOL><DEDENT>for type in standard_types:<EOL><INDENT>type = type.strip()<EOL>if type and type.lower() != "<STR_LIT>":<EOL><INDENT>if not type.lower().startswith("<STR_LIT>"):<EOL><INDENT>type_list.append(type)<EOL><DEDENT>elif type[<NUM_LIT:2>:].lower() not in [x.lower() for x in type_list]:<EOL><INDENT>type_list.append(type[<NUM_LIT:2>:])<EOL><DEDENT><DEDENT><DEDENT><DEDENT>try:<EOL><INDENT>type_list.append("<STR_LIT>" % int(object.params.get("<STR_LIT>")[<NUM_LIT:0>]))<EOL><DEDENT>except (IndexError, TypeError, ValueError):<EOL><INDENT>try:<EOL><INDENT>for x in object.params.get("<STR_LIT>"):<EOL><INDENT>if x.lower() == "<STR_LIT>" and "<STR_LIT>" not in type_list:<EOL><INDENT>type_list.append("<STR_LIT>")<EOL><DEDENT><DEDENT><DEDENT>except TypeError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>if type_list:<EOL><INDENT>return type_list<EOL><DEDENT>return [default_type]<EOL>

get list of types for phone number, email or post address
:param object: vcard class object
:type object: vobject.vCard
:param default_type: use if the object contains no type
:type default_type: str
:returns: list of type labels
:rtype: list(str)


@staticmethod<EOL><INDENT>def _parse_type_value(types, value, supported_types):<DEDENT>

custom_types = []<EOL>standard_types = []<EOL>pref = <NUM_LIT:0><EOL>for type in types:<EOL><INDENT>type = type.strip()<EOL>if type:<EOL><INDENT>if type.lower() in supported_types:<EOL><INDENT>standard_types.append(type)<EOL><DEDENT>elif type.lower() == "<STR_LIT>":<EOL><INDENT>pref += <NUM_LIT:1><EOL><DEDENT>elif re.match(r"<STR_LIT>", type.lower()):<EOL><INDENT>pref += int(type.split("<STR_LIT:=>")[<NUM_LIT:1>])<EOL><DEDENT>else:<EOL><INDENT>if type.lower().startswith("<STR_LIT>"):<EOL><INDENT>custom_types.append(type[<NUM_LIT:2>:])<EOL>standard_types.append(type)<EOL><DEDENT>else:<EOL><INDENT>custom_types.append(type)<EOL>standard_types.append("<STR_LIT>".format(type))<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return (standard_types, custom_types, pref)<EOL>

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

        :param types: list of type values
        :type types: list(str)
        :param value: the corresponding label, required for more verbose
            exceptions
        :type value: str
        :param supported_types: all allowed standard types
        :type supported_types: list(str)
        :returns: tuple of standard and custom types and pref integer
        :rtype: tuple(list(str), list(str), int)


def __init__(self, filename, *args, **kwargs):

super().__init__(*args, **kwargs)<EOL>self.filename = filename<EOL>

Store the filename that caused the error.


def __init__(self, name, private_objects=tuple(), localize_dates=True,<EOL>skip=False):

self._loaded = False<EOL>self.contacts = {}<EOL>self._short_uids = None<EOL>self.name = name<EOL>self._private_objects = private_objects<EOL>self._localize_dates = localize_dates<EOL>self._skip = skip<EOL>

:param name: the name to identify the address book
:type name: str
:param private_objects: the names of private vCard extension fields to
    load
:type private_objects: iterable(str)
:param localize_dates: wheater to display dates in the local format
:type localize_dates: bool
:param skip: skip unparsable vCard files
:type skip: bool


sum = <NUM_LIT:0><EOL>for char1, char2 in zip(uid1, uid2):<EOL><INDENT>if char1 == char2:<EOL><INDENT>sum += <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>return sum<EOL>

Calculate the minimum length of initial substrings of uid1 and uid2
        for them to be different.

        :param uid1: first uid to compare
        :type uid1: str
        :param uid2: second uid to compare
        :type uid2: str
        :returns: the length of the shortes unequal initial substrings
        :rtype: int


regexp = re.compile(query, re.IGNORECASE | re.DOTALL)<EOL>for contact in self.contacts.values():<EOL><INDENT>contact_details = contact.print_vcard()<EOL>if regexp.search(contact_details) is not None:<EOL><INDENT>yield contact<EOL><DEDENT>else:<EOL><INDENT>clean_contact_details = re.sub("<STR_LIT>", "<STR_LIT>",<EOL>contact_details)<EOL>if regexp.search(clean_contact_details) is not Noneand len(re.sub("<STR_LIT>", "<STR_LIT>", query)) >= <NUM_LIT:3>:<EOL><INDENT>yield contact<EOL><DEDENT><DEDENT><DEDENT>

Search in all fields for contacts matching query.

        :param query: the query to search for
        :type query: str
        :yields: all found contacts
        :rtype: generator(carddav_object.CarddavObject)


regexp = re.compile(query, re.IGNORECASE | re.DOTALL)<EOL>for contact in self.contacts.values():<EOL><INDENT>if regexp.search(contact.get_full_name()) is not None:<EOL><INDENT>yield contact<EOL><DEDENT><DEDENT>

Search in the name filed for contacts matching query.

        :param query: the query to search for
        :type query: str
        :yields: all found contacts
        :rtype: generator(carddav_object.CarddavObject)


try:<EOL><INDENT>yield self.contacts[query]<EOL><DEDENT>except KeyError:<EOL><INDENT>for uid in self.contacts:<EOL><INDENT>if uid.startswith(query):<EOL><INDENT>yield self.contacts[uid]<EOL><DEDENT><DEDENT><DEDENT>

Search for contacts with a matching uid.

        :param query: the query to search for
        :type query: str
        :yields: all found contacts
        :rtype: generator(carddav_object.CarddavObject)


def search(self, query, method="<STR_LIT:all>"):

logging.debug('<STR_LIT>', self.name, query)<EOL>if not self._loaded:<EOL><INDENT>self.load(query)<EOL><DEDENT>if method == "<STR_LIT:all>":<EOL><INDENT>search_function = self._search_all<EOL><DEDENT>elif method == "<STR_LIT:name>":<EOL><INDENT>search_function = self._search_names<EOL><DEDENT>elif method == "<STR_LIT>":<EOL><INDENT>search_function = self._search_uid<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>return list(search_function(query))<EOL>

Search this address book for contacts matching the query.

        The method can be one of "all", "name" and "uid".  The backend for this
        address book migth be load()ed if needed.

        :param query: the query to search for
        :type query: str
        :param method: the type of fileds to use when seaching
        :type method: str
        :returns: all found contacts
        :rtype: list(carddav_object.CarddavObject)


if self._short_uids is None:<EOL><INDENT>if not self._loaded:<EOL><INDENT>self.load(query)<EOL><DEDENT>if not self.contacts:<EOL><INDENT>self._short_uids = {}<EOL><DEDENT>elif len(self.contacts) == <NUM_LIT:1>:<EOL><INDENT>self._short_uids = {uid[<NUM_LIT:0>:<NUM_LIT:1>]: contact<EOL>for uid, contact in self.contacts.items()}<EOL><DEDENT>else:<EOL><INDENT>self._short_uids = {}<EOL>sorted_uids = sorted(self.contacts)<EOL>item0, item1 = sorted_uids[:<NUM_LIT:2>]<EOL>same1 = self._compare_uids(item0, item1)<EOL>self._short_uids[item0[:same1 + <NUM_LIT:1>]] = self.contacts[item0]<EOL>for item_new in sorted_uids[<NUM_LIT:2>:]:<EOL><INDENT>item0, item1 = item1, item_new<EOL>same0, same1 = same1, self._compare_uids(item0, item1)<EOL>same = max(same0, same1)<EOL>self._short_uids[item0[:same + <NUM_LIT:1>]] = self.contacts[item0]<EOL><DEDENT>self._short_uids[item1[:same1 + <NUM_LIT:1>]] = self.contacts[item1]<EOL><DEDENT><DEDENT>return self._short_uids<EOL>

Create a dictionary of shortend UIDs for all contacts.

        All arguments are only used if the address book is not yet initialized
        and will just be handed to self.load().

        :param query: see self.load()
        :type query: str
        :returns: the contacts mapped by the shortes unique prefix of their UID
        :rtype: dict(str: CarddavObject)


if uid:<EOL><INDENT>short_uids = self.get_short_uid_dict()<EOL>for length_of_uid in range(len(uid), <NUM_LIT:0>, -<NUM_LIT:1>):<EOL><INDENT>if short_uids.get(uid[:length_of_uid]) is not None:<EOL><INDENT>return uid[:length_of_uid]<EOL><DEDENT><DEDENT><DEDENT>return "<STR_LIT>"<EOL>

Get the shortend UID for the given UID.

        :param uid: the full UID to shorten
        :type uid: str
        :returns: the shortend uid or the empty string
        :rtype: str


pass<EOL>

Load the vCards from the backing store.

        If a query is given loading is limited to entries which match the
        query.  If the query is None all entries will be loaded.

        :param query: the query to limit loading to matching entries
        :type query: str
        :returns: the number of loaded contacts and the number of errors
        :rtype: (int, int)


def __init__(self, name, path, **kwargs):

self.path = os.path.expanduser(path)<EOL>if not os.path.isdir(self.path):<EOL><INDENT>raise FileNotFoundError("<STR_LIT>"<EOL>"<STR_LIT>".format(path, name))<EOL><DEDENT>super().__init__(name, **kwargs)<EOL>

:param name: the name to identify the address book
:type name: str
:param path: the path to the backing structure on disk
:type path: str
:param **kwargs: further arguments for the parent constructor


def _find_vcard_files(self, search=None, search_in_source_files=False):

files = glob.glob(os.path.join(self.path, "<STR_LIT>"))<EOL>if search and search_in_source_files:<EOL><INDENT>for filename in files:<EOL><INDENT>with open(filename, "<STR_LIT:r>") as filehandle:<EOL><INDENT>if re.search(search, filehandle.read(),<EOL>re.IGNORECASE | re.DOTALL):<EOL><INDENT>yield filename<EOL><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>yield from files<EOL><DEDENT>

Find all vcard files inside this address book.

        If a search string is given only files which contents match that will
        be returned.

        :param search: a regular expression to limit the results
        :type search: str
        :param search_in_source_files: apply search regexp directly on the .vcf files to speed up parsing (less accurate)
        :type search_in_source_files: bool
        :returns: the paths of the vcard files
        :rtype: generator


def load(self, query=None, search_in_source_files=False):

if self._loaded:<EOL><INDENT>return<EOL><DEDENT>logging.debug('<STR_LIT>', self.name, query)<EOL>errors = <NUM_LIT:0><EOL>for filename in self._find_vcard_files(<EOL>search=query, search_in_source_files=search_in_source_files):<EOL><INDENT>try:<EOL><INDENT>card = CarddavObject.from_file(self, filename,<EOL>self._private_objects,<EOL>self._localize_dates)<EOL><DEDENT>except (IOError, vobject.base.ParseError) as err:<EOL><INDENT>verb = "<STR_LIT>" if isinstance(err, IOError) else "<STR_LIT>"<EOL>logging.debug("<STR_LIT>", verb,<EOL>filename, err)<EOL>if self._skip:<EOL><INDENT>errors += <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>logging.error(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>", filename, self.name)<EOL>sys.exit(<NUM_LIT:2>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>uid = card.get_uid()<EOL>if not uid:<EOL><INDENT>logging.warning("<STR_LIT>"<EOL>"<STR_LIT>", card,<EOL>self.name)<EOL><DEDENT>elif uid in self.contacts:<EOL><INDENT>logging.warning(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>", card,<EOL>self.contacts[uid], self.name)<EOL><DEDENT>else:<EOL><INDENT>self.contacts[uid] = card<EOL><DEDENT><DEDENT><DEDENT>self._loaded = True<EOL>if errors:<EOL><INDENT>logging.warning(<EOL>"<STR_LIT>",<EOL>errors, len(self.contacts) + errors, self)<EOL><DEDENT>logging.debug('<STR_LIT>',<EOL>len(self.contacts), self.name)<EOL>

Load all vcard files in this address book from disk.

        If a search string is given only files which contents match that will
        be loaded.

        :param query: a regular expression to limit the results
        :type query: str
        :param search_in_source_files: apply search regexp directly on the .vcf files to speed up parsing (less accurate)
        :type search_in_source_files: bool
        :returns: the number of successfully loaded cards and the number of
            errors
        :rtype: int, int
        :throws: AddressBookParseError


def __init__(self, name, abooks, **kwargs):

super().__init__(name, **kwargs)<EOL>self._abooks = abooks<EOL>

:param name: the name to identify the address book
:type name: str
:param abooks: a list of address books to combine in this collection
:type abooks: list(AddressBook)
:param **kwargs: further arguments for the parent constructor


for abook in self._abooks:<EOL><INDENT>if abook.name == name:<EOL><INDENT>return abook<EOL><DEDENT><DEDENT>

Get one of the backing abdress books by its name,

        :param name: the name of the address book to get
        :type name: str
        :returns: the matching address book or None
        :rtype: AddressBook or NoneType


if isinstance(input, list):<EOL><INDENT>return delimiter.join(<EOL>list_to_string(item, delimiter) for item in input)<EOL><DEDENT>return input<EOL>

converts list to string recursively so that nested lists are supported

    :param input: a list of strings and lists of strings (and so on recursive)
    :type input: list
    :param delimiter: the deimiter to use when joining the items
    :type delimiter: str
    :returns: the recursively joined list
    :rtype: str


<EOL>for format_string in ("<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>"):<EOL><INDENT>try:<EOL><INDENT>return datetime.strptime(input, format_string)<EOL><DEDENT>except ValueError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>for format_string in ("<STR_LIT>", "<STR_LIT>"):<EOL><INDENT>try:<EOL><INDENT>return datetime.strptime('<STR_LIT>'.join(input.rsplit("<STR_LIT::>", <NUM_LIT:1>)),<EOL>format_string)<EOL><DEDENT>except ValueError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>raise ValueError<EOL>

Convert string to date object.

    :param input: the date string to parse
    :type input: str
    :returns: the parsed datetime object
    :rtype: datetime.datetime


def convert_to_yaml(<EOL>name, value, indentation, indexOfColon, show_multi_line_character):

strings = []<EOL>if isinstance(value, list):<EOL><INDENT>if len(value) == <NUM_LIT:1>and isinstance(value[<NUM_LIT:0>], str):<EOL><INDENT>value = value[<NUM_LIT:0>]<EOL><DEDENT>elif len(value) == <NUM_LIT:1>and isinstance(value[<NUM_LIT:0>], list)and len(value[<NUM_LIT:0>]) == <NUM_LIT:1>and isinstance(value[<NUM_LIT:0>][<NUM_LIT:0>], str):<EOL><INDENT>value = value[<NUM_LIT:0>][<NUM_LIT:0>]<EOL><DEDENT><DEDENT>if isinstance(value, str):<EOL><INDENT>strings.append("<STR_LIT>" % (<EOL>'<STR_LIT:U+0020>' * indentation, name, '<STR_LIT:U+0020>' * (indexOfColon-len(name)),<EOL>indent_multiline_string(value, indentation+<NUM_LIT:4>,<EOL>show_multi_line_character)))<EOL><DEDENT>elif isinstance(value, list):<EOL><INDENT>strings.append("<STR_LIT>" % (<EOL>'<STR_LIT:U+0020>' * indentation, name, '<STR_LIT:U+0020>' * (indexOfColon-len(name))))<EOL>for outer in value:<EOL><INDENT>if isinstance(outer, list)and len(outer) == <NUM_LIT:1>and isinstance(outer[<NUM_LIT:0>], str):<EOL><INDENT>outer = outer[<NUM_LIT:0>]<EOL><DEDENT>if isinstance(outer, str):<EOL><INDENT>strings.append("<STR_LIT>" % (<EOL>'<STR_LIT:U+0020>' * (indentation+<NUM_LIT:4>), indent_multiline_string(<EOL>outer, indentation+<NUM_LIT:8>, show_multi_line_character)))<EOL><DEDENT>elif isinstance(outer, list):<EOL><INDENT>strings.append("<STR_LIT>" % ('<STR_LIT:U+0020>' * (indentation+<NUM_LIT:4>)))<EOL>for inner in outer:<EOL><INDENT>if isinstance(inner, str):<EOL><INDENT>strings.append("<STR_LIT>" % (<EOL>'<STR_LIT:U+0020>' * (indentation+<NUM_LIT:8>), indent_multiline_string(<EOL>inner, indentation+<NUM_LIT:12>,<EOL>show_multi_line_character)))<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>return strings<EOL>

converts a value list into yaml syntax
    :param name: name of object (example: phone)
    :type name: str
    :param value: object contents
    :type value: str, list(str), list(list(str))
    :param indentation: indent all by number of spaces
    :type indentation: int
    :param indexOfColon: use to position : at the name string (-1 for no space)
    :type indexOfColon: int
    :param show_multi_line_character: option to hide "|"
    :type show_multi_line_character: boolean
    :returns: yaml formatted string array of name, value pair
    :rtype: list(str)


def convert_to_vcard(name, value, allowed_object_type):

if isinstance(value, str):<EOL><INDENT>if allowed_object_type == ObjectType.list_with_strings:<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>" + name + "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>return value.strip()<EOL><DEDENT><DEDENT>elif isinstance(value, list):<EOL><INDENT>if allowed_object_type == ObjectType.string:<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>" + name + "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>for entry in value:<EOL><INDENT>if not isinstance(entry, str):<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>" + name + "<STR_LIT>")<EOL><DEDENT><DEDENT>return [x.strip() for x in value if x]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if allowed_object_type == ObjectType.string:<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>" + name + "<STR_LIT>")<EOL><DEDENT>elif allowed_object_type == ObjectType.list_with_strings:<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>" + name + "<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>" + name + "<STR_LIT>")<EOL><DEDENT><DEDENT>

converts user input into vcard compatible data structures
    :param name: object name, only required for error messages
    :type name: str
    :param value: user input
    :type value: str or list(str)
    :param allowed_object_type: set the accepted return type for vcard
        attribute
    :type allowed_object_type: enum of type ObjectType
    :returns: cleaned user input, ready for vcard or a ValueError
    :rtype: str or list(str)


for action, alias_list in cls.action_map.items():<EOL><INDENT>if alias in alias_list:<EOL><INDENT>return action<EOL><DEDENT><DEDENT>return None<EOL>

Find the name of the action for the supplied alias.  If no action is
        asociated with the given alias, None is returned.

        :param alias: the alias to look up
        :type alias: str
        :rturns: the name of the corresponding action or None
        :rtype: str or NoneType


return cls.action_map.get(action)<EOL>

Find all aliases for the given action.  If there is no such action,
        None is returned.

        :param action: the action name to look up
        :type action: str
        :returns: the list of aliases corresponding to the action or None
        :rtype: list(str) or NoneType


return cls.action_map.keys()<EOL>

Find the names of all defined actions.

        :returns: all action names
        :rtype: iterable(str)


for key, value in cls.action_map.items():<EOL><INDENT>yield key<EOL>yield from value<EOL><DEDENT>

Find the names of all defined actions and their aliases.

        :returns: the names of all actions and aliases
        :rtype: generator(str)


<EOL>no_pickle_keys = self.invalid_dict_pickle_keys(msg_dict)<EOL>if no_pickle_keys == []:<EOL><INDENT>self.r_q.put(msg_dict)<EOL><DEDENT>else:<EOL><INDENT>hash_func = md5()<EOL>hash_func.update(str(msg_dict))<EOL>dict_hash = str(hash_func.hexdigest())[-<NUM_LIT:7>:]  <EOL>linesep = os.linesep<EOL>sys.stderr.write(<EOL>"<STR_LIT>".format(<EOL>datetime.now(),<EOL>Style.BRIGHT,<EOL>dict_hash,<EOL>Style.RESET_ALL,<EOL>Fore.MAGENTA,<EOL>msg_dict,<EOL>Style.RESET_ALL,<EOL>linesep,<EOL>)<EOL>)<EOL>err_frag1 = (<EOL>Style.BRIGHT<EOL>+ "<STR_LIT>".format(dict_hash)<EOL>+ Style.RESET_ALL<EOL>)<EOL>err_frag2 = Fore.YELLOW + "<STR_LIT>".format(no_pickle_keys) + Style.RESET_ALL<EOL>err_frag3 = "<STR_LIT>".format(linesep)<EOL>sys.stderr.write(err_frag1 + err_frag2 + err_frag3)<EOL>for key in sorted(no_pickle_keys):<EOL><INDENT>sys.stderr.write(<EOL>"<STR_LIT>".format(<EOL>key,<EOL>Fore.MAGENTA,<EOL>repr(msg_dict.get(key)),<EOL>Style.RESET_ALL,<EOL>linesep,<EOL>)<EOL>)<EOL>if isinstance(msg_dict.get(key), object):<EOL><INDENT>thisobj = msg_dict.get(key)<EOL>no_pickle_attrs = self.invalid_obj_pickle_attrs(thisobj)<EOL>err_frag1 = (<EOL>Style.BRIGHT<EOL>+ "<STR_LIT>".format(dict_hash)<EOL>+ Style.RESET_ALL<EOL>)<EOL>err_frag2 = (<EOL>Fore.YELLOW + "<STR_LIT>".format(no_pickle_attrs) + Style.RESET_ALL<EOL>)<EOL>err_frag3 = "<STR_LIT>".format(linesep)<EOL>sys.stderr.write(err_frag1 + err_frag2 + err_frag3)<EOL>for attr in no_pickle_attrs:<EOL><INDENT>sys.stderr.write(<EOL>"<STR_LIT>".format(<EOL>key,<EOL>attr,<EOL>Fore.RED,<EOL>repr(getattr(thisobj, attr)),<EOL>Style.RESET_ALL,<EOL>linesep,<EOL>)<EOL>)<EOL><DEDENT><DEDENT><DEDENT>sys.stderr.write(<EOL>"<STR_LIT>".format(<EOL>Style.BRIGHT, dict_hash, Style.RESET_ALL, linesep<EOL>)<EOL>)<EOL>for key in sorted(set(msg_dict.keys()).difference(no_pickle_keys)):<EOL><INDENT>sys.stderr.write(<EOL>"<STR_LIT>".format(<EOL>key,<EOL>Fore.GREEN,<EOL>repr(msg_dict.get(key)),<EOL>Style.RESET_ALL,<EOL>linesep,<EOL>)<EOL>)<EOL><DEDENT><DEDENT>

Send message dicts through r_q, and throw explicit errors for
        pickle problems


no_pickle_keys = list()<EOL>for key, val in msg_dict.items():<EOL><INDENT>try:<EOL><INDENT>pickle.dumps(key)<EOL>pickle.dumps(val)<EOL><DEDENT>except TypeError:<EOL><INDENT>no_pickle_keys.append(key)  <EOL><DEDENT>except pickle.PicklingError:<EOL><INDENT>no_pickle_keys.append(key)  <EOL><DEDENT>except pickle.UnpickleableError:<EOL><INDENT>no_pickle_keys.append(key)  <EOL><DEDENT><DEDENT>return no_pickle_keys<EOL>

Return a list of keys that can't be pickled.  Return [] if
        there are no pickling problems with the values associated with the
        keys.  Return the list of keys, if there are problems.