1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-15 00:30:33 +03:00

Trace: Add support to EDMC.py & misc cleanups

* EDMC: Add --trace (to match EDMarketConnector.py) and TRACE as option to
  --loglevel.
* EDMC: docstrings added.
* EDMCLogging: Set logger name based on if GUI or CLI.
* EDMarketConnector:
  * Re-order imports.
  * Misc. formatting cleanups.
  * f-strings not .format().
  * Removed un-necessary "# noqa: N806" comments.
This commit is contained in:
Athanasius 2020-09-23 17:38:38 +01:00
parent 46e3b3aff8
commit 3c0ac76f90
3 changed files with 92 additions and 51 deletions

69
EDMC.py
View File

@ -1,19 +1,23 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# """Command-line interface. Requires prior setup through the GUI."""
# Command-line interface. Requires prior setup through the GUI.
#
import argparse import argparse
import json import json
import locale import locale
import logging
import os import os
import re import re
import sys import sys
from os.path import getmtime, join from os.path import getmtime, join
from time import sleep, time from time import sleep, time
from typing import Any, Optional from typing import TYPE_CHECKING, Any, Optional
# isort: off
from EDMCLogging import edmclogger, logger, logging
if TYPE_CHECKING:
from logging import trace, TRACE # type: ignore # noqa: F401
# isort: on
edmclogger.set_channels_loglevel(logging.INFO)
# workaround for https://github.com/EDCD/EDMarketConnector/issues/568 # workaround for https://github.com/EDCD/EDMarketConnector/issues/568
os.environ["EDMC_NO_UI"] = "1" os.environ["EDMC_NO_UI"] = "1"
@ -21,7 +25,6 @@ os.environ["EDMC_NO_UI"] = "1"
import collate import collate
import commodity import commodity
import companion import companion
import EDMCLogging
import edshipyard import edshipyard
import l10n import l10n
import loadout import loadout
@ -40,11 +43,9 @@ sys.path.append(config.internal_plugin_dir)
import eddn # noqa: E402 import eddn # noqa: E402
# isort: on # isort: on
logger = EDMCLogging.Logger(appcmdname).get_logger()
logger.setLevel(logging.INFO)
def log_locale(prefix: str) -> None: def log_locale(prefix: str) -> None:
"""Log the current state of locale settings."""
logger.debug(f'''Locale: {prefix} logger.debug(f'''Locale: {prefix}
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)}
@ -62,12 +63,30 @@ EXIT_SUCCESS, EXIT_SERVER, EXIT_CREDENTIALS, EXIT_VERIFICATION, EXIT_LAGGING, EX
JOURNAL_RE = re.compile(r'^Journal(Beta)?\.[0-9]{12}\.[0-9]{2}\.log$') JOURNAL_RE = re.compile(r'^Journal(Beta)?\.[0-9]{12}\.[0-9]{2}\.log$')
# quick and dirty version comparison assuming "strict" numeric only version numbers
def versioncmp(versionstring): def versioncmp(versionstring):
"""Quick and dirty version comparison assuming "strict" numeric only version numbers."""
return list(map(int, versionstring.split('.'))) return list(map(int, versionstring.split('.')))
def deep_get(target: dict, *args: str, default=None) -> Any: def deep_get(target: dict, *args: str, default=None) -> Any:
"""
Walk into a dict and return the specified deep value.
Example usage:
>>> thing = {'a': {'b': {'c': 'foo'} } }
>>> deep_get(thing, ('a', 'b', 'c'), None)
'foo'
>>> deep_get(thing, ('a', 'b'), None)
{'c': 'foo'}
>>> deep_get(thing, ('a', 'd'), None)
None
:param target: The dict to walk into for the desired value.
:param args: The list of keys to walk down through.
:param default: What to return if the target has no value.
:return: The value at the target deep key.
"""
if not hasattr(target, 'get'): if not hasattr(target, 'get'):
raise ValueError(f"Cannot call get on {target} ({type(target)})") raise ValueError(f"Cannot call get on {target} ({type(target)})")
@ -83,6 +102,7 @@ def deep_get(target: dict, *args: str, default=None) -> Any:
def main(): def main():
"""Run the main code of the program."""
try: try:
# arg parsing # arg parsing
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
@ -93,7 +113,16 @@ def main():
) )
parser.add_argument('-v', '--version', help='print program version and exit', action='store_const', const=True) parser.add_argument('-v', '--version', help='print program version and exit', action='store_const', const=True)
parser.add_argument('--loglevel', metavar='loglevel', help='Set the logging loglevel to one of: CRITICAL, ERROR, WARNING, INFO, DEBUG') # noqa: E501 group_loglevel = parser.add_mutually_exclusive_group()
group_loglevel.add_argument('--loglevel',
metavar='loglevel',
help='Set the logging loglevel to one of: '
'CRITICAL, ERROR, WARNING, INFO, DEBUG, TRACE',
)
group_loglevel.add_argument('--trace',
help='Set the Debug logging loglevel to TRACE',
action='store_true',
)
parser.add_argument('-a', metavar='FILE', help='write ship loadout to FILE in Companion API json format') parser.add_argument('-a', metavar='FILE', help='write ship loadout to FILE in Companion API json format')
parser.add_argument('-e', metavar='FILE', help='write ship loadout to FILE in E:D Shipyard plain text format') parser.add_argument('-e', metavar='FILE', help='write ship loadout to FILE in E:D Shipyard plain text format')
parser.add_argument('-l', metavar='FILE', help='write ship locations to FILE in CSV format') parser.add_argument('-l', metavar='FILE', help='write ship locations to FILE in CSV format')
@ -117,11 +146,14 @@ def main():
return return
if args.loglevel: if args.trace:
if args.loglevel not in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'): edmclogger.set_channels_loglevel(logging.TRACE)
print('loglevel must be one of: CRITICAL, ERROR, WARNING, INFO, DEBUG', file=sys.stderr)
elif args.loglevel:
if args.loglevel not in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'TRACE'):
print('loglevel must be one of: CRITICAL, ERROR, WARNING, INFO, DEBUG, TRACE', file=sys.stderr)
sys.exit(EXIT_ARGS) sys.exit(EXIT_ARGS)
logger.setLevel(args.loglevel) edmclogger.set_channels_loglevel(args.loglevel)
logger.debug(f'Startup v{appversion} : Running on Python v{sys.version}') logger.debug(f'Startup v{appversion} : Running on Python v{sys.version}')
logger.debug(f'''Platform: {sys.platform} logger.debug(f'''Platform: {sys.platform}
@ -250,10 +282,9 @@ sys.path: {sys.path}'''
stats.export_status(data, args.t) stats.export_status(data, args.t)
if data['commander'].get('docked'): if data['commander'].get('docked'):
print('{},{}'.format( print(f'{deep_get(data, "lastSystem", "name", default="Unknown")},'
deep_get(data, 'lastSystem', 'name', default='Unknown'), f'{deep_get(data, "lastStarport", "name", default="Unknown")}'
deep_get(data, 'lastStarport', 'name', default='Unknown') )
))
else: else:
print(deep_get(data, 'lastSystem', 'name', default='Unknown')) print(deep_get(data, 'lastSystem', 'name', default='Unknown'))

View File

@ -381,5 +381,11 @@ def get_main_logger() -> logging.Logger:
loglevel = config.get('loglevel') loglevel = config.get('loglevel')
if not loglevel: if not loglevel:
loglevel = logging.INFO loglevel = logging.INFO
edmclogger = Logger(appname, loglevel=loglevel)
if not os.getenv('EDMC_NO_UI'):
base_logger_name = appname
else:
base_logger_name = appcmdname
edmclogger = Logger(base_logger_name, loglevel=loglevel)
logger = edmclogger.get_logger() logger = edmclogger.get_logger()

View File

@ -2,20 +2,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import argparse import argparse
from builtins import str import html
from builtins import object
import sys
from sys import platform
import json import json
import locale import locale
import re
import sys
import webbrowser
from builtins import object, str
from os import chdir, environ from os import chdir, environ
from os.path import dirname, isdir, join from os.path import dirname, isdir, join
import re from sys import platform
import html from time import localtime, strftime, time
from time import time, localtime, strftime from typing import TYPE_CHECKING
import webbrowser
from config import appname, applongname, appversion, appversion_nobuild, copyright, config from EDMCLogging import edmclogger, logger, logging
# isort: off
if TYPE_CHECKING:
from logging import trace, TRACE # type: ignore # noqa: F401
# isort: on
from config import applongname, appname, appversion, appversion_nobuild, config, copyright
# TODO: Test: Make *sure* this redirect is working, else py2exe is going to cause an exit popup # TODO: Test: Make *sure* this redirect is working, else py2exe is going to cause an exit popup
if __name__ == "__main__": if __name__ == "__main__":
@ -37,10 +44,11 @@ if getattr(sys, 'frozen', False):
environ['TK_LIBRARY'] = join(dirname(sys.path[0]), 'lib', 'tk') environ['TK_LIBRARY'] = join(dirname(sys.path[0]), 'lib', 'tk')
import tkinter as tk import tkinter as tk
from tkinter import ttk
import tkinter.filedialog import tkinter.filedialog
import tkinter.font import tkinter.font
import tkinter.messagebox import tkinter.messagebox
from tkinter import ttk
from ttkHyperlinkLabel import HyperlinkLabel from ttkHyperlinkLabel import HyperlinkLabel
if __debug__: if __debug__:
@ -50,18 +58,18 @@ if __debug__:
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 commodity import commodity
from commodity import COMMODITY_CSV import companion
import td
import stats
import prefs
import plug import plug
import prefs
import stats
import td
from commodity import COMMODITY_CSV
from dashboard import dashboard
from hotkey import hotkeymgr from hotkey import hotkeymgr
from l10n import Translations from l10n import Translations
from monitor import monitor from monitor import monitor
from protocol import protocolhandler from protocol import protocolhandler
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]
@ -935,7 +943,8 @@ class AppWindow(object):
def onexit(self, event=None): def onexit(self, event=None):
# http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7
if platform != 'darwin' or self.w.winfo_rooty() > 0: if platform != 'darwin' or self.w.winfo_rooty() > 0:
config.set('geometry', '+{1}+{2}'.format(*self.w.geometry().split('+'))) x, y = self.w.geometry().split('+')[1:3] # e.g. '212x170+2881+1267'
config.set('geometry', f'+{x}+{y}')
self.w.withdraw() # Following items can take a few seconds, so hide the main window while they happen self.w.withdraw() # Following items can take a few seconds, so hide the main window while they happen
protocolhandler.close() protocolhandler.close()
hotkeymgr.unregister() hotkeymgr.unregister()
@ -987,13 +996,13 @@ def enforce_single_instance() -> None:
# Ensure only one copy of the app is running under this user account. OSX does this automatically. Linux TODO. # Ensure only one copy of the app is running under this user account. OSX does this automatically. Linux TODO.
if platform == 'win32': if platform == 'win32':
import ctypes import ctypes
from ctypes.wintypes import HWND, LPWSTR, LPCWSTR, INT, BOOL, LPARAM from ctypes.wintypes import BOOL, HWND, INT, LPARAM, LPCWSTR, LPWSTR
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]
GetWindowText = ctypes.windll.user32.GetWindowTextW # noqa: N806 GetWindowText = ctypes.windll.user32.GetWindowTextW # noqa: N806
GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int] # noqa: N806 GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int]
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW # noqa: N806 GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW # noqa: N806
GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd # noqa: N806 GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd # noqa: N806
@ -1076,11 +1085,6 @@ if __name__ == "__main__":
args = parser.parse_args() args = parser.parse_args()
from EDMCLogging import edmclogger, logger, logging
# isort: off
from logging import trace, TRACE # type: ignore # noqa: F401
# isort: on
if args.trace: if args.trace:
logger.setLevel(logging.TRACE) logger.setLevel(logging.TRACE)
edmclogger.set_channels_loglevel(logging.TRACE) edmclogger.set_channels_loglevel(logging.TRACE)