Skip to content

Commit

Permalink
[#95] Python 3
Browse files Browse the repository at this point in the history
  • Loading branch information
quicklizard99 committed Dec 2, 2016
1 parent 458cb97 commit b09f49f
Show file tree
Hide file tree
Showing 85 changed files with 910 additions and 912 deletions.
15 changes: 6 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
language: python

python:
- "2.7"
- "3.5"

virtualenv:
system_site_packages: true

before_install:
- sudo apt-get update
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 ]]; then
sudo apt-get install -y --fix-missing libzbar-dev libdmtx0a;
fi

# We do this conditionally because it saves us some downloading if the
# version is the same.
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh;
- if [[ "$TRAVIS_PYTHON_VERSION" == "3.5" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
fi
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
Expand All @@ -25,11 +25,8 @@ before_install:
# Useful for debugging any issues with conda
- conda info -a

- conda create -y -n test-environment python=$TRAVIS_PYTHON_VERSION pillow pyqt=5.6.0 numpy scikit-learn
- conda create -y -n test-environment python=$TRAVIS_PYTHON_VERSION numpy opencv pillow pyqt scikit-learn scipy
- source activate test-environment
# conda's own opencv has all sorts of inexplicable conflicts with other
# packages - install menpo's build of opencv
- conda install -y --channel https://conda.anaconda.org/menpo opencv
- python setup.py install

install:
Expand All @@ -39,7 +36,7 @@ install:
- pyrcc5 icons.qrc > inselect/gui/icons.py

script:
- nosetests --verbose --with-coverage --cover-inclusive --cover-tests --cover-package=inselect inselect
- nosetests --verbose --with-coverage --cover-inclusive --cover-tests --cover-package=inselect --verbose inselect

after_success:
- coveralls
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Version 0.1.35
- #368 Ugly error message when creating a new inselect document on Mac OS X
- #367 Reveal file doesn't work on Windows
- #273 Inselect as a package
- #95 Python 3
- #83 Architecture and code organisation

Version 0.1.34
Expand Down
2 changes: 1 addition & 1 deletion bin/plist.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
"""Alter Inselect's existing plist file
"""

Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ echo Tests
nosetests --with-coverage --cover-html --cover-inclusive --cover-erase --cover-tests --cover-package=inselect inselect

echo Source build
./setup.py sdist
./setup.py sdist bdist_wheel --universal
mv dist/inselect-$VERSION.tar.gz .

if [[ "$OSTYPE" == "darwin"* ]]; then
Expand Down
2 changes: 1 addition & 1 deletion inselect.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
import sys

if sys.platform == 'win32' and hasattr(sys, 'frozen'):
Expand Down
4 changes: 2 additions & 2 deletions inselect/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def main(args=None):
# Install global exception hook only after the application has been created
sys.excepthook = report_exception_to_user

debug_print(u'Settings stored in [{0}]'.format(QSettings().fileName()))
debug_print('Settings stored in [{0}]'.format(QSettings().fileName()))

if parsed.locale:
debug_print('Will set locale to [{0}]'.format(parsed.locale))
Expand All @@ -97,7 +97,7 @@ def main(args=None):
# Set Python's locale module to the user's default locale
locale.setlocale(locale.LC_ALL, '')

debug_print(u'Locale is [{0}]'.format(QLocale().name()))
debug_print('Locale is [{0}]'.format(QLocale().name()))

# Application icon
icon = QIcon()
Expand Down
2 changes: 1 addition & 1 deletion inselect/gui/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def _machine_summary():
def show_about_box(parent=None):
"""Shows a modal about box
"""
body = u"""<h1>{application} {version}</h1>
body = """<h1>{application} {version}</h1>
<p>
Segmentation, validation and annotation of images of museum objects.
Expand Down
12 changes: 6 additions & 6 deletions inselect/gui/cookie_cutter_choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def __init__(self):
self._current = self._load(previous)
except Exception:
debug_print(
u'Error loading cookie cutter [{0}]'.format(previous)
'Error loading cookie cutter [{0}]'.format(previous)
)

@classmethod
Expand All @@ -49,17 +49,17 @@ def last_directory(cls):

def _load(self, path):
"Loads the CookieCutter in path"
debug_print(u'CookieCutterChoice._load [{0}]'.format(path))
debug_print('CookieCutterChoice._load [{0}]'.format(path))
return CookieCutter.load(path)

def load(self, path):
"""Loads the CookieCutter in path, updates settings and emits
cookie_cutter_changed
"""
debug_print(u'CookieCutterChoice.load [{0}]'.format(path))
debug_print('CookieCutterChoice.load [{0}]'.format(path))
self._current = self._load(path)
QSettings().setValue(self.PATH_KEY, unicode(path))
QSettings().setValue(self.DIRECTORY_KEY, unicode(Path(path).parent))
QSettings().setValue(self.PATH_KEY, str(path))
QSettings().setValue(self.DIRECTORY_KEY, str(Path(path).parent))
self.cookie_cutter_changed.emit()

def clear(self):
Expand All @@ -73,7 +73,7 @@ def create_and_use(self, boxes, path):
"""Creates a new CookieCutter file that contains boxes, writes in to
path and sets it to be the current choice
"""
debug_print(u'CookieCutterChoice.create_and_use to [{0}]'.format(path))
debug_print('CookieCutterChoice.create_and_use to [{0}]'.format(path))
cookie_cutter = CookieCutter('', boxes)
cookie_cutter.save(path)
self.load(path)
Expand Down
4 changes: 2 additions & 2 deletions inselect/gui/cookie_cutter_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CookieCutterWidget(QObject):
shows a popup menu when pressed.
"""

FILE_FILTER = u'Inselect cookie cutter (*{0})'.format(
FILE_FILTER = 'Inselect cookie cutter (*{0})'.format(
CookieCutter.EXTENSION
)

Expand Down Expand Up @@ -61,7 +61,7 @@ def choose(self, checked=False):
debug_print('CookieCutterWidget.choose_cookie_cutter')
path, selectedFilter = QFileDialog.getOpenFileName(
None, "Choose cookie cutter",
unicode(cookie_cutter_choice().last_directory()),
str(cookie_cutter_choice().last_directory()),
self.FILE_FILTER
)

Expand Down
64 changes: 33 additions & 31 deletions inselect/gui/main_window.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from __future__ import print_function

import sys

from datetime import datetime
from functools import partial
from itertools import count, izip
from itertools import count
from pathlib import Path

from qtpy import QtWidgets
Expand Down Expand Up @@ -56,12 +56,12 @@
class MainWindow(QMainWindow):
"""The application's main window
"""
DOCUMENT_FILE_FILTER = u'Inselect documents (*{0});;Images ({1})'.format(
DOCUMENT_FILE_FILTER = 'Inselect documents (*{0});;Images ({1})'.format(
InselectDocument.EXTENSION,
u' '.join(IMAGE_PATTERNS)
' '.join(IMAGE_PATTERNS)
)

IMAGE_FILE_FILTER = u'Images ({0})'.format(u' '.join(IMAGE_PATTERNS))
IMAGE_FILE_FILTER = 'Images ({0})'.format(' '.join(IMAGE_PATTERNS))

def __init__(self, print_time=False):
"""if print_time is True, will print, when a document is closed, the
Expand Down Expand Up @@ -274,7 +274,7 @@ def open_file(self, path=None):
the .inselect file is opened
* If an image file, a new .inselect file is created and opened
"""
debug_print(u'MainWindow.open_file [{0}]'.format(path))
debug_print('MainWindow.open_file [{0}]'.format(path))

if not path:
folder = QSettings().value(
Expand All @@ -298,7 +298,7 @@ def open_file(self, path=None):
elif IMAGE_SUFFIXES_RE.match(path.name):
# Compute the path to the inselect document (which may or
# may not already exist) of the image file
doc_of_image = path.name.replace(InselectDocument.THUMBNAIL_SUFFIX, u'')
doc_of_image = path.name.replace(InselectDocument.THUMBNAIL_SUFFIX, '')
doc_of_image = path.parent / doc_of_image
doc_of_image = doc_of_image.with_suffix(InselectDocument.EXTENSION)
if doc_of_image.is_file():
Expand All @@ -320,7 +320,7 @@ def open_file(self, path=None):
debug_print('Opening inselect document [{0}]'.format(document_path))
self.open_document(path=document_path)
elif image_path:
msg = u'Creating new inselect document for image [{0}]'
msg = 'Creating new inselect document for image [{0}]'
debug_print(msg.format(image_path))
self.new_document(image_path)
else:
Expand All @@ -334,7 +334,7 @@ def new_document(self, path, default_metadata_items=None):

path = Path(path)
if not path.is_file():
raise InselectError(u'Image file [{0}] does not exist'.format(path))
raise InselectError('Image file [{0}] does not exist'.format(path))
else:
# Callable for worker thread
thumbnail_width = user_template_choice().current.thumbnail_width_pixels
Expand Down Expand Up @@ -368,7 +368,7 @@ def new_document_finished(self, operation):

self.open_document(document=document)

msg = u'New Inselect document [{0}] created in [{1}]'
msg = 'New Inselect document [{0}] created in [{1}]'
msg = msg.format(document_path.stem, document_path.parent)
QMessageBox.information(self, "Document created", msg)

Expand All @@ -388,7 +388,7 @@ def _sync_recent_documents_actions(self):
raise ValueError(msg.format(len(recent)))
else:
# Show as many actions as there are recent documents
for index, path, action in izip(count(), recent, self.recent_doc_actions):
for index, path, action in zip(count(), recent, self.recent_doc_actions):
action.setEnabled(True)
action.setText(path.stem)
action.setToolTip(str(path))
Expand Down Expand Up @@ -439,8 +439,8 @@ def open_document(self, path=None, document=None):
self.sync_ui()

if not is_writable(path):
msg = (u'The file [{0}] is read-only.\n\n'
u'You will not be able to save any changes that you make.')
msg = ('The file [{0}] is read-only.\n\n'
'You will not be able to save any changes that you make.')
msg = msg.format(path.name)
QMessageBox.warning(self, "Document is read-only", msg)

Expand Down Expand Up @@ -585,21 +585,22 @@ def save_screengrab(self, checked=False):
# Investigate https://pypi.python.org/pypi/qimage2ndarray/0.2

# Work out the supported image file extensions
extensions = QImageWriter.supportedImageFormats()
extensions = sorted([str(e).lower() for e in extensions])
extensions = ['*.{0}'.format(e) for e in extensions]
extensions = {
'*.{0}'.format(bytes(e).decode().lower()) for
e in QImageWriter.supportedImageFormats()
}

# Only some of these make sense. For example, do not offer the user
# the change to save an eps, which is a format supported by QImageWriter
extensions = sorted(set(extensions).intersection(IMAGE_PATTERNS))
extensions = sorted(extensions.intersection(IMAGE_PATTERNS))

filter = 'Images ({0})'.format(' '.join(extensions))

if self.document_path:
# Default name is the name of this document with '_screengrab' appended
default_fname = u'{0}_screengrab'.format(self.document_path.stem)
default_fname = '{0}_screengrab'.format(self.document_path.stem)
else:
default_fname = u'inselect_screengrab'
default_fname = 'inselect_screengrab'

# Default suffix is jpg, if available
for e in ('.jpg', '.jpeg', '.png'):
Expand All @@ -608,6 +609,7 @@ def save_screengrab(self, checked=False):
break
else:
# Use the first available extension
print(111, repr(extensions))
default_extension = extensions[0][1:]

default_fname = Path(default_fname).with_suffix(default_extension)
Expand All @@ -617,11 +619,11 @@ def save_screengrab(self, checked=False):
QStandardPaths.DocumentsLocation
)

debug_print(u'Default screengrab dir [{0}]'.format(default_dir))
debug_print(u'Default screengrab fname [{0}]'.format(default_fname))
debug_print('Default screengrab dir [{0}]'.format(default_dir))
debug_print('Default screengrab fname [{0}]'.format(default_fname))
path, selectedFilter = QFileDialog.getSaveFileName(
self, "Save image file of boxes view",
unicode(Path(default_dir) / default_fname),
str(Path(default_dir) / default_fname),
filter=filter
)

Expand Down Expand Up @@ -660,18 +662,18 @@ def close_document(self, checked=False, document_to_open=None):
self.document_path.resolve() == document_to_open.resolve()):
if self.model.is_modified:
# Ask the user if they work like to revert
msg = (u'The document [{0}] is already open and has been '
u'changed. Would you like to discard your changes and '
u'revert to the previous version?')
msg = ('The document [{0}] is already open and has been '
'changed. Would you like to discard your changes and '
'revert to the previous version?')
msg = msg.format(self.document_path.stem)
res = QMessageBox.question(self, u'Discard changes?', msg,
res = QMessageBox.question(self, 'Discard changes?', msg,
(QMessageBox.Yes | QMessageBox.No),
QMessageBox.No)
close = QMessageBox.Yes == res
else:
# Let the user know that the document is already open and
# take no action
msg = u'The document [{0}] is already open'
msg = 'The document [{0}] is already open'
msg = msg.format(self.document_path.stem)
QMessageBox.information(self, 'Document already open', msg,
QMessageBox.Ok)
Expand Down Expand Up @@ -707,7 +709,7 @@ def empty_document(self, checked=False):
if self.time_doc_opened and self.print_time:
elapsed = datetime.utcnow() - self.time_doc_opened
self.time_doc_opened = None
print(u'{0},{1}s'.format(self.document_path, elapsed.total_seconds()))
print('{0},{1}s'.format(self.document_path, elapsed.total_seconds()))

# Clear selection before closing for performance reasons
self.select_none()
Expand Down Expand Up @@ -974,7 +976,7 @@ def _create_menu_actions(self):
self.exit_action.shortcut()])

self.recent_doc_actions = [None] * RecentDocuments.MAX_RECENT_DOCS
for index in xrange(RecentDocuments.MAX_RECENT_DOCS):
for index in range(RecentDocuments.MAX_RECENT_DOCS):
self.recent_doc_actions[index] = QAction(
'Recent document', self,
triggered=partial(self.open_recent, index=index)
Expand Down Expand Up @@ -1063,7 +1065,7 @@ def _create_menu_actions(self):
self.plugin_actions[index] = action
if hasattr(plugin, 'config'):
ui_action = QAction(
u"Configure '{0}'...".format(plugin.NAME), self,
"Configure '{0}'...".format(plugin.NAME), self,
triggered=partial(self.show_plugin_config, index),
icon=load_icon(':/icons/configure.png')
)
Expand Down Expand Up @@ -1449,7 +1451,7 @@ def new_cookie_cutter(self):

def save_to_cookie_cutter(self, checked=False):
"Saves bounding boxes to a new 'cookie cutter' file"
folder = unicode(cookie_cutter_choice().last_directory())
folder = str(cookie_cutter_choice().last_directory())
path, selectedFilter = QFileDialog.getSaveFileName(
self, "New cookie cutter", folder,
CookieCutterWidget.FILE_FILTER
Expand Down
Loading

0 comments on commit b09f49f

Please sign in to comment.