diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 4bee216..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include setup.py -include pavement.py -include paver-minilib.zip -include pygtktalog/locale/*/*/*.mo diff --git a/README.rst b/README.rst index 6048835..8ba85aa 100644 --- a/README.rst +++ b/README.rst @@ -1,131 +1,74 @@ -pyGTKtalog +pycatalog ========== -Pygtktalog is Linux/FreeBSD program for indexing CD, DVD, BR or directories on -filesystem. It is similar to `gtktalog`_ or `gwhere`_. There is no coincidence -in name of application, because it's meant to be replacement (in some way) for -gtktalog, which seems to be dead project for years. +Pycatalog is a commandline Linux/FreeBSD program for indexing CD, DVD, BR or +directories on filesystem. It is similar to `gtktalog`_ or `gwhere`_. There is +no coincidence in name of application, because it's meant to be replacement +(in some way) for gtktalog, which seems to be dead project for years. -Current version is 2.0. +Note, that even if it share same code base with pyGTKtalog, which was meant to +be desktop application, now pycatalog is pure console app, just for use with +commandline. You can find last version of pyGTKtalog under ``pyGTKtalog`` +branch, although bear in mind, that it was written with `python 2.7`_ and +pyGTK_, which both are dead now. -FEATURES +Current version is 3.0. + +Features -------- * Scan for files in selected media * Support for grouping files depending on file name (expected patterns in file names) -* Get/generate thumbnails from EXIF and other images * Store selected EXIF tags * Add/edit description and notes * Fetch comments for images made in `gThumb`_ -* Add/remove unlimited images to any file or directory * `Tagging files`_ * And more :) -Frontends ---------- - -New version of pyGTKtalog was meant to use multiple interfaces. - -#. First for the new incarnation of pyGTKtalog is… command line tool for - accessing catalog dbs. With ``cmdcatalog.py`` it's possible to: - - * create new catalog - * update it - * list - * find files - * fsck (for maintenance for orphaned thumbs/images) - -#. ``gtktalog.py``. This is written from scratch frontend in pygtk. Still work - in progress. - Requirements ------------ -pyGTKtalog requires python and following libraries: +pycatalog requires python and following libraries: -* `python 3`_, tested on python 3.6 -* `sqlalchemy 1.2`_ or higher -* `pygtk 2.24`_ (only for ``gtktalog.py``, will not work with python3) -* `pillow`_ for image manipulation +* `python 3.10`_ and up +* `sqlalchemy 1.4`_ * `exifread`_ for parse EXIF information -It may work on other (lower) version of libraries, and it should work with -higher versions of libraries. GTK3 support will follow. - -pyGTKtalog extensively uses external programs in unix spirit, however there is +Pycatalog extensively uses external programs in unix spirit, however there is small possibility of using it Windows (probably with limitations) and quite big possibility to run it on other sophisticated unix-like systems (i.e. BeOS/ZETA/Haiku, QNX or MacOSX). Programs that are used: -* ``mencoder`` (provided by `mplayer`_ package) -* ``montage``, ``convert`` from `ImageMagick`_ +* ``midentify`` (provided by `mplayer`_ package) For development process following programs are used: -* `gettext`_ -* `intltool`_ * `nose`_ * `coverage`_ -* `paver`_ * `tox`_ -INSTALATION +Instalation ----------- You don't have to install it if you don't want to. You can just change current -directory to pyGTKtalog and simply run:: +directory to pycatalog and simply run:: $ paver run That's it. Alternatively, if you like to put it in more system wide place, all you have to do is: -#. put pyGTKtalog directory into your destination of choice (/usr/local/share, +#. put pycatalog directory into your destination of choice (/usr/local/share, /opt or ~/ is typical bet) -#. copy pyGTKtalog shell script to /usr/bin, /usr/local/bin or in +#. copy pycatalog shell script to /usr/bin, /usr/local/bin or in other place, where PATH variable is pointing or you feel like. -#. then modify pyGTKtalog line 6 to match right ``pygtktalog.py`` directory +#. then modify pycatalog line 6 to match right ``pycatalog.py`` directory -Then, just run pyGTKtalog script. - -Technical details ------------------ - -Catalog file is plain sqlite database (optionally compressed with bzip2). All -images are stored in location pointed by db entry in ``config`` table - it is -assumed, that images directory will be placed within the root directory, where -the main db lies. -Generated sha512 hash from image file itself. There is small possibility for two -identical hash for different image files. However, no images are overwritten. -Thumbnail filename for each image is simply concatenation of image filename in -images directory and '_t' string. - -There is also converter from old database to new for internal use only. In -public release there will be no other formats so it will be useless, and -deleted. There are some issues with converting. All thumbnails will be lost. -All images without big image will be lost. There are serious changes with -application design, and I decided, that is better to keep media unpacked on -disk, instead of pack it every time with save and unpack with open methods. New -design prevent from deleting any file from media directory (placed in -``~/.pygtktalog/images``). Functionality for exporting images and corresponding -db file is planned. - - -DEVELOPMENT ------------ - -Several tools has been used to develop pyGTKtalog. - -Paver -^^^^^ - -I've choose `Paver`_ as make equivalent. Inside main project directory there is -``pavement.py`` script, which provides several tasks, that can be helpful in a work -with sources. Paver is also used to generate standard ``setup.py``. +Then, just run pycatalog script. LICENSE ======= @@ -136,18 +79,12 @@ file in top-level directory. .. _coverage: http://nedbatchelder.com/code/coverage/ .. _exifread: https://github.com/ianare/exif-py -.. _gettext: http://www.gnu.org/software/gettext/gettext.html .. _gthumb: http://gthumb.sourceforge.net .. _gtktalog: http://www.nongnu.org/gtktalog/ .. _gwhere: http://www.gwhere.org/home.php3 -.. _imagemagick: http://imagemagick.org/script/index.php -.. _intltool: http://www.gnome.org/ .. _mplayer: http://mplayerhq.hu .. _nose: http://code.google.com/p/python-nose/ -.. _paver: https://pythonhosted.org/paver/ -.. _pillow: https://python-pillow.org/ -.. _pygtk 2.24: http://www.pygtk.org -.. _python 3: http://www.python.org/ -.. _sqlalchemy 1.2: http://www.sqlalchemy.org +.. _python 3.10: http://www.python.org/ +.. _sqlalchemy 1.4: http://www.sqlalchemy.org .. _tagging files: http://en.wikipedia.org/wiki/tag_%28metadata%29 .. _tox: https://testrun.org/tox diff --git a/scripts/cmdcatalog.py b/pycatalog/__init__.py old mode 100755 new mode 100644 similarity index 98% rename from scripts/cmdcatalog.py rename to pycatalog/__init__.py index f68858c..0ad9b41 --- a/scripts/cmdcatalog.py +++ b/pycatalog/__init__.py @@ -1,6 +1,5 @@ -#!/usr/bin/env python """ -Fast and ugly CLI interface for pyGTKtalog +Fast and ugly CLI interface """ import argparse import os @@ -9,11 +8,11 @@ import sys from sqlalchemy import or_ -from pygtktalog import scan -from pygtktalog import misc -from pygtktalog import dbobjects as dbo -from pygtktalog.dbcommon import connect, Session -from pygtktalog import logger +from pycatalog import scan +from pycatalog import misc +from pycatalog import dbobjects as dbo +from pycatalog.dbcommon import connect, Session +from pycatalog import logger BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(30, 38) @@ -418,6 +417,7 @@ def add_dir(args): def create_db(args): """List""" + __import__('pdb').set_trace() obj = Iface(args.db, args.pretend, args.debug) obj.create(args.dir_to_add, args.imagedir) obj.close() @@ -516,6 +516,5 @@ def main(): parser.print_help() - if __name__ == '__main__': main() diff --git a/pygtktalog/dbcommon.py b/pycatalog/dbcommon.py similarity index 96% rename from pygtktalog/dbcommon.py rename to pycatalog/dbcommon.py index cb1ad1f..0355599 100644 --- a/pygtktalog/dbcommon.py +++ b/pycatalog/dbcommon.py @@ -9,7 +9,7 @@ from sqlalchemy import MetaData, create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base -from pygtktalog.logger import get_logger +from pycatalog.logger import get_logger # Prepare SQLAlchemy objects diff --git a/pygtktalog/dbobjects.py b/pycatalog/dbobjects.py similarity index 98% rename from pygtktalog/dbobjects.py rename to pycatalog/dbobjects.py index 39d5e3c..8cac4c1 100644 --- a/pygtktalog/dbobjects.py +++ b/pycatalog/dbobjects.py @@ -12,10 +12,10 @@ from sqlalchemy import Column, Table, Integer, Text from sqlalchemy import DateTime, ForeignKey, Sequence from sqlalchemy.orm import relation, backref -from pygtktalog.dbcommon import Base -from pygtktalog.thumbnail import ThumbCreator -from pygtktalog.logger import get_logger -from pygtktalog.misc import mk_paths +from pycatalog.dbcommon import Base +from pycatalog.thumbnail import ThumbCreator +from pycatalog.logger import get_logger +from pycatalog.misc import mk_paths LOG = get_logger(__name__) diff --git a/pygtktalog/logger.py b/pycatalog/logger.py similarity index 95% rename from pygtktalog/logger.py rename to pycatalog/logger.py index 0301d60..80a829c 100644 --- a/pygtktalog/logger.py +++ b/pycatalog/logger.py @@ -71,12 +71,12 @@ def get_logger(module_name, level='INFO', to_file=True, to_console=True): @level - Log level (as string), one of DEBUG, INFO, WARN, ERROR and CRITICAL. @to_file - If True, additionally stores full log in file inside - .pygtktalog config directory and to stderr, otherwise log + .pycatalog config directory and to stderr, otherwise log is only redirected to stderr. Returns: object of logging.Logger class """ - path = os.path.join(os.path.expanduser("~"), ".pygtktalog", "app.log") + path = os.path.join(os.path.expanduser("~"), ".pycatalog", "app.log") log = logging.getLogger(module_name) log.setLevel(LEVEL[level]) diff --git a/pygtktalog/misc.py b/pycatalog/misc.py similarity index 95% rename from pygtktalog/misc.py rename to pycatalog/misc.py index c3eb8a0..3bd3ac3 100644 --- a/pygtktalog/misc.py +++ b/pycatalog/misc.py @@ -9,8 +9,8 @@ import os import errno from zlib import crc32 -import pygtktalog.dbcommon -from pygtktalog.logger import get_logger +import pycatalog.dbcommon +from pycatalog.logger import get_logger LOG = get_logger(__name__) @@ -33,7 +33,7 @@ def float_to_string(float_length): def calculate_image_path(dbpath=None, create=False): """Calculate image path out of provided path or using current connection""" if not dbpath: - dbpath = pygtktalog.dbcommon.DbFilename + dbpath = pycatalog.dbcommon.DbFilename if dbpath == ":memory:": raise OSError("Cannot create image path out of in-memory db!") diff --git a/pygtktalog/pygtkutils.py b/pycatalog/pygtkutils.py similarity index 100% rename from pygtktalog/pygtkutils.py rename to pycatalog/pygtkutils.py diff --git a/pygtktalog/scan.py b/pycatalog/scan.py similarity index 97% rename from pygtktalog/scan.py rename to pycatalog/scan.py index 0f38bb2..94224b1 100644 --- a/pygtktalog/scan.py +++ b/pycatalog/scan.py @@ -10,11 +10,11 @@ import re from datetime import datetime import mimetypes -import pygtktalog.misc -from pygtktalog.dbobjects import File, Image, Thumbnail, Config, TYPE -from pygtktalog.dbcommon import Session -from pygtktalog.logger import get_logger -from pygtktalog.video import Video +import pycatalog.misc +from pycatalog.dbobjects import File, Image, Thumbnail, Config, TYPE +from pycatalog.dbcommon import Session +from pycatalog.logger import get_logger +from pycatalog.video import Video LOG = get_logger(__name__) @@ -476,9 +476,9 @@ class Scan(object): image_path = (self._session.query(Config) .filter(Config.key == "image_path")).one() if image_path.value == ":same_as_db:": - image_path = pygtktalog.misc.calculate_image_path() + image_path = pycatalog.misc.calculate_image_path() else: - image_path = pygtktalog.misc.calculate_image_path(image_path.value) + image_path = pycatalog.misc.calculate_image_path(image_path.value) self.img_path = image_path diff --git a/pygtktalog/thumbnail.py b/pycatalog/thumbnail.py similarity index 98% rename from pygtktalog/thumbnail.py rename to pycatalog/thumbnail.py index 57d9a98..87cce00 100644 --- a/pygtktalog/thumbnail.py +++ b/pycatalog/thumbnail.py @@ -13,7 +13,7 @@ import shutil from PIL import Image import exifread -from pygtktalog.logger import get_logger +from pycatalog.logger import get_logger LOG = get_logger(__name__) diff --git a/pygtktalog/video.py b/pycatalog/video.py similarity index 99% rename from pygtktalog/video.py rename to pycatalog/video.py index 4ab617f..519120e 100644 --- a/pygtktalog/video.py +++ b/pycatalog/video.py @@ -208,7 +208,7 @@ class Video(object): @no_pictures - number of pictures timeit result: python /usr/lib/python2.6/timeit.py -n 1 -r 1 'from \ - pygtktalog.video import Video; v = Video("/home/gryf/t/a.avi"); \ + pycatalog.video import Video; v = Video("/home/gryf/t/a.avi"); \ v.capture()' 1 loops, best of 1: 18.8 sec per loop """ diff --git a/pygtktalog/__init__.py b/pygtktalog/__init__.py deleted file mode 100644 index 338d6f0..0000000 --- a/pygtktalog/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" - Project: pyGTKtalog - Description: Initialization for main module - i18n and so. - Type: core - Author: Roman 'gryf' Dobosz, gryf73@gmail.com - Created: 2009-05-05 -""" -__version__ = "3.0.0" -__appname__ = "pyGTKtalog" -__copyright__ = "\u00A9 Roman 'gryf' Dobosz" -__summary__ = "%s is simple tool for managing file collections." % __appname__ -__web__ = "http://github.com/gryf/pygtktalog" - -__all__ = ['dbcommon', - 'dbobjects', - 'dialogs', - 'logger', - 'misc'] diff --git a/pygtktalog/gtk2/__init__.py b/pygtktalog/gtk2/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pygtktalog/gtk2/gui.py b/pygtktalog/gtk2/gui.py deleted file mode 100644 index e2ae55b..0000000 --- a/pygtktalog/gtk2/gui.py +++ /dev/null @@ -1,257 +0,0 @@ -# -*- coding: utf-8 -*- - -import gtk - -from pygtktalog import logger - -UI = """ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""" -LOG = logger.get_logger(__name__) -LOG.setLevel(2) - - -class ConnectedWidgets(object): - """grouped widgets""" - def __init__(self, toolbar, menu): - super(ConnectedWidgets, self).__init__() - self.toolbar = toolbar - self.menu = menu - - def hide(self): - self.toolbar.hide() - self.menu.hide() - - def show(self): - self.toolbar.show() - self.menu.show() - - def set_sensitive(self, state): - self.toolbar.set_sensitive(state) - self.menu.set_sensitive(state) - - -class MainWindow(object): - - def __init__(self, debug=False): - """Initialize window""" - LOG.debug("initialize") - self.window = gtk.Window() - self.window.set_default_size(650, -1) - self.window.set_title("pygtktalog") - self.window.connect("delete-event", self.on_quit) - - self.recent = None - self.toolbar = None - self.statusbar = None - self.cancel = None - self.debug = None - - vbox = gtk.VBox(False, 0) - - self._setup_menu_toolbar(vbox) - - # TODO: - # 1. toolbar with selected tags - # 2. main view (splitter) - # 3. treeview with tag cloud (left split) - # 4. splitter (right split) - # 5. file list (upper split) - # 6. details w images and thumb (lower split) - # 7. status bar (if needed…) - - hbox = gtk.HBox(False, 0) - vbox.add(hbox) - - self.window.add(vbox) - self.window.show_all() - self.debug.hide() - - def fake_recent(self): - recent_menu = gtk.Menu() - for i in "one two techno foo bar baz".split(): - item = gtk.MenuItem(i) - item.connect_object("activate", self.on_recent, - "/some/fake/path/" + i) - recent_menu.append(item) - item.show() - self.recent.set_submenu(recent_menu) - - def _setup_menu_toolbar(self, vbox): - """Create menu/toolbar using uimanager.""" - actions = [('File', None, '_File'), - ('New', gtk.STOCK_NEW, '_New', None, - 'Create new catalog', self.on_new), - ('Open', gtk.STOCK_OPEN, '_Open', None, - 'Open catalog file', self.on_open), - ('Save', gtk.STOCK_SAVE, '_Save', None, - 'Save catalog file', self.on_save), - ('Save As', gtk.STOCK_SAVE_AS, - '_Save As', None, None, self.on_save), - ('Import', None, '_Import', None, None, self.on_import), - ('Export', None, '_Export', None, None, self.on_export), - ('Recent', None, '_Recent files'), - ('Quit', gtk.STOCK_QUIT, '_Quit', None, - 'Quit the Program', self.on_quit), - ('Edit', None, '_Edit'), - ('Delete', gtk.STOCK_DELETE, '_Delete', None, None, - self.on_delete), - ('Find', gtk.STOCK_FIND, '_Find', None, 'Find file', - self.on_find), - ('Preferences', gtk.STOCK_PREFERENCES, '_Preferences'), - ('Catalog', None, '_Catalog'), - ('Add_CD', gtk.STOCK_CDROM, '_Add CD', None, - 'Add CD/DVD/BR to catalog'), - ('Add_Dir', gtk.STOCK_DIRECTORY, '_Add Dir', None, - 'Add directory to catalog'), - ('Delete_all_images', None, '_Delete all images'), - ('Delete_all_thumbnails', None, '_Delete all thumbnails'), - ('Save_all_images', None, '_Save all images…'), - ('Catalog_statistics', None, '_Catalog statistics'), - ('Cancel', gtk.STOCK_CANCEL, '_Cancel'), - ('View', None, '_View'), - ('Help', None, '_Help'), - ('About', gtk.STOCK_ABOUT, '_About'), - ('Debug', gtk.STOCK_DIALOG_INFO, 'Debug')] - - toggles = [('Toolbar', None, '_Toolbar'), - ('Statusbar', None, '_Statusbar')] - - mgr = gtk.UIManager() - accelgrp = mgr.get_accel_group() - self.window.add_accel_group(accelgrp) - - agrp = gtk.ActionGroup("Actions") - agrp.add_actions(actions) - agrp.add_toggle_actions(toggles) - - mgr.insert_action_group(agrp, 0) - mgr.add_ui_from_string(UI) - - help_widget = mgr.get_widget("/MenuBar/Help") - help_widget.set_right_justified(True) - - self.recent = mgr.get_widget("/MenuBar/File/Recent") - self.fake_recent() - - menubar = mgr.get_widget("/MenuBar") - vbox.pack_start(menubar) - self.toolbar = mgr.get_widget("/ToolBar") - vbox.pack_start(self.toolbar) - - menu_cancel = mgr.get_widget('/MenuBar/Catalog/Cancel') - toolbar_cancel = mgr.get_widget('/ToolBar/Cancel') - self.cancel = ConnectedWidgets(toolbar_cancel, menu_cancel) - self.cancel.set_sensitive(False) - - self.debug = mgr.get_widget('/ToolBar/Debug') - - self.toolbar = mgr.get_widget('/MenuBar/View/Toolbar') - self.statusbar = mgr.get_widget('/MenuBar/View/Statusbar') - - def on_new(self, *args, **kwargs): - LOG.debug("On new") - return - - def on_open(self, *args, **kwargs): - LOG.debug("On open") - return - - def on_save(self, *args, **kwargs): - LOG.debug("On save") - return - - def on_save_as(self, *args, **kwargs): - LOG.debug("On save as") - return - - def on_import(self, *args, **kwargs): - LOG.debug("On import") - return - - def on_export(self, *args, **kwargs): - LOG.debug("On export") - return - - def on_recent(self, *args, **kwargs): - LOG.debug("On recent") - print args, kwargs - - def on_quit(self, *args, **kwargs): - LOG.debug("on quit") - gtk.main_quit() - - def on_delete(self, *args, **kwargs): - LOG.debug("On delete") - return - - def on_find(self, *args, **kwargs): - LOG.debug("On find") - return - - def on_about(self, event, menuitem): - LOG.debug("about", event, menuitem) - return - - -def run(): - MainWindow() - gtk.mainloop() diff --git a/scripts/gtktalog.py b/scripts/gtktalog.py deleted file mode 100755 index c80167e..0000000 --- a/scripts/gtktalog.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -""" - Project: pyGTKtalog - Description: Main gui file launcher - Type: UI - Author: Roman 'gryf' Dobosz, gryf73@gmail.com - Created: 2016-08-19 -""" -import sys -import tempfile -import os - -from pygtktalog.dbobjects import File, Config -from pygtktalog.dbcommon import connect, Session -from pygtktalog.gtk2 import gui - - -class App(object): - """Main app class""" - - def __init__(self, dbname): - """Initialze""" - self._dbname = None - self.sess = Session() - - if dbname: - self._dbname = dbname - self.engine = connect(dbname) - else: - self._create_tmp_db() - - self.root = None - self._dbname = dbname - - def _create_tmp_db(self): - """Create temporatry db, untill user decide to save it""" - fdsc, self._tmpdb = tempfile.mkstemp() - os.close(fdsc) - self.engine = connect(self._tmpdb) - - self.root = File() - self.root.id = 1 - self.root.filename = 'root' - self.root.size = 0 - self.root.source = 0 - self.root.type = 0 - self.root.parent_id = 1 - - config = Config() - config.key = "image_path" - config.value = ":same_as_db:" - - self.sess.add(self.root) - self.sess.add(config) - self.sess.commit() - - def run(self): - """Initialize gui""" - gui.run() - - -def main(): - db = sys.argv if len(sys.argv) == 2 else None - app = App(db) - app.run() - - -if __name__ == "__main__": - main() diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..4c3204c --- /dev/null +++ b/setup.cfg @@ -0,0 +1,41 @@ +[metadata] +name = pycatalog +summary = Catalog application for keeping content list of disks and discs +description_file = README.rst +author = Roman Dobosz +author_email = gryf73@gmail.com +home_page = https://github.com/gryf/pycatalog +license = BSD +keywords = catalog, gwhere, collection +classifier = + Development Status :: 4 - Beta + Environment :: Console + Intended Audience :: End Users/Desktop + License :: OSI Approved :: BSD License + Operating System :: POSIX :: Linux + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Topic :: Database + Topic :: Desktop Environment + +[install] +record = install.log + +[options.entry_points] +console_scripts = + pycatalog = pycatalog:main + +[files] +packages = + pycatalog + +[options] +install_requires = + pillow + sqlalchemy + +[bdist_wheel] +universal = 1 diff --git a/setup.py b/setup.py index 2447dd6..89f4891 100755 --- a/setup.py +++ b/setup.py @@ -1,31 +1,5 @@ -#!/usr/bin/env python2 -""" -Setup for the pyGTKtalog project -""" -from distutils.core import setup +#!/usr/bin/env python +import setuptools -setup(name='pygtktalog', - packages=['pygtktalog'], - version='3.0', - description='Catalog application with GTK interface', - author='Roman Dobosz', - author_email='gryf73@gmail.com', - url='https://github.com/gryf/pygtktalog', - download_url='https://github.com/gryf/pygtktalog.git', - keywords=['catalog', 'gwhere', 'where is it', 'collection', 'GTK'], - requires=['Pillow', 'sqlalchemy'], - scripts=['scripts/cmdcatalog.py'], - classifiers=['Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Intended Audience :: End Users/Desktop', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Topic :: Multimedia :: Graphics'], - long_description=open('README.rst').read(), - options={'test': {'verbose': False, - 'coverage': False}}) +setuptools.setup(setup_requires=['pbr>=2.0.0'], pbr=True)