Commit Graph
6434 Commits
Author SHA1 Message Date
Inutt f4e70dbe5b Add documentation for relative plugin imports
diff --git a/PLUGINS.md b/PLUGINS.md
index 6fd20ef9..71aaec7a 100644
--- a/PLUGINS.md
+++ b/PLUGINS.md
@@ -163,6 +163,19 @@ circular imports.
 For an example of how this is done, look at the code in `plugins/common_coreutils.py`
 and the usage of these functions in other core plugins.

+Plugins may import additional code modules from `load.py` in the usual way. Note
+that using an import statement like `import my_module` or `from my_module import
+foo` will only import one module with that name **across all plugins**. This can
+be used to create a shared library used by several plugins if used carefully,
+but may create a conflict if another plugin also has a module of the same name
+containing different code. For example if two plugins both contain a
+`widgets.py` file and both do `import widgets`, only one of the two modules will
+actually be imported.
+
+To avoid this issue, use a relative import statement such as `import .widgets`
+or `from .widgets import foo` to ensure that the module is loaded from the
+current plugin, even if the name conflicts with another plugin's code.
+
 ---

 ## Logging
2025-11-24 20:14:51 +00:00
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
David Sangrey 48dafaf31f Update ChangeLog.md 2025-11-20 18:19:04 -05:00
David Sangrey 459a794460 [PRE-RELEASE] 6.0.0-beta2 Release/6.0.0-beta2 2025-11-20 18:03:58 -05:00
David Sangrey a8e34f2a3b Add Multicrew Check Too 2025-11-20 18:00:06 -05:00
David Sangrey b85705c13a [#2532] Ignore Loadout If Embarked 2025-11-20 17:53:57 -05:00
David Sangrey 691e0a66ad Merge pull request #2531 from dvdmuckle/develop
Improve Linux config import
2025-11-19 22:19:11 -05:00
David Muckle f2d2354fb5 Improve linux config import and logging 2025-11-19 21:50:34 -05:00
David Sangrey 8dbd5cae69 [Minor] Add Custom Config Path, Add Additional Logging 2025-11-19 20:57:41 -05:00
David Sangrey 3fee941bbb [Minor] Fix Some Output Tooling 2025-11-18 22:17:26 -05:00
David Sangrey bc09786b28 [RELEASE] 6.0.0-beta1 Release/6.0.0-beta1 2025-11-18 21:50:56 -05:00
David Sangrey 61e8ff0c7a [Minor] Fix "Reset Provider" popup on first run 2025-11-18 18:56:37 -05:00
David Sangrey 4bd6ec6d7a Merge pull request #2528 from HullSeals/enhancement/261/disable-plugins
Scrollable Notebook and Plugin Enable/Disable System
2025-11-18 18:39:23 -05:00
David Sangrey d545a78b1f Merge branch 'beta' into enhancement/261/disable-plugins 2025-11-17 20:55:49 -05:00
David Sangrey 7a56ea78dc [5.13.3] Update Changelog Release/5.13.3 2025-11-17 19:42:48 -05:00
Ben Peddell f80ac51fe2 [Bugfix] Fix race starting journal monitor
Fixes a race identified where long plugin init times can result in
the following error being thrown in the journal monitor thread,
requiring a preferences reload to have journals continuing to be
processed:

```
Exception in thread Journal worker:
Traceback (most recent call last):
  File "/home/testing/.pyenv/versions/3.11.9/lib/python3.11/threading.py", line 1045, in _bootstrap_inner
    self.run()
  File "/home/testing/.pyenv/versions/3.11.9/lib/python3.11/threading.py", line 982, in run
    self._target(*self._args, **self._kwargs)
  File "/home/testing/gitstuff/EDMarketConnector/monitor.py", line 461, in worker
    self.root.event_generate('<<JournalEvent>>', when="tail")
  File "/home/testing/.pyenv/versions/3.11.9/lib/python3.11/tkinter/__init__.py", line 1933, in event_generate
    self.tk.call(args)
RuntimeError: main thread is not in main loop
```
2025-11-17 19:34:05 -05:00
David Sangrey ca243b775f [#261] Enable Plugin Enable/Disable System
This does rely on plugins respecting a stop call.
2025-11-17 19:12:12 -05:00
David Sangrey 84dc66c8ac [#1293] Create Scrollable Notebook 2025-11-17 19:05:24 -05:00
David Sangrey 435e0d9bd3 Merge pull request #2527 from HullSeals/enhancement/517/config-unification
New Config System
2025-11-17 19:02:02 -05:00
David Sangrey 0f5ab3e706 Update windows-build.yml 2025-11-17 00:00:38 -05:00
David Sangrey 7b97f29867 [Minor] I shouldn't code late at night 2025-11-16 23:54:41 -05:00
David Sangrey 9d2d02ae47 [1790] Rename Output Zip 2025-11-16 23:47:33 -05:00
David Sangrey ef355f5745 Revert Bad Change 2025-11-16 23:33:36 -05:00
David Sangrey 0c175506e7 Merge branch 'enhancement/517/config-unification' of https://github.com/HullSeals/EDMarketConnector into enhancement/517/config-unification 2025-11-16 23:30:38 -05:00
David Sangrey c1229b60a2 [1790] Improve Speed of Builds 2025-11-16 23:29:59 -05:00
David Sangrey ae10433f49 [1790] Improve Speed of Builds 2025-11-16 23:19:52 -05:00
David Sangrey 1cf8e3f4dd [Minor] :( 2025-11-16 22:54:56 -05:00
David Sangrey 0f30b5f650 [1790] Update Build Script 2025-11-16 22:51:55 -05:00
David Sangrey 6e982e8a54 [#1790] Build 64 and 32 Bit Installers 2025-11-16 22:37:25 -05:00
David Sangrey ab0b09420d [517] Handle Other Exceptions 2025-11-16 22:20:39 -05:00
David Sangrey 13eb8b375c [512] Remove Old Tests
These don't apply... because the config they were written for no longer exists.
2025-11-16 21:55:02 -05:00
David Sangrey b638326a25 Merge branch 'develop' into enhancement/517/config-unification 2025-11-16 21:50:45 -05:00
David Sangrey 16212e154b [517] Set Logging Handler and Remove Old Tests 2025-11-16 21:46:36 -05:00
David Sangrey bbfdb0953c Merge pull request #2499 from klightspeed/fix-journal-startup-race
[Bugfix] Fix race starting journal monitor
2025-11-16 21:41:45 -05:00
David Sangrey fa0ec91b8f [517] Don't Die If Nothing to Convert 2025-11-16 20:54:54 -05:00
David Sangrey 52b5c19480 [Minor] Whitespace Stuff 2025-11-16 19:09:42 -05:00
David Sangrey 567d42e4b3 [517] Hand Over Config to New Format 2025-11-16 19:08:19 -05:00
David Sangrey 2d3373843e [517] Export Windows Config to TOML 2025-11-13 22:41:33 -05:00
David Sangrey 71e803f8b5 [Minor] Don't Continually Enable EDAstro 2025-11-13 22:31:02 -05:00
David Sangrey 5405664d52 [Minor] Don't Continually Enable EDAstro 2025-11-13 22:26:00 -05:00
David Sangrey bbb905a534 Remove Prefs Dep Function 2025-11-13 21:46:21 -05:00
David Sangrey a6bafe58b7 Remove Deprecated Functions 2025-11-13 21:45:06 -05:00
David SangreyandPhilipp Trulson c190ce92b3 [#2526] System Profiler Button Fix
Moving this to Develop instead of Main

Co-Authored-By: Philipp Trulson <der-eismann@users.noreply.github.com>
2025-11-13 21:11:36 -05:00
David Sangrey d9e202b968 Merge pull request #2525 from HullSeals/enhancement/2116/additional-tk-to-ttk
Updater Refactor and Additional TK->TTK
2025-11-13 21:04:04 -05:00
David Sangrey 03cbe85535 [2116] A Few More Hand-Overs 2025-11-11 23:17:02 -05:00
David Sangrey b8fa0f841b Revert Bad Label Style Change 2025-11-11 22:31:54 -05:00
David Sangrey 30da989bc5 [Minor] Update LastError to a Dataclass 2025-11-11 22:16:57 -05:00
David Sangrey 0994f1351b [#2440] Refactor Updater 2025-11-11 21:47:02 -05:00
David Sangrey 29784a3e78 [Docs] Update Documentation 2025-11-11 20:31:50 -05:00
David Sangrey c3f9247cd1 [#2116] Hand more things to TTK 2025-11-11 20:24:58 -05:00