finalcif 136__tar.gz → 138__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.
- {finalcif-136 → finalcif-138}/.gitignore +1 -0
- {finalcif-136 → finalcif-138}/PKG-INFO +3 -3
- finalcif-138/finalcif/__init__.py +2 -0
- {finalcif-136 → finalcif-138}/finalcif/appwindow.py +37 -18
- {finalcif-136 → finalcif-138}/finalcif/cif/cif_dict_foo.py +26 -2
- {finalcif-136 → finalcif-138}/finalcif/cif/cif_file_io.py +52 -42
- {finalcif-136 → finalcif-138}/finalcif/cif/cif_order.py +20 -1
- {finalcif-136 → finalcif-138}/finalcif/cif/core_dict.py +1732 -734
- {finalcif-136 → finalcif-138}/finalcif/cif/hkl.py +5 -2
- {finalcif-136 → finalcif-138}/finalcif/cif/modulation_dict.py +683 -323
- {finalcif-136 → finalcif-138}/finalcif/cif/powder_dict.py +500 -194
- {finalcif-136 → finalcif-138}/finalcif/cif/restraints_dict.py +323 -128
- {finalcif-136 → finalcif-138}/finalcif/cif/twin_dict.py +54 -26
- {finalcif-136 → finalcif-138}/finalcif/datafiles/bruker_data.py +21 -20
- {finalcif-136 → finalcif-138}/finalcif/datafiles/p4p_reader.py +2 -2
- {finalcif-136 → finalcif-138}/finalcif/datafiles/sadabs.py +1 -1
- {finalcif-136 → finalcif-138}/finalcif/equip_property/equipment.py +27 -6
- {finalcif-136 → finalcif-138}/finalcif/finalcif_start.py +2 -1
- {finalcif-136 → finalcif-138}/finalcif/gui/custom_classes.py +3 -1
- {finalcif-136 → finalcif-138}/finalcif/gui/import_selector.py +0 -1
- {finalcif-136 → finalcif-138}/finalcif/gui/loop_creator.py +1 -1
- {finalcif-136 → finalcif-138}/finalcif/gui/loop_creator_ui.py +0 -6
- {finalcif-136 → finalcif-138}/finalcif/gui/loop_creator_ui.ui +2 -14
- {finalcif-136 → finalcif-138}/finalcif/gui/loops.py +47 -6
- {finalcif-136 → finalcif-138}/finalcif/gui/plaintextedit.py +24 -8
- {finalcif-136 → finalcif-138}/finalcif/gui/text_templates_ui.py +0 -4
- {finalcif-136 → finalcif-138}/finalcif/gui/text_templates_ui.ui +0 -6
- {finalcif-136 → finalcif-138}/finalcif/gui/text_value_editor.py +16 -3
- finalcif-138/finalcif/gui/validators.py +269 -0
- {finalcif-136 → finalcif-138}/finalcif/report/references.py +30 -24
- {finalcif-136 → finalcif-138}/finalcif/report/report_text.py +35 -15
- {finalcif-136 → finalcif-138}/finalcif/report/tables.py +0 -2
- {finalcif-136 → finalcif-138}/finalcif/report/templated_report.py +173 -43
- finalcif-138/finalcif/template/machines/D8_VENTURE.cif +16 -0
- {finalcif-136 → finalcif-138}/finalcif/template/report.tmpl +20 -20
- finalcif-138/finalcif/template/template1.docx +0 -0
- finalcif-138/finalcif/template/template_text.docx +0 -0
- finalcif-138/finalcif/template/template_without_text.docx +0 -0
- {finalcif-136 → finalcif-138}/finalcif/template/templates.py +9 -9
- {finalcif-136 → finalcif-138}/finalcif/tools/misc.py +4 -2
- {finalcif-136 → finalcif-138}/finalcif/tools/options.py +0 -1
- {finalcif-136 → finalcif-138}/finalcif/tools/platon.py +7 -4
- {finalcif-136 → finalcif-138}/finalcif.exe +0 -0
- {finalcif-136 → finalcif-138}/pyproject.toml +1 -1
- finalcif-136/finalcif/__init__.py +0 -2
- finalcif-136/finalcif/template/template1.docx +0 -0
- finalcif-136/finalcif/template/template_text.docx +0 -0
- finalcif-136/finalcif/template/template_without_text.docx +0 -0
- finalcif-136/work/bootstrap.min.css +0 -7
- {finalcif-136 → finalcif-138}/.gitattributes +0 -0
- {finalcif-136 → finalcif-138}/.run/Make Documentation MAC.run.xml +0 -0
- {finalcif-136 → finalcif-138}/.run/compile_ui_files.run.xml +0 -0
- {finalcif-136 → finalcif-138}/.run/make documentation Windows.run.xml +0 -0
- {finalcif-136 → finalcif-138}/CODE_OF_CONDUCT.md +0 -0
- {finalcif-136 → finalcif-138}/CONTRIBUTING.md +0 -0
- {finalcif-136 → finalcif-138}/Finalcif_installer_win.spec +0 -0
- {finalcif-136 → finalcif-138}/Finalcif_linux_onefile.spec +0 -0
- {finalcif-136 → finalcif-138}/Finalcif_mac.spec +0 -0
- {finalcif-136 → finalcif-138}/Hydrogen_solution_type.cif +0 -0
- {finalcif-136 → finalcif-138}/LICENSE +0 -0
- {finalcif-136 → finalcif-138}/README.md +0 -0
- {finalcif-136 → finalcif-138}/finalcif/app_path.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/all_cif_dicts.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/atoms.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/checkcif/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/checkcif/checkcif.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/cod/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/cod/deposit.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/cod/deposit_check.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/cod/deposition_list.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/cod/doi.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/cod/upload.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/cod/website_parser.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/reference.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/cif/text.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/datafiles/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/datafiles/bruker_frame.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/datafiles/ccdc_mail.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/datafiles/data.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/datafiles/saint.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/datafiles/shelx_lst.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/datafiles/utils.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/displaymol/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/displaymol/molecule2D.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/displaymol/sdm.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/displaymol/vtk_molecule.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/equip_property/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/equip_property/author_loop_templates.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/equip_property/properties.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/equip_property/tools.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/combobox.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/dialogs.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/edit_button.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/equipmenttable.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/file_editor.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/finalcif_gui_ui.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/finalcif_gui_ui.ui +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/import_selector_ui.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/import_selector_ui.ui +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/mainstackwidget.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/mixins.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/new_key_dialog.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/new_key_dialog_ui.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/new_key_dialog_ui.ui +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/playground.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/propertytable.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/spell_check_edit.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/gui/vrf_classes.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/icon/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/icon/finalcif.png +0 -0
- {finalcif-136 → finalcif-138}/finalcif/icon/finalcif2.ico +0 -0
- {finalcif-136 → finalcif-138}/finalcif/icon/finalcif2.png +0 -0
- {finalcif-136 → finalcif-138}/finalcif/icon/multitable.ico +0 -0
- {finalcif-136 → finalcif-138}/finalcif/icon/multitable.png +0 -0
- {finalcif-136 → finalcif-138}/finalcif/icon/multitable.xcf +0 -0
- {finalcif-136 → finalcif-138}/finalcif/report/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/report/archive_report.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/report/gui/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/report/gui/mainwindow.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/report/gui/mainwindow.ui +0 -0
- {finalcif-136 → finalcif-138}/finalcif/report/mtools.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/report/symm.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/template/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/template/bootstrap/bootstrap.min.css +0 -0
- {finalcif-136 → finalcif-138}/finalcif/template/mathml2omml.xsl +0 -0
- {finalcif-136 → finalcif-138}/finalcif/template/template_for_multitable.docx +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/__init__.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/download.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/dsrmath.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/pupdate.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/settings.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/shred.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/space_groups.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/spgr_format.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/statusbar.py +0 -0
- {finalcif-136 → finalcif-138}/finalcif/tools/sumformula.py +0 -0
- {finalcif-136 → finalcif-138}/install_requirements +0 -0
- {finalcif-136 → finalcif-138}/install_requirements.bat +0 -0
- {finalcif-136 → finalcif-138}/requirements.txt +0 -0
- {finalcif-136 → finalcif-138}/requirements_devel.txt +0 -0
- {finalcif-136 → finalcif-138}/requirements_doku.txt +0 -0
- {finalcif-136 → finalcif-138}/run_finalcif +0 -0
- {finalcif-136 → finalcif-138}/run_finalcif.bat +0 -0
- {finalcif-136 → finalcif-138}/screenshots/finalcif_checkcif.png +0 -0
- {finalcif-136 → finalcif-138}/screenshots/finalcif_details.png +0 -0
- {finalcif-136 → finalcif-138}/screenshots/finalcif_loops.png +0 -0
- {finalcif-136 → finalcif-138}/screenshots/finalcif_loops2.png +0 -0
- {finalcif-136 → finalcif-138}/screenshots/finalcif_main.png +0 -0
- {finalcif-136 → finalcif-138}/screenshots/finalcif_report.png +0 -0
- {finalcif-136 → finalcif-138}/screenshots/finalcif_responses.png +0 -0
- {finalcif-136 → finalcif-138}/update.exe +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: finalcif
|
|
3
|
-
Version:
|
|
3
|
+
Version: 138
|
|
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
|
|
@@ -11,7 +11,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
13
|
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
14
|
-
Requires-Python: >=3.
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
15
|
Requires-Dist: altgraph
|
|
16
16
|
Requires-Dist: certifi
|
|
17
17
|
Requires-Dist: chardet
|
|
@@ -13,18 +13,20 @@ from contextlib import suppress
|
|
|
13
13
|
from datetime import datetime
|
|
14
14
|
from math import sin, radians
|
|
15
15
|
from pathlib import Path, WindowsPath
|
|
16
|
-
from shutil import which
|
|
17
16
|
from typing import Union, Dict, Tuple, List, Optional
|
|
18
17
|
|
|
19
18
|
import gemmi.cif
|
|
20
|
-
import requests
|
|
21
|
-
from PyQt5 import QtCore, QtGui, QtWebEngineWidgets
|
|
19
|
+
import requests
|
|
20
|
+
from PyQt5 import QtCore, QtGui, QtWebEngineWidgets, QtWidgets
|
|
22
21
|
from PyQt5.QtCore import Qt, QEvent
|
|
23
|
-
from PyQt5.QtWidgets import QMainWindow, QShortcut, QCheckBox, QListWidgetItem, QApplication,
|
|
24
|
-
|
|
22
|
+
from PyQt5.QtWidgets import (QMainWindow, QShortcut, QCheckBox, QListWidgetItem, QApplication,
|
|
23
|
+
QPlainTextEdit, QFileDialog, QMessageBox, QScrollBar)
|
|
25
24
|
from gemmi import cif
|
|
26
25
|
|
|
27
26
|
from finalcif import VERSION
|
|
27
|
+
# QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
|
|
28
|
+
# QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
|
|
29
|
+
from finalcif.cif.checkcif.checkcif import MyHTMLParser, AlertHelp, CheckCif
|
|
28
30
|
from finalcif.cif.cif_file_io import CifContainer, GemmiError
|
|
29
31
|
from finalcif.cif.cod.deposit import CODdeposit
|
|
30
32
|
from finalcif.cif.text import utf8_to_str, quote
|
|
@@ -67,7 +69,6 @@ if app is None:
|
|
|
67
69
|
app = QApplication([])
|
|
68
70
|
with suppress(ImportError):
|
|
69
71
|
import qtawesome as qta
|
|
70
|
-
from finalcif.cif.checkcif.checkcif import MyHTMLParser, AlertHelp, CheckCif
|
|
71
72
|
|
|
72
73
|
|
|
73
74
|
class AppWindow(QMainWindow):
|
|
@@ -633,10 +634,9 @@ class AppWindow(QMainWindow):
|
|
|
633
634
|
|
|
634
635
|
def setTextEditSizes(self):
|
|
635
636
|
for ui in [self.ui.Spacegroup_top_LineEdit, self.ui.CCDCNumLineEdit, self.ui.SumFormMainLineEdit]:
|
|
636
|
-
ui.setFixedHeight(self.ui.appendCifPushButton.height()
|
|
637
|
-
ui.setFixedHeight(self.ui.appendCifPushButton.height() + 6)
|
|
638
|
-
ui.setFixedHeight(self.ui.appendCifPushButton.height() + 6)
|
|
637
|
+
ui.setFixedHeight(self.ui.appendCifPushButton.height())
|
|
639
638
|
vScrollBar = ui.verticalScrollBar()
|
|
639
|
+
# Scroll down a bit, or text will not be in the vertical center:
|
|
640
640
|
vScrollBar.triggerAction(QScrollBar.SliderSingleStepAdd)
|
|
641
641
|
|
|
642
642
|
def moveEvent(self, a0: QtGui.QMoveEvent) -> None:
|
|
@@ -1035,7 +1035,7 @@ class AppWindow(QMainWindow):
|
|
|
1035
1035
|
log_widget=self.ui.CheckCifLogPlainTextEdit,
|
|
1036
1036
|
output_widget=self.ui.CheckcifPlaintextEdit,
|
|
1037
1037
|
cif_file=self.cif.fileobj)
|
|
1038
|
-
if not Path(
|
|
1038
|
+
if runner.platon_exe is not None and not Path(runner.platon_exe).exists():
|
|
1039
1039
|
self.ui.CheckCifLogPlainTextEdit.setPlainText('\nPlaton executable not found!')
|
|
1040
1040
|
self.ui.CheckCifLogPlainTextEdit.appendPlainText(
|
|
1041
1041
|
'You can download Platon at http://www.platonsoft.nl/platon/\n')
|
|
@@ -1135,12 +1135,20 @@ class AppWindow(QMainWindow):
|
|
|
1135
1135
|
make_multi_tables(cif=self.cif, output_filename=str(multi_table_document))
|
|
1136
1136
|
else:
|
|
1137
1137
|
print('Report with templates')
|
|
1138
|
-
|
|
1139
|
-
ok =
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1138
|
+
template_path = Path(self.get_checked_templates_list_text())
|
|
1139
|
+
ok = False
|
|
1140
|
+
if template_path.suffix in ('.docx',):
|
|
1141
|
+
t = TemplatedReport(format=ReportFormat.RICHTEXT, options=self.options, cif=self.cif)
|
|
1142
|
+
ok = t.make_templated_docx_report(output_filename=str(report_filename),
|
|
1143
|
+
picfile=picfile,
|
|
1144
|
+
template_path=Path(self.get_checked_templates_list_text()))
|
|
1145
|
+
elif template_path.suffix in ('.html', '.tmpl'):
|
|
1146
|
+
t = TemplatedReport(format=ReportFormat.HTML, options=self.options, cif=self.cif)
|
|
1147
|
+
report_filename = report_filename.with_suffix('.html')
|
|
1148
|
+
ok = t.make_templated_html_report(output_filename=str(report_filename),
|
|
1149
|
+
picfile=picfile,
|
|
1150
|
+
template_path=template_path.parent,
|
|
1151
|
+
template_file=template_path.name)
|
|
1144
1152
|
if not ok:
|
|
1145
1153
|
return None
|
|
1146
1154
|
except FileNotFoundError as e:
|
|
@@ -1308,7 +1316,7 @@ class AppWindow(QMainWindow):
|
|
|
1308
1316
|
previous_values.append(loop2.values)
|
|
1309
1317
|
for loop in self.cif.loops:
|
|
1310
1318
|
if loop.values not in previous_values:
|
|
1311
|
-
changes_cif.add_loop_to_cif(loop_tags=loop.tags,
|
|
1319
|
+
changes_cif.add_loop_to_cif(loop_tags=loop.tags, row_values=loop.values)
|
|
1312
1320
|
changes_cif.save(filename=self.finalcif_changes_filename)
|
|
1313
1321
|
|
|
1314
1322
|
def get_changes_cif(self, finalcif_changes_filename: Path) -> CifContainer:
|
|
@@ -1336,7 +1344,7 @@ class AppWindow(QMainWindow):
|
|
|
1336
1344
|
self.add_row(key=key, value=value)
|
|
1337
1345
|
self.ui.cif_main_table.setText(key=key, column=Column.EDIT, color=None, txt=value)
|
|
1338
1346
|
for loop in changes.loops:
|
|
1339
|
-
self.cif.add_loop_to_cif(loop_tags=loop.tags,
|
|
1347
|
+
self.cif.add_loop_to_cif(loop_tags=loop.tags, row_values=loop.values)
|
|
1340
1348
|
return True
|
|
1341
1349
|
|
|
1342
1350
|
def is_row_a_cif_item(self, vhead: str) -> bool:
|
|
@@ -1513,6 +1521,7 @@ class AppWindow(QMainWindow):
|
|
|
1513
1521
|
raise
|
|
1514
1522
|
# unable_to_open_message(Path(self.cif.filename), not_ok)
|
|
1515
1523
|
self.load_recent_cifs_list()
|
|
1524
|
+
self.set_vertical_header_width()
|
|
1516
1525
|
if self.options.track_changes and load_changes:
|
|
1517
1526
|
changes_exist = False
|
|
1518
1527
|
if self.changes_cif_has_zero_size():
|
|
@@ -1557,6 +1566,16 @@ class AppWindow(QMainWindow):
|
|
|
1557
1566
|
t = QtCore.QTimer(self)
|
|
1558
1567
|
t.singleShot(1000, self.check_cecksums)
|
|
1559
1568
|
|
|
1569
|
+
def set_vertical_header_width(self):
|
|
1570
|
+
"""
|
|
1571
|
+
Sets the width of the vertical header to the length of the longest string in the list.
|
|
1572
|
+
"""
|
|
1573
|
+
vheader: QtWidgets.QHeaderView = self.ui.cif_main_table.verticalHeader()
|
|
1574
|
+
fm = QtGui.QFontMetrics(vheader.font(), self)
|
|
1575
|
+
# noinspection PyTypeChecker
|
|
1576
|
+
longest_string: str = max(self.ui.cif_main_table.vheaderitems, key=len)
|
|
1577
|
+
vheader.setMaximumWidth(fm.width(longest_string + 'O'))
|
|
1578
|
+
|
|
1560
1579
|
def changes_cif_has_values(self) -> bool:
|
|
1561
1580
|
try:
|
|
1562
1581
|
return not self.get_changes_cif(self.finalcif_changes_filename).is_empty()
|
|
@@ -21,6 +21,15 @@ def format_definition(definition: str):
|
|
|
21
21
|
return newdef
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
formats = {
|
|
25
|
+
'char' : 'string',
|
|
26
|
+
'uchar': 'case-insensitive string',
|
|
27
|
+
'numb' : 'number (int or float)',
|
|
28
|
+
'null' : '? (unknown)' or '. (not applicable)',
|
|
29
|
+
'' : '--'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
24
33
|
def process_cif_dict(cdic):
|
|
25
34
|
"""
|
|
26
35
|
Creates a dictionary with cif keywords as key and help text as value.
|
|
@@ -36,6 +45,7 @@ def process_cif_dict(cdic):
|
|
|
36
45
|
example_detail = item.get('_example_detail', '')
|
|
37
46
|
enumeration = item.get('_enumeration', '')
|
|
38
47
|
enumeration_detail = item.get('_enumeration_detail', '')
|
|
48
|
+
default = item.get('_enumeration_default', '')
|
|
39
49
|
if example:
|
|
40
50
|
if isinstance(example, list) and not enumeration_detail:
|
|
41
51
|
example = '\n'.join([str(x) for x in example])
|
|
@@ -52,15 +62,29 @@ def process_cif_dict(cdic):
|
|
|
52
62
|
["{}\n\t{}\n".format(str(x), str(y)) for x, y in zip(enumeration, enumeration_detail)])
|
|
53
63
|
enumeration = format_definition(escape(str(enumeration)))
|
|
54
64
|
definition = '{}\n\n<h3>Example:</h3>\n{}'.format(definition, enumeration)
|
|
65
|
+
type_format = item.get("_type", "")
|
|
66
|
+
enum_range = item.get('_enumeration_range', '')
|
|
55
67
|
if isinstance(name, list):
|
|
56
68
|
for n in name:
|
|
57
69
|
# For keys like 'atom_site_aniso_b_[]' where the name has several subnames:
|
|
58
|
-
alldic[n] =
|
|
70
|
+
alldic[n] = help_text(definition, n, type_format, enum_range, default)
|
|
59
71
|
else:
|
|
60
|
-
alldic[name] =
|
|
72
|
+
alldic[name] = help_text(definition, name, type_format, enum_range, default)
|
|
61
73
|
return alldic
|
|
62
74
|
|
|
63
75
|
|
|
76
|
+
def help_text(definition: str, name: str, type_format: str, enum_range: str, enum_default) -> str:
|
|
77
|
+
if enum_range.endswith(':'):
|
|
78
|
+
enum_range = enum_range + '∞'
|
|
79
|
+
limits = f'\n<br><p><h4>Limits:</h4> {enum_range} </p>'
|
|
80
|
+
default = f'\n<br><p><h4>Default:</h4> {enum_default} </p>'
|
|
81
|
+
return (f'<pre><h2>{name}</h2>{format_definition(definition)}</pre>'
|
|
82
|
+
f'\n<br><p><h4>Type:</h4> {formats.get(type_format, "")}</p>'
|
|
83
|
+
f'{limits if enum_range else ""}'
|
|
84
|
+
f'{default if enum_default else ""}'
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
64
88
|
def load_cif_as_dictionary(link, path_to_cif):
|
|
65
89
|
if not path_to_cif.exists():
|
|
66
90
|
get_dictionary_cif(link, path_to_cif)
|
|
@@ -13,6 +13,7 @@ from typing import Dict, List, Tuple, Union, Generator
|
|
|
13
13
|
|
|
14
14
|
import gemmi
|
|
15
15
|
from gemmi.cif import as_string, Document, Loop
|
|
16
|
+
from packaging.version import Version
|
|
16
17
|
from shelxfile import Shelxfile
|
|
17
18
|
|
|
18
19
|
from finalcif.cif.cif_order import order, special_keys
|
|
@@ -39,6 +40,8 @@ class CifContainer():
|
|
|
39
40
|
new_block: Create a new block (new file) if a name is given. Otherwise, just
|
|
40
41
|
the existing document is opened.
|
|
41
42
|
"""
|
|
43
|
+
self._hkl_file: str = ''
|
|
44
|
+
self._abs_hkl_details: Dict[str, str] = {}
|
|
42
45
|
if isinstance(file, str):
|
|
43
46
|
self.fileobj = Path(file)
|
|
44
47
|
elif isinstance(file, Path):
|
|
@@ -94,7 +97,7 @@ class CifContainer():
|
|
|
94
97
|
The suffix needs '-finalcif' in order to contain the finalcif ending.
|
|
95
98
|
"foo/bar/baz-finalcif.cif"
|
|
96
99
|
|
|
97
|
-
:param
|
|
100
|
+
:param force_strip: Forces to strip the filename also after the '-finalcif' string.
|
|
98
101
|
"""
|
|
99
102
|
file_witout_finalcif = strip_finalcif_of_name(Path(self.filename).stem, till_name_ends=force_strip)
|
|
100
103
|
filename = self.path_base.joinpath(Path(prefix + file_witout_finalcif + suffix))
|
|
@@ -141,7 +144,9 @@ class CifContainer():
|
|
|
141
144
|
|
|
142
145
|
@property
|
|
143
146
|
def hkl_extra_info(self):
|
|
144
|
-
|
|
147
|
+
if not self._abs_hkl_details:
|
|
148
|
+
self._abs_hkl_details = self._sadabs_hkl_details()
|
|
149
|
+
return self._abs_hkl_details
|
|
145
150
|
|
|
146
151
|
def check_hkl_min_max(self) -> None:
|
|
147
152
|
if not all([self['_diffrn_reflns_limit_h_min'], self['_diffrn_reflns_limit_h_max'],
|
|
@@ -198,8 +203,8 @@ class CifContainer():
|
|
|
198
203
|
"""
|
|
199
204
|
This method returns an empty string when the item value is '?'
|
|
200
205
|
"""
|
|
201
|
-
if self.block.find_value(item):
|
|
202
|
-
return as_string(
|
|
206
|
+
if value := self.block.find_value(item):
|
|
207
|
+
return as_string(value)
|
|
203
208
|
else:
|
|
204
209
|
return ''
|
|
205
210
|
|
|
@@ -255,15 +260,17 @@ class CifContainer():
|
|
|
255
260
|
print(f'File {filename} is empty.')
|
|
256
261
|
return
|
|
257
262
|
self.order_cif_keys()
|
|
258
|
-
print('Saving to', Path(filename).resolve())
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
263
|
+
print('Saving CIF to', Path(filename).resolve())
|
|
264
|
+
if Version(gemmi.__version__) > Version('0.6.3'):
|
|
265
|
+
options = gemmi.cif.WriteOptions()
|
|
266
|
+
options.prefer_pairs = False
|
|
267
|
+
options.compact = False
|
|
268
|
+
options.align_pairs = 33
|
|
269
|
+
options.align_loops = 15
|
|
270
|
+
options.misuse_hash = False
|
|
271
|
+
self.doc.write_file(str(filename), options=options)
|
|
272
|
+
else:
|
|
273
|
+
self.doc.write_file(str(filename), gemmi.cif.Style.Indent35)
|
|
267
274
|
|
|
268
275
|
def order_cif_keys(self) -> None:
|
|
269
276
|
"""
|
|
@@ -304,10 +311,14 @@ class CifContainer():
|
|
|
304
311
|
def hkl_file(self) -> str:
|
|
305
312
|
hkl_loop: Loop = self.get_loop('_diffrn_refln_index_h')
|
|
306
313
|
if hkl_loop and hkl_loop.width() > 4:
|
|
307
|
-
|
|
314
|
+
if not self._hkl_file:
|
|
315
|
+
self._hkl_file = self._hkl_from_cif_format(hkl_loop)
|
|
316
|
+
return self._hkl_file
|
|
308
317
|
else:
|
|
309
318
|
# returns an empty string if no cif hkl was found:
|
|
310
|
-
|
|
319
|
+
if not self._hkl_file:
|
|
320
|
+
self._hkl_file = self._hkl_from_shelx()
|
|
321
|
+
return self._hkl_file
|
|
311
322
|
|
|
312
323
|
def _hkl_from_cif_format(self, hkl_loop: Loop) -> str:
|
|
313
324
|
hkl_list = []
|
|
@@ -333,7 +344,7 @@ class CifContainer():
|
|
|
333
344
|
return ''
|
|
334
345
|
|
|
335
346
|
@property
|
|
336
|
-
def hkl_as_cif(self):
|
|
347
|
+
def hkl_as_cif(self) -> str:
|
|
337
348
|
return HKL(self.hkl_file, self.block.name, hklf_type=self.hklf_number).hkl_as_cif
|
|
338
349
|
|
|
339
350
|
@property
|
|
@@ -362,7 +373,7 @@ class CifContainer():
|
|
|
362
373
|
return self.hkl_file
|
|
363
374
|
|
|
364
375
|
@staticmethod
|
|
365
|
-
def _find_line_of_000(lines: str):
|
|
376
|
+
def _find_line_of_000(lines: str) -> int:
|
|
366
377
|
pattern = re.compile(r'^\s+0\s+0\s+0\s+0.*')
|
|
367
378
|
for num, line in enumerate(lines.splitlines(keepends=False)):
|
|
368
379
|
found = pattern.match(line)
|
|
@@ -370,7 +381,7 @@ class CifContainer():
|
|
|
370
381
|
return num
|
|
371
382
|
return 0
|
|
372
383
|
|
|
373
|
-
def
|
|
384
|
+
def _sadabs_hkl_details(self) -> Dict[str, str]:
|
|
374
385
|
"""
|
|
375
386
|
This method tries to determine the information witten at the end of a cif hkl file by sadabs.
|
|
376
387
|
"""
|
|
@@ -411,7 +422,7 @@ class CifContainer():
|
|
|
411
422
|
all_sadabs_items[key] = gemmi.cif.as_string(val).strip()
|
|
412
423
|
return all_sadabs_items
|
|
413
424
|
|
|
414
|
-
def normal_search(self, hkl):
|
|
425
|
+
def normal_search(self, hkl) -> int:
|
|
415
426
|
pattern = re.compile(r'\s+0\s+0\s+0\s+0')
|
|
416
427
|
found = pattern.search(hkl)
|
|
417
428
|
if found:
|
|
@@ -420,7 +431,7 @@ class CifContainer():
|
|
|
420
431
|
zero_reflection_position = 0
|
|
421
432
|
return zero_reflection_position
|
|
422
433
|
|
|
423
|
-
def reversed_search(self, hkl_splitted: List):
|
|
434
|
+
def reversed_search(self, hkl_splitted: List[str]) -> int:
|
|
424
435
|
pattern = re.compile(r'\s+0\s+0\s+0\s+0')
|
|
425
436
|
zero_reflection_position = 0
|
|
426
437
|
for num, line in enumerate(reversed(hkl_splitted)):
|
|
@@ -463,14 +474,20 @@ class CifContainer():
|
|
|
463
474
|
loops.append(b.loop)
|
|
464
475
|
return loops
|
|
465
476
|
|
|
466
|
-
def add_loop_to_cif(self, loop_tags: List[str],
|
|
477
|
+
def add_loop_to_cif(self, loop_tags: List[str], row_values: Union[List[str], Tuple[str]]) -> gemmi.cif.Loop:
|
|
467
478
|
gemmi_loop = self.init_loop(loop_tags)
|
|
468
|
-
for row in list(grouper(
|
|
479
|
+
for row in list(grouper(row_values, len(loop_tags))):
|
|
469
480
|
gemmi_loop.add_row(row)
|
|
470
481
|
return gemmi_loop
|
|
471
482
|
|
|
483
|
+
def add_loop_from_columns(self, loop_tags: List[str],
|
|
484
|
+
column_values: Union[List[List[str]], Tuple[Tuple[str]]]) -> gemmi.cif.Loop:
|
|
485
|
+
gemmi_loop = self.init_loop(loop_tags)
|
|
486
|
+
gemmi_loop.set_all_values(column_values)
|
|
487
|
+
return gemmi_loop
|
|
488
|
+
|
|
472
489
|
@property
|
|
473
|
-
def n_loops(self):
|
|
490
|
+
def n_loops(self) -> int:
|
|
474
491
|
return len(self.loops)
|
|
475
492
|
|
|
476
493
|
def get_loop(self, key_in_loop: str) -> gemmi.cif.Loop:
|
|
@@ -483,7 +500,7 @@ class CifContainer():
|
|
|
483
500
|
return self.block.init_loop('', loop_keywords)
|
|
484
501
|
|
|
485
502
|
@property
|
|
486
|
-
def z_value(self):
|
|
503
|
+
def z_value(self) -> float:
|
|
487
504
|
return self.atomic_struct.cell.volume / self.atomic_struct.cell.volume_per_image()
|
|
488
505
|
|
|
489
506
|
@property
|
|
@@ -638,7 +655,7 @@ class CifContainer():
|
|
|
638
655
|
@property
|
|
639
656
|
def is_centrosymm(self) -> bool:
|
|
640
657
|
"""
|
|
641
|
-
Whether a
|
|
658
|
+
Whether a structure is centrosymmetric or not.
|
|
642
659
|
"""
|
|
643
660
|
if not self.symmops or self.symmops == ['']:
|
|
644
661
|
# Do not crash without symmops
|
|
@@ -749,8 +766,7 @@ class CifContainer():
|
|
|
749
766
|
publ_loop = self.block.find_loop('_geom_bond_publ_flag')
|
|
750
767
|
bond = namedtuple('bond', ('label1', 'label2', 'dist', 'symm'))
|
|
751
768
|
for label1, label2, dist, symm, publ in zip(label1, label2, dist, symm, publ_loop):
|
|
752
|
-
if without_h and (self.ishydrogen(label1) or self.ishydrogen(label2)) or
|
|
753
|
-
self.yes_not_set(publ, self._has_publ_flag_set(publ_loop)):
|
|
769
|
+
if (without_h and (self.ishydrogen(label1) or self.ishydrogen(label2)) or self.yes_not_set(publ)):
|
|
754
770
|
continue
|
|
755
771
|
else:
|
|
756
772
|
yield bond(label1=label1, label2=label2, dist=dist, symm=self.checksymm(symm))
|
|
@@ -773,9 +789,6 @@ class CifContainer():
|
|
|
773
789
|
return p.torsang
|
|
774
790
|
return None
|
|
775
791
|
|
|
776
|
-
def _has_publ_flag_set(self, publ_loop: gemmi.cif.Column) -> bool:
|
|
777
|
-
return any([x[0].lower() == 'y' for x in list(publ_loop) if x])
|
|
778
|
-
|
|
779
792
|
def angles(self, without_H: bool = False) -> Generator:
|
|
780
793
|
label1 = self.block.find_loop('_geom_angle_atom_site_label_1')
|
|
781
794
|
label2 = self.block.find_loop('_geom_angle_atom_site_label_2')
|
|
@@ -787,9 +800,8 @@ class CifContainer():
|
|
|
787
800
|
angle = namedtuple('angle', ('label1', 'label2', 'label3', 'angle_val', 'symm1', 'symm2'))
|
|
788
801
|
for label1, label2, label3, angle_val, symm1, symm2, publ in \
|
|
789
802
|
zip(label1, label2, label3, angle_val, symm1, symm2, publ_loop):
|
|
790
|
-
if without_H and (
|
|
791
|
-
|
|
792
|
-
self.yes_not_set(publ, self._has_publ_flag_set(publ_loop)):
|
|
803
|
+
if (without_H and (self.ishydrogen(label1) or self.ishydrogen(label2) or
|
|
804
|
+
self.ishydrogen(label3)) or (self.yes_not_set(publ))):
|
|
793
805
|
continue
|
|
794
806
|
else:
|
|
795
807
|
yield angle(label1=label1, label2=label2, label3=label3, angle_val=angle_val,
|
|
@@ -837,9 +849,8 @@ class CifContainer():
|
|
|
837
849
|
torsang, symm1, symm2,
|
|
838
850
|
symm3,
|
|
839
851
|
symm4, publ_loop):
|
|
840
|
-
if without_h and (self.ishydrogen(label1) or self.ishydrogen(label2)
|
|
841
|
-
or self.ishydrogen(label3) or self.ishydrogen(label3)) or
|
|
842
|
-
self.yes_not_set(publ, self._has_publ_flag_set(publ_loop)):
|
|
852
|
+
if (without_h and (self.ishydrogen(label1) or self.ishydrogen(label2)
|
|
853
|
+
or self.ishydrogen(label3) or self.ishydrogen(label3)) or self.yes_not_set(publ)):
|
|
843
854
|
continue
|
|
844
855
|
yield tors(label1=label1, label2=label2, label3=label3, label4=label4, torsang=torsang,
|
|
845
856
|
symm1=self.checksymm(symm1),
|
|
@@ -859,14 +870,14 @@ class CifContainer():
|
|
|
859
870
|
publ_loop = self.block.find_loop('_geom_hbond_publ_flag')
|
|
860
871
|
hydr = namedtuple('HydrogenBond', ('label_d', 'label_h', 'label_a', 'dist_dh', 'dist_ha', 'dist_da',
|
|
861
872
|
'angle_dha', 'symm'))
|
|
862
|
-
for label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ in
|
|
863
|
-
zip(label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ_loop):
|
|
864
|
-
if self.yes_not_set(publ
|
|
873
|
+
for label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ in (
|
|
874
|
+
zip(label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ_loop)):
|
|
875
|
+
if self.yes_not_set(publ):
|
|
865
876
|
continue
|
|
866
877
|
yield hydr(label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, self.checksymm(symm))
|
|
867
878
|
|
|
868
|
-
def yes_not_set(self, publ: str
|
|
869
|
-
return
|
|
879
|
+
def yes_not_set(self, publ: str):
|
|
880
|
+
return publ not in {'y', 'yes', '?', '.'} or publ in {'n', 'no'}
|
|
870
881
|
|
|
871
882
|
def key_value_pairs(self) -> List[Tuple[str, str]]:
|
|
872
883
|
"""
|
|
@@ -957,7 +968,6 @@ class CifContainer():
|
|
|
957
968
|
if __name__ == '__main__':
|
|
958
969
|
# c = CifContainer('../41467_2015.cif')
|
|
959
970
|
# c = CifContainer('test-data/p21c.cif')
|
|
960
|
-
from pprint import pp
|
|
961
971
|
|
|
962
972
|
c = CifContainer('test-data/DK_Zucker2_0m.cif')
|
|
963
973
|
c.load_this_block(len(c.doc) - 1)
|
|
@@ -17,6 +17,13 @@ special_keys = ['_iucr_refine_instructions_details',
|
|
|
17
17
|
]
|
|
18
18
|
|
|
19
19
|
order = [
|
|
20
|
+
'_audit_update_record',
|
|
21
|
+
'_audit_contact_author',
|
|
22
|
+
'_audit_contact_author_name',
|
|
23
|
+
'_audit_contact_author_phone',
|
|
24
|
+
'_audit_contact_author_email',
|
|
25
|
+
'_audit_contact_author_fax',
|
|
26
|
+
'_audit_contact_author_address',
|
|
20
27
|
'_audit_author_id',
|
|
21
28
|
'_audit_author_id_audit',
|
|
22
29
|
'_audit_author_name',
|
|
@@ -128,7 +135,6 @@ order = [
|
|
|
128
135
|
'_publ_contact_author_id_orcid',
|
|
129
136
|
'_publ_contact_author_footnote',
|
|
130
137
|
|
|
131
|
-
|
|
132
138
|
'_shelx_SHELXL_version_number',
|
|
133
139
|
'_chemical_name_systematic',
|
|
134
140
|
'_chemical_name_common',
|
|
@@ -341,4 +347,17 @@ order = [
|
|
|
341
347
|
'_geom_details',
|
|
342
348
|
'_geom_special_details',
|
|
343
349
|
|
|
350
|
+
'_bruker_diffrn_runs_wavelength',
|
|
351
|
+
'_bruker_diffrn_runs_temperature',
|
|
352
|
+
'_bruker_diffrn_runs_current',
|
|
353
|
+
'_bruker_diffrn_runs_voltage',
|
|
354
|
+
'_bruker_diffrn_runs_images',
|
|
355
|
+
'_bruker_diffrn_runs_time',
|
|
356
|
+
'_bruker_diffrn_runs_width',
|
|
357
|
+
'_bruker_diffrn_runs_axis',
|
|
358
|
+
'_bruker_diffrn_runs_chi',
|
|
359
|
+
'_bruker_diffrn_runs_phi',
|
|
360
|
+
'_bruker_diffrn_runs_omega',
|
|
361
|
+
'_bruker_diffrn_runs_theta',
|
|
362
|
+
'_bruker_diffrn_runs_distance',
|
|
344
363
|
]
|