1
0
mirror of https://github.com/gryf/pygtktalog.git synced 2025-12-17 03:20:17 +01:00

Added basic Python3 support

This commit is contained in:
2019-02-24 13:16:23 +01:00
parent 28a99b0470
commit 07690f9c94
9 changed files with 50 additions and 60 deletions

View File

@@ -44,15 +44,14 @@ Requirements
pyGTKtalog requires python and following libraries:
* `python 2.7`_
* `sqlalchemy 1.0`_
* `pygtk 2.24`_ (only for ``gtktalog.py``)
* `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
* `exifread`_ for parse EXIF information
It may work on other (lower) version of libraries, and it should work with
higher versions of libraries, although it will not work on Python 3 yet, nor
GTK3.
higher versions of libraries. GTK3 support will follow.
pyGTKtalog extensively uses external programs in unix spirit, however there is
small possibility of using it Windows (probably with limitations) and quite big
@@ -148,7 +147,7 @@ file in top-level directory.
.. _paver: https://pythonhosted.org/paver/
.. _pillow: https://python-pillow.org/
.. _pygtk 2.24: http://www.pygtk.org
.. _python 2.7: http://www.python.org/
.. _sqlalchemy 1.0: http://www.sqlalchemy.org
.. _python 3: http://www.python.org/
.. _sqlalchemy 1.2: http://www.sqlalchemy.org
.. _tagging files: http://en.wikipedia.org/wiki/tag_%28metadata%29
.. _tox: https://testrun.org/tox

View File

@@ -6,19 +6,15 @@
Created: 2009-05-05
"""
__version__ = "2.0.0"
__version__ = "3.0.0"
__appname__ = "pyGTKtalog"
__copyright__ = u"\u00A9 Roman 'gryf' Dobosz"
__copyright__ = "\u00A9 Roman 'gryf' Dobosz"
__summary__ = "%s is simple tool for managing file collections." % __appname__
__web__ = "http://github.com/gryf/pygtktalog"
import os
import sys
import locale
import gettext
import __builtin__
from pygtktalog.logger import get_logger
__all__ = ['dbcommon',
@@ -49,9 +45,9 @@ except locale.Error:
# module.textdomain(GETTEXT_DOMAIN)
# register the gettext function for the whole interpreter as "_"
__builtin__._ = gettext.gettext
_ = gettext.gettext
# wrap errors into usefull message
# # wrap errors into usefull message
# def log_exception(exc_type, exc_val, traceback):
# get_logger(__name__).error(exc_val)
#

View File

@@ -63,8 +63,7 @@ class File(Base):
self.source = src
def __repr__(self):
return "<File('%s', %s)>" % (self.filename.encode('utf-8'),
str(self.id))
return "<File('%s', %s)>" % (self.filename, str(self.id))
def get_all_children(self):
"""

View File

@@ -36,7 +36,7 @@ def cprint(txt, color):
"magenta": MAGENTA,
"cyan": CYAN,
"white": WHITE}
print COLOR_SEQ % (30 + color_map[color]) + txt + RESET_SEQ
print(COLOR_SEQ % (30 + color_map[color]) + txt + RESET_SEQ)
class DummyFormater(logging.Formatter):

View File

@@ -50,7 +50,7 @@ def calculate_image_path(dbpath=None, create=False):
if not os.path.exists(images_dir):
try:
os.mkdir(images_dir)
except OSError, err:
except OSError as err:
if err.errno != errno.EEXIST:
raise
elif not os.path.exists(images_dir):
@@ -60,7 +60,7 @@ def calculate_image_path(dbpath=None, create=False):
def mk_paths(fname, img_path):
"""Make path for provided pathname by calculating crc32 out of file"""
with open(fname) as fobj:
with open(fname, 'r+b') as fobj:
new_path = "%x" % (crc32(fobj.read(10*1024*1024)) & 0xffffffff)
new_path = [new_path[i:i + 2] for i in range(0, len(new_path), 2)]

View File

@@ -155,7 +155,7 @@ class Scan(object):
# in case of such, better get me a byte string. It is not perfect
# though, since it WILL crash if the update_path would contain some
# unconvertable characters.
update_path = update_path.encode("utf-8")
update_path = update_path
# refresh objects
LOG.debug("Refreshing objects")
@@ -199,8 +199,7 @@ class Scan(object):
'.ogm': 'video',
'.ogv': 'video'}
fp = os.path.join(fobj.filepath.encode(sys.getfilesystemencoding()),
fobj.filename.encode(sys.getfilesystemencoding()))
fp = os.path.join(fobj.filepath, fobj.filename)
mimeinfo = mimetypes.guess_type(fp)
if mimeinfo[0]:
@@ -287,13 +286,8 @@ class Scan(object):
"""
fullpath = os.path.join(path, fname)
fname = fname.decode(sys.getfilesystemencoding(),
errors="replace")
path = path.decode(sys.getfilesystemencoding(),
errors="replace")
if ftype == TYPE['link']:
fname = fname + " -> " + os.readlink(fullpath).decode('utf-8')
fname = fname + " -> " + os.readlink(fullpath)
fob = {'filename': fname,
'path': path,
@@ -378,7 +372,7 @@ class Scan(object):
LOG.info("Scanning `%s' [%s/%s]", fullpath, self.current_count,
self.files_count)
root, dirs, files = os.walk(fullpath).next()
root, dirs, files = next(os.walk(fullpath))
for fname in files:
fpath = os.path.join(root, fname)
extension = os.path.splitext(fname)[1]

View File

@@ -92,10 +92,10 @@ class Video(object):
if scale < 1:
return None
no_pictures = self.tags['length'] / scale
no_pictures = self.tags['length'] // scale
if no_pictures > 8:
no_pictures = (no_pictures / 8) * 8 # only multiple of 8, please.
no_pictures = (no_pictures // 8) * 8 # only multiple of 8, please.
else:
# for really short movies
no_pictures = 4
@@ -113,16 +113,16 @@ class Video(object):
"""
Return formatted tags as a string
"""
out_tags = u''
out_tags = ''
if 'container' in self.tags:
out_tags += u"Container: %s\n" % self.tags['container']
out_tags += "Container: %s\n" % self.tags['container']
if 'width' in self.tags and 'height' in self.tags:
out_tags += u"Resolution: %sx%s\n" % (self.tags['width'],
out_tags += "Resolution: %sx%s\n" % (self.tags['width'],
self.tags['height'])
if 'duration' in self.tags:
out_tags += u"Duration: %s\n" % self.tags['duration']
out_tags += "Duration: %s\n" % self.tags['duration']
if 'video_codec' in self.tags:
out_tags += "Video codec: %s\n" % self.tags['video_codec']
@@ -178,7 +178,7 @@ class Video(object):
@directory - full output directory name
@no_pictures - number of pictures to take
"""
step = float(self.tags['length'] / (no_pictures + 1))
step = self.tags['length'] / (no_pictures + 1)
current_time = 0
for dummy in range(1, no_pictures + 1):
current_time += step
@@ -191,7 +191,8 @@ class Video(object):
try:
shutil.move(os.path.join(directory, "00000001.jpg"),
os.path.join(directory, "picture_%s.jpg" % time))
except IOError, (errno, strerror):
except IOError as exc:
errno, strerror = exc.args
LOG.error('error capturing file from movie "%s" at position '
'%s. Errors: %s, %s', self.filename, time, errno,
strerror)
@@ -234,7 +235,7 @@ class Video(object):
img_list = [Image.open(os.path.join(directory, fn)).resize(dim) \
for fn in ifn_list]
rows = no_pictures / row_length
rows = no_pictures // row_length
cols = row_length
isize = (cols * dim[0] + cols + 1,
rows * dim[1] + rows + 1)

View File

@@ -40,7 +40,7 @@ def colorize(txt, color):
def asserdb(func):
def wrapper(args):
if not os.path.exists(args.db):
print colorize("File `%s' does not exists!" % args.db, 'red')
print(colorize("File `%s' does not exists!" % args.db, 'red'))
sys.exit(1)
func(args)
return wrapper
@@ -151,7 +151,7 @@ class Iface(object):
node = self.root
msg = "Content of path `/':"
print colorize(msg, 'white')
print(colorize(msg, 'white'))
if recursive:
items = self._walk(node)
@@ -168,7 +168,7 @@ class Iface(object):
else:
filenames = sorted(items.keys())
print '\n'.join(filenames)
print('\n'.join(filenames))
def update(self, path, dir_to_update=None):
"""
@@ -179,8 +179,8 @@ class Iface(object):
self.root = self.root.filter(dbo.File.type == dbo.TYPE['root']).first()
node = self._resolve_path(path)
if node == self.root:
print colorize('Cannot update entire db, since root was provided '
'as path.', 'red')
print(colorize('Cannot update entire db, since root was provided '
'as path.', 'red'))
return
if not dir_to_update:
@@ -189,8 +189,8 @@ class Iface(object):
if not os.path.exists(dir_to_update):
raise OSError("Path to updtate doesn't exists: %s", dir_to_update)
print colorize("Updating node `%s' against directory "
"`%s'" % (path, dir_to_update), 'white')
print(colorize("Updating node `%s' against directory "
"`%s'" % (path, dir_to_update), 'white'))
if not self.dry_run:
scanob = scan.Scan(dir_to_update)
# scanob.update_files(node.id)
@@ -215,8 +215,8 @@ class Iface(object):
self.sess.add(config)
self.sess.commit()
print colorize("Creating new db against directory `%s'" % dir_to_add,
'white')
print(colorize("Creating new db against directory `%s'" % dir_to_add,
'white'))
if not self.dry_run:
if data_dir == ':same_as_db:':
misc.calculate_image_path(None, True)
@@ -234,7 +234,7 @@ class Iface(object):
if not os.path.exists(dir_to_add):
raise OSError("Path to add doesn't exists: %s", dir_to_add)
print colorize("Adding directory `%s'" % dir_to_add, 'white')
print(colorize("Adding directory `%s'" % dir_to_add, 'white'))
if not self.dry_run:
scanob = scan.Scan(dir_to_add)
scanob.add_files()
@@ -273,19 +273,19 @@ class Iface(object):
result = []
for word in search_words:
phrase = u'%%%s%%' % word.decode('utf-8')
phrase = u'%%%s%%' % word
query = query.filter(dbo.File.filename.like(phrase))
for item in query.all():
result.append(self._get_full_path(item))
if not result:
print "No results for `%s'" % ' '.join(search_words)
print("No results for `%s'" % ' '.join(search_words))
return
result.sort()
for item in result:
print self._annotate(item, search_words)
print(self._annotate(item, search_words))
def fsck(self):
"""Fsck orphaned images/thumbs"""
@@ -342,9 +342,9 @@ class Iface(object):
sys.stdout.flush()
if self.dry_run:
print "Following files are not associated to any items in the DB:"
print("Following files are not associated to any items in the DB:")
for filename in sorted(files_to_remove):
print filename
print(filename)
self.sess.rollback()
else:
_remove_files(image_path, files_to_remove)

View File

@@ -7,7 +7,7 @@ from distutils.core import setup
setup(name='pygtktalog',
packages=['pygtktalog'],
version='2.0',
version='3.0',
description='Catalog application with GTK interface',
author='Roman Dobosz',
author_email='gryf73@gmail.com',
@@ -18,7 +18,8 @@ setup(name='pygtktalog',
scripts=['scripts/cmdcatalog.py'],
classifiers=['Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 2 :: Only',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Development Status :: 4 - Beta',
'Environment :: Console',
'Intended Audience :: End Users/Desktop',