diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 75f31d53..7d3202b9 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -1,6 +1,11 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import print_function +from future import standard_library +standard_library.install_aliases() +from builtins import str +from builtins import object import sys from sys import platform from collections import OrderedDict @@ -26,11 +31,11 @@ if getattr(sys, 'frozen', False): if 'TCL_LIBRARY' in environ: environ.pop('TCL_LIBRARY') -import Tkinter as tk -import ttk -import tkFileDialog -import tkFont -import tkMessageBox +import tkinter as tk +import tkinter.ttk +import tkinter.filedialog +import tkinter.font +import tkinter.messagebox from ttkHyperlinkLabel import HyperlinkLabel if __debug__: @@ -58,7 +63,7 @@ from theme import theme SERVER_RETRY = 5 # retry pause for Companion servers [s] -class AppWindow: +class AppWindow(object): # Tkinter Event types EVENT_KEYPRESS = 2 @@ -125,7 +130,7 @@ class AppWindow: else: appitem.grid(columnspan=2, sticky=tk.EW) - self.button = ttk.Button(frame, text=_('Update'), width=28, default=tk.ACTIVE, state=tk.DISABLED) # Update button in main window + self.button = tkinter.ttk.Button(frame, text=_('Update'), width=28, default=tk.ACTIVE, state=tk.DISABLED) # Update button in main window self.theme_button = tk.Label(frame, width = platform == 'darwin' and 32 or 28, state=tk.DISABLED) self.status = tk.Label(frame, name='status', anchor=tk.W) @@ -378,10 +383,10 @@ class AppWindow: self.file_menu.entryconfigure(0, state=tk.NORMAL) # Status self.file_menu.entryconfigure(1, state=tk.NORMAL) # Save Raw Data except (companion.CredentialsError, companion.ServerError, companion.ServerLagging) as e: - self.status['text'] = unicode(e) + self.status['text'] = str(e) except Exception as e: if __debug__: print_exc() - self.status['text'] = unicode(e) + self.status['text'] = str(e) self.cooldown() def getandsend(self, event=None, retrying=False): @@ -480,7 +485,7 @@ class AppWindow: # Companion API problem except companion.ServerLagging as e: if retrying: - self.status['text'] = unicode(e) + self.status['text'] = str(e) play_bad = True else: # Retry once if Companion server is unresponsive @@ -488,14 +493,14 @@ class AppWindow: return # early exit to avoid starting cooldown count except companion.CmdrError as e: # Companion API return doesn't match Journal - self.status['text'] = unicode(e) + self.status['text'] = str(e) play_bad = True companion.session.invalidate() self.login() except Exception as e: # Including CredentialsError, ServerError if __debug__: print_exc() - self.status['text'] = unicode(e) + self.status['text'] = str(e) play_bad = True if not self.status['text']: # no errors @@ -510,7 +515,7 @@ class AppWindow: try: data = companion.session.station() if __debug__: - print 'Retry for shipyard - ' + (data['commander'].get('docked') and (data.get('lastStarport', {}).get('ships') and 'Success' or 'Failure') or 'Undocked!') + print('Retry for shipyard - ' + (data['commander'].get('docked') and (data.get('lastStarport', {}).get('ships') and 'Success' or 'Failure') or 'Undocked!')) if not data['commander'].get('docked'): pass # might have undocked while we were waiting for retry in which case station data is unreliable elif (data.get('lastSystem', {}).get('name') == monitor.system and @@ -577,7 +582,7 @@ class AppWindow: if entry['event'] in ['StartUp', 'LoadGame'] and monitor.started: # Can start dashboard monitoring if not dashboard.start(self.w, monitor.started): - print "Can't start Status monitoring" + print("Can't start Status monitoring") # Export loadout if entry['event'] == 'Loadout' and not monitor.state['Captain'] and config.getint('output') & config.OUT_SHIP: @@ -606,10 +611,10 @@ class AppWindow: self.file_menu.entryconfigure(0, state=tk.NORMAL) # Status self.file_menu.entryconfigure(1, state=tk.NORMAL) # Save Raw Data except companion.ServerError as e: - self.status['text'] = unicode(e) + self.status['text'] = str(e) except Exception as e: if __debug__: print_exc() - self.status['text'] = unicode(e) + self.status['text'] = str(e) self.cooldown() # Handle Status event @@ -677,7 +682,7 @@ class AppWindow: try: data = companion.session.station() self.status['text'] = '' - f = tkFileDialog.asksaveasfilename(parent = self.w, + f = tkinter.filedialog.asksaveasfilename(parent = self.w, defaultextension = platform=='darwin' and '.json' or '', filetypes = [('JSON', '.json'), ('All Files', '*')], initialdir = config.get('outdir'), @@ -689,7 +694,7 @@ class AppWindow: self.status['text'] = str(e) except Exception as e: if __debug__: print_exc() - self.status['text'] = unicode(e) + self.status['text'] = str(e) def onexit(self, event=None): if platform!='darwin' or self.w.winfo_rooty()>0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 @@ -797,7 +802,7 @@ if __name__ == "__main__": # By default py2exe tries to write log to dirname(sys.executable) which fails when installed import tempfile sys.stdout = sys.stderr = open(join(tempfile.gettempdir(), '%s.log' % appname), 'wt', 0) # unbuffered - print '%s %s %s' % (applongname, appversion, strftime('%Y-%m-%dT%H:%M:%S', localtime())) + print('%s %s %s' % (applongname, appversion, strftime('%Y-%m-%dT%H:%M:%S', localtime()))) Translations.install(config.get('language') or None) # Can generate errors so wait til log set up diff --git a/companion.py b/companion.py index 3dab1ab6..8e9d484a 100644 --- a/companion.py +++ b/companion.py @@ -1,7 +1,13 @@ +from __future__ import print_function +from future import standard_library +standard_library.install_aliases() +from builtins import str +from builtins import range +from builtins import object import base64 import csv import requests -from cookielib import LWPCookieJar # No longer needed but retained in case plugins use it +from http.cookiejar import LWPCookieJar # No longer needed but retained in case plugins use it from email.utils import parsedate import hashlib import json @@ -11,7 +17,7 @@ from os.path import dirname, isfile, join import sys import time from traceback import print_exc -import urlparse +import urllib.parse import webbrowser import zlib @@ -104,7 +110,7 @@ def listify(thing): return list(thing) # array is not sparse elif isinstance(thing, dict): retval = [] - for k,v in thing.iteritems(): + for k,v in thing.items(): idx = int(k) if idx >= len(retval): retval.extend([None] * (idx - len(retval))) @@ -121,36 +127,36 @@ class ServerError(Exception): def __unicode__(self): return _('Error: Frontier server is down') # Raised when cannot contact the Companion API server def __str__(self): - return unicode(self).encode('utf-8') + return str(self).encode('utf-8') class ServerLagging(Exception): def __unicode__(self): return _('Error: Frontier server is lagging') # Raised when Companion API server is returning old data, e.g. when the servers are too busy def __str__(self): - return unicode(self).encode('utf-8') + return str(self).encode('utf-8') class SKUError(Exception): def __unicode__(self): return _('Error: Frontier server SKU problem') # Raised when the Companion API server thinks that the user has not purchased E:D. i.e. doesn't have the correct 'SKU' def __str__(self): - return unicode(self).encode('utf-8') + return str(self).encode('utf-8') class CredentialsError(Exception): def __init__(self, message=None): - self.message = message and unicode(message) or _('Error: Invalid Credentials') + self.message = message and str(message) or _('Error: Invalid Credentials') def __unicode__(self): return self.message def __str__(self): - return unicode(self).encode('utf-8') + return str(self).encode('utf-8') class CmdrError(Exception): def __unicode__(self): return _('Error: Wrong Cmdr') # Raised when the user has multiple accounts and the username/password setting is not for the account they're currently playing OR the user has reset their Cmdr and the Companion API server is still returning data for the old Cmdr def __str__(self): - return unicode(self).encode('utf-8') + return str(self).encode('utf-8') -class Auth: +class Auth(object): def __init__(self, cmdr): self.cmdr = cmdr @@ -180,16 +186,16 @@ class Auth: config.save() # Save settings now for use by command-line app return data.get('access_token') else: - print 'Auth\tCan\'t refresh token for %s' % self.cmdr.encode('utf-8') + print('Auth\tCan\'t refresh token for %s' % self.cmdr.encode('utf-8')) self.dump(r) except: - print 'Auth\tCan\'t refresh token for %s' % self.cmdr.encode('utf-8') + print('Auth\tCan\'t refresh token for %s' % self.cmdr.encode('utf-8')) print_exc() else: - print 'Auth\tNo token for %s' % self.cmdr.encode('utf-8') + print('Auth\tNo token for %s' % self.cmdr.encode('utf-8')) # New request - print 'Auth\tNew authorization request' + print('Auth\tNew authorization request') self.verifier = self.base64URLEncode(os.urandom(32)) self.state = self.base64URLEncode(os.urandom(8)) # Won't work under IE: https://blogs.msdn.microsoft.com/ieinternals/2011/07/13/understanding-protocols/ @@ -198,16 +204,16 @@ class Auth: def authorize(self, payload): # Handle OAuth authorization code callback. Returns access token if successful, otherwise raises CredentialsError if not '?' in payload: - print 'Auth\tMalformed response "%s"' % payload.encode('utf-8') + print('Auth\tMalformed response "%s"' % payload.encode('utf-8')) raise CredentialsError() # Not well formed - data = urlparse.parse_qs(payload[payload.index('?')+1:]) + data = urllib.parse.parse_qs(payload[payload.index('?')+1:]) if not self.state or not data.get('state') or data['state'][0] != self.state: - print 'Auth\tUnexpected response "%s"' % payload.encode('utf-8') + print('Auth\tUnexpected response "%s"' % payload.encode('utf-8')) raise CredentialsError() # Unexpected reply if not data.get('code'): - print 'Auth\tNegative response "%s"' % payload.encode('utf-8') + print('Auth\tNegative response "%s"' % payload.encode('utf-8')) if data.get('error_description'): raise CredentialsError('Error: %s' % data['error_description'][0]) elif data.get('error'): @@ -229,7 +235,7 @@ class Auth: r = self.session.post(SERVER_AUTH + URL_TOKEN, data=data, timeout=auth_timeout) data = r.json() if r.status_code == requests.codes.ok: - print 'Auth\tNew token for %s' % self.cmdr.encode('utf-8') + print('Auth\tNew token for %s' % self.cmdr.encode('utf-8')) cmdrs = config.get('cmdrs') idx = cmdrs.index(self.cmdr) tokens = config.get('fdev_apikeys') or [] @@ -239,12 +245,12 @@ class Auth: config.save() # Save settings now for use by command-line app return data.get('access_token') except: - print 'Auth\tCan\'t get token for %s' % self.cmdr.encode('utf-8') + print('Auth\tCan\'t get token for %s' % self.cmdr.encode('utf-8')) print_exc() if r: self.dump(r) raise CredentialsError() - print 'Auth\tCan\'t get token for %s' % self.cmdr.encode('utf-8') + print('Auth\tCan\'t get token for %s' % self.cmdr.encode('utf-8')) self.dump(r) if data.get('error_description'): raise CredentialsError('Error: %s' % data['error_description']) @@ -257,7 +263,7 @@ class Auth: @staticmethod def invalidate(cmdr): - print 'Auth\tInvalidated token for %s' % cmdr.encode('utf-8') + print('Auth\tInvalidated token for %s' % cmdr.encode('utf-8')) cmdrs = config.get('cmdrs') idx = cmdrs.index(cmdr) tokens = config.get('fdev_apikeys') or [] @@ -267,15 +273,15 @@ class Auth: config.save() # Save settings now for use by command-line app def dump(self, r): - print 'Auth\t' + r.url, r.status_code, r.reason and r.reason.decode('utf-8') or 'None', r.text.encode('utf-8') + print('Auth\t' + r.url, r.status_code, r.reason and r.reason.decode('utf-8') or 'None', r.text.encode('utf-8')) def base64URLEncode(self, text): return base64.urlsafe_b64encode(text).replace('=', '') -class Session: +class Session(object): - STATE_INIT, STATE_AUTH, STATE_OK = range(3) + STATE_INIT, STATE_AUTH, STATE_OK = list(range(3)) def __init__(self): self.state = Session.STATE_INIT @@ -429,7 +435,7 @@ class Session: Auth.invalidate(self.credentials['cmdr']) def dump(self, r): - print 'cAPI\t' + r.url, r.status_code, r.reason and r.reason.encode('utf-8') or 'None', r.text.encode('utf-8') + print('cAPI\t' + r.url, r.status_code, r.reason and r.reason.encode('utf-8') or 'None', r.text.encode('utf-8')) # Returns a shallow copy of the received data suitable for export to older tools - English commodity names and anomalies fixed up @@ -451,7 +457,7 @@ def fixup(data): # But also see https://github.com/Marginal/EDMarketConnector/issues/32 for thing in ['buyPrice', 'sellPrice', 'demand', 'demandBracket', 'stock', 'stockBracket']: if not isinstance(commodity.get(thing), numbers.Number): - if __debug__: print 'Invalid "%s":"%s" (%s) for "%s"' % (thing, commodity.get(thing), type(commodity.get(thing)), commodity.get('name', '')) + if __debug__: print('Invalid "%s":"%s" (%s) for "%s"' % (thing, commodity.get(thing), type(commodity.get(thing)), commodity.get('name', ''))) break else: if not category_map.get(commodity['categoryname'], True): # Check not marketable i.e. Limpets @@ -461,13 +467,13 @@ def fixup(data): elif commodity.get('legality'): # Check not prohibited pass elif not commodity.get('categoryname'): - if __debug__: print 'Missing "categoryname" for "%s"' % commodity.get('name', '') + if __debug__: print('Missing "categoryname" for "%s"' % commodity.get('name', '')) elif not commodity.get('name'): - if __debug__: print 'Missing "name" for a commodity in "%s"' % commodity.get('categoryname', '') + if __debug__: print('Missing "name" for a commodity in "%s"' % commodity.get('categoryname', '')) elif not commodity['demandBracket'] in range(4): - if __debug__: print 'Invalid "demandBracket":"%s" for "%s"' % (commodity['demandBracket'], commodity['name']) + if __debug__: print('Invalid "demandBracket":"%s" for "%s"' % (commodity['demandBracket'], commodity['name'])) elif not commodity['stockBracket'] in range(4): - if __debug__: print 'Invalid "stockBracket":"%s" for "%s"' % (commodity['stockBracket'], commodity['name']) + if __debug__: print('Invalid "stockBracket":"%s" for "%s"' % (commodity['stockBracket'], commodity['name'])) else: # Rewrite text fields new = dict(commodity) # shallow copy @@ -498,7 +504,7 @@ def ship(data): def filter_ship(d): filtered = {} - for k, v in d.iteritems(): + for k, v in d.items(): if v == []: pass # just skip empty fields for brevity elif k in ['alive', 'cargo', 'cockpitBreached', 'health', 'oxygenRemaining', 'rebuilds', 'starsystem', 'station']: @@ -519,7 +525,7 @@ def ship(data): # Ship name suitable for writing to a file def ship_file_name(ship_name, ship_type): - name = unicode(ship_name or ship_map.get(ship_type.lower(), ship_type)).strip() + name = str(ship_name or ship_map.get(ship_type.lower(), ship_type)).strip() if name.endswith('.'): name = name[:-1] if name.lower() in ['con', 'prn', 'aux', 'nul', diff --git a/config.py b/config.py index 6f7834b1..9fee7e80 100644 --- a/config.py +++ b/config.py @@ -1,3 +1,8 @@ +from __future__ import division +from builtins import str +from past.builtins import basestring +from builtins import object +from past.utils import old_div import numbers import sys from os import getenv, makedirs, mkdir, pardir @@ -89,7 +94,7 @@ elif platform=='linux2': from iniparse import RawConfigParser -class Config: +class Config(object): OUT_MKT_EDDN = 1 # OUT_MKT_BPC = 2 # No longer supported @@ -146,7 +151,7 @@ class Config: elif hasattr(val, '__iter__'): return list(val) # make writeable else: - return unicode(val) + return str(val) def getint(self, key): try: @@ -212,7 +217,7 @@ class Config: if disposition.value == REG_CREATED_NEW_KEY: buf = ctypes.create_unicode_buffer('1') RegSetValueEx(sparklekey, 'CheckForUpdates', 0, 1, buf, len(buf)*2) - buf = ctypes.create_unicode_buffer(unicode(update_interval)) + buf = ctypes.create_unicode_buffer(str(update_interval)) RegSetValueEx(sparklekey, 'UpdateInterval', 0, 1, buf, len(buf)*2) RegCloseKey(sparklekey) @@ -224,13 +229,13 @@ class Config: size = DWORD() if RegQueryValueEx(self.hkey, key, 0, ctypes.byref(typ), None, ctypes.byref(size)) or typ.value not in [REG_SZ, REG_MULTI_SZ]: return None - buf = ctypes.create_unicode_buffer(size.value / 2) + buf = ctypes.create_unicode_buffer(old_div(size.value, 2)) if RegQueryValueEx(self.hkey, key, 0, ctypes.byref(typ), buf, ctypes.byref(size)): return None elif typ.value == REG_MULTI_SZ: return [x for x in ctypes.wstring_at(buf, len(buf)-2).split(u'\x00')] else: - return unicode(buf.value) + return str(buf.value) def getint(self, key): typ = DWORD() @@ -248,7 +253,7 @@ class Config: elif isinstance(val, numbers.Integral): RegSetValueEx(self.hkey, key, 0, REG_DWORD, ctypes.byref(DWORD(val)), 4) elif hasattr(val, '__iter__'): # iterable - stringval = u'\x00'.join([unicode(x) or u' ' for x in val] + [u'']) # null terminated non-empty strings + stringval = u'\x00'.join([str(x) or u' ' for x in val] + [u'']) # null terminated non-empty strings buf = ctypes.create_unicode_buffer(stringval) RegSetValueEx(self.hkey, key, 0, REG_MULTI_SZ, buf, len(buf)*2) else: @@ -333,14 +338,14 @@ class Config: def save(self): with codecs.open(self.filename, 'w', 'utf-8') as h: - h.write(unicode(self.config.data)) + h.write(str(self.config.data)) def close(self): self.save() self.config = None def _escape(self, val): - return unicode(val).replace(u'\\', u'\\\\').replace(u'\n', u'\\n').replace(u';', u'\\;') + return str(val).replace(u'\\', u'\\\\').replace(u'\n', u'\\n').replace(u';', u'\\;') def _unescape(self, val): chars = list(val) diff --git a/dashboard.py b/dashboard.py index e224b4ba..878eaedd 100644 --- a/dashboard.py +++ b/dashboard.py @@ -1,3 +1,6 @@ +from __future__ import division +from __future__ import print_function +from past.utils import old_div import json from calendar import timegm from operator import itemgetter @@ -68,18 +71,18 @@ class Dashboard(FileSystemEventHandler): self.observed = self.observer.schedule(self, self.currentdir) if __debug__: - print '%s Dashboard "%s"' % (polling and 'Polling' or 'Monitoring', self.currentdir) + print('%s Dashboard "%s"' % (polling and 'Polling' or 'Monitoring', self.currentdir)) # Even if we're not intending to poll, poll at least once to process pre-existing # data and to check whether the watchdog thread has crashed due to events not # being supported on this filesystem. - self.root.after(self._POLL * 1000/2, self.poll, True) + self.root.after(old_div(self._POLL * 1000,2), self.poll, True) return True def stop(self): if __debug__: - print 'Stopping monitoring Dashboard' + print('Stopping monitoring Dashboard') self.currentdir = None if self.observed: self.observed = None diff --git a/l10n.py b/l10n.py index 953ef7bf..8c0b0880 100755 --- a/l10n.py +++ b/l10n.py @@ -3,6 +3,11 @@ # Localization with gettext is a pain on non-Unix systems. Use OSX-style strings files instead. # +from __future__ import print_function +from future import standard_library +standard_library.install_aliases() +from builtins import str +from builtins import object import codecs from collections import OrderedDict import numbers @@ -12,14 +17,14 @@ import re import sys from sys import platform from traceback import print_exc -import __builtin__ +import builtins import locale try: locale.setlocale(locale.LC_ALL, '') except: # Locale env variables incorrect or locale package not installed/configured on Linux, mysterious reasons on Windows - print "Can't set locale!" + print("Can't set locale!") from config import config @@ -48,7 +53,7 @@ elif platform == 'win32': GetNumberFormatEx.restype = ctypes.c_int -class Translations: +class Translations(object): FALLBACK = 'en' # strings in this code are in English FALLBACK_NAME = 'English' @@ -63,7 +68,7 @@ class Translations: def install_dummy(self): # For when translation is not desired or not available self.translations = { None: {} } - __builtin__.__dict__['_'] = lambda x: unicode(x).replace(ur'\"', u'"').replace(u'{CR}', u'\n') # Promote strings to Unicode for consistency + builtins.__dict__['_'] = lambda x: str(x).replace(r'\"', u'"').replace(u'{CR}', u'\n') # Promote strings to Unicode for consistency def install(self, lang=None): available = self.available() @@ -91,11 +96,11 @@ class Translations: if isdir(plugin_path): try: self.translations[plugin] = self.contents(lang, plugin_path) - except UnicodeDecodeError, e: - print 'Malformed file %s.strings in plugin %s: %s' % (lang, plugin, e) + except UnicodeDecodeError as e: + print('Malformed file %s.strings in plugin %s: %s' % (lang, plugin, e)) except: print_exc() - __builtin__.__dict__['_'] = self.translate + builtins.__dict__['_'] = self.translate def contents(self, lang, plugin_path=None): assert lang in self.available() @@ -108,11 +113,11 @@ class Translations: if line.strip(): match = Translations.TRANS_RE.match(line) if match: - translations[match.group(1).replace(ur'\"', u'"')] = match.group(2).replace(ur'\"', u'"').replace(u'{CR}', u'\n') + translations[match.group(1).replace(r'\"', u'"')] = match.group(2).replace(r'\"', u'"').replace(u'{CR}', u'\n') elif __debug__ and not Translations.COMMENT_RE.match(line): - print 'Bad translation: %s' % line.strip() + print('Bad translation: %s' % line.strip()) if translations.get(LANGUAGE_ID, LANGUAGE_ID) == LANGUAGE_ID: - translations[LANGUAGE_ID] = unicode(lang) # Replace language name with code if missing + translations[LANGUAGE_ID] = str(lang) # Replace language name with code if missing return translations def translate(self, x, context=None): @@ -120,13 +125,13 @@ class Translations: context = context[len(config.plugin_dir)+1:].split(os.sep)[0] if __debug__: if self.translations[None] and context not in self.translations: - print 'No translations for "%s"' % context + print('No translations for "%s"' % context) return self.translations.get(context, {}).get(x) or self.translate(x) else: if __debug__: if self.translations[None] and x not in self.translations[None]: - print 'Missing translation: "%s"' % x - return self.translations[None].get(x) or unicode(x).replace(ur'\"', u'"').replace(u'{CR}', u'\n') + print('Missing translation: "%s"' % x) + return self.translations[None].get(x) or str(x).replace(r'\"', u'"').replace(u'{CR}', u'\n') # Returns list of available language codes def available(self): @@ -173,7 +178,7 @@ class Translations: return codecs.open(join(self.respath(), '%s.strings' % lang), 'r', 'utf-8') -class Locale: +class Locale(object): def __init__(self): if platform=='darwin': @@ -274,7 +279,7 @@ if __name__ == "__main__": os.mkdir(LOCALISATION_DIR) template = codecs.open(join(LOCALISATION_DIR, 'en.template'), 'w', 'utf-8') template.write('/* Language name */\n"%s" = "%s";\n\n' % (LANGUAGE_ID, 'English')) - for thing in sorted(seen, key=unicode.lower): + for thing in sorted(seen, key=str.lower): if seen[thing]: template.write('/* %s */\n' % (seen[thing])) template.write('"%s" = "%s";\n\n' % (thing, thing)) diff --git a/monitor.py b/monitor.py index 78ced29c..743381e1 100644 --- a/monitor.py +++ b/monitor.py @@ -1,3 +1,4 @@ +from __future__ import print_function from collections import defaultdict, OrderedDict import json import re @@ -152,8 +153,8 @@ class EDLogs(FileSystemEventHandler): self.observed = self.observer.schedule(self, self.currentdir) if __debug__: - print '%s Journal "%s"' % (polling and 'Polling' or 'Monitoring', self.currentdir) - print 'Start logfile "%s"' % self.logfile + print('%s Journal "%s"' % (polling and 'Polling' or 'Monitoring', self.currentdir)) + print('Start logfile "%s"' % self.logfile) if not self.running(): self.thread = threading.Thread(target = self.worker, name = 'Journal worker') @@ -164,7 +165,7 @@ class EDLogs(FileSystemEventHandler): def stop(self): if __debug__: - print 'Stopping monitoring Journal' + print('Stopping monitoring Journal') self.currentdir = None self.version = self.mode = self.group = self.cmdr = self.planet = self.system = self.station = self.stationtype = self.stationservices = self.coordinates = self.systemaddress = None self.is_beta = False @@ -206,7 +207,7 @@ class EDLogs(FileSystemEventHandler): self.parse_entry(line) # Some events are of interest even in the past except: if __debug__: - print 'Invalid journal entry "%s"' % repr(line) + print('Invalid journal entry "%s"' % repr(line)) logpos = loghandle.tell() else: loghandle = None @@ -262,7 +263,7 @@ class EDLogs(FileSystemEventHandler): fcntl(loghandle, F_GLOBAL_NOCACHE, -1) # required to avoid corruption on macOS over SMB logpos = 0 if __debug__: - print 'New logfile "%s"' % logfile + print('New logfile "%s"' % logfile) if logfile: loghandle.seek(0, SEEK_END) # required to make macOS notice log change over SMB @@ -454,10 +455,10 @@ class EDLogs(FileSystemEventHandler): payload = dict(entry) payload.pop('event') payload.pop('timestamp') - for k,v in payload.iteritems(): + for k,v in payload.items(): self.state['Rank'][k] = (v,0) elif entry['event'] == 'Progress': - for k,v in entry.iteritems(): + for k,v in entry.items(): if k in self.state['Rank']: self.state['Rank'][k] = (self.state['Rank'][k][0], min(v, 100)) # perhaps not taken promotion mission yet elif entry['event'] in ['Reputation', 'Statistics']: @@ -621,7 +622,7 @@ class EDLogs(FileSystemEventHandler): return entry except: if __debug__: - print 'Invalid journal entry "%s"' % repr(line) + print('Invalid journal entry "%s"' % repr(line)) print_exc() return { 'event': None } diff --git a/myNotebook.py b/myNotebook.py index f65eb4f2..88807428 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -7,8 +7,8 @@ from sys import platform -import Tkinter as tk -import ttk +import tkinter as tk +from tkinter import ttk # Can't do this with styles on OSX - http://www.tkdocs.com/tutorial/styles.html#whydifficult diff --git a/plug.py b/plug.py index e6b0e87d..72514342 100644 --- a/plug.py +++ b/plug.py @@ -8,7 +8,7 @@ import operator import threading # We don't use it, but plugins might from traceback import print_exc -import Tkinter as tk +import tkinter as tk import myNotebook as nb from config import config diff --git a/prefs.py b/prefs.py index 5096d194..f73855cf 100644 --- a/prefs.py +++ b/prefs.py @@ -5,9 +5,9 @@ from os.path import dirname, expanduser, expandvars, exists, isdir, join, normpa from sys import platform import webbrowser -import Tkinter as tk -import ttk -import tkColorChooser +import tkinter as tk +from tkinter import ttk +from tkinter import colorchooser as tkColorChooser from ttkHyperlinkLabel import HyperlinkLabel import myNotebook as nb diff --git a/protocol.py b/protocol.py index 2c28e2cc..98e6611f 100644 --- a/protocol.py +++ b/protocol.py @@ -1,8 +1,12 @@ +from __future__ import print_function # edmc: protocol handler for cAPI authorisation +from future import standard_library +standard_library.install_aliases() +from builtins import object import threading -import urllib2 +import urllib.request, urllib.error, urllib.parse import sys from config import appname @@ -17,7 +21,7 @@ if sys.platform == 'win32': is_wine = False -class GenericProtocolHandler: +class GenericProtocolHandler(object): def __init__(self): self.redirect = 'edmc://auth' # Base redirection URL @@ -67,7 +71,7 @@ if sys.platform == 'darwin' and getattr(sys, 'frozen', False): return self def handleEvent_withReplyEvent_(self, event, replyEvent): - protocolhandler.lasturl = urllib2.unquote(event.paramDescriptorForKeyword_(keyDirectObject).stringValue()).strip() + protocolhandler.lasturl = urllib.parse.unquote(event.paramDescriptorForKeyword_(keyDirectObject).stringValue()).strip() protocolhandler.master.after(ProtocolHandler.POLL, protocolhandler.poll) @@ -189,7 +193,7 @@ elif sys.platform == 'win32' and getattr(sys, 'frozen', False) and not is_wine: args = wstring_at(GlobalLock(msg.lParam)).strip() GlobalUnlock(msg.lParam) if args.lower().startswith('open("') and args.endswith('")'): - url = urllib2.unquote(args[6:-2]).strip() + url = urllib.parse.unquote(args[6:-2]).strip() if url.startswith(self.redirect): self.event(url) SetForegroundWindow(GetParent(self.master.winfo_id())) # raise app window @@ -202,11 +206,11 @@ elif sys.platform == 'win32' and getattr(sys, 'frozen', False) and not is_wine: TranslateMessage(byref(msg)) DispatchMessage(byref(msg)) else: - print 'Failed to register DDE for cAPI' + print('Failed to register DDE for cAPI') else: # Linux / Run from source - from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler + from http.server import HTTPServer, BaseHTTPRequestHandler class ProtocolHandler(GenericProtocolHandler): @@ -236,7 +240,7 @@ else: # Linux / Run from source class HTTPRequestHandler(BaseHTTPRequestHandler): def parse(self): - url = urllib2.unquote(self.path) + url = urllib.parse.unquote(self.path) if url.startswith('/auth'): protocolhandler.event(url) self.send_response(200) diff --git a/stats.py b/stats.py index a5bd1ac9..58f30d05 100644 --- a/stats.py +++ b/stats.py @@ -6,8 +6,8 @@ import time if __debug__: from traceback import print_exc -import Tkinter as tk -import ttk +import tkinter as tk +from tkinter import ttk import myNotebook as nb import companion diff --git a/theme.py b/theme.py index 8c55e3c5..e77fcd73 100644 --- a/theme.py +++ b/theme.py @@ -1,3 +1,4 @@ +from __future__ import division # # Theme support # @@ -5,12 +6,17 @@ # So can't use ttk's theme support. So have to change colors manually. # +from future import standard_library +standard_library.install_aliases() +from builtins import str +from builtins import object +from past.utils import old_div from sys import platform from os.path import join -import Tkinter as tk -import ttk -import tkFont +import tkinter as tk +from tkinter import ttk +from tkinter import font as tkFont from ttkHyperlinkLabel import HyperlinkLabel from config import appname, applongname, config @@ -95,7 +101,7 @@ elif platform == 'linux2': dpy = None -class _Theme: +class _Theme(object): def __init__(self): self.active = None # Starts out with no theme @@ -207,7 +213,7 @@ class _Theme: 'foreground' : config.get('dark_text'), 'activebackground' : config.get('dark_text'), 'activeforeground' : 'grey4', - 'disabledforeground' : '#%02x%02x%02x' % (r/384, g/384, b/384), + 'disabledforeground' : '#%02x%02x%02x' % (old_div(r,384), old_div(g,384), old_div(b,384)), 'highlight' : config.get('dark_highlight'), # Font only supports Latin 1 / Supplement / Extended, and a few General Punctuation and Mathematical Operators 'font' : (theme > 1 and not 0x250 < ord(_('Cmdr')[0]) < 0x3000 and diff --git a/ttkHyperlinkLabel.py b/ttkHyperlinkLabel.py index 73f1a9e4..d1d50ebb 100644 --- a/ttkHyperlinkLabel.py +++ b/ttkHyperlinkLabel.py @@ -1,9 +1,9 @@ from sys import platform import webbrowser -import Tkinter as tk -import ttk -import tkFont +import tkinter as tk +from tkinter import ttk +from tkinter import font as tkFont if platform == 'win32': import subprocess