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 Sangrey and Philipp 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