Commit Graph
119 Commits
Author SHA1 Message Date
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 30da989bc5 [Minor] Update LastError to a Dataclass 2025-11-11 22:16:57 -05:00
David Sangrey 65273742d0 [#1775] Retire Usage of Assert
Removes assert statements from EDMC non-test code, paving the way to enable -OO code.
2025-04-27 21:58:01 -04:00
David Sangrey 4c334835f2 [Minor] Simplify if-else statements 2025-04-11 19:57:18 -04:00
David Sangrey 2c4e409ca3 Merge branch 'main' into develop 2025-04-02 00:01:39 -04:00
David Sangrey 84538c88e9 [Minor] Update Winsparkle Ver, Remove UwU
Also clarifies an import for importlib and fixes a pre-commit hook
2025-04-01 23:27:13 -04:00
Florian Probst 92a752cee0 Update plug.py 2025-02-24 23:31:28 +01:00
David Sangrey f18ead9efa [#1428] Implement Timestamp Checker 2025-02-16 20:49:03 -05:00
David Sangrey f8b7a8b919 [2114] Cleanup Initial Commit
Some of these are already paths.
2024-06-10 17:49:13 -04:00
David Sangrey fe8818d187 [2114] Apply PathLib Handover 2024-06-10 17:21:06 -04:00
David Sangrey d4960efa8c [Lang] Update Translations
Also corrects fleetcarrier to proper Fleet Carrier
2024-06-03 16:44:18 -04:00
David Sangrey 47f36a035c [1462] Remove Useless Comment
Add Slightly More Useful Comment
2024-05-01 11:08:27 -04:00
David Sangrey c48df655d1 [#1462] LoadModule Replacement, Take Two
The previous attempt was almost correct - but we needed to ensure that the system was aware of the module in order to handle it correctly.
2024-04-30 23:16:51 -04:00
David Sangrey d9c7a79155 [Minor] Update Type Hintings
No Content Changes, Shuts Up MyPy
2024-04-06 16:59:49 -04:00
David Sangrey b7633fa6e3 Handover a number of Lists to Tuples
Tuples are (slightly) more efficient for comparing if x in y. Not that it'll really matter at this scale, but it's technically better and simple to implement.

Applying to all files except theme.py, because theme.py is scary.
2023-12-27 00:29:35 -05:00
Phoebe 34d91dfb2d [Enhancement] Broken Plugins Popup
- Adds a Popup at startup about Plugins that failed to load.
- Adds entry about broken Plugins in the Settings - Plugins tab.
- Adds corresponding translation entries.
2023-12-14 01:06:09 +01:00
David Sangrey f30fb56f6e [2051] Re-add missing context
It's not a refactor if I don't accidentally nuke a lang comment
2023-11-30 22:05:59 -05:00
David Sangrey cb2a18025c [2051] First Pass Remaining Files 2023-11-30 21:30:18 -05:00
David Sangrey eedb9b840c #1462 It was, in fact, not that simple. 2023-08-03 22:31:36 -04:00
David Sangrey 0f5be049ed #1462 Suppress MyPy, who is Wrong. 2023-08-03 18:05:39 -04:00
David Sangrey db73b9d775 #2047 Suppress Inaccurate MyPy 2023-08-03 17:33:23 -04:00
David Sangrey 816d041992 #1462 Remove Deprecated load_module() 2023-08-03 16:30:50 -04:00
Athanasius 6b9ec285fd plug.py: Use x if x else y not or , & small type cleanup 2022-12-30 16:43:58 +00:00
Athanasius 74b070ffe9 Merge pull request #1773 from aussig/feature/847/capi-fleetcarrier
Feature/847/capi fleetcarrier
2022-12-30 16:15:37 +00:00
Athanasius 18833c5e36 plugins: Comment *why* the "load plugins that are packages" first is there
It's *NOT* that it will actually load the plugin *as* a package, as the code
explicitly only loads `load.py` still.
2022-12-26 19:48:38 +00:00
aussig 1c39ca5eb9 Merge branch 'develop' into feature/847/capi-fleetcarrier 2022-12-24 10:38:22 +00:00
Athanasius 5d1eb9e3b1 Fix "could be None" conditional for call to plug.notify_journal_entry()
In testing the *first* hit on this does have `monitor.cmdr` set, but neither
`monitor.system` or `monitor.station`.  So:

1. Allow those to be `None` in the function signature,
2. Guard against only `monitor.cmdr` being falsey before the call.
3. Move the `if err:` to the same scope.
2022-12-24 10:11:11 +00:00
aussig 41962663d8 Merge branch 'develop' into feature/847/capi-fleetcarrier 2022-12-24 08:21:18 +00:00
Athanasius 37b054b3d3 Fix type of master passed to plug.load_plugins() 2022-12-23 14:47:27 +00:00
Athanasius 71cbfb8358 plugins/edsm: Lots of type fixing, inc. conditionals where None is possible 2022-12-23 14:47:23 +00:00
Athanasius f4b150960c prefs.py & related files: Fix up mypy type checking
* Some trivial.
* As myNotebook.py's class is based on `ttk.Notebook`, typing changed to
  that.
2022-12-23 14:47:21 +00:00
Athanasius 26b12f5b14 plugins/inara, plug.py: Minor typing fixes 2022-12-23 14:47:18 +00:00
aussig 9e17c46b25 Implement suggestions from PR #1773. 2022-12-22 16:21:42 +00:00
aussig 8e5953408e Handling of /fleetcarrier CAPI endpoint and implementation of plugin callback function 2022-12-21 23:00:35 +00:00
Athanasius b6fe115ea7 CAPI: Add support for plugin cmdr_data_legacy()
* Renames `plug.notify_newdata()` to the more precise `notify_capidata()`.
* If CAPI data was from SERVER_LEGACY, then use plugin `cmdr_data_legacy()`
  instead of `cmdr_data()`.
2022-12-08 11:17:52 +00:00
Athanasius a0c73a5c71 plug.py: flake8 & mypy pass 2022-12-03 14:48:50 +00:00
Athanasius 1f21c7fae4 plug.py: Only type annotation coverage to go in flake8 2022-12-03 14:10:09 +00:00
Athanasius 3247fb805c plug.py: Further docstring fixes 2022-12-03 14:05:59 +00:00
Athanasius 413b2f06f8 plug.py: Some docstrings, change to plugin loading
* Plugin loading: Avoid using .format()
2022-12-03 14:03:47 +00:00
Athanasius c8081f339a plug.py: Use logger.trace_if(...) 2021-08-13 15:14:02 +01:00
norohind c08c1a574e plug.py: reorder notify* functions 2021-08-11 13:55:46 +03:00
norohind ba38b5f02d plug.py: more verbose log message on failed while handling CQC mode journal entry 2021-08-10 16:16:01 +03:00
norohind 7b39b0fda0 plug.py: use copy.deepcopy() instead of dict() in cqc_callback
To create deepcopy for passing data to cqc_callback
2021-08-10 15:55:14 +03:00
norohind 030713f5b9 plug.py: rename journal_entry to cqc_callback in notify_journal_entry_cqc 2021-08-10 13:55:10 +03:00
norohind 6e2f49a63c plug.py: remove useless 'as e' in notify_journal_entry_cqc 2021-08-10 13:51:22 +03:00
norohind 3283439485 Code style fixes 2021-08-10 03:00:36 +03:00
norohindandA_D 84500b775a More paranoia about is journal_entry_cqc callable
Co-authored-by: A_D <A-UNDERSCORE-D@users.noreply.github.com>
2021-08-10 02:52:39 +03:00
norohind 27fe43bf8c WIP: implement journal_entry_cqc()
journal_entry_cqc function in plugin's api allow plugins to recieve
journal events when player are in CQC
2021-08-09 04:37:23 +03:00
A_D fe90f1f0b3 Cleaned up imports, removed incase imports
closes EDCD/EDMarketConnector#569
2021-05-28 14:46:51 +02:00
Athanasius bc6557dd9c Quieten various TRACE log output.
* A lot of this is commented out.  It might be useful in the future, but
  is just too noisy for now.
* Changed the protocol webserver to info, as it is.
* Left the EDSM 'not 1XX, 2XX or 5XX' in as it's a warning, so 'pass's
  on the conditional bodies that would be empty now trace's are
  commented.
2021-04-12 08:31:47 +01:00