Merge pull request #1387 from brunal/improve-path-query

Improve path query: autodetect only if the target exists
This commit is contained in:
Adrian Sampson 2015-03-30 22:36:25 -05:00
commit 882723a0bf
4 changed files with 63 additions and 4 deletions

View file

@ -75,6 +75,17 @@ class PathQuery(dbcore.FieldQuery):
# As a directory (prefix).
self.dir_path = util.bytestring_path(os.path.join(self.file_path, b''))
@classmethod
def is_path_query(cls, query_part):
"""Try to guess whether a unicode query part is a path query.
Condition: separator precedes colon and the file exists.
"""
colon = query_part.find(':')
if colon != -1:
query_part = query_part[:colon]
return os.sep in query_part and os.path.exists(query_part)
def match(self, item):
path = item.path if self.case_sensitive else item.path.lower()
return (path == self.file_path) or path.startswith(self.dir_path)
@ -1097,8 +1108,7 @@ def parse_query_parts(parts, model_cls):
path_parts = []
non_path_parts = []
for s in parts:
if s.find(os.sep, 0, s.find(':')) != -1:
# Separator precedes colon.
if PathQuery.is_path_query(s):
path_parts.append(s)
else:
non_path_parts.append(s)

View file

@ -6,6 +6,8 @@ Changelog
Features:
* :ref:`pathquery` are automatically triggered only if the
path targeted by the query exists.
* :doc:`/plugins/duplicates` now accepts a ``--strict`` option that
will only report duplicates if all attributes are explicitly set.
:bug:`1000`

View file

@ -166,6 +166,8 @@ Find all items with a file modification time between 2008-12-01 and
$ beet ls 'mtime:2008-12-01..2008-12-02'
.. _pathquery:
Path Queries
------------
@ -175,8 +177,8 @@ Sometimes it's useful to find all the items in your library that are
$ beet list path:/my/music/directory
In fact, beets automatically recognizes any query term containing a path
separator (``/`` on POSIX systems) as a path query, so this command is
equivalent::
separator (``/`` on POSIX systems) as a path query if that path exists, so this
command is equivalent as long as ``/my/music/directory`` exist::
$ beet list /my/music/directory

View file

@ -18,6 +18,8 @@ from __future__ import (division, absolute_import, print_function,
unicode_literals)
from functools import partial
from mock import patch
import os
from test import _common
from test._common import unittest
@ -374,6 +376,13 @@ class PathQueryTest(_common.LibTestCase, TestHelper, AssertsMixin):
self.i.store()
self.lib.add_album([self.i])
self.patcher = patch('beets.library.os.path.exists')
self.patcher.start().return_value = True
def tearDown(self):
super(PathQueryTest, self).tearDown()
self.patcher.stop()
def test_path_exact_match(self):
q = 'path:/a/b/c.mp3'
results = self.lib.items(q)
@ -503,6 +512,42 @@ class PathQueryTest(_common.LibTestCase, TestHelper, AssertsMixin):
q = makeq()
self.assertEqual(q.case_sensitive, False)
@patch('beets.library.os')
def test_path_sep_detection(self, mock_os):
mock_os.sep = '/'
is_path = beets.library.PathQuery.is_path_query
self.assertTrue(is_path('/foo/bar'))
self.assertTrue(is_path('foo/bar'))
self.assertTrue(is_path('foo/'))
self.assertFalse(is_path('foo'))
self.assertTrue(is_path('foo/:bar'))
self.assertFalse(is_path('foo:bar/'))
self.assertFalse(is_path('foo:/bar'))
def test_path_detection(self):
# cover existence test
self.patcher.stop()
is_path = beets.library.PathQuery.is_path_query
try:
self.touch(b'foo/bar')
# test absolute
self.assertTrue(is_path(os.path.join(self.temp_dir, b'foo/bar')))
self.assertTrue(is_path(os.path.join(self.temp_dir, b'foo')))
self.assertFalse(is_path(b'foo/bar'))
cur_dir = os.getcwd()
try:
os.chdir(self.temp_dir)
self.assertTrue(is_path(b'foo/'))
self.assertTrue(is_path(b'foo/bar'))
self.assertTrue(is_path(b'foo/bar:tagada'))
self.assertFalse(is_path(b'bar'))
finally:
os.chdir(cur_dir)
finally:
self.patcher.start()
class IntQueryTest(unittest.TestCase, TestHelper):