From 8eca5302754db5456c4049d1ae3d6b24e4c4949f Mon Sep 17 00:00:00 2001 From: Hugo Posnic Date: Sat, 18 Nov 2017 14:44:11 +0100 Subject: [PATCH] First try to adopt Python3 and PyQt5 --- src/trimage/{ThreadPool => }/ThreadPool.py | 124 ++++++++++----------- src/trimage/ThreadPool/__init__.py | 1 - src/trimage/{filesize => }/filesize.py | 0 src/trimage/filesize/PKG-INFO | 71 ------------ src/trimage/filesize/README.txt | 50 --------- src/trimage/filesize/__init__.py | 2 - src/trimage/trimage.py | 59 +++++----- src/trimage/ui.py | 37 +++--- 8 files changed, 109 insertions(+), 235 deletions(-) rename src/trimage/{ThreadPool => }/ThreadPool.py (84%) delete mode 100644 src/trimage/ThreadPool/__init__.py rename src/trimage/{filesize => }/filesize.py (100%) delete mode 100644 src/trimage/filesize/PKG-INFO delete mode 100644 src/trimage/filesize/README.txt delete mode 100644 src/trimage/filesize/__init__.py diff --git a/src/trimage/ThreadPool/ThreadPool.py b/src/trimage/ThreadPool.py similarity index 84% rename from src/trimage/ThreadPool/ThreadPool.py rename to src/trimage/ThreadPool.py index 5c64409..7f92344 100644 --- a/src/trimage/ThreadPool/ThreadPool.py +++ b/src/trimage/ThreadPool.py @@ -2,13 +2,13 @@ ThreadPool Implementation @author: Morten Holdflod Moeller - morten@holdflod.dk -@license: LGPL v3 +@license: LGPL v3 ''' from __future__ import with_statement from threading import Thread, RLock from time import sleep -from Queue import Queue, Empty +from queue import Queue, Empty import logging import sys @@ -31,7 +31,7 @@ class ThreadPoolMixIn: self.__private_threadpool = True else: self.__private_threadpool = False - + self.__threadpool = threadpool def process_request_thread(self, request, client_address): @@ -48,11 +48,11 @@ class ThreadPoolMixIn: self.close_request(request) def process_request(self, request, client_address): - self.__threadpool.add_job(self.process_request_thread, [request, client_address]) + self.__threadpool.add_job(self.process_request_thread, [request, client_address]) def shutdown(self): if (self.__private_threadpool): self.__threadpool.shutdown() - + class AddJobException(Exception): ''' @@ -61,64 +61,64 @@ class AddJobException(Exception): ''' def __init__(self, msg): Exception.__init__(self, msg) - + class ThreadPool: ''' The class implementing the ThreadPool. - - Instantiate and add jobs using add_job(func, args_list) + + Instantiate and add jobs using add_job(func, args_list) ''' class Job: #IGNORE:R0903 ''' Class encapsulating a job to be handled - by ThreadPool workers + by ThreadPool workers ''' def __init__(self, function, args, return_callback=None): self.callable = function self.arguments = args self.return_callback = return_callback - + def execute(self): ''' Called to execute the function ''' try: return_value = self.callable(*self.arguments) #IGNORE:W0142 - except Exception, excep: #IGNORE:W0703 + except Exception as excep: #IGNORE:W0703 logger = logging.getLogger("threadpool.worker") logger.warning("A job in the ThreadPool raised an exception: " + excep) #else do nothing cause we don't know what to do... - return - + return + try: if (self.return_callback != None): self.return_callback(return_value) - except Exception, _: #IGNORE:W0703 everything could go wrong... + except Exception as _: #IGNORE:W0703 everything could go wrong... logger = logging.getLogger('threadpool') logger.warning('Error while delivering return value to callback function') class Worker(Thread): ''' - A worker thread handling jobs in the thread pool + A worker thread handling jobs in the thread pool job queue ''' - + def __init__(self, pool): Thread.__init__(self) - + if (not isinstance(pool, ThreadPool)): raise TypeError("pool is not a ThreadPool instance") - + self.pool = pool - + self.alive = True self.start() - + def run(self): ''' - The workers main-loop getting jobs from queue + The workers main-loop getting jobs from queue and executing them ''' while self.alive: @@ -130,83 +130,83 @@ class ThreadPool: self.pool.worker_inactive() else: self.alive = False - + self.pool.punch_out() - + def __init__(self, max_workers = 5, kill_workers_after = 3): if (not isinstance(max_workers, int)): raise TypeError("max_workers is not an int") if (max_workers < 1): raise ValueError('max_workers must be >= 1') - + if (not isinstance(kill_workers_after, int)): raise TypeError("kill_workers_after is not an int") - + self.__max_workers = max_workers self.__kill_workers_after = kill_workers_after - + # This Queue is assumed Thread Safe self.__jobs = Queue() - - self.__worker_count_lock = RLock() + + self.__worker_count_lock = RLock() self.__worker_count = 0 self.__active_worker_count = 0 - + self.__shutting_down = False logger = logging.getLogger('threadpool') logger.info('started') - + def shutdown(self, wait_for_workers_period = 1, clean_shutdown_reties = 5): if (not isinstance(clean_shutdown_reties, int)): raise TypeError("clean_shutdown_reties is not an int") if (not clean_shutdown_reties >= 0): raise ValueError('clean_shutdown_reties must be >= 0') - + if (not isinstance(wait_for_workers_period, int)): raise TypeError("wait_for_workers_period is not an int") if (not wait_for_workers_period >= 0): raise ValueError('wait_for_workers_period must be >= 0') - + logger = logging.getLogger("threadpool") logger.info("shutting down") - + with self.__worker_count_lock: self.__shutting_down = True self.__max_workers = 0 self.__kill_workers_after = 0 - + retries_left = clean_shutdown_reties while (retries_left > 0): - + with self.__worker_count_lock: logger.info("waiting for workers to shut down (%i), %i workers left"%(retries_left, self.__worker_count)) if (self.__worker_count > 0): retries_left -= 1 else: retries_left = 0 - + sleep(wait_for_workers_period) - - + + with self.__worker_count_lock: if (self.__worker_count > 0): logger.warning("shutdown stopped waiting. Still %i active workers"%self.__worker_count) clean_shutdown = False else: clean_shutdown = True - + logger.info("shutdown complete") - + return clean_shutdown - + def punch_out(self): ''' - Called by worker to update worker count + Called by worker to update worker count when the worker is shutting down ''' with self.__worker_count_lock: self.__worker_count -= 1 - + def __new_worker(self): ''' Adding a new worker thread to the thread pool @@ -214,58 +214,58 @@ class ThreadPool: with self.__worker_count_lock: ThreadPool.Worker(self) self.__worker_count += 1 - + def worker_active(self): with self.__worker_count_lock: self.__active_worker_count = self.__active_worker_count + 1 - + def worker_inactive(self): with self.__worker_count_lock: self.__active_worker_count = self.__active_worker_count - 1 - + def add_job(self, function, args = None, return_callback=None): ''' Put new job into queue ''' - + if (not callable(function)): raise TypeError("function is not a callable") if (not ( args == None or isinstance(args, list))): raise TypeError("args is not a list") if (not (return_callback == None or callable(return_callback))): raise TypeError("return_callback is not a callable") - + if (args == None): args = [] - + job = ThreadPool.Job(function, args, return_callback) - + with self.__worker_count_lock: if (self.__shutting_down): raise AddJobException("ThreadPool is shutting down") - + try: start_new_worker = False if (self.__worker_count < self.__max_workers): if (self.__active_worker_count == self.__worker_count): start_new_worker = True - + self.__jobs.put(job) - - if (start_new_worker): + + if (start_new_worker): self.__new_worker() - + except Exception: raise AddJobException("Could not add job") - - + + def get_job(self): ''' - Retrieve next job from queue - workers die (and should) when - returning None + Retrieve next job from queue + workers die (and should) when + returning None ''' - + job = None try: if (self.__kill_workers_after < 0): @@ -276,5 +276,5 @@ class ThreadPool: job = self.__jobs.get(True, self.__kill_workers_after) except Empty: job = None - + return job diff --git a/src/trimage/ThreadPool/__init__.py b/src/trimage/ThreadPool/__init__.py deleted file mode 100644 index 727a8b3..0000000 --- a/src/trimage/ThreadPool/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ThreadPool import ThreadPool, ThreadPoolMixIn \ No newline at end of file diff --git a/src/trimage/filesize/filesize.py b/src/trimage/filesize.py similarity index 100% rename from src/trimage/filesize/filesize.py rename to src/trimage/filesize.py diff --git a/src/trimage/filesize/PKG-INFO b/src/trimage/filesize/PKG-INFO deleted file mode 100644 index fe3aadb..0000000 --- a/src/trimage/filesize/PKG-INFO +++ /dev/null @@ -1,71 +0,0 @@ -Metadata-Version: 1.0 -Name: hurry.filesize -Version: 0.9 -Summary: A simple Python library for human readable file sizes (or anything sized in bytes). -Home-page: UNKNOWN -Author: Martijn Faassen, Startifact -Author-email: faassen@startifact.com -License: ZPL 2.1 -Description: hurry.filesize - ============== - - hurry.filesize a simple Python library that can take a number of bytes and - returns a human-readable string with the size in it, in kilobytes (K), - megabytes (M), etc. - - The default system it uses is "traditional", where multipliers of 1024 - increase the unit size:: - - >>> from hurry.filesize import size - >>> size(1024) - '1K' - - An alternative, slightly more verbose system:: - - >>> from hurry.filesize import alternative - >>> size(1, system=alternative) - '1 byte' - >>> size(10, system=alternative) - '10 bytes' - >>> size(1024, system=alternative) - '1 KB' - - A verbose system:: - - >>> from hurry.filesize import verbose - >>> size(10, system=verbose) - '10 bytes' - >>> size(1024, system=verbose) - '1 kilobyte' - >>> size(2000, system=verbose) - '1 kilobyte' - >>> size(3000, system=verbose) - '2 kilobytes' - >>> size(1024 * 1024, system=verbose) - '1 megabyte' - >>> size(1024 * 1024 * 3, system=verbose) - '3 megabytes' - - You can also use the SI system, where multipliers of 1000 increase the unit - size:: - - >>> from hurry.filesize import si - >>> size(1000, system=si) - '1K' - - - Changes - ======= - - 0.9 (2009-03-11) - ---------------- - - * Initial public release. - - Download - ======== - -Keywords: file size bytes -Platform: UNKNOWN -Classifier: Programming Language :: Python -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/src/trimage/filesize/README.txt b/src/trimage/filesize/README.txt deleted file mode 100644 index 6a0fad6..0000000 --- a/src/trimage/filesize/README.txt +++ /dev/null @@ -1,50 +0,0 @@ -hurry.filesize -============== - -hurry.filesize a simple Python library that can take a number of bytes and -returns a human-readable string with the size in it, in kilobytes (K), -megabytes (M), etc. - -The default system it uses is "traditional", where multipliers of 1024 -increase the unit size:: - - >>> from hurry.filesize import size - >>> size(1024) - '1K' - -An alternative, slightly more verbose system:: - - >>> from hurry.filesize import alternative - >>> size(1, system=alternative) - '1 byte' - >>> size(10, system=alternative) - '10 bytes' - >>> size(1024, system=alternative) - '1 KB' - -A verbose system:: - - >>> from hurry.filesize import verbose - >>> size(10, system=verbose) - '10 bytes' - >>> size(1024, system=verbose) - '1 kilobyte' - >>> size(2000, system=verbose) - '1 kilobyte' - >>> size(3000, system=verbose) - '2 kilobytes' - >>> size(1024 * 1024, system=verbose) - '1 megabyte' - >>> size(1024 * 1024 * 3, system=verbose) - '3 megabytes' - -You can also use the SI system, where multipliers of 1000 increase the unit -size:: - - >>> from hurry.filesize import si - >>> size(1000, system=si) - '1K' - - -http://pypi.python.org/pypi/hurry.filesize - diff --git a/src/trimage/filesize/__init__.py b/src/trimage/filesize/__init__.py deleted file mode 100644 index 68d9fc2..0000000 --- a/src/trimage/filesize/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from filesize import size -from filesize import traditional, alternative, verbose, iec, si diff --git a/src/trimage/trimage.py b/src/trimage/trimage.py index 84b13a0..5fb8bf5 100644 --- a/src/trimage/trimage.py +++ b/src/trimage/trimage.py @@ -11,13 +11,14 @@ from shutil import copy from subprocess import call, PIPE from optparse import OptionParser -from PyQt4.QtCore import * -from PyQt4.QtGui import * +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * from filesize import * from imghdr import what as determinetype -from Queue import Queue -from ThreadPool import ThreadPool +from queue import Queue +from ThreadPool import ThreadPool, ThreadPoolMixIn from multiprocessing import cpu_count from ui import Ui_trimage @@ -25,7 +26,7 @@ from ui import Ui_trimage VERSION = "1.0.5" -class StartQT4(QMainWindow): +class StartQT5(QMainWindow): def __init__(self, parent=None): QWidget.__init__(self, parent) @@ -40,7 +41,7 @@ class StartQT4(QMainWindow): QCoreApplication.setOrganizationDomain("trimage.org") QCoreApplication.setApplicationName("Trimage") self.settings = QSettings() - self.restoreGeometry(self.settings.value("geometry").toByteArray()) + self.restoreGeometry(self.settings.value("geometry")) # check if apps are installed if self.checkapps(): @@ -61,17 +62,15 @@ class StartQT4(QMainWindow): self.thread = Worker() # connect signals with slots - QObject.connect(self.ui.addfiles, SIGNAL("clicked()"), - self.file_dialog) - QObject.connect(self.ui.recompress, SIGNAL("clicked()"), - self.recompress_files) - QObject.connect(self.quit_shortcut, SIGNAL("activated()"), - qApp, SLOT('quit()')) - QObject.connect(self.ui.processedfiles, SIGNAL("fileDropEvent"), - self.file_drop) - QObject.connect(self.thread, SIGNAL("finished()"), self.update_table) - QObject.connect(self.thread, SIGNAL("terminated()"), self.update_table) - QObject.connect(self.thread, SIGNAL("updateUi"), self.update_table) + self.ui.addfiles.clicked.connect(self.file_dialog) + self.ui.recompress.clicked.connect(self.recompress_files) + # QObject.connect(self.quit_shortcut, SIGNAL("activated()"), + # qApp, SLOT('quit()')) + # QObject.connect(self.ui.processedfiles, SIGNAL("fileDropEvent"), + # self.file_drop) + # QObject.connect(self.thread, SIGNAL("finished()"), self.update_table) + # QObject.connect(self.thread, SIGNAL("terminated()"), self.update_table) + # QObject.connect(self.thread, SIGNAL("updateUi"), self.update_table) self.compressing_icon = QIcon(QPixmap(self.ui.get_image("pixmaps/compressing.gif"))) @@ -143,8 +142,8 @@ class StartQT4(QMainWindow): def file_dialog(self): """Open a file dialog and send the selected images to compress_file.""" fd = QFileDialog(self) - fd.restoreState(self.settings.value("fdstate").toByteArray()) - directory = self.settings.value("directory", QVariant("")).toString() + fd.restoreState(self.settings.value("fdstate")) + directory = self.settings.value("directory", QVariant("")) fd.setDirectory(directory) images = fd.getOpenFileNames(self, @@ -155,8 +154,8 @@ class StartQT4(QMainWindow): self.settings.setValue("fdstate", QVariant(fd.saveState())) if images: - self.settings.setValue("directory", QVariant(path.dirname(unicode(images[0])))) - self.delegator([unicode(fullpath) for fullpath in images]) + self.settings.setValue("directory", QVariant(path.dirname(images[0][0]))) + self.delegator([fullpath for fullpath in images]) def recompress_files(self): """Send each file in the current file list to compress_file again.""" @@ -174,16 +173,16 @@ class StartQT4(QMainWindow): for fullpath in images: try: # recompress images already in the list image = (i.image for i in self.imagelist - if i.image.fullpath == fullpath).next() + if i.image.fullpath == fullpath[0]).__next__() if image.compressed: image.reset() image.recompression = True delegatorlist.append(image) except StopIteration: - if not path.isdir(fullpath): - self. add_image(fullpath, delegatorlist) + if not path.isdir(fullpath[0]): + self.add_image(fullpath[0], delegatorlist) else: - self.walk(fullpath, delegatorlist) + self.walk(fullpath[0], delegatorlist) self.update_table() self.thread.compress_file(delegatorlist, self.showapp, self.verbose, @@ -214,7 +213,7 @@ class StartQT4(QMainWindow): self.systemtray.trayIcon.setToolTip("Trimage image compressor (" + str(len(self.imagelist)) + " files)") self.setWindowTitle("Trimage image compressor (" + str(len(self.imagelist)) + " files)") else: - print >> sys.stderr, u"[error] %s not a supported image file and/or not writeable" % image.fullpath + print(str(sys.stderr) + "[error] {} not a supported image file and/or not writeable".format(image.fullpath)) """ UI Functions @@ -287,7 +286,7 @@ class StartQT4(QMainWindow): while True: try: return call(command, shell=True, stdout=PIPE) - except OSError, e: + except OSError as e: if e.errno == errno.EINTR: continue else: @@ -488,7 +487,7 @@ class Worker(QThread): tp._ThreadPool__jobs.empty()): image = self.toDisplay.get() - self.emit(SIGNAL("updateUi")) + ##self.emit(SIGNAL("updateUi")) if not self.showapp and self.verbose: # we work via the commandline if image.retcode == 0: @@ -497,7 +496,7 @@ class Worker(QThread): + ir['oldfilesizestr'] + ", New Size: " + ir['newfilesizestr'] + ", Ratio: " + ir['ratiostr']) else: - print >> sys.stderr, u"[error] %s could not be compressed" % image.fullpath + print(str(sys.stderr) + "[error] {} could not be compressed".format(image.fullpath)) class Systray(QWidget): @@ -550,7 +549,7 @@ class Systray(QWidget): if __name__ == "__main__": app = QApplication(sys.argv) - myapp = StartQT4() + myapp = StartQT5() if myapp.showapp: myapp.show() diff --git a/src/trimage/ui.py b/src/trimage/ui.py index 47937da..ca3a98f 100644 --- a/src/trimage/ui.py +++ b/src/trimage/ui.py @@ -1,5 +1,6 @@ -from PyQt4.QtCore import * -from PyQt4.QtGui import * +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * from os import path class TrimageTableView(QTableView): @@ -44,7 +45,7 @@ class Ui_trimage(object): self.centralwidget.setObjectName("centralwidget") self.gridLayout_2 = QGridLayout(self.centralwidget) - self.gridLayout_2.setMargin(0) + #self.gridLayout_2.setMargin(0) self.gridLayout_2.setSpacing(0) self.gridLayout_2.setObjectName("gridLayout_2") @@ -60,7 +61,7 @@ class Ui_trimage(object): self.verticalLayout = QVBoxLayout(self.widget) self.verticalLayout.setSpacing(0) - self.verticalLayout.setMargin(0) + #self.verticalLayout.setMargin(0) self.verticalLayout.setObjectName("verticalLayout") self.frame = QFrame(self.widget) @@ -68,12 +69,12 @@ class Ui_trimage(object): self.verticalLayout_2 = QVBoxLayout(self.frame) self.verticalLayout_2.setSpacing(0) - self.verticalLayout_2.setMargin(0) + #self.verticalLayout_2.setMargin(0) self.verticalLayout_2.setObjectName("verticalLayout_2") self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setSpacing(0) - self.horizontalLayout.setMargin(10) + #self.horizontalLayout.setMargin(10) self.horizontalLayout.setObjectName("horizontalLayout") self.addfiles = QPushButton(self.frame) @@ -93,7 +94,7 @@ class Ui_trimage(object): font.setPointSize(8) self.label.setFont(font) self.label.setFrameShadow(QFrame.Plain) - self.label.setMargin(1) + #self.label.setMargin(1) self.label.setIndent(10) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) @@ -143,24 +144,22 @@ class Ui_trimage(object): def retranslateUi(self, trimage): """ Fill in the texts for all UI elements """ trimage.setWindowTitle(QApplication.translate("trimage", - "Trimage image compressor", None, QApplication.UnicodeUTF8)) + "Trimage image compressor", None)) self.addfiles.setToolTip(QApplication.translate("trimage", - "Add file to the compression list", None, - QApplication.UnicodeUTF8)) + "Add file to the compression list", None)) self.addfiles.setText(QApplication.translate("trimage", - "&Add and compress", None, QApplication.UnicodeUTF8)) + "&Add and compress", None)) self.addfiles.setShortcut(QApplication.translate("trimage", - "Alt+A", None, QApplication.UnicodeUTF8)) + "Alt+A", None)) self.label.setText(QApplication.translate("trimage", - "Drag and drop images onto the table", None, - QApplication.UnicodeUTF8)) + "Drag and drop images onto the table", None)) self.recompress.setToolTip(QApplication.translate("trimage", - "Recompress all images", None, QApplication.UnicodeUTF8)) + "Recompress all images", None)) self.recompress.setText(QApplication.translate("trimage", - "&Recompress", None, QApplication.UnicodeUTF8)) + "&Recompress", None)) self.recompress.setShortcut(QApplication.translate("trimage", - "Alt+R", None, QApplication.UnicodeUTF8)) + "Alt+R", None)) self.processedfiles.setToolTip(QApplication.translate("trimage", - "Drag files in here", None, QApplication.UnicodeUTF8)) + "Drag files in here", None)) self.processedfiles.setWhatsThis(QApplication.translate("trimage", - "Drag files in here", None, QApplication.UnicodeUTF8)) + "Drag files in here", None))