diff --git a/tests/io/test_molfile_v3000_reader.py b/tests/io/test_molfile_v3000_reader.py index 90508fe..e88946a 100644 --- a/tests/io/test_molfile_v3000_reader.py +++ b/tests/io/test_molfile_v3000_reader.py @@ -236,21 +236,25 @@ def test_graph_from_file_with_multi_attachment(): [ # missing "BEGIN ATOM" ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 1 1\n" - "M V30 1 H 0 0 0 0\n", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 1 1\n" + "M V30 1 H 0 0 0 0\n" + ), 'Expected "BEGIN ATOM" on line 7, found "1 H 0 0 0 0"', ), # missing "END ATOM" ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 2 0\n" - "M V30 BEGIN ATOM\n" - "M V30 1 H 0 0 0 0\n" - "M V30 2 H 0 0 0 0\n" - "M V30 3 H 0 0 0 0\n", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 2 0\n" + "M V30 BEGIN ATOM\n" + "M V30 1 H 0 0 0 0\n" + "M V30 2 H 0 0 0 0\n" + "M V30 3 H 0 0 0 0\n" + ), 'Expected "END ATOM" on line 10, found "3 H 0 0 0 0"', ), ], @@ -293,29 +297,33 @@ def test_parsing_bond_block(): [ # missing "BEGIN BOND" ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 2 1\n" - "M V30 BEGIN ATOM\n" - "M V30 1 H 0 0 0 0\n" - "M V30 2 H 0 0 0 0\n" - "M V30 END ATOM\n" - "M V30 1 1 1 2", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 2 1\n" + "M V30 BEGIN ATOM\n" + "M V30 1 H 0 0 0 0\n" + "M V30 2 H 0 0 0 0\n" + "M V30 END ATOM\n" + "M V30 1 1 1 2" + ), 'Expected "BEGIN BOND" on line 11, found "1 1 1 2"', ), # missing "END BOND" ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 2 2\n" - "M V30 BEGIN ATOM\n" - "M V30 1 H 0 0 0 0\n" - "M V30 2 H 0 0 0 0\n" - "M V30 END ATOM\n" - "M V30 BEGIN BOND\n" - "M V30 1 1 1 2\n" - "M V30 1 1 2 1\n" - "M V30 1 1 1 1", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 2 2\n" + "M V30 BEGIN ATOM\n" + "M V30 1 H 0 0 0 0\n" + "M V30 2 H 0 0 0 0\n" + "M V30 END ATOM\n" + "M V30 BEGIN BOND\n" + "M V30 1 1 1 2\n" + "M V30 1 1 2 1\n" + "M V30 1 1 1 1" + ), 'Expected "END BOND" on line 14, found "1 1 1 1"', ), ], @@ -420,16 +428,20 @@ def test_concat_lines_with_dash_raises_exception(lines, expected_error_msg): [ # missing COUNTS line ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 BEGIN ATOM", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 BEGIN ATOM" + ), 'Bad counts line: "M V30 BEGIN ATOM"', ), # number of bonds missing ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 1", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 1" + ), 'Bad counts line: "M V30 COUNTS 1"', ), ], @@ -446,29 +458,33 @@ def test_molfile_with_invalid_counts_line_raises_exception(molfile, expected_err "molfile, expected_error_msg", [ ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 2 1\n" - "M V30 BEGIN ATOM\n" - "M V30 1 H 0 0 0 0\n" - "M V30 2 H 0 0 0 0\n" - "M V30 END ATOM\n" - "M V30 BEGIN BOND\n" - "M V30 1 1 3 1\n" - "M V30 END BOND", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 2 1\n" + "M V30 BEGIN ATOM\n" + "M V30 1 H 0 0 0 0\n" + "M V30 2 H 0 0 0 0\n" + "M V30 END ATOM\n" + "M V30 BEGIN BOND\n" + "M V30 1 1 3 1\n" + "M V30 END BOND" + ), "Unknown atom index 3 in bond", ), ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 2 1\n" - "M V30 BEGIN ATOM\n" - "M V30 1 H 0 0 0 0\n" - "M V30 2 H 0 0 0 0\n" - "M V30 END ATOM\n" - "M V30 BEGIN BOND\n" - "M V30 1 1 2 5\n" - "M V30 END BOND", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 2 1\n" + "M V30 BEGIN ATOM\n" + "M V30 1 H 0 0 0 0\n" + "M V30 2 H 0 0 0 0\n" + "M V30 END ATOM\n" + "M V30 BEGIN BOND\n" + "M V30 1 1 2 5\n" + "M V30 END BOND" + ), "Unknown atom index 5 in bond", ), ], @@ -485,31 +501,35 @@ def test_molfile_with_invalid_bond_index_raises_exception(molfile, expected_erro "molfile, expected_error_msg", [ ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 2 1\n" - "M V30 BEGIN ATOM\n" - "M V30 1 * 0 0 0 0\n" - "M V30 2 * 0 0 0 0\n" - "M V30 END ATOM\n" - "M V30 BEGIN BOND\n" - "M V30 1 1 1 2\n" - "M V30 END BOND", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 2 1\n" + "M V30 BEGIN ATOM\n" + "M V30 1 * 0 0 0 0\n" + "M V30 2 * 0 0 0 0\n" + "M V30 END ATOM\n" + "M V30 BEGIN BOND\n" + "M V30 1 1 1 2\n" + "M V30 END BOND" + ), re.escape('Two "star" atoms (index 1 and 2) may not be connected'), ), ( - "\n\n\n 0 0 0 0 0 999 V3000\n" - "M V30 BEGIN CTAB\n" - "M V30 COUNTS 4 1\n" - "M V30 BEGIN ATOM\n" - "M V30 1 * 0 0 0 0\n" - "M V30 2 H 0 0 0 0\n" - "M V30 3 H 0 0 0 0\n" - "M V30 4 H 0 0 0 0\n" - "M V30 END ATOM\n" - "M V30 BEGIN BOND\n" - "M V30 1 1 1 2 ENDPTS=(1 3 4)\n" - "M V30 END BOND", + ( + "\n\n\n 0 0 0 0 0 999 V3000\n" + "M V30 BEGIN CTAB\n" + "M V30 COUNTS 4 1\n" + "M V30 BEGIN ATOM\n" + "M V30 1 * 0 0 0 0\n" + "M V30 2 H 0 0 0 0\n" + "M V30 3 H 0 0 0 0\n" + "M V30 4 H 0 0 0 0\n" + "M V30 END ATOM\n" + "M V30 BEGIN BOND\n" + "M V30 1 1 1 2 ENDPTS=(1 3 4)\n" + "M V30 END BOND" + ), re.escape('Error in "ENDPTS=(1 3 4)": Expected 1 endpoints, found 2'), ), ], diff --git a/tests/parser/test_exception.py b/tests/parser/test_exception.py index b9978a4..43b878c 100644 --- a/tests/parser/test_exception.py +++ b/tests/parser/test_exception.py @@ -15,13 +15,15 @@ ( "CH4/(1-2)/(1:=14)", re.escape( - "line 1:13 missing {'mass', 'rad'} at '='\nCH4/(1-2)/(1:=14)\n ^" + "line 1:13 missing {'mass', 'rad'} at '='\nCH4/(1-2)/(1:=14)\n " + " ^" ), ), ( "CH4/(1-2)/(1:massmass=14)", re.escape( - "line 1:17 extraneous input 'mass' expecting '='\nCH4/(1-2)/(1:massmass=14)\n ^^^^" + "line 1:17 extraneous input 'mass' expecting" + " '='\nCH4/(1-2)/(1:massmass=14)\n ^^^^" ), ), ( @@ -31,7 +33,8 @@ ( "CH4/(1-)", re.escape( - "line 1:7 mismatched input ')' expecting {'1', '2', '3', '4', '5', '6', '7', '8', '9', GREATER_THAN_NINE}\nCH4/(1-)\n ^" + "line 1:7 mismatched input ')' expecting {'1', '2', '3', '4', '5', '6'," + " '7', '8', '9', GREATER_THAN_NINE}\nCH4/(1-)\n ^" ), ), ], diff --git a/tests/parser/test_parser.py b/tests/parser/test_parser.py index cea2ced..c6b2369 100644 --- a/tests/parser/test_parser.py +++ b/tests/parser/test_parser.py @@ -128,7 +128,10 @@ def test_node_attributes(node_attributes, expected_node_attributes): def test_overriding_node_attribute_raises_exception( node_attributes, offending_node_index, offending_key ): - expected_error_msg = f'^Atom {offending_node_index}: Attribute "{offending_key}" was already defined.$' + expected_error_msg = ( + f'^Atom {offending_node_index}: Attribute "{offending_key}" was already' + " defined.$" + ) with pytest.raises(TucanParserException, match=expected_error_msg): _extract_node_attributes(node_attributes) diff --git a/tucan/element_attributes.py b/tucan/element_attributes.py index 0abb759..efb1a09 100644 --- a/tucan/element_attributes.py +++ b/tucan/element_attributes.py @@ -6,6 +6,7 @@ which was set to lightgrey for better visibility. Colors beyond meitnerium are not officially assigned so far and were thus set to the same value as for Mt. """ + from __future__ import annotations from typing import Final diff --git a/tucan/graph_utils.py b/tucan/graph_utils.py index 79ab1b6..ceb9489 100644 --- a/tucan/graph_utils.py +++ b/tucan/graph_utils.py @@ -42,9 +42,11 @@ def _add_invariant_code( ) -> None: for atom, attrs in atom_attrs.items(): invariant_code = tuple( - attrs[icd.key] - if (default_value := icd.default_value) is None - else attrs.get(icd.key, default_value) + ( + attrs[icd.key] + if (default_value := icd.default_value) is None + else attrs.get(icd.key, default_value) + ) for icd in invariant_code_definitions ) atom_attrs[atom].update({INVARIANT_CODE: invariant_code}) diff --git a/tucan/io/molfile_v3000_reader.py b/tucan/io/molfile_v3000_reader.py index 94e1ce9..390a39f 100644 --- a/tucan/io/molfile_v3000_reader.py +++ b/tucan/io/molfile_v3000_reader.py @@ -78,13 +78,15 @@ def _parse_atom_block( if (begin_atom_str := " ".join(lines[atom_block_offset - 1][2:])) != "BEGIN ATOM": raise MolfileParserException( - f'Expected "BEGIN ATOM" on line {atom_block_offset}, found "{begin_atom_str}"' + f'Expected "BEGIN ATOM" on line {atom_block_offset}, found' + f' "{begin_atom_str}"' ) if ( end_atom_str := " ".join(lines[atom_block_offset + atom_count][2:]) ) != "END ATOM": raise MolfileParserException( - f'Expected "END ATOM" on line {atom_block_offset + atom_count + 1}, found "{end_atom_str}"' + f'Expected "END ATOM" on line {atom_block_offset + atom_count + 1}, found' + f' "{end_atom_str}"' ) atom_attrs = {} @@ -120,9 +122,11 @@ def _parse_atom_attributes( optional_attrs = { CHG: [int(i.split("=")[1]) for i in line if "CHG" in i], - MASS: [int(i.split("=")[1]) for i in line if "MASS" in i] - if not isotope_mass - else [isotope_mass], + MASS: ( + [int(i.split("=")[1]) for i in line if "MASS" in i] + if not isotope_mass + else [isotope_mass] + ), RAD: [int(i.split("=")[1]) for i in line if "RAD" in i], } for key, val in optional_attrs.items(): @@ -147,13 +151,15 @@ def _parse_bond_block( if (begin_bond_str := " ".join(lines[bond_block_offset - 1][2:])) != "BEGIN BOND": raise MolfileParserException( - f'Expected "BEGIN BOND" on line {bond_block_offset}, found "{begin_bond_str}"' + f'Expected "BEGIN BOND" on line {bond_block_offset}, found' + f' "{begin_bond_str}"' ) if ( end_bond_str := " ".join(lines[bond_block_offset + bond_count][2:]) ) != "END BOND": raise MolfileParserException( - f'Expected "END BOND" on line {bond_block_offset + bond_count + 1}, found "{end_bond_str}"' + f'Expected "END BOND" on line {bond_block_offset + bond_count + 1}, found' + f' "{end_bond_str}"' ) bonds = {} @@ -166,7 +172,8 @@ def _parse_bond_block( atom2_is_star = atom2_index in star_atoms if atom1_is_star and atom2_is_star: raise MolfileParserException( - f'Two "star" atoms (index {atom1_index + 1} and {atom2_index + 1}) may not be connected' + f'Two "star" atoms (index {atom1_index + 1} and {atom2_index + 1}) may' + " not be connected" ) elif atom1_is_star: bond_tuples = _parse_bond_line_with_star_atom(line, atom2_index) @@ -197,7 +204,8 @@ def _parse_bond_line_with_star_atom( numbers = [int(num) for num in endpts_token[8:-1].split()] if (expected_n_endpts := numbers[0]) != (n_endpts := len(numbers) - 1): raise MolfileParserException( - f'Error in "{endpts_token}": Expected {expected_n_endpts} endpoints, found {n_endpts}' + f'Error in "{endpts_token}": Expected {expected_n_endpts} endpoints, found' + f" {n_endpts}" ) return [(start_atom_index, end_atom_index - 1) for end_atom_index in numbers[1:]] diff --git a/tucan/visualization.py b/tucan/visualization.py index 7a32f90..c9c337d 100644 --- a/tucan/visualization.py +++ b/tucan/visualization.py @@ -88,7 +88,8 @@ def draw_molecules( """ if highlight not in [ATOMIC_NUMBER, PARTITION]: print( - f"Please select one of {{'{PARTITION}', '{ATOMIC_NUMBER}'}} for `highlight`." + f"Please select one of {{'{PARTITION}', '{ATOMIC_NUMBER}'}} for" + " `highlight`." ) return n_molecules = len(m_list)