moleditpy 1.8.2__tar.gz → 1.8.4__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moleditpy
3
- Version: 1.8.2
3
+ Version: 1.8.4
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
  Project-URL: Homepage, https://github.com/HiroYokoyama/python_molecular_editor
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "moleditpy"
7
7
 
8
- version = "1.8.2"
8
+ version = "1.8.4"
9
9
 
10
10
  authors = [
11
11
  { name="HiroYokoyama", email="titech.yoko.hiro@gmail.com" },
@@ -11,7 +11,7 @@ DOI 10.5281/zenodo.17268532
11
11
  """
12
12
 
13
13
  #Version
14
- VERSION = '1.8.2'
14
+ VERSION = '1.8.4'
15
15
 
16
16
  print("-----------------------------------------------------")
17
17
  print("MoleditPy — A Python-based molecular editing software")
@@ -245,10 +245,10 @@ class TranslationDialog(Dialog3DPickingMixin, QDialog):
245
245
  self.apply_button.clicked.connect(self.apply_translation)
246
246
  self.apply_button.setEnabled(False)
247
247
  button_layout.addWidget(self.apply_button)
248
-
249
- cancel_button = QPushButton("Cancel")
250
- cancel_button.clicked.connect(self.reject)
251
- button_layout.addWidget(cancel_button)
248
+
249
+ close_button = QPushButton("Close")
250
+ close_button.clicked.connect(self.reject)
251
+ button_layout.addWidget(close_button)
252
252
 
253
253
  layout.addLayout(button_layout)
254
254
 
@@ -337,8 +337,6 @@ class TranslationDialog(Dialog3DPickingMixin, QDialog):
337
337
  # キラルラベルを更新
338
338
  self.main_window.update_chiral_labels()
339
339
 
340
- self.accept()
341
-
342
340
  except Exception as e:
343
341
  QMessageBox.critical(self, "Error", f"Failed to apply translation: {str(e)}")
344
342
 
@@ -680,10 +678,10 @@ class SymmetrizeDialog(QDialog):
680
678
  self.apply_button.clicked.connect(self.apply_symmetrization)
681
679
  self.apply_button.setDefault(True)
682
680
  button_layout.addWidget(self.apply_button)
683
-
684
- cancel_button = QPushButton("Cancel")
685
- cancel_button.clicked.connect(self.reject)
686
- button_layout.addWidget(cancel_button)
681
+
682
+ close_button = QPushButton("Close")
683
+ close_button.clicked.connect(self.reject)
684
+ button_layout.addWidget(close_button)
687
685
 
688
686
  layout.addLayout(button_layout)
689
687
 
@@ -813,8 +811,6 @@ class SymmetrizeDialog(QDialog):
813
811
  f"Molecular structure has been symmetrized according to {point_group['name']} point group."
814
812
  )
815
813
 
816
- self.accept()
817
-
818
814
  except Exception as e:
819
815
  QMessageBox.critical(self, "Error", f"Failed to apply symmetrization: {str(e)}")
820
816
  print(f"Symmetrization error: {e}")
@@ -1866,12 +1862,12 @@ class MirrorDialog(QDialog):
1866
1862
 
1867
1863
  apply_button = QPushButton("Apply Mirror")
1868
1864
  apply_button.clicked.connect(self.apply_mirror)
1869
-
1870
- cancel_button = QPushButton("Cancel")
1871
- cancel_button.clicked.connect(self.reject)
1872
-
1865
+
1866
+ close_button = QPushButton("Close")
1867
+ close_button.clicked.connect(self.reject)
1868
+
1873
1869
  button_layout.addWidget(apply_button)
1874
- button_layout.addWidget(cancel_button)
1870
+ button_layout.addWidget(close_button)
1875
1871
 
1876
1872
  layout.addLayout(button_layout)
1877
1873
 
@@ -1924,8 +1920,6 @@ class MirrorDialog(QDialog):
1924
1920
  plane_names = ["XY", "XZ", "YZ"]
1925
1921
  self.main_window.statusBar().showMessage(f"Molecule mirrored across {plane_names[plane_id]} plane.")
1926
1922
 
1927
- self.accept()
1928
-
1929
1923
  except Exception as e:
1930
1924
  QMessageBox.critical(self, "Error", f"Failed to apply mirror transformation: {str(e)}")
1931
1925
 
@@ -1977,10 +1971,10 @@ class PlanarizationDialog(Dialog3DPickingMixin, QDialog):
1977
1971
  self.apply_button.clicked.connect(self.apply_planarization)
1978
1972
  self.apply_button.setEnabled(False)
1979
1973
  button_layout.addWidget(self.apply_button)
1980
-
1981
- cancel_button = QPushButton("Cancel")
1982
- cancel_button.clicked.connect(self.reject)
1983
- button_layout.addWidget(cancel_button)
1974
+
1975
+ close_button = QPushButton("Close")
1976
+ close_button.clicked.connect(self.reject)
1977
+ button_layout.addWidget(close_button)
1984
1978
 
1985
1979
  layout.addLayout(button_layout)
1986
1980
 
@@ -2147,8 +2141,6 @@ class PlanarizationDialog(Dialog3DPickingMixin, QDialog):
2147
2141
  # キラルラベルを更新
2148
2142
  self.main_window.update_chiral_labels()
2149
2143
 
2150
- self.accept()
2151
-
2152
2144
  except Exception as e:
2153
2145
  QMessageBox.critical(self, "Error", f"Failed to apply planarization: {str(e)}")
2154
2146
 
@@ -2221,9 +2213,9 @@ class AlignmentDialog(Dialog3DPickingMixin, QDialog):
2221
2213
  self.apply_button.setEnabled(False)
2222
2214
  button_layout.addWidget(self.apply_button)
2223
2215
 
2224
- cancel_button = QPushButton("Cancel")
2225
- cancel_button.clicked.connect(self.reject)
2226
- button_layout.addWidget(cancel_button)
2216
+ close_button = QPushButton("Close")
2217
+ close_button.clicked.connect(self.reject)
2218
+ button_layout.addWidget(close_button)
2227
2219
 
2228
2220
  layout.addLayout(button_layout)
2229
2221
 
@@ -2396,7 +2388,6 @@ class AlignmentDialog(Dialog3DPickingMixin, QDialog):
2396
2388
  self.main_window.update_chiral_labels()
2397
2389
 
2398
2390
  QMessageBox.information(self, "Success", f"Alignment to {self.axis.upper()}-axis completed.")
2399
- self.accept()
2400
2391
 
2401
2392
  except Exception as e:
2402
2393
  QMessageBox.critical(self, "Error", f"Failed to apply alignment: {str(e)}")
@@ -3315,7 +3306,6 @@ class MoleculeScene(QGraphicsScene):
3315
3306
  return needs_update
3316
3307
 
3317
3308
  def mousePressEvent(self, event):
3318
- self.clear_all_problem_flags()
3319
3309
  self.press_pos = event.scenePos()
3320
3310
  self.mouse_moved_since_press = False
3321
3311
  self.data_changed_in_event = False
@@ -7131,9 +7121,8 @@ class MainWindow(QMainWindow):
7131
7121
  self.mode_actions['select'].setChecked(True)
7132
7122
 
7133
7123
  def trigger_conversion(self):
7134
- mol = self.data.to_rdkit_mol(use_2d_stereo=False)
7135
- if not mol or mol.GetNumAtoms() == 0:
7136
- # 3Dビューと関連データをクリア
7124
+ # 2Dエディタに原子が存在しない場合は3Dビューをクリア
7125
+ if not self.data.atoms:
7137
7126
  self.plotter.clear()
7138
7127
  self.current_mol = None
7139
7128
  self.analysis_action.setEnabled(False)
@@ -7141,8 +7130,13 @@ class MainWindow(QMainWindow):
7141
7130
  self.view_2d.setFocus()
7142
7131
  return
7143
7132
 
7144
- # 化学的問題のフラグをクリア(分子が存在する場合のみ)
7145
- self.scene.clear_all_problem_flags()
7133
+ mol = self.data.to_rdkit_mol(use_2d_stereo=False)
7134
+
7135
+ # 分子オブジェクトが作成できない場合でも化学的問題をチェック
7136
+ if not mol or mol.GetNumAtoms() == 0:
7137
+ # RDKitでの変換に失敗した場合は、独自の化学的問題チェックを実行
7138
+ self.check_chemistry_problems_fallback()
7139
+ return
7146
7140
 
7147
7141
  # 原子プロパティを保存(ワーカープロセスで失われるため)
7148
7142
  self.original_atom_properties = {}
@@ -7156,6 +7150,8 @@ class MainWindow(QMainWindow):
7156
7150
 
7157
7151
  problems = Chem.DetectChemistryProblems(mol)
7158
7152
  if problems:
7153
+ # 化学的問題が見つかった場合は既存のフラグをクリアしてから新しい問題を表示
7154
+ self.scene.clear_all_problem_flags()
7159
7155
  self.statusBar().showMessage(f"Error: {len(problems)} chemistry problem(s) found.")
7160
7156
  # 既存の選択状態をクリア
7161
7157
  self.scene.clearSelection()
@@ -7175,6 +7171,9 @@ class MainWindow(QMainWindow):
7175
7171
  self.view_2d.setFocus()
7176
7172
  return
7177
7173
 
7174
+ # 化学的問題がない場合のみフラグをクリアして3D変換を実行
7175
+ self.scene.clear_all_problem_flags()
7176
+
7178
7177
  try:
7179
7178
  Chem.SanitizeMol(mol)
7180
7179
  except Exception:
@@ -7251,6 +7250,63 @@ class MainWindow(QMainWindow):
7251
7250
 
7252
7251
  self.view_2d.setFocus()
7253
7252
 
7253
+ def check_chemistry_problems_fallback(self):
7254
+ """RDKit変換が失敗した場合の化学的問題チェック(独自実装)"""
7255
+ try:
7256
+ # 既存のフラグをクリア
7257
+ self.scene.clear_all_problem_flags()
7258
+
7259
+ # 簡易的な化学的問題チェック
7260
+ problem_atoms = []
7261
+
7262
+ for atom_id, atom_data in self.data.atoms.items():
7263
+ atom_item = atom_data.get('item')
7264
+ if not atom_item:
7265
+ continue
7266
+
7267
+ symbol = atom_data['symbol']
7268
+ charge = atom_data.get('charge', 0)
7269
+
7270
+ # 結合数を計算
7271
+ bond_count = 0
7272
+ for (id1, id2), bond_data in self.data.bonds.items():
7273
+ if id1 == atom_id or id2 == atom_id:
7274
+ bond_count += bond_data.get('order', 1)
7275
+
7276
+ # 基本的な価数チェック
7277
+ is_problematic = False
7278
+ if symbol == 'C' and bond_count > 4:
7279
+ is_problematic = True
7280
+ elif symbol == 'N' and bond_count > 3 and charge == 0:
7281
+ is_problematic = True
7282
+ elif symbol == 'O' and bond_count > 2 and charge == 0:
7283
+ is_problematic = True
7284
+ elif symbol == 'H' and bond_count > 1:
7285
+ is_problematic = True
7286
+ elif symbol in ['F', 'Cl', 'Br', 'I'] and bond_count > 1 and charge == 0:
7287
+ is_problematic = True
7288
+
7289
+ if is_problematic:
7290
+ problem_atoms.append(atom_item)
7291
+
7292
+ if problem_atoms:
7293
+ # 問題のある原子に赤枠を設定
7294
+ for atom_item in problem_atoms:
7295
+ atom_item.has_problem = True
7296
+ atom_item.update()
7297
+
7298
+ self.statusBar().showMessage(f"Error: {len(problem_atoms)} chemistry problem(s) found (valence issues).")
7299
+ else:
7300
+ self.statusBar().showMessage("Error: Invalid chemical structure (RDKit conversion failed).")
7301
+
7302
+ self.scene.clearSelection()
7303
+ self.view_2d.setFocus()
7304
+
7305
+ except Exception as e:
7306
+ print(f"Error in fallback chemistry check: {e}")
7307
+ self.statusBar().showMessage("Error: Invalid chemical structure.")
7308
+ self.view_2d.setFocus()
7309
+
7254
7310
  def optimize_3d_structure(self):
7255
7311
  """現在の3D分子構造を力場で最適化する"""
7256
7312
  if not self.current_mol:
@@ -9100,9 +9156,20 @@ class MainWindow(QMainWindow):
9100
9156
 
9101
9157
  def clean_up_2d_structure(self):
9102
9158
  self.statusBar().showMessage("Optimizing 2D structure...")
9159
+
9160
+ # 最初に既存の化学的問題フラグをクリア
9161
+ self.scene.clear_all_problem_flags()
9162
+
9163
+ # 2Dエディタに原子が存在しない場合
9164
+ if not self.data.atoms:
9165
+ self.statusBar().showMessage("Error: No atoms to optimize.")
9166
+ return
9167
+
9103
9168
  mol = self.data.to_rdkit_mol()
9104
9169
  if mol is None or mol.GetNumAtoms() == 0:
9105
- self.statusBar().showMessage("Error: No atoms to optimize."); return
9170
+ # RDKit変換が失敗した場合は化学的問題をチェック
9171
+ self.check_chemistry_problems_fallback()
9172
+ return
9106
9173
 
9107
9174
  try:
9108
9175
  # 安定版:原子IDとRDKit座標の確実なマッピング
@@ -11161,9 +11228,9 @@ class BondLengthDialog(Dialog3DPickingMixin, QDialog):
11161
11228
  self.apply_button.setEnabled(False)
11162
11229
  button_layout.addWidget(self.apply_button)
11163
11230
 
11164
- cancel_button = QPushButton("Cancel")
11165
- cancel_button.clicked.connect(self.reject)
11166
- button_layout.addWidget(cancel_button)
11231
+ close_button = QPushButton("Close")
11232
+ close_button.clicked.connect(self.reject)
11233
+ button_layout.addWidget(close_button)
11167
11234
 
11168
11235
  layout.addLayout(button_layout)
11169
11236
 
@@ -11345,8 +11412,6 @@ class BondLengthDialog(Dialog3DPickingMixin, QDialog):
11345
11412
 
11346
11413
  # キラルラベルを更新
11347
11414
  self.main_window.update_chiral_labels()
11348
-
11349
- self.accept()
11350
11415
 
11351
11416
  def adjust_bond_length(self, new_distance):
11352
11417
  """結合長を調整"""
@@ -11512,9 +11577,9 @@ class AngleDialog(Dialog3DPickingMixin, QDialog):
11512
11577
  self.apply_button.setEnabled(False)
11513
11578
  button_layout.addWidget(self.apply_button)
11514
11579
 
11515
- cancel_button = QPushButton("Cancel")
11516
- cancel_button.clicked.connect(self.reject)
11517
- button_layout.addWidget(cancel_button)
11580
+ close_button = QPushButton("Close")
11581
+ close_button.clicked.connect(self.reject)
11582
+ button_layout.addWidget(close_button)
11518
11583
 
11519
11584
  layout.addLayout(button_layout)
11520
11585
 
@@ -11723,8 +11788,6 @@ class AngleDialog(Dialog3DPickingMixin, QDialog):
11723
11788
 
11724
11789
  # キラルラベルを更新
11725
11790
  self.main_window.update_chiral_labels()
11726
-
11727
- self.accept()
11728
11791
 
11729
11792
  def adjust_angle(self, new_angle_deg):
11730
11793
  """角度を調整(均等回転オプション付き)"""
@@ -11911,9 +11974,9 @@ class DihedralDialog(Dialog3DPickingMixin, QDialog):
11911
11974
  self.apply_button.setEnabled(False)
11912
11975
  button_layout.addWidget(self.apply_button)
11913
11976
 
11914
- cancel_button = QPushButton("Cancel")
11915
- cancel_button.clicked.connect(self.reject)
11916
- button_layout.addWidget(cancel_button)
11977
+ close_button = QPushButton("Close")
11978
+ close_button.clicked.connect(self.reject)
11979
+ button_layout.addWidget(close_button)
11917
11980
 
11918
11981
  layout.addLayout(button_layout)
11919
11982
 
@@ -12121,8 +12184,6 @@ class DihedralDialog(Dialog3DPickingMixin, QDialog):
12121
12184
 
12122
12185
  # キラルラベルを更新
12123
12186
  self.main_window.update_chiral_labels()
12124
-
12125
- self.accept()
12126
12187
 
12127
12188
  def adjust_dihedral(self, new_dihedral_deg):
12128
12189
  """二面角を調整(改善されたアルゴリズム)"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moleditpy
3
- Version: 1.8.2
3
+ Version: 1.8.4
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
  Project-URL: Homepage, https://github.com/HiroYokoyama/python_molecular_editor
File without changes
File without changes