Inutt b9f3cf3d6a Fix relative imports in plugins
Allow plugins to use relative imports to avoid conflicts between modules with the same name from another plugin.

Fixes #2345
diff --git a/plug.py b/plug.py
index 1a8779f7..8890c80f 100644
--- a/plug.py
+++ b/plug.py
@@ -48,13 +48,20 @@ last_error = LastError()
 class Plugin:
     """An EDMC plugin."""

-    def __init__(self, name: str, loadfile: Path | None, plugin_logger: logging.Logger | None):  # noqa: CCR001
+    def __init__(
+        self,
+        name: str,
+        loadfile: Path | None,
+        plugin_logger: logging.Logger | None,
+        internal: bool = False
+    ):  # noqa: CCR001
         """
         Load a single plugin.

         :param name: Base name of the file being loaded from.
         :param loadfile: Full path/filename of the plugin.
         :param plugin_logger: The logging instance for this plugin to use.
+        :param internal: True to use internal plugin loader logic. Defaults to False.
         :raises Exception: Typically, ImportError or OSError
         """
         self.name: str = name  # Display name.
@@ -65,14 +72,19 @@ class Plugin:
         if loadfile:
             logger.info(f'loading plugin "{name.replace(".", "_")}" from "{loadfile}"')
             try:
-                filename = 'plugin_'
-                filename += name.encode(encoding='ascii', errors='replace').decode('utf-8').replace('.', '_')
-                spec = importlib.util.spec_from_file_location(filename, loadfile)
-                # Replaces older load_module() code. Includes a safety check that the module name is set.
-                if spec is not None and spec.loader is not None:
-                    module = importlib.util.module_from_spec(spec)
-                    sys.modules[module.__name__] = module
-                    spec.loader.exec_module(module)
+                if internal:
+                    filename = 'plugin_'
+                    filename += name.encode(encoding='ascii', errors='replace').decode('utf-8').replace('.', '_')
+                    spec = importlib.util.spec_from_file_location(filename, loadfile)
+                    # Replaces older load_module() code. Includes a safety check that the module name is set.
+                    if spec is not None and spec.loader is not None:
+                        module = importlib.util.module_from_spec(spec)
+                        sys.modules[module.__name__] = module
+                        spec.loader.exec_module(module)
+                else:
+                    module = importlib.import_module('.load', name)
+
+                if module:
                     if getattr(module, 'plugin_start3', None):
                         newname = module.plugin_start3(Path(loadfile).resolve().parent)
                         self.name = str(newname) if newname else self.name
@@ -170,7 +182,7 @@ def _load_internal_plugins():
             try:
                 plugin_name = name[:-3]
                 plugin_path = config.internal_plugin_dir_path / name
-                plugin = Plugin(plugin_name, plugin_path, logger)
+                plugin = Plugin(plugin_name, plugin_path, logger, internal=True)
                 plugin.folder = None
                 internal.append(plugin)
             except Exception:

diff --git a/plug.py b/plug.py
index 1a8779f7..8890c80f 100644
--- a/plug.py
+++ b/plug.py
@@ -48,13 +48,20 @@ last_error = LastError()
 class Plugin:
     """An EDMC plugin."""

-    def __init__(self, name: str, loadfile: Path | None, plugin_logger: logging.Logger | None):  # noqa: CCR001
+    def __init__(
+        self,
+        name: str,
+        loadfile: Path | None,
+        plugin_logger: logging.Logger | None,
+        internal: bool = False
+    ):  # noqa: CCR001
         """
         Load a single plugin.

         :param name: Base name of the file being loaded from.
         :param loadfile: Full path/filename of the plugin.
         :param plugin_logger: The logging instance for this plugin to use.
+        :param internal: True to use internal plugin loader logic. Defaults to False.
         :raises Exception: Typically, ImportError or OSError
         """
         self.name: str = name  # Display name.
@@ -65,14 +72,19 @@ class Plugin:
         if loadfile:
             logger.info(f'loading plugin "{name.replace(".", "_")}" from "{loadfile}"')
             try:
-                filename = 'plugin_'
-                filename += name.encode(encoding='ascii', errors='replace').decode('utf-8').replace('.', '_')
-                spec = importlib.util.spec_from_file_location(filename, loadfile)
-                # Replaces older load_module() code. Includes a safety check that the module name is set.
-                if spec is not None and spec.loader is not None:
-                    module = importlib.util.module_from_spec(spec)
-                    sys.modules[module.__name__] = module
-                    spec.loader.exec_module(module)
+                if internal:
+                    filename = 'plugin_'
+                    filename += name.encode(encoding='ascii', errors='replace').decode('utf-8').replace('.', '_')
+                    spec = importlib.util.spec_from_file_location(filename, loadfile)
+                    # Replaces older load_module() code. Includes a safety check that the module name is set.
+                    if spec is not None and spec.loader is not None:
+                        module = importlib.util.module_from_spec(spec)
+                        sys.modules[module.__name__] = module
+                        spec.loader.exec_module(module)
+                else:
+                    module = importlib.import_module('.load', name)
+
+                if module:
                     if getattr(module, 'plugin_start3', None):
                         newname = module.plugin_start3(Path(loadfile).resolve().parent)
                         self.name = str(newname) if newname else self.name
@@ -170,7 +182,7 @@ def _load_internal_plugins():
             try:
                 plugin_name = name[:-3]
                 plugin_path = config.internal_plugin_dir_path / name
-                plugin = Plugin(plugin_name, plugin_path, logger)
+                plugin = Plugin(plugin_name, plugin_path, logger, internal=True)
                 plugin.folder = None
                 internal.append(plugin)
             except Exception:
2025-11-24 18:00:58 +00:00
2025-11-18 22:17:26 -05:00
2025-11-20 18:03:58 -05:00
2025-06-30 12:41:24 +00:00
2025-11-11 20:31:50 -05:00
2024-05-06 13:53:48 -04:00
2025-11-20 18:00:06 -05:00
2025-04-11 20:49:13 -04:00
2025-11-18 22:17:26 -05:00
2025-11-16 21:55:02 -05:00
2023-11-16 16:14:59 -05:00
2024-04-05 17:20:05 -04:00
2018-08-01 00:23:47 +01:00
2024-04-27 20:10:09 -04:00
2024-04-05 17:20:05 -04:00
2025-11-20 18:19:04 -05:00
2025-04-11 19:57:18 -04:00
2024-06-10 17:21:06 -04:00
2015-06-02 20:14:04 +01:00
2024-06-10 17:21:06 -04:00
2025-04-27 21:58:01 -04:00
2025-11-13 21:45:06 -05:00
2022-12-21 18:26:42 +00:00
2024-06-10 18:16:11 -04:00
2025-11-11 20:24:58 -05:00
2025-11-24 18:00:58 +00:00
2025-05-03 19:52:14 -04:00
2020-07-06 16:31:04 +01:00
2025-04-27 21:58:01 -04:00
2015-09-12 04:03:12 +01:00
2015-09-12 04:03:12 +01:00
2025-11-11 20:24:58 -05:00
2024-03-27 22:01:49 -04:00
2025-11-11 21:47:02 -05:00

Any questions or offers of help can be directed to the EDCD Discord #edmc channel:

Discord chat

Elite: Dangerous Market Connector (EDMC)

This application is only of use to PC players of the game Elite Dangerous (and its expansions). It won't work with PS4 or Xbox accounts.

It utilises the Journal files written by the game on the user's computer, together with data from the API Frontier Developments supplies in order to feed this data to various third party sites that the user may find useful.

See the Wiki documentation for more details.

Installation & Uninstall

Please see the Installation & Setup wiki page.

Running from source

Please see the Running from source wiki page.

Plugins

Plugins extend the behaviour of this app. See the Plugins wiki page for more information.

If you would like to write a plugin please see PLUGINS.md.

Troubleshooting

Please see the Troubleshooting wiki page.

Reporting a problem

Please report a problem as a new GitHub issue. See Reporting a problem for further guidance, including how to find the necessary log files to attach to the report.

Packaging for distribution

Please see docs/Releasing.md.

Disclaimer

This app uses the “Companion” web API that Frontier originally supplied for their Elite Dangerous iOS app and now support for third-party apps. If that API ceases to function in the future then much of this application's functionality will be curtailed (although it could still utilise Journal files).

Acknowledgements

Please see the Acknowledgements wiki page.

License

Copyright © 2015-2019 Jonathan Harris, 2020-2024 EDCD

Licensed under the GNU Public License (GPL) version 2 or later.

S
Description
Downloads commodity market and other station data from the game Elite: Dangerous for use with all popular online and offline trading tools.
Readme GPL-2.0
45 MiB
0 Stars 1 Watchers 0 Forks
Languages
Python 99.7%
Shell 0.3%