Skip to content

Commit 9579ee6

Browse files
committed
add uv, fix plugin loading
1 parent 6c18722 commit 9579ee6

3 files changed

Lines changed: 127 additions & 57 deletions

File tree

openglider/utils/plugin.py

Lines changed: 46 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,37 @@
1111
logger = logging.getLogger(__name__)
1212

1313

14-
def setup_plugins(app: Optional[GliderApp] = None) -> list[str]:
14+
def setup_plugins(app: Optional["GliderApp"] = None) -> list[str]:
1515
"""
1616
Discover and initialize OpenGlider plugins.
1717
"""
1818
plugins = []
19-
potential_plugins = _discover_plugins()
20-
21-
for plugin_name in potential_plugins:
19+
seen = set()
20+
21+
for plugin_name in _discover_plugins():
22+
if plugin_name in seen:
23+
continue
24+
seen.add(plugin_name)
25+
2226
logger.info(f"Loading plugin: {plugin_name}")
23-
27+
2428
if not _load_plugin(plugin_name, app):
2529
continue
26-
30+
2731
plugins.append(plugin_name)
28-
32+
2933
if plugins:
3034
logger.info(f"Successfully loaded {len(plugins)} plugin(s): {', '.join(plugins)}")
3135
else:
3236
logger.info("No plugins loaded")
33-
37+
3438
return plugins
3539

3640

41+
def _normalize(name: str) -> str:
42+
return name.lower().replace("-", "_").strip()
43+
44+
3745
def _discover_plugins() -> list[str]:
3846
"""
3947
Discover OpenGlider plugins using importlib.metadata.
@@ -45,70 +53,52 @@ def _discover_plugins() -> list[str]:
4553
Returns:
4654
List of plugin package names
4755
"""
48-
plugins = []
49-
56+
plugins = {}
57+
5058
try:
51-
# Get all installed distributions
52-
distributions = importlib.metadata.distributions()
53-
54-
for dist in distributions:
55-
name = dist.metadata.get("Name", "")
56-
57-
# Match openglider-* or openglider_* but not openglider itself
58-
if name and name != "openglider":
59-
# Normalize name for comparison (PEP 503)
60-
normalized = name.lower().replace("-", "_")
61-
if normalized.startswith("openglider_"):
62-
# Use the normalized form as module name
63-
plugins.append(normalized)
64-
59+
for dist in importlib.metadata.distributions():
60+
name = dist.metadata.get("Name") or dist.name
61+
if not name:
62+
continue
63+
64+
normalized = _normalize(name)
65+
66+
# only match plugins
67+
if not normalized.startswith("openglider_"):
68+
continue
69+
70+
# deduplicate by normalized name
71+
plugins[normalized] = dist
72+
6573
except Exception as e:
6674
logger.error(f"Error discovering plugins: {e}", exc_info=True)
67-
68-
return plugins
6975

76+
return list(plugins.keys())
7077

71-
def _load_plugin(plugin_name: str, app: Optional[GliderApp]) -> bool:
72-
"""
73-
Load and initialize a single plugin.
74-
75-
Args:
76-
plugin_name: Name of the plugin module to load
77-
app: The GliderApp instance to pass to the init function
78-
fail_fast: Whether to raise exceptions or just log them
79-
80-
Returns:
81-
True if plugin loaded successfully, False otherwise
82-
83-
Raises:
84-
Exception: If fail_fast=True and loading fails
85-
"""
78+
79+
def _load_plugin(plugin_name: str, app: Optional["GliderApp"]) -> bool:
8680
try:
8781
module = importlib.import_module(plugin_name)
8882

8983
# Look for the init function
9084
init_func: Optional[Callable] = getattr(module, "init", None)
91-
85+
9286
if init_func is None:
93-
logger.warning(f"Plugin '{plugin_name}' has no init() function - skipping initialization")
94-
logger.info(f"dir: {dir(module)}")
87+
logger.warning(f"Plugin '{plugin_name}' has no init() function")
9588
return False
96-
89+
9790
if not callable(init_func):
98-
logger.warning(f"Plugin '{plugin_name}' has non-callable init attribute - skipping")
91+
logger.warning(f"Plugin '{plugin_name}' init is not callable")
9992
return False
100-
101-
# Call the plugin's init function
93+
10294
init_func(app)
103-
logger.debug(f"Successfully initialized plugin: {plugin_name}")
95+
logger.debug(f"Initialized plugin: {plugin_name}")
10496
return True
105-
97+
10698
except ImportError as e:
107-
error_msg = f"Failed to import plugin '{plugin_name}': {e}"
108-
logger.error(error_msg, exc_info=True)
99+
logger.error(f"Failed to import plugin '{plugin_name}': {e}", exc_info=True)
109100
return False
110-
101+
111102
except Exception as e:
112-
error_msg = f"Error initializing plugin '{plugin_name}': {e}"
113-
logger.error(error_msg)
114-
raise
103+
logger.error(f"Error initializing plugin '{plugin_name}': {e}", exc_info=True)
104+
raise

openglider/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import packaging.version
22

33
__version__ = '0.1.3'
4-
version = packaging.version.Version(__version__)
4+
version = packaging.version.Version(__version__)

pyproject.toml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "openglider"
7+
dynamic = ["version"]
8+
description = "A python library for paraglider design"
9+
readme = "README.md"
10+
requires-python = ">=3.8"
11+
license = "GPL-3.0-or-later"
12+
authors = [
13+
{ name = "airG products", email = "simon@airg.family" }
14+
]
15+
keywords = ["paraglider", "flying"]
16+
classifiers = [
17+
"Programming Language :: Python :: 3",
18+
"Programming Language :: Python :: 3.8",
19+
"Programming Language :: Python :: 3.9",
20+
"Programming Language :: Python :: 3.10",
21+
"Programming Language :: Python :: 3.11",
22+
"Programming Language :: Python :: 3.12",
23+
]
24+
25+
dependencies = [
26+
"euklid",
27+
"pyfoil",
28+
"pydantic",
29+
"svgwrite",
30+
"numpy",
31+
"scipy",
32+
"ezdxf",
33+
"ezodf",
34+
"lxml",
35+
"pyexcel-ods",
36+
"packaging",
37+
"meshpy",
38+
"svglib",
39+
]
40+
41+
[project.optional-dependencies]
42+
gui = [
43+
"qtpy",
44+
"pyside6",
45+
"qtawesome",
46+
"qasync",
47+
"qtmodern",
48+
"qtconsole",
49+
"pyqtgraph",
50+
"matplotlib",
51+
"vtk",
52+
]
53+
54+
[project.scripts]
55+
openglider = "openglider.gui:start_main_window"
56+
57+
[project.urls]
58+
Homepage = "https://www.openglider.org"
59+
Repository = "https://github.com/booya-at/OpenGlider"
60+
61+
[tool.hatch.version]
62+
path = "openglider/version.py"
63+
pattern = "(?s).*__version__\\s*=\\s*['\"](?P<version>[^'\"]+)['\"].*"
64+
65+
[tool.hatch.build.targets.wheel]
66+
packages = ["openglider"]
67+
68+
[tool.hatch.build.targets.wheel.force-include]
69+
"openglider/py.typed" = "openglider/py.typed"
70+
71+
[tool.uv]
72+
dev-dependencies = [
73+
"pytest>=7.0",
74+
"mypy>=1.0",
75+
]
76+
77+
[tool.mypy]
78+
python_version = "3.8"
79+
warn_return_any = true
80+
warn_unused_configs = true

0 commit comments

Comments
 (0)