Skip to content

Commit

Permalink
initial Python 3 port
Browse files Browse the repository at this point in the history
See jwilk#13 for a list of known problems.
  • Loading branch information
FriedrichFroebel committed Oct 22, 2021
1 parent 6f44725 commit 09db823
Show file tree
Hide file tree
Showing 18 changed files with 89 additions and 72 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.

PYTHON = python
PYTHON = python3

PREFIX = /usr/local
DESTDIR =
Expand Down
7 changes: 0 additions & 7 deletions lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,4 @@
didjvu's private modules
'''

import sys

if sys.version_info < (2, 7):
raise RuntimeError('Python 2.7 is required') # no coverage
if sys.version_info >= (3, 0):
raise RuntimeError('Python 2.X is required') # no coverage

# vim:ts=4 sts=4 sw=4 et
17 changes: 11 additions & 6 deletions lib/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ def replace_underscores(s):

def _get_method_params_help(methods):
result = ['binarization methods and their parameters:']
for name, method in sorted(methods.iteritems()):
for name, method in sorted(methods.items()):
result += [' ' + name]
for arg in method.args.itervalues():
for arg in list(method.args.values()):
arg_help = arg.name
if arg.type in {int, float}:
arg_help += '=' + 'NX'[arg.type is float]
Expand Down Expand Up @@ -153,7 +153,7 @@ class defaults(object):
bg_subsample = 3

def __init__(self, methods, default_method):
argparse.ArgumentParser.__init__(self, formatter_class=argparse.RawDescriptionHelpFormatter)
super(ArgumentParser, self).__init__(formatter_class=argparse.RawDescriptionHelpFormatter)
self.add_argument('--version', action=version.VersionAction)
# --test is used internally to implement “make test(-installed)”; do not use directly
self.add_argument('--test', nargs=argparse.REMAINDER, action=TestAction, help=argparse.SUPPRESS)
Expand Down Expand Up @@ -214,7 +214,7 @@ def __init__(self, methods, default_method):
)
default_crcb = getattr(default, '{lr}_crcb'.format(lr=layer))
p.add_argument(
'--{lr}-crcb'.format(lr=layer), choices=map(str, djvu.CRCB.values),
'--{lr}-crcb'.format(lr=layer), choices=list(map(str, djvu.CRCB.values)),
help='chrominance encoding for {layer} (default: {crcb})'.format(layer=layer_name, crcb=default_crcb)
)
default_subsample = getattr(default, '{lr}_subsample'.format(lr=layer))
Expand Down Expand Up @@ -310,13 +310,18 @@ def _parse_params(self, options):
if (arg.max is not None) and pvalue > arg.max:
self.error('parameter {0} must be <= {1}'.format(pname, arg.max))
result[arg.name] = pvalue
for arg in o.method.args.itervalues():
for arg in list(o.method.args.values()):
if (not arg.has_default) and (arg.name not in result):
self.error('parameter {0} is not set'.format(arg.name))
return result

def parse_args(self, actions):
o = argparse.ArgumentParser.parse_args(self)
if not hasattr(o, 'fg_bg_defaults'):
import sys
self.print_usage()
print('didjvu: error: too few arguments')
sys.exit(2)
if o.fg_bg_defaults is None:
for layer in 'fg', 'bg':
namespace = argparse.Namespace()
Expand Down Expand Up @@ -354,7 +359,7 @@ def dump_options(o, multipage=False):
method_name += ' '.join(
'{0}={1}'.format(pname, pvalue)
for pname, pvalue
in sorted(o.params.iteritems())
in sorted(o.params.items())
)
yield ('method', method_name)
if multipage:
Expand Down
14 changes: 7 additions & 7 deletions lib/didjvu.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
didjvu core
'''

from __future__ import print_function


import itertools
import logging
Expand Down Expand Up @@ -92,16 +92,16 @@ def subsample_fg(image, mask, options):
mask_get = mask.get
subsampled_image_set = subsampled_image.set
subsampled_mask_set = subsampled_mask.set
for sy in xrange(0, subsampled_image.nrows):
for sy in range(0, subsampled_image.nrows):
x0 = 0
for sx in xrange(0, subsampled_image.ncols):
for sx in range(0, subsampled_image.ncols):
n = r = g = b = 0
y = y0
for dy in xrange(ratio):
for dy in range(ratio):
if y >= height:
break
x = x0
for dx in xrange(ratio):
for dx in range(ratio):
if x >= width:
break
pt = gamera.Point(x, y)
Expand Down Expand Up @@ -247,11 +247,11 @@ def check_multi_output(self, o):
error('cannot output multiple files to a single file')
assert len(o.masks) == len(o.output) == len(o.input)
o.output = (
open(f, 'wb') if isinstance(f, basestring) else f
open(f, 'wb') if isinstance(f, str) else f
for f in o.output
)
o.xmp_output = (
open(f, 'wb') if isinstance(f, basestring) else f
open(f, 'wb') if isinstance(f, str) else f
for f in o.xmp_output
)

Expand Down
6 changes: 3 additions & 3 deletions lib/djvu_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def __init__(self, width=None, height=None, dpi=None, **chunks):
self._dirty = set() # Chunks that need to be re-read from the file.
self._pristine = False # Should save() be a no-op?
self._file = None
for (k, v) in chunks.iteritems():
for (k, v) in list(chunks.items()):
self[k] = v

def _load_file(self):
Expand Down Expand Up @@ -234,7 +234,7 @@ def save(self):
raise ValueError
args = ['djvumake', None, 'INFO={w},{h},{r}'.format(w=self.width, h=self.height, r=self.dpi)]
incl_dir = None
for key, value in sorted(self._chunks.iteritems(), key=_chunk_order):
for key, value in sorted(list(self._chunks.items()), key=_chunk_order):
try:
key = self._chunk_names[key]
except KeyError:
Expand All @@ -250,7 +250,7 @@ def save(self):
elif incl_dir != new_incl_dir:
raise ValueError
value = os.path.basename(value)
if not isinstance(value, basestring):
if not isinstance(value, str):
value = value.name
if key == 'BG44':
value += ':99'
Expand Down
4 changes: 2 additions & 2 deletions lib/filetype.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ def check(filename):
cls = generic
with open(filename, 'rb') as file:
header = file.read(16)
if header.startswith('AT&TFORM'):
if header.startswith(b'AT&TFORM'):
cls = djvu
if header.endswith('DJVU'):
if header.endswith(b'DJVU'):
cls = djvu_single
return cls

Expand Down
8 changes: 4 additions & 4 deletions lib/gamera_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
import gamera.args

def has_version(*req_version):
return tuple(map(int, version.split('.'))) >= req_version
return True # tuple(map(int, version.split('.'))) >= req_version

def load_image(filename):
pil_image = PIL.open(filename)
Expand Down Expand Up @@ -112,7 +112,7 @@ class Argument(object):

def __init__(self, arg):
self.name = arg.name.replace(' ', '-').replace('_', '-')
for gtype, ptype in self._type_map.iteritems():
for gtype, ptype in list(self._type_map.items()):
if isinstance(arg, gtype):
self.type = ptype
break
Expand Down Expand Up @@ -158,7 +158,7 @@ def __call__(self, image, **kwargs):
kwargs = dict(
(key.replace('-', '_'), value)
for key, value
in kwargs.iteritems()
in list(kwargs.items())
)
pixel_types = self._pixel_types
if image.data.pixel_type not in pixel_types:
Expand Down Expand Up @@ -192,7 +192,7 @@ class _methods(object):
if has_version(3, 4, 0):
from gamera.plugins.binarization import brink_threshold
methods = {}
for name, plugin in vars(_methods).items():
for name, plugin in list(vars(_methods).items()):
if name.startswith('_'):
continue
name = replace_suffix('', name)
Expand Down
8 changes: 4 additions & 4 deletions lib/ipc.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def get_signal_names():
del data['SIGCLD']
except KeyError: # no coverage
pass
return dict((no, name) for name, no in data.iteritems())
return dict((no, name) for name, no in list(data.items()))

CalledProcessError = subprocess.CalledProcessError

Expand Down Expand Up @@ -83,7 +83,7 @@ def override_env(cls, override):
lc_ctype = env.get('LC_ALL') or env.get('LC_CTYPE') or env.get('LANG')
env = dict(
(k, v)
for k, v in env.iteritems()
for k, v in list(env.items())
if not (k.startswith('LC_') or k in {'LANG', 'LANGUAGE'})
)
if lc_ctype:
Expand All @@ -109,8 +109,8 @@ def __init__(self, *args, **kwargs):
ex.filename = self.__command
raise

def wait(self):
return_code = subprocess.Popen.wait(self)
def wait(self, timeout=None):
return_code = subprocess.Popen.wait(self, timeout=timeout)
if return_code > 0:
raise CalledProcessError(return_code, self.__command)
if return_code < 0:
Expand Down
2 changes: 1 addition & 1 deletion lib/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
didjvu version information
'''

from __future__ import print_function


import argparse
import sys
Expand Down
2 changes: 1 addition & 1 deletion lib/xmp/pyexiv2_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def __setitem__(self, key, value):
value = value.as_datetime(cls=datetime_for_pyexiv2)
elif key.startswith('didjvu.'):
value = str(value)
elif key == 'dc.format' and isinstance(value, basestring):
elif key == 'dc.format' and isinstance(value, str):
value = tuple(value.split('/', 1))
self._meta['Xmp.' + key] = value

Expand Down
26 changes: 17 additions & 9 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

from lib import cli


class test_range_int():

def test_lt_min(self):
Expand Down Expand Up @@ -60,6 +61,7 @@ def test_non_int(self):
with assert_raises(ValueError):
t('ham')


class test_slice_type():

def test_non_int(self):
Expand Down Expand Up @@ -134,6 +136,7 @@ def test_plus_lt(self):
with assert_raises(ValueError):
t('42+-5')


def test_slice_repr():

def t(inp, exp):
Expand All @@ -146,27 +149,32 @@ def t(inp, exp):
t([42], '42')
t([23, 37, 42], '23+14+5')


def test_intact():
x = object()
intact_x = cli.intact(x)
assert_is(intact_x(), x)


def test_replace_underscores():
assert_equal(
cli.replace_underscores('eggs_ham_spam'),
'eggs-ham-spam'
)


class MockActions(object):
def __getattr__(self, name):
def f(options):
return (name, options)
return f


class MockMethod(object):
def __init__(self):
self.args = {}


class test_argument_parser():

methods = dict(
Expand All @@ -184,20 +192,20 @@ def test_init(self):
cli.ArgumentParser(self.methods, 'djvu')

def test_no_args(self):
stderr = io.BytesIO()
with interim(sys, argv=['didjvu'], stderr=stderr):
stdout = io.StringIO()
with interim(sys, argv=['didjvu'], stdout=stdout):
ap = cli.ArgumentParser(self.methods, 'djvu')
with assert_raises(SystemExit) as ecm:
ap.parse_args({})
assert_equal(ecm.exception.args, (2,))
assert_multi_line_equal(
stderr.getvalue(),
stdout.getvalue(),
'usage: didjvu [-h] [--version] {{{actions}}} ...\n'
'didjvu: error: too few arguments\n'.format(actions=','.join(self.anames))
)

def _test_action_no_args(self, action):
stderr = io.BytesIO()
stderr = io.StringIO()
with interim(sys, argv=['didjvu', action], stderr=stderr):
ap = cli.ArgumentParser(self.methods, 'djvu')
with assert_raises(SystemExit) as ecm:
Expand All @@ -207,7 +215,7 @@ def _test_action_no_args(self, action):
stderr.getvalue(),
(r'(?s)\A'
'usage: didjvu {action} .*\n'
'didjvu {action}: error: too few arguments\n'
'didjvu {action}: error: the following arguments are required: .*'
r'\Z').format(action=action)
)

Expand All @@ -218,7 +226,7 @@ def test_action_no_args(self):
yield t, 'encode'

def test_bad_action(self, action='eggs'):
stderr = io.BytesIO()
stderr = io.StringIO()
with interim(sys, argv=['didjvu', action], stderr=stderr):
ap = cli.ArgumentParser(self.methods, 'djvu')
with assert_raises(SystemExit) as ecm:
Expand All @@ -231,7 +239,7 @@ def test_bad_action(self, action='eggs'):
)

def _test_action(self, action, *args):
stderr = io.BytesIO()
stderr = io.StringIO()
argv = ['didjvu', action]
argv += args
with interim(sys, argv=argv, stderr=stderr):
Expand Down Expand Up @@ -268,8 +276,8 @@ def test_action_defaults(self):

def _test_help(self, action=None):
argv = ['didjvu', action, '--help']
argv = filter(None, argv)
stdout = io.BytesIO()
argv = list([_f for _f in argv if _f])
stdout = io.StringIO()
with interim(sys, argv=argv, stdout=stdout):
ap = cli.ArgumentParser(self.methods, 'djvu')
with assert_raises(SystemExit) as ecm:
Expand Down
3 changes: 2 additions & 1 deletion tests/test_djvu.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ def ddjvu(djvu_file, fmt='ppm'):
stdout=ipc.PIPE,
stderr=ipc.PIPE
)
if isinstance(djvu_file, basestring):
if isinstance(djvu_file, str):
djvu_path = djvu_file
cmdline += [djvu_path]
else:
stdio.update(stdin=djvu_file)
child = ipc.Subprocess(cmdline, **stdio)
stdout, stderr = child.communicate()
stderr = stderr.decode()
if child.returncode != 0:
raise RuntimeError('ddjvu failed')
if stderr != '':
Expand Down
4 changes: 2 additions & 2 deletions tests/test_fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

def test_copy_file():
def t(s):
input_file = io.BytesIO(s)
output_file = io.BytesIO()
input_file = io.StringIO(s)
output_file = io.StringIO()
length = fs.copy_file(input_file, output_file)
assert_equal(output_file.tell(), length)
output_file.seek(0)
Expand Down
Loading

0 comments on commit 09db823

Please sign in to comment.