diff --git a/.gitignore b/.gitignore index 43ae0e2..4d80ee3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ __pycache__/ *.py[cod] +.coverage +.tox +tags +MANIFEST +.cache +pygtktalog.egg-info diff --git a/pygtktalog/__init__.py b/pygtktalog/__init__.py index 0446619..adafbb2 100644 --- a/pygtktalog/__init__.py +++ b/pygtktalog/__init__.py @@ -6,12 +6,11 @@ Created: 2009-05-05 """ -__version__ = "1.9.0" +__version__ = "2.0.0" __appname__ = "pyGTKtalog" __copyright__ = u"\u00A9 Roman 'gryf' Dobosz" __summary__ = "%s is simple tool for managing file collections." % __appname__ -__web__ = "http://bitbucket.org/gryf" -__logo_img__ = "views/pixmaps/Giant Worms.png" +__web__ = "http://github.com/gryf/pygtktalog" import os import sys @@ -19,15 +18,10 @@ import locale import gettext import __builtin__ -import gtk.glade - from pygtktalog.logger import get_logger -__all__ = ['controllers', - 'models', - 'views', - 'EXIF', +__all__ = ['EXIF', 'dbcommon', 'dbobjects', 'dialogs', @@ -48,12 +42,12 @@ except locale.Error: # unknown locale string, fallback to C locale.setlocale(locale.LC_ALL, 'C') -for module in gtk.glade, gettext: - if os.path.exists(LOCALE_PATH): - module.bindtextdomain(GETTEXT_DOMAIN, LOCALE_PATH) - else: - module.bindtextdomain(GETTEXT_DOMAIN) - module.textdomain(GETTEXT_DOMAIN) +# for module in gtk.glade, gettext: +# if os.path.exists(LOCALE_PATH): +# module.bindtextdomain(GETTEXT_DOMAIN, LOCALE_PATH) +# else: +# module.bindtextdomain(GETTEXT_DOMAIN) +# module.textdomain(GETTEXT_DOMAIN) # register the gettext function for the whole interpreter as "_" __builtin__._ = gettext.gettext diff --git a/pygtktalog/dialogs.py b/pygtktalog/dialogs.py deleted file mode 100644 index cee3d7c..0000000 --- a/pygtktalog/dialogs.py +++ /dev/null @@ -1,231 +0,0 @@ -""" - Project: pyGTKtalog - Description: Simple dialogs for interact with user - Type: helper - Author: Roman 'gryf' Dobosz, gryf73@gmail.com - Created: 2009-05-12 -""" -import os - -import gtk - -import pygtktalog - - -class Dialog(object): - """ - Show simple dialog for questions - Returns: Bool - True, if "OK" button pressed, False otherwise. - """ - - def __init__(self, dialog_type, message, secondary_msg="", title=""): - """ - Initialize some defaults - """ - self.dialog = None - self.buttons = gtk.BUTTONS_OK - self.ok_default = False - self.message = message - self.secondary_msg = secondary_msg - self.type = dialog_type - self.title = title - - def run(self): - """Show the dialog""" - if self.dialog is None: - self._create_dialog() - - # Change default/focus from cancel/no to ok/yes. Suitable only for - # Question dialog. - # Ofcourse, if something changes in the future, this could break - # things. - if self.ok_default: - # this is tricky: Ok/Yes buttons appears as first on the list, but - # they are visibile in oposite order. This could be a bug. - button = self.dialog.get_action_area().get_children()[0] - button.grab_default() - - retval = self.dialog.run() - self.dialog.destroy() - if retval == gtk.RESPONSE_OK or retval == gtk.RESPONSE_YES: - return True - return False - - def _create_dialog(self): - """Create MessageDialog widgt""" - if self.type == gtk.MESSAGE_QUESTION and \ - self.buttons not in (gtk.BUTTONS_YES_NO, gtk.BUTTONS_OK_CANCEL): - self.buttons = gtk.BUTTONS_YES_NO - - self.dialog = gtk.MessageDialog(buttons=self.buttons, type=self.type, - message_format=self.message) - self.dialog.format_secondary_text(self.secondary_msg) - self.dialog.set_title(self.title) - - -class ChooseFile(object): - """ - Common file chooser - """ - URI = None - BUTTON_PAIRS = {'cancel': (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), - 'ok': (gtk.STOCK_OK, gtk.RESPONSE_APPLY), - 'save': (gtk.STOCK_SAVE, gtk.RESPONSE_APPLY), - 'open': (gtk.STOCK_OPEN, gtk.RESPONSE_APPLY)} - CHOOSER_TYPES = {'open': gtk.FILE_CHOOSER_ACTION_OPEN, - 'save': gtk.FILE_CHOOSER_ACTION_SAVE} - FILTERS = {'catalogs': {'name': "Catalog files", - 'patterns': ("*.sqlite", "*.sqlite.bz2")}, - 'all': {'name': "All files", 'patterns': ("*.*",)}} - - def __init__(self, title="", buttons=('cancel', 'ok'), path=None, - chooser_type="open"): - super(ChooseFile, self).__init__() - self.path = path - self.title = title - self.action = self.CHOOSER_TYPES[chooser_type] - self.buttons = [] - for button in buttons: - self.buttons.append(self.BUTTON_PAIRS[button][0]) - self.buttons.append(self.BUTTON_PAIRS[button][1]) - self.buttons = tuple(self.buttons) - self.confirmation = False - self.dialog = None - self.filters = [] - - def _mk_dialog(self): - """ - Create FileChooserDialog object - """ - self.dialog = gtk.FileChooserDialog(self.title, None, self.action, - self.buttons) - self.dialog.set_action(gtk.FILE_CHOOSER_ACTION_SAVE) - self.dialog.set_default_response(gtk.RESPONSE_OK) - self.dialog.set_do_overwrite_confirmation(self.confirmation) - self.dialog.set_title(self.title) - - if self.URI: - self.dialog.set_current_folder_uri(self.URI) - elif self.path and os.path.exists(self.path): - self.path = "file://" + os.path.abspath(self.path) - self.dialog.set_current_folder_uri(self.path) - - for filtr in self._get_filters(): - self.dialog.add_filter(filtr) - - def _get_filters(self): - """ - """ - filters = [] - for filter_def in self.filters: - filtr = gtk.FileFilter() - filtr.set_name(self.FILTERS[filter_def]['name']) - for pat in self.FILTERS[filter_def]['patterns']: - filtr.add_pattern(pat) - filters.append(filtr) - return filters - - def run(self): - """ - Show dialog, get response. - Returns: - - Returns: String - with filename, None otherwise. - """ - - if self.dialog is None: - self._mk_dialog() - - response = self.dialog.run() - filename = None - - if response == gtk.RESPONSE_APPLY: - filename = self.dialog.get_filename() - self.__class__.URI = self.dialog.get_current_folder_uri() - - self.dialog.destroy() - return filename - - -def yesno(message, secondarymsg="", title="", default=False): - """Question with yes-no buttons. Returns False on 'no', True on 'yes'""" - dialog = Dialog(gtk.MESSAGE_QUESTION, message, secondarymsg, title) - dialog.buttons = gtk.BUTTONS_YES_NO - dialog.ok_default = default - return dialog.run() - - -def okcancel(message, secondarymsg="", title="", default=False): - """Question with ok-cancel buttons. Returns False on 'cancel', True on - 'ok'""" - dialog = Dialog(gtk.MESSAGE_QUESTION, message, secondarymsg, title) - dialog.buttons = gtk.BUTTONS_OK_CANCEL - dialog.ok_default = default - return dialog.run() - - -def info(message, secondarymsg="", title="", button=gtk.BUTTONS_OK): - """Info dialog. Button defaults to gtk.BUTTONS_OK, but can be changed with - gtk.BUTTONS_CANCEL, gtk.BUTTONS_CLOSE or gtk.BUTTONS_NONE. - Always returns True.""" - dialog = Dialog(gtk.MESSAGE_INFO, message, secondarymsg, title) - dialog.buttons = button - dialog.run() - return True - - -def warn(message, secondarymsg="", title="", button=gtk.BUTTONS_OK): - """Warning dialog. Button defaults to gtk.BUTTONS_OK, but can be changed - with gtk.BUTTONS_CANCEL, gtk.BUTTONS_CLOSE or gtk.BUTTONS_NONE. - Always returns True.""" - dialog = Dialog(gtk.MESSAGE_WARNING, message, secondarymsg, title) - dialog.buttons = button - dialog.run() - return True - - -def error(message, secondarymsg="", title="", button=gtk.BUTTONS_OK): - """Error dialog. Button defaults to gtk.BUTTONS_OK, but can be changed with - gtk.BUTTONS_CANCEL, gtk.BUTTONS_CLOSE or gtk.BUTTONS_NONE. - Always returns True.""" - dialog = Dialog(gtk.MESSAGE_ERROR, message, secondarymsg, title) - dialog.buttons = button - dialog.run() - return True - - -def open_catalog(title=_("Open catalog"), path=None): - """ - Request filename from user to open. - Returns: string - full path and filename or None - """ - requester = ChooseFile(title) - requester.filters = ['catalogs', 'all'] - return requester.run() - - -def save_catalog(title=_("Open catalog"), path=None): - """ - Request filename from user for save. - Returns: string - full path and filename or None - """ - requester = ChooseFile(title, chooser_type="save") - requester.filters = ['catalogs', 'all'] - requester.confirmation = True - return requester.run() - - -def about(): - """ - Show About dialog - """ - dialog = gtk.AboutDialog() - dialog.set_version(pygtktalog.__version__) - dialog.set_program_name(pygtktalog.__appname__) - dialog.set_copyright(pygtktalog.__copyright__) - dialog.set_comments(pygtktalog.__summary__) - dialog.set_website(pygtktalog.__web__) - dialog.set_logo(gtk.gdk.pixbuf_new_from_file(\ - os.path.join(os.path.dirname(__file__), pygtktalog.__logo_img__))) - dialog.run() - dialog.destroy() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3a32ea1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +Pillow +exifread +sqlalchemy diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..f0d47e7 --- /dev/null +++ b/setup.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python2 +""" +Setup for the pyGTKtalog project +""" +from distutils.core import setup + + +setup(name='pygtktalog', + packages=['pygtktalog'], + version='2.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 :: 2 :: Only', + '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}}) diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..8bc49f6 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,4 @@ +pytest +pytest-cov +pytest-pep8 +coverage diff --git a/tests/dialogs_test.py b/tests/dialogs_test.py deleted file mode 100644 index 5dfed2e..0000000 --- a/tests/dialogs_test.py +++ /dev/null @@ -1,77 +0,0 @@ -""" - Project: pyGTKtalog - Description: Test simple dialogs - Type: test - Author: Roman 'gryf' Dobosz, gryf73@gmail.com - Created: 2009-05-19 -""" -import unittest -import os - -import gtk - -from pygtktalog.dialogs import Dialog, yesno, okcancel, info, warn, error - - -class MessageDialogMock(gtk.MessageDialog): - """Mock class for MessageDialog, which shouldn't be displayed in a test""" - - def run(self): - """Carefull! only for MESSAGE_INFO return value is RESPONSE_OK!""" - if self.get_property('message-type') == gtk.MESSAGE_INFO: - return gtk.RESPONSE_OK - else: - return gtk.RESPONSE_CANCEL - -class TestDialog(unittest.TestCase): - """Tests for Dialog class""" - - def test_dialog_create(self): - """Test dialog creation and run method""" - # overwrite MessageDialog class in gtk module - gtk.MessageDialog = MessageDialogMock - dialog = Dialog(gtk.MESSAGE_INFO, 'msg', 'secondarymsg', 'title') - self.assertTrue(dialog.buttons == gtk.BUTTONS_OK, "dialog should have" - " gtk.BUTTONS_OK") - self.assertTrue(dialog.run(), "dialog should return True") - - dialog = Dialog(gtk.MESSAGE_QUESTION, 'msg', 'secondarymsg', 'title') - self.assertFalse(dialog.run(), "dialog should return False") - # NOTE: dialog should be run before test against buttons attribute - self.assertTrue(dialog.buttons == gtk.BUTTONS_YES_NO, - "dialog should have gtk.BUTTONS_YES_NO") - - dialog = Dialog(gtk.MESSAGE_QUESTION, 'msg', 'secondarymsg', 'title') - dialog.buttons = gtk.BUTTONS_OK - dialog.ok_default = True - self.assertFalse(dialog.run(), "dialog should return True") - - def test_error(self): - """Test error function""" - result = error('msg', 'secondarymsg', 'title') - self.assertTrue(result, "Should return True") - - def test_warn(self): - """Test warn function""" - result = warn('msg', 'secondarymsg', 'title') - self.assertTrue(result, "Should return True") - - def test_info(self): - """Test info function""" - result = info('msg', 'secondarymsg', 'title') - self.assertTrue(result, "Should return True") - - def test_yesno(self): - """Test yesno function""" - result = yesno('msg', 'secondarymsg', 'title') - self.assertFalse(result, "Should return False") - - def test_okcancel(self): - """Test yesno function""" - result = okcancel('msg', 'secondarymsg', 'title') - self.assertFalse(result, "Should return False") - - -if __name__ == "__main__": - os.chdir(os.path.join(os.path.abspath(os.path.dirname(__file__)), "../")) - unittest.main() diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..33b1e5b --- /dev/null +++ b/tox.ini @@ -0,0 +1,23 @@ +[tox] +envlist = cleanup,py27,pep8 + +usedevelop = True + +[testenv] +usedevelop=True +setenv = COVERAGE_FILE = .coverage +commands = py.test --cov=pygtktalog --cov-report=term-missing +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt + +[testenv:pep8] +usedevelop=True +commands = py.test --pep8 -m pep8 +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt + +[testenv:cleanup] +setenv = +COVERAGE_FILE = .coverage +deps = coverage +commands = coverage erase