finalcif 151__tar.gz → 153__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.
Files changed (162) hide show
  1. {finalcif-151 → finalcif-153}/.gitignore +1 -0
  2. finalcif-153/.python-version +1 -0
  3. {finalcif-151 → finalcif-153}/Finalcif_installer_win.spec +1 -0
  4. {finalcif-151 → finalcif-153}/PKG-INFO +7 -4
  5. finalcif-153/finalcif/__init__.py +2 -0
  6. {finalcif-151 → finalcif-153}/finalcif/appwindow.py +30 -22
  7. {finalcif-151 → finalcif-153}/finalcif/cif/checkcif/checkcif.py +1 -1
  8. {finalcif-151 → finalcif-153}/finalcif/cif/cif_file_io.py +23 -15
  9. {finalcif-151 → finalcif-153}/finalcif/cif/cod/deposit.py +5 -5
  10. {finalcif-151 → finalcif-153}/finalcif/cif/hkl.py +5 -1
  11. {finalcif-151 → finalcif-153}/finalcif/ciforder/order.py +1 -1
  12. {finalcif-151 → finalcif-153}/finalcif/ciforder/order_ui.py +3 -3
  13. {finalcif-151 → finalcif-153}/finalcif/datafiles/shelx_lst.py +21 -12
  14. {finalcif-151 → finalcif-153}/finalcif/displaymol/molecule2D.py +3 -3
  15. {finalcif-151 → finalcif-153}/finalcif/displaymol/vtk_molecule.py +2 -2
  16. {finalcif-151 → finalcif-153}/finalcif/equip_property/author_loop_templates.py +30 -2
  17. {finalcif-151 → finalcif-153}/finalcif/equip_property/equipment.py +2 -2
  18. {finalcif-151 → finalcif-153}/finalcif/equip_property/properties.py +2 -2
  19. {finalcif-151 → finalcif-153}/finalcif/finalcif_start.py +4 -2
  20. {finalcif-151 → finalcif-153}/finalcif/gui/block_combobox.py +1 -1
  21. {finalcif-151 → finalcif-153}/finalcif/gui/combobox.py +3 -3
  22. {finalcif-151 → finalcif-153}/finalcif/gui/custom_classes.py +4 -4
  23. {finalcif-151 → finalcif-153}/finalcif/gui/dialogs.py +19 -15
  24. {finalcif-151 → finalcif-153}/finalcif/gui/edit_button.py +1 -1
  25. {finalcif-151 → finalcif-153}/finalcif/gui/equipmenttable.py +2 -2
  26. {finalcif-151 → finalcif-153}/finalcif/gui/file_editor.py +5 -5
  27. {finalcif-151 → finalcif-153}/finalcif/gui/finalcif_gui_ui.py +3 -3
  28. {finalcif-151 → finalcif-153}/finalcif/gui/import_selector_ui.py +3 -3
  29. {finalcif-151 → finalcif-153}/finalcif/gui/loop_creator.py +2 -2
  30. {finalcif-151 → finalcif-153}/finalcif/gui/loop_creator_ui.py +3 -3
  31. {finalcif-151 → finalcif-153}/finalcif/gui/loops.py +4 -4
  32. {finalcif-151 → finalcif-153}/finalcif/gui/mainstackwidget.py +1 -1
  33. {finalcif-151 → finalcif-153}/finalcif/gui/new_key_dialog.py +3 -3
  34. {finalcif-151 → finalcif-153}/finalcif/gui/new_key_dialog_ui.py +3 -3
  35. {finalcif-151 → finalcif-153}/finalcif/gui/plaintextedit.py +6 -6
  36. {finalcif-151 → finalcif-153}/finalcif/gui/playground.py +4 -4
  37. {finalcif-151 → finalcif-153}/finalcif/gui/propertytable.py +1 -1
  38. {finalcif-151 → finalcif-153}/finalcif/gui/spell_check_edit.py +4 -4
  39. {finalcif-151 → finalcif-153}/finalcif/gui/text_templates_ui.py +3 -3
  40. {finalcif-151 → finalcif-153}/finalcif/gui/text_value_editor.py +4 -4
  41. {finalcif-151 → finalcif-153}/finalcif/gui/vrf_classes.py +4 -4
  42. {finalcif-151 → finalcif-153}/finalcif/report/gui/mainwindow.py +3 -3
  43. {finalcif-151 → finalcif-153}/finalcif/report/templated_report.py +1 -1
  44. {finalcif-151 → finalcif-153}/finalcif/template/templates.py +7 -6
  45. {finalcif-151 → finalcif-153}/finalcif/tools/download.py +3 -3
  46. {finalcif-151 → finalcif-153}/finalcif/tools/platon.py +2 -2
  47. {finalcif-151 → finalcif-153}/finalcif/tools/settings.py +4 -3
  48. {finalcif-151 → finalcif-153}/pyproject.toml +7 -5
  49. {finalcif-151 → finalcif-153}/requirements.txt +2 -2
  50. finalcif-153/uv.lock +1273 -0
  51. finalcif-151/finalcif/__init__.py +0 -2
  52. finalcif-151/uv.lock +0 -1071
  53. {finalcif-151 → finalcif-153}/.gitattributes +0 -0
  54. {finalcif-151 → finalcif-153}/.ruff.toml +0 -0
  55. {finalcif-151 → finalcif-153}/.run/Make Documentation MAC.run.xml +0 -0
  56. {finalcif-151 → finalcif-153}/.run/compile_ui_files.run.xml +0 -0
  57. {finalcif-151 → finalcif-153}/.run/make documentation Windows.run.xml +0 -0
  58. {finalcif-151 → finalcif-153}/CODE_OF_CONDUCT.md +0 -0
  59. {finalcif-151 → finalcif-153}/CONTRIBUTING.md +0 -0
  60. {finalcif-151 → finalcif-153}/Finalcif_linux_onefile.spec +0 -0
  61. {finalcif-151 → finalcif-153}/Finalcif_mac.spec +0 -0
  62. {finalcif-151 → finalcif-153}/Hydrogen_solution_type.cif +0 -0
  63. {finalcif-151 → finalcif-153}/LICENSE +0 -0
  64. {finalcif-151 → finalcif-153}/README.md +0 -0
  65. {finalcif-151 → finalcif-153}/finalcif/app_path.py +0 -0
  66. {finalcif-151 → finalcif-153}/finalcif/cif/__init__.py +0 -0
  67. {finalcif-151 → finalcif-153}/finalcif/cif/all_cif_dicts.py +0 -0
  68. {finalcif-151 → finalcif-153}/finalcif/cif/atoms.py +0 -0
  69. {finalcif-151 → finalcif-153}/finalcif/cif/checkcif/__init__.py +0 -0
  70. {finalcif-151 → finalcif-153}/finalcif/cif/cif_dict_foo.py +0 -0
  71. {finalcif-151 → finalcif-153}/finalcif/cif/cif_order.py +0 -0
  72. {finalcif-151 → finalcif-153}/finalcif/cif/cod/__init__.py +0 -0
  73. {finalcif-151 → finalcif-153}/finalcif/cif/cod/deposit_check.py +0 -0
  74. {finalcif-151 → finalcif-153}/finalcif/cif/cod/deposition_list.py +0 -0
  75. {finalcif-151 → finalcif-153}/finalcif/cif/cod/doi.py +0 -0
  76. {finalcif-151 → finalcif-153}/finalcif/cif/cod/upload.py +0 -0
  77. {finalcif-151 → finalcif-153}/finalcif/cif/cod/website_parser.py +0 -0
  78. {finalcif-151 → finalcif-153}/finalcif/cif/core_dict.py +0 -0
  79. {finalcif-151 → finalcif-153}/finalcif/cif/modulation_dict.py +0 -0
  80. {finalcif-151 → finalcif-153}/finalcif/cif/powder_dict.py +0 -0
  81. {finalcif-151 → finalcif-153}/finalcif/cif/reference.py +0 -0
  82. {finalcif-151 → finalcif-153}/finalcif/cif/restraints_dict.py +0 -0
  83. {finalcif-151 → finalcif-153}/finalcif/cif/text.py +0 -0
  84. {finalcif-151 → finalcif-153}/finalcif/cif/twin_dict.py +0 -0
  85. {finalcif-151 → finalcif-153}/finalcif/ciforder/__init__.py +0 -0
  86. {finalcif-151 → finalcif-153}/finalcif/ciforder/order_ui.ui +0 -0
  87. {finalcif-151 → finalcif-153}/finalcif/datafiles/__init__.py +0 -0
  88. {finalcif-151 → finalcif-153}/finalcif/datafiles/bruker_data.py +0 -0
  89. {finalcif-151 → finalcif-153}/finalcif/datafiles/bruker_frame.py +0 -0
  90. {finalcif-151 → finalcif-153}/finalcif/datafiles/ccdc_mail.py +0 -0
  91. {finalcif-151 → finalcif-153}/finalcif/datafiles/data.py +0 -0
  92. {finalcif-151 → finalcif-153}/finalcif/datafiles/p4p_reader.py +0 -0
  93. {finalcif-151 → finalcif-153}/finalcif/datafiles/sadabs.py +0 -0
  94. {finalcif-151 → finalcif-153}/finalcif/datafiles/saint.py +0 -0
  95. {finalcif-151 → finalcif-153}/finalcif/datafiles/utils.py +0 -0
  96. {finalcif-151 → finalcif-153}/finalcif/displaymol/__init__.py +0 -0
  97. {finalcif-151 → finalcif-153}/finalcif/displaymol/sdm.py +0 -0
  98. {finalcif-151 → finalcif-153}/finalcif/equip_property/__init__.py +0 -0
  99. {finalcif-151 → finalcif-153}/finalcif/equip_property/tools.py +0 -0
  100. {finalcif-151 → finalcif-153}/finalcif/gui/__init__.py +0 -0
  101. {finalcif-151 → finalcif-153}/finalcif/gui/finalcif_gui_ui.ui +0 -0
  102. {finalcif-151 → finalcif-153}/finalcif/gui/import_selector.py +0 -0
  103. {finalcif-151 → finalcif-153}/finalcif/gui/import_selector_ui.ui +0 -0
  104. {finalcif-151 → finalcif-153}/finalcif/gui/loop_creator_ui.ui +0 -0
  105. {finalcif-151 → finalcif-153}/finalcif/gui/mixins.py +0 -0
  106. {finalcif-151 → finalcif-153}/finalcif/gui/new_key_dialog_ui.ui +0 -0
  107. {finalcif-151 → finalcif-153}/finalcif/gui/text_templates_ui.ui +0 -0
  108. {finalcif-151 → finalcif-153}/finalcif/gui/validators.py +0 -0
  109. {finalcif-151 → finalcif-153}/finalcif/icon/__init__.py +0 -0
  110. {finalcif-151 → finalcif-153}/finalcif/icon/finalcif.png +0 -0
  111. {finalcif-151 → finalcif-153}/finalcif/icon/finalcif2.ico +0 -0
  112. {finalcif-151 → finalcif-153}/finalcif/icon/finalcif2.png +0 -0
  113. {finalcif-151 → finalcif-153}/finalcif/icon/multitable.ico +0 -0
  114. {finalcif-151 → finalcif-153}/finalcif/icon/multitable.png +0 -0
  115. {finalcif-151 → finalcif-153}/finalcif/icon/multitable.xcf +0 -0
  116. {finalcif-151 → finalcif-153}/finalcif/report/__init__.py +0 -0
  117. {finalcif-151 → finalcif-153}/finalcif/report/archive_report.py +0 -0
  118. {finalcif-151 → finalcif-153}/finalcif/report/gui/__init__.py +0 -0
  119. {finalcif-151 → finalcif-153}/finalcif/report/gui/mainwindow.ui +0 -0
  120. {finalcif-151 → finalcif-153}/finalcif/report/mtools.py +0 -0
  121. {finalcif-151 → finalcif-153}/finalcif/report/references.py +0 -0
  122. {finalcif-151 → finalcif-153}/finalcif/report/report_text.py +0 -0
  123. {finalcif-151 → finalcif-153}/finalcif/report/symm.py +0 -0
  124. {finalcif-151 → finalcif-153}/finalcif/report/tables.py +0 -0
  125. {finalcif-151 → finalcif-153}/finalcif/template/__init__.py +0 -0
  126. {finalcif-151 → finalcif-153}/finalcif/template/bootstrap/bootstrap.min.css +0 -0
  127. {finalcif-151 → finalcif-153}/finalcif/template/machines/D8_VENTURE.cif +0 -0
  128. {finalcif-151 → finalcif-153}/finalcif/template/mathml2omml.xsl +0 -0
  129. {finalcif-151 → finalcif-153}/finalcif/template/report.tmpl +0 -0
  130. {finalcif-151 → finalcif-153}/finalcif/template/report_default.docx +0 -0
  131. {finalcif-151 → finalcif-153}/finalcif/template/template1.docx +0 -0
  132. {finalcif-151 → finalcif-153}/finalcif/template/template_for_multitable.docx +0 -0
  133. {finalcif-151 → finalcif-153}/finalcif/template/template_text.docx +0 -0
  134. {finalcif-151 → finalcif-153}/finalcif/template/template_without_text.docx +0 -0
  135. {finalcif-151 → finalcif-153}/finalcif/template/xsl/convert.py +0 -0
  136. {finalcif-151 → finalcif-153}/finalcif/template/xsl/xmltohtml.xsl +0 -0
  137. {finalcif-151 → finalcif-153}/finalcif/tools/__init__.py +0 -0
  138. {finalcif-151 → finalcif-153}/finalcif/tools/chemparse.py +0 -0
  139. {finalcif-151 → finalcif-153}/finalcif/tools/dsrmath.py +0 -0
  140. {finalcif-151 → finalcif-153}/finalcif/tools/misc.py +0 -0
  141. {finalcif-151 → finalcif-153}/finalcif/tools/options.py +0 -0
  142. {finalcif-151 → finalcif-153}/finalcif/tools/pupdate.py +0 -0
  143. {finalcif-151 → finalcif-153}/finalcif/tools/shred.py +0 -0
  144. {finalcif-151 → finalcif-153}/finalcif/tools/space_groups.py +0 -0
  145. {finalcif-151 → finalcif-153}/finalcif/tools/spgr_format.py +0 -0
  146. {finalcif-151 → finalcif-153}/finalcif/tools/statusbar.py +0 -0
  147. {finalcif-151 → finalcif-153}/finalcif/tools/sumformula.py +0 -0
  148. {finalcif-151 → finalcif-153}/finalcif.exe +0 -0
  149. {finalcif-151 → finalcif-153}/install_requirements +0 -0
  150. {finalcif-151 → finalcif-153}/install_requirements.bat +0 -0
  151. {finalcif-151 → finalcif-153}/requirements_devel.txt +0 -0
  152. {finalcif-151 → finalcif-153}/requirements_doku.txt +0 -0
  153. {finalcif-151 → finalcif-153}/run_finalcif +0 -0
  154. {finalcif-151 → finalcif-153}/run_finalcif.bat +0 -0
  155. {finalcif-151 → finalcif-153}/screenshots/finalcif_checkcif.png +0 -0
  156. {finalcif-151 → finalcif-153}/screenshots/finalcif_details.png +0 -0
  157. {finalcif-151 → finalcif-153}/screenshots/finalcif_loops.png +0 -0
  158. {finalcif-151 → finalcif-153}/screenshots/finalcif_loops2.png +0 -0
  159. {finalcif-151 → finalcif-153}/screenshots/finalcif_main.png +0 -0
  160. {finalcif-151 → finalcif-153}/screenshots/finalcif_report.png +0 -0
  161. {finalcif-151 → finalcif-153}/screenshots/finalcif_responses.png +0 -0
  162. {finalcif-151 → finalcif-153}/update.exe +0 -0
@@ -225,3 +225,4 @@ tests/examples/multi-multitable.docx
225
225
  tests/examples/report_multi-finalcif.docx
226
226
  tests/examples/work/cu_BruecknerJK_153F40_0m.lxt
227
227
  finalcif_keys_order.cif
228
+ !/.python-version
@@ -0,0 +1 @@
1
+ cpython@3.12
@@ -2,6 +2,7 @@
2
2
 
3
3
  import sys
4
4
  from os import path
5
+ #pyinstaller myapp.py --noconfirm --onedir --hidden-import PySide6.QtWebEngineWidgets --exclude-module PySide6.QtMultimedia
5
6
 
6
7
  block_cipher = None
7
8
  site_packages = next(p for p in sys.path if 'site-packages' in p)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: finalcif
3
- Version: 151
3
+ Version: 153
4
4
  Summary: CIF file editor
5
5
  Project-URL: Homepage, https://dkratzert.de/finalcif.html
6
6
  Project-URL: Bug Tracker, https://github.com/dkratzert/FinalCif/issues
@@ -14,17 +14,20 @@ Classifier: Topic :: Scientific/Engineering :: Chemistry
14
14
  Requires-Python: >=3.10
15
15
  Requires-Dist: certifi
16
16
  Requires-Dist: chardet
17
+ Requires-Dist: charset-normalizer
17
18
  Requires-Dist: crossrefapi
18
19
  Requires-Dist: docxtpl
19
- Requires-Dist: gemmi<0.7.0
20
- Requires-Dist: hatchling>=1.27.0
20
+ Requires-Dist: gemmi
21
+ Requires-Dist: hatchling
21
22
  Requires-Dist: html2text
22
23
  Requires-Dist: lxml
23
24
  Requires-Dist: numpy
25
+ Requires-Dist: packaging
24
26
  Requires-Dist: pefile
25
27
  Requires-Dist: pybind11
26
28
  Requires-Dist: pyenchant
27
- Requires-Dist: pyside6<6.9
29
+ Requires-Dist: pyside6
30
+ Requires-Dist: pyside6-addons
28
31
  Requires-Dist: python-docx
29
32
  Requires-Dist: qtawesome
30
33
  Requires-Dist: qtpy
@@ -0,0 +1,2 @@
1
+
2
+ VERSION = 153
@@ -14,12 +14,16 @@ from datetime import datetime
14
14
  from math import sin, radians
15
15
  from pathlib import Path, WindowsPath
16
16
 
17
- import gemmi.cif
17
+ import gemmi
18
+
19
+ if hasattr(gemmi, 'set_leak_warnings'):
20
+ gemmi.set_leak_warnings(False)
21
+
18
22
  import requests
19
- from PySide6 import QtCore, QtGui, QtWebEngineWidgets, QtWidgets
20
- from PySide6.QtCore import Qt, QEvent
21
- from PySide6.QtWidgets import (QMainWindow, QCheckBox, QListWidgetItem, QApplication,
22
- QPlainTextEdit, QFileDialog, QMessageBox, QScrollBar)
23
+ from qtpy import QtCore, QtGui, QtWebEngineWidgets, QtWidgets, compat
24
+ from qtpy.QtCore import Qt, QEvent
25
+ from qtpy.QtWidgets import (QMainWindow, QCheckBox, QListWidgetItem, QApplication,
26
+ QPlainTextEdit, QMessageBox, QScrollBar)
23
27
  from gemmi import cif
24
28
 
25
29
  from finalcif import VERSION
@@ -417,11 +421,12 @@ class AppWindow(QMainWindow):
417
421
  def export_all_templates(self, filename: Path | None = None):
418
422
  import pickle
419
423
  if not filename:
420
- filename, _ = QFileDialog.getSaveFileName(dir=str(Path(self.get_last_workdir()).joinpath(
421
- f'finalcif_templates_{time.strftime("%Y-%m-%d")}.dat')),
422
- selectedFilter="Template File (*.dat)",
423
- filter="Template File (*.dat)",
424
- caption='Save templates')
424
+ filename, _ = compat.getsavefilename(parent=self,
425
+ basedir=str(Path(self.get_last_workdir()).joinpath(
426
+ f'finalcif_templates_{time.strftime("%Y-%m-%d")}.dat')),
427
+ selectedfilter="Template File (*.dat)",
428
+ filters="Template File (*.dat)",
429
+ caption='Save templates')
425
430
  if not filename:
426
431
  return
427
432
  templates = {'text' : self.export_raw_text_templates(),
@@ -440,10 +445,11 @@ class AppWindow(QMainWindow):
440
445
  def import_all_templates(self, filename: Path | None = None):
441
446
  import pickle
442
447
  if not filename:
443
- filename, _ = QFileDialog.getOpenFileName(dir=self.get_last_workdir(),
444
- selectedFilter="Template File (*.dat)",
445
- filter="Template File (*.dat)",
446
- caption='Save templates')
448
+ filename, _ = compat.getopenfilename(parent=self,
449
+ basedir=self.get_last_workdir(),
450
+ selectedfilter="Template File (*.dat)",
451
+ filters="Template File (*.dat)",
452
+ caption='Save templates')
447
453
  if not filename:
448
454
  return
449
455
  try:
@@ -495,7 +501,7 @@ class AppWindow(QMainWindow):
495
501
  """
496
502
  Imports a text template from a CIF file.
497
503
  """
498
- filename = cif_file_open_dialog()
504
+ filename = cif_file_open_dialog(parent=self)
499
505
  if not filename:
500
506
  return
501
507
  try:
@@ -536,7 +542,8 @@ class AppWindow(QMainWindow):
536
542
  if not filename.strip():
537
543
  return
538
544
  try:
539
- doc.write_file(filename, style=cif.Style.Indent35)
545
+ write_options = cif.WriteOptions(cif.Style.Indent35)
546
+ doc.write_file(filename, options=write_options)
540
547
  # Path(filename).write_text(doc.as_string(cif.Style.Indent35))
541
548
  except PermissionError:
542
549
  if Path(filename).is_dir():
@@ -1103,9 +1110,10 @@ class AppWindow(QMainWindow):
1103
1110
  if file:
1104
1111
  self.report_picture_path = Path(file)
1105
1112
  else:
1106
- filename, _ = QFileDialog.getOpenFileName(filter="Image Files (*.png *.jpg *.jpeg *.bmp "
1107
- "*.gif *.tif *.tiff *.eps *.emf *.wmf)",
1108
- caption='Open a Report Picture')
1113
+ filename, _ = compat.getopenfilename(parent=self,
1114
+ filters="Image Files (*.png *.jpg *.jpeg *.bmp "
1115
+ "*.gif *.tif *.tiff *.eps *.emf *.wmf)",
1116
+ caption='Open a Report Picture')
1109
1117
  self.set_report_picture_path(filename)
1110
1118
 
1111
1119
  def set_report_picture_path(self, filename: str):
@@ -1409,7 +1417,7 @@ class AppWindow(QMainWindow):
1409
1417
  """
1410
1418
  imp_cif: CifContainer | None = None
1411
1419
  if not filename:
1412
- filename = cif_file_open_dialog(filter="CIF file (*.cif *.pcf *.cif_od *.cfx *.sqf)")
1420
+ filename = cif_file_open_dialog(parent=self, filter="CIF file (*.cif *.pcf *.cif_od *.cfx *.sqf)")
1413
1421
  if not filename:
1414
1422
  return
1415
1423
  try:
@@ -1460,7 +1468,7 @@ class AppWindow(QMainWindow):
1460
1468
  """
1461
1469
  self.ui.datanameComboBox.blockSignals(True)
1462
1470
  if not filepath:
1463
- filepath = Path(cif_file_open_dialog(last_dir=self.get_last_workdir()))
1471
+ filepath = Path(cif_file_open_dialog(parent=self, last_dir=self.get_last_workdir()))
1464
1472
  if not filepath.is_file():
1465
1473
  return
1466
1474
  self.set_path_display_in_file_selector(str(filepath))
@@ -1669,7 +1677,7 @@ class AppWindow(QMainWindow):
1669
1677
  self.load_cif_file(filepath=self.cif.fileobj, load_changes=False)
1670
1678
 
1671
1679
  def get_file_from_dialog(self) -> Path | None:
1672
- fp = cif_file_open_dialog(last_dir=self.get_last_workdir())
1680
+ fp = cif_file_open_dialog(parent=self, last_dir=self.get_last_workdir())
1673
1681
  if not fp:
1674
1682
  return None
1675
1683
  filepath = Path(fp)
@@ -14,7 +14,7 @@ from html.parser import HTMLParser
14
14
  from pathlib import Path
15
15
 
16
16
  import requests
17
- from PySide6.QtCore import QThread, Signal
17
+ from qtpy.QtCore import QThread, Signal
18
18
  from requests.exceptions import MissingSchema
19
19
 
20
20
  from finalcif.cif.cif_file_io import CifContainer
@@ -12,6 +12,10 @@ from contextlib import suppress
12
12
  from pathlib import Path
13
13
 
14
14
  import gemmi
15
+
16
+ if hasattr(gemmi, 'set_leak_warnings'):
17
+ gemmi.set_leak_warnings(False)
18
+
15
19
  from gemmi.cif import as_string, Document, Loop
16
20
  from packaging.version import Version
17
21
  from shelxfile import Shelxfile
@@ -207,18 +211,20 @@ class CifContainer:
207
211
  return doc
208
212
 
209
213
  def cif_as_string(self, without_hkl=False) -> str:
214
+ opt = gemmi.cif.WriteOptions(gemmi.cif.Style.Indent35)
215
+
210
216
  if without_hkl:
211
217
  # return a copy, do not delete hkl from original:
212
218
  doc = gemmi.cif.Document()
213
- doc.parse_string(self.doc.as_string(style=gemmi.cif.Style.Indent35))
219
+ doc.parse_string(self.doc.as_string(options=opt))
214
220
  for block in doc:
215
221
  if block.find_pair_item('_shelx_hkl_file'):
216
222
  block.find_pair_item('_shelx_hkl_file').erase()
217
223
  if block.find_pair_item('_shelx_fcf_file'):
218
224
  block.find_pair_item('_shelx_fcf_file').erase()
219
- return doc.as_string(style=gemmi.cif.Style.Indent35)
225
+ return doc.as_string(options=opt)
220
226
  else:
221
- return self.doc.as_string(style=gemmi.cif.Style.Indent35)
227
+ return self.doc.as_string(options=opt)
222
228
 
223
229
  def __getitem__(self, item: str) -> str:
224
230
  """
@@ -712,13 +718,13 @@ class CifContainer:
712
718
  x = self.block.find_loop('_atom_site_fract_x')
713
719
  y = self.block.find_loop('_atom_site_fract_y')
714
720
  z = self.block.find_loop('_atom_site_fract_z')
715
- part = self.block.find_loop('_atom_site_disorder_group')
716
- occ = self.block.find_loop('_atom_site_occupancy')
721
+ part = self.block.find_loop('_atom_site_disorder_group') or ('0',) * len(labels)
722
+ occ = self.block.find_loop('_atom_site_occupancy') or ('1.000000',) * len(labels)
717
723
  u_eq = self.block.find_loop('_atom_site_U_iso_or_equiv')
718
724
  atom = namedtuple('atom', ('label', 'type', 'x', 'y', 'z', 'part', 'occ', 'u_eq'))
719
725
  for label, type, x, y, z, part, occ, u_eq in zip(labels, types, x, y, z,
720
- part if part else ('0',) * len(labels),
721
- occ if occ else ('1.000000',) * len(labels),
726
+ part,
727
+ occ,
722
728
  u_eq, strict=True):
723
729
  if without_h and self.ishydrogen(label):
724
730
  continue
@@ -809,7 +815,7 @@ class CifContainer:
809
815
  label2 = self.block.find_loop('_geom_bond_atom_site_label_2')
810
816
  dist = self.block.find_loop('_geom_bond_distance')
811
817
  symm = self.block.find_loop('_geom_bond_site_symmetry_2')
812
- publ_loop = self.block.find_loop('_geom_bond_publ_flag')
818
+ publ_loop = self.block.find_loop('_geom_bond_publ_flag') or len(label1) * ['?']
813
819
  bond = namedtuple('bond', ('label1', 'label2', 'dist', 'symm'))
814
820
  for label1, label2, dist, symm, publ in zip(label1, label2, dist, symm, publ_loop):
815
821
  if (without_h and (self.ishydrogen(label1) or self.ishydrogen(label2))) or self.yes_not_set(publ):
@@ -847,10 +853,10 @@ class CifContainer:
847
853
  angle_val = self.block.find_loop('_geom_angle')
848
854
  symm1 = self.block.find_loop('_geom_angle_site_symmetry_1')
849
855
  symm2 = self.block.find_loop('_geom_angle_site_symmetry_3')
850
- publ_loop = self.block.find_loop('_geom_angle_publ_flag')
856
+ publ_loop = self.block.find_loop('_geom_angle_publ_flag') or len(label1) * ['?']
851
857
  angle = namedtuple('angle', ('label1', 'label2', 'label3', 'angle_val', 'symm1', 'symm2'))
852
858
  for label1, label2, label3, angle_val, symm1, symm2, publ in \
853
- zip(label1, label2, label3, angle_val, symm1, symm2, publ_loop, strict=True):
859
+ zip(label1, label2, label3, angle_val, symm1, symm2, publ_loop, strict=True):
854
860
  if ((without_H and (self.ishydrogen(label1) or self.ishydrogen(label2) or
855
861
  self.ishydrogen(label3))) or (self.yes_not_set(publ))):
856
862
  continue
@@ -892,14 +898,16 @@ class CifContainer:
892
898
  symm2 = self.block.find_loop('_geom_torsion_site_symmetry_2')
893
899
  symm3 = self.block.find_loop('_geom_torsion_site_symmetry_3')
894
900
  symm4 = self.block.find_loop('_geom_torsion_site_symmetry_4')
895
- publ_loop = self.block.find_loop('_geom_torsion_publ_flag')
901
+ publ_loop = self.block.find_loop('_geom_torsion_publ_flag') or len(label1) * ['?']
896
902
  tors = namedtuple('Torsion',
897
903
  ('label1', 'label2', 'label3', 'label4', 'torsang', 'symm1', 'symm2', 'symm3', 'symm4'))
898
- for label1, label2, label3, label4, torsang, symm1, symm2, symm3, symm4, publ in zip(label1, label2, label3, # noqa: B020
904
+ for label1, label2, label3, label4, torsang, symm1, symm2, symm3, symm4, publ in zip(label1, label2, label3,
905
+ # noqa: B020
899
906
  label4,
900
907
  torsang, symm1, symm2,
901
908
  symm3,
902
- symm4, publ_loop, strict=True):
909
+ symm4, publ_loop,
910
+ strict=True):
903
911
  if ((without_h and (self.ishydrogen(label1) or self.ishydrogen(label2)
904
912
  or self.ishydrogen(label3) or self.ishydrogen(label3))) or self.yes_not_set(publ)):
905
913
  continue
@@ -918,11 +926,11 @@ class CifContainer:
918
926
  dist_da = self.block.find_loop('_geom_hbond_distance_DA')
919
927
  angle_dha = self.block.find_loop('_geom_hbond_angle_DHA')
920
928
  symm = self.block.find_loop('_geom_hbond_site_symmetry_A')
921
- publ_loop = self.block.find_loop('_geom_hbond_publ_flag')
929
+ publ_loop = self.block.find_loop('_geom_hbond_publ_flag') or len(label_d) * ['?']
922
930
  hydr = namedtuple('HydrogenBond', ('label_d', 'label_h', 'label_a', 'dist_dh', 'dist_ha', 'dist_da',
923
931
  'angle_dha', 'symm'))
924
932
  for label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ in (
925
- zip(label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ_loop)):
933
+ zip(label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ_loop)):
926
934
  if self.yes_not_set(publ):
927
935
  continue
928
936
  if self.picometer:
@@ -10,7 +10,7 @@ from pathlib import Path
10
10
  from urllib.parse import urlparse
11
11
 
12
12
  import requests
13
- from PySide6.QtWidgets import QTableWidgetItem, QTextBrowser, QFrame
13
+ from qtpy.QtWidgets import QTableWidgetItem, QTextBrowser, QFrame
14
14
 
15
15
  from finalcif.cif.cif_file_io import CifContainer
16
16
  from finalcif.cif.cod.deposition_list import CODFetcher
@@ -210,7 +210,7 @@ class CODdeposit:
210
210
  if f.authenticated:
211
211
  self.token_valid = True
212
212
  else:
213
- self.ui.statusBar.showMessage('Unable to login. Check username/password.', timeout=12000)
213
+ self.ui.statusBar.showMessage('Unable to login. Check username/password.', 12000)
214
214
  f.get_table_data_by_token(self._cod_token)
215
215
  parser = MyCODStructuresParser()
216
216
  parser.feed(f.table_html)
@@ -346,14 +346,14 @@ class CODdeposit:
346
346
  self.ui.depositionOptionsStackedWidget.setCurrentIndex(self.deposition_type_to_int(deposition_type))
347
347
 
348
348
  def reset_deposit_button_state_to_initial(self):
349
- self.ui.depositCIFpushButton.disconnect()
349
+ self.ui.depositCIFpushButton.clicked.disconnect()
350
350
  self.ui.depositOutputTextBrowser.clear()
351
351
  self.ui.depositCIFpushButton.setText("Deposit CIF")
352
352
  self.ui.depositCIFpushButton.clicked.connect(self._init_deposit)
353
353
 
354
354
  def set_deposit_button_to_try_again(self):
355
355
  self.ui.depositCIFpushButton.setText("Try Again")
356
- self.ui.depositCIFpushButton.disconnect()
356
+ self.ui.depositCIFpushButton.clicked.disconnect()
357
357
  self.ui.depositCIFpushButton.clicked.connect(lambda: self.switch_to_page(self.deposition_type))
358
358
 
359
359
  def log_response_text(self, resp: requests.Response, *args, **kwargs):
@@ -380,7 +380,7 @@ class CODdeposit:
380
380
  self.user_email = text
381
381
 
382
382
  def _set_external_hkl_file(self) -> None:
383
- file = cif_file_open_dialog(filter="HKL file (*.hkl *.fcf)")
383
+ file = cif_file_open_dialog(parent=self, filter="HKL file (*.hkl *.fcf)")
384
384
  if file.endswith('.hkl'):
385
385
  if self.cif.res_file_data:
386
386
  hklf = self.cif._hklf_number_from_shelxl_file()
@@ -5,6 +5,7 @@ from pathlib import Path
5
5
  import gemmi
6
6
  import numpy as np
7
7
  from gemmi.cif import Loop, Document, Style
8
+ from packaging import version
8
9
 
9
10
  Limit = namedtuple('Limit', 'h_max, h_min, k_max, k_min, l_max, l_min')
10
11
 
@@ -30,7 +31,10 @@ class HKL:
30
31
 
31
32
  @property
32
33
  def hkl_as_cif(self) -> str:
33
- return self._doc.as_string(style=Style.Simple)
34
+ if version.parse(gemmi.__version__) < version.parse('0.5.1'):
35
+ return self._doc.as_string(style=Style.Simple)
36
+ else:
37
+ return self._doc.as_string(options=gemmi.cif.WriteOptions(Style.Simple))
34
38
 
35
39
  def _add_hkl_as_loop(self) -> None:
36
40
  """
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
  from typing import TYPE_CHECKING
7
7
 
8
8
  import gemmi
9
- from PySide6 import QtWidgets, QtCore
9
+ from qtpy import QtWidgets, QtCore
10
10
 
11
11
  from finalcif.cif import cif_order
12
12
  from finalcif.ciforder.order_ui import Ui_CifOrderForm
@@ -6,14 +6,14 @@
6
6
  ##
7
7
  ################################################################################
8
8
 
9
- from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
9
+ from qtpy.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
10
10
  QMetaObject, QObject, QPoint, QRect,
11
11
  QSize, QTime, QUrl, Qt)
12
- from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
12
+ from qtpy.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
13
13
  QFont, QFontDatabase, QGradient, QIcon,
14
14
  QImage, QKeySequence, QLinearGradient, QPainter,
15
15
  QPalette, QPixmap, QRadialGradient, QTransform)
16
- from PySide6.QtWidgets import (QAbstractItemView, QApplication, QGridLayout, QHeaderView,
16
+ from qtpy.QtWidgets import (QAbstractItemView, QApplication, QGridLayout, QHeaderView,
17
17
  QLabel, QPushButton, QSizePolicy, QSpacerItem,
18
18
  QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget)
19
19
 
@@ -19,7 +19,7 @@ class SHELXTlistfile(ParserMixin):
19
19
  self.solutions = {}
20
20
  self.parse_file()
21
21
 
22
- def parse_file(self):
22
+ def parse_file(self) -> None:
23
23
  """
24
24
  + SHELXT - CRYSTAL STRUCTURE SOLUTION - VERSION 2018/2 +
25
25
  """
@@ -29,11 +29,15 @@ class SHELXTlistfile(ParserMixin):
29
29
  if 'SHELXTL' in line:
30
30
  self.version = 'SHELXT ' + line.split()[-1]
31
31
  if line.strip().startswith('R1 Rweak Alpha'):
32
- for n in range(100):
33
- if not self._text[num + 1 + n]:
34
- break
35
- if self._text[num + 1]:
36
- self.solutions[self._text[num + 1 + n][58:76].strip()] = self._text[num + 1 + n][37:51].strip()
32
+ try:
33
+ for n in range(100):
34
+ if not self._text[num + 1 + n]:
35
+ break
36
+ if self._text[num + 1]:
37
+ self.solutions[self._text[num + 1 + n][58:76].strip()] = self._text[num + 1 + n][37:51].strip()
38
+ except IndexError:
39
+ return None
40
+ return None
37
41
 
38
42
 
39
43
  class SolutionProgram:
@@ -58,17 +62,22 @@ class SolutionProgram:
58
62
  except (TypeError, AttributeError):
59
63
  res = ''
60
64
  byxt = res.find('REM SHELXT solution in')
61
- for x in xt_files:
62
- shelxt = SHELXTlistfile(x.as_posix())
63
- if shelxt.version and byxt:
64
- self.method = 'direct'
65
- self.solution_listfile = 'foo' # x.name
66
- return shelxt
67
65
  if byxt > 0:
66
+ for x in xt_files:
67
+ shelxt = SHELXTlistfile(x.as_posix())
68
+ if shelxt.version and byxt:
69
+ self.method = 'direct'
70
+ self.solution_listfile = 'foo' # x.name
71
+ return shelxt
68
72
  xt = SHELXTlistfile('')
69
73
  xt.version = "SHELXT (G. Sheldrick)"
70
74
  self.method = 'direct'
71
75
  return xt
76
+ if res.find('Best SHELXD solution'):
77
+ xt = SHELXTlistfile('')
78
+ xt.version = "SHELXD (G. Sheldrick)"
79
+ self.method = 'dual space'
80
+ return xt
72
81
  xt = SHELXTlistfile('')
73
82
  xt.version = "SHELXS (G. Sheldrick)"
74
83
  self.method = 'direct'
@@ -5,9 +5,9 @@ from math import sqrt, cos, sin, dist
5
5
  from pathlib import Path
6
6
 
7
7
  import numpy as np
8
- from PySide6 import QtWidgets, QtCore, QtGui
9
- from PySide6.QtCore import Qt
10
- from PySide6.QtGui import QPainter, QPen, QBrush, QColor, QMouseEvent, QPalette, QImage, QResizeEvent, QWheelEvent
8
+ from qtpy import QtWidgets, QtCore, QtGui
9
+ from qtpy.QtCore import Qt
10
+ from qtpy.QtGui import QPainter, QPen, QBrush, QColor, QMouseEvent, QPalette, QImage, QResizeEvent, QWheelEvent
11
11
 
12
12
  from finalcif.cif.atoms import get_radius_from_element, element2color
13
13
  from finalcif.cif.cif_file_io import CifContainer
@@ -1,8 +1,8 @@
1
1
  import sys
2
2
 
3
3
  import vtk
4
- from PySide6 import QtWidgets, QtCore
5
- from PySide6.QtGui import QSurfaceFormat
4
+ from qtpy import QtWidgets, QtCore
5
+ from qtpy.QtGui import QSurfaceFormat
6
6
  from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
7
7
  from vtkmodules.vtkCommonCore import vtkLookupTable
8
8
  from vtkmodules.vtkDomainsChemistry import vtkPeriodicTable
@@ -13,7 +13,7 @@ from pathlib import Path
13
13
  from typing import TYPE_CHECKING
14
14
 
15
15
  import gemmi.cif
16
- from PySide6.QtWidgets import QListWidgetItem
16
+ from qtpy.QtWidgets import QListWidgetItem
17
17
  from gemmi.cif import Loop, as_string
18
18
 
19
19
  from finalcif.cif.cif_file_io import CifContainer
@@ -59,6 +59,10 @@ class AuthorLoops:
59
59
  f'{self.cif_key}_phone', f'{self.cif_key}_id_orcid', f'{self.cif_key}_id_iucr',
60
60
  f'{self.cif_key}_footnote']
61
61
  self.settings = FinalCifSettings()
62
+ try:
63
+ self._migrate_pyqt_saved_templates()
64
+ except ImportError as e:
65
+ print(f'Import of old settings failed:\n{e}')
62
66
  if app:
63
67
  self.ui.authorEditTabWidget.setCurrentIndex(0)
64
68
  self.contact_author_checked(self.ui.ContactAuthorCheckBox.isChecked())
@@ -67,6 +71,30 @@ class AuthorLoops:
67
71
  self.show_authors_list()
68
72
  self.make_sure_to_save_only_when_name_field_has_text()
69
73
 
74
+ def _migrate_pyqt_saved_templates(self) -> None:
75
+ """Author entries saved by PyQt5 (pre-v151) cannot be loaded by PySide2. Load such entries
76
+ using PyQt5 and re-save with PySide2.
77
+ """
78
+
79
+ UPGRADE_FLAG = "v152_migrated_author_templates"
80
+ if self.settings.load_value_of_key(UPGRADE_FLAG):
81
+ return
82
+
83
+ import PyQt5.QtCore
84
+ pyqt_settings = PyQt5.QtCore.QSettings(self.settings.organization, self.settings.software_name)
85
+
86
+ pyqt_settings.beginGroup("authors_list")
87
+ for author in self.authors_list():
88
+ pyside_loopdata = self.author_loopdata(author)
89
+ pyqt_loopdata = pyqt_settings.value(author)
90
+ if not pyside_loopdata and isinstance(pyqt_loopdata, Author):
91
+ self.general_author_save(pyqt_loopdata)
92
+ print(f"Migrated pre-v151 saved author data for \"{author}\".")
93
+ pyqt_settings.endGroup()
94
+
95
+ self.settings.save_key_value(UPGRADE_FLAG, True)
96
+ del pyqt_settings
97
+
70
98
  def connect_signals_and_slots(self) -> None:
71
99
  self.ui.AddThisAuthorToLoopPushButton.clicked.connect(self.save_author_to_loop)
72
100
  self.ui.AddThisAuthorToLoopPushButton_cif.clicked.connect(self.save_author_to_loop)
@@ -300,7 +328,7 @@ class AuthorLoops:
300
328
  Import an author from a cif file.
301
329
  """
302
330
  if not filename:
303
- filename = cif_file_open_dialog(filter="CIF file (*.cif)")
331
+ filename = cif_file_open_dialog(parent=self.app, filter="CIF file (*.cif)")
304
332
  if not filename:
305
333
  return
306
334
  doc = read_document_from_cif_file(filename)
@@ -4,8 +4,8 @@ from bisect import bisect
4
4
  from pathlib import Path
5
5
  from typing import TYPE_CHECKING
6
6
 
7
- from PySide6 import QtCore
8
- from PySide6.QtWidgets import QListWidgetItem
7
+ from qtpy import QtCore
8
+ from qtpy.QtWidgets import QListWidgetItem
9
9
  from gemmi import cif
10
10
 
11
11
  from finalcif.app_path import application_path
@@ -6,8 +6,8 @@ from contextlib import suppress
6
6
  from pathlib import Path
7
7
  from typing import TYPE_CHECKING
8
8
 
9
- from PySide6 import QtCore
10
- from PySide6.QtWidgets import QListWidgetItem, QTableWidget, QStackedWidget, QLabel
9
+ from qtpy import QtCore
10
+ from qtpy.QtWidgets import QListWidgetItem, QTableWidget, QStackedWidget, QLabel
11
11
  from gemmi import cif
12
12
 
13
13
  from finalcif.cif.text import retranslate_delimiter, utf8_to_str
@@ -5,11 +5,14 @@
5
5
  # and you think this stuff is worth it, you can buy me a beer in return.
6
6
  # Dr. Daniel Kratzert
7
7
  # ----------------------------------------------------------------------------
8
+ import os
9
+
10
+ os.environ['QT_API'] = 'pyside6'
8
11
  import sys
9
12
  import time
10
13
  import traceback
11
14
  from pathlib import Path
12
-
15
+ from qtpy.QtGui import QIcon
13
16
  from finalcif import VERSION
14
17
  from finalcif.app_path import application_path
15
18
  from finalcif.appwindow import AppWindow, DEBUG, app
@@ -74,7 +77,6 @@ def main():
74
77
  file = None
75
78
  app.setQuitOnLastWindowClosed(True)
76
79
  w = AppWindow(file=file)
77
- from PySide6.QtGui import QIcon
78
80
  app.setWindowIcon(QIcon(str(application_path / r'icon/finalcif2.png')))
79
81
  w.setWindowTitle(f'FinalCif v{VERSION}')
80
82
  # w.showMaximized() # For full screen view
@@ -1,4 +1,4 @@
1
- from PySide6 import QtWidgets, QtCore
1
+ from qtpy import QtWidgets, QtCore
2
2
 
3
3
 
4
4
  class ComboBoxWithContextMenu(QtWidgets.QComboBox):
@@ -2,9 +2,9 @@ from __future__ import annotations
2
2
  from textwrap import wrap
3
3
  from typing import TYPE_CHECKING
4
4
 
5
- from PySide6 import QtCore, QtGui
6
- from PySide6.QtCore import Qt, QObject, QEvent
7
- from PySide6.QtWidgets import QComboBox, QSizePolicy
5
+ from qtpy import QtCore, QtGui
6
+ from qtpy.QtCore import Qt, QObject, QEvent
7
+ from qtpy.QtWidgets import QComboBox, QSizePolicy
8
8
 
9
9
  from finalcif.gui.validators import validators
10
10
 
@@ -3,10 +3,10 @@ from __future__ import annotations
3
3
  import re
4
4
  from enum import IntEnum
5
5
 
6
- from PySide6 import QtCore, QtGui
7
- from PySide6.QtCore import QEvent, QObject, Qt
8
- from PySide6.QtGui import QColor, QKeySequence, QBrush
9
- from PySide6.QtWidgets import QAbstractScrollArea, QTableWidget, \
6
+ from qtpy import QtCore, QtGui
7
+ from qtpy.QtCore import QEvent, QObject, Qt
8
+ from qtpy.QtGui import QColor, QKeySequence, QBrush
9
+ from qtpy.QtWidgets import QAbstractScrollArea, QTableWidget, \
10
10
  QTableWidgetItem, QWidget, QApplication, QHeaderView
11
11
 
12
12
  from finalcif.cif.text import retranslate_delimiter