Skip to content

Commit

Permalink
Merge pull request #29 from NaturalHistoryMuseum/feature/26-python3
Browse files Browse the repository at this point in the history
Feature/26 python3
  • Loading branch information
quicklizard99 authored Nov 12, 2016
2 parents ce89093 + 35f19eb commit c8822bf
Show file tree
Hide file tree
Showing 25 changed files with 85 additions and 60 deletions.
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,5 @@ dist/
.DS_Store
.coverage
htmlcov
setup.cfg
gouda/config_dev.py
cover

.tox
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# v0.1.10
- #26 Python 3 support

# v0.1.9
- #27 Support pyzbar

Expand Down
2 changes: 1 addition & 1 deletion gouda/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.1.9'
__version__ = '0.1.10'
2 changes: 1 addition & 1 deletion gouda/engines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
from .inlite import InliteEngine
from .softek import SoftekEngine
from .stecos import StecosEngine
from .zbar_engine import ZbarEngine
from .zbar import ZbarEngine
from .zxing import ZxingEngine
2 changes: 1 addition & 1 deletion gouda/engines/accusoft.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def decode_file(self, path):
# TODO LH Who owns dib?
res = windll.kernel32.GlobalFree(dib)
if res:
print('Error freeing global handle [{0}]'.format(
debug_print('Error freeing global handle [{0}]'.format(
win32api.GetLastError()
))
self.ie.FileName = ''
Expand Down
3 changes: 1 addition & 2 deletions gouda/engines/dtk.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import os
import tempfile

Expand Down Expand Up @@ -80,7 +79,7 @@ def available(cls):
def decode_file(self, path):
self.d.ReadFromFile(str(path))
barcodes = [None] * self.d.Barcodes.Count
for i in xrange(0, self.d.Barcodes.Count):
for i in range(0, self.d.Barcodes.Count):
b = self.d.Barcodes.Item(i)
barcodes[i] = Barcode(self.types.get(b.Type, 'Unknown'),
b.BarcodeString)
Expand Down
1 change: 0 additions & 1 deletion gouda/engines/inlite.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import os
import tempfile

Expand Down
6 changes: 2 additions & 4 deletions gouda/engines/libdmtx.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from __future__ import absolute_import

import subprocess
import tempfile

import cv2
from PIL import Image

from gouda import config
from gouda.barcode import Barcode
Expand Down Expand Up @@ -33,7 +31,7 @@ def available(cls):
return pylibdmtx is not None

def decode_file(self, path):
return self(cv2.imread(str(path)))
return self(Image.open(str(path)))

def __call__(self, img):
res = pylibdmtx.decode(
Expand Down
2 changes: 1 addition & 1 deletion gouda/engines/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def engine_options():
'zxing': ZxingEngine,
}

options = {k: v for k, v in options.iteritems() if v.available()}
options = {k: v for k, v in options.items() if v.available()}

if AccusoftEngine.available():
options.update({
Expand Down
2 changes: 1 addition & 1 deletion gouda/engines/softek.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def available(cls):
def decode_file(self, path):
self.d.ScanBarCode(str(path))
barcodes = [None] * self.d.BarCodeCount
for i in xrange(0, self.d.BarCodeCount):
for i in range(0, self.d.BarCodeCount):
barcodes[i] = Barcode(str(self.d.BarStringType(1+i)),
self.d.BarString(1+i))
return barcodes
Expand Down
File renamed without changes.
8 changes: 5 additions & 3 deletions gouda/scripts/decode_barcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def _destination(self, path):
destination = path
if self.avoid_collisions:
while destination.is_file():
fname = u'{0}-{1}{2}'.format(
fname = '{0}-{1}{2}'.format(
path.stem,
next(self.suffix[path.name]),
path.suffix
Expand All @@ -138,15 +138,17 @@ def result(self, path, result):
print(' No barcodes')
else:
# TODO How best to sanitize filenames?
values = [re.sub('[^a-zA-Z0-9_-]', '_', b.data) for b in barcodes]
values = [
re.sub('[^a-zA-Z0-9_-]', '_', b.data.decode()) for b in barcodes
]

# The first time round the loop, the file will be renamed and
# first_destination set to the new filename.
# On subsequent iterations, first_destination will copied
# to new destinations.
first_destination = None
for value in values:
dest = path.with_name(u'{0}{1}'.format(value, path.suffix))
dest = path.with_name('{0}{1}'.format(value, path.suffix))
dest = self._destination(dest)
source = first_destination if first_destination else path
rename = not bool(first_destination)
Expand Down
2 changes: 1 addition & 1 deletion gouda/strategies/resize.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def resize(img, engine):
for sharpening in (0, 1, 2):
if sharpening > 0:
img = _unsharpmask(img)
for f in [round(x * 0.01, 2) for x in xrange(100, 0, -5)]:
for f in [round(x * 0.01, 2) for x in range(100, 0, -5)]:
msg = 'resize: scaling factor [{0}] sharpening [{1}]'
msg = msg.format(f, sharpening)
debug_print(msg)
Expand Down
2 changes: 2 additions & 0 deletions gouda/strategies/roi/decode.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import print_function

import cv2
import numpy as np

Expand Down
7 changes: 6 additions & 1 deletion gouda/strategies/roi/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .rect import Rect
from gouda.util import debug_print

# debug_print = print

class Detector(object):
"""Detects candidate barcode areas in an image
Expand Down Expand Up @@ -89,9 +90,11 @@ def _compute_candidates(self):

debug_print('Contours')
cont_img = closing.copy()
# Taking only the last two elements of the sequence returned by
# findContours makes the code tolerant of OpenCV 2.4.x and 3.x
contours, hierarchy = cv2.findContours(
cont_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
)[-2:]

working_images = {
'resized': resized,
Expand All @@ -102,7 +105,9 @@ def _compute_candidates(self):
'closing': closing,
}


candidates = [cv2.boundingRect(c) for c in contours]

candidates = [
Rect(x, y, width, height) for x, y, width, height in candidates
]
Expand Down
2 changes: 2 additions & 0 deletions gouda/strategies/roi/rect.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import division

import collections


Expand Down
6 changes: 5 additions & 1 deletion gouda/strategies/roi/roi.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from __future__ import print_function

from .decode import Decoder
from .detect import Detector
from .filter import AreaFilter


from pprint import pprint

def roi(img, engine):
# Regions of the image that might contain barcodes

Expand All @@ -21,4 +25,4 @@ def roi(img, engine):
if barcode.data not in res:
res[barcode.data] = barcode

return ('roi', res.values()) if res else None
return ('roi', list(res.values())) if res else None
26 changes: 13 additions & 13 deletions gouda/tests/test_decode_barcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from gouda.engines import ZbarEngine
from gouda.scripts.decode_barcodes import main

from utils import temp_directory_with_files
from .utils import temp_directory_with_files


TESTDATA = Path(__file__).parent.joinpath('test_data')
Expand All @@ -17,7 +17,7 @@ class TestRename(unittest.TestCase):
def test_rename(self):
"File is renamed with value of barcode"
with temp_directory_with_files(TESTDATA.joinpath('code128.png')) as tempdir:
main(['zbar', '--action=rename', unicode(tempdir)])
main(['zbar', '--action=rename', str(tempdir)])
self.assertEqual(
['Stegosaurus.png'],
[path.name for path in sorted(tempdir.iterdir())]
Expand All @@ -26,7 +26,7 @@ def test_rename(self):
def test_rename_multiple(self):
"File with multiple barcodes results in renamed / copied to three files"
with temp_directory_with_files(TESTDATA.joinpath('BM001128287.jpg')) as tempdir:
main(['zbar', '--action=rename', unicode(tempdir)])
main(['zbar', '--action=rename', str(tempdir)])
self.assertEqual(
['BM001128286.jpg', 'BM001128287.jpg', 'BM001128288.jpg'],
[path.name for path in sorted(tempdir.iterdir())]
Expand All @@ -36,16 +36,16 @@ def test_rename_with_collisions(self):
"Files with same barcode values results in just a single rename"
with temp_directory_with_files(TESTDATA.joinpath('code128.png')) as tempdir:
shutil.copy(
unicode(TESTDATA.joinpath('code128.png')),
unicode(tempdir.joinpath('first copy.png'))
str(TESTDATA.joinpath('code128.png')),
str(tempdir.joinpath('first copy.png'))
)

shutil.copy(
unicode(TESTDATA.joinpath('code128.png')),
unicode(tempdir.joinpath('second copy.png'))
str(TESTDATA.joinpath('code128.png')),
str(tempdir.joinpath('second copy.png'))
)

main(['zbar', '--action=rename', unicode(tempdir)])
main(['zbar', '--action=rename', str(tempdir)])
self.assertEqual(
['Stegosaurus.png', 'first copy.png', 'second copy.png'],
[path.name for path in sorted(tempdir.iterdir(), key=lambda p: p.name)]
Expand All @@ -55,16 +55,16 @@ def test_rename_avoid_collisions(self):
"Files with same barcode values results in new files with suffixes"
with temp_directory_with_files(TESTDATA.joinpath('code128.png')) as tempdir:
shutil.copy(
unicode(TESTDATA.joinpath('code128.png')),
unicode(tempdir.joinpath('first copy.png'))
str(TESTDATA.joinpath('code128.png')),
str(tempdir.joinpath('first copy.png'))
)

shutil.copy(
unicode(TESTDATA.joinpath('code128.png')),
unicode(tempdir.joinpath('second copy.png'))
str(TESTDATA.joinpath('code128.png')),
str(tempdir.joinpath('second copy.png'))
)

main(['zbar', '--action=rename', unicode(tempdir), '--avoid-collisions'])
main(['zbar', '--action=rename', str(tempdir), '--avoid-collisions'])
print([path.name for path in sorted(tempdir.iterdir())])
self.assertEqual(
['Stegosaurus-1.png', 'Stegosaurus-2.png', 'Stegosaurus.png'],
Expand Down
8 changes: 4 additions & 4 deletions gouda/tests/test_engines.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,25 @@ class TestEngine(unittest.TestCase):
NOBARCODE = cv2.imread(str(TESTDATA / 'nobarcode.png'))

def _test_1d(self, engine, type='CODE128'):
expected = [Barcode(type=type, data='Stegosaurus')]
expected = [Barcode(type=type, data=b'Stegosaurus')]
res = engine(self.CODE128)
self.assertEqual(expected, res)
self.assertEqual([], engine(self.NOBARCODE))

def _test_dm(self, engine, type='Data Matrix'):
expected = [Barcode(type=type, data=u'Triceratops')]
expected = [Barcode(type=type, data=b'Triceratops')]
res = engine(self.DATAMATRIX)
self.assertEqual(expected, res)
self.assertEqual([], engine(self.NOBARCODE))

def _test_qr(self, engine, type='QR Code'):
expected = [Barcode(type=type, data=u'Thalassiodracon')]
expected = [Barcode(type=type, data=b'Thalassiodracon')]
res = engine(self.QRCODE)
self.assertEqual(expected, res)
self.assertEqual([], engine(self.NOBARCODE))

def _test_pdf417(self, engine, type='PDF 417'):
expected = [Barcode(type=type, data=u'Metasequoia')]
expected = [Barcode(type=type, data=b'Metasequoia')]
res = engine(self.PDF417)
self.assertEqual(expected, res)
self.assertEqual([], engine(self.NOBARCODE))
Expand Down
2 changes: 1 addition & 1 deletion gouda/tests/test_rect.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def test_bottomright(self):
self.assertEqual(Point(2, 4), self.R.bottomright)

def test_centre(self):
self.assertEqual(Point(1, 2), self.R.centre)
self.assertEqual(Point(1.0, 2.5), self.R.centre)

def test_comparison(self):
a = Rect(0, 1, 2, 3)
Expand Down
4 changes: 2 additions & 2 deletions gouda/tests/test_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ def _test(self, file, engine, strategy, expected):
return method, barcodes

def _test_1d(self, strategy):
expected = ['BM001128286', 'BM001128287', 'BM001128288']
expected = [b'BM001128286', b'BM001128287', b'BM001128288']
return self._test('BM001128287.jpg',
self.ONED_ENGINE,
strategy,
expected)

def _test_dm(self, strategy):
expected = ['1265025']
expected = [b'1265025']
return self._test('BMNHE_1265025.jpg',
self.DM_ENGINE,
strategy,
Expand Down
2 changes: 1 addition & 1 deletion gouda/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import cv2

try:
from _winreg import OpenKey, HKEY_LOCAL_MACHINE
from winreg import OpenKey, HKEY_LOCAL_MACHINE
except ImportError:
OpenKey = HKEY_LOCAL_MACHINE = None

Expand Down
12 changes: 6 additions & 6 deletions requirements.pip
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# TODO How to specify OpenCV? 'cv2>=2.4.8',
pathlib>=1.0.1
Pillow>=3.2.0
pathlib==1.0.1; python_version == '2.7'
pylibdmtx==0.1.4
pyzbar==0.1.2
numpy>=1.8.2
Pillow==3.4.2
numpy==1.11.2

# Packages required for distribution
PyInstaller==3.1.1

# Packages required for testing
coveralls>=1.1
nose>=1.3.4

# Packages required for distribution
PyInstaller==3.1.1
28 changes: 16 additions & 12 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,30 @@
'test_suite': 'gouda.tests',
'scripts': ['gouda/scripts/{0}.py'.format(script) for script in SCRIPTS],
'entry_points': {
'console_scripts':
['{0}=gouda.scripts.{0}:main'.format(script) for script in SCRIPTS],
'console_scripts': [
'{0}=gouda.scripts.{0}:main'.format(script) for script in SCRIPTS
],
},
'install_requires': [
# TODO How to specify OpenCV? 'cv2>=2.4.8,<3',
'pathlib>=1.0.1',
'pylibdmtx>=0.1.1',
'pyzbar>=0.1.1',
# TODO How to specify OpenCV? 'cv2>=2.4.8'
'Pillow>=3.2.0',
'pylibdmtx>=0.1.4',
'pyzbar>=0.1.2',
'numpy>=1.8.2',
],
'tests_require': [
'nose>=1.3.4',
],
'extras_require': {
':python_version=="2.7"': ['pathlib>=1.0.1'],
},
'classifiers': [
'Development Status :: 4 - Beta',
'License :: OSI Approved :: MIT License',
'Topic :: Utilities',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
]
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
],
}


Expand All @@ -53,7 +57,7 @@ def setuptools_setup():
setup(**setup_data)


if (2, 7) == sys.version_info[:2]:
if (2, 7) == sys.version_info[:2] or (3, 4) <= sys.version_info:
setuptools_setup()
else:
sys.exit('Only Python 2.7 is supported')
sys.exit('Python versions 2.7 and >= 3.4 are supported')
Loading

0 comments on commit c8822bf

Please sign in to comment.