diff --git a/comicapi/comet.py b/comicapi/comet.py index 2b3d97b..d1741c5 100644 --- a/comicapi/comet.py +++ b/comicapi/comet.py @@ -19,8 +19,8 @@ import xml.etree.ElementTree as ET #from pprint import pprint #import zipfile -from genericmetadata import GenericMetadata -import utils +from .genericmetadata import GenericMetadata +from . import utils class CoMet: @@ -76,7 +76,7 @@ class CoMet: # helper func def assign(comet_entry, md_entry): if md_entry is not None: - ET.SubElement(root, comet_entry).text = u"{0}".format(md_entry) + ET.SubElement(root, comet_entry).text = "{0}".format(md_entry) # title is manditory if md.title is None: @@ -131,43 +131,43 @@ class CoMet: if credit['role'].lower() in set(self.writer_synonyms): ET.SubElement( root, - 'writer').text = u"{0}".format( + 'writer').text = "{0}".format( credit['person']) if credit['role'].lower() in set(self.penciller_synonyms): ET.SubElement( root, - 'penciller').text = u"{0}".format( + 'penciller').text = "{0}".format( credit['person']) if credit['role'].lower() in set(self.inker_synonyms): ET.SubElement( root, - 'inker').text = u"{0}".format( + 'inker').text = "{0}".format( credit['person']) if credit['role'].lower() in set(self.colorist_synonyms): ET.SubElement( root, - 'colorist').text = u"{0}".format( + 'colorist').text = "{0}".format( credit['person']) if credit['role'].lower() in set(self.letterer_synonyms): ET.SubElement( root, - 'letterer').text = u"{0}".format( + 'letterer').text = "{0}".format( credit['person']) if credit['role'].lower() in set(self.cover_synonyms): ET.SubElement( root, - 'coverDesigner').text = u"{0}".format( + 'coverDesigner').text = "{0}".format( credit['person']) if credit['role'].lower() in set(self.editor_synonyms): ET.SubElement( root, - 'editor').text = u"{0}".format( + 'editor').text = "{0}".format( credit['person']) # self pretty-print diff --git a/comicapi/comicarchive.py b/comicapi/comicarchive.py index cac1e01..ac7c83d 100644 --- a/comicapi/comicarchive.py +++ b/comicapi/comicarchive.py @@ -23,7 +23,7 @@ import subprocess import platform import ctypes import time -import StringIO +import io #import io #import locale #import shutil @@ -65,12 +65,13 @@ try: self._data += chunk return 1 rarfile._ReadIntoMemory._callback = _rar_cb -except: - print "WARNING: cannot find libunrar, rar support is disabled" +except Exception as e: + print(e) + print("WARNING: cannot find libunrar, rar support is disabled") pass -if platform.system() == "Windows": - import _subprocess +#if platform.system() == "Windows": +# import _subprocess try: import Image @@ -78,11 +79,11 @@ try: except ImportError: pil_available = False -from comicinfoxml import ComicInfoXml -from comicbookinfo import ComicBookInfo -from comet import CoMet -from genericmetadata import GenericMetadata, PageType -from filenameparser import FileNameParser +from .comicinfoxml import ComicInfoXml +from .comicbookinfo import ComicBookInfo +from .comet import CoMet +from .genericmetadata import GenericMetadata, PageType +from .filenameparser import FileNameParser #from settings import ComicTaggerSettings @@ -109,7 +110,10 @@ class ZipArchiver: return comment def setArchiveComment(self, comment): - return self.writeZipComment(self.path, comment) + zf = zipfile.ZipFile(self.path, 'a') + zf.comment = bytes(comment, 'utf-8') + zf.close() + return True def readArchiveFile(self, archive_file): data = "" @@ -118,14 +122,13 @@ class ZipArchiver: try: data = zf.read(archive_file) except zipfile.BadZipfile as e: - print >> sys.stderr, u"bad zipfile [{0}]: {1} :: {2}".format( - e, self.path, archive_file) + print("bad zipfile [{0}]: {1} :: {2}".format(e, self.path, archive_file), file=sys.stderr) zf.close() raise IOError except Exception as e: zf.close() - print >> sys.stderr, u"bad zipfile [{0}]: {1} :: {2}".format( - e, self.path, archive_file) + print("bad zipfile [{0}]: {1} :: {2}".format( + e, self.path, archive_file), file=sys.stderr) raise IOError finally: zf.close() @@ -164,8 +167,8 @@ class ZipArchiver: zf.close() return namelist except Exception as e: - print >> sys.stderr, u"Unable to get zipfile list [{0}]: {1}".format( - e, self.path) + print("Unable to get zipfile list [{0}]: {1}".format( + e, self.path), file=sys.stderr) return [] def rebuildZipFile(self, exclude_list): @@ -220,7 +223,7 @@ class ZipArchiver: found = False value = bytearray() - + # walk backwards to find the "End of Central Directory" record while (not found) and (-pos != file_length): # seek, relative to EOF @@ -253,12 +256,12 @@ class ZipArchiver: fo.seek(pos + 2, 2) # write out the comment itself - fo.write(comment) + fo.write(bytes(comment)) fo.truncate() fo.close() else: raise Exception('Failed to write comment to zip file!') - except: + except Exception as e: return False else: return True @@ -280,8 +283,8 @@ class ZipArchiver: if not self.writeZipComment(self.path, comment): return False except Exception as e: - print >> sys.stderr, u"Error while copying to {0}: {1}".format( - self.path, e) + print("Error while copying to {0}: {1}".format( + self.path, e), file=sys.stderr) return False else: return True @@ -305,7 +308,7 @@ class RarArchiver: # windows only, keeps the cmd.exe from popping up if platform.system() == "Windows": self.startupinfo = subprocess.STARTUPINFO() - self.startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW + self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW else: self.startupinfo = None @@ -314,37 +317,38 @@ class RarArchiver: pass def getArchiveComment(self): - rarc = self.getRARObj() return rarc.comment def setArchiveComment(self, comment): - if self.rar_exe_path is not None: try: # write comment to temp file tmp_fd, tmp_name = tempfile.mkstemp() - f = os.fdopen(tmp_fd, 'w+b') + f = os.fdopen(tmp_fd, 'w+') f.write(comment) f.close() working_dir = os.path.dirname(os.path.abspath(self.path)) - + # use external program to write comment to Rar archive - subprocess.call([self.rar_exe_path, + proc_args = [self.rar_exe_path, 'c', '-w' + working_dir, '-c-', '-z' + tmp_name, - self.path], + self.path] + subprocess.call(proc_args, startupinfo=self.startupinfo, - stdout=RarArchiver.devnull) + stdout=RarArchiver.devnull, + stdin=RarArchiver.devnull, + stderr=RarArchiver.devnull) if platform.system() == "Darwin": time.sleep(1) - os.remove(tmp_name) - except: + except Exception as e: + print(e) return False else: return True @@ -376,26 +380,26 @@ class RarArchiver: #entries = rarc.read_files( archive_file ) if entries[0][0].file_size != len(entries[0][1]): - print >> sys.stderr, u"readArchiveFile(): [file is not expected size: {0} vs {1}] {2}:{3} [attempt # {4}]".format( + print("readArchiveFile(): [file is not expected size: {0} vs {1}] {2}:{3} [attempt # {4}]".format( entries[0][0].file_size, len( - entries[0][1]), self.path, archive_file, tries) + entries[0][1]), self.path, archive_file, tries), file=sys.stderr) continue except (OSError, IOError) as e: - print >> sys.stderr, u"readArchiveFile(): [{0}] {1}:{2} attempt#{3}".format( - str(e), self.path, archive_file, tries) + print("readArchiveFile(): [{0}] {1}:{2} attempt#{3}".format( + str(e), self.path, archive_file, tries), file=sys.stderr) time.sleep(1) except Exception as e: - print >> sys.stderr, u"Unexpected exception in readArchiveFile(): [{0}] for {1}:{2} attempt#{3}".format( - str(e), self.path, archive_file, tries) + print("Unexpected exception in readArchiveFile(): [{0}] for {1}:{2} attempt#{3}".format( + str(e), self.path, archive_file, tries), file=sys.stderr) break else: # Success" # entries is a list of of tuples: ( rarinfo, filedata) if tries > 1: - print >> sys.stderr, u"Attempted read_files() {0} times".format( - tries) + print("Attempted read_files() {0} times".format( + tries), file=sys.stderr) if (len(entries) == 1): return entries[0][1] else: @@ -428,7 +432,9 @@ class RarArchiver: self.path, tmp_file], startupinfo=self.startupinfo, - stdout=RarArchiver.devnull) + stdout=RarArchiver.devnull, + stdin=RarArchiver.devnull, + stderr=RarArchiver.devnull) if platform.system() == "Darwin": time.sleep(1) @@ -451,7 +457,9 @@ class RarArchiver: self.path, archive_file], startupinfo=self.startupinfo, - stdout=RarArchiver.devnull) + stdout=RarArchiver.devnull, + stdin=RarArchiver.devnull, + stderr=RarArchiver.devnull) if platform.system() == "Darwin": time.sleep(1) @@ -479,8 +487,8 @@ class RarArchiver: namelist.append(item.filename) except (OSError, IOError) as e: - print >> sys.stderr, u"getArchiveFilenameList(): [{0}] {1} attempt#{2}".format( - str(e), self.path, tries) + print("getArchiveFilenameList(): [{0}] {1} attempt#{2}".format( + str(e), self.path, tries), file=sys.stderr) time.sleep(1) else: @@ -497,8 +505,8 @@ class RarArchiver: rarc = rarfile.RarFile( self.path ) except (OSError, IOError) as e: - print >> sys.stderr, u"getRARObj(): [{0}] {1} attempt#{2}".format( - str(e), self.path, tries) + print("getRARObj(): [{0}] {1} attempt#{2}".format( + str(e), self.path, tries), file=sys.stderr) time.sleep(1) else: @@ -634,7 +642,7 @@ class ComicArchive: logo_data = None class ArchiveType: - Zip, Rar, Folder, Pdf, Unknown = range(5) + Zip, Rar, Folder, Pdf, Unknown = list(range(5)) def __init__(self, path, rar_exe_path=None, default_image_path=None): self.path = path @@ -729,7 +737,7 @@ class ComicArchive: if self.archive_type == self.ArchiveType.Unknown: return False - elif check_rar_status and self.isRar() and self.rar_exe_path is None: + elif check_rar_status and self.isRar() and not self.rar_exe_path: return False elif not os.access(self.path, os.W_OK): @@ -817,7 +825,7 @@ class ComicArchive: try: image_data = self.archiver.readArchiveFile(filename) except IOError: - print >> sys.stderr, u"Error reading in page. Substituting logo page." + print("Error reading in page. Substituting logo page.", file=sys.stderr) image_data = ComicArchive.logo_data return image_data @@ -859,7 +867,7 @@ class ComicArchive: # sort by most common sorted_buckets = sorted( - length_buckets.iteritems(), + iter(length_buckets.items()), key=lambda k_v: ( k_v[1], k_v[0]), @@ -1006,7 +1014,7 @@ class ComicArchive: try: raw_cix = self.archiver.readArchiveFile(self.ci_xml_filename) except IOError: - print "Error reading in raw CIX!" + print("Error reading in raw CIX!") raw_cix = "" return raw_cix @@ -1075,13 +1083,13 @@ class ComicArchive: def readRawCoMet(self): if not self.hasCoMet(): - print >> sys.stderr, self.path, "doesn't have CoMet data!" + print(self.path, "doesn't have CoMet data!", file=sys.stderr) return None try: raw_comet = self.archiver.readArchiveFile(self.comet_filename) except IOError: - print >> sys.stderr, u"Error reading in raw CoMet!" + print("Error reading in raw CoMet!", file=sys.stderr) raw_comet = "" return raw_comet @@ -1136,7 +1144,7 @@ class ComicArchive: data = self.archiver.readArchiveFile(n) except: data = "" - print >> sys.stderr, u"Error reading in Comet XML for validation!" + print("Error reading in Comet XML for validation!", file=sys.stderr) if CoMet().validateString(data): # since we found it, save it! self.comet_filename = n @@ -1156,7 +1164,7 @@ class ComicArchive: data = self.getPage(idx) if data is not None: try: - im = Image.open(StringIO.StringIO(data)) + im = Image.open(io.StringIO(data)) w, h = im.size p['ImageSize'] = str(len(data)) diff --git a/comicapi/comicbookinfo.py b/comicapi/comicbookinfo.py index 80e80f4..cb2d9e2 100644 --- a/comicapi/comicbookinfo.py +++ b/comicapi/comicbookinfo.py @@ -18,8 +18,8 @@ import json from datetime import datetime #import zipfile -from genericmetadata import GenericMetadata -import utils +from .genericmetadata import GenericMetadata +from . import utils #import ctversion @@ -27,7 +27,7 @@ class ComicBookInfo: def metadataFromString(self, string): - cbi_container = json.loads(unicode(string, 'utf-8')) + cbi_container = json.loads(str(string, 'utf-8')) metadata = GenericMetadata() @@ -109,7 +109,7 @@ class ComicBookInfo: # helper func def toInt(s): i = None - if type(s) in [str, unicode, int]: + if type(s) in [str, str, int]: try: i = int(s) except ValueError: diff --git a/comicapi/comicinfoxml.py b/comicapi/comicinfoxml.py index 02cc61e..757fa46 100644 --- a/comicapi/comicinfoxml.py +++ b/comicapi/comicinfoxml.py @@ -19,8 +19,8 @@ import xml.etree.ElementTree as ET #from pprint import pprint #import zipfile -from genericmetadata import GenericMetadata -import utils +from .genericmetadata import GenericMetadata +from . import utils class ComicInfoXml: @@ -54,7 +54,8 @@ class ComicInfoXml: header = '\n' tree = self.convertMetadataToXML(self, metadata) - return header + ET.tostring(tree.getroot()) + tree_str = ET.tostring(tree.getroot()).decode() + return header + tree_str def indent(self, elem, level=0): # for making the XML output readable @@ -85,7 +86,7 @@ class ComicInfoXml: def assign(cix_entry, md_entry): if md_entry is not None: - ET.SubElement(root, cix_entry).text = u"{0}".format(md_entry) + ET.SubElement(root, cix_entry).text = "{0}".format(md_entry) assign('Title', md.title) assign('Series', md.series) diff --git a/comicapi/filenameparser.py b/comicapi/filenameparser.py index 5bfbf26..476d14b 100644 --- a/comicapi/filenameparser.py +++ b/comicapi/filenameparser.py @@ -22,7 +22,7 @@ This should probably be re-written, but, well, it mostly works! import re import os -from urllib import unquote +from urllib.parse import unquote class FileNameParser: diff --git a/comicapi/genericmetadata.py b/comicapi/genericmetadata.py index f9d5a4d..b3679a2 100644 --- a/comicapi/genericmetadata.py +++ b/comicapi/genericmetadata.py @@ -20,7 +20,7 @@ possible, however lossy it might be # See the License for the specific language governing permissions and # limitations under the License. -import utils +from . import utils class PageType: @@ -251,7 +251,7 @@ class GenericMetadata: return "No metadata" def add_string(tag, val): - if val is not None and u"{0}".format(val) != "": + if val is not None and "{0}".format(val) != "": vals.append((tag, val)) def add_attr_string(tag): @@ -314,7 +314,7 @@ class GenericMetadata: # format the data nicely outstr = "" - fmt_str = u"{0: <" + str(flen) + "} {1}\n" + fmt_str = "{0: <" + str(flen) + "} {1}\n" for i in vals: outstr += fmt_str.format(i[0] + ":", i[1]) diff --git a/comicapi/issuestring.py b/comicapi/issuestring.py index 1a561c0..2f441c1 100644 --- a/comicapi/issuestring.py +++ b/comicapi/issuestring.py @@ -44,7 +44,7 @@ class IssueString: if len(text) == 0: return - text = unicode(text) + text = str(text) # skip the minus sign if it's first if text[0] == '-': @@ -119,7 +119,7 @@ class IssueString: def asFloat(self): # return the float, with no suffix - if self.suffix == u"½": + if self.suffix == "½": if self.num is not None: return self.num + .5 else: diff --git a/comicapi/utils.py b/comicapi/utils.py index f82309f..bd6facb 100644 --- a/comicapi/utils.py +++ b/comicapi/utils.py @@ -55,20 +55,22 @@ def get_recursive_filelist(pathlist): # if path is a folder, walk it recursively, and all files underneath if isinstance(p, str): # make sure string is unicode - p = p.decode(filename_encoding) # , 'replace') - elif not isinstance(p, unicode): + #p = p.decode(filename_encoding) # , 'replace') + pass + elif not isinstance(p, str): # it's probably a QString - p = unicode(p) + p = str(p) if os.path.isdir(p): for root, dirs, files in os.walk(p): for f in files: if isinstance(f, str): # make sure string is unicode - f = f.decode(filename_encoding, 'replace') - elif not isinstance(f, unicode): + #f = f.decode(filename_encoding, 'replace') + pass + elif not isinstance(f, str): # it's probably a QString - f = unicode(f) + f = str(f) filelist.append(os.path.join(root, f)) else: filelist.append(p) @@ -121,7 +123,7 @@ def which(program): def removearticles(text): text = text.lower() - articles = ['and', 'the', 'a', '&', 'issue'] + articles = ['and', 'a', '&', 'issue'] newText = '' for word in text.split(' '): if word not in articles: