1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-06-12 21:32:29 +03:00

Merge pull request #703 from EDCD/feature/tk-dir-dialog

Locale: More detailed login at startup around changes
This commit is contained in:
Athanasius 2020-09-16 09:43:39 +01:00 committed by GitHub
commit beeadf266a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -23,6 +23,7 @@ if __name__ == "__main__":
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
# By default py2exe tries to write log to dirname(sys.executable) which fails when installed # By default py2exe tries to write log to dirname(sys.executable) which fails when installed
import tempfile import tempfile
# unbuffered not allowed for text in python3, so use `1 for line buffering # unbuffered not allowed for text in python3, so use `1 for line buffering
sys.stdout = sys.stderr = open(join(tempfile.gettempdir(), f'{appname}.log'), mode='wt', buffering=1) sys.stdout = sys.stderr = open(join(tempfile.gettempdir(), f'{appname}.log'), mode='wt', buffering=1)
@ -45,6 +46,7 @@ if __debug__:
if platform != 'win32': if platform != 'win32':
import pdb import pdb
import signal import signal
signal.signal(signal.SIGTERM, lambda sig, frame: pdb.Pdb().set_trace(frame)) signal.signal(signal.SIGTERM, lambda sig, frame: pdb.Pdb().set_trace(frame))
import companion import companion
@ -61,7 +63,6 @@ from protocol import protocolhandler
from dashboard import dashboard from dashboard import dashboard
from theme import theme from theme import theme
SERVER_RETRY = 5 # retry pause for Companion servers [s] SERVER_RETRY = 5 # retry pause for Companion servers [s]
SHIPYARD_HTML_TEMPLATE = """ SHIPYARD_HTML_TEMPLATE = """
@ -81,7 +82,6 @@ SHIPYARD_HTML_TEMPLATE = """
class AppWindow(object): class AppWindow(object):
# Tkinter Event types # Tkinter Event types
EVENT_KEYPRESS = 2 EVENT_KEYPRESS = 2
EVENT_BUTTON = 4 EVENT_BUTTON = 4
@ -104,10 +104,14 @@ class AppWindow(object):
if platform == 'win32': if platform == 'win32':
self.w.wm_iconbitmap(default='EDMarketConnector.ico') self.w.wm_iconbitmap(default='EDMarketConnector.ico')
else: else:
self.w.tk.call('wm', 'iconphoto', self.w, '-default', tk.PhotoImage(file=join(config.respath, 'EDMarketConnector.png'))) # noqa: E501 self.w.tk.call('wm', 'iconphoto', self.w, '-default',
self.theme_icon = tk.PhotoImage(data='R0lGODlhFAAQAMZQAAoKCQoKCgsKCQwKCQsLCgwLCg4LCQ4LCg0MCg8MCRAMCRANChINCREOChIOChQPChgQChgRCxwTCyYVCSoXCS0YCTkdCTseCT0fCTsjDU0jB0EnDU8lB1ElB1MnCFIoCFMoCEkrDlkqCFwrCGEuCWIuCGQvCFs0D1w1D2wyCG0yCF82D182EHE0CHM0CHQ1CGQ5EHU2CHc3CHs4CH45CIA6CIE7CJdECIdLEolMEohQE5BQE41SFJBTE5lUE5pVE5RXFKNaFKVbFLVjFbZkFrxnFr9oFsNqFsVrF8RsFshtF89xF9NzGNh1GNl2GP+KG////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEKAH8ALAAAAAAUABAAAAeegAGCgiGDhoeIRDiIjIZGKzmNiAQBQxkRTU6am0tPCJSGShuSAUcLoIIbRYMFra4FAUgQAQCGJz6CDQ67vAFJJBi0hjBBD0w9PMnJOkAiJhaIKEI7HRoc19ceNAolwbWDLD8uAQnl5ga1I9CHEjEBAvDxAoMtFIYCBy+kFDKHAgM3ZtgYSLAGgwkp3pEyBOJCC2ELB31QATGioAoVAwEAOw==') # noqa: E501 tk.PhotoImage(file=join(config.respath, 'EDMarketConnector.png'))) # noqa: E501
self.theme_minimize = tk.BitmapImage(data='#define im_width 16\n#define im_height 16\nstatic unsigned char im_bits[] = {\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f,\n 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n') # noqa: E501 self.theme_icon = tk.PhotoImage(
self.theme_close = tk.BitmapImage(data='#define im_width 16\n#define im_height 16\nstatic unsigned char im_bits[] = {\n 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x1c, 0x38, 0x38, 0x1c, 0x70, 0x0e,\n 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07, 0x70, 0x0e, 0x38, 0x1c,\n 0x1c, 0x38, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00 };\n') # noqa: E501 data='R0lGODlhFAAQAMZQAAoKCQoKCgsKCQwKCQsLCgwLCg4LCQ4LCg0MCg8MCRAMCRANChINCREOChIOChQPChgQChgRCxwTCyYVCSoXCS0YCTkdCTseCT0fCTsjDU0jB0EnDU8lB1ElB1MnCFIoCFMoCEkrDlkqCFwrCGEuCWIuCGQvCFs0D1w1D2wyCG0yCF82D182EHE0CHM0CHQ1CGQ5EHU2CHc3CHs4CH45CIA6CIE7CJdECIdLEolMEohQE5BQE41SFJBTE5lUE5pVE5RXFKNaFKVbFLVjFbZkFrxnFr9oFsNqFsVrF8RsFshtF89xF9NzGNh1GNl2GP+KG////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEKAH8ALAAAAAAUABAAAAeegAGCgiGDhoeIRDiIjIZGKzmNiAQBQxkRTU6am0tPCJSGShuSAUcLoIIbRYMFra4FAUgQAQCGJz6CDQ67vAFJJBi0hjBBD0w9PMnJOkAiJhaIKEI7HRoc19ceNAolwbWDLD8uAQnl5ga1I9CHEjEBAvDxAoMtFIYCBy+kFDKHAgM3ZtgYSLAGgwkp3pEyBOJCC2ELB31QATGioAoVAwEAOw==') # noqa: E501
self.theme_minimize = tk.BitmapImage(
data='#define im_width 16\n#define im_height 16\nstatic unsigned char im_bits[] = {\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f,\n 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n') # noqa: E501
self.theme_close = tk.BitmapImage(
data='#define im_width 16\n#define im_height 16\nstatic unsigned char im_bits[] = {\n 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x1c, 0x38, 0x38, 0x1c, 0x70, 0x0e,\n 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07, 0x70, 0x0e, 0x38, 0x1c,\n 0x1c, 0x38, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00 };\n') # noqa: E501
frame = tk.Frame(self.w, name=appname.lower()) frame = tk.Frame(self.w, name=appname.lower())
frame.grid(sticky=tk.NSEW) frame.grid(sticky=tk.NSEW)
@ -152,7 +156,8 @@ class AppWindow(object):
row = frame.grid_size()[1] row = frame.grid_size()[1]
self.button.grid(row=row, columnspan=2, sticky=tk.NSEW) self.button.grid(row=row, columnspan=2, sticky=tk.NSEW)
self.theme_button.grid(row=row, columnspan=2, sticky=tk.NSEW) self.theme_button.grid(row=row, columnspan=2, sticky=tk.NSEW)
theme.register_alternate((self.button, self.theme_button, self.theme_button), {'row': row, 'columnspan': 2, 'sticky': tk.NSEW}) # noqa: E501 theme.register_alternate((self.button, self.theme_button, self.theme_button),
{'row': row, 'columnspan': 2, 'sticky': tk.NSEW}) # noqa: E501
self.status.grid(columnspan=2, sticky=tk.EW) self.status.grid(columnspan=2, sticky=tk.EW)
self.button.bind('<Button-1>', self.getandsend) self.button.bind('<Button-1>', self.getandsend)
theme.button_bind(self.theme_button, self.getandsend) theme.button_bind(self.theme_button, self.getandsend)
@ -291,6 +296,7 @@ class AppWindow(object):
# Check that the titlebar will be at least partly on screen # Check that the titlebar will be at least partly on screen
import ctypes import ctypes
from ctypes.wintypes import POINT from ctypes.wintypes import POINT
# https://msdn.microsoft.com/en-us/library/dd145064 # https://msdn.microsoft.com/en-us/library/dd145064
MONITOR_DEFAULTTONULL = 0 # noqa: N806 MONITOR_DEFAULTTONULL = 0 # noqa: N806
if ctypes.windll.user32.MonitorFromPoint(POINT(int(match.group(1)) + 16, int(match.group(2)) + 16), if ctypes.windll.user32.MonitorFromPoint(POINT(int(match.group(1)) + 16, int(match.group(2)) + 16),
@ -322,6 +328,7 @@ class AppWindow(object):
# Load updater after UI creation (for WinSparkle) # Load updater after UI creation (for WinSparkle)
import update import update
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
# Running in frozen .exe, so use (Win)Sparkle # Running in frozen .exe, so use (Win)Sparkle
self.updater = update.Updater(tkroot=self.w, provider='external') self.updater = update.Updater(tkroot=self.w, provider='external')
@ -453,7 +460,7 @@ class AppWindow(object):
if not retrying: if not retrying:
if time() < self.holdofftime: # Was invoked by key while in cooldown if time() < self.holdofftime: # Was invoked by key while in cooldown
self.status['text'] = '' self.status['text'] = ''
if play_sound and (self.holdofftime-time()) < companion.holdoff*0.75: if play_sound and (self.holdofftime - time()) < companion.holdoff * 0.75:
hotkeymgr.play_bad() # Don't play sound in first few seconds to prevent repeats hotkeymgr.play_bad() # Don't play sound in first few seconds to prevent repeats
return return
elif play_sound: elif play_sound:
@ -493,7 +500,7 @@ class AppWindow(object):
if isdir('dump'): if isdir('dump'):
with open('dump/{system}{station}.{timestamp}.json'.format( with open('dump/{system}{station}.{timestamp}.json'.format(
system=data['lastSystem']['name'], system=data['lastSystem']['name'],
station=data['commander'].get('docked') and '.'+data['lastStarport']['name'] or '', station=data['commander'].get('docked') and '.' + data['lastStarport']['name'] or '',
timestamp=strftime('%Y-%m-%dT%H.%M.%S', localtime())), 'wb') as h: timestamp=strftime('%Y-%m-%dT%H.%M.%S', localtime())), 'wb') as h:
h.write(json.dumps(data, h.write(json.dumps(data,
ensure_ascii=False, ensure_ascii=False,
@ -525,7 +532,7 @@ class AppWindow(object):
self.status['text'] = _("You're not docked at a station!") self.status['text'] = _("You're not docked at a station!")
play_bad = True play_bad = True
# Ignore possibly missing shipyard info # Ignore possibly missing shipyard info
elif (config.getint('output') & config.OUT_MKT_EDDN)\ elif (config.getint('output') & config.OUT_MKT_EDDN) \
and not (data['lastStarport'].get('commodities') or data['lastStarport'].get('modules')): and not (data['lastStarport'].get('commodities') or data['lastStarport'].get('modules')):
if not self.status['text']: if not self.status['text']:
self.status['text'] = _("Station doesn't have anything!") self.status['text'] = _("Station doesn't have anything!")
@ -585,12 +592,12 @@ class AppWindow(object):
if not data['commander'].get('docked'): if not data['commander'].get('docked'):
# might have un-docked while we were waiting for retry in which case station data is unreliable # might have un-docked while we were waiting for retry in which case station data is unreliable
pass pass
elif (data.get('lastSystem', {}).get('name') == monitor.system and elif (data.get('lastSystem', {}).get('name') == monitor.system and
data.get('lastStarport', {}).get('name') == monitor.station and data.get('lastStarport', {}).get('name') == monitor.station and
data.get('lastStarport', {}).get('ships', {}).get('shipyard_list')): data.get('lastStarport', {}).get('ships', {}).get('shipyard_list')):
self.eddn.export_shipyard(data, monitor.is_beta) self.eddn.export_shipyard(data, monitor.is_beta)
elif tries > 1: # bogus data - retry elif tries > 1: # bogus data - retry
self.w.after(int(SERVER_RETRY * 1000), lambda: self.retry_for_shipyard(tries-1)) self.w.after(int(SERVER_RETRY * 1000), lambda: self.retry_for_shipyard(tries - 1))
except Exception: except Exception:
pass pass
@ -600,11 +607,11 @@ class AppWindow(object):
def crewroletext(role): def crewroletext(role):
# Return translated crew role. Needs to be dynamic to allow for changing language. # Return translated crew role. Needs to be dynamic to allow for changing language.
return { return {
None: '', None : '',
'Idle': '', 'Idle' : '',
'FighterCon': _('Fighter'), # Multicrew role 'FighterCon': _('Fighter'), # Multicrew role
'FireCon': _('Gunner'), # Multicrew role 'FireCon' : _('Gunner'), # Multicrew role
'FlightCon': _('Helm'), # Multicrew role 'FlightCon' : _('Helm'), # Multicrew role
}.get(role, role) }.get(role, role)
while True: while True:
@ -626,8 +633,8 @@ class AppWindow(object):
self.ship_label['text'] = _('Ship') + ':' # Main window self.ship_label['text'] = _('Ship') + ':' # Main window
self.ship.configure( self.ship.configure(
text=monitor.state['ShipName'] text=monitor.state['ShipName']
or companion.ship_map.get(monitor.state['ShipType'], monitor.state['ShipType']) or companion.ship_map.get(monitor.state['ShipType'], monitor.state['ShipType'])
or '', or '',
url=self.shipyard_url) url=self.shipyard_url)
else: else:
self.cmdr['text'] = '' self.cmdr['text'] = ''
@ -673,7 +680,7 @@ class AppWindow(object):
logger.info("Can't start Status monitoring") logger.info("Can't start Status monitoring")
# Export loadout # Export loadout
if entry['event'] == 'Loadout' and not monitor.state['Captain']\ if entry['event'] == 'Loadout' and not monitor.state['Captain'] \
and config.getint('output') & config.OUT_SHIP: and config.getint('output') & config.OUT_SHIP:
monitor.export_ship() monitor.export_ship()
@ -690,10 +697,10 @@ class AppWindow(object):
hotkeymgr.play_bad() hotkeymgr.play_bad()
# Auto-Update after docking, but not if auth callback is pending # Auto-Update after docking, but not if auth callback is pending
if entry['event'] in ('StartUp', 'Location', 'Docked')\ if entry['event'] in ('StartUp', 'Location', 'Docked') \
and monitor.station\ and monitor.station \
and not config.getint('output') & config.OUT_MKT_MANUAL\ and not config.getint('output') & config.OUT_MKT_MANUAL \
and config.getint('output') & config.OUT_STATION_ANY\ and config.getint('output') & config.OUT_STATION_ANY \
and companion.session.state != companion.Session.STATE_AUTH: and companion.session.state != companion.Session.STATE_AUTH:
self.w.after(int(SERVER_RETRY * 1000), self.getandsend) self.w.after(int(SERVER_RETRY * 1000), self.getandsend)
@ -760,10 +767,10 @@ class AppWindow(object):
return f'file://localhost/{file_name}' return f'file://localhost/{file_name}'
def system_url(self, system): def system_url(self, system):
return plug.invoke(config.get('system_provider'), 'EDSM', 'system_url', monitor.system) return plug.invoke(config.get('system_provider'), 'EDSM', 'system_url', monitor.system)
def station_url(self, station): def station_url(self, station):
return plug.invoke(config.get('station_provider'), 'eddb', 'station_url', monitor.system, monitor.station) return plug.invoke(config.get('station_provider'), 'eddb', 'station_url', monitor.system, monitor.station)
def cooldown(self): def cooldown(self):
if time() < self.holdofftime: if time() < self.holdofftime:
@ -837,7 +844,7 @@ class AppWindow(object):
############################################################ ############################################################
# version <link to changelog> # version <link to changelog>
ttk.Label(frame).grid(row=row, column=0) # spacer ttk.Label(frame).grid(row=row, column=0) # spacer
row += 1 row += 1
self.appversion_label = tk.Label(frame, text=appversion) self.appversion_label = tk.Label(frame, text=appversion)
self.appversion_label.grid(row=row, column=0, sticky=tk.E) self.appversion_label.grid(row=row, column=0, sticky=tk.E)
@ -855,7 +862,7 @@ class AppWindow(object):
############################################################ ############################################################
# <copyright> # <copyright>
ttk.Label(frame).grid(row=row, column=0) # spacer ttk.Label(frame).grid(row=row, column=0) # spacer
row += 1 row += 1
self.copyright = tk.Label(frame, text=copyright) self.copyright = tk.Label(frame, text=copyright)
self.copyright.grid(row=row, columnspan=3, sticky=tk.EW) self.copyright.grid(row=row, columnspan=3, sticky=tk.EW)
@ -864,7 +871,7 @@ class AppWindow(object):
############################################################ ############################################################
# OK button to close the window # OK button to close the window
ttk.Label(frame).grid(row=row, column=0) # spacer ttk.Label(frame).grid(row=row, column=0) # spacer
row += 1 row += 1
button = ttk.Button(frame, text=_('OK'), command=self.apply) button = ttk.Button(frame, text=_('OK'), command=self.apply)
button.grid(row=row, column=2, sticky=tk.E) button.grid(row=row, column=2, sticky=tk.E)
@ -895,7 +902,7 @@ class AppWindow(object):
last_system: str = data.get("lastSystem", {}).get("name", "Unknown") last_system: str = data.get("lastSystem", {}).get("name", "Unknown")
last_starport: str = '' last_starport: str = ''
if data['commander'].get('docked'): if data['commander'].get('docked'):
last_starport = '.'+data.get('lastStarport', {}).get('name', 'Unknown') last_starport = '.' + data.get('lastStarport', {}).get('name', 'Unknown')
timestamp: str = strftime('%Y-%m-%dT%H.%M.%S', localtime()) timestamp: str = strftime('%Y-%m-%dT%H.%M.%S', localtime())
f = tkinter.filedialog.asksaveasfilename(parent=self.w, f = tkinter.filedialog.asksaveasfilename(parent=self.w,
defaultextension=default_extension, defaultextension=default_extension,
@ -971,6 +978,7 @@ def enforce_single_instance() -> None:
if platform == 'win32': if platform == 'win32':
import ctypes import ctypes
from ctypes.wintypes import HWND, LPWSTR, LPCWSTR, INT, BOOL, LPARAM from ctypes.wintypes import HWND, LPWSTR, LPCWSTR, INT, BOOL, LPARAM
EnumWindows = ctypes.windll.user32.EnumWindows # noqa: N806 EnumWindows = ctypes.windll.user32.EnumWindows # noqa: N806
GetClassName = ctypes.windll.user32.GetClassNameW # noqa: N806 GetClassName = ctypes.windll.user32.GetClassNameW # noqa: N806
GetClassName.argtypes = [HWND, LPWSTR, ctypes.c_int] # noqa: N806 GetClassName.argtypes = [HWND, LPWSTR, ctypes.c_int] # noqa: N806
@ -1004,9 +1012,9 @@ def enforce_single_instance() -> None:
def enumwindowsproc(window_handle, l_param): def enumwindowsproc(window_handle, l_param):
# class name limited to 256 - https://msdn.microsoft.com/en-us/library/windows/desktop/ms633576 # class name limited to 256 - https://msdn.microsoft.com/en-us/library/windows/desktop/ms633576
cls = ctypes.create_unicode_buffer(257) cls = ctypes.create_unicode_buffer(257)
if GetClassName(window_handle, cls, 257)\ if GetClassName(window_handle, cls, 257) \
and cls.value == 'TkTopLevel'\ and cls.value == 'TkTopLevel' \
and window_title(window_handle) == applongname\ and window_title(window_handle) == applongname \
and GetProcessHandleFromHwnd(window_handle): and GetProcessHandleFromHwnd(window_handle):
# If GetProcessHandleFromHwnd succeeds then the app is already running as this user # If GetProcessHandleFromHwnd succeeds then the app is already running as this user
if len(sys.argv) > 1 and sys.argv[1].startswith(protocolhandler.redirect): if len(sys.argv) > 1 and sys.argv[1].startswith(protocolhandler.redirect):
@ -1028,38 +1036,52 @@ def test_logging():
logger.debug('Test from EDMarketConnector.py top-level test_logging()') logger.debug('Test from EDMarketConnector.py top-level test_logging()')
# Run the app def log_locale(prefix: str) -> None:
if __name__ == "__main__": logger.debug(f'''Locale: {prefix}
enforce_single_instance()
from EDMCLogging import logger
logger.info(f'Startup v{appversion} : Running on Python v{sys.version}')
logger.debug(f'''Platform: {sys.platform}
argv[0]: {sys.argv[0]}
exec_prefix: {sys.exec_prefix}
executable: {sys.executable}
sys.path: {sys.path}
Locale LC_COLLATE: {locale.getlocale(locale.LC_COLLATE)} Locale LC_COLLATE: {locale.getlocale(locale.LC_COLLATE)}
Locale LC_CTYPE: {locale.getlocale(locale.LC_CTYPE)} Locale LC_CTYPE: {locale.getlocale(locale.LC_CTYPE)}
Locale LC_MONETARY: {locale.getlocale(locale.LC_MONETARY)} Locale LC_MONETARY: {locale.getlocale(locale.LC_MONETARY)}
Locale LC_NUMERIC: {locale.getlocale(locale.LC_NUMERIC)} Locale LC_NUMERIC: {locale.getlocale(locale.LC_NUMERIC)}
Locale LC_TIME: {locale.getlocale(locale.LC_TIME)}''' Locale LC_TIME: {locale.getlocale(locale.LC_TIME)}'''
) )
# Run the app
if __name__ == "__main__":
enforce_single_instance()
from EDMCLogging import logger
logger.info(f'Startup v{appversion} : Running on Python v{sys.version}')
logger.debug(f'''Platform: {sys.platform}
argv[0]: {sys.argv[0]}
exec_prefix: {sys.exec_prefix}
executable: {sys.executable}
sys.path: {sys.path}'''
)
# Change locale to a utf8 one # Change locale to a utf8 one
# First make sure the local is actually set as per locale's idea of defaults # Log what we have at startup
log_locale('Initial Locale')
# Make sure the local is actually set as per locale's idea of defaults
locale.setlocale(locale.LC_ALL, '') locale.setlocale(locale.LC_ALL, '')
log_locale('After LC_ALL defaults set')
# Now find out the current locale, mostly the language # Now find out the current locale, mostly the language
locale_startup = locale.getlocale(locale.LC_ALL) locale_startup = locale.getlocale(locale.LC_ALL)
logger.debug(f'Locale LC_ALL: {locale_startup}')
# Now set that same language, but utf8 encoding (it was probably cp1252 # Now set that same language, but utf8 encoding (it was probably cp1252
# or equivalent for other languages). # or equivalent for other languages).
locale.setlocale(locale.LC_ALL, (locale_startup[0], 'utf8')) locale.setlocale(locale.LC_ALL, (locale_startup[0], 'utf8'))
log_locale('After switching to utf8 encoding (same language)')
# TODO: unittests in place of these # TODO: unittests in place of these
# logger.debug('Test from __main__') # logger.debug('Test from __main__')
# test_logging() # test_logging()
class A(object): class A(object):
class B(object): class B(object):
def __init__(self): def __init__(self):
logger.debug('A call from A.B.__init__') logger.debug('A call from A.B.__init__')
@ -1102,7 +1124,8 @@ Locale LC_TIME: {locale.getlocale(locale.LC_TIME)}'''
# Now the string should match, so try translation # Now the string should match, so try translation
popup_text = _(popup_text) popup_text = _(popup_text)
# And substitute in the other words. # And substitute in the other words.
popup_text = popup_text.format(PLUGINS=_('Plugins'), FILE=_('File'), SETTINGS=_('Settings'), DISABLED='.disabled') popup_text = popup_text.format(PLUGINS=_('Plugins'), FILE=_('File'), SETTINGS=_('Settings'),
DISABLED='.disabled')
# And now we do need these to be actual \r\n # And now we do need these to be actual \r\n
popup_text = popup_text.replace('\\n', '\n') popup_text = popup_text.replace('\\n', '\n')
popup_text = popup_text.replace('\\r', '\r') popup_text = popup_text.replace('\\r', '\r')