class TestHelper(object): """Helper mixin for high-level cli and plugin tests. This mixin provides methods to isolate beets' global state provide fixtures. """ # TODO automate teardown through hook registration def setup_beets(self, disk=False): """Setup pristine global configuration and library for testing. Sets ``beets.config`` so we can safely use any functionality that uses the global configuration. All paths used are contained in a temporary directory Sets the following properties on itself. - ``temp_dir`` Path to a temporary directory containing all files specific to beets - ``libdir`` Path to a subfolder of ``temp_dir``, containing the library's media files. Same as ``config['directory']``. - ``config`` The global configuration used by beets. - ``lib`` Library instance created with the settings from ``config``. Make sure you call ``teardown_beets()`` afterwards. """ self.create_temp_dir() os.environ['BEETSDIR'] = self.temp_dir self.config = beets.config self.config.clear() self.config.read() self.config['plugins'] = [] self.config['verbose'] = True self.config['color'] = False self.config['threaded'] = False self.libdir = os.path.join(self.temp_dir, 'libdir') os.mkdir(self.libdir) self.config['directory'] = self.libdir if disk: dbpath = self.config['library'].as_filename() else: dbpath = ':memory:' self.lib = Library(dbpath, self.libdir) def teardown_beets(self): del self.lib._connections if 'BEETSDIR' in os.environ: del os.environ['BEETSDIR'] self.remove_temp_dir() self.config.clear() beets.config.read(user=False, defaults=True) def load_plugins(self, *plugins): """Load and initialize plugins by names. Similar setting a list of plugins in the configuration. Make sure you call ``unload_plugins()`` afterwards. """ beets.config['plugins'] = plugins beets.plugins.load_plugins(plugins) beets.plugins.find_plugins() def unload_plugins(self): """Unload all plugins and remove the from the configuration. """ beets.config['plugins'] = [] for plugin in beets.plugins._classes: plugin.listeners = None beets.plugins._classes = set() beets.plugins._instances = {} def create_importer(self, item_count=1, album_count=1): """Create files to import and return corresponding session. Copies the specified number of files to a subdirectory of `self.temp_dir` and creates a `TestImportSession` for this path. """ import_dir = os.path.join(self.temp_dir, 'import') if not os.path.isdir(import_dir): os.mkdir(import_dir) album_no = 0 while album_count: album = u'album {0}'.format(album_no) album_dir = os.path.join(import_dir, album) if os.path.exists(album_dir): album_no += 1 continue os.mkdir(album_dir) album_count -= 1 track_no = 0 album_item_count = item_count while album_item_count: title = 'track {0}'.format(track_no) src = os.path.join(_common.RSRC, 'full.mp3') dest = os.path.join(album_dir, '{0}.mp3'.format(title)) if os.path.exists(dest): track_no += 1 continue album_item_count -= 1 shutil.copy(src, dest) mediafile = MediaFile(dest) mediafile.update({ 'artist': 'artist', 'albumartist': 'album artist', 'title': title, 'album': album, 'mb_albumid': None, 'mb_trackid': None, }) mediafile.save() config['import']['quiet'] = True config['import']['autotag'] = False config['import']['resume'] = False return TestImportSession(self.lib, logfile=None, query=None, paths=[import_dir]) def add_item_fixtures(self, ext='mp3', count=1): """Add a number of items with files to the database. """ items = [] path = os.path.join(_common.RSRC, 'full.' + ext) for i in range(count): item = Item.from_path(str(path)) item.album = u'\u00e4lbum {0}'.format(i) # Check unicode paths item.title = u't\u00eftle {0}'.format(i) item.add(self.lib) item.move(copy=True) item.store() items.append(item) return items def add_album_fixture(self, track_count=1, ext='mp3'): """Add an album with files to the database. """ items = [] path = os.path.join(_common.RSRC, 'full.' + ext) for i in range(track_count): item = Item.from_path(str(path)) item.album = u'\u00e4lbum' # Check unicode paths item.title = u't\u00eftle {0}'.format(i) item.add(self.lib) item.move(copy=True) item.store() items.append(item) return self.lib.add_album(items) def create_mediafile_fixture(self, ext='mp3'): """Copies a fixture mediafile with the extension to a temporary location and returns the path. It keeps track of the created locations and will delete the with `remove_mediafile_fixtures()` """ src = os.path.join(_common.RSRC, 'full.' + ext) handle, path = mkstemp() os.close(handle) shutil.copyfile(src, path) if not hasattr(self, '_mediafile_fixtures'): self._mediafile_fixtures = [] self._mediafile_fixtures.append(path) return path def remove_mediafile_fixtures(self): if hasattr(self, '_mediafile_fixtures'): for path in self._mediafile_fixtures: os.remove(path) def run_command(self, *args): if hasattr(self, 'lib'): lib = self.lib else: lib = Library(':memory:') beets.ui._raw_main(list(args), lib) def run_with_output(self, *args): with capture_stdout() as out: self.run_command(*args) return out.getvalue() def create_temp_dir(self): """Create a temporary directory and assign it into `self.temp_dir`. Call `remove_temp_dir` later to delete it. """ self.temp_dir = mkdtemp() def remove_temp_dir(self): """Delete the temporary directory created by `create_temp_dir`. """ shutil.rmtree(self.temp_dir)
class TestHelper(object): """Helper mixin for high-level cli and plugin tests. This mixin provides methods to isolate beets' global state provide fixtures. """ # TODO automate teardown through hook registration def setup_beets(self, disk=False): """Setup pristine global configuration and library for testing. Sets ``beets.config`` so we can safely use any functionality that uses the global configuration. All paths used are contained in a temporary directory Sets the following properties on itself. - ``temp_dir`` Path to a temporary directory containing all files specific to beets - ``libdir`` Path to a subfolder of ``temp_dir``, containing the library's media files. Same as ``config['directory']``. - ``config`` The global configuration used by beets. - ``lib`` Library instance created with the settings from ``config``. Make sure you call ``teardown_beets()`` afterwards. """ self.create_temp_dir() os.environ['BEETSDIR'] = self.temp_dir self.config = beets.config self.config.clear() self.config.read() self.config['plugins'] = [] self.config['verbose'] = 1 self.config['ui']['color'] = False self.config['threaded'] = False self.libdir = os.path.join(self.temp_dir, 'libdir') os.mkdir(self.libdir) self.config['directory'] = self.libdir if disk: dbpath = self.config['library'].as_filename() else: dbpath = ':memory:' self.lib = Library(dbpath, self.libdir) def teardown_beets(self): self.lib._close() if 'BEETSDIR' in os.environ: del os.environ['BEETSDIR'] self.remove_temp_dir() self.config.clear() beets.config.read(user=False, defaults=True) def load_plugins(self, *plugins): """Load and initialize plugins by names. Similar setting a list of plugins in the configuration. Make sure you call ``unload_plugins()`` afterwards. """ # FIXME this should eventually be handled by a plugin manager beets.config['plugins'] = plugins beets.plugins.load_plugins(plugins) beets.plugins.find_plugins() # Take a backup of the original _types to restore when unloading Item._original_types = dict(Item._types) Album._original_types = dict(Album._types) Item._types.update(beets.plugins.types(Item)) Album._types.update(beets.plugins.types(Album)) def unload_plugins(self): """Unload all plugins and remove the from the configuration. """ # FIXME this should eventually be handled by a plugin manager beets.config['plugins'] = [] beets.plugins._classes = set() beets.plugins._instances = {} Item._types = Item._original_types Album._types = Album._original_types def create_importer(self, item_count=1, album_count=1): """Create files to import and return corresponding session. Copies the specified number of files to a subdirectory of `self.temp_dir` and creates a `TestImportSession` for this path. """ import_dir = os.path.join(self.temp_dir, 'import') if not os.path.isdir(import_dir): os.mkdir(import_dir) album_no = 0 while album_count: album = u'album {0}'.format(album_no) album_dir = os.path.join(import_dir, album) if os.path.exists(album_dir): album_no += 1 continue os.mkdir(album_dir) album_count -= 1 track_no = 0 album_item_count = item_count while album_item_count: title = u'track {0}'.format(track_no) src = os.path.join(_common.RSRC, 'full.mp3') dest = os.path.join(album_dir, '{0}.mp3'.format(title)) if os.path.exists(dest): track_no += 1 continue album_item_count -= 1 shutil.copy(src, dest) mediafile = MediaFile(dest) mediafile.update({ 'artist': 'artist', 'albumartist': 'album artist', 'title': title, 'album': album, 'mb_albumid': None, 'mb_trackid': None, }) mediafile.save() config['import']['quiet'] = True config['import']['autotag'] = False config['import']['resume'] = False return TestImportSession(self.lib, loghandler=None, query=None, paths=[import_dir]) # Library fixtures methods def create_item(self, **values): """Return an `Item` instance with sensible default values. The item receives its attributes from `**values` paratmeter. The `title`, `artist`, `album`, `track`, `format` and `path` attributes have defaults if they are not given as parameters. The `title` attribute is formated with a running item count to prevent duplicates. The default for the `path` attribute respects the `format` value. The item is attached to the database from `self.lib`. """ item_count = self._get_item_count() values_ = { 'title': u't\u00eftle {0}', 'artist': u'the \u00e4rtist', 'album': u'the \u00e4lbum', 'track': item_count, 'format': 'MP3', } values_.update(values) values_['title'] = values_['title'].format(item_count) values_['db'] = self.lib item = Item(**values_) if 'path' not in values: item['path'] = 'audio.' + item['format'].lower() return item def add_item(self, **values): """Add an item to the library and return it. Creates the item by passing the parameters to `create_item()`. If `path` is not set in `values` it is set to `item.destination()`. """ # When specifying a path, store it normalized (as beets does # ordinarily). if 'path' in values: values['path'] = util.normpath(values['path']) item = self.create_item(**values) item.add(self.lib) # Ensure every item has a path. if 'path' not in values: item['path'] = item.destination() item.store() return item def add_item_fixture(self, **values): """Add an item with an actual audio file to the library. """ item = self.create_item(**values) extension = item['format'].lower() item['path'] = os.path.join(_common.RSRC, 'min.' + extension) item.add(self.lib) item.move(copy=True) item.store() return item def add_album(self, **values): item = self.add_item(**values) return self.lib.add_album([item]) def add_item_fixtures(self, ext='mp3', count=1): """Add a number of items with files to the database. """ # TODO base this on `add_item()` items = [] path = os.path.join(_common.RSRC, 'full.' + ext) for i in range(count): item = Item.from_path(bytes(path)) item.album = u'\u00e4lbum {0}'.format(i) # Check unicode paths item.title = u't\u00eftle {0}'.format(i) item.add(self.lib) item.move(copy=True) item.store() items.append(item) return items def add_album_fixture(self, track_count=1, ext='mp3'): """Add an album with files to the database. """ items = [] path = os.path.join(_common.RSRC, 'full.' + ext) for i in range(track_count): item = Item.from_path(bytes(path)) item.album = u'\u00e4lbum' # Check unicode paths item.title = u't\u00eftle {0}'.format(i) item.add(self.lib) item.move(copy=True) item.store() items.append(item) return self.lib.add_album(items) def create_mediafile_fixture(self, ext='mp3', images=[]): """Copies a fixture mediafile with the extension to a temporary location and returns the path. It keeps track of the created locations and will delete the with `remove_mediafile_fixtures()` `images` is a subset of 'png', 'jpg', and 'tiff'. For each specified extension a cover art image is added to the media file. """ src = os.path.join(_common.RSRC, 'full.' + ext) handle, path = mkstemp() os.close(handle) shutil.copyfile(src, path) if images: mediafile = MediaFile(path) imgs = [] for img_ext in images: img_path = os.path.join(_common.RSRC, 'image-2x3.{0}'.format(img_ext)) with open(img_path, 'rb') as f: imgs.append(Image(f.read())) mediafile.images = imgs mediafile.save() if not hasattr(self, '_mediafile_fixtures'): self._mediafile_fixtures = [] self._mediafile_fixtures.append(path) return path def remove_mediafile_fixtures(self): if hasattr(self, '_mediafile_fixtures'): for path in self._mediafile_fixtures: os.remove(path) def _get_item_count(self): if not hasattr(self, '__item_count'): count = 0 self.__item_count = count + 1 return count # Running beets commands def run_command(self, *args): if hasattr(self, 'lib'): lib = self.lib else: lib = Library(':memory:') beets.ui._raw_main(list(args), lib) def run_with_output(self, *args): with capture_stdout() as out: self.run_command(*args) return out.getvalue().decode('utf-8') # Safe file operations def create_temp_dir(self): """Create a temporary directory and assign it into `self.temp_dir`. Call `remove_temp_dir` later to delete it. """ self.temp_dir = mkdtemp() def remove_temp_dir(self): """Delete the temporary directory created by `create_temp_dir`. """ shutil.rmtree(self.temp_dir) def touch(self, path, dir=None, content=''): """Create a file at `path` with given content. If `dir` is given, it is prepended to `path`. After that, if the path is relative, it is resolved with respect to `self.temp_dir`. """ if dir: path = os.path.join(dir, path) if not os.path.isabs(path): path = os.path.join(self.temp_dir, path) parent = os.path.dirname(path) if not os.path.isdir(parent): os.makedirs(parent) with open(path, 'a+') as f: f.write(content) return path
class TestHelper(object): """Helper mixin for high-level cli and plugin tests. This mixin provides methods to isolate beets' global state provide fixtures. """ # TODO automate teardown through hook registration def setup_beets(self, disk=False): """Setup pristine global configuration and library for testing. Sets ``beets.config`` so we can safely use any functionality that uses the global configuration. All paths used are contained in a temporary directory Sets the following properties on itself. - ``temp_dir`` Path to a temporary directory containing all files specific to beets - ``libdir`` Path to a subfolder of ``temp_dir``, containing the library's media files. Same as ``config['directory']``. - ``config`` The global configuration used by beets. - ``lib`` Library instance created with the settings from ``config``. Make sure you call ``teardown_beets()`` afterwards. """ self.create_temp_dir() os.environ['BEETSDIR'] = util.py3_path(self.temp_dir) self.config = beets.config self.config.clear() self.config.read() self.config['plugins'] = [] self.config['verbose'] = 1 self.config['ui']['color'] = False self.config['threaded'] = False self.libdir = os.path.join(self.temp_dir, b'libdir') os.mkdir(self.libdir) self.config['directory'] = util.py3_path(self.libdir) if disk: dbpath = util.bytestring_path(self.config['library'].as_filename()) else: dbpath = ':memory:' self.lib = Library(dbpath, self.libdir) def teardown_beets(self): self.lib._close() if 'BEETSDIR' in os.environ: del os.environ['BEETSDIR'] self.remove_temp_dir() self.config.clear() beets.config.read(user=False, defaults=True) def load_plugins(self, *plugins): """Load and initialize plugins by names. Similar setting a list of plugins in the configuration. Make sure you call ``unload_plugins()`` afterwards. """ # FIXME this should eventually be handled by a plugin manager beets.config['plugins'] = plugins beets.plugins.load_plugins(plugins) beets.plugins.find_plugins() # Take a backup of the original _types and _queries to restore # when unloading. Item._original_types = dict(Item._types) Album._original_types = dict(Album._types) Item._types.update(beets.plugins.types(Item)) Album._types.update(beets.plugins.types(Album)) Item._original_queries = dict(Item._queries) Album._original_queries = dict(Album._queries) Item._queries.update(beets.plugins.named_queries(Item)) Album._queries.update(beets.plugins.named_queries(Album)) def unload_plugins(self): """Unload all plugins and remove the from the configuration. """ # FIXME this should eventually be handled by a plugin manager beets.config['plugins'] = [] beets.plugins._classes = set() beets.plugins._instances = {} Item._types = Item._original_types Album._types = Album._original_types Item._queries = Item._original_queries Album._queries = Album._original_queries def create_importer(self, item_count=1, album_count=1): """Create files to import and return corresponding session. Copies the specified number of files to a subdirectory of `self.temp_dir` and creates a `TestImportSession` for this path. """ import_dir = os.path.join(self.temp_dir, b'import') if not os.path.isdir(import_dir): os.mkdir(import_dir) album_no = 0 while album_count: album = util.bytestring_path(u'album {0}'.format(album_no)) album_dir = os.path.join(import_dir, album) if os.path.exists(album_dir): album_no += 1 continue os.mkdir(album_dir) album_count -= 1 track_no = 0 album_item_count = item_count while album_item_count: title = u'track {0}'.format(track_no) src = os.path.join(_common.RSRC, b'full.mp3') title_file = util.bytestring_path('{0}.mp3'.format(title)) dest = os.path.join(album_dir, title_file) if os.path.exists(dest): track_no += 1 continue album_item_count -= 1 shutil.copy(src, dest) mediafile = MediaFile(dest) mediafile.update({ 'artist': 'artist', 'albumartist': 'album artist', 'title': title, 'album': album, 'mb_albumid': None, 'mb_trackid': None, }) mediafile.save() config['import']['quiet'] = True config['import']['autotag'] = False config['import']['resume'] = False return TestImportSession(self.lib, loghandler=None, query=None, paths=[import_dir]) # Library fixtures methods def create_item(self, **values): """Return an `Item` instance with sensible default values. The item receives its attributes from `**values` paratmeter. The `title`, `artist`, `album`, `track`, `format` and `path` attributes have defaults if they are not given as parameters. The `title` attribute is formated with a running item count to prevent duplicates. The default for the `path` attribute respects the `format` value. The item is attached to the database from `self.lib`. """ item_count = self._get_item_count() values_ = { 'title': u't\u00eftle {0}', 'artist': u'the \u00e4rtist', 'album': u'the \u00e4lbum', 'track': item_count, 'format': 'MP3', } values_.update(values) values_['title'] = values_['title'].format(item_count) values_['db'] = self.lib item = Item(**values_) if 'path' not in values: item['path'] = 'audio.' + item['format'].lower() # mtime needs to be set last since other assignments reset it. item.mtime = 12345 return item def add_item(self, **values): """Add an item to the library and return it. Creates the item by passing the parameters to `create_item()`. If `path` is not set in `values` it is set to `item.destination()`. """ # When specifying a path, store it normalized (as beets does # ordinarily). if 'path' in values: values['path'] = util.normpath(values['path']) item = self.create_item(**values) item.add(self.lib) # Ensure every item has a path. if 'path' not in values: item['path'] = item.destination() item.store() return item def add_item_fixture(self, **values): """Add an item with an actual audio file to the library. """ item = self.create_item(**values) extension = item['format'].lower() item['path'] = os.path.join(_common.RSRC, util.bytestring_path('min.' + extension)) item.add(self.lib) item.move(operation=MoveOperation.COPY) item.store() return item def add_album(self, **values): item = self.add_item(**values) return self.lib.add_album([item]) def add_item_fixtures(self, ext='mp3', count=1): """Add a number of items with files to the database. """ # TODO base this on `add_item()` items = [] path = os.path.join(_common.RSRC, util.bytestring_path('full.' + ext)) for i in range(count): item = Item.from_path(path) item.album = u'\u00e4lbum {0}'.format(i) # Check unicode paths item.title = u't\u00eftle {0}'.format(i) # mtime needs to be set last since other assignments reset it. item.mtime = 12345 item.add(self.lib) item.move(operation=MoveOperation.COPY) item.store() items.append(item) return items def add_album_fixture(self, track_count=1, ext='mp3'): """Add an album with files to the database. """ items = [] path = os.path.join(_common.RSRC, util.bytestring_path('full.' + ext)) for i in range(track_count): item = Item.from_path(path) item.album = u'\u00e4lbum' # Check unicode paths item.title = u't\u00eftle {0}'.format(i) # mtime needs to be set last since other assignments reset it. item.mtime = 12345 item.add(self.lib) item.move(operation=MoveOperation.COPY) item.store() items.append(item) return self.lib.add_album(items) def create_mediafile_fixture(self, ext='mp3', images=[]): """Copies a fixture mediafile with the extension to a temporary location and returns the path. It keeps track of the created locations and will delete the with `remove_mediafile_fixtures()` `images` is a subset of 'png', 'jpg', and 'tiff'. For each specified extension a cover art image is added to the media file. """ src = os.path.join(_common.RSRC, util.bytestring_path('full.' + ext)) handle, path = mkstemp() os.close(handle) shutil.copyfile(src, path) if images: mediafile = MediaFile(path) imgs = [] for img_ext in images: file = util.bytestring_path('image-2x3.{0}'.format(img_ext)) img_path = os.path.join(_common.RSRC, file) with open(img_path, 'rb') as f: imgs.append(Image(f.read())) mediafile.images = imgs mediafile.save() if not hasattr(self, '_mediafile_fixtures'): self._mediafile_fixtures = [] self._mediafile_fixtures.append(path) return path def remove_mediafile_fixtures(self): if hasattr(self, '_mediafile_fixtures'): for path in self._mediafile_fixtures: os.remove(path) def _get_item_count(self): if not hasattr(self, '__item_count'): count = 0 self.__item_count = count + 1 return count # Running beets commands def run_command(self, *args, **kwargs): """Run a beets command with an arbitrary amount of arguments. The Library` defaults to `self.lib`, but can be overridden with the keyword argument `lib`. """ sys.argv = ['beet'] # avoid leakage from test suite args lib = None if hasattr(self, 'lib'): lib = self.lib lib = kwargs.get('lib', lib) beets.ui._raw_main(_convert_args(list(args)), lib) def run_with_output(self, *args): with capture_stdout() as out: self.run_command(*args) return util.text_string(out.getvalue()) # Safe file operations def create_temp_dir(self): """Create a temporary directory and assign it into `self.temp_dir`. Call `remove_temp_dir` later to delete it. """ temp_dir = mkdtemp() self.temp_dir = util.bytestring_path(temp_dir) def remove_temp_dir(self): """Delete the temporary directory created by `create_temp_dir`. """ shutil.rmtree(self.temp_dir) def touch(self, path, dir=None, content=''): """Create a file at `path` with given content. If `dir` is given, it is prepended to `path`. After that, if the path is relative, it is resolved with respect to `self.temp_dir`. """ if dir: path = os.path.join(dir, path) if not os.path.isabs(path): path = os.path.join(self.temp_dir, path) parent = os.path.dirname(path) if not os.path.isdir(parent): os.makedirs(util.syspath(parent)) with open(util.syspath(path), 'a+') as f: f.write(content) return path
class TestHelper(object): """Helper mixin for high-level cli and plugin tests. This mixin provides methods to isolate beets' global state provide fixtures. """ # TODO automate teardown through hook registration def setup_beets(self, disk=False): """Setup pristine global configuration and library for testing. Sets ``beets.config`` so we can safely use any functionality that uses the global configuration. All paths used are contained in a temporary directory Sets the following properties on itself. - ``temp_dir`` Path to a temporary directory containing all files specific to beets - ``libdir`` Path to a subfolder of ``temp_dir``, containing the library's media files. Same as ``config['directory']``. - ``config`` The global configuration used by beets. - ``lib`` Library instance created with the settings from ``config``. Make sure you call ``teardown_beets()`` afterwards. """ self.create_temp_dir() os.environ['BEETSDIR'] = self.temp_dir self.config = beets.config self.config.clear() self.config.read() self.config['plugins'] = [] self.config['verbose'] = True self.config['color'] = False self.config['threaded'] = False self.libdir = os.path.join(self.temp_dir, 'libdir') os.mkdir(self.libdir) self.config['directory'] = self.libdir if disk: dbpath = self.config['library'].as_filename() else: dbpath = ':memory:' self.lib = Library(dbpath, self.libdir) def teardown_beets(self): del self.lib._connections del os.environ['BEETSDIR'] self.remove_temp_dir() self.config.clear() beets.config.read(user=False, defaults=True) def load_plugins(self, *plugins): """Load and initialize plugins by names. Similar setting a list of plugins in the configuration. Make sure you call ``unload_plugins()`` afterwards. """ beets.config['plugins'] = plugins beets.plugins.load_plugins(plugins) beets.plugins.find_plugins() def unload_plugins(self): """Unload all plugins and remove the from the configuration. """ beets.config['plugins'] = [] for plugin in beets.plugins._classes: plugin.listeners = None beets.plugins._classes = set() beets.plugins._instances = {} def create_importer(self, item_count=1, album_count=1): """Returns import session with fixtures. Copies the specified number of files to a subdirectory of ``self.temp_dir`` and creates a ``TestImportSession`` for this path. """ import_dir = os.path.join(self.temp_dir, 'import') if not os.path.isdir(import_dir): os.mkdir(import_dir) for i in range(album_count): album = u'album {0}'.format(i) album_dir = os.path.join(import_dir, album) os.mkdir(album_dir) for j in range(item_count): title = 'track {0}'.format(j) src = os.path.join(_common.RSRC, 'full.mp3') dest = os.path.join(album_dir, '{0}.mp3'.format(title)) shutil.copy(src, dest) mediafile = MediaFile(dest) mediafile.update({ 'artist': 'artist', 'albumartist': 'album artist', 'title': title, 'album': album, 'mb_albumid': None, 'mb_trackid': None, }) mediafile.save() config['import']['quiet'] = True config['import']['autotag'] = False config['import']['resume'] = False return TestImportSession(self.lib, logfile=None, query=None, paths=[import_dir]) def add_item_fixtures(self, ext='mp3', count=1): """Add a number of items with files to the database. """ items = [] path = os.path.join(_common.RSRC, 'full.' + ext) for i in range(count): item = Item.from_path(str(path)) item.album = u'\xc3\xa4lbum {0}'.format(i) # Check unicode paths item.title = u't\xc3\x8ftle {0}'.format(i) item.add(self.lib) item.move(copy=True) item.store() items.append(item) return items def add_album_fixture(self, track_count=1): """Add an album with files to the database. """ items = [] path = os.path.join(_common.RSRC, 'full.mp3') for i in range(track_count): item = Item.from_path(str(path)) item.album = u'\u00e4lbum' # Check unicode paths item.title = u't\u00eftle {0}'.format(i) item.add(self.lib) item.move(copy=True) item.store() items.append(item) return self.lib.add_album(items) def create_mediafile_fixture(self, ext='mp3'): """Copies a fixture mediafile with the extension to a temporary location and returns the path. It keeps track of the created locations and will delete the with `remove_mediafile_fixtures()` """ src = os.path.join(_common.RSRC, 'full.' + ext) handle, path = mkstemp() os.close(handle) shutil.copyfile(src, path) if not hasattr(self, '_mediafile_fixtures'): self._mediafile_fixtures = [] self._mediafile_fixtures.append(path) return path def remove_mediafile_fixtures(self): if hasattr(self, '_mediafile_fixtures'): for path in self._mediafile_fixtures: os.remove(path) def run_command(self, *args): if hasattr(self, 'lib'): lib = self.lib else: lib = Library(':memory:') beets.ui._raw_main(list(args), lib) def create_temp_dir(self): """Create a temporary directory and assign it into `self.temp_dir`. Call `remove_temp_dir` later to delete it. """ self.temp_dir = mkdtemp() def remove_temp_dir(self): """Delete the temporary directory created by `create_temp_dir`. """ shutil.rmtree(self.temp_dir)