1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-12 15:27:14 +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
#
# Command-line interface. Requires prior setup through the GUI.
#
"""Command-line interface. Requires prior setup through the GUI."""
import argparse
import json
import locale
import logging
import os
import re
import sys
from os.path import getmtime, join
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
os.environ["EDMC_NO_UI"] = "1"
@ -21,7 +25,6 @@ os.environ["EDMC_NO_UI"] = "1"
import collate
import commodity
import companion
import EDMCLogging
import edshipyard
import l10n
import loadout
@ -40,11 +43,9 @@ sys.path.append(config.internal_plugin_dir)
import eddn # noqa: E402
# isort: on
logger = EDMCLogging.Logger(appcmdname).get_logger()
logger.setLevel(logging.INFO)
def log_locale(prefix: str) -> None:
"""Log the current state of locale settings."""
logger.debug(f'''Locale: {prefix}
Locale LC_COLLATE: {locale.getlocale(locale.LC_COLLATE)}
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$')
# quick and dirty version comparison assuming "strict" numeric only version numbers
def versioncmp(versionstring):
"""Quick and dirty version comparison assuming "strict" numeric only version numbers."""
return list(map(int, versionstring.split('.')))
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'):
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():
"""Run the main code of the program."""
try:
# arg parsing
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('--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('-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')
@ -117,11 +146,14 @@ def main():
return
if args.loglevel:
if args.loglevel not in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'):
print('loglevel must be one of: CRITICAL, ERROR, WARNING, INFO, DEBUG', file=sys.stderr)
if args.trace:
edmclogger.set_channels_loglevel(logging.TRACE)
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)
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'''Platform: {sys.platform}
@ -250,10 +282,9 @@ sys.path: {sys.path}'''
stats.export_status(data, args.t)
if data['commander'].get('docked'):
print('{},{}'.format(
deep_get(data, 'lastSystem', 'name', default='Unknown'),
deep_get(data, 'lastStarport', 'name', default='Unknown')
))
print(f'{deep_get(data, "lastSystem", "name", default="Unknown")},'
f'{deep_get(data, "lastStarport", "name", default="Unknown")}'
)
else:
print(deep_get(data, 'lastSystem', 'name', default='Unknown'))

View File

@ -381,5 +381,11 @@ def get_main_logger() -> logging.Logger:
loglevel = config.get('loglevel')
if not loglevel:
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()

View File

@ -2,20 +2,27 @@
# -*- coding: utf-8 -*-
import argparse
from builtins import str
from builtins import object
import sys
from sys import platform
import html
import json
import locale
import re
import sys
import webbrowser
from builtins import object, str
from os import chdir, environ
from os.path import dirname, isdir, join
import re
import html
from time import time, localtime, strftime
import webbrowser
from sys import platform
from time import localtime, strftime, time
from typing import TYPE_CHECKING
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
if __name__ == "__main__":
@ -37,10 +44,11 @@ if getattr(sys, 'frozen', False):
environ['TK_LIBRARY'] = join(dirname(sys.path[0]), 'lib', 'tk')
import tkinter as tk
from tkinter import ttk
import tkinter.filedialog
import tkinter.font
import tkinter.messagebox
from tkinter import ttk
from ttkHyperlinkLabel import HyperlinkLabel
if __debug__:
@ -50,18 +58,18 @@ if __debug__:
signal.signal(signal.SIGTERM, lambda sig, frame: pdb.Pdb().set_trace(frame))
import companion
import commodity
from commodity import COMMODITY_CSV
import td
import stats
import prefs
import companion
import plug
import prefs
import stats
import td
from commodity import COMMODITY_CSV
from dashboard import dashboard
from hotkey import hotkeymgr
from l10n import Translations
from monitor import monitor
from protocol import protocolhandler
from dashboard import dashboard
from theme import theme
SERVER_RETRY = 5 # retry pause for Companion servers [s]
@ -614,11 +622,11 @@ class AppWindow(object):
def crewroletext(role):
# Return translated crew role. Needs to be dynamic to allow for changing language.
return {
None : '',
'Idle' : '',
None: '',
'Idle': '',
'FighterCon': _('Fighter'), # Multicrew role
'FireCon' : _('Gunner'), # Multicrew role
'FlightCon' : _('Helm'), # Multicrew role
'FireCon': _('Gunner'), # Multicrew role
'FlightCon': _('Helm'), # Multicrew role
}.get(role, role)
while True:
@ -641,8 +649,8 @@ class AppWindow(object):
self.ship_label['text'] = _('Ship') + ':' # Main window
self.ship.configure(
text=monitor.state['ShipName']
or companion.ship_map.get(monitor.state['ShipType'], monitor.state['ShipType'])
or '',
or companion.ship_map.get(monitor.state['ShipType'], monitor.state['ShipType'])
or '',
url=self.shipyard_url)
else:
self.cmdr['text'] = ''
@ -935,7 +943,8 @@ class AppWindow(object):
def onexit(self, event=None):
# http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7
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
protocolhandler.close()
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.
if platform == 'win32':
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
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.argtypes = [HWND, LPWSTR, ctypes.c_int] # noqa: N806
GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int]
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW # noqa: N806
GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd # noqa: N806
@ -1076,11 +1085,6 @@ if __name__ == "__main__":
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:
logger.setLevel(logging.TRACE)
edmclogger.set_channels_loglevel(logging.TRACE)