finalcif 177__tar.gz → 178__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-178/LICENSE.md +5 -0
- {finalcif-177 → finalcif-178}/PKG-INFO +5 -8
- {finalcif-177 → finalcif-178}/README.md +2 -4
- finalcif-178/finalcif/__init__.py +3 -0
- {finalcif-177 → finalcif-178}/finalcif/appwindow.py +20 -17
- {finalcif-177 → finalcif-178}/finalcif/report/references.py +0 -117
- {finalcif-177 → finalcif-178}/finalcif/report/report_text.py +1 -50
- {finalcif-177 → finalcif-178}/finalcif/report/templated_report.py +35 -13
- {finalcif-177 → finalcif-178}/finalcif/template/report.tmpl +9 -4
- finalcif-178/finalcif/template/report_default.docx +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/report_fastmolwidget.tmpl +9 -4
- finalcif-178/finalcif/template/template_for_multitable.docx +0 -0
- finalcif-178/finalcif/template/template_text.docx +0 -0
- finalcif-178/finalcif/template/template_without_text.docx +0 -0
- finalcif-178/githooks/pre-push +76 -0
- {finalcif-177 → finalcif-178}/pyproject.toml +4 -3
- {finalcif-177 → finalcif-178}/uv.lock +198 -190
- finalcif-177/LICENSE +0 -7
- finalcif-177/finalcif/__init__.py +0 -3
- finalcif-177/finalcif/report/mtools.py +0 -43
- finalcif-177/finalcif/report/tables.py +0 -965
- finalcif-177/finalcif/template/report_default.docx +0 -0
- finalcif-177/finalcif/template/template_for_multitable.docx +0 -0
- finalcif-177/finalcif/template/template_text.docx +0 -0
- finalcif-177/finalcif/template/template_without_text.docx +0 -0
- {finalcif-177 → finalcif-178}/.gitattributes +0 -0
- {finalcif-177 → finalcif-178}/.githooks/pre-push +0 -0
- {finalcif-177 → finalcif-178}/.gitignore +0 -0
- {finalcif-177 → finalcif-178}/.python-version +0 -0
- {finalcif-177 → finalcif-178}/.ruff.toml +0 -0
- {finalcif-177 → finalcif-178}/.run/Make Documentation MAC.run.xml +0 -0
- {finalcif-177 → finalcif-178}/.run/compile_ui_files.run.xml +0 -0
- {finalcif-177 → finalcif-178}/.run/make documentation Windows.run.xml +0 -0
- {finalcif-177 → finalcif-178}/AGENTS.md +0 -0
- {finalcif-177 → finalcif-178}/CODE_OF_CONDUCT.md +0 -0
- {finalcif-177 → finalcif-178}/CONTRIBUTING.md +0 -0
- {finalcif-177 → finalcif-178}/Finalcif_installer_win.spec +0 -0
- {finalcif-177 → finalcif-178}/Finalcif_linux_onefile.spec +0 -0
- {finalcif-177 → finalcif-178}/Finalcif_mac.spec +0 -0
- {finalcif-177 → finalcif-178}/finalcif/app_path.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/all_cif_dicts.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/atoms.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/checkcif/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/checkcif/checkcif.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cif_dict_foo.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cif_file_io.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cif_keyword_mapping.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cif_order.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cod/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cod/deposit.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cod/deposit_check.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cod/deposition_list.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cod/doi.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cod/upload.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/cod/website_parser.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/core_dict.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/hkl.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/modulation_dict.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/powder_dict.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/reference.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/restraints_dict.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/text.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/twin_dict.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/cif/vrf_entry.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/ciforder/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/ciforder/order.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/ciforder/order_ui.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/ciforder/order_ui.ui +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/bruker_data.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/bruker_frame.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/ccdc_mail.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/data.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/p4p_reader.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/sadabs.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/saint.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/shelx_lst.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/datafiles/utils.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/equip_property/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/equip_property/author_loop_templates.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/equip_property/equipment.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/equip_property/properties.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/equip_property/tools.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/finalcif_start.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/block_combobox.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/checkcif_browser.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/cif_table_model.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/cif_table_view.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/combobox.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/custom_classes.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/dialogs.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/edit_button.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/equipmenttable.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/file_editor.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/finalcif_gui_ui.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/finalcif_gui_ui.ui +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/import_selector.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/import_selector_ui.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/import_selector_ui.ui +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/loop_creator.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/loop_creator_ui.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/loop_creator_ui.ui +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/loops.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/mainstackwidget.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/mixins.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/new_key_dialog.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/new_key_dialog_ui.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/new_key_dialog_ui.ui +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/plaintextedit.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/playground.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/propertytable.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/shelx_navigation.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/single_line_textedit.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/spell_check_edit.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/squeeze_dialog.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/syntax_highlighter.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/text_templates_ui.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/text_templates_ui.ui +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/text_value_editor.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/timers.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/validators.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/vrf_classes.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/gui/vzs_viewer.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/icon/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/icon/finalcif.png +0 -0
- {finalcif-177 → finalcif-178}/finalcif/icon/finalcif2.ico +0 -0
- {finalcif-177 → finalcif-178}/finalcif/icon/finalcif2.png +0 -0
- {finalcif-177 → finalcif-178}/finalcif/icon/multitable.ico +0 -0
- {finalcif-177 → finalcif-178}/finalcif/icon/multitable.png +0 -0
- {finalcif-177 → finalcif-178}/finalcif/icon/multitable.xcf +0 -0
- {finalcif-177 → finalcif-178}/finalcif/report/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/report/archive_report.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/report/gui/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/report/gui/mainwindow.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/report/gui/mainwindow.ui +0 -0
- {finalcif-177 → finalcif-178}/finalcif/report/symm.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/bootstrap/bootstrap.min.css +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/machines/D8_VENTURE.cif +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/mathml2omml.xsl +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/miew/LICENSES +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/miew/Miew.css +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/miew/Miew.min.js +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/miew/lodash.min.js +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/miew/three.js +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/report.tex +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/report2.tex +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/template1.docx +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/templates.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/FakePlasTeX/FakeContext.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/FakePlasTeX/FakeTokenizer.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/FakePlasTeX/README.md +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/FakePlasTeX/TokenizerPassThru.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/LICENSE +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/u2l.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/unicode-math-table.tex +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/unicode2latex/unicode-math-xetex.sty +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/xsl/convert.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/xsl/xmltohtml.xsl +0 -0
- {finalcif-177 → finalcif-178}/finalcif/template/xsl/xmltolatex.xsl +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/__init__.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/chemparse.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/download.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/dsrmath.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/formal_charge.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/misc.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/mol_file_writer.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/options.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/platon.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/pupdate.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/selfupdate.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/settings.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/shred.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/solvents.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/space_groups.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/spgr_format.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/squeeze.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/statusbar.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/sumformula.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif/tools/z_from_packing.py +0 -0
- {finalcif-177 → finalcif-178}/finalcif.exe +0 -0
- {finalcif-177 → finalcif-178}/platon/README.txt +0 -0
- {finalcif-177 → finalcif-178}/platon/compile_platon.bat +0 -0
- {finalcif-177 → finalcif-178}/platon/platon_special.exe +0 -0
- {finalcif-177 → finalcif-178}/platon/platon_special.f +0 -0
- {finalcif-177 → finalcif-178}/pylock.toml +0 -0
- {finalcif-177 → finalcif-178}/run_and_capture.py +0 -0
- {finalcif-177 → finalcif-178}/run_finalcif +0 -0
- {finalcif-177 → finalcif-178}/run_finalcif.bat +0 -0
- {finalcif-177 → finalcif-178}/screenshots/finalcif_checkcif.png +0 -0
- {finalcif-177 → finalcif-178}/screenshots/finalcif_details.png +0 -0
- {finalcif-177 → finalcif-178}/screenshots/finalcif_loops.png +0 -0
- {finalcif-177 → finalcif-178}/screenshots/finalcif_loops2.png +0 -0
- {finalcif-177 → finalcif-178}/screenshots/finalcif_main.png +0 -0
- {finalcif-177 → finalcif-178}/screenshots/finalcif_report.png +0 -0
- {finalcif-177 → finalcif-178}/screenshots/finalcif_responses.png +0 -0
- {finalcif-177 → finalcif-178}/screenshots/loops_column_buttons.png +0 -0
- {finalcif-177 → finalcif-178}/work/compare_z_platon.py +0 -0
- {finalcif-177 → finalcif-178}/work/diagnose_1519506.py +0 -0
- {finalcif-177 → finalcif-178}/work/diagnose_z.py +0 -0
- {finalcif-177 → finalcif-178}/work/investigate_failures.py +0 -0
- {finalcif-177 → finalcif-178}/work/validate_cod.py +0 -0
- {finalcif-177 → finalcif-178}/work/validate_zprime.py +0 -0
finalcif-178/LICENSE.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"THE BEER-WARE LICENSE" (Revision 42):
|
|
2
|
+
Daniel Kratzert, dkratzert@gmx.de wrote this file. As long as you retain
|
|
3
|
+
this notice you can do whatever you want with this stuff. If we meet some day,
|
|
4
|
+
and you think this stuff is worth it, you can buy me a beer in return.
|
|
5
|
+
Dr. Daniel Kratzert
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: finalcif
|
|
3
|
-
Version:
|
|
3
|
+
Version: 178
|
|
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
|
|
7
7
|
Author-email: Daniel Kratzert <dkratzert@gmx.de>
|
|
8
|
-
License-
|
|
8
|
+
License-Expression: Beerware
|
|
9
|
+
License-File: LICENSE.md
|
|
9
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
-
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
|
|
@@ -33,16 +33,13 @@ Requires-Dist: qtpy
|
|
|
33
33
|
Requires-Dist: requests
|
|
34
34
|
Requires-Dist: shelxfile>=24
|
|
35
35
|
Requires-Dist: urllib3==2.7.0
|
|
36
|
-
Requires-Dist: wheel==0.47.0
|
|
37
36
|
Description-Content-Type: text/markdown
|
|
38
37
|
|
|
39
38
|

|
|
40
39
|
[](https://github.com/dkratzert/FinalCif/actions/workflows/python_tests.yml)
|
|
41
40
|

|
|
42
|
-
[](https://pypi.org/project/finalcif/)
|
|
42
|
+
|
|
46
43
|
|
|
47
44
|
|
|
48
45
|
# FinalCif
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|

|
|
2
2
|
[](https://github.com/dkratzert/FinalCif/actions/workflows/python_tests.yml)
|
|
3
3
|

|
|
4
|
-
[](https://pypi.org/project/finalcif/)
|
|
5
|
+
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
# FinalCif
|
|
@@ -21,7 +21,6 @@ from math import sin, radians
|
|
|
21
21
|
from pathlib import Path, WindowsPath
|
|
22
22
|
from typing import cast, TYPE_CHECKING
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
if TYPE_CHECKING:
|
|
26
25
|
from finalcif.cif.checkcif.checkcif import MyHTMLParser
|
|
27
26
|
|
|
@@ -1625,7 +1624,6 @@ class AppWindow(QMainWindow):
|
|
|
1625
1624
|
"""
|
|
1626
1625
|
Generates a report document.
|
|
1627
1626
|
"""
|
|
1628
|
-
from finalcif.report.tables import make_multi_tables
|
|
1629
1627
|
from finalcif.report.templated_report import ReportFormat, TemplatedReport
|
|
1630
1628
|
from docx.image.exceptions import UnrecognizedImageError
|
|
1631
1629
|
current_block = self.ui.datanameComboBox.currentIndex()
|
|
@@ -1638,7 +1636,7 @@ class AppWindow(QMainWindow):
|
|
|
1638
1636
|
return None
|
|
1639
1637
|
self.load_cif_file(self.cif.finalcif_file, block=current_block, load_changes=False)
|
|
1640
1638
|
report_filename = self.cif.finalcif_file_prefixed(prefix='report_', suffix='-finalcif.docx')
|
|
1641
|
-
multi_table_document
|
|
1639
|
+
multi_table_document: Path | None = None
|
|
1642
1640
|
self.cif.picometer = self.options.use_picometers
|
|
1643
1641
|
# The picture after the header:
|
|
1644
1642
|
if self.report_picture_path:
|
|
@@ -1652,9 +1650,12 @@ class AppWindow(QMainWindow):
|
|
|
1652
1650
|
if template_path.suffix in ('.docx',):
|
|
1653
1651
|
t = TemplatedReport(format=ReportFormat.RICHTEXT, options=self.options, cif=self.cif)
|
|
1654
1652
|
ok = t.make_templated_docx_report(output_filename=str(report_filename),
|
|
1655
|
-
template_path=
|
|
1656
|
-
if self.cif.is_multi_cif and self.cif.doc[0].name != 'global'
|
|
1657
|
-
|
|
1653
|
+
template_path=template_path)
|
|
1654
|
+
if (ok and self.cif.is_multi_cif and self.cif.doc[0].name != 'global'
|
|
1655
|
+
and not t.is_multi_cif_template):
|
|
1656
|
+
multi_table_document = self.cif.finalcif_file_prefixed(prefix='', suffix='-multitable.docx')
|
|
1657
|
+
ok = t.make_templated_docx_report(output_filename=str(multi_table_document),
|
|
1658
|
+
template_path=application_path / 'template' / 'template_for_multitable.docx')
|
|
1658
1659
|
elif template_path.suffix in ('.html', '.tmpl'):
|
|
1659
1660
|
t = TemplatedReport(format=ReportFormat.HTML, options=self.options, cif=self.cif)
|
|
1660
1661
|
report_filename = report_filename.with_suffix('.html')
|
|
@@ -1687,16 +1688,16 @@ class AppWindow(QMainWindow):
|
|
|
1687
1688
|
if DEBUG:
|
|
1688
1689
|
print('dbg> Unrecognized image error')
|
|
1689
1690
|
raise
|
|
1690
|
-
show_general_warning(self,'The report contains an unrecognized image format.')
|
|
1691
|
+
show_general_warning(self, 'The report contains an unrecognized image format.')
|
|
1691
1692
|
return None
|
|
1692
1693
|
if not self.running_inside_unit_test:
|
|
1693
1694
|
self.open_report_document(report_filename, multi_table_document)
|
|
1694
1695
|
# Save report and other files to a zip file:
|
|
1695
|
-
self.zip_report(report_filename)
|
|
1696
|
+
self.zip_report(report_filename, multi_table_document)
|
|
1696
1697
|
return None
|
|
1697
1698
|
return None
|
|
1698
1699
|
|
|
1699
|
-
def zip_report(self, report_filename: Path) -> None:
|
|
1700
|
+
def zip_report(self, report_filename: Path, multi_table_document: Path | None = None) -> None:
|
|
1700
1701
|
from finalcif.report.archive_report import ArchiveReport
|
|
1701
1702
|
zipfile = self.cif.finalcif_file.with_suffix('.zip')
|
|
1702
1703
|
if zipfile.exists():
|
|
@@ -1711,16 +1712,16 @@ class AppWindow(QMainWindow):
|
|
|
1711
1712
|
with suppress(Exception):
|
|
1712
1713
|
pdfname = self.cif.finalcif_file_prefixed(prefix='checkcif-', suffix='-finalcif.pdf')
|
|
1713
1714
|
arc.zip.write(filename=pdfname, arcname=pdfname.name)
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1715
|
+
if multi_table_document is not None:
|
|
1716
|
+
with suppress(Exception):
|
|
1717
|
+
arc.zip.write(filename=multi_table_document, arcname=multi_table_document.name)
|
|
1717
1718
|
with suppress(Exception):
|
|
1718
1719
|
prp_list = self.cif.finalcif_file.parent.glob('*.prp')
|
|
1719
1720
|
sorted_prp = sorted(prp_list, key=lambda x: x.stat().st_mtime)
|
|
1720
1721
|
arc.zip.write(filename=sorted_prp[-1], arcname=sorted_prp[-1].name)
|
|
1721
1722
|
|
|
1722
|
-
def open_report_document(self, report_filename: Path, multi_table_document: Path) -> None:
|
|
1723
|
-
if
|
|
1723
|
+
def open_report_document(self, report_filename: Path, multi_table_document: Path | None = None) -> None:
|
|
1724
|
+
if multi_table_document is not None:
|
|
1724
1725
|
open_file(multi_table_document)
|
|
1725
1726
|
open_file(report_filename)
|
|
1726
1727
|
|
|
@@ -2295,16 +2296,18 @@ class AppWindow(QMainWindow):
|
|
|
2295
2296
|
d = 0.0
|
|
2296
2297
|
self.ui.numRestraintsLineEdit.setText(self.cif['_refine_ls_number_restraints'])
|
|
2297
2298
|
self.ui.thetaMaxLineEdit.setText(thetamax)
|
|
2298
|
-
self.
|
|
2299
|
+
theta_full = self.cif['_diffrn_reflns_theta_full']
|
|
2300
|
+
self.ui.thetaFullLineEdit.setText(theta_full)
|
|
2299
2301
|
self.ui.dLineEdit.setText(f"{d:5.3f}")
|
|
2300
2302
|
try:
|
|
2301
|
-
|
|
2303
|
+
fraction = self.cif['_diffrn_measured_fraction_theta_full']
|
|
2304
|
+
compl = float(fraction) * 100
|
|
2302
2305
|
if not compl:
|
|
2303
2306
|
compl = 0.0
|
|
2304
2307
|
except (TypeError, ValueError):
|
|
2305
2308
|
compl = 0.0
|
|
2306
2309
|
try:
|
|
2307
|
-
self.ui.completeLineEdit.setText(f"{compl:<5.1f}")
|
|
2310
|
+
self.ui.completeLineEdit.setText(f"{compl:<5.1f} (at {theta_full}°)")
|
|
2308
2311
|
except ValueError:
|
|
2309
2312
|
pass
|
|
2310
2313
|
self.ui.wavelengthLineEdit.setText(f"{wavelen}")
|
|
@@ -5,10 +5,6 @@
|
|
|
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
|
-
from contextlib import suppress
|
|
9
|
-
from typing import Union
|
|
10
|
-
|
|
11
|
-
from docx.text.paragraph import Paragraph
|
|
12
8
|
from docxtpl import RichText
|
|
13
9
|
|
|
14
10
|
from finalcif import VERSION
|
|
@@ -43,89 +39,6 @@ Missing: d*trek
|
|
|
43
39
|
"""
|
|
44
40
|
|
|
45
41
|
|
|
46
|
-
class ReferenceList:
|
|
47
|
-
"""
|
|
48
|
-
This reference list holds a list of all used references. During each self.append(Reference()), a new reference is
|
|
49
|
-
appended to the list.
|
|
50
|
-
At the end of the document, a numbered list of references can be generated with self.make_make_literature_list().
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
def __init__(self, paragraph: Paragraph):
|
|
54
|
-
self.paragraph = paragraph
|
|
55
|
-
self._references = []
|
|
56
|
-
|
|
57
|
-
def append(self, ref: Union[list['Reference'], tuple['Reference'], 'Reference']) -> None:
|
|
58
|
-
"""Adds a superscript list of reference numbers in brackets to the document."""
|
|
59
|
-
if isinstance(ref, list | tuple):
|
|
60
|
-
if not ref:
|
|
61
|
-
return None
|
|
62
|
-
self._append_list(ref)
|
|
63
|
-
else:
|
|
64
|
-
if ref not in self._references:
|
|
65
|
-
self._references.append(ref)
|
|
66
|
-
self.paragraph.add_run(f'[{self._references.index(ref) + 1}]').font.superscript = True
|
|
67
|
-
# better not here:
|
|
68
|
-
# self.paragraph.add_run(' ')
|
|
69
|
-
|
|
70
|
-
def _append_list(self, reflist: list) -> None:
|
|
71
|
-
reflst_long = []
|
|
72
|
-
self.paragraph.add_run('[').font.superscript = True
|
|
73
|
-
reflist = [x for x in reflist if x]
|
|
74
|
-
for n, ref in enumerate(reflist):
|
|
75
|
-
if ref not in self._references:
|
|
76
|
-
self._references.append(ref)
|
|
77
|
-
refnum = self._references.index(ref) + 1
|
|
78
|
-
reflst_long.append(refnum)
|
|
79
|
-
reftxt = self.get_sequence(reflst_long)
|
|
80
|
-
self.paragraph.add_run(reftxt).font.superscript = True
|
|
81
|
-
self.paragraph.add_run(']').font.superscript = True
|
|
82
|
-
|
|
83
|
-
@staticmethod
|
|
84
|
-
def get_sequence(stringlist: list[int]) -> str:
|
|
85
|
-
"""
|
|
86
|
-
Converts a list of numbers into a string of numbers where recurring sequences
|
|
87
|
-
are described with a range.
|
|
88
|
-
|
|
89
|
-
>>> ReferenceList.get_sequence([1, 3, 4, 5, 6, 8, 11])
|
|
90
|
-
'1,3-6,8,11'
|
|
91
|
-
"""
|
|
92
|
-
folg = []
|
|
93
|
-
start = 0
|
|
94
|
-
for n, val in enumerate(stringlist):
|
|
95
|
-
val = int(val)
|
|
96
|
-
nextval = 0
|
|
97
|
-
with suppress(IndexError):
|
|
98
|
-
nextval = int(stringlist[n + 1])
|
|
99
|
-
nextnext = 0
|
|
100
|
-
with suppress(IndexError):
|
|
101
|
-
nextnext = int(stringlist[n + 2])
|
|
102
|
-
# a sequence starts:
|
|
103
|
-
if nextnext == val + 2 and not start:
|
|
104
|
-
start = val
|
|
105
|
-
# in a sequence and next value is not +1 -> squence ends with val:
|
|
106
|
-
if start and nextval != val + 1:
|
|
107
|
-
folg.append(f'{start}-{val}')
|
|
108
|
-
start = 0
|
|
109
|
-
continue
|
|
110
|
-
# everything outside a sequence:
|
|
111
|
-
if not start:
|
|
112
|
-
folg.append(val)
|
|
113
|
-
return ','.join([str(x) for x in folg])
|
|
114
|
-
|
|
115
|
-
def make_literature_list(self, document):
|
|
116
|
-
if len(self._references) < 10:
|
|
117
|
-
template = 'references_ni'
|
|
118
|
-
else:
|
|
119
|
-
template = 'references'
|
|
120
|
-
for num, ref in enumerate(self._references, 1):
|
|
121
|
-
paragraph_reflist = document.add_paragraph('', template)
|
|
122
|
-
paragraph_reflist.add_run(f'[{num!s}] \t')
|
|
123
|
-
ref.add_reference(paragraph_reflist)
|
|
124
|
-
|
|
125
|
-
def __repr__(self):
|
|
126
|
-
return '\n'.join([f'[{num}] {x}' for num, x in enumerate(self._references)])
|
|
127
|
-
|
|
128
|
-
|
|
129
42
|
class Reference:
|
|
130
43
|
def __init__(self):
|
|
131
44
|
self.authors = ''
|
|
@@ -137,31 +50,6 @@ class Reference:
|
|
|
137
50
|
self.program = ''
|
|
138
51
|
self.count = 0
|
|
139
52
|
|
|
140
|
-
def add_reference(self, p: Paragraph) -> None:
|
|
141
|
-
if self.authors:
|
|
142
|
-
p.add_run(self.authors)
|
|
143
|
-
p.add_run(', ')
|
|
144
|
-
if self.journal:
|
|
145
|
-
p.add_run(self.journal).italic = True
|
|
146
|
-
if not self.journal.endswith('.'):
|
|
147
|
-
p.add_run(', ')
|
|
148
|
-
else:
|
|
149
|
-
p.add_run(' ')
|
|
150
|
-
if self.year:
|
|
151
|
-
p.add_run(self.year).bold = True
|
|
152
|
-
p.add_run(', ')
|
|
153
|
-
if self.volume:
|
|
154
|
-
p.add_run(self.volume).italic = True
|
|
155
|
-
p.add_run(', ')
|
|
156
|
-
if self.pages:
|
|
157
|
-
p.add_run(self.pages)
|
|
158
|
-
if self.doi:
|
|
159
|
-
p.add_run(', ')
|
|
160
|
-
if self.doi:
|
|
161
|
-
p.add_run(self.doi)
|
|
162
|
-
if any([self.journal, self.pages, self.year, self.volume, self.doi]):
|
|
163
|
-
p.add_run('.')
|
|
164
|
-
|
|
165
53
|
@property
|
|
166
54
|
def richtext(self) -> RichText:
|
|
167
55
|
r = RichText('')
|
|
@@ -589,8 +477,3 @@ class CrysalisProReference(Reference):
|
|
|
589
477
|
self.journal = version
|
|
590
478
|
self.year = year
|
|
591
479
|
self.pages = pages
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
if __name__ == '__main__':
|
|
595
|
-
r = ReferenceList.get_sequence([1, 2, 3, 6])
|
|
596
|
-
print(r)
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
3
|
import gemmi
|
|
4
|
-
from docx import Document
|
|
5
4
|
from docx.oxml.xmlchemy import BaseOxmlElement
|
|
6
|
-
from docx.text.paragraph import Paragraph
|
|
7
|
-
from docx.text.run import Run
|
|
8
5
|
from lxml import etree
|
|
9
6
|
from lxml.etree import XSLTAccessControl
|
|
10
7
|
|
|
11
8
|
from finalcif.app_path import application_path
|
|
12
9
|
from finalcif.cif.cif_file_io import CifContainer
|
|
13
10
|
from finalcif.cif.text import retranslate_delimiter, string_to_utf8
|
|
14
|
-
from finalcif.
|
|
15
|
-
from finalcif.tools.misc import (protected_space, angstrom, remove_line_endings)
|
|
11
|
+
from finalcif.tools.misc import angstrom, remove_line_endings
|
|
16
12
|
|
|
17
13
|
|
|
18
14
|
def math_to_word(eq: str) -> BaseOxmlElement:
|
|
@@ -57,41 +53,6 @@ def _get_cooling_device(cif: CifContainer) -> str:
|
|
|
57
53
|
return ''
|
|
58
54
|
|
|
59
55
|
|
|
60
|
-
class FormatMixin:
|
|
61
|
-
|
|
62
|
-
def bold(self, run: Run):
|
|
63
|
-
r = run.bold = True
|
|
64
|
-
return r
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class SpaceChar:
|
|
68
|
-
def __init__(self, paragraph: Paragraph):
|
|
69
|
-
self.p = paragraph
|
|
70
|
-
|
|
71
|
-
def regular(self) -> None:
|
|
72
|
-
self.p.add_run(' ')
|
|
73
|
-
|
|
74
|
-
def protected(self):
|
|
75
|
-
self.p.add_run(protected_space)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
class RefinementDetails:
|
|
79
|
-
def __init__(self, cif: CifContainer, document: Document):
|
|
80
|
-
ph = document.add_paragraph(style='Heading 2')
|
|
81
|
-
ph.add_run(text=fr"Refinement details for {cif.block.name}")
|
|
82
|
-
p = document.add_paragraph()
|
|
83
|
-
try:
|
|
84
|
-
p.style = document.styles['fliesstext']
|
|
85
|
-
except KeyError:
|
|
86
|
-
print('DBG> Text style not found')
|
|
87
|
-
text = ' '.join(cif['_refine_special_details'].splitlines(keepends=False))
|
|
88
|
-
if cif['_olex2_refine_details']:
|
|
89
|
-
text += ' '.join(cif['_olex2_refine_details'].splitlines(keepends=False))
|
|
90
|
-
# Replacing semicolon, because it can damage the CIF:
|
|
91
|
-
text = text.replace(';', '.')
|
|
92
|
-
p.add_run(string_to_utf8(text).strip())
|
|
93
|
-
|
|
94
|
-
|
|
95
56
|
def get_inf_article(next_word: str) -> str:
|
|
96
57
|
if not next_word:
|
|
97
58
|
return 'a'
|
|
@@ -133,13 +94,3 @@ def format_radiation(radiation_type: str) -> list:
|
|
|
133
94
|
return radtype
|
|
134
95
|
else:
|
|
135
96
|
return radtype
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def make_report_text(cif, document: Document) -> references.ReferenceList:
|
|
139
|
-
paragr = document.add_paragraph()
|
|
140
|
-
try:
|
|
141
|
-
paragr.style = document.styles['fliesstext']
|
|
142
|
-
except KeyError:
|
|
143
|
-
print('DBG> Text style not found')
|
|
144
|
-
ref = references.ReferenceList(paragr)
|
|
145
|
-
return ref
|
|
@@ -13,7 +13,7 @@ from collections.abc import Callable
|
|
|
13
13
|
from contextlib import suppress
|
|
14
14
|
from math import sin, radians
|
|
15
15
|
from pathlib import Path
|
|
16
|
-
from typing import Any
|
|
16
|
+
from typing import Any, Literal
|
|
17
17
|
|
|
18
18
|
from qtpy.QtWidgets import QApplication
|
|
19
19
|
|
|
@@ -725,7 +725,7 @@ class Formatter(abc.ABC):
|
|
|
725
725
|
if 'OLEX' in refined.upper():
|
|
726
726
|
self.literature['refinement'] = ref.Olex2Reference()
|
|
727
727
|
if ('NOSPHERA2' in refined.upper() or 'NOSPHERA2' in cif['_refine_special_details'].upper() or
|
|
728
|
-
|
|
728
|
+
'NOSPHERAT2' in cif['_olex2_refine_details'].upper()):
|
|
729
729
|
self.literature['refinement'] = ref.Nosphera2Reference()
|
|
730
730
|
return string_to_utf8(refined.split('(')[0]).strip()
|
|
731
731
|
|
|
@@ -779,11 +779,28 @@ class Formatter(abc.ABC):
|
|
|
779
779
|
U23=u23.replace('-', minus_sign))
|
|
780
780
|
for label, u11, u22, u33, u23, u13, u12 in cif.displacement_parameters())
|
|
781
781
|
|
|
782
|
-
def get_completeness(self, cif: CifContainer) -> str:
|
|
782
|
+
def get_completeness(self, cif: CifContainer, theta_limit: Literal['full', 'max'] = 'full') -> str:
|
|
783
|
+
"""
|
|
784
|
+
Completeness in % for the given theta limit ('full' or 'max').
|
|
785
|
+
The standard CIF values used to report the completeness are
|
|
786
|
+
_diffrn_measured_fraction_theta_max and _diffrn_measured_fraction_theta_full.
|
|
787
|
+
|
|
788
|
+
How they differ
|
|
789
|
+
_diffrn_measured_fraction_theta_full:
|
|
790
|
+
Reports the fraction of independent reflections measured up to a standardized
|
|
791
|
+
"full" resolution limit (e.g., theta = 25.2° for Mo-K⍺
|
|
792
|
+
or 67.5° for Cu-K⍺). This is the metric most rigorously checked for publication.
|
|
793
|
+
|
|
794
|
+
_diffrn_measured_fraction_theta_max:
|
|
795
|
+
Reports the fraction of independent reflections measured up to the absolute highest
|
|
796
|
+
angle collected in that specific experiment, even if it exceeds or falls short of
|
|
797
|
+
the standard resolution limit.
|
|
798
|
+
"""
|
|
799
|
+
fraction = cif[f'_diffrn_measured_fraction_theta_{theta_limit}']
|
|
783
800
|
try:
|
|
784
|
-
completeness = f"{float(
|
|
801
|
+
completeness = f"{float(fraction) * 100:.1f}"
|
|
785
802
|
except ValueError:
|
|
786
|
-
completeness =
|
|
803
|
+
completeness = fraction
|
|
787
804
|
return completeness
|
|
788
805
|
|
|
789
806
|
def format_experiment_table(self, cif: CifContainer):
|
|
@@ -1122,6 +1139,7 @@ class TemplatedReport:
|
|
|
1122
1139
|
self.options = options
|
|
1123
1140
|
self.text_formatter = text_factory(options, cif)[self.format]
|
|
1124
1141
|
self.references = {}
|
|
1142
|
+
self.is_multi_cif_template = False
|
|
1125
1143
|
|
|
1126
1144
|
def count_reference(self, ref):
|
|
1127
1145
|
if self.references:
|
|
@@ -1167,6 +1185,8 @@ class TemplatedReport:
|
|
|
1167
1185
|
# plain text full reference:
|
|
1168
1186
|
jinja_env.filters['ref_txt'] = self.reference_text
|
|
1169
1187
|
try:
|
|
1188
|
+
variables = tpl_doc.get_undeclared_template_variables(jinja_env=jinja_env)
|
|
1189
|
+
self.is_multi_cif_template = bool({'blocklist', 'block'} & variables)
|
|
1170
1190
|
tpl_doc.render(context, jinja_env=jinja_env, autoescape=True)
|
|
1171
1191
|
tpl_doc.save(output_filename)
|
|
1172
1192
|
return True
|
|
@@ -1180,7 +1200,6 @@ class TemplatedReport:
|
|
|
1180
1200
|
show_general_warning(parent=None, window_title='Warning', warn_text='Document generation failed',
|
|
1181
1201
|
info_text=str(e))
|
|
1182
1202
|
print(e)
|
|
1183
|
-
raise
|
|
1184
1203
|
return False
|
|
1185
1204
|
|
|
1186
1205
|
def make_templated_html_report(self,
|
|
@@ -1298,10 +1317,10 @@ class TemplatedReport:
|
|
|
1298
1317
|
'space_group' : self.text_formatter.space_group_formatted(cif, tpl_doc),
|
|
1299
1318
|
'structure_figure' : self.text_formatter.make_picture(options,
|
|
1300
1319
|
options.structure_figure, tpl_doc) if (
|
|
1301
|
-
|
|
1320
|
+
options and options.report_text) else '',
|
|
1302
1321
|
'crystal_video' : self.text_formatter.make_picture(options,
|
|
1303
1322
|
options.video_image, tpl_doc) if (
|
|
1304
|
-
|
|
1323
|
+
options and options.report_text) else '',
|
|
1305
1324
|
'3d_structure' : self.text_formatter.make_3d(cif, options) if options else '',
|
|
1306
1325
|
'crystallization_method' : self.text_formatter.get_crystallization_method(cif),
|
|
1307
1326
|
'sum_formula' : self.text_formatter.format_sum_formula(
|
|
@@ -1332,8 +1351,11 @@ class TemplatedReport:
|
|
|
1332
1351
|
'indepentent_refl' : this_or_quest(cif['_reflns_number_total']),
|
|
1333
1352
|
'r_int' : this_or_quest(cif['_diffrn_reflns_av_R_equivalents']),
|
|
1334
1353
|
'r_sigma' : this_or_quest(cif['_diffrn_reflns_av_unetI/netI']),
|
|
1335
|
-
'completeness' : self.text_formatter.get_completeness(cif),
|
|
1354
|
+
'completeness' : self.text_formatter.get_completeness(cif, 'full'),
|
|
1355
|
+
'completeness_theta_full': self.text_formatter.get_completeness(cif, 'full'),
|
|
1356
|
+
'completeness_theta_max' : self.text_formatter.get_completeness(cif, 'max'),
|
|
1336
1357
|
'theta_full' : cif['_diffrn_reflns_theta_full'],
|
|
1358
|
+
'theta_max' : cif['_diffrn_reflns_theta_max'],
|
|
1337
1359
|
'resolution_angstrom' : self.text_formatter.get_angstrom_resolution(cif),
|
|
1338
1360
|
'redundancy' : self.text_formatter.get_redundancy(cif),
|
|
1339
1361
|
'data' : this_or_quest(cif['_refine_ls_number_reflns']),
|
|
@@ -1475,15 +1497,15 @@ if __name__ == '__main__':
|
|
|
1475
1497
|
|
|
1476
1498
|
import subprocess
|
|
1477
1499
|
|
|
1478
|
-
report_type = ReportFormat.
|
|
1500
|
+
report_type = ReportFormat.HTML
|
|
1479
1501
|
|
|
1480
1502
|
data = Path('tests')
|
|
1481
1503
|
testcif = Path(data / 'examples/1979688.cif').absolute()
|
|
1482
|
-
testcif = Path(data / r'..\test-data\4060314.cif').absolute()
|
|
1504
|
+
# testcif = Path(data / r'..\test-data\4060314.cif').absolute()
|
|
1483
1505
|
|
|
1484
1506
|
# testcif = Path(r'test-data/p31c.cif').absolute()
|
|
1485
|
-
#testcif = Path(r'test-data/p31c.cif').absolute()
|
|
1486
|
-
#testcif = Path(r"D:\Downloads\9008564.cif").absolute()
|
|
1507
|
+
# testcif = Path(r'test-data/p31c.cif').absolute()
|
|
1508
|
+
# testcif = Path(r"D:\Downloads\9008564.cif").absolute()
|
|
1487
1509
|
cif = CifContainer(testcif)
|
|
1488
1510
|
|
|
1489
1511
|
pic = pathlib.Path("screenshots/finalcif_checkcif.png")
|
|
@@ -250,11 +250,16 @@
|
|
|
250
250
|
</td>
|
|
251
251
|
</tr>
|
|
252
252
|
<tr>
|
|
253
|
-
<td>Completeness{% if
|
|
254
|
-
θ = {{
|
|
255
|
-
|
|
253
|
+
<td>Completeness{% if theta_full %} to
|
|
254
|
+
θ = {{ theta_full|float_num(2) }}°{% endif %}
|
|
255
|
+
</td>
|
|
256
|
+
<td>{{ completeness_theta_full }}%</td>
|
|
257
|
+
</tr>
|
|
258
|
+
<tr>
|
|
259
|
+
<td>Completeness{% if theta_max %} to
|
|
260
|
+
θ = {{ theta_max|float_num(2) }}°{% endif %}
|
|
256
261
|
</td>
|
|
257
|
-
<td>{{
|
|
262
|
+
<td>{{ completeness_theta_max }}%</td>
|
|
258
263
|
</tr>
|
|
259
264
|
<tr>
|
|
260
265
|
<td>Data / Restraints / Parameters</td>
|
|
Binary file
|
|
@@ -289,11 +289,16 @@
|
|
|
289
289
|
</td>
|
|
290
290
|
</tr>
|
|
291
291
|
<tr>
|
|
292
|
-
<td>Completeness{% if
|
|
293
|
-
θ = {{
|
|
294
|
-
|
|
292
|
+
<td>Completeness{% if theta_full %} to
|
|
293
|
+
θ = {{ theta_full|float_num(2) }}°{% endif %}
|
|
294
|
+
</td>
|
|
295
|
+
<td>{{ completeness_theta_full }}%</td>
|
|
296
|
+
</tr>
|
|
297
|
+
<tr>
|
|
298
|
+
<td>Completeness{% if theta_max %} to
|
|
299
|
+
θ = {{ theta_max|float_num(2) }}°{% endif %}
|
|
295
300
|
</td>
|
|
296
|
-
<td>{{
|
|
301
|
+
<td>{{ completeness_theta_max }}%</td>
|
|
297
302
|
</tr>
|
|
298
303
|
<tr>
|
|
299
304
|
<td>Data / Restraints / Parameters</td>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
#
|
|
3
|
+
# pre-push hook: reject pushing version tags (e.g. "version-177") whose
|
|
4
|
+
# numeric version is newer than the VERSION defined in finalcif/__init__.py
|
|
5
|
+
# at the commit the tag points to.
|
|
6
|
+
#
|
|
7
|
+
# Git has no client-side hook that fires on local `git tag` creation, so
|
|
8
|
+
# this is enforced at push time instead, which is the last point before
|
|
9
|
+
# the tag becomes visible to others.
|
|
10
|
+
#
|
|
11
|
+
# Install (once per clone):
|
|
12
|
+
# git config core.hooksPath githooks
|
|
13
|
+
#
|
|
14
|
+
# Tag names are expected to look like "version-NNN" (matching VERSION = NN).
|
|
15
|
+
# Tags that don't match this pattern are ignored by this check.
|
|
16
|
+
|
|
17
|
+
VERSION_FILE="finalcif/__init__.py"
|
|
18
|
+
z40="0000000000000000000000000000000000000000"
|
|
19
|
+
|
|
20
|
+
reject=0
|
|
21
|
+
|
|
22
|
+
while read -r local_ref local_sha remote_ref remote_sha; do
|
|
23
|
+
case "$local_ref" in
|
|
24
|
+
refs/tags/*) ;;
|
|
25
|
+
*) continue ;;
|
|
26
|
+
esac
|
|
27
|
+
|
|
28
|
+
# Tag deletion (local_sha is all zeros) - nothing to check.
|
|
29
|
+
if [ "$local_sha" = "$z40" ]; then
|
|
30
|
+
continue
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
tag_name=${local_ref#refs/tags/}
|
|
34
|
+
|
|
35
|
+
# Only enforce the check for tags named like "version-<number>".
|
|
36
|
+
case "$tag_name" in
|
|
37
|
+
version-[0-9]*)
|
|
38
|
+
tag_version=${tag_name#version-}
|
|
39
|
+
case "$tag_version" in
|
|
40
|
+
*[!0-9]*) continue ;; # not purely numeric, skip
|
|
41
|
+
esac
|
|
42
|
+
;;
|
|
43
|
+
*) continue ;;
|
|
44
|
+
esac
|
|
45
|
+
|
|
46
|
+
# Resolve to the commit the tag points at (handles annotated tags).
|
|
47
|
+
commit_sha=$(git rev-list -n 1 "$local_sha" 2>/dev/null)
|
|
48
|
+
if [ -z "$commit_sha" ]; then
|
|
49
|
+
commit_sha="$local_sha"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
file_content=$(git show "$commit_sha:$VERSION_FILE" 2>/dev/null)
|
|
53
|
+
if [ -z "$file_content" ]; then
|
|
54
|
+
echo "pre-push: warning: could not read $VERSION_FILE at $commit_sha for tag $tag_name; skipping check" >&2
|
|
55
|
+
continue
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
file_version=$(printf '%s\n' "$file_content" | sed -n "s/^VERSION *= *\\([0-9]\\+\\).*/\\1/p" | head -n 1)
|
|
59
|
+
if [ -z "$file_version" ]; then
|
|
60
|
+
echo "pre-push: warning: could not parse VERSION from $VERSION_FILE at $commit_sha; skipping check" >&2
|
|
61
|
+
continue
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if [ "$tag_version" -gt "$file_version" ]; then
|
|
65
|
+
echo "pre-push: rejected: tag '$tag_name' (version $tag_version) is newer than" >&2
|
|
66
|
+
echo " VERSION = $file_version in $VERSION_FILE at commit $commit_sha." >&2
|
|
67
|
+
echo " Update $VERSION_FILE to $tag_version before tagging/pushing." >&2
|
|
68
|
+
reject=1
|
|
69
|
+
fi
|
|
70
|
+
done
|
|
71
|
+
|
|
72
|
+
if [ "$reject" -eq 1 ]; then
|
|
73
|
+
exit 1
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
exit 0
|