MoleditPy-linux 2.0.1__py3-none-any.whl → 2.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- moleditpy_linux/modules/constants.py +1 -1
- moleditpy_linux/modules/main_window_main_init.py +31 -3
- moleditpy_linux/modules/plugin_manager.py +64 -29
- {moleditpy_linux-2.0.1.dist-info → moleditpy_linux-2.1.1.dist-info}/METADATA +3 -3
- {moleditpy_linux-2.0.1.dist-info → moleditpy_linux-2.1.1.dist-info}/RECORD +9 -9
- {moleditpy_linux-2.0.1.dist-info → moleditpy_linux-2.1.1.dist-info}/WHEEL +0 -0
- {moleditpy_linux-2.0.1.dist-info → moleditpy_linux-2.1.1.dist-info}/entry_points.txt +0 -0
- {moleditpy_linux-2.0.1.dist-info → moleditpy_linux-2.1.1.dist-info}/licenses/LICENSE +0 -0
- {moleditpy_linux-2.0.1.dist-info → moleditpy_linux-2.1.1.dist-info}/top_level.txt +0 -0
|
@@ -1728,7 +1728,7 @@ class MainWindowMainInit(object):
|
|
|
1728
1728
|
|
|
1729
1729
|
explore_plugins_action = QAction("Explore Plugins", self)
|
|
1730
1730
|
explore_plugins_action.triggered.connect(
|
|
1731
|
-
lambda: QDesktopServices.openUrl(QUrl("https://github.
|
|
1731
|
+
lambda: QDesktopServices.openUrl(QUrl("https://hiroyokoyama.github.io/moleditpy-plugins/explorer/"))
|
|
1732
1732
|
)
|
|
1733
1733
|
plugin_menu.addAction(explore_plugins_action)
|
|
1734
1734
|
|
|
@@ -1736,14 +1736,42 @@ class MainWindowMainInit(object):
|
|
|
1736
1736
|
|
|
1737
1737
|
# Add dynamic plugin actions
|
|
1738
1738
|
plugins = self.plugin_manager.discover_plugins(self)
|
|
1739
|
+
|
|
1739
1740
|
if not plugins:
|
|
1740
1741
|
no_plugin_action = QAction("(No plugins found)", self)
|
|
1741
1742
|
no_plugin_action.setEnabled(False)
|
|
1742
1743
|
plugin_menu.addAction(no_plugin_action)
|
|
1743
1744
|
else:
|
|
1745
|
+
# Sort plugins: directories first (to create menus), then alphabetical by name
|
|
1746
|
+
# Actually simple sort by rel_folder, name is fine
|
|
1747
|
+
plugins.sort(key=lambda x: (x.get('rel_folder', ''), x['name']))
|
|
1748
|
+
|
|
1749
|
+
# Dictionary to keep track of created submenus: path -> QMenu
|
|
1750
|
+
menus = { "": plugin_menu }
|
|
1751
|
+
|
|
1744
1752
|
for p in plugins:
|
|
1745
|
-
|
|
1753
|
+
rel_folder = p.get('rel_folder', "")
|
|
1754
|
+
|
|
1755
|
+
# Get or create the parent menu for this plugin
|
|
1756
|
+
parent_menu = menus.get("") # Start at root
|
|
1757
|
+
|
|
1758
|
+
if rel_folder:
|
|
1759
|
+
# Split path and traverse/create submenus
|
|
1760
|
+
parts = rel_folder.split(os.sep)
|
|
1761
|
+
current_path = ""
|
|
1762
|
+
for part in parts:
|
|
1763
|
+
new_path = os.path.join(current_path, part) if current_path else part
|
|
1764
|
+
|
|
1765
|
+
if new_path not in menus:
|
|
1766
|
+
# Create new submenu
|
|
1767
|
+
sub_menu = parent_menu.addMenu(part)
|
|
1768
|
+
menus[new_path] = sub_menu
|
|
1769
|
+
|
|
1770
|
+
parent_menu = menus[new_path]
|
|
1771
|
+
current_path = new_path
|
|
1772
|
+
|
|
1773
|
+
# Add action to the resolved parent_menu
|
|
1746
1774
|
action = QAction(p['name'], self)
|
|
1747
1775
|
action.triggered.connect(lambda checked, mod=p['module']: self.plugin_manager.run_plugin(mod, self.mw if hasattr(self, 'mw') else self))
|
|
1748
|
-
|
|
1776
|
+
parent_menu.addAction(action)
|
|
1749
1777
|
|
|
@@ -34,7 +34,8 @@ class PluginManager:
|
|
|
34
34
|
|
|
35
35
|
def discover_plugins(self, parent=None):
|
|
36
36
|
"""
|
|
37
|
-
|
|
37
|
+
Recursively scans the plugin directory for .py files and attempts to import them.
|
|
38
|
+
Ignores __pycache__ and other directories starting with "__".
|
|
38
39
|
Returns a list of valid loaded plugins.
|
|
39
40
|
"""
|
|
40
41
|
self.ensure_plugin_dir()
|
|
@@ -43,35 +44,69 @@ class PluginManager:
|
|
|
43
44
|
if not os.path.exists(self.plugin_dir):
|
|
44
45
|
return []
|
|
45
46
|
|
|
46
|
-
for
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
for root, dirs, files in os.walk(self.plugin_dir):
|
|
48
|
+
# Modify dirs in-place to skip hidden directories and __pycache__
|
|
49
|
+
dirs[:] = [d for d in dirs if not d.startswith('__') and d != '__pycache__']
|
|
50
|
+
|
|
51
|
+
for filename in files:
|
|
52
|
+
if filename.endswith(".py") and not filename.startswith("__"):
|
|
53
|
+
filepath = os.path.join(root, filename)
|
|
54
|
+
|
|
55
|
+
# Calculate relative folder path for menu structure
|
|
56
|
+
# equivalent to: rel_path = os.path.relpath(root, self.plugin_dir)
|
|
57
|
+
# if root is plugin_dir, rel_path is '.'
|
|
58
|
+
rel_folder = os.path.relpath(root, self.plugin_dir)
|
|
59
|
+
if rel_folder == '.':
|
|
60
|
+
rel_folder = ""
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
# Unique module name based on file path to avoid conflicts
|
|
64
|
+
# e.g. plugins.subdir.myplugin
|
|
65
|
+
module_name = os.path.splitext(os.path.relpath(filepath, self.plugin_dir))[0].replace(os.sep, '.')
|
|
59
66
|
|
|
60
|
-
|
|
61
|
-
if
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
spec = importlib.util.spec_from_file_location(module_name, filepath)
|
|
68
|
+
if spec and spec.loader:
|
|
69
|
+
module = importlib.util.module_from_spec(spec)
|
|
70
|
+
sys.modules[spec.name] = module
|
|
71
|
+
spec.loader.exec_module(module)
|
|
72
|
+
|
|
73
|
+
# Check for required attributes
|
|
74
|
+
plugin_name = getattr(module, 'PLUGIN_NAME', filename[:-3])
|
|
75
|
+
|
|
76
|
+
# Valid plugin if it has 'run' OR 'autorun'
|
|
77
|
+
has_run = hasattr(module, 'run') and callable(module.run)
|
|
78
|
+
has_autorun = hasattr(module, 'autorun') and callable(module.autorun)
|
|
79
|
+
|
|
80
|
+
if has_run:
|
|
81
|
+
self.plugins.append({
|
|
82
|
+
'name': plugin_name,
|
|
83
|
+
'module': module,
|
|
84
|
+
'rel_folder': rel_folder
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
if has_autorun:
|
|
88
|
+
try:
|
|
89
|
+
if parent:
|
|
90
|
+
module.autorun(parent)
|
|
91
|
+
else:
|
|
92
|
+
print(f"Skipping autorun for {plugin_name}: parent not provided.")
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f"Error executing autorun for {filename}: {e}")
|
|
95
|
+
traceback.print_exc()
|
|
96
|
+
|
|
97
|
+
if not has_run and not has_autorun:
|
|
98
|
+
print(f"Plugin {filename} skipped: Missing 'run(main_window)' or 'autorun(main_window)' function.")
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
# Robust error handling
|
|
102
|
+
msg = f"Failed to load plugin {filename}:\n{e}"
|
|
103
|
+
print(msg)
|
|
104
|
+
traceback.print_exc()
|
|
105
|
+
if parent:
|
|
106
|
+
# Use print/status bar instead of popups for non-critical failures during bulk load?
|
|
107
|
+
# For now, keep it visible but maybe less intrusive if many fail?
|
|
108
|
+
# sticking to original logic just in catch block
|
|
109
|
+
pass
|
|
75
110
|
|
|
76
111
|
return self.plugins
|
|
77
112
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy-linux
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
|
|
5
5
|
Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -764,7 +764,7 @@ This application combines a modern GUI built with **PyQt6**, powerful cheminform
|
|
|
764
764
|
|
|
765
765
|
## Installation and Execution
|
|
766
766
|
|
|
767
|
-
For detailed instructions, please refer to the project [Wiki](https://github.com/HiroYokoyama/python_molecular_editor/wiki). A [Docker version](https://github.com/HiroYokoyama/python_molecular_editor_docker) is also available.
|
|
767
|
+
For detailed instructions, please refer to the project [Wiki](https://github.com/HiroYokoyama/python_molecular_editor/wiki). A [Docker version](https://github.com/HiroYokoyama/python_molecular_editor_docker) is also available. A [Windows installer](https://hiroyokoyama.github.io/python_molecular_editor/windows-installer/windows_installer) is also distributed.
|
|
768
768
|
|
|
769
769
|
#### Requirements
|
|
770
770
|
|
|
@@ -879,7 +879,7 @@ This project is licensed under the **GNU General Public License v3.0 (GPL-v3)**.
|
|
|
879
879
|
|
|
880
880
|
## インストールと実行
|
|
881
881
|
|
|
882
|
-
詳細な手順については、プロジェクトの[Wiki](https://github.com/HiroYokoyama/python_molecular_editor/wiki)を参照してください。[Docker版](https://github.com/HiroYokoyama/python_molecular_editor_docker)も利用可能です。
|
|
882
|
+
詳細な手順については、プロジェクトの[Wiki](https://github.com/HiroYokoyama/python_molecular_editor/wiki)を参照してください。[Docker版](https://github.com/HiroYokoyama/python_molecular_editor_docker)も利用可能です。[Windows向けインストーラー](https://hiroyokoyama.github.io/python_molecular_editor/windows-installer/windows_installer-jp)も使用できます。
|
|
883
883
|
|
|
884
884
|
#### 必要ライブラリ
|
|
885
885
|
|
|
@@ -12,7 +12,7 @@ moleditpy_linux/modules/bond_item.py,sha256=eVkEeKvM4igYI67DYxpey3FllqDyt_iWDo4V
|
|
|
12
12
|
moleditpy_linux/modules/bond_length_dialog.py,sha256=k5x_DhK9Q8CSwouKhEo_kLRRdaYHDaK84KDNmuDNLvY,14868
|
|
13
13
|
moleditpy_linux/modules/calculation_worker.py,sha256=KiGQY7i-QCQofEoE0r65KoQgpEGFcbhmxWv6egfkUdc,42324
|
|
14
14
|
moleditpy_linux/modules/color_settings_dialog.py,sha256=Ow44BhCOLo0AFb6klO001k6B4drOgKX9DeNBQhZLp5o,15474
|
|
15
|
-
moleditpy_linux/modules/constants.py,sha256=
|
|
15
|
+
moleditpy_linux/modules/constants.py,sha256=ZCF3IMNj8vWg3vJ7tMXLqVddvhpk0-wlUQWyMIaUEd0,4702
|
|
16
16
|
moleditpy_linux/modules/constrained_optimization_dialog.py,sha256=IEdNVhFoNSEMeA5ABpUH9Q88-YzDXFloQM2gwnPwnHY,30150
|
|
17
17
|
moleditpy_linux/modules/custom_interactor_style.py,sha256=NjsXE2a43IDNEanZBlcG9eR4ZIERT1MsQC6lbfesapQ,38453
|
|
18
18
|
moleditpy_linux/modules/custom_qt_interactor.py,sha256=MFaTuDh-FPeFBS4303CqxsxmsOIOW4QXUz6USwI8PHQ,2451
|
|
@@ -25,7 +25,7 @@ moleditpy_linux/modules/main_window_dialog_manager.py,sha256=S1ROCWqzB2uVSKHY4o5
|
|
|
25
25
|
moleditpy_linux/modules/main_window_edit_3d.py,sha256=uY203adPg3CLyAdbG2NCThG2Am0WduzPDan9rXAlc14,19841
|
|
26
26
|
moleditpy_linux/modules/main_window_edit_actions.py,sha256=lUFxNFTUQzeXN8CNlb4_4S9j4M1EEq8kpJmh9dCzM3M,64818
|
|
27
27
|
moleditpy_linux/modules/main_window_export.py,sha256=e0HA_jeaokIOBunQqGxUn5QKdniCmE8GrsE1Igy6zm8,38351
|
|
28
|
-
moleditpy_linux/modules/main_window_main_init.py,sha256=
|
|
28
|
+
moleditpy_linux/modules/main_window_main_init.py,sha256=zEaEME6AnOjHGoXnVoOgEvBgxE2NYmMH78J-hw0Qt1I,79806
|
|
29
29
|
moleditpy_linux/modules/main_window_molecular_parsers.py,sha256=Ex4-urYsKf6PyHp4XToOhgXzuYWa_n7q--QmHci4OCU,48401
|
|
30
30
|
moleditpy_linux/modules/main_window_project_io.py,sha256=q1vEmWQDqla32HVkmk8-j0OY9ut5TI5NJ4ikahewkEo,17259
|
|
31
31
|
moleditpy_linux/modules/main_window_string_importers.py,sha256=mQVDv2Dj4MwnPgMRe2IqdAAKnB_quE6QfYeAgCjfv28,10892
|
|
@@ -38,7 +38,7 @@ moleditpy_linux/modules/molecule_scene.py,sha256=c5GNL7LrzerXYWshmpY_6Rg-2cBlF7x
|
|
|
38
38
|
moleditpy_linux/modules/move_group_dialog.py,sha256=65HVXTJSaQ9lp03XFhI1l7OzUsXmH_aqd8OgwjpjfGg,27174
|
|
39
39
|
moleditpy_linux/modules/periodic_table_dialog.py,sha256=ItEZUts1XCietz9paY-spvbzxh6SXak3GnikwqkHZCw,4006
|
|
40
40
|
moleditpy_linux/modules/planarize_dialog.py,sha256=yY8o-SxT8vGEHVWnjDTXecRv5NUaEejEsXH-836Xk8g,8681
|
|
41
|
-
moleditpy_linux/modules/plugin_manager.py,sha256=
|
|
41
|
+
moleditpy_linux/modules/plugin_manager.py,sha256=2GwuJurN09VVmPYjnr5GhrBf4JSxqLFVeVbqoKo5T24,5570
|
|
42
42
|
moleditpy_linux/modules/settings_dialog.py,sha256=Nr7yE8UmYRi3VObWvRlrnv0DnjSjmYXbvqryZ02O12k,65348
|
|
43
43
|
moleditpy_linux/modules/template_preview_item.py,sha256=Ks3C35pYFuLT5G4fsloI7ljE6ESXoYyGvLkM22qcmt0,6673
|
|
44
44
|
moleditpy_linux/modules/template_preview_view.py,sha256=4OCHZDO51BvJpKdfrBWJ4_4WfLfFSKxsVIyf7I-Kj2E,3350
|
|
@@ -48,9 +48,9 @@ moleditpy_linux/modules/zoomable_view.py,sha256=hjwljui13QpvjvxJHY4Evot4jMQvxRBQ
|
|
|
48
48
|
moleditpy_linux/modules/assets/icon.icns,sha256=wD5R6-Vw7K662tVKhu2E1ImN0oUuyAP4youesEQsn9c,139863
|
|
49
49
|
moleditpy_linux/modules/assets/icon.ico,sha256=RfgFcx7-dHY_2STdsOQCQziY5SNhDr3gPnjO6jzEDPI,147975
|
|
50
50
|
moleditpy_linux/modules/assets/icon.png,sha256=kCFN1WacYIdy0GN6SFEbNA00ef39pCczBnFdkkBI8Bs,147110
|
|
51
|
-
moleditpy_linux-2.
|
|
52
|
-
moleditpy_linux-2.
|
|
53
|
-
moleditpy_linux-2.
|
|
54
|
-
moleditpy_linux-2.
|
|
55
|
-
moleditpy_linux-2.
|
|
56
|
-
moleditpy_linux-2.
|
|
51
|
+
moleditpy_linux-2.1.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
52
|
+
moleditpy_linux-2.1.1.dist-info/METADATA,sha256=9Usa04e1Bm9OT4_sxfMltQGSiTlNJlKGiLbhMEW3Ae8,59354
|
|
53
|
+
moleditpy_linux-2.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
54
|
+
moleditpy_linux-2.1.1.dist-info/entry_points.txt,sha256=-OzipSi__yVwlimNtu3eiRP5t5UMg55Cs0udyhXYiyw,60
|
|
55
|
+
moleditpy_linux-2.1.1.dist-info/top_level.txt,sha256=qyqe-hDYL6CXyin9E5Me5rVl3PG84VqiOjf9bQvfJLs,16
|
|
56
|
+
moleditpy_linux-2.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|