Return the symbols in this library.

        Parameters
        ----------
        all_symbols : `bool`
            If True returns all symbols under all snapshots, even if the symbol has been deleted
            in the current version (i.e. it exists under a snapshot... Default: False
        snapshot : `str`
            Return the symbols available under the snapshot.
        regex : `str`
            filter symbols by the passed in regular expression
        kwargs :
            kwarg keys are used as fields to query for symbols with metadata matching
            the kwargs query

        Returns
        -------
        String list of symbols in the library

def list_symbols(self, all_symbols=False, snapshot=None, regex=None, **kwargs):
        """
        Return the symbols in this library.

        Parameters
        ----------
        all_symbols : `bool`
            If True returns all symbols under all snapshots, even if the symbol has been deleted
            in the current version (i.e. it exists under a snapshot... Default: False
        snapshot : `str`
            Return the symbols available under the snapshot.
        regex : `str`
            filter symbols by the passed in regular expression
        kwargs :
            kwarg keys are used as fields to query for symbols with metadata matching
            the kwargs query

        Returns
        -------
        String list of symbols in the library
        """
        query = {}
        if regex is not None:
            query['symbol'] = {'$regex': regex}
        if kwargs:
            for k, v in six.iteritems(kwargs):
                # TODO: this doesn't work as expected as it ignores the versions with metadata.deleted set
                #       as a result it will return symbols with matching metadata which have been deleted
                #       Maybe better add a match step in the pipeline instead of making it part of the query
                query['metadata.' + k] = v
        if snapshot is not None:
            try:
                query['parent'] = self._snapshots.find_one({'name': snapshot})['_id']
            except TypeError:
                raise NoDataFoundException('No snapshot %s in library %s' % (snapshot, self._arctic_lib.get_name()))
        elif all_symbols:
            return self._versions.find(query).distinct('symbol')

        # Return just the symbols which aren't deleted in the 'trunk' of this library
        pipeline = []
        if query:
            # Match based on user criteria first
            pipeline.append({'$match': query})
        pipeline.extend([
            # version_custom value is: 2*version + (0 if deleted else 1)
            # This is used to optimize aggregation query:
            #  - avoid sorting
            #  - be able to rely on the latest version (max) for the deleted status
            #
            # Be aware of that if you don't use custom sort or if use a sort before $group which utilizes
            # exactly an existing index, the $group will do best effort to utilize this index:
            #  - https://jira.mongodb.org/browse/SERVER-4507
            {'$group': {
                '_id': '$symbol',
                'version_custom': {
                    '$max': {
                        '$add': [
                            {'$multiply': ['$version', 2]},
                            {'$cond': [{'$eq': ['$metadata.deleted', True]}, 1, 0]}
                        ]
                    }
                },
            }},
            # Don't include symbols which are part of some snapshot, but really deleted...
            {'$match': {'version_custom': {'$mod': [2, 0]}}}
        ])

        # We may hit the group memory limit (100MB), so use allowDiskUse to circumvent this
        #  - https://docs.mongodb.com/manual/reference/operator/aggregation/group/#group-memory-limit
        return sorted([x['_id'] for x in self._versions.aggregate(pipeline, allowDiskUse=True)])