Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/exampleplugin/src/plugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ entry = "main"
version = "1.0"

min_api_version = "0.1.0"
max_api_version = "0.1.10"
max_api_version = "1.1.10"
2 changes: 1 addition & 1 deletion example/plugins/folderplugin/plugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ entry = "main"
version = "1.0"

min_api_version = "0.1.0"
max_api_version = "0.1.10"
max_api_version = "1.1.10"
4 changes: 2 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@


if __name__ == "__main__":
manager = create_default_manager(API_VERSION, Path("example/exampleplugin/build/"))
manager = create_default_manager(API_VERSION, Path("example/plugins/"))
manager.initialize_hooks()

plugin_src = Path("example/exampleplugin")
Expand Down Expand Up @@ -105,4 +105,4 @@
print(sort_plugins(plugins))
print()

# manager.load_all_plugins()
manager.load_all_plugins()
4 changes: 2 additions & 2 deletions openpluginloader/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

def archive_plugin():
"""Builds a plugin into a targz"""
src = CWD if len(sys.argv) < 1 else Path(sys.argv[0])
dest = DEFAULT_DEST if len(sys.argv) < 2 else Path(sys.argv[1])
src = CWD if len(sys.argv) < 1 else CWD / sys.argv[0]
dest = DEFAULT_DEST if len(sys.argv) < 2 else CWD / sys.argv[1]

meta_loader = DefaultMetadataLoader()
archiver = DefaultPluginArchiver()
Expand Down
115 changes: 85 additions & 30 deletions openpluginloader/defaultstrategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,10 @@ def exec_module(self, module: ModuleType):
with clear_module_caches(DEFAULT_MODS):
with set_meta_paths(
[
TarGzImportHook(self.tar_file_path, Path("site-packages")),
TarGzImportHook(self.tar_file_path, Path()),
TarGZPluginFileImportHook(
self.tar_file_path, Path("site-packages")
),
TarGZPluginFileImportHook(self.tar_file_path, Path()),
*(
metapath
for metapath in sys.meta_path
Expand Down Expand Up @@ -316,36 +318,73 @@ def __init__(self, tar_file_path: Path, sub_path: Path):
self.tar_file_path = tar_file_path
self.sub_path = sub_path

def find_spec(self, fullname: str, path, target=None) -> ModuleSpec | None:
fullname_path = self.sub_path / "/".join(fullname.split("."))
def make_module_spec(
self, fullname: str, file_path: str, path: str | None, is_package: bool
):
return ModuleSpec(
fullname,
TarGzLoader(
fullname,
file_path,
self.tar_file_path,
),
origin=path,
is_package=is_package,
)

def _find_spec_folder(
self, fullname: str, path: str | None, target=None
) -> ModuleSpec | None:
fullname_path = (
self.tar_file_path / self.sub_path / "/".join(fullname.split("."))
)
if fullname_path.absolute().exists() and fullname_path.absolute().is_dir():
spec = self.make_module_spec(
fullname, str(fullname_path.absolute()), path, True
)

spec.has_location = True
elif Path(str(fullname_path.absolute()) + ".py").exists():
spec = self.make_module_spec(
fullname, str((str(fullname_path.absolute()) + ".py")), path, False
)

spec.has_location = True
else:
return None
return spec

def find_spec(
self, fullname: str, path: list[str] | None | str, target=None
) -> ModuleSpec | None:
if isinstance(path, list):
path = path[0] if len(path) > 0 else None

if self.tar_file_path.is_file() and tarfile.is_tarfile(self.tar_file_path):
return self._find_spec_targz(fullname, path, target)
elif self.tar_file_path.is_dir():
return self._find_spec_folder(fullname, path, target)
return None

def _find_spec_targz(
self, fullname: str, path: str | None, target=None
) -> ModuleSpec | None:
fullname_path = self.sub_path / "/".join(fullname.split("."))

with tarfile.open(self.tar_file_path, "r:gz") as f:
names = f.getnames()
if any(Path(name).is_relative_to(fullname_path) for name in names):
spec = ModuleSpec(
fullname,
TarGzLoader(
fullname,
str(self.tar_file_path / fullname_path),
self.tar_file_path,
),
origin=path,
is_package=True,
spec = self.make_module_spec(
fullname, str(self.tar_file_path / fullname_path), path, True
)

spec.has_location = True
elif (str(fullname_path).replace("\\", "/") + ".py") in names:
spec = ModuleSpec(
spec = self.make_module_spec(
fullname,
TarGzLoader(
fullname,
str(self.tar_file_path / (str(fullname_path) + ".py")),
self.tar_file_path,
),
origin=path,
is_package=False,
str(self.tar_file_path / (str(fullname_path) + ".py")),
path,
False,
)

spec.has_location = True
Expand All @@ -354,7 +393,29 @@ def find_spec(self, fullname: str, path, target=None) -> ModuleSpec | None:
return spec


class TarGzPluginImportHook:
class TarGZPluginFileImportHook(TarGzImportHook):
"""Actually in charge of loading individual files inside of a plugin."""

def make_module_spec(
self,
fullname: str,
file_path: str,
path: str | None,
is_package: bool,
):
return ModuleSpec(
fullname,
TarGzPluginLoader(
fullname,
file_path,
self.tar_file_path,
),
origin=path,
is_package=is_package,
)


class DefaultPluginImportHook:
"""An import hook that interprets any modules prefixed as `plugin.<plugin-name>` as
a plugin within whatever plugin path is being used
"""
Expand Down Expand Up @@ -387,12 +448,6 @@ def __init__(
)
self.plugins_module.has_location = True

def find_module(
self,
fullname,
path,
): ...

def create_plugin_module(
self, plugin_meta: PluginMetadata, fullname: str
) -> ModuleSpec:
Expand Down Expand Up @@ -489,7 +544,7 @@ def create_default_manager(
plugin_scanner=scanner,
api_version=api_version,
import_hooks=[
TarGzPluginImportHook(
DefaultPluginImportHook(
plugin_path, scanner.get_available_plugins(api_version)
),
],
Expand All @@ -510,5 +565,5 @@ def create_default_manager(
"PluginFolderLoader",
# # finders
"TarGzImportHook",
"TarGzPluginImportHook",
"DefaultPluginImportHook",
]
8 changes: 4 additions & 4 deletions openpluginloader/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ def load_plugin(self, plugin: PluginMetadata):

Important: Ensure you run `.initialize_hooks()` first
"""
if plugin.min_api_version < self.api_version:
raise PluginOutOfDate(plugin, self.api_version)
if plugin.max_api_version > self.api_version:
raise PluginTooNew(plugin, self.api_version)
if plugin.min_api_version > self.api_version:
raise PluginOutOfDate(plugin, self.api_version, plugin.min_api_version)
if plugin.max_api_version < self.api_version:
raise PluginTooNew(plugin, self.api_version, plugin.max_api_version)

return self.loading_strategy.load_plugin(plugin)

Expand Down
1 change: 1 addition & 0 deletions other_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("We aren't supposed to be able to get here")
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "openpluginloader"
version = "1.0.3"
version = "1.0.4"
description = "A plugin loader library meant for wide use and quick adoption."
readme = "README.md"
requires-python = ">=3.13"
Expand Down
Loading