MoleditPy 2.2.0__py3-none-any.whl → 2.2.0a0__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.
@@ -16,7 +16,7 @@ from PyQt6.QtGui import QFont, QColor
16
16
  from rdkit import Chem
17
17
 
18
18
  #Version
19
- VERSION = '2.2.0'
19
+ VERSION = '2.2.0a0'
20
20
 
21
21
  ATOM_RADIUS = 18
22
22
  BOND_OFFSET = 3.5
@@ -32,7 +32,7 @@ except Exception:
32
32
  # PyQt6 Modules
33
33
  from PyQt6.QtWidgets import (
34
34
  QApplication, QWidget, QVBoxLayout, QHBoxLayout,
35
- QPushButton, QSplitter, QToolBar, QSizePolicy, QLabel, QToolButton, QMenu, QMessageBox, QFileDialog
35
+ QPushButton, QSplitter, QToolBar, QSizePolicy, QLabel, QToolButton, QMenu, QMessageBox
36
36
  )
37
37
 
38
38
  from PyQt6.QtGui import (
@@ -1755,32 +1755,10 @@ class MainWindowMainInit(object):
1755
1755
  """Discovers plugins and updates the plugin menu actions."""
1756
1756
  if not self.plugin_manager:
1757
1757
  return
1758
-
1759
- PLUGIN_ACTION_TAG = "plugin_managed"
1760
-
1761
- # Helper to clear tagged actions from a menu
1762
- def clear_plugin_actions(menu):
1763
- if not menu: return
1764
- for act in list(menu.actions()):
1765
- if act.data() == PLUGIN_ACTION_TAG:
1766
- menu.removeAction(act)
1767
- # Recurse into submenus to clean deep actions
1768
- elif act.menu():
1769
- clear_plugin_actions(act.menu())
1770
1758
 
1771
- # Clear existing plugin actions from main Plugin menu
1759
+ # Clear existing plugin actions
1772
1760
  plugin_menu.clear()
1773
1761
 
1774
- # Clear tagged actions from ALL top-level menus in the Menu Bar
1775
- # This ensures we catch actions added to standard menus (File, Edit) OR custom menus
1776
- for top_action in self.menuBar().actions():
1777
- if top_action.menu():
1778
- clear_plugin_actions(top_action.menu())
1779
-
1780
- # Clear Export menu (if button exists)
1781
- if hasattr(self, 'export_button') and self.export_button.menu():
1782
- clear_plugin_actions(self.export_button.menu())
1783
-
1784
1762
  # Only keep the Manager action
1785
1763
  manage_plugins_action = QAction("Plugin Manager...", self)
1786
1764
  def show_plugin_manager():
@@ -1836,9 +1814,9 @@ class MainWindowMainInit(object):
1836
1814
  action_text = text if text else parts[-1]
1837
1815
  action = QAction(action_text, self)
1838
1816
  action.triggered.connect(callback)
1839
- action.setData(PLUGIN_ACTION_TAG) # TAG THE ACTION
1840
1817
  current_menu.addAction(action)
1841
1818
 
1819
+ # 2. Add Toolbar Buttons (New System)
1842
1820
  # 2. Add Toolbar Buttons (New System)
1843
1821
  # Use dedicated plugin toolbar
1844
1822
  if hasattr(self, 'plugin_toolbar'):
@@ -1862,12 +1840,14 @@ class MainWindowMainInit(object):
1862
1840
  self.plugin_toolbar.hide()
1863
1841
 
1864
1842
  # 3. Legacy Menu Building (Folder based)
1843
+
1865
1844
  if not plugins:
1866
1845
  no_plugin_action = QAction("(No plugins found)", self)
1867
1846
  no_plugin_action.setEnabled(False)
1868
1847
  plugin_menu.addAction(no_plugin_action)
1869
1848
  else:
1870
1849
  # Sort plugins: directories first (to create menus), then alphabetical by name
1850
+ # Actually simple sort by rel_folder, name is fine
1871
1851
  plugins.sort(key=lambda x: (x.get('rel_folder', ''), x['name']))
1872
1852
 
1873
1853
  # Dictionary to keep track of created submenus: path -> QMenu
@@ -1875,6 +1855,7 @@ class MainWindowMainInit(object):
1875
1855
 
1876
1856
  for p in plugins:
1877
1857
  # Only add legacy plugins (with 'run' function) to the generic Plugins menu.
1858
+ # New plugins (with 'initialize') should register their own menu actions if needed.
1878
1859
  if hasattr(p['module'], 'run'):
1879
1860
  rel_folder = p.get('rel_folder', '')
1880
1861
  # Get or create the parent menu for this plugin
@@ -1901,83 +1882,114 @@ class MainWindowMainInit(object):
1901
1882
  parent_menu.addAction(action)
1902
1883
 
1903
1884
  # 4. Integrate Export Actions into Export Button and Menu
1904
- # 4. Integrate Export Actions into Export Button AND Main File->Export Menu
1905
1885
  if self.plugin_manager.export_actions:
1906
- # Find Main File -> Export menu
1907
- main_export_menu = None
1908
- for top_action in self.menuBar().actions():
1909
- if top_action.text().replace('&', '') == 'File' and top_action.menu():
1910
- for sub_action in top_action.menu().actions():
1911
- if sub_action.text().replace('&', '') == 'Export' and sub_action.menu():
1912
- main_export_menu = sub_action.menu()
1913
- break
1914
- if main_export_menu: break
1915
-
1916
- # List of menus to populate
1917
- target_menus = []
1886
+ # Add separator if we have custom exports (and haven't added it yet for this session/update)
1887
+ # Since update_plugin_menu clears the dynamic plugin actions but NOT the export menu (which is on a button),
1888
+ # we need to be careful not to duplicate.
1889
+ # Ideally, we should clear custom actions from the export menu first.
1890
+ # For simplicity, we'll just check existence.
1891
+
1918
1892
  if hasattr(self, 'export_button') and self.export_button.menu():
1919
- target_menus.append(self.export_button.menu())
1920
- if main_export_menu:
1921
- target_menus.append(main_export_menu)
1922
-
1923
- for menu in target_menus:
1924
- # Add separator
1925
- sep = menu.addSeparator()
1926
- sep.setData(PLUGIN_ACTION_TAG)
1927
-
1928
- for exp in self.plugin_manager.export_actions:
1929
- label = exp['label']
1930
- callback = exp['callback']
1931
-
1932
- a = QAction(label, self)
1933
- a.triggered.connect(callback)
1934
- a.setData(PLUGIN_ACTION_TAG)
1935
- menu.addAction(a)
1893
+ # Naive approach: check if separator/actions exist.
1894
+ # Better approach: Add them to a specific section or manage them explicitly.
1895
+ # Here we just append if not present.
1896
+
1897
+ # Check if we need a separator (if we have built-in actions)
1898
+ if self.export_button.menu().actions():
1899
+ has_sep = False
1900
+ for a in self.export_button.menu().actions():
1901
+ if a.isSeparator():
1902
+ has_sep = True
1903
+ # Get or create the parent menu for this plugin
1904
+ # For folder based hierarchy only?
1905
+ # ... (Refer to existing code for menu building, skipped here for brevity)
1906
+ pass
1936
1907
 
1937
1908
  # 5. Integrate File Openers into Import Menu
1938
1909
  if hasattr(self, 'import_menu') and self.plugin_manager.file_openers:
1939
- # Add separator
1940
- sep = self.import_menu.addSeparator()
1941
- sep.setData(PLUGIN_ACTION_TAG)
1942
-
1910
+ # Add a separator if plugins are present
1911
+ has_plugins = len(self.plugin_manager.file_openers) > 0
1912
+ if has_plugins:
1913
+ self.import_menu.addSeparator()
1914
+
1943
1915
  for ext, info in self.plugin_manager.file_openers.items():
1916
+ # ext e.g. .xyz
1917
+ # info = {'plugin': name, 'callback': cb}
1944
1918
  label = f"Import {ext} ({info.get('plugin', 'Plugin')})..."
1945
1919
 
1946
- def make_cb(callback):
1947
- def _cb():
1948
- fpath, _ = QFileDialog.getOpenFileName(
1949
- self, f"Import {ext}", "",
1950
- f"{info.get('plugin', 'Plugin')} File (*{ext});;All Files (*)"
1951
- )
1952
- if fpath:
1953
- callback(fpath)
1954
- self.current_file_path = fpath
1955
- self.update_window_title()
1956
- return _cb
1957
-
1958
- a = QAction(label, self)
1959
- a.triggered.connect(make_cb(info['callback']))
1960
- a.setData(PLUGIN_ACTION_TAG)
1961
- self.import_menu.addAction(a)
1920
+ # duplicate check
1921
+ exists = False
1922
+ for act in self.import_menu.actions():
1923
+ if act.text() == label:
1924
+ exists = True
1925
+ break
1926
+
1927
+ if not exists:
1928
+ def make_cb(callback):
1929
+ def _cb():
1930
+ # Standard file dialog to pick file, then callback
1931
+ fpath, _ = QFileDialog.getOpenFileName(
1932
+ self, f"Import {ext}", "",
1933
+ f"{info.get('plugin', 'Plugin')} File (*{ext});;All Files (*)"
1934
+ )
1935
+ if fpath:
1936
+ callback(fpath)
1937
+ self.current_file_path = fpath # Update current file path?
1938
+ self.update_window_title()
1939
+ return _cb
1940
+
1941
+ a = QAction(label, self)
1942
+ a.triggered.connect(make_cb(info['callback']))
1943
+ self.import_menu.addAction(a)
1962
1944
 
1963
1945
  # 6. Integrate Analysis Tools into Analysis Menu
1964
- # Find Analysis menu again as it might not be defined if cleanup block was generic
1965
- analysis_menu = None
1966
- for action in self.menuBar().actions():
1967
- if action.text().replace('&', '') == 'Analysis':
1968
- analysis_menu = action.menu()
1969
- break
1970
-
1971
- if analysis_menu and self.plugin_manager.analysis_tools:
1972
- # Add separator
1973
- sep = analysis_menu.addSeparator()
1974
- sep.setData(PLUGIN_ACTION_TAG)
1946
+ if hasattr(self, 'analysis_action') and self.plugin_manager.analysis_tools:
1947
+ # Determine parent menu (Analysis)
1948
+ # self.analysis_action is just an action, we need the menu it belongs to?
1949
+ # Or did we stash the analysis_menu?
1950
+ # Looking at init, analysis_menu wasn't stored as self.analysis_menu, but we can find it via menuBar.
1975
1951
 
1976
- for tool in self.plugin_manager.analysis_tools:
1977
- label = f"{tool['label']} ({tool.get('plugin', 'Plugin')})"
1978
-
1979
- a = QAction(label, self)
1980
- a.triggered.connect(tool['callback'])
1981
- a.setData(PLUGIN_ACTION_TAG)
1982
- analysis_menu.addAction(a)
1952
+ # Let's find "Analysis" menu
1953
+ analysis_menu = None
1954
+ for action in self.menuBar().actions():
1955
+ if action.text().replace('&', '') == 'Analysis':
1956
+ analysis_menu = action.menu()
1957
+ break
1958
+
1959
+ if analysis_menu:
1960
+ # Add separator if we have plugins
1961
+ if self.plugin_manager.analysis_tools:
1962
+ analysis_menu.addSeparator()
1963
+
1964
+ for tool in self.plugin_manager.analysis_tools:
1965
+ label = f"{tool['label']} ({tool.get('plugin', 'Plugin')})"
1966
+ # duplicate check
1967
+ exists = False
1968
+ for act in analysis_menu.actions():
1969
+ if act.text() == label:
1970
+ exists = True
1971
+ break
1972
+ if not exists:
1973
+ a = QAction(label, self)
1974
+ a.triggered.connect(tool['callback'])
1975
+ analysis_menu.addAction(a)
1976
+
1977
+ # 7. Integrate Export Actions (Continued)
1978
+ if self.plugin_manager.export_actions:
1979
+ for exp in self.plugin_manager.export_actions:
1980
+ label = exp['label']
1981
+ callback = exp['callback']
1982
+
1983
+ exists = False
1984
+ for act in self.export_button.menu().actions():
1985
+ if act.text() == label:
1986
+ exists = True
1987
+ break
1988
+
1989
+ if not exists:
1990
+ a = QAction(label, self)
1991
+ a.triggered.connect(callback)
1992
+ self.export_button.menu().addAction(a)
1993
+
1994
+ # 5. Integrate File Openers (Implicitly handled during file load) uses PluginManager directly
1983
1995
 
@@ -298,7 +298,7 @@ class MainWindowUiManager(object):
298
298
 
299
299
 
300
300
  def dragEnterEvent(self, event):
301
- """ウィンドウ全体でサポートされているファイルのドラッグを受け入れる"""
301
+ """ウィンドウ全体で .pmeraw、.pmeprj、.mol、.sdf、.xyz ファイルのドラッグを受け入れる"""
302
302
  # Accept if any dragged local file has a supported extension
303
303
  if event.mimeData().hasUrls():
304
304
  urls = event.mimeData().urls()
@@ -306,28 +306,9 @@ class MainWindowUiManager(object):
306
306
  try:
307
307
  if url.isLocalFile():
308
308
  file_path = url.toLocalFile()
309
- file_lower = file_path.lower()
310
-
311
- # Built-in extensions
312
- if file_lower.endswith(('.pmeraw', '.pmeprj', '.mol', '.sdf', '.xyz')):
309
+ if file_path.lower().endswith(('.pmeraw', '.pmeprj', '.mol', '.sdf', '.xyz')):
313
310
  event.acceptProposedAction()
314
311
  return
315
-
316
- # Plugin-registered file openers
317
- if self.plugin_manager and hasattr(self.plugin_manager, 'file_openers'):
318
- for ext in self.plugin_manager.file_openers.keys():
319
- if file_lower.endswith(ext):
320
- event.acceptProposedAction()
321
- return
322
-
323
- # Plugin drop handlers (accept more liberally for custom logic)
324
- # A plugin drop handler might handle it, so accept
325
- if self.plugin_manager and hasattr(self.plugin_manager, 'drop_handlers'):
326
- if len(self.plugin_manager.drop_handlers) > 0:
327
- # Accept any file if drop handlers are registered
328
- # They will check the file type in dropEvent
329
- event.acceptProposedAction()
330
- return
331
312
  except Exception:
332
313
  continue
333
314
  event.ignore()
@@ -159,7 +159,16 @@ class PluginContext:
159
159
  self._manager.register_3d_style(self._plugin_name, style_name, callback)
160
160
 
161
161
 
162
-
162
+ def add_panel_button(self, text: str, callback: Callable, panel: str = "right"):
163
+ """
164
+ Add a button to the bottom control panel.
165
+
166
+ Args:
167
+ text: Label on the button.
168
+ callback: Function to call on click.
169
+ panel: "left" (2D Editor) or "right" (3D Viewer). Default "right".
170
+ """
171
+ self._manager.register_panel_button(self._plugin_name, text, callback, panel)
163
172
 
164
173
 
165
174
 
@@ -40,6 +40,7 @@ class PluginManager:
40
40
  # Registries for actions
41
41
  self.menu_actions = [] # List of (plugin_name, path, callback, text, icon, shortcut)
42
42
  self.toolbar_actions = []
43
+ self.context_menu_3d_actions = []
43
44
  self.drop_handlers = [] # List of (priority, plugin_name, callback)
44
45
 
45
46
  # Extended Registries (Added to prevent lazy initialization "monkey patching")
@@ -48,6 +49,7 @@ class PluginManager:
48
49
  self.file_openers = {}
49
50
  self.analysis_tools = []
50
51
  self.save_handlers = {}
52
+ self.save_handlers = {}
51
53
  self.load_handlers = {}
52
54
  self.custom_3d_styles = {} # style_name -> {'plugin': name, 'callback': func}
53
55
 
@@ -98,15 +100,6 @@ class PluginManager:
98
100
  self.toolbar_actions = []
99
101
  self.drop_handlers = []
100
102
 
101
- # Clear extended registries
102
- self.export_actions = []
103
- self.optimization_methods = {}
104
- self.file_openers = {}
105
- self.analysis_tools = []
106
- self.save_handlers = {}
107
- self.load_handlers = {}
108
- self.custom_3d_styles = {}
109
-
110
103
  if not os.path.exists(self.plugin_dir):
111
104
  return []
112
105
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoleditPy
3
- Version: 2.2.0
3
+ Version: 2.2.0a0
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
@@ -12,7 +12,7 @@ moleditpy/modules/bond_item.py,sha256=eVkEeKvM4igYI67DYxpey3FllqDyt_iWDo4VPYMhaP
12
12
  moleditpy/modules/bond_length_dialog.py,sha256=k5x_DhK9Q8CSwouKhEo_kLRRdaYHDaK84KDNmuDNLvY,14868
13
13
  moleditpy/modules/calculation_worker.py,sha256=KiGQY7i-QCQofEoE0r65KoQgpEGFcbhmxWv6egfkUdc,42324
14
14
  moleditpy/modules/color_settings_dialog.py,sha256=Ow44BhCOLo0AFb6klO001k6B4drOgKX9DeNBQhZLp5o,15474
15
- moleditpy/modules/constants.py,sha256=hdfz_yUW2nYenApAz_N45ia1Qo8bZKhuYC0lw9WOozM,4702
15
+ moleditpy/modules/constants.py,sha256=6HptVW41_PUUuwc0jeOi5L0fRM7EARkE__J18Cmv-RM,4704
16
16
  moleditpy/modules/constrained_optimization_dialog.py,sha256=IEdNVhFoNSEMeA5ABpUH9Q88-YzDXFloQM2gwnPwnHY,30150
17
17
  moleditpy/modules/custom_interactor_style.py,sha256=NjsXE2a43IDNEanZBlcG9eR4ZIERT1MsQC6lbfesapQ,38453
18
18
  moleditpy/modules/custom_qt_interactor.py,sha256=MFaTuDh-FPeFBS4303CqxsxmsOIOW4QXUz6USwI8PHQ,2451
@@ -25,11 +25,11 @@ moleditpy/modules/main_window_dialog_manager.py,sha256=S1ROCWqzB2uVSKHY4o5CbTtJA
25
25
  moleditpy/modules/main_window_edit_3d.py,sha256=uY203adPg3CLyAdbG2NCThG2Am0WduzPDan9rXAlc14,19841
26
26
  moleditpy/modules/main_window_edit_actions.py,sha256=lUFxNFTUQzeXN8CNlb4_4S9j4M1EEq8kpJmh9dCzM3M,64818
27
27
  moleditpy/modules/main_window_export.py,sha256=e0HA_jeaokIOBunQqGxUn5QKdniCmE8GrsE1Igy6zm8,38351
28
- moleditpy/modules/main_window_main_init.py,sha256=AZb2GZmvUYsVBhV2c54FEoWmFXRPkdSMlsshKraOGPs,89315
28
+ moleditpy/modules/main_window_main_init.py,sha256=sRDrzGCenF2e0bb_mSVwf84nduqmuR6jGzzY7Sp9q6c,90311
29
29
  moleditpy/modules/main_window_molecular_parsers.py,sha256=Ex4-urYsKf6PyHp4XToOhgXzuYWa_n7q--QmHci4OCU,48401
30
30
  moleditpy/modules/main_window_project_io.py,sha256=q1vEmWQDqla32HVkmk8-j0OY9ut5TI5NJ4ikahewkEo,17259
31
31
  moleditpy/modules/main_window_string_importers.py,sha256=mQVDv2Dj4MwnPgMRe2IqdAAKnB_quE6QfYeAgCjfv28,10892
32
- moleditpy/modules/main_window_ui_manager.py,sha256=HofI6T9EvcSSzPbsdPqkYEEDoB6Hui1Uj2Ll-wwczGA,24016
32
+ moleditpy/modules/main_window_ui_manager.py,sha256=dqnBzvYZdE5Da6x4IAeGYSgwHp4EUO13THudf2hUePo,22843
33
33
  moleditpy/modules/main_window_view_3d.py,sha256=TKRerktpCTYxX9HU-dSOnIhx4OyZaVrRYj4pEOUXmGc,74088
34
34
  moleditpy/modules/main_window_view_loaders.py,sha256=Dbdgv4TY_ZkX8Qyaevwr-mBJYJ59CBzRTEks-U1FiGw,14462
35
35
  moleditpy/modules/mirror_dialog.py,sha256=c3v4qY6R4FAljzk4EPaDjL9ZdZMjLQSFLqDMXz2fBUk,4696
@@ -38,8 +38,8 @@ moleditpy/modules/molecule_scene.py,sha256=khdt7h9Mk_D1cMbYeHGtq7P9aFXo0xG-hcShU
38
38
  moleditpy/modules/move_group_dialog.py,sha256=65HVXTJSaQ9lp03XFhI1l7OzUsXmH_aqd8OgwjpjfGg,27174
39
39
  moleditpy/modules/periodic_table_dialog.py,sha256=ItEZUts1XCietz9paY-spvbzxh6SXak3GnikwqkHZCw,4006
40
40
  moleditpy/modules/planarize_dialog.py,sha256=yY8o-SxT8vGEHVWnjDTXecRv5NUaEejEsXH-836Xk8g,8681
41
- moleditpy/modules/plugin_interface.py,sha256=W6Hw1OLqMkcg8XU-S347v2sDBMEoo6iiCSbmL6MjZrA,7639
42
- moleditpy/modules/plugin_manager.py,sha256=cxbqIE7Rb_KeBd-cG1vF2ySY2qNx8IJVRXjVPyQMFDc,13457
41
+ moleditpy/modules/plugin_interface.py,sha256=54zMHkjf9TCyXyAqYeYvnG-R4mWhTaSZ8oIQt3lHqvQ,8082
42
+ moleditpy/modules/plugin_manager.py,sha256=bhQ5Biwug1M1dBFE8l0onH6OKYdFf4tBMwyuZKoOaZI,13243
43
43
  moleditpy/modules/plugin_manager_window.py,sha256=m2lJ-UltwoXQ2SYA1im6Q0v-5SfqWL2HcOBCTzUmiBw,9963
44
44
  moleditpy/modules/settings_dialog.py,sha256=Nr7yE8UmYRi3VObWvRlrnv0DnjSjmYXbvqryZ02O12k,65348
45
45
  moleditpy/modules/template_preview_item.py,sha256=djdq3tz73d_fJGOvai3E-V9Hk9q9ZW7skx7BV59mooA,6556
@@ -50,9 +50,9 @@ moleditpy/modules/zoomable_view.py,sha256=hjwljui13QpvjvxJHY4Evot4jMQvxRBQUNH5HU
50
50
  moleditpy/modules/assets/icon.icns,sha256=wD5R6-Vw7K662tVKhu2E1ImN0oUuyAP4youesEQsn9c,139863
51
51
  moleditpy/modules/assets/icon.ico,sha256=RfgFcx7-dHY_2STdsOQCQziY5SNhDr3gPnjO6jzEDPI,147975
52
52
  moleditpy/modules/assets/icon.png,sha256=kCFN1WacYIdy0GN6SFEbNA00ef39pCczBnFdkkBI8Bs,147110
53
- moleditpy-2.2.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
54
- moleditpy-2.2.0.dist-info/METADATA,sha256=H70VL50a9I7mF8SFXSCHD5No6-Y9j4g931eYke8RzP8,59275
55
- moleditpy-2.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
56
- moleditpy-2.2.0.dist-info/entry_points.txt,sha256=yH1h9JjALhok1foXT3-hYrC4ufoZt8b7oiBcsdnGNNM,54
57
- moleditpy-2.2.0.dist-info/top_level.txt,sha256=ARICrS4ihlPXqywlKl6o-oJa3Qz3gZRWu_VZsQ3_c44,10
58
- moleditpy-2.2.0.dist-info/RECORD,,
53
+ moleditpy-2.2.0a0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
54
+ moleditpy-2.2.0a0.dist-info/METADATA,sha256=3GgjhoFXb5wzlOyGD_uu-BxSbALiAUKDI7jQcUtJLEk,59277
55
+ moleditpy-2.2.0a0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
56
+ moleditpy-2.2.0a0.dist-info/entry_points.txt,sha256=yH1h9JjALhok1foXT3-hYrC4ufoZt8b7oiBcsdnGNNM,54
57
+ moleditpy-2.2.0a0.dist-info/top_level.txt,sha256=ARICrS4ihlPXqywlKl6o-oJa3Qz3gZRWu_VZsQ3_c44,10
58
+ moleditpy-2.2.0a0.dist-info/RECORD,,