def _get_existing_instance(self, query, value):
        """Retrieve the related object from an existing instance in the DB.

        :param query: A SQLAlchemy `Query <sqlalchemy.orm.query.Query>` object.
        :param value: The serialized value to mapto an existing instance.
        :raises NoResultFound: if there is no matching record.
        """
        if self.columns:
            result = query.filter_by(
                **{prop.key: value.get(prop.key) for prop in self.related_keys}
            ).one()
        else:
            # Use a faster path if the related key is the primary key.
            result = query.get([value.get(prop.key) for prop in self.related_keys])
            if result is None:
                raise NoResultFound
        return result

Retrieve the related object from an existing instance in the DB .


def get_declared_fields(mcs, klass, cls_fields, inherited_fields, dict_cls):
        """Updates declared fields with fields converted from the SQLAlchemy model
        passed as the `model` class Meta option.
        """
        opts = klass.opts
        Converter = opts.model_converter
        converter = Converter(schema_cls=klass)
        declared_fields = super(SchemaMeta, mcs).get_declared_fields(
            klass, cls_fields, inherited_fields, dict_cls
        )
        fields = mcs.get_fields(converter, opts, declared_fields, dict_cls)
        fields.update(declared_fields)
        return fields

def get_declared_fields ( mcs , klass , cls_fields , inherited_fields , dict_cls ) : opts = klass . opts Converter = opts . model_converter converter = Converter ( schema_cls = klass ) declared_fields = super ( SchemaMeta , mcs ) . get_declared_fields ( klass , cls_fields , inherited_fields , dict_cls ) fields = mcs . get_fields ( converter , opts , declared_fields , dict_cls ) fields . update ( declared_fields ) return fields

Updates declared fields with fields converted from the SQLAlchemy model passed as the model class Meta option .


def load(self, data, session=None, instance=None, transient=False, *args, **kwargs):
        """Deserialize data to internal representation.

        :param session: Optional SQLAlchemy session.
        :param instance: Optional existing instance to modify.
        :param transient: Optional switch to allow transient instantiation.
        """
        self._session = session or self._session
        self._transient = transient or self._transient
        if not (self.transient or self.session):
            raise ValueError("Deserialization requires a session")
        self.instance = instance or self.instance
        try:
            return super(ModelSchema, self).load(data, *args, **kwargs)
        finally:
            self.instance = None

def
load
(
self
,
data
,
session
=
,
instance
=
,
transient
=
False
,
*
args
,
*
*
kwargs
)
:
self
.
_session
=
session
or
self
.
_session
self
.
_transient
=
transient
or
self
.
_transient
if
not
(
self
.
transient
or
self
.
session
)
:
raise
ValueError
(
"Deserialization requires a session"
)
self
.
instance
=
instance
or
self
.
instance
try
:
return
super
(
ModelSchema
,
self
)
.
load
(
data
,
*
args
,
*
*
kwargs
)
finally
:
self
.
instance
=

Deserialize data to internal representation .


def _split_model_kwargs_association(self, data):
        """Split serialized attrs to ensure association proxies are passed separately.

        This is necessary for Python < 3.6.0, as the order in which kwargs are passed
        is non-deterministic, and associations must be parsed by sqlalchemy after their
        intermediate relationship, unless their `creator` has been set.

        Ignore invalid keys at this point - behaviour for unknowns should be
        handled elsewhere.

        :param data: serialized dictionary of attrs to split on association_proxy.
        """
        association_attrs = {
            key: value
            for key, value in iteritems(data)
            # association proxy
            if hasattr(getattr(self.opts.model, key, None), "remote_attr")
        }
        kwargs = {
            key: value
            for key, value in iteritems(data)
            if (hasattr(self.opts.model, key) and key not in association_attrs)
        }
        return kwargs, association_attrs

def
_split_model_kwargs_association
(
self
,
data
)
:
association_attrs
=
{
key
:
value
for
key
,
value
in
iteritems
(
data
)
# association proxy
if
hasattr
(
getattr
(
self
.
opts
.
model
,
key
,
)
,
"remote_attr"
)
}
kwargs
=
{
key
:
value
for
key
,
value
in
iteritems
(
data
)
if
(
hasattr
(
self
.
opts
.
model
,
key
)
and
key
not
in
association_attrs
)
}
return
kwargs
,
association_attrs

Split serialized attrs to ensure association proxies are passed separately .


def gc():
    """Deletes old stellar tables that are not used anymore"""
    def after_delete(database):
        click.echo("Deleted table %s" % database)

    app = get_app()
    upgrade_from_old_version(app)
    app.delete_orphan_snapshots(after_delete)

def
gc
(
)
:
def
after_delete
(
database
)
:
click
.
echo
(
"Deleted table %s"
%
database
)
app
=
get_app
(
)
upgrade_from_old_version
(
app
)
app
.
delete_orphan_snapshots
(
after_delete
)


def snapshot(name):
    """Takes a snapshot of the database"""
    app = get_app()
    upgrade_from_old_version(app)
    name = name or app.default_snapshot_name

    if app.get_snapshot(name):
        click.echo("Snapshot with name %s already exists" % name)
        sys.exit(1)
    else:
        def before_copy(table_name):
            click.echo("Snapshotting database %s" % table_name)
        app.create_snapshot(name, before_copy=before_copy)

def
snapshot
(
name
)
:
app
=
get_app
(
)
upgrade_from_old_version
(
app
)
name
=
name
or
app
.
default_snapshot_name
if
app
.
get_snapshot
(
name
)
:
click
.
echo
(
"Snapshot with name %s already exists"
%
name
)
sys
.
exit
(
1
)
else
:
def
before_copy
(
table_name
)
:
click
.
echo
(
"Snapshotting database %s"
%
table_name
)
app
.
create_snapshot
(
name
,
before_copy
=
before_copy
)


def list():
    """Returns a list of snapshots"""
    snapshots = get_app().get_snapshots()

    click.echo('\n'.join(
        '%s: %s' % (
            s.snapshot_name,
            humanize.naturaltime(datetime.utcnow() - s.created_at)
        )
        for s in snapshots
    ))

def
list
(
)
:
snapshots
=
get_app
(
)
.
get_snapshots
(
)
click
.
echo
(
'\n'
.
join
(
'%s: %s'
%
(
s
.
snapshot_name
,
humanize
.
naturaltime
(
datetime
.
utcnow
(
)
s
.
created_at
)
)
for
s
in
snapshots
)
)


def restore(name):
    """Restores the database from a snapshot"""
    app = get_app()

    if not name:
        snapshot = app.get_latest_snapshot()
        if not snapshot:
            click.echo(
                "Couldn't find any snapshots for project %s" %
                load_config()['project_name']
            )
            sys.exit(1)
    else:
        snapshot = app.get_snapshot(name)
        if not snapshot:
            click.echo(
                "Couldn't find snapshot with name %s.\n"
                "You can list snapshots with 'stellar list'" % name
            )
            sys.exit(1)

    # Check if slaves are ready
    if not snapshot.slaves_ready:
        if app.is_copy_process_running(snapshot):
            sys.stdout.write(
                'Waiting for background process(%s) to finish' %
                snapshot.worker_pid
            )
            sys.stdout.flush()
            while not snapshot.slaves_ready:
                sys.stdout.write('.')
                sys.stdout.flush()
                sleep(1)
                app.db.session.refresh(snapshot)
            click.echo('')
        else:
            click.echo('Background process missing, doing slow restore.')
            app.inline_slave_copy(snapshot)

    app.restore(snapshot)
    click.echo('Restore complete.')


def remove(name):
    """Removes a snapshot"""
    app = get_app()

    snapshot = app.get_snapshot(name)
    if not snapshot:
        click.echo("Couldn't find snapshot %s" % name)
        sys.exit(1)

    click.echo("Deleting snapshot %s" % name)
    app.remove_snapshot(snapshot)
    click.echo("Deleted")

def
remove
(
name
)
:
app
=
get_app
(
)
snapshot
=
app
.
get_snapshot
(
name
)
if
not
snapshot
:
click
.
echo
(
"Couldn't find snapshot %s"
%
name
)
sys
.
exit
(
1
)
click
.
echo
(
"Deleting snapshot %s"
%
name
)
app
.
remove_snapshot
(
snapshot
)
click
.
echo
(
"Deleted"
)


def rename(old_name, new_name):
    """Renames a snapshot"""
    app = get_app()

    snapshot = app.get_snapshot(old_name)
    if not snapshot:
        click.echo("Couldn't find snapshot %s" % old_name)
        sys.exit(1)

    new_snapshot = app.get_snapshot(new_name)
    if new_snapshot:
        click.echo("Snapshot with name %s already exists" % new_name)
        sys.exit(1)

    app.rename_snapshot(snapshot, new_name)
    click.echo("Renamed snapshot %s to %s" % (old_name, new_name))

def
rename
(
old_name
,
new_name
)
:
app
=
get_app
(
)
snapshot
=
app
.
get_snapshot
(
old_name
)
if
not
snapshot
:
click
.
echo
(
"Couldn't find snapshot %s"
%
old_name
)
sys
.
exit
(
1
)
new_snapshot
=
app
.
get_snapshot
(
new_name
)
if
new_snapshot
:
click
.
echo
(
"Snapshot with name %s already exists"
%
new_name
)
sys
.
exit
(
1
)
app
.
rename_snapshot
(
snapshot
,
new_name
)
click
.
echo
(
"Renamed snapshot %s to %s"
%
(
old_name
,
new_name
)
)


def replace(name):
    """Replaces a snapshot"""
    app = get_app()

    snapshot = app.get_snapshot(name)
    if not snapshot:
        click.echo("Couldn't find snapshot %s" % name)
        sys.exit(1)

    app.remove_snapshot(snapshot)
    app.create_snapshot(name)
    click.echo("Replaced snapshot %s" % name)

def
replace
(
name
)
:
app
=
get_app
(
)
snapshot
=
app
.
get_snapshot
(
name
)
if
not
snapshot
:
click
.
echo
(
"Couldn't find snapshot %s"
%
name
)
sys
.
exit
(
1
)
app
.
remove_snapshot
(
snapshot
)
app
.
create_snapshot
(
name
)
click
.
echo
(
"Replaced snapshot %s"
%
name
)


def on_epoch_end(self) -> None:
        'Updates indexes after each epoch for shuffling'
        self.indexes = np.arange(self.nrows)
        if self.shuffle:
            np.random.shuffle(self.indexes)

def on_epoch_end ( self ) -> None : self . indexes = np . arange ( self . nrows ) if self . shuffle : np . random . shuffle ( self . indexes )


def textacy_cleaner(text: str) -> str:
    """
    Defines the default function for cleaning text.

    This function operates over a list.
    """
    return preprocess_text(text,
                           fix_unicode=True,
                           lowercase=True,
                           transliterate=True,
                           no_urls=True,
                           no_emails=True,
                           no_phone_numbers=True,
                           no_numbers=True,
                           no_currency_symbols=True,
                           no_punct=True,
                           no_contractions=False,
                           no_accents=True)

def textacy_cleaner ( text : str ) -> str : return preprocess_text ( text , fix_unicode = True , lowercase = True , transliterate = True , no_urls = True , no_emails = True , no_phone_numbers = True , no_numbers = True , no_currency_symbols = True , no_punct = True , no_contractions = False , no_accents = True )

Defines the default function for cleaning text .


def apply_parallel(func: Callable,
                   data: List[Any],
                   cpu_cores: int = None) -> List[Any]:
    """
    Apply function to list of elements.

    Automatically determines the chunk size.
    """
    if not cpu_cores:
        cpu_cores = cpu_count()

    try:
        chunk_size = ceil(len(data) / cpu_cores)
        pool = Pool(cpu_cores)
        transformed_data = pool.map(func, chunked(data, chunk_size), chunksize=1)
    finally:
        pool.close()
        pool.join()
        return transformed_data

def apply_parallel ( func : Callable , data : List [ Any ] , cpu_cores : int = None ) -> List [ Any ] : if not cpu_cores : cpu_cores = cpu_count ( ) try : chunk_size = ceil ( len ( data ) / cpu_cores ) pool = Pool ( cpu_cores ) transformed_data = pool . map ( func , chunked ( data , chunk_size ) , chunksize = 1 ) finally : pool . close ( ) pool . join ( ) return transformed_data


def process_text_constructor(cleaner: Callable,
                             tokenizer: Callable,
                             append_indicators: bool,
                             start_tok: str,
                             end_tok: str):
    """Generate a function that will clean and tokenize text."""
    def process_text(text):
        if append_indicators:
            return [[start_tok] + tokenizer(cleaner(doc)) + [end_tok] for doc in text]
        return [tokenizer(cleaner(doc)) for doc in text]

    return process_text

def process_text_constructor ( cleaner : Callable , tokenizer : Callable , append_indicators : bool , start_tok : str , end_tok : str ) : def process_text ( text ) : if append_indicators : return [ [ start_tok ] + tokenizer ( cleaner ( doc ) ) + [ end_tok ] for doc in text ] return [ tokenizer ( cleaner ( doc ) ) for doc in text ] return process_text

Generate a function that will clean and tokenize text .


def process_text(self, text: List[str]) -> List[List[str]]:
        """Combine the cleaner and tokenizer."""
        process_text = process_text_constructor(cleaner=self.cleaner,
                                                tokenizer=self.tokenizer,
                                                append_indicators=self.append_indicators,
                                                start_tok=self.start_tok,
                                                end_tok=self.end_tok)
        return process_text(text)

def process_text ( self , text : List [ str ] ) -> List [ List [ str ] ] : process_text = process_text_constructor ( cleaner = self . cleaner , tokenizer = self . tokenizer , append_indicators = self . append_indicators , start_tok = self . start_tok , end_tok = self . end_tok ) return process_text ( text )


def parallel_process_text(self, data: List[str]) -> List[List[str]]:
        """Apply cleaner -> tokenizer."""
        process_text = process_text_constructor(cleaner=self.cleaner,
                                                tokenizer=self.tokenizer,
                                                append_indicators=self.append_indicators,
                                                start_tok=self.start_tok,
                                                end_tok=self.end_tok)
        n_cores = self.num_cores
        return flattenlist(apply_parallel(process_text, data, n_cores))

def parallel_process_text ( self , data : List [ str ] ) -> List [ List [ str ] ] : process_text = process_text_constructor ( cleaner = self . cleaner , tokenizer = self . tokenizer , append_indicators = self . append_indicators , start_tok = self . start_tok , end_tok = self . end_tok ) n_cores = self . num_cores return flattenlist ( apply_parallel ( process_text , data , n_cores ) )


def generate_doc_length_stats(self):
        """Analyze document length statistics for padding strategy"""
        heuristic = self.heuristic_pct
        histdf = (pd.DataFrame([(a, b) for a, b in self.document_length_histogram.items()],
                               columns=['bin', 'doc_count'])
                  .sort_values(by='bin'))
        histdf['cumsum_pct'] = histdf.doc_count.cumsum() / histdf.doc_count.sum()

        self.document_length_stats = histdf
        self.doc_length_huerestic = histdf.query(f'cumsum_pct >= {heuristic}').bin.head(1).values[0]
        logging.warning(' '.join(["Setting maximum document length to",
                                  f'{self.doc_length_huerestic} based upon',
                                  f'heuristic of {heuristic} percentile.\n',
                                  'See full histogram by insepecting the',
                                  "`document_length_stats` attribute."]))
        self.padding_maxlen = self.doc_length_huerestic


def token_count_pandas(self):
        """ See token counts as pandas dataframe"""
        freq_df = pd.DataFrame.from_dict(self.indexer.word_counts, orient='index')
        freq_df.columns = ['count']
        return freq_df.sort_values('count', ascending=False)

def token_count_pandas ( self ) : freq_df = pd . DataFrame . from_dict ( self . indexer . word_counts , orient = 'index' ) freq_df . columns = [ 'count' ] return freq_df . sort_values ( 'count' , ascending = False )


def map_param_type(param_type):
    """
    Perform param type mapping
    This requires a bit of logic since this isn't standardized.
    If a type doesn't map, assume str
    """
    main_type, sub_type = TYPE_INFO_RE.match(param_type).groups()

    if main_type in ('list', 'array'):
        # Handle no sub-type: "required list"
        if sub_type is not None:
            sub_type = sub_type.strip()

        if not sub_type:
            sub_type = 'str'

        # Handle list of pairs: "optional list<pair<callsign, path>>"
        sub_match = TYPE_INFO_RE.match(sub_type)
        if sub_match:
            sub_type = sub_match.group(1).lower()

        return [PARAM_TYPE_MAP.setdefault(sub_type, string_types)]

    return PARAM_TYPE_MAP.setdefault(main_type, string_types)

Perform param type mapping This requires a bit of logic since this isn t standardized . If a type doesn t map assume str


def parse_interfaces(interfaces):
    """
    Parse the conduit.query json dict response
    This performs the logic of parsing the non-standard params dict
        and then returning a dict Resource can understand
    """
    parsed_interfaces = collections.defaultdict(dict)

    for m, d in iteritems(interfaces):
        app, func = m.split('.', 1)

        method = parsed_interfaces[app][func] = {}

        # Make default assumptions since these aren't provided by Phab
        method['formats'] = ['json', 'human']
        method['method'] = 'POST'

        method['optional'] = {}
        method['required'] = {}

        for name, type_info in iteritems(dict(d['params'])):
            # Set the defaults
            optionality = 'required'
            param_type = 'string'

            # Usually in the format: <optionality> <param_type>
            type_info = TYPE_INFO_COMMENT_RE.sub('', type_info)
            info_pieces = TYPE_INFO_SPLITTER_RE.findall(type_info)
            for info_piece in info_pieces:
                if info_piece in ('optional', 'required'):
                    optionality = info_piece
                elif info_piece == 'ignored':
                    optionality = 'optional'
                    param_type = 'string'
                elif info_piece == 'nonempty':
                    optionality = 'required'
                elif info_piece == 'deprecated':
                    optionality = 'optional'
                else:
                    param_type = info_piece

            method[optionality][name] = map_param_type(param_type)

    return dict(parsed_interfaces)

Parse the conduit . query json dict response This performs the logic of parsing the non - standard params dict and then returning a dict Resource can understand


def inverse(self):
        """The inverse of this bidict.

        *See also* :attr:`inv`
        """
        # Resolve and return a strong reference to the inverse bidict.
        # One may be stored in self._inv already.
        if self._inv is not None:
            return self._inv
        # Otherwise a weakref is stored in self._invweak. Try to get a strong ref from it.
        inv = self._invweak()
        if inv is not None:
            return inv
        # Refcount of referent must have dropped to zero, as in `bidict().inv.inv`. Init a new one.
        self._init_inv()  # Now this bidict will retain a strong ref to its inverse.
        return self._inv


def _update_with_rollback(self, on_dup, *args, **kw):
        """Update, rolling back on failure."""
        writelog = []
        appendlog = writelog.append
        dedup_item = self._dedup_item
        write_item = self._write_item
        for (key, val) in _iteritems_args_kw(*args, **kw):
            try:
                dedup_result = dedup_item(key, val, on_dup)
            except DuplicationError:
                undo_write = self._undo_write
                for dedup_result, write_result in reversed(writelog):
                    undo_write(dedup_result, write_result)
                raise
            if dedup_result is not _NOOP:
                write_result = write_item(key, val, dedup_result)
                appendlog((dedup_result, write_result))

def _update_with_rollback ( self , on_dup , * args , * * kw ) : writelog = [ ] appendlog = writelog . append dedup_item = self . _dedup_item write_item = self . _write_item for ( key , val ) in _iteritems_args_kw ( * args , * * kw ) : try : dedup_result = dedup_item ( key , val , on_dup ) except DuplicationError : undo_write = self . _undo_write for dedup_result , write_result in reversed ( writelog ) : undo_write ( dedup_result , write_result ) raise if dedup_result is not _NOOP : write_result = write_item ( key , val , dedup_result ) appendlog ( ( dedup_result , write_result ) )


def copy(self):
        """A shallow copy."""
        # Could just ``return self.__class__(self)`` here instead, but the below is faster. It uses
        # __new__ to create a copy instance while bypassing its __init__, which would result
        # in copying this bidict's items into the copy instance one at a time. Instead, make whole
        # copies of each of the backing mappings, and make them the backing mappings of the copy,
        # avoiding copying items one at a time.
        copy = self.__class__.__new__(self.__class__)
        copy._fwdm = self._fwdm.copy()  # pylint: disable=protected-access
        copy._invm = self._invm.copy()  # pylint: disable=protected-access
        copy._init_inv()  # pylint: disable=protected-access
        return copy


def copy(self):
        """A shallow copy of this ordered bidict."""
        # Fast copy implementation bypassing __init__. See comments in :meth:`BidictBase.copy`.
        copy = self.__class__.__new__(self.__class__)
        sntl = _Sentinel()
        fwdm = self._fwdm.copy()
        invm = self._invm.copy()
        cur = sntl
        nxt = sntl.nxt
        for (key, val) in iteritems(self):
            nxt = _Node(cur, sntl)
            cur.nxt = fwdm[key] = invm[val] = nxt
            cur = nxt
        sntl.prv = nxt
        copy._sntl = sntl  # pylint: disable=protected-access
        copy._fwdm = fwdm  # pylint: disable=protected-access
        copy._invm = invm  # pylint: disable=protected-access
        copy._init_inv()  # pylint: disable=protected-access
        return copy


def equals_order_sensitive(self, other):
        """Order-sensitive equality check.

        *See also* :ref:`eq-order-insensitive`
        """
        # Same short-circuit as BidictBase.__eq__. Factoring out not worth function call overhead.
        if not isinstance(other, Mapping) or len(self) != len(other):
            return False
        return all(i == j for (i, j) in izip(iteritems(self), iteritems(other)))


def inverted(arg):
    """Yield the inverse items of the provided object.

    If *arg* has a :func:`callable` ``__inverted__`` attribute,
    return the result of calling it.

    Otherwise, return an iterator over the items in `arg`,
    inverting each item on the fly.

    *See also* :attr:`bidict.BidirectionalMapping.__inverted__`
    """
    inv = getattr(arg, '__inverted__', None)
    if callable(inv):
        return inv()
    return ((val, key) for (key, val) in _iteritems_mapping_or_iterable(arg))

def inverted ( arg ) : inv = getattr ( arg , '__inverted__' , None ) if callable ( inv ) : return inv ( ) return ( ( val , key ) for ( key , val ) in _iteritems_mapping_or_iterable ( arg ) )

Yield the inverse items of the provided object .


def clear(self):
        """Remove all items."""
        self._fwdm.clear()
        self._invm.clear()
        self._sntl.nxt = self._sntl.prv = self._sntl

def clear ( self ) : self . _fwdm . clear ( ) self . _invm . clear ( ) self . _sntl . nxt = self . _sntl . prv = self . _sntl


def move_to_end(self, key, last=True):
        """Move an existing key to the beginning or end of this ordered bidict.

        The item is moved to the end if *last* is True, else to the beginning.

        :raises KeyError: if the key does not exist
        """
        node = self._fwdm[key]
        node.prv.nxt = node.nxt
        node.nxt.prv = node.prv
        sntl = self._sntl
        if last:
            last = sntl.prv
            node.prv = last
            node.nxt = sntl
            sntl.prv = last.nxt = node
        else:
            first = sntl.nxt
            node.prv = sntl
            node.nxt = first
            sntl.nxt = first.prv = node

def move_to_end ( self , key , last = True ) : node = self . _fwdm [ key ] node . prv . nxt = node . nxt node . nxt . prv = node . prv sntl = self . _sntl if last : last = sntl . prv node . prv = last node . nxt = sntl sntl . prv = last . nxt = node else : first = sntl . nxt node . prv = sntl node . nxt = first sntl . nxt = first . prv = node

Move an existing key to the beginning or end of this ordered bidict .


def write_temp_file(text=""):
    """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

    """
    with NamedTemporaryFile(mode='w+t', suffix='.yml', delete=False) \
         as tempfile:
        tempfile.write(text)
        return tempfile.name

def write_temp_file ( text = "" ) : with NamedTemporaryFile ( mode = 'w+t' , suffix = '.yml' , delete = False ) as tempfile : tempfile . write ( text ) return tempfile . name

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


def get_contacts(address_books, query, method="all", reverse=False,
                 group=False, sort="first_name"):
    """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)

    """
    # Search for the contacts in all address books.
    contacts = []
    for address_book in address_books:
        contacts.extend(address_book.search(query, method=method))
    # Sort the contacts.
    if group:
        if sort == "first_name":
            return sorted(contacts, reverse=reverse, key=lambda x: (
                unidecode(x.address_book.name).lower(),
                unidecode(x.get_first_name_last_name()).lower()))
        elif sort == "last_name":
            return sorted(contacts, reverse=reverse, key=lambda x: (
                unidecode(x.address_book.name).lower(),
                unidecode(x.get_last_name_first_name()).lower()))
        else:
            raise ValueError('sort must be "first_name" or "last_name" not '
                             '{}.'.format(sort))
    else:
        if sort == "first_name":
            return sorted(contacts, reverse=reverse, key=lambda x:
                          unidecode(x.get_first_name_last_name()).lower())
        elif sort == "last_name":
            return sorted(contacts, reverse=reverse, key=lambda x:
                          unidecode(x.get_last_name_first_name()).lower())
        else:
            raise ValueError('sort must be "first_name" or "last_name" not '
                             '{}.'.format(sort))

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


def merge_args_into_config(args, config):
    """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

    """
    # display by name: first or last name
    if "display" in args and args.display:
        config.set_display_by_name(args.display)
    # group by address book
    if "group_by_addressbook" in args and args.group_by_addressbook:
        config.set_group_by_addressbook(True)
    # reverse contact list
    if "reverse" in args and args.reverse:
        config.set_reverse(True)
    # sort criteria: first or last name
    if "sort" in args and args.sort:
        config.sort = args.sort
    # preferred vcard version
    if "vcard_version" in args and args.vcard_version:
        config.set_preferred_vcard_version(args.vcard_version)
    # search in source files
    if "search_in_source_files" in args and args.search_in_source_files:
        config.set_search_in_source_files(True)
    # skip unparsable vcards
    if "skip_unparsable" in args and args.skip_unparsable:
        config.set_skip_unparsable(True)
    # If the user could but did not specify address books on the command line
    # it means they want to use all address books in that place.
    if "addressbook" in args and not args.addressbook:
        args.addressbook = [abook.name for abook in config.abooks]
    if "target_addressbook" in args and not args.target_addressbook:
        args.target_addressbook = [abook.name for abook in config.abooks]

Merge the parsed arguments from argparse into the config object .


def load_address_books(names, config, search_queries):
    """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

    """
    all_names = {str(book) for book in config.abooks}
    if not names:
        names = all_names
    elif not all_names.issuperset(names):
        sys.exit('Error: The entered address books "{}" do not exist.\n'
                 'Possible values are: {}'.format(
                     '", "'.join(set(names) - all_names),
                     ', '.join(all_names)))
    # load address books which are defined in the configuration file
    for name in names:
        address_book = config.abook.get_abook(name)
        address_book.load(search_queries[address_book.name],
                search_in_source_files=config.search_in_source_files())
        yield address_book

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


def prepare_search_queries(args):
    """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)

    """
    # get all possible search queries for address book parsing
    source_queries = []
    target_queries = []
    if "source_search_terms" in args and args.source_search_terms:
        escaped_term = ".*".join(re.escape(x)
                                 for x in args.source_search_terms)
        source_queries.append(escaped_term)
        args.source_search_terms = escaped_term
    if "search_terms" in args and args.search_terms:
        escaped_term = ".*".join(re.escape(x) for x in args.search_terms)
        source_queries.append(escaped_term)
        args.search_terms = escaped_term
    if "target_contact" in args and args.target_contact:
        escaped_term = re.escape(args.target_contact)
        target_queries.append(escaped_term)
        args.target_contact = escaped_term
    if "uid" in args and args.uid:
        source_queries.append(args.uid)
    if "target_uid" in args and args.target_uid:
        target_queries.append(args.target_uid)
    # create and return regexp, None means that no query is given and hence all
    # contacts should be searched.
    source_queries = "^.*(%s).*$" % ')|('.join(source_queries) \
        if source_queries else None
    target_queries = "^.*(%s).*$" % ')|('.join(target_queries) \
        if target_queries else None
    logging.debug('Created source query regex: %s', source_queries)
    logging.debug('Created target query regex: %s', target_queries)
    # Get all possible search queries for address book parsing, always
    # depending on the fact if the address book is used to find source or
    # target contacts or both.
    queries = {abook.name: [] for abook in config.abook._abooks}
    for name in queries:
        if "addressbook" in args and name in args.addressbook:
            queries[name].append(source_queries)
        if "target_addressbook" in args and name in args.target_addressbook:
            queries[name].append(target_queries)
        # If None is included in the search queries of an address book it means
        # that either no source or target query was given and this address book
        # is affected by this.  All contacts should be loaded from that address
        # book.
        if None in queries[name]:
            queries[name] = None
        else:
            queries[name] = "({})".format(')|('.join(queries[name]))
    logging.debug('Created query regex: %s', queries)
    return queries

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


def new_subcommand(selected_address_books, input_from_stdin_or_file,
                   open_editor):
    """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

    """
    # ask for address book, in which to create the new contact
    selected_address_book = choose_address_book_from_list(
        "Select address book for new contact", selected_address_books)
    if selected_address_book is None:
        print("Error: address book list is empty")
        sys.exit(1)
    # if there is some data in stdin
    if input_from_stdin_or_file:
        # create new contact from stdin
        try:
            new_contact = CarddavObject.from_user_input(
                selected_address_book, input_from_stdin_or_file,
                config.get_supported_private_objects(),
                config.get_preferred_vcard_version(),
                config.localize_dates())
        except ValueError as err:
            print(err)
            sys.exit(1)
        else:
            new_contact.write_to_file()
        if open_editor:
            modify_existing_contact(new_contact)
        else:
            print("Creation successful\n\n%s" % new_contact.print_vcard())
    else:
        create_new_contact(selected_address_book)


def birthdays_subcommand(vcard_list, parsable):
    """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

    """
    # filter out contacts without a birthday date
    vcard_list = [
        vcard for vcard in vcard_list if vcard.get_birthday() is not None]
    # sort by date (month and day)
    # The sort function should work for strings and datetime objects.  All
    # strings will besorted before any datetime objects.
    vcard_list.sort(
        key=lambda x: (x.get_birthday().month, x.get_birthday().day)
        if isinstance(x.get_birthday(), datetime.datetime)
        else (0, 0, x.get_birthday()))
    # add to string list
    birthday_list = []
    for vcard in vcard_list:
        date = vcard.get_birthday()
        if parsable:
            if config.display_by_name() == "first_name":
                birthday_list.append("%04d.%02d.%02d\t%s"
                                     % (date.year, date.month, date.day,
                                        vcard.get_first_name_last_name()))
            else:
                birthday_list.append("%04d.%02d.%02d\t%s"
                                     % (date.year, date.month, date.day,
                                        vcard.get_last_name_first_name()))
        else:
            if config.display_by_name() == "first_name":
                birthday_list.append("%s\t%s"
                                     % (vcard.get_first_name_last_name(),
                                        vcard.get_formatted_birthday()))
            else:
                birthday_list.append("%s\t%s"
                                     % (vcard.get_last_name_first_name(),
                                        vcard.get_formatted_birthday()))
    if birthday_list:
        if parsable:
            print('\n'.join(birthday_list))
        else:
            list_birthdays(birthday_list)
    else:
        if not parsable:
            print("Found no birthdays")
        sys.exit(1)


def phone_subcommand(search_terms, vcard_list, parsable):
    """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

    """
    all_phone_numbers_list = []
    matching_phone_number_list = []
    for vcard in vcard_list:
        for type, number_list in sorted(vcard.get_phone_numbers().items(),
                                        key=lambda k: k[0].lower()):
            for number in sorted(number_list):
                if config.display_by_name() == "first_name":
                    name = vcard.get_first_name_last_name()
                else:
                    name = vcard.get_last_name_first_name()
                # create output lines
                line_formatted = "\t".join([name, type, number])
                line_parsable = "\t".join([number, name, type])
                if parsable:
                    # parsable option: start with phone number
                    phone_number_line = line_parsable
                else:
                    # else: start with name
                    phone_number_line = line_formatted
                if re.search(search_terms,
                             "%s\n%s" % (line_formatted, line_parsable),
                             re.IGNORECASE | re.DOTALL):
                    matching_phone_number_list.append(phone_number_line)
                elif len(re.sub("\D", "", search_terms)) >= 3:
                    # The user likely searches for a phone number cause the
                    # search string contains at least three digits.  So we
                    # remove all non-digit chars from the phone number field
                    # and match against that.
                    if re.search(re.sub("\D", "", search_terms),
                                 re.sub("\D", "", number), re.IGNORECASE):
                        matching_phone_number_list.append(phone_number_line)
                # collect all phone numbers in a different list as fallback
                all_phone_numbers_list.append(phone_number_line)
    if matching_phone_number_list:
        if parsable:
            print('\n'.join(matching_phone_number_list))
        else:
            list_phone_numbers(matching_phone_number_list)
    elif all_phone_numbers_list:
        if parsable:
            print('\n'.join(all_phone_numbers_list))
        else:
            list_phone_numbers(all_phone_numbers_list)
    else:
        if not parsable:
            print("Found no phone numbers")
        sys.exit(1)

Print a phone application friendly contact table .


def list_subcommand(vcard_list, parsable):
    """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

    """
    if not vcard_list:
        if not parsable:
            print("Found no contacts")
        sys.exit(1)
    elif parsable:
        contact_line_list = []
        for vcard in vcard_list:
            if config.display_by_name() == "first_name":
                name = vcard.get_first_name_last_name()
            else:
                name = vcard.get_last_name_first_name()
            contact_line_list.append('\t'.join([vcard.get_uid(), name,
                                                vcard.address_book.name]))
        print('\n'.join(contact_line_list))
    else:
        list_contacts(vcard_list)

def
list_subcommand
(
vcard_list
,
parsable
)
:
if
not
vcard_list
:
if
not
parsable
:
print
(
"Found no contacts"
)
sys
.
exit
(
1
)
elif
parsable
:
contact_line_list
=
[
]
for
vcard
in
vcard_list
:
if
config
.
display_by_name
(
)
==
"first_name"
:
name
=
vcard
.
get_first_name_last_name
(
)
else
:
name
=
vcard
.
get_last_name_first_name
(
)
contact_line_list
.
append
(
'\t'
.
join
(
[
vcard
.
get_uid
(
)
,
name
,
vcard
.
address_book
.
name
]
)
)
print
(
'\n'
.
join
(
contact_line_list
)
)
else
:
list_contacts
(
vcard_list
)


def modify_subcommand(selected_vcard, input_from_stdin_or_file, open_editor):
    """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

    """
    # show warning, if vcard version of selected contact is not 3.0 or 4.0
    if selected_vcard.get_version() not in config.supported_vcard_versions:
        print("Warning:\nThe selected contact is based on vcard version %s "
              "but khard only supports the creation and modification of vcards"
              " with version 3.0 and 4.0.\nIf you proceed, the contact will be"
              " converted to vcard version %s but beware: This could corrupt "
              "the contact file or cause data loss."
              % (selected_vcard.get_version(),
                 config.get_preferred_vcard_version()))
        while True:
            input_string = input("Do you want to proceed anyway (y/n)? ")
            if input_string.lower() in ["", "n", "q"]:
                print("Canceled")
                sys.exit(0)
            if input_string.lower() == "y":
                break
    # if there is some data in stdin
    if input_from_stdin_or_file:
        # create new contact from stdin
        try:
            new_contact = \
                CarddavObject.from_existing_contact_with_new_user_input(
                    selected_vcard, input_from_stdin_or_file,
                    config.localize_dates())
        except ValueError as err:
            print(err)
            sys.exit(1)
        if selected_vcard == new_contact:
            print("Nothing changed\n\n%s" % new_contact.print_vcard())
        else:
            print("Modification\n\n%s\n" % new_contact.print_vcard())
            while True:
                input_string = input("Do you want to proceed (y/n)? ")
                if input_string.lower() in ["", "n", "q"]:
                    print("Canceled")
                    break
                if input_string.lower() == "y":
                    new_contact.write_to_file(overwrite=True)
                    if open_editor:
                        modify_existing_contact(new_contact)
                    else:
                        print("Done")
                    break
    else:
        modify_existing_contact(selected_vcard)

Modify a contact in an external editor .


def remove_subcommand(selected_vcard, force):
    """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

    """
    if not force:
        while True:
            input_string = input(
                "Deleting contact %s from address book %s. Are you sure? "
                "(y/n): " % (selected_vcard, selected_vcard.address_book))
            if input_string.lower() in ["", "n", "q"]:
                print("Canceled")
                sys.exit(0)
            if input_string.lower() == "y":
                break
    selected_vcard.delete_vcard_file()
    print("Contact %s deleted successfully" % selected_vcard.get_full_name())


def source_subcommand(selected_vcard, editor):
    """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

    """
    child = subprocess.Popen([editor, selected_vcard.filename])
    child.communicate()

def source_subcommand ( selected_vcard , editor ) : child = subprocess . Popen ( [ editor , selected_vcard . filename ] ) child . communicate ( )

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


def merge_subcommand(vcard_list, selected_address_books, search_terms,
                     target_uid):
    """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

    """
    # Check arguments.
    if target_uid != "" and search_terms != "":
        print("You can not specify a target uid and target search terms for a "
              "merge.")
        sys.exit(1)
    # Find possible target contacts.
    if target_uid != "":
        target_vcards = get_contacts(selected_address_books, target_uid,
                                     method="uid")
        # We require that the uid given can uniquely identify a contact.
        if len(target_vcards) != 1:
            if not target_vcards:
                print("Found no contact for target uid %s" % target_uid)
            else:
                print("Found multiple contacts for target uid %s" % target_uid)
                for vcard in target_vcards:
                    print("    %s: %s" % (vcard, vcard.get_uid()))
            sys.exit(1)
    else:
        target_vcards = get_contact_list_by_user_selection(
            selected_address_books, search_terms, False)
    # get the source vcard, from which to merge
    source_vcard = choose_vcard_from_list("Select contact from which to merge",
                                          vcard_list)
    if source_vcard is None:
        print("Found no source contact for merging")
        sys.exit(1)
    else:
        print("Merge from %s from address book %s\n\n"
              % (source_vcard, source_vcard.address_book))
    # get the target vcard, into which to merge
    target_vcard = choose_vcard_from_list("Select contact into which to merge",
                                          target_vcards)
    if target_vcard is None:
        print("Found no target contact for merging")
        sys.exit(1)
    else:
        print("Merge into %s from address book %s\n\n"
              % (target_vcard, target_vcard.address_book))
    # merging
    if source_vcard == target_vcard:
        print("The selected contacts are already identical")
    else:
        merge_existing_contacts(source_vcard, target_vcard, True)


def copy_or_move_subcommand(action, vcard_list, target_address_book_list):
    """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

    """
    # get the source vcard, which to copy or move
    source_vcard = choose_vcard_from_list(
        "Select contact to %s" % action.title(), vcard_list)
    if source_vcard is None:
        print("Found no contact")
        sys.exit(1)
    else:
        print("%s contact %s from address book %s"
              % (action.title(), source_vcard, source_vcard.address_book))

    # get target address book
    if len(target_address_book_list) == 1 \
            and target_address_book_list[0] == source_vcard.address_book:
        print("The address book %s already contains the contact %s"
              % (target_address_book_list[0], source_vcard))
        sys.exit(1)
    else:
        available_address_books = [abook for abook in target_address_book_list
                                   if abook != source_vcard.address_book]
        selected_target_address_book = choose_address_book_from_list(
            "Select target address book", available_address_books)
        if selected_target_address_book is None:
            print("Error: address book list is empty")
            sys.exit(1)

    # check if a contact already exists in the target address book
    target_vcard = choose_vcard_from_list(
        "Select target contact which to overwrite",
        get_contact_list_by_user_selection([selected_target_address_book],
                                           source_vcard.get_full_name(), True))
    # If the target contact doesn't exist, move or copy the source contact into
    # the target address book without further questions.
    if target_vcard is None:
        copy_contact(source_vcard, selected_target_address_book,
                     action == "move")
    else:
        if source_vcard == target_vcard:
            # source and target contact are identical
            print("Target contact: %s" % target_vcard)
            if action == "move":
                copy_contact(source_vcard, selected_target_address_book, True)
            else:
                print("The selected contacts are already identical")
        else:
            # source and target contacts are different
            # either overwrite the target one or merge into target contact
            print("The address book %s already contains the contact %s\n\n"
                  "Source\n\n%s\n\nTarget\n\n%s\n\n"
                  "Possible actions:\n"
                  "  a: %s anyway\n"
                  "  m: Merge from source into target contact\n"
                  "  o: Overwrite target contact\n"
                  "  q: Quit" % (
                      target_vcard.address_book, source_vcard,
                      source_vcard.print_vcard(), target_vcard.print_vcard(),
                      "Move" if action == "move" else "Copy"))
            while True:
                input_string = input("Your choice: ")
                if input_string.lower() == "a":
                    copy_contact(source_vcard, selected_target_address_book,
                                 action == "move")
                    break
                if input_string.lower() == "o":
                    copy_contact(source_vcard, selected_target_address_book,
                                 action == "move")
                    target_vcard.delete_vcard_file()
                    break
                if input_string.lower() == "m":
                    merge_existing_contacts(source_vcard, target_vcard,
                                            action == "move")
                    break
                if input_string.lower() in ["", "q"]:
                    print("Canceled")
                    break

Copy or move a contact to a different address book .


def get_action(cls, alias):
        """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

        """
        for action, alias_list in cls.action_map.items():
            if alias in alias_list:
                return action
        return None

def get_action ( cls , alias ) : for action , alias_list in cls . action_map . items ( ) : if alias in alias_list : return action return None

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


def _convert_boolean_config_value(config, name, default=True):
        """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

        """
        if name not in config:
            config[name] = default
        elif config[name] == "yes":
            config[name] = True
        elif config[name] == "no":
            config[name] = False
        else:
            raise ValueError("Error in config file\nInvalid value for %s "
                             "parameter\nPossible values: yes, no" % name)


def new_contact(cls, address_book, supported_private_objects, version,
            localize_dates):
        """Use this to create a new and empty contact."""
        return cls(address_book, None, supported_private_objects, version,
                localize_dates)

def new_contact ( cls , address_book , supported_private_objects , version , localize_dates ) : return cls ( address_book , None , supported_private_objects , version , localize_dates )

Use this to create a new and empty contact .


def from_file(cls, address_book, filename, supported_private_objects,
            localize_dates):
        """
        Use this if you want to create a new contact from an existing .vcf
        file.
        """
        return cls(address_book, filename, supported_private_objects, None,
                localize_dates)

def from_file ( cls , address_book , filename , supported_private_objects , localize_dates ) : return cls ( address_book , filename , supported_private_objects , None , localize_dates )

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


def from_user_input(cls, address_book, user_input,
                        supported_private_objects, version, localize_dates):
        """Use this if you want to create a new contact from user input."""
        contact = cls(address_book, None, supported_private_objects, version,
                localize_dates)
        contact._process_user_input(user_input)
        return contact

def from_user_input ( cls , address_book , user_input , supported_private_objects , version , localize_dates ) : contact = cls ( address_book , None , supported_private_objects , version , localize_dates ) contact . _process_user_input ( user_input ) return contact

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


def from_existing_contact_with_new_user_input(cls, contact, user_input,
            localize_dates):
        """
        Use this if you want to clone an existing contact and  replace its data
        with new user input in one step.
        """
        contact = cls(contact.address_book, contact.filename,
                      contact.supported_private_objects, None, localize_dates)
        contact._process_user_input(user_input)
        return contact

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


def _get_names_part(self, part):
        """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)

        """
        try:
            the_list = getattr(self.vcard.n.value, part)
        except AttributeError:
            return []
        else:
            # check if list only contains empty strings
            if not ''.join(the_list):
                return []
        return the_list if isinstance(the_list, list) else [the_list]

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


def _add_category(self, categories):
        """ categories variable must be a list """
        categories_obj = self.vcard.add('categories')
        categories_obj.value = helpers.convert_to_vcard(
            "category", categories, ObjectType.list_with_strings)

def _add_category ( self , categories ) : categories_obj = self . vcard . add ( 'categories' ) categories_obj . value = helpers . convert_to_vcard ( "category" , categories , ObjectType . list_with_strings )


def _parse_type_value(types, value, supported_types):
        """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)

        """
        custom_types = []
        standard_types = []
        pref = 0
        for type in types:
            type = type.strip()
            if type:
                if type.lower() in supported_types:
                    standard_types.append(type)
                elif type.lower() == "pref":
                    pref += 1
                elif re.match(r"^pref=\d{1,2}$", type.lower()):
                    pref += int(type.split("=")[1])
                else:
                    if type.lower().startswith("x-"):
                        custom_types.append(type[2:])
                        standard_types.append(type)
                    else:
                        custom_types.append(type)
                        standard_types.append("X-{}".format(type))
        return (standard_types, custom_types, pref)

def _parse_type_value ( types , value , supported_types ) : custom_types = [ ] standard_types = [ ] pref = 0 for type in types : type = type . strip ( ) if type : if type . lower ( ) in supported_types : standard_types . append ( type ) elif type . lower ( ) == "pref" : pref += 1 elif re . match ( r"^pref=\d{1,2}$" , type . lower ( ) ) : pref += int ( type . split ( "=" ) [ 1 ] ) else : if type . lower ( ) . startswith ( "x-" ) : custom_types . append ( type [ 2 : ] ) standard_types . append ( type ) else : custom_types . append ( type ) standard_types . append ( "X-{}" . format ( type ) ) return ( standard_types , custom_types , pref )

Parse type value of phone numbers email and post addresses .


def list_to_string(input, delimiter):
    """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
    """
    if isinstance(input, list):
        return delimiter.join(
            list_to_string(item, delimiter) for item in input)
    return input

def list_to_string ( input , delimiter ) : if isinstance ( input , list ) : return delimiter . join ( list_to_string ( item , delimiter ) for item in input ) return input


def string_to_date(input):
    """Convert string to date object.

    :param input: the date string to parse
    :type input: str
    :returns: the parsed datetime object
    :rtype: datetime.datetime
    """
    # try date formats --mmdd, --mm-dd, yyyymmdd, yyyy-mm-dd and datetime
    # formats yyyymmddThhmmss, yyyy-mm-ddThh:mm:ss, yyyymmddThhmmssZ,
    # yyyy-mm-ddThh:mm:ssZ.
    for format_string in ("--%m%d", "--%m-%d", "%Y%m%d", "%Y-%m-%d",
                          "%Y%m%dT%H%M%S", "%Y-%m-%dT%H:%M:%S",
                          "%Y%m%dT%H%M%SZ", "%Y-%m-%dT%H:%M:%SZ"):
        try:
            return datetime.strptime(input, format_string)
        except ValueError:
            pass
    # try datetime formats yyyymmddThhmmsstz and yyyy-mm-ddThh:mm:sstz where tz
    # may look like -06:00.
    for format_string in ("%Y%m%dT%H%M%S%z", "%Y-%m-%dT%H:%M:%S%z"):
        try:
            return datetime.strptime(''.join(input.rsplit(":", 1)),
                                     format_string)
        except ValueError:
            pass
    raise ValueError


def _compare_uids(uid1, uid2):
        """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
        """
        sum = 0
        for char1, char2 in zip(uid1, uid2):
            if char1 == char2:
                sum += 1
            else:
                break
        return sum

def _compare_uids ( uid1 , uid2 ) : sum = 0 for char1 , char2 in zip ( uid1 , uid2 ) : if char1 == char2 : sum += 1 else : break return sum

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


def _search_all(self, query):
        """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)
        for contact in self.contacts.values():
            # search in all contact fields
            contact_details = contact.print_vcard()
            if regexp.search(contact_details) is not None:
                yield contact
            else:
                # find phone numbers with special chars like /
                clean_contact_details = re.sub("[^a-zA-Z0-9\n]", "",
                                               contact_details)
                if regexp.search(clean_contact_details) is not None \
                        and len(re.sub("\D", "", query)) >= 3:
                    yield contact

Search in all fields for contacts matching query .


def _search_names(self, query):
        """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)

        """
        regexp = re.compile(query, re.IGNORECASE | re.DOTALL)
        for contact in self.contacts.values():
            # only search in contact name
            if regexp.search(contact.get_full_name()) is not None:
                yield contact

def
_search_names
(
self
,
query
)
:
regexp
=
re
.
compile
(
query
,
re
.
IGNORECASE
|
re
.
DOTALL
)
for
contact
in
self
.
contacts
.
values
(
)
:
# only search in contact name
if
regexp
.
search
(
contact
.
get_full_name
(
)
)
is
not
:
yield
contact

Search in the name filed for contacts matching query .


def _search_uid(self, query):
        """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)

        """
        try:
            # First we treat the argument as a full UID and try to match it
            # exactly.
            yield self.contacts[query]
        except KeyError:
            # If that failed we look for all contacts whos UID start with the
            # given query.
            for uid in self.contacts:
                if uid.startswith(query):
                    yield self.contacts[uid]

Search for contacts with a matching uid .


def search(self, query, method="all"):
        """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)

        """
        logging.debug('address book %s, searching with %s', self.name, query)
        if not self._loaded:
            self.load(query)
        if method == "all":
            search_function = self._search_all
        elif method == "name":
            search_function = self._search_names
        elif method == "uid":
            search_function = self._search_uid
        else:
            raise ValueError('Only the search methods "all", "name" and "uid" '
                             'are supported.')
        return list(search_function(query))

Search this address book for contacts matching the query .


def get_short_uid_dict(self, query=None):
        """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 self._short_uids is None:
            if not self._loaded:
                self.load(query)
            if not self.contacts:
                self._short_uids = {}
            elif len(self.contacts) == 1:
                self._short_uids = {uid[0:1]: contact
                                    for uid, contact in self.contacts.items()}
            else:
                self._short_uids = {}
                sorted_uids = sorted(self.contacts)
                # Prepare for the loop; the first and last items are handled
                # seperatly.
                item0, item1 = sorted_uids[:2]
                same1 = self._compare_uids(item0, item1)
                self._short_uids[item0[:same1 + 1]] = self.contacts[item0]
                for item_new in sorted_uids[2:]:
                    # shift the items and the common prefix lenght one further
                    item0, item1 = item1, item_new
                    same0, same1 = same1, self._compare_uids(item0, item1)
                    # compute the final prefix length for item1
                    same = max(same0, same1)
                    self._short_uids[item0[:same + 1]] = self.contacts[item0]
                # Save the last item.
                self._short_uids[item1[:same1 + 1]] = self.contacts[item1]
        return self._short_uids

Create a dictionary of shortend UIDs for all contacts .


def get_short_uid(self, uid):
        """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
        """
        if uid:
            short_uids = self.get_short_uid_dict()
            for length_of_uid in range(len(uid), 0, -1):
                if short_uids.get(uid[:length_of_uid]) is not None:
                    return uid[:length_of_uid]
        return ""

def get_short_uid ( self , uid ) : if uid : short_uids = self . get_short_uid_dict ( ) for length_of_uid in range ( len ( uid ) , 0 , - 1 ) : if short_uids . get ( uid [ : length_of_uid ] ) is not None : return uid [ : length_of_uid ] return ""

Get the shortend UID for the given UID .


def _find_vcard_files(self, search=None, search_in_source_files=False):
        """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

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

def _find_vcard_files ( self , search = None , search_in_source_files = False ) : files = glob . glob ( os . path . join ( self . path , "*.vcf" ) ) if search and search_in_source_files : for filename in files : with open ( filename , "r" ) as filehandle : if re . search ( search , filehandle . read ( ) , re . IGNORECASE | re . DOTALL ) : yield filename else : yield from files

Find all vcard files inside this address book .


def load(self, query=None, search_in_source_files=False):
        """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
        """
        if self._loaded:
            return
        logging.debug('Loading Vdir %s with query %s', self.name, query)
        errors = 0
        for filename in self._find_vcard_files(
                search=query, search_in_source_files=search_in_source_files):
            try:
                card = CarddavObject.from_file(self, filename,
                                               self._private_objects,
                                               self._localize_dates)
            except (IOError, vobject.base.ParseError) as err:
                verb = "open" if isinstance(err, IOError) else "parse"
                logging.debug("Error: Could not %s file %s\n%s", verb,
                              filename, err)
                if self._skip:
                    errors += 1
                else:
                    # FIXME: This should throw an apropriate exception and the
                    # sys.exit should be called somewhere closer to the command
                    # line parsing.
                    logging.error(
                        "The vcard file %s of address book %s could not be "
                        "parsed\nUse --debug for more information or "
                        "--skip-unparsable to proceed", filename, self.name)
                    sys.exit(2)
            else:
                uid = card.get_uid()
                if not uid:
                    logging.warning("Card %s from address book %s has no UID "
                                    "and will not be availbale.", card,
                                    self.name)
                elif uid in self.contacts:
                    logging.warning(
                        "Card %s and %s from address book %s have the same "
                        "UID. The former will not be availbale.", card,
                        self.contacts[uid], self.name)
                else:
                    self.contacts[uid] = card
        self._loaded = True
        if errors:
            logging.warning(
                "%d of %d vCard files of address book %s could not be parsed.",
                errors, len(self.contacts) + errors, self)
        logging.debug('Loded %s contacts from address book %s.',
                      len(self.contacts), self.name)

Load all vcard files in this address book from disk .


def get_abook(self, name):
        """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

        """
        for abook in self._abooks:
            if abook.name == name:
                return abook

def get_abook ( self , name ) : for abook in self . _abooks : if abook . name == name : return abook


def avail_archs(self):
        ''' Initialize the dictionary of architectures for assembling via keystone'''

        return {
            ARM32:   (KS_ARCH_ARM,     KS_MODE_ARM),
            ARM64:   (KS_ARCH_ARM64,   KS_MODE_LITTLE_ENDIAN),
            ARM_TB:  (KS_ARCH_ARM,     KS_MODE_THUMB),
            HEXAGON: (KS_ARCH_HEXAGON, KS_MODE_BIG_ENDIAN),
            MIPS32:  (KS_ARCH_MIPS,    KS_MODE_MIPS32),
            MIPS64:  (KS_ARCH_MIPS,    KS_MODE_MIPS64),
            PPC32:   (KS_ARCH_PPC,     KS_MODE_PPC32),
            PPC64:   (KS_ARCH_PPC,     KS_MODE_PPC64),
            SPARC32: (KS_ARCH_SPARC,   KS_MODE_SPARC32),
            SPARC64: (KS_ARCH_SPARC,   KS_MODE_SPARC64),
            SYSTEMZ: (KS_ARCH_SYSTEMZ, KS_MODE_BIG_ENDIAN),
            X86_16:  (KS_ARCH_X86,     KS_MODE_16),
            X86_32:  (KS_ARCH_X86,     KS_MODE_32),
            X86_64:  (KS_ARCH_X86,     KS_MODE_64),
        }


def avail_archs(self):
        ''' Initialize the dictionary of architectures for disassembling via capstone'''

        return {
            ARM32:   (CS_ARCH_ARM,   CS_MODE_ARM),
            ARM64:   (CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN),
            ARM_TB:  (CS_ARCH_ARM,   CS_MODE_THUMB),
            MIPS32:  (CS_ARCH_MIPS,  CS_MODE_MIPS32),
            MIPS64:  (CS_ARCH_MIPS,  CS_MODE_MIPS64),
            SPARC32: (CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN),
            SPARC64: (CS_ARCH_SPARC, CS_MODE_V9),
            SYSTEMZ: (CS_ARCH_SYSZ,  CS_MODE_BIG_ENDIAN),
            X86_16:  (CS_ARCH_X86,   CS_MODE_16),
            X86_32:  (CS_ARCH_X86,   CS_MODE_32),
            X86_64:  (CS_ARCH_X86,   CS_MODE_64),
        }


def getargspec_permissive(func):
    """
    An `inspect.getargspec` with a relaxed sanity check to support Cython.

    Motivation:

        A Cython-compiled function is *not* an instance of Python's
        types.FunctionType.  That is the sanity check the standard Py2
        library uses in `inspect.getargspec()`.  So, an exception is raised
        when calling `argh.dispatch_command(cythonCompiledFunc)`.  However,
        the CyFunctions do have perfectly usable `.func_code` and
        `.func_defaults` which is all `inspect.getargspec` needs.

        This function just copies `inspect.getargspec()` from the standard
        library but relaxes the test to a more duck-typing one of having
        both `.func_code` and `.func_defaults` attributes.
    """
    if inspect.ismethod(func):
        func = func.im_func

    # Py2 Stdlib uses isfunction(func) which is too strict for Cython-compiled
    # functions though such have perfectly usable func_code, func_defaults.
    if not (hasattr(func, "func_code") and hasattr(func, "func_defaults")):
        raise TypeError('{!r} missing func_code or func_defaults'.format(func))

    args, varargs, varkw = inspect.getargs(func.func_code)
    return inspect.ArgSpec(args, varargs, varkw, func.func_defaults)

An inspect . getargspec with a relaxed sanity check to support Cython .


def dispatch(parser, argv=None, add_help_command=True,
             completion=True, pre_call=None,
             output_file=sys.stdout, errors_file=sys.stderr,
             raw_output=False, namespace=None,
             skip_unknown_args=False):
    """
    Parses given list of arguments using given parser, calls the relevant
    function and prints the result.

    The target function should expect one positional argument: the
    :class:`argparse.Namespace` object. However, if the function is decorated with
    :func:`~argh.decorators.plain_signature`, the positional and named
    arguments from the namespace object are passed to the function instead
    of the object itself.

    :param parser:

        the ArgumentParser instance.

    :param argv:

        a list of strings representing the arguments. If `None`, ``sys.argv``
        is used instead. Default is `None`.

    :param add_help_command:

        if `True`, converts first positional argument "help" to a keyword
        argument so that ``help foo`` becomes ``foo --help`` and displays usage
        information for "foo". Default is `True`.

    :param output_file:

        A file-like object for output. If `None`, the resulting lines are
        collected and returned as a string. Default is ``sys.stdout``.

    :param errors_file:

        Same as `output_file` but for ``sys.stderr``.

    :param raw_output:

        If `True`, results are written to the output file raw, without adding
        whitespaces or newlines between yielded strings. Default is `False`.

    :param completion:

        If `True`, shell tab completion is enabled. Default is `True`. (You
        will also need to install it.)  See :mod:`argh.completion`.

    :param skip_unknown_args:

        If `True`, unknown arguments do not cause an error
        (`ArgumentParser.parse_known_args` is used).

    :param namespace:

        An `argparse.Namespace`-like object.  By default an
        :class:`ArghNamespace` object is used.  Please note that support for
        combined default and nested functions may be broken if a different
        type of object is forced.

    By default the exceptions are not wrapped and will propagate. The only
    exception that is always wrapped is :class:`~argh.exceptions.CommandError`
    which is interpreted as an expected event so the traceback is hidden.
    You can also mark arbitrary exceptions as "wrappable" by using the
    :func:`~argh.decorators.wrap_errors` decorator.
    """
    if completion:
        autocomplete(parser)

    if argv is None:
        argv = sys.argv[1:]

    if add_help_command:
        if argv and argv[0] == 'help':
            argv.pop(0)
            argv.append('--help')

    if skip_unknown_args:
        parse_args = parser.parse_known_args
    else:
        parse_args = parser.parse_args

    if not namespace:
        namespace = ArghNamespace()

    # this will raise SystemExit if parsing fails
    namespace_obj = parse_args(argv, namespace=namespace)

    function = _get_function_from_namespace_obj(namespace_obj)

    if function:
        lines = _execute_command(function, namespace_obj, errors_file,
                                 pre_call=pre_call)
    else:
        # no commands declared, can't dispatch; display help message
        lines = [parser.format_usage()]

    if output_file is None:
        # user wants a string; we create an internal temporary file-like object
        # and will return its contents as a string
        if sys.version_info < (3,0):
            f = compat.BytesIO()
        else:
            f = compat.StringIO()
    else:
        # normally this is stdout; can be any file
        f = output_file

    for line in lines:
        # print the line as soon as it is generated to ensure that it is
        # displayed to the user before anything else happens, e.g.
        # raw_input() is called

        io.dump(line, f)
        if not raw_output:
            # in most cases user wants one message per line
            io.dump('\n', f)

    if output_file is None:
        # user wanted a string; return contents of our temporary file-like obj
        f.seek(0)
        return f.read()

Parses given list of arguments using given parser calls the relevant function and prints the result .


def safe_input(prompt):
    """
    Prompts user for input. Correctly handles prompt message encoding.
    """

    if sys.version_info < (3,0):
        if isinstance(prompt, compat.text_type):
            # Python 2.x: unicode →  bytes
            encoding = locale.getpreferredencoding() or 'utf-8'
            prompt = prompt.encode(encoding)
    else:
        if not isinstance(prompt, compat.text_type):
            # Python 3.x: bytes →  unicode
            prompt = prompt.decode()

    return _input(prompt)

def
safe_input
(
prompt
)
:
if
sys
.
version_info
<
(
3
,
0
)
:
if
isinstance
(
prompt
,
compat
.
text_type
)
:
# Python 2.x: unicode →  bytes
encoding
=
locale
.
getpreferredencoding
(
)
or
'utf-8'
prompt
=
prompt
.
encode
(
encoding
)
else
:
if
not
isinstance
(
prompt
,
compat
.
text_type
)
:
# Python 3.x: bytes →  unicode
prompt
=
prompt
.
decode
(
)
return
_input
(
prompt
)

Prompts user for input . Correctly handles prompt message encoding .


def encode_output(value, output_file):
    """
    Encodes given value so it can be written to given file object.

    Value may be Unicode, binary string or any other data type.

    The exact behaviour depends on the Python version:

    Python 3.x

        `sys.stdout` is a `_io.TextIOWrapper` instance that accepts `str`
        (unicode) and breaks on `bytes`.

        It is OK to simply assume that everything is Unicode unless special
        handling is introduced in the client code.

        Thus, no additional processing is performed.

    Python 2.x

        `sys.stdout` is a file-like object that accepts `str` (bytes)
        and breaks when `unicode` is passed to `sys.stdout.write()`.

        We can expect both Unicode and bytes. They need to be encoded so as
        to match the file object encoding.

        The output is binary if the object doesn't explicitly require Unicode.

    """
    if sys.version_info > (3,0):
        # Python 3:  whatever → unicode
        return compat.text_type(value)
    else:
        # Python 2:  handle special cases
        stream_encoding = getattr(output_file, 'encoding', None)
        if stream_encoding:
            if stream_encoding.upper() == 'UTF-8':
                return compat.text_type(value)
            else:
                return value.encode(stream_encoding, 'ignore')
        else:
            # no explicit encoding requirements; force binary
            if isinstance(value, compat.text_type):
                # unicode → binary
                return value.encode('utf-8')
            else:
                return str(value)

Encodes given value so it can be written to given file object .


def _guess(kwargs):
    """
    Adds types, actions, etc. to given argument specification.
    For example, ``default=3`` implies ``type=int``.

    :param arg: a :class:`argh.utils.Arg` instance
    """
    guessed = {}

    # Parser actions that accept argument 'type'
    TYPE_AWARE_ACTIONS = 'store', 'append'

    # guess type/action from default value
    value = kwargs.get('default')
    if value is not None:
        if isinstance(value, bool):
            if kwargs.get('action') is None:
                # infer action from default value
                guessed['action'] = 'store_false' if value else 'store_true'
        elif kwargs.get('type') is None:
            # infer type from default value
            # (make sure that action handler supports this keyword)
            if kwargs.get('action', 'store') in TYPE_AWARE_ACTIONS:
                guessed['type'] = type(value)

    # guess type from choices (first item)
    if kwargs.get('choices') and 'type' not in list(guessed) + list(kwargs):
        guessed['type'] = type(kwargs['choices'][0])

    return dict(kwargs, **guessed)

Adds types actions etc . to given argument specification . For example default = 3 implies type = int .


def add_commands(parser, functions, namespace=None, namespace_kwargs=None,
                 func_kwargs=None,
                 # deprecated args:
                 title=None, description=None, help=None):
    """
    Adds given functions as commands to given parser.

    :param parser:

        an :class:`argparse.ArgumentParser` instance.

    :param functions:

        a list of functions. A subparser is created for each of them.
        If the function is decorated with :func:`~argh.decorators.arg`, the
        arguments are passed to :class:`argparse.ArgumentParser.add_argument`.
        See also :func:`~argh.dispatching.dispatch` for requirements
        concerning function signatures. The command name is inferred from the
        function name. Note that the underscores in the name are replaced with
        hyphens, i.e. function name "foo_bar" becomes command name "foo-bar".

    :param namespace:

        an optional string representing the group of commands. For example, if
        a command named "hello" is added without the namespace, it will be
        available as "prog.py hello"; if the namespace if specified as "greet",
        then the command will be accessible as "prog.py greet hello". The
        namespace itself is not callable, so "prog.py greet" will fail and only
        display a help message.

    :param func_kwargs:

        a `dict` of keyword arguments to be passed to each nested ArgumentParser
        instance created per command (i.e. per function).  Members of this
        dictionary have the highest priority, so a function's docstring is
        overridden by a `help` in `func_kwargs` (if present).

    :param namespace_kwargs:

        a `dict` of keyword arguments to be passed to the nested ArgumentParser
        instance under given `namespace`.

    Deprecated params that should be moved into `namespace_kwargs`:

    :param title:

        passed to :meth:`argparse.ArgumentParser.add_subparsers` as `title`.

        .. deprecated:: 0.26.0

           Please use `namespace_kwargs` instead.

    :param description:

        passed to :meth:`argparse.ArgumentParser.add_subparsers` as
        `description`.

        .. deprecated:: 0.26.0

           Please use `namespace_kwargs` instead.

    :param help:

        passed to :meth:`argparse.ArgumentParser.add_subparsers` as `help`.

        .. deprecated:: 0.26.0

           Please use `namespace_kwargs` instead.

    .. note::

        This function modifies the parser object. Generally side effects are
        bad practice but we don't seem to have any choice as ArgumentParser is
        pretty opaque.
        You may prefer :class:`~argh.helpers.ArghParser.add_commands` for a bit
        more predictable API.

    .. note::

       An attempt to add commands to a parser which already has a default
       function (e.g. added with :func:`~argh.assembling.set_default_command`)
       results in `AssemblingError`.

    """
    # FIXME "namespace" is a correct name but it clashes with the "namespace"
    # that represents arguments (argparse.Namespace and our ArghNamespace).
    # We should rename the argument here.

    if DEST_FUNCTION in parser._defaults:
        _require_support_for_default_command_with_subparsers()

    namespace_kwargs = namespace_kwargs or {}

    # FIXME remove this by 1.0
    #
    if title:
        warnings.warn('argument `title` is deprecated in add_commands(),'
                      ' use `parser_kwargs` instead', DeprecationWarning)
        namespace_kwargs['description'] = title
    if help:
        warnings.warn('argument `help` is deprecated in add_commands(),'
                      ' use `parser_kwargs` instead', DeprecationWarning)
        namespace_kwargs['help'] = help
    if description:
        warnings.warn('argument `description` is deprecated in add_commands(),'
                      ' use `parser_kwargs` instead', DeprecationWarning)
        namespace_kwargs['description'] = description
    #
    # /

    subparsers_action = get_subparsers(parser, create=True)

    if namespace:
        # Make a nested parser and init a deeper _SubParsersAction under it.

        # Create a named group of commands.  It will be listed along with
        # root-level commands in ``app.py --help``; in that context its `title`
        # can be used as a short description on the right side of its name.
        # Normally `title` is shown above the list of commands
        # in ``app.py my-namespace --help``.
        subsubparser_kw = {
            'help': namespace_kwargs.get('title'),
        }
        subsubparser = subparsers_action.add_parser(namespace, **subsubparser_kw)
        subparsers_action = subsubparser.add_subparsers(**namespace_kwargs)
    else:
        assert not namespace_kwargs, ('`parser_kwargs` only makes sense '
                                      'with `namespace`.')

    for func in functions:
        cmd_name, func_parser_kwargs = _extract_command_meta_from_func(func)

        # override any computed kwargs by manually supplied ones
        if func_kwargs:
            func_parser_kwargs.update(func_kwargs)

        # create and set up the parser for this command
        command_parser = subparsers_action.add_parser(cmd_name, **func_parser_kwargs)
        set_default_command(command_parser, func)

Adds given functions as commands to given parser .


def named(new_name):
    """
    Sets given string as command name instead of the function name.
    The string is used verbatim without further processing.

    Usage::

        @named('load')
        def do_load_some_stuff_and_keep_the_original_function_name(args):
            ...

    The resulting command will be available only as ``load``.  To add aliases
    without renaming the command, check :func:`aliases`.

    .. versionadded:: 0.19
    """
    def wrapper(func):
        setattr(func, ATTR_NAME, new_name)
        return func
    return wrapper

def named ( new_name ) : def wrapper ( func ) : setattr ( func , ATTR_NAME , new_name ) return func return wrapper

Sets given string as command name instead of the function name . The string is used verbatim without further processing .


def arg(*args, **kwargs):
    """
    Declares an argument for given function. Does not register the function
    anywhere, nor does it modify the function in any way.

    The signature of the decorator matches that of
    :meth:`argparse.ArgumentParser.add_argument`, only some keywords are not
    required if they can be easily guessed (e.g. you don't have to specify type
    or action when an `int` or `bool` default value is supplied).

    Typical use cases:

    - In combination with :func:`expects_obj` (which is not recommended);
    - in combination with ordinary function signatures to add details that
      cannot be expressed with that syntax (e.g. help message).

    Usage::

        from argh import arg

        @arg('path', help='path to the file to load')
        @arg('--format', choices=['yaml','json'])
        @arg('-v', '--verbosity', choices=range(0,3), default=2)
        def load(path, something=None, format='json', dry_run=False, verbosity=1):
            loaders = {'json': json.load, 'yaml': yaml.load}
            loader = loaders[args.format]
            data = loader(args.path)
            if not args.dry_run:
                if verbosity < 1:
                    print('saving to the database')
                put_to_database(data)

    In this example:

    - `path` declaration is extended with `help`;
    - `format` declaration is extended with `choices`;
    - `dry_run` declaration is not duplicated;
    - `verbosity` is extended with `choices` and the default value is
      overridden.  (If both function signature and `@arg` define a default
      value for an argument, `@arg` wins.)

    .. note::

        It is recommended to avoid using this decorator unless there's no way
        to tune the argument's behaviour or presentation using ordinary
        function signatures.  Readability counts, don't repeat yourself.

    """
    def wrapper(func):
        declared_args = getattr(func, ATTR_ARGS, [])
        # The innermost decorator is called first but appears last in the code.
        # We need to preserve the expected order of positional arguments, so
        # the outermost decorator inserts its value before the innermost's:
        declared_args.insert(0, dict(option_strings=args, **kwargs))
        setattr(func, ATTR_ARGS, declared_args)
        return func
    return wrapper

Declares an argument for given function . Does not register the function anywhere nor does it modify the function in any way .


def confirm(action, default=None, skip=False):
    """
    A shortcut for typical confirmation prompt.

    :param action:

        a string describing the action, e.g. "Apply changes". A question mark
        will be appended.

    :param default:

        `bool` or `None`. Determines what happens when user hits :kbd:`Enter`
        without typing in a choice. If `True`, default choice is "yes". If
        `False`, it is "no". If `None` the prompt keeps reappearing until user
        types in a choice (not necessarily acceptable) or until the number of
        iteration reaches the limit. Default is `None`.

    :param skip:

        `bool`; if `True`, no interactive prompt is used and default choice is
        returned (useful for batch mode). Default is `False`.

    Usage::

        def delete(key, silent=False):
            item = db.get(Item, args.key)
            if confirm('Delete '+item.title, default=True, skip=silent):
                item.delete()
                print('Item deleted.')
            else:
                print('Operation cancelled.')

    Returns `None` on `KeyboardInterrupt` event.
    """
    MAX_ITERATIONS = 3
    if skip:
        return default
    else:
        defaults = {
            None: ('y','n'),
            True: ('Y','n'),
            False: ('y','N'),
        }
        y, n = defaults[default]
        prompt = text_type('{action}? ({y}/{n})').format(**locals())
        choice = None
        try:
            if default is None:
                cnt = 1
                while not choice and cnt < MAX_ITERATIONS:
                    choice = safe_input(prompt)
                    cnt += 1
            else:
                choice = safe_input(prompt)
        except KeyboardInterrupt:
            return None
    if choice in ('yes', 'y', 'Y'):
        return True
    if choice in ('no', 'n', 'N'):
        return False
    if default is not None:
        return default
    return None

def
confirm
(
action
,
default
=
,
skip
=
False
)
:
MAX_ITERATIONS
=
3
if
skip
:
return
default
else
:
defaults
=
{
:
(
'y'
,
'n'
)
,
True
:
(
'Y'
,
'n'
)
,
False
:
(
'y'
,
'N'
)
,
}
y
,
n
=
defaults
[
default
]
prompt
=
text_type
(
'{action}? ({y}/{n})'
)
.
format
(
*
*
locals
(
)
)
choice
=
try
:
if
default
is
:
cnt
=
1
while
not
choice
and
cnt
<
MAX_ITERATIONS
:
choice
=
safe_input
(
prompt
)
cnt
+=
1
else
:
choice
=
safe_input
(
prompt
)
except
KeyboardInterrupt
:
return
if
choice
in
(
'yes'
,
'y'
,
'Y'
)
:
return
True
if
choice
in
(
'no'
,
'n'
,
'N'
)
:
return
False
if
default
is
not
:
return
default
return

A shortcut for typical confirmation prompt .


def replace(self, **kwargs):
        '''
        Copy the Query object, optionally replacing the filters, order_by, or
        limit information on the copy. This is mostly an internal detail that
        you can ignore.
        '''
        data = {
            'model': self._model,
            'filters': self._filters,
            'order_by': self._order_by,
            'limit': self._limit,
            'select': self._select,
        }
        data.update(**kwargs)
        return Query(**data)

def replace ( self , * * kwargs ) : data = { 'model' : self . _model , 'filters' : self . _filters , 'order_by' : self . _order_by , 'limit' : self . _limit , 'select' : self . _select , } data . update ( * * kwargs ) return Query ( * * data )

Copy the Query object optionally replacing the filters order_by or limit information on the copy . This is mostly an internal detail that you can ignore .