Improve path query parts detection: test existence

Detect path parts of a query with `PathQuery.is_path_query()` which
tests for `os.sep` presence AND query part existence.

Also fix a bug where "my_path/" would not get detected: colon absence would
make search for `os.sep` only happen in "my_path".

Fix #1385.
This commit is contained in:
Bruno Cauet 2015-03-30 13:05:56 +02:00
parent e953e6bdcb
commit ad34642877
2 changed files with 57 additions and 2 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

@ -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):