From d8f58603fc2d68612adeea44b64073ba3ffb970b Mon Sep 17 00:00:00 2001 From: Thomas Scholtes Date: Sun, 3 Aug 2014 11:24:27 +0200 Subject: [PATCH] Replace URLs with paths --- beets/attachments.py | 101 ++++++++++++++------------------------- test/test_attachments.py | 4 +- 2 files changed, 39 insertions(+), 66 deletions(-) diff --git a/beets/attachments.py b/beets/attachments.py index d90040586..63da9ad0d 100644 --- a/beets/attachments.py +++ b/beets/attachments.py @@ -14,10 +14,9 @@ import re -import urlparse from argparse import ArgumentParser +import os.path -from beets.plugins import find_plugins from beets import dbcore from beets.dbcore.query import Query, AndQuery @@ -37,13 +36,13 @@ class Attachment(dbcore.db.Model): """Represents an attachment in the database. An attachment has four properties that correspond to fields in the - database: `url`, `type`, `ref`, and `ref_type`. Flexible + database: `path`, `type`, `ref`, and `ref_type`. Flexible attributes are accessed as `attachment[key]`. """ _fields = { 'id': dbcore.types.Id(), - 'url': dbcore.types.String(), + 'path': dbcore.types.String(), 'ref': dbcore.types.Integer(), 'ref_type': dbcore.types.String(), 'type': dbcore.types.String(), @@ -51,11 +50,12 @@ class Attachment(dbcore.db.Model): _table = 'attachments' _flex_table = 'attachment_metadata' - def __init__(self, db=None, libdir=None, path=None, **values): - if path is not None: - values['url'] = path + def __init__(self, db=None, entity=None, path=None, **values): super(Attachment, self).__init__(db, **values) - self.libdir = libdir + if path is not None: + self.path = path + if entity is not None: + self.entity = entity @property def entity(self): @@ -80,59 +80,44 @@ class Attachment(dbcore.db.Model): self.ref = entity.id def move(self, destination=None, copy=False, force=False): - """Moves the attachment from its original `url` to its - destination URL. + """Moves the attachment from its original `path` to + `destination` and updates `self.path`. If `destination` is given it must be a path. If the path is relative, it is treated relative to the `libdir`. + TODO: Review next paragraph. If the destination is `None` the method retrieves a template from a `type -> template` map using the attachements type. It then evaluates the template in the context of the attachment and its associated entity. - The method tries to retrieve the resource from `self.url` and - saves it to `destination`. If the destination already exists and - `force` is `False` it raises an error. Otherwise the destination - is overwritten and `self.url` is set to `destination`. + If the destination already exists and `force` is `False` it + raises an error. - If `copy` is `False` and the original `url` pointed to a local - file it removes that file. + If `copy` is `False` (the default) then the original file is deleted. """ # TODO implement raise NotImplementedError @property def path(self): - if self.resolve().scheme == 'file': - return self.resolve().path + path = self['path'] + if not os.path.isabs(path): + libdir = self._db.directory + assert os.path.isabs(libdir) + path = os.path.normpath(os.path.join(libdir, path)) + return path @path.setter def path(self, value): - self.url = value + self['path'] = value - def resolve(self): - """Return a url structure for the `url` property. - - This is similar to `urlparse(attachment.url)`. If `url` has - no schema it defaults to `file`. If the schema is `file` and - the path is relative it is resolved relative to the `libdir`. - - The return value is an instance of `urlparse.ParseResult`. - """ - (scheme, netloc, path, params, query, fragment) = \ - urlparse.urlparse(self.url, scheme='file') - # if not os.path.isabs(path): - # assert os.path.isabs(beetsdir) - # path = os.path.normpath(os.path.join(beetsdir, path)) - return urlparse.ParseResult(scheme, netloc, path, - params, query, fragment) def _validate(self): # TODO integrate this into the `store()` method. assert self.entity assert re.match(r'^[a-zA-Z][-\w]*', self.type) - urlparse.urlparse(self.url) def __getattr__(self, key): if key in self._fields.keys(): @@ -160,9 +145,9 @@ class AttachmentFactory(object): allows plugins to provide additional data. """ - def __init__(self, db=None, libdir=None): + def __init__(self, db=None): self._db = db - self._libdir = libdir + self._libdir = db.directory self._discoverers = [] self._collectors = [] @@ -182,39 +167,27 @@ class AttachmentFactory(object): queries.append(attachment_query) return self._db._fetch(Attachment, AndQuery(queries)) - def discover(self, url, entity=None): - """Yield a list of attachments for types registered with the url. + def discover(self, path, entity=None): + """Yield a list of attachments for types registered with the path. The method uses the registered type discoverer functions to get - a list of types for `url`. For each type it yields an attachment - created with `create_with_type`. - - The scheme of the url defaults to `file`. + a list of types for `path`. For each type it yields an attachment + through `create`. """ - url = urlparse.urlparse(url, scheme='file') - if url.scheme != 'file': - # TODO Discoverers are only required to handle paths. In the - # future we might want to add the possibility to register - # discoverers for general URLs. - return + for type in self._discover_types(path): + yield self.create(path, type, entity) - for type in self._discover_types(url.path): - yield self.create(url.path, type, entity) - - def create(self, url, type, entity=None): + def create(self, path, type, entity=None): """Return a populated `Attachment` instance. - The `url`, `type`, and `entity` properties of the attachment are - set corresponding to the arguments. The method also set - flexible attributes for metadata retrieved from all registered - collectors. + The `path`, `type`, and `entity` properties of the attachment + are set corresponding to the arguments. In addition the method + set retrieves meta data from registered collectors and and adds + it as flexible attributes """ - # TODO extend this to handle general urls - attachment = Attachment(db=self._db, libdir=self._libdir, - url=url, type=type) - if entity is not None: - attachment.entity = entity - for key, value in self._collect_meta(type, url).items(): + attachment = Attachment(db=self._db, path=path, + entity=entity, type=type) + for key, value in self._collect_meta(type, attachment.path).items(): attachment[key] = value return attachment diff --git a/test/test_attachments.py b/test/test_attachments.py index 5ff0313cd..327e4b614 100644 --- a/test/test_attachments.py +++ b/test/test_attachments.py @@ -30,9 +30,9 @@ class AttachmentFactoryTest(unittest.TestCase): self.lib = Library(':memory:') self.factory = AttachmentFactory(self.lib) - def test_create_with_url_and_type(self): + def test_create_with_path_and_type(self): attachment = self.factory.create('/path/to/attachment', 'coverart') - self.assertEqual(attachment.url, '/path/to/attachment') + self.assertEqual(attachment.path, '/path/to/attachment') self.assertEqual(attachment.type, 'coverart') def test_create_sets_entity(self):