mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-05-21 17:41:20 +03:00
Merge branch 'stable' into releases
This commit is contained in:
commit
3019cea52e
45
ChangeLog.md
45
ChangeLog.md
@ -27,6 +27,51 @@ produce the Windows executables and installer.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Release 5.3.1
|
||||||
|
===
|
||||||
|
|
||||||
|
This release addresses some issues with newer EDDN code which could cause
|
||||||
|
erroneous alerts to the player, or sending of bad messages.
|
||||||
|
|
||||||
|
* EDDN: Cope with `ApproachSettlement` on login occurring before `Location`,
|
||||||
|
such that we don't yet know the name of the star system the player is in.
|
||||||
|
|
||||||
|
Closes [#1484](https://github.com/EDCD/EDMarketConnector/pull/1484)
|
||||||
|
|
||||||
|
* EDDN: Cope with `ApproachSettlement` missing planetary coordinates on login
|
||||||
|
at/near a settlement in Horizons.
|
||||||
|
|
||||||
|
Closes [#1476](https://github.com/EDCD/EDMarketConnector/pull/1476)
|
||||||
|
|
||||||
|
* EDDN: Change the `CodexEntry` "empty string" checks to only apply to those
|
||||||
|
values where the schema enforces "must be at least one character".
|
||||||
|
|
||||||
|
This prevents the big 'CodexEntry had empty string, PLEASE ALERT THE EDMC
|
||||||
|
DEVELOPERS' message from triggering on, e.g. `NearestDestination` being
|
||||||
|
empty, which the schema allows.
|
||||||
|
|
||||||
|
Closes [#1481](https://github.com/EDCD/EDMarketConnector/issues/1481)
|
||||||
|
|
||||||
|
Plugin Developers
|
||||||
|
---
|
||||||
|
|
||||||
|
* If you use a sub-class for a widget the core code will no longer break if
|
||||||
|
your code raises an exception. e.g. a plugin was failing due to Python
|
||||||
|
3.10 using `collections.abc` instead of `collections`, and the plugin's
|
||||||
|
custom widget had a `configure()` method which was called by the core
|
||||||
|
theme code on startup or theme change. This then caused the whole
|
||||||
|
application UI to never show up on startup.
|
||||||
|
|
||||||
|
This also applies if you set up a button such that enter/leave on it, i.e.
|
||||||
|
mouse in/out, causes the `theme.py` code for that to trigger.
|
||||||
|
|
||||||
|
So, now in such cases the main UI should actually show up, although your
|
||||||
|
plugin's UI might look weird due to theming not being properly applied.
|
||||||
|
|
||||||
|
The plugin exception **WILL** be logged, at ERROR level.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Release 5.3.0
|
Release 5.3.0
|
||||||
===
|
===
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@ Please be sure to read the [Avoiding potential pitfalls](#avoiding-potential-pit
|
|||||||
section, else you might inadvertently cause issues for the core
|
section, else you might inadvertently cause issues for the core
|
||||||
EDMarketConnector code including whole application crashes.
|
EDMarketConnector code including whole application crashes.
|
||||||
|
|
||||||
|
## Being aware of core application changes
|
||||||
|
|
||||||
It is highly advisable to ensure you are aware of all EDMarketConnector
|
It is highly advisable to ensure you are aware of all EDMarketConnector
|
||||||
releases, including the pre-releases. The -beta and -rc changelogs will
|
releases, including the pre-releases. The -beta and -rc changelogs will
|
||||||
contain valuable information about any forthcoming changes that affect plugins.
|
contain valuable information about any forthcoming changes that affect plugins.
|
||||||
@ -55,6 +57,11 @@ The easiest way is:
|
|||||||
And, of course, either ensure you check your GitHub messages regularly, or
|
And, of course, either ensure you check your GitHub messages regularly, or
|
||||||
have it set up to email you such notifications.
|
have it set up to email you such notifications.
|
||||||
|
|
||||||
|
You should also keep an eye on [our GitHub Discussions](https://github.com/EDCD/EDMarketConnector/discussions)
|
||||||
|
in case there are any proposed changes to EDMC plugin functionality. You can
|
||||||
|
do this by ensuring 'Discussions' is also ticked when following the steps
|
||||||
|
above to set up a 'Custom' watch on this repository.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
@ -52,7 +52,7 @@ appcmdname = 'EDMC'
|
|||||||
# <https://semver.org/#semantic-versioning-specification-semver>
|
# <https://semver.org/#semantic-versioning-specification-semver>
|
||||||
# Major.Minor.Patch(-prerelease)(+buildmetadata)
|
# Major.Minor.Patch(-prerelease)(+buildmetadata)
|
||||||
# NB: Do *not* import this, use the functions appversion() and appversion_nobuild()
|
# NB: Do *not* import this, use the functions appversion() and appversion_nobuild()
|
||||||
_static_appversion = '5.3.0'
|
_static_appversion = '5.3.1'
|
||||||
_cached_version: Optional[semantic_version.Version] = None
|
_cached_version: Optional[semantic_version.Version] = None
|
||||||
copyright = '© 2015-2019 Jonathan Harris, 2020-2022 EDCD'
|
copyright = '© 2015-2019 Jonathan Harris, 2020-2022 EDCD'
|
||||||
|
|
||||||
|
@ -829,7 +829,7 @@ class EDDN:
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warning("Neither this_coordinates or this.coordinates set, can't add StarPos")
|
logger.warning("Neither this_coordinates or this.coordinates set, can't add StarPos")
|
||||||
return 'No source for adding StarPos to approachsettlement/1 !'
|
return 'No source for adding StarPos to EDDN message !'
|
||||||
|
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
@ -970,7 +970,9 @@ class EDDN:
|
|||||||
logger.warning(f'this.body_id was not set properly: "{this.body_id}" ({type(this.body_id)})')
|
logger.warning(f'this.body_id was not set properly: "{this.body_id}" ({type(this.body_id)})')
|
||||||
#######################################################################
|
#######################################################################
|
||||||
|
|
||||||
for k, v in entry.items():
|
# Check just the top-level strings with minLength=1 in the schema
|
||||||
|
for k in ('System', 'Name', 'Region', 'Category', 'SubCategory'):
|
||||||
|
v = entry[k]
|
||||||
if v is None or isinstance(v, str) and v == '':
|
if v is None or isinstance(v, str) and v == '':
|
||||||
logger.warning(f'post-processing entry contains entry["{k}"] = {v} {(type(v))}')
|
logger.warning(f'post-processing entry contains entry["{k}"] = {v} {(type(v))}')
|
||||||
# We should drop this message and VERY LOUDLY inform the
|
# We should drop this message and VERY LOUDLY inform the
|
||||||
@ -978,6 +980,13 @@ class EDDN:
|
|||||||
# raw Journal event that caused this.
|
# raw Journal event that caused this.
|
||||||
return 'CodexEntry had empty string, PLEASE ALERT THE EDMC DEVELOPERS'
|
return 'CodexEntry had empty string, PLEASE ALERT THE EDMC DEVELOPERS'
|
||||||
|
|
||||||
|
# Also check traits
|
||||||
|
if 'Traits' in entry:
|
||||||
|
for v in entry['Traits']:
|
||||||
|
if v is None or isinstance(v, str) and v == '':
|
||||||
|
logger.warning(f'post-processing entry[\'Traits\'] contains {v} {(type(v))}\n{entry["Traits"]}\n')
|
||||||
|
return 'CodexEntry Trait had empty string, PLEASE ALERT THE EDMC DEVELOPERS'
|
||||||
|
|
||||||
msg = {
|
msg = {
|
||||||
'$schemaRef': f'https://eddn.edcd.io/schemas/codexentry/1{"/test" if is_beta else ""}',
|
'$schemaRef': f'https://eddn.edcd.io/schemas/codexentry/1{"/test" if is_beta else ""}',
|
||||||
'message': entry
|
'message': entry
|
||||||
@ -1126,6 +1135,27 @@ class EDDN:
|
|||||||
# "event": "ApproachSettlement",
|
# "event": "ApproachSettlement",
|
||||||
# "timestamp": "2021-10-14T12:37:54Z"
|
# "timestamp": "2021-10-14T12:37:54Z"
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Bugs
|
||||||
|
#######################################################################
|
||||||
|
# WORKAROUND 3.8.0.404 | 2022-02-18: ApproachSettlement missing coords
|
||||||
|
# As of Horizons ("gameversion":"3.8.0.404", "build":"r280105/r0 ")
|
||||||
|
# if you log back in (certainly a game client restart) at a
|
||||||
|
# Planetary Port, then the ApproachSettlement event written will be
|
||||||
|
# missing the Latitude and Longitude.
|
||||||
|
# Ref: https://github.com/EDCD/EDMarketConnector/issues/1476
|
||||||
|
if any(
|
||||||
|
k not in entry for k in ('Latitude', 'Longitude')
|
||||||
|
):
|
||||||
|
logger.debug(
|
||||||
|
f'ApproachSettlement without at least one of Latitude or Longitude:\n{entry}\n'
|
||||||
|
)
|
||||||
|
# No need to alert the user, it will only annoy them
|
||||||
|
return ""
|
||||||
|
# WORKAROUND END
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# Augmentations
|
# Augmentations
|
||||||
#######################################################################
|
#######################################################################
|
||||||
@ -1499,6 +1529,12 @@ def journal_entry( # noqa: C901, CCR001
|
|||||||
return this.eddn.export_journal_navroute(cmdr, is_beta, entry)
|
return this.eddn.export_journal_navroute(cmdr, is_beta, entry)
|
||||||
|
|
||||||
elif event_name == 'approachsettlement':
|
elif event_name == 'approachsettlement':
|
||||||
|
# An `ApproachSettlement` can appear *before* `Location` if you
|
||||||
|
# logged at one. We won't have necessary augmentation data
|
||||||
|
# at this point, so bail.
|
||||||
|
if system is None:
|
||||||
|
return ""
|
||||||
|
|
||||||
return this.eddn.export_journal_approachsettlement(
|
return this.eddn.export_journal_approachsettlement(
|
||||||
cmdr,
|
cmdr,
|
||||||
system,
|
system,
|
||||||
@ -1507,6 +1543,14 @@ def journal_entry( # noqa: C901, CCR001
|
|||||||
entry
|
entry
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# NB: If adding FSSSignalDiscovered these absolutely come in at login
|
||||||
|
# time **BEFORE** the `Location` event, so we won't yet know things
|
||||||
|
# like SystemNane, or StarPos.
|
||||||
|
# We can either have the "now send the batch" code add such (but
|
||||||
|
# that has corner cases around changing systems in the meantime),
|
||||||
|
# drop those events, or if the schema allows, send without those
|
||||||
|
# augmentations.
|
||||||
|
|
||||||
elif event_name == 'fssallbodiesfound':
|
elif event_name == 'fssallbodiesfound':
|
||||||
return this.eddn.export_journal_fssallbodiesfound(
|
return this.eddn.export_journal_fssallbodiesfound(
|
||||||
cmdr,
|
cmdr,
|
||||||
|
@ -5,7 +5,7 @@ wheel
|
|||||||
# We can't rely on just picking this up from either the base (not venv),
|
# We can't rely on just picking this up from either the base (not venv),
|
||||||
# or venv-init-time version. Specify here so that dependabot will prod us
|
# or venv-init-time version. Specify here so that dependabot will prod us
|
||||||
# about new versions.
|
# about new versions.
|
||||||
setuptools==60.8.2
|
setuptools==60.9.3
|
||||||
|
|
||||||
# Static analysis tools
|
# Static analysis tools
|
||||||
flake8==4.0.1
|
flake8==4.0.1
|
||||||
@ -23,7 +23,7 @@ flake8-use-fstring==1.3
|
|||||||
mypy==0.931
|
mypy==0.931
|
||||||
pep8-naming==0.12.1
|
pep8-naming==0.12.1
|
||||||
safety==1.10.3
|
safety==1.10.3
|
||||||
types-requests==2.27.9
|
types-requests==2.27.10
|
||||||
|
|
||||||
# Code formatting tools
|
# Code formatting tools
|
||||||
autopep8==1.6.0
|
autopep8==1.6.0
|
||||||
@ -33,14 +33,14 @@ grip==4.6.0
|
|||||||
|
|
||||||
# Packaging
|
# Packaging
|
||||||
# Used to put together a WiX configuration from template/auto-gen
|
# Used to put together a WiX configuration from template/auto-gen
|
||||||
lxml==4.7.1
|
lxml==4.8.0
|
||||||
# We only need py2exe on windows.
|
# We only need py2exe on windows.
|
||||||
# Pre-release version addressing semantic_version 2.9.0+ issues:
|
# Pre-release version addressing semantic_version 2.9.0+ issues:
|
||||||
# <https://github.com/py2exe/py2exe/issues/126>
|
# <https://github.com/py2exe/py2exe/issues/126>
|
||||||
py2exe==0.11.1.0; sys_platform == 'win32'
|
py2exe==0.11.1.0; sys_platform == 'win32'
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
pytest==7.0.0
|
pytest==7.0.1
|
||||||
pytest-cov==3.0.0 # Pytest code coverage support
|
pytest-cov==3.0.0 # Pytest code coverage support
|
||||||
coverage[toml]==6.3.1 # pytest-cov dep. This is here to ensure that it includes TOML support for pyproject.toml configs
|
coverage[toml]==6.3.1 # pytest-cov dep. This is here to ensure that it includes TOML support for pyproject.toml configs
|
||||||
# For manipulating folder permissions and the like.
|
# For manipulating folder permissions and the like.
|
||||||
|
35
theme.py
35
theme.py
@ -14,6 +14,9 @@ from tkinter import ttk
|
|||||||
|
|
||||||
from config import config
|
from config import config
|
||||||
from ttkHyperlinkLabel import HyperlinkLabel
|
from ttkHyperlinkLabel import HyperlinkLabel
|
||||||
|
from EDMCLogging import get_main_logger
|
||||||
|
|
||||||
|
logger = get_main_logger()
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
@ -192,18 +195,36 @@ class _Theme(object):
|
|||||||
def _enter(self, event, image):
|
def _enter(self, event, image):
|
||||||
widget = event.widget
|
widget = event.widget
|
||||||
if widget and widget['state'] != tk.DISABLED:
|
if widget and widget['state'] != tk.DISABLED:
|
||||||
|
try:
|
||||||
widget.configure(state=tk.ACTIVE)
|
widget.configure(state=tk.ACTIVE)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
logger.exception(f'Failure setting widget active: {widget=}')
|
||||||
|
|
||||||
if image:
|
if image:
|
||||||
|
try:
|
||||||
image.configure(foreground=self.current['activeforeground'],
|
image.configure(foreground=self.current['activeforeground'],
|
||||||
background=self.current['activebackground'])
|
background=self.current['activebackground'])
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
logger.exception(f'Failure configuring image: {image=}')
|
||||||
|
|
||||||
def _leave(self, event, image):
|
def _leave(self, event, image):
|
||||||
widget = event.widget
|
widget = event.widget
|
||||||
if widget and widget['state'] != tk.DISABLED:
|
if widget and widget['state'] != tk.DISABLED:
|
||||||
|
try:
|
||||||
widget.configure(state=tk.NORMAL)
|
widget.configure(state=tk.NORMAL)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
logger.exception(f'Failure setting widget normal: {widget=}')
|
||||||
|
|
||||||
if image:
|
if image:
|
||||||
|
try:
|
||||||
image.configure(foreground=self.current['foreground'], background=self.current['background'])
|
image.configure(foreground=self.current['foreground'], background=self.current['background'])
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
logger.exception(f'Failure configuring image: {image=}')
|
||||||
|
|
||||||
# Set up colors
|
# Set up colors
|
||||||
def _colors(self, root, theme):
|
def _colors(self, root, theme):
|
||||||
style = ttk.Style()
|
style = ttk.Style()
|
||||||
@ -266,51 +287,65 @@ class _Theme(object):
|
|||||||
widget.winfo_class(), widget, 'text' in widget.keys() and widget['text'])
|
widget.winfo_class(), widget, 'text' in widget.keys() and widget['text'])
|
||||||
attribs = self.widgets.get(widget, [])
|
attribs = self.widgets.get(widget, [])
|
||||||
|
|
||||||
|
try:
|
||||||
if isinstance(widget, tk.BitmapImage):
|
if isinstance(widget, tk.BitmapImage):
|
||||||
# not a widget
|
# not a widget
|
||||||
if 'fg' not in attribs:
|
if 'fg' not in attribs:
|
||||||
widget.configure(foreground=self.current['foreground']),
|
widget.configure(foreground=self.current['foreground']),
|
||||||
|
|
||||||
if 'bg' not in attribs:
|
if 'bg' not in attribs:
|
||||||
widget.configure(background=self.current['background'])
|
widget.configure(background=self.current['background'])
|
||||||
|
|
||||||
elif 'cursor' in widget.keys() and str(widget['cursor']) not in ['', 'arrow']:
|
elif 'cursor' in widget.keys() and str(widget['cursor']) not in ['', 'arrow']:
|
||||||
# Hack - highlight widgets like HyperlinkLabel with a non-default cursor
|
# Hack - highlight widgets like HyperlinkLabel with a non-default cursor
|
||||||
if 'fg' not in attribs:
|
if 'fg' not in attribs:
|
||||||
widget.configure(foreground=self.current['highlight']),
|
widget.configure(foreground=self.current['highlight']),
|
||||||
if 'insertbackground' in widget.keys(): # tk.Entry
|
if 'insertbackground' in widget.keys(): # tk.Entry
|
||||||
widget.configure(insertbackground=self.current['foreground']),
|
widget.configure(insertbackground=self.current['foreground']),
|
||||||
|
|
||||||
if 'bg' not in attribs:
|
if 'bg' not in attribs:
|
||||||
widget.configure(background=self.current['background'])
|
widget.configure(background=self.current['background'])
|
||||||
if 'highlightbackground' in widget.keys(): # tk.Entry
|
if 'highlightbackground' in widget.keys(): # tk.Entry
|
||||||
widget.configure(highlightbackground=self.current['background'])
|
widget.configure(highlightbackground=self.current['background'])
|
||||||
|
|
||||||
if 'font' not in attribs:
|
if 'font' not in attribs:
|
||||||
widget.configure(font=self.current['font'])
|
widget.configure(font=self.current['font'])
|
||||||
|
|
||||||
elif 'activeforeground' in widget.keys():
|
elif 'activeforeground' in widget.keys():
|
||||||
# e.g. tk.Button, tk.Label, tk.Menu
|
# e.g. tk.Button, tk.Label, tk.Menu
|
||||||
if 'fg' not in attribs:
|
if 'fg' not in attribs:
|
||||||
widget.configure(foreground=self.current['foreground'],
|
widget.configure(foreground=self.current['foreground'],
|
||||||
activeforeground=self.current['activeforeground'],
|
activeforeground=self.current['activeforeground'],
|
||||||
disabledforeground=self.current['disabledforeground'])
|
disabledforeground=self.current['disabledforeground'])
|
||||||
|
|
||||||
if 'bg' not in attribs:
|
if 'bg' not in attribs:
|
||||||
widget.configure(background=self.current['background'],
|
widget.configure(background=self.current['background'],
|
||||||
activebackground=self.current['activebackground'])
|
activebackground=self.current['activebackground'])
|
||||||
if sys.platform == 'darwin' and isinstance(widget, tk.Button):
|
if sys.platform == 'darwin' and isinstance(widget, tk.Button):
|
||||||
widget.configure(highlightbackground=self.current['background'])
|
widget.configure(highlightbackground=self.current['background'])
|
||||||
|
|
||||||
if 'font' not in attribs:
|
if 'font' not in attribs:
|
||||||
widget.configure(font=self.current['font'])
|
widget.configure(font=self.current['font'])
|
||||||
elif 'foreground' in widget.keys():
|
elif 'foreground' in widget.keys():
|
||||||
# e.g. ttk.Label
|
# e.g. ttk.Label
|
||||||
if 'fg' not in attribs:
|
if 'fg' not in attribs:
|
||||||
widget.configure(foreground=self.current['foreground']),
|
widget.configure(foreground=self.current['foreground']),
|
||||||
|
|
||||||
if 'bg' not in attribs:
|
if 'bg' not in attribs:
|
||||||
widget.configure(background=self.current['background'])
|
widget.configure(background=self.current['background'])
|
||||||
|
|
||||||
if 'font' not in attribs:
|
if 'font' not in attribs:
|
||||||
widget.configure(font=self.current['font'])
|
widget.configure(font=self.current['font'])
|
||||||
|
|
||||||
elif 'background' in widget.keys() or isinstance(widget, tk.Canvas):
|
elif 'background' in widget.keys() or isinstance(widget, tk.Canvas):
|
||||||
# e.g. Frame, Canvas
|
# e.g. Frame, Canvas
|
||||||
if 'bg' not in attribs:
|
if 'bg' not in attribs:
|
||||||
widget.configure(background=self.current['background'],
|
widget.configure(background=self.current['background'],
|
||||||
highlightbackground=self.current['disabledforeground'])
|
highlightbackground=self.current['disabledforeground'])
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
logger.exception(f'Plugin widget issue ? {widget=}')
|
||||||
|
|
||||||
# Apply configured theme
|
# Apply configured theme
|
||||||
|
|
||||||
def apply(self, root):
|
def apply(self, root):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user