Beispiel #1
0
def parse_query_parts(parts, model_cls):
    """Given a beets query string as a list of components, return the
    `Query` and `Sort` they represent.

    Like `dbcore.parse_sorted_query`, with beets query prefixes and
    special path query detection.
    """
    # Get query types and their prefix characters.
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())

    # Special-case path-like queries, which are non-field queries
    # containing path separators (/).
    path_parts = []
    non_path_parts = []
    for s in parts:
        if PathQuery.is_path_query(s):
            path_parts.append(s)
        else:
            non_path_parts.append(s)

    query, sort = dbcore.parse_sorted_query(
        model_cls, non_path_parts, prefixes
    )

    # Add path queries to aggregate query.
    # Match field / flexattr depending on whether the model has the path field
    fast_path_query = 'path' in model_cls._fields
    query.subqueries += [PathQuery('path', s, fast_path_query)
                         for s in path_parts]

    return query, sort
Beispiel #2
0
def parse_query_parts(parts, model_cls):
    """Given a beets query string as a list of components, return the
    `Query` and `Sort` they represent.

    Like `dbcore.parse_sorted_query`, with beets query prefixes and
    special path query detection.
    """
    # Get query types and their prefix characters.
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())

    # Special-case path-like queries, which are non-field queries
    # containing path separators (/).
    path_parts = []
    non_path_parts = []
    for s in parts:
        if PathQuery.is_path_query(s):
            path_parts.append(s)
        else:
            non_path_parts.append(s)

    query, sort = dbcore.parse_sorted_query(model_cls, non_path_parts,
                                            prefixes)

    # Add path queries to aggregate query.
    # Match field / flexattr depending on whether the model has the path field
    fast_path_query = 'path' in model_cls._fields
    query.subqueries += [
        PathQuery('path', s, fast_path_query) for s in path_parts
    ]

    return query, sort
Beispiel #3
0
def parse_query_parts(parts, model_cls):
    """Given a beets query string as a list of components, return the
    `Query` and `Sort` they represent.

    Like `dbcore.parse_sorted_query`, with beets query prefixes and
    special path query detection.
    """
    # Get query types and their prefix characters.
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())

    # Special-case path-like queries, which are non-field queries
    # containing path separators (/).
    if 'path' in model_cls._fields:
        path_parts = []
        non_path_parts = []
        for s in parts:
            if s.find(os.sep, 0, s.find(':')) != -1:
                # Separator precedes colon.
                path_parts.append(s)
            else:
                non_path_parts.append(s)
    else:
        path_parts = ()
        non_path_parts = parts

    query, sort = dbcore.parse_sorted_query(
        model_cls, non_path_parts, prefixes
    )

    # Add path queries to aggregate query.
    if path_parts:
        query.subqueries += [PathQuery('path', s) for s in path_parts]
    return query, sort
Beispiel #4
0
def parse_query_parts(parts, model_cls):
    """Given a beets query string as a list of components, return the
    `Query` and `Sort` they represent.

    Like `dbcore.parse_sorted_query`, with beets query prefixes and
    special path query detection.
    """
    # Get query types and their prefix characters.
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())

    # Special-case path-like queries, which are non-field queries
    # containing path separators (/).
    if 'path' in model_cls._fields:
        path_parts = []
        non_path_parts = []
        for s in parts:
            if s.find(os.sep, 0, s.find(':')) != -1:
                # Separator precedes colon.
                path_parts.append(s)
            else:
                non_path_parts.append(s)
    else:
        path_parts = ()
        non_path_parts = parts

    query, sort = dbcore.parse_sorted_query(model_cls, non_path_parts,
                                            prefixes)

    # Add path queries to aggregate query.
    if path_parts:
        query.subqueries += [PathQuery('path', s) for s in path_parts]
    return query, sort
Beispiel #5
0
def construct_query_part(query_part, model_cls):
    """Create a query from a single query component, `query_part`, for
    querying instances of `model_cls`. Return a `Query` instance.
    """
    # Shortcut for empty query parts.
    if not query_part:
        return dbcore.query.TrueQuery()

    # Set up and parse the string.
    query_classes = dict((k, t.query) for (k, t) in model_cls._fields.items())
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())
    key, pattern, query_class = \
        parse_query_part(query_part, query_classes, prefixes)

    # No key specified.
    if key is None:
        if os.sep in pattern and 'path' in model_cls._fields:
            # This looks like a path.
            return PathQuery('path', pattern)
        elif issubclass(query_class, dbcore.FieldQuery):
            # The query type matches a specific field, but none was
            # specified. So we use a version of the query that matches
            # any field.
            return dbcore.query.AnyFieldQuery(pattern,
                                              model_cls._search_fields,
                                              query_class)
        else:
            # Other query type.
            return query_class(pattern)

    key = key.lower()
    return query_class(key.lower(), pattern, key in model_cls._fields)
Beispiel #6
0
def parse_query_part(part):
    """Takes a query in the form of a key/value pair separated by a
    colon. The value part is matched against a list of prefixes that
    can be extended by plugins to add custom query types. For
    example, the colon prefix denotes a regular expression query.

    The function returns a tuple of `(key, value, cls)`. `key` may
    be None, indicating that any field may be matched. `cls` is a
    subclass of `FieldQuery`.

    For instance,
    parse_query('stapler') == (None, 'stapler', None)
    parse_query('color:red') == ('color', 'red', None)
    parse_query(':^Quiet') == (None, '^Quiet', RegexpQuery)
    parse_query('color::b..e') == ('color', 'b..e', RegexpQuery)

    Prefixes may be 'escaped' with a backslash to disable the keying
    behavior.
    """
    part = part.strip()
    match = PARSE_QUERY_PART_REGEX.match(part)

    prefixes = {':': RegexpQuery}
    prefixes.update(plugins.queries())

    if match:
        key = match.group(1)
        term = match.group(2).replace('\:', ':')
        # Match the search term against the list of prefixes.
        for pre, query_class in prefixes.items():
            if term.startswith(pre):
                return key, term[len(pre):], query_class
        if key and NumericQuery.applies_to(key):
            return key, term, NumericQuery
        return key, term, SubstringQuery  # The default query type.
Beispiel #7
0
def construct_query_part(query_part, model_cls):
    """Create a query from a single query component, `query_part`, for
    querying instances of `model_cls`. Return a `Query` instance.
    """
    # Shortcut for empty query parts.
    if not query_part:
        return dbcore.query.TrueQuery()

    # Set up and parse the string.
    query_classes = dict((k, t.query) for (k, t) in model_cls._fields.items())
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())
    key, pattern, query_class = \
        parse_query_part(query_part, query_classes, prefixes)

    # No key specified.
    if key is None:
        if os.sep in pattern and 'path' in model_cls._fields:
            # This looks like a path.
            return PathQuery('path', pattern)
        elif issubclass(query_class, dbcore.FieldQuery):
            # The query type matches a specific field, but none was
            # specified. So we use a version of the query that matches
            # any field.
            return dbcore.query.AnyFieldQuery(pattern,
                                              model_cls._search_fields,
                                              query_class)
        else:
            # Other query type.
            return query_class(pattern)

    key = key.lower()
    return query_class(key.lower(), pattern, key in model_cls._fields)
Beispiel #8
0
def get_query(val, model_cls):
    """Take a value which may be None, a query string, a query string
    list, or a Query object, and return a suitable Query object.

    `model_cls` is the subclass of Model indicating which entity this
    is a query for (i.e., Album or Item) and is used to determine which
    fields are searched.
    """
    # Get query types and their prefix characters.
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())

    # Convert a single string into a list of space-separated
    # criteria.
    if isinstance(val, basestring):
        # A bug in Python < 2.7.3 prevents correct shlex splitting of
        # Unicode strings.
        # http://bugs.python.org/issue6988
        if isinstance(val, unicode):
            val = val.encode('utf8')
        val = [s.decode('utf8') for s in shlex.split(val)]

    if val is None:
        return dbcore.query.TrueQuery()

    elif isinstance(val, list) or isinstance(val, tuple):
        # Special-case path-like queries, which are non-field queries
        # containing path separators (/).
        if 'path' in model_cls._fields:
            path_parts = []
            non_path_parts = []
            for s in val:
                if s.find(os.sep, 0, s.find(':')) != -1:
                    # Separator precedes colon.
                    path_parts.append(s)
                else:
                    non_path_parts.append(s)
        else:
            path_parts = ()
            non_path_parts = val

        # Parse remaining parts and construct an AndQuery.
        query = dbcore.query_from_strings(
            dbcore.AndQuery, model_cls, prefixes, non_path_parts
        )

        # Add path queries to aggregate query.
        if path_parts:
            query.subqueries += [PathQuery('path', s) for s in path_parts]
        return query

    elif isinstance(val, dbcore.Query):
        return val

    else:
        raise ValueError('query must be None or have type Query or str')
Beispiel #9
0
def get_query(val, model_cls):
    """Take a value which may be None, a query string, a query string
    list, or a Query object, and return a suitable Query object.

    `model_cls` is the subclass of Model indicating which entity this
    is a query for (i.e., Album or Item) and is used to determine which
    fields are searched.
    """
    # Get query types and their prefix characters.
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())

    # Convert a single string into a list of space-separated
    # criteria.
    if isinstance(val, basestring):
        # A bug in Python < 2.7.3 prevents correct shlex splitting of
        # Unicode strings.
        # http://bugs.python.org/issue6988
        if isinstance(val, unicode):
            val = val.encode('utf8')
        val = [s.decode('utf8') for s in shlex.split(val)]

    if val is None:
        return dbcore.query.TrueQuery()

    elif isinstance(val, list) or isinstance(val, tuple):
        # Special-case path-like queries, which are non-field queries
        # containing path separators (/).
        if 'path' in model_cls._fields:
            path_parts = []
            non_path_parts = []
            for s in val:
                if s.find(os.sep, 0, s.find(':')) != -1:
                    # Separator precedes colon.
                    path_parts.append(s)
                else:
                    non_path_parts.append(s)
        else:
            path_parts = ()
            non_path_parts = val

        # Parse remaining parts and construct an AndQuery.
        query = dbcore.query_from_strings(dbcore.AndQuery, model_cls, prefixes,
                                          non_path_parts)

        # Add path queries to aggregate query.
        if path_parts:
            query.subqueries += [PathQuery('path', s) for s in path_parts]
        return query

    elif isinstance(val, dbcore.Query):
        return val

    else:
        raise ValueError('query must be None or have type Query or str')
Beispiel #10
0
def construct_query_part(query_part, model_cls):
    """Create a query from a single query component, `query_part`, for
    querying instances of `model_cls`. Return a `Query` instance or
    `None` if the value cannot be parsed.
    """
    query_classes = dict((k, t.query) for (k, t) in model_cls._fields.items())
    prefixes = {':': dbcore.query.RegexpQuery}
    prefixes.update(plugins.queries())
    parsed = parse_query_part(query_part, query_classes, prefixes)
    if not parsed:
        return

    key, pattern, query_class = parsed

    # No key specified.
    if key is None:
        if os.sep in pattern and 'path' in model_cls._fields:
            # This looks like a path.
            return PathQuery('path', pattern)
        elif issubclass(query_class, dbcore.FieldQuery):
            # The query type matches a specific field, but none was
            # specified. So we use a version of the query that matches
            # any field.
            return dbcore.query.AnyFieldQuery(pattern,
                                              model_cls._search_fields,
                                              query_class)
        else:
            # Other query type.
            return query_class(pattern)

    key = key.lower()

    # Singleton query (not a real field).
    if key == 'singleton':
        return SingletonQuery(util.str2bool(pattern))

    # Other field.
    else:
        return query_class(key.lower(), pattern, key in model_cls._fields)