1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-13 07:47:14 +03:00

Plugin migration

This commit is contained in:
Jonathan Harris 2019-10-02 03:01:08 +01:00 committed by Athanasius
parent 3fe4454888
commit c62d110448
8 changed files with 33 additions and 59 deletions

View File

@ -22,7 +22,7 @@ Plugins are python files. The plugin folder must have a file named `load.py` tha
EDMC will import the `load.py` file as a module and then call the `plugin_start()` function.
```python
def plugin_start(plugin_dir):
def plugin_start3(plugin_dir):
"""
Load this plugin into EDMC
"""
@ -30,7 +30,7 @@ def plugin_start(plugin_dir):
return "Test"
```
Any errors or print statements from your plugin will appear in `%TMP%\EDMarketConnector.log` on Windows or `$TMPDIR/EDMarketConnector.log` on Mac.
Any errors or print statements from your plugin will appear in `%TMP%\EDMarketConnector.log` on Windows, `$TMPDIR/EDMarketConnector.log` on Mac, and `$TMP/EDMarketConnector.log` on Linux.
This gets called when the user closes the program:
@ -279,12 +279,12 @@ EDMC now lets you disable a plugin without deleting it, simply rename the plugin
Disabled and enabled plugins are listed on the "Plugins" Settings tab
# Migration to Python 3.7
# Migration
In a future release EDMC will use Python **3.7**, instead of the Python 2.7 it has historically used. As of mid-2020 there is a [python3 branch](https://github.com/EDCD/EDMarketConnector/tree/python3) to test migrated plugins against. This is a brief outline of the steps required to migrate a plugin from earlier versions of EDMC:
Starting with release 3.5 EDMC uses Python **3.7**. This is a brief outline of the steps required to migrate a plugin from earlier versions of EDMC:
- Rename the function `plugin_start` to `plugin_start3(plugin_dir)`. Plugins without a `plugin_start3` function will be listed as disabled on EDMC's "Plugins" tab and a message like "plugin SuperSpaceHelper needs migrating" will appear in the log.
- Rename the function `plugin_start` to `plugin_start3(plugin_dir)`. Plugins without a `plugin_start3` function are listed as disabled on EDMC's "Plugins" tab and a message like "plugin SuperSpaceHelper needs migrating" appears in the log.
- Check that callback functions `plugin_prefs`, `prefs_changed`, `journal_entry`, `dashboard_entry` and `cmdr_data` if used are declared with the correct number of arguments. Older versions of this app were tolerant of missing arguments in these function declarations.
- Port the code to Python 3.7. The [2to3](https://docs.python.org/3/library/2to3.html) tool can automate much of this work.
Depending on the complexity of the plugin it may be feasible to make it compatible with both EDMC 3.4 + Python 2.7 and later EDMC + Python 3.7. [Here's](https://python-future.org/compatible_idioms.html) a guide on writing Python 2/3 compatible code and [here's](https://github.com/Marginal/HabZone/commit/3c41cd41d5ad81ef36aab40e967e3baf77b4bd06) an example of the changes required for a simple plugin.
Depending on the complexity of the plugin it may be feasible to make it compatible with both EDMC 3.4 + Python 2.7 and EDMC 3.5 + Python 3.7. [Here's](https://python-future.org/compatible_idioms.html) a guide on writing Python 2/3 compatible code and [here's](https://github.com/Marginal/HabZone/commit/3c41cd41d5ad81ef36aab40e967e3baf77b4bd06) an example of the changes required for a simple plugin.

66
plug.py
View File

@ -91,13 +91,19 @@ class Plugin(object):
if loadfile:
sys.stdout.write('loading plugin {} from "{}"\n'.format(name.replace('.', '_'), loadfile))
module = importlib.machinery.SourceFileLoader('plugin_{}'.format(name.encode(encoding='ascii', errors='replace').decode('utf-8').replace('.', '_')), loadfile).load_module()
if module.plugin_start.__code__.co_argcount == 0:
newname = module.plugin_start()
else:
newname = module.plugin_start(os.path.dirname(loadfile))
self.name = newname and str(newname) or name
self.module = module
try:
module = importlib.machinery.SourceFileLoader('plugin_{}'.format(name.encode(encoding='ascii', errors='replace').decode('utf-8').replace('.', '_')), loadfile).load_module()
if getattr(module, 'plugin_start3', None):
newname = module.plugin_start3(os.path.dirname(loadfile))
self.name = newname and str(newname) or name
self.module = module
elif getattr(module, 'plugin_start', None):
sys.stdout.write('plugin %s needs migrating\n' % name)
else:
sys.stdout.write('plugin %s has no plugin_start3() function\n' % name)
except:
print_exc()
raise
else:
sys.stdout.write('plugin %s disabled\n' % name)
@ -143,10 +149,7 @@ class Plugin(object):
plugin_prefs = self._get_func('plugin_prefs')
if plugin_prefs:
try:
if plugin_prefs.__code__.co_argcount == 1:
frame = plugin_prefs(parent)
else:
frame = plugin_prefs(parent, cmdr, is_beta)
frame = plugin_prefs(parent, cmdr, is_beta)
if not isinstance(frame, nb.Frame):
raise AssertionError
return frame
@ -169,7 +172,7 @@ def load_plugins(master):
plugin.folder = None # Suppress listing in Plugins prefs tab
internal.append(plugin)
except:
print_exc()
pass
PLUGINS.extend(sorted(internal, key = lambda p: operator.attrgetter('name')(p).lower()))
# Add plugin folder to load path so packages can be loaded from plugin folder
@ -190,7 +193,7 @@ def load_plugins(master):
sys.path.append(os.path.join(config.plugin_dir, name))
found.append(Plugin(name, os.path.join(config.plugin_dir, name, 'load.py')))
except:
print_exc()
pass
PLUGINS.extend(sorted(found, key = lambda p: operator.attrgetter('name')(p).lower()))
def provides(fn_name):
@ -268,10 +271,7 @@ def notify_prefs_changed(cmdr, is_beta):
prefs_changed = plugin._get_func('prefs_changed')
if prefs_changed:
try:
if prefs_changed.__code__.co_argcount == 0:
prefs_changed()
else:
prefs_changed(cmdr, is_beta)
prefs_changed(cmdr, is_beta)
except:
print_exc()
@ -293,12 +293,7 @@ def notify_journal_entry(cmdr, is_beta, system, station, entry, state):
if journal_entry:
try:
# Pass a copy of the journal entry in case the callee modifies it
if journal_entry.__code__.co_argcount == 4:
newerror = journal_entry(cmdr, system, station, dict(entry))
elif journal_entry.__code__.co_argcount == 5:
newerror = journal_entry(cmdr, system, station, dict(entry), dict(state))
else:
newerror = journal_entry(cmdr, is_beta, system, station, dict(entry), dict(state))
newerror = journal_entry(cmdr, is_beta, system, station, dict(entry), dict(state))
error = error or newerror
except:
print_exc()
@ -326,26 +321,6 @@ def notify_dashboard_entry(cmdr, is_beta, entry):
return error
def notify_system_changed(timestamp, system, coordinates):
"""
Send notification data to each plugin when we arrive at a new system.
:param timestamp:
:param system:
.. deprecated:: 2.2
Use :func:`journal_entry` with the 'FSDJump' event.
"""
for plugin in PLUGINS:
system_changed = plugin._get_func('system_changed')
if system_changed:
try:
if system_changed.__code__.co_argcount == 2:
system_changed(timestamp, system)
else:
system_changed(timestamp, system, coordinates)
except:
print_exc()
def notify_newdata(data, is_beta):
"""
Send the latest EDMC data from the FD servers to each plugin
@ -358,10 +333,7 @@ def notify_newdata(data, is_beta):
cmdr_data = plugin._get_func('cmdr_data')
if cmdr_data:
try:
if cmdr_data.__code__.co_argcount == 1:
newerror = cmdr_data(data)
else:
newerror = cmdr_data(data, is_beta)
newerror = cmdr_data(data, is_beta)
error = error or newerror
except:
print_exc()

View File

@ -12,7 +12,7 @@ if not config.get('shipyard_provider') and config.getint('shipyard'):
config.delete('shipyard')
def plugin_start():
def plugin_start3(plugin_dir):
return 'Coriolis'
# Return a URL for the current ship

View File

@ -51,7 +51,7 @@ def station_id(system_name, station_name):
return this.station_ids.get((system_id(system_name), station_name), 0)
def plugin_start():
def plugin_start3(plugin_dir):
return 'eddb'
def plugin_app(parent):

View File

@ -331,7 +331,7 @@ class EDDN(object):
# Plugin callbacks
def plugin_start():
def plugin_start3(plugin_dir):
return 'EDDN'
def plugin_app(parent):

View File

@ -50,7 +50,7 @@ def station_url(system_name, station_name):
return 'https://www.edsm.net/en/system?systemName=%s&stationName=ALL' % urllib.parse.quote(system_name)
def plugin_start():
def plugin_start3(plugin_dir):
# Can't be earlier since can only call PhotoImage after window is created
this._IMG_KNOWN = tk.PhotoImage(data = 'R0lGODlhEAAQAMIEAFWjVVWkVWS/ZGfFZ////////////////yH5BAEKAAQALAAAAAAQABAAAAMvSLrc/lAFIUIkYOgNXt5g14Dk0AQlaC1CuglM6w7wgs7rMpvNV4q932VSuRiPjQQAOw==') # green circle
this._IMG_UNKNOWN = tk.PhotoImage(data = 'R0lGODlhEAAQAKEDAGVLJ+ddWO5fW////yH5BAEKAAMALAAAAAAQABAAAAItnI+pywYRQBtA2CtVvTwjDgrJFlreEJRXgKSqwB5keQ6vOKq1E+7IE5kIh4kCADs=') # red circle
@ -89,6 +89,8 @@ def plugin_stop():
this.queue.put(None)
this.thread.join()
this.thread = None
# Suppress 'Exception ignored in: <function Image.__del__ at ...>' errors
this._IMG_KNOWN = this._IMG_UNKNOWN = this._IMG_NEW = this._IMG_ERROR = None
def plugin_prefs(parent, cmdr, is_beta):

View File

@ -6,7 +6,7 @@ import json
import io
def plugin_start():
def plugin_start3(plugin_dir):
return 'EDSY'
# Return a URL for the current ship

View File

@ -64,7 +64,7 @@ def station_url(system_name, station_name):
return this.station or this.system
def plugin_start():
def plugin_start3(plugin_dir):
this.thread = Thread(target = worker, name = 'Inara worker')
this.thread.daemon = True
this.thread.start()