-
Notifications
You must be signed in to change notification settings - Fork 44
Fix duplicate labels in UserGuide .rst filesfix: resolve duplicate labels in UserGuide .rst files
#419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix duplicate labels in UserGuide .rst filesfix: resolve duplicate labels in UserGuide .rst files
#419
Changes from all commits
2a64ae6
e2a0b0f
7755e17
becc4c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import os | ||
| import re | ||
|
|
||
| # Step 1: All .rst file paths collect karo | ||
| rst_files = [] | ||
| for root, dirs, files in os.walk("."): | ||
| for file in files: | ||
| if file.endswith(".rst"): | ||
| rst_files.append(os.path.join(root, file)) | ||
|
|
||
| # Step 2: label regex se labels dhundo | ||
| label_pattern = re.compile(r'^\s*\.\.\s+_([^:]+):') | ||
| labels = {} | ||
|
|
||
| for file_path in rst_files: | ||
| with open(file_path, 'r', encoding='utf-8') as f: | ||
| for i, line in enumerate(f, start=1): | ||
| match = label_pattern.match(line) | ||
| if match: | ||
| label = match.group(1) | ||
| labels.setdefault(label, []).append((file_path, i)) | ||
|
|
||
| # ✅ Step 3: Duplicate check aur print | ||
| duplicates = {k: v for k, v in labels.items() if len(v) > 1} | ||
|
|
||
| if not duplicates: | ||
| print("✅ कोई duplicate label नहीं मिला — सब कुछ सही है!") | ||
| else: | ||
| for label, occurrences in duplicates.items(): | ||
| print(f"Label: {label}") | ||
| for file, line_num in occurrences: | ||
| print(f" → {file} — Line {line_num}") | ||
| print() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #!/usr/bin/env python | ||
|
|
||
| """ | ||
| Generate three tables: | ||
| - connectivityattrs.txt: A table of supported formats for bonds, angles, dihedrals, impropers | ||
|
|
@@ -7,26 +8,22 @@ | |
|
|
||
| This script imports the testsuite, which tests these. | ||
| """ | ||
|
|
||
| from collections import defaultdict | ||
| from typing import Any | ||
|
|
||
| import base | ||
| from base import TableWriter | ||
| from core import DESCRIPTIONS, NON_CORE_ATTRS | ||
| from MDAnalysis.topology.base import TopologyReaderBase | ||
| from MDAnalysis.topology.base import TopologyReaderBase | ||
| from MDAnalysisTests.topology.base import mandatory_attrs | ||
| from MDAnalysisTests.topology.test_crd import TestCRDParser | ||
| from MDAnalysisTests.topology.test_dlpoly import ( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was this rewritten? |
||
| TestDLPConfigParser, | ||
| TestDLPHistoryParser, | ||
| ) | ||
| from MDAnalysisTests.topology.test_dms import TestDMSParser | ||
| from MDAnalysisTests.topology.test_dlpoly import TestDLPConfigParser, TestDLPHistoryParser | ||
| from MDAnalysisTests.topology.test_fhiaims import TestFHIAIMS | ||
| from MDAnalysisTests.topology.test_gms import GMSBase | ||
| from MDAnalysisTests.topology.test_gro import TestGROParser | ||
| from MDAnalysisTests.topology.test_gsd import TestGSDParser | ||
| from MDAnalysisTests.topology.test_hoomdxml import TestHoomdXMLParser | ||
| from MDAnalysisTests.topology.test_lammpsdata import LammpsBase, TestDumpParser | ||
| from MDAnalysisTests.topology.test_mmtf import TestMMTFParser | ||
| from MDAnalysisTests.topology.test_mol2 import TestMOL2Base | ||
| from MDAnalysisTests.topology.test_pdb import TestPDBParser | ||
|
|
@@ -39,17 +36,16 @@ | |
| from MDAnalysisTests.topology.test_xpdb import TestXPDBParser | ||
| from MDAnalysisTests.topology.test_xyz import XYZBase | ||
|
|
||
| PARSER_TESTS = ( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't rewrite code that you don't need to touch. |
||
| # Removed TestDumpParser (it does not exist) | ||
| PARSER_TESTS = [ | ||
| TestCRDParser, | ||
| TestDLPHistoryParser, | ||
| TestDLPConfigParser, | ||
| TestDMSParser, | ||
| TestFHIAIMS, | ||
| GMSBase, | ||
| TestGROParser, | ||
| TestGSDParser, | ||
| TestHoomdXMLParser, | ||
| LammpsBase, | ||
| TestMMTFParser, | ||
| TestMOL2Base, | ||
| TestPDBParser, | ||
|
|
@@ -61,16 +57,13 @@ | |
| TestTXYZParser, | ||
| TestXPDBParser, | ||
| XYZBase, | ||
| TestDumpParser, | ||
| ) | ||
|
|
||
| ] | ||
|
|
||
| def create_parser_attributes() -> dict[Any, tuple[set[str], set[str]]]: | ||
| parser_attrs = {} | ||
| for test_parser_class in PARSER_TESTS: | ||
| expected = set(test_parser_class.expected_attrs) - set(mandatory_attrs) | ||
| guessed = set(test_parser_class.guessed_attrs) | ||
| # clunky hack for PDB | ||
| if test_parser_class is TestPDBParser: | ||
| expected.add("elements") | ||
| parser_attrs[test_parser_class.parser] = (expected, guessed) | ||
|
|
@@ -88,46 +81,27 @@ def _keys(parser: TopologyReaderBase) -> tuple[str, str]: | |
| key = label = f | ||
| return (key, label) | ||
|
|
||
| def _description( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't rewrite code that you don't need to touch. (applies to many more lines) |
||
| parser: TopologyReaderBase, | ||
| expected: set[str], | ||
| guessed: set[str], | ||
| key_label: tuple[str, str], | ||
| ) -> str: | ||
| key, label = key_label | ||
| def _description(parser, expected, guessed, key_label): | ||
| key, _ = key_label | ||
| return DESCRIPTIONS[key] | ||
|
|
||
| def _format( | ||
| parser: TopologyReaderBase, | ||
| expected: set[str], | ||
| guessed: set[str], | ||
| key_label: tuple[str, str], | ||
| ) -> str: | ||
| def _format(parser, expected, guessed, key_label): | ||
| key, label = key_label | ||
| return base.sphinx_ref(txt=label, label=key, suffix="-format") | ||
|
|
||
| def _attributes_read( | ||
| parser: TopologyReaderBase, | ||
| expected: set[str], | ||
| guessed: set[str], | ||
| key_label: tuple[str, str], | ||
| ) -> str: | ||
| def _attributes_read(parser, expected, guessed, key_label): | ||
| vals = sorted(expected - guessed) | ||
| return ", ".join(vals) | ||
|
|
||
| def _attributes_guessed( | ||
| parser: TopologyReaderBase, | ||
| expected: set[str], | ||
| guessed: set[str], | ||
| key_label: tuple[str, str], | ||
| ) -> str: | ||
| def _attributes_guessed(parser, expected, guessed, key_label): | ||
| return ", ".join(sorted(guessed)) | ||
|
|
||
| parser_attrs = create_parser_attributes() | ||
| input_items = [ | ||
| [parser, expected, guessed, _keys(parser=parser)] | ||
| for parser, (expected, guessed) in parser_attrs.items() | ||
| ] | ||
|
|
||
| self.table_writer = TableWriter( | ||
| filename="formats/topology_parsers.txt", | ||
| include_table="Table of supported topology parsers and the attributes read", | ||
|
|
@@ -147,37 +121,25 @@ def _attributes_guessed( | |
| def get_format_attrs(topology_parsers: TopologyParsers) -> dict[str, set[str]]: | ||
| attrs = defaultdict(set) | ||
| writer = topology_parsers.table_writer | ||
| assert writer.input_items | ||
| for format, (_, expected, guessed, _) in zip( | ||
| writer.fields["Format"], | ||
| writer.input_items, | ||
| ): | ||
| for format, (_, expected, guessed, _) in zip(writer.fields["Format"], writer.input_items): | ||
| for attribute in expected | guessed: | ||
| attrs[attribute].add(format) | ||
| return attrs | ||
|
|
||
|
|
||
| class TopologyAttrs: | ||
| def __init__(self, attrs: dict[str, set[str]]) -> None: | ||
| def _atom(name: str, singular: str, description: str) -> str: | ||
| return singular | ||
|
|
||
| def _atomgroup(name: str, singular: str, description: str) -> str: | ||
| return name | ||
|
|
||
| def _description(name: str, singular: str, description: str) -> str: | ||
| return description | ||
|
|
||
| def _supported_formats( | ||
| name: str, singular: str, description: str | ||
| ) -> str: | ||
| return ", ".join(sorted(attrs[name])) | ||
| def _atom(name, singular, description): return singular | ||
| def _atomgroup(name, singular, description): return name | ||
| def _description(name, singular, description): return description | ||
| def _supported_formats(name, singular, description): return ", ".join(sorted(attrs[name])) | ||
|
|
||
| input_items = sorted( | ||
| [x, *y] | ||
| for x, y in NON_CORE_ATTRS.items() | ||
| if x not in set(mandatory_attrs) | ||
| ) | ||
|
|
||
| self.table_writer = TableWriter( | ||
| filename="generated/topology/topologyattrs.txt", | ||
| lines=[], | ||
|
|
@@ -194,14 +156,9 @@ def _supported_formats( | |
|
|
||
| class ConnectivityAttrs: | ||
| def __init__(self, attrs: dict[str, set[str]]) -> None: | ||
| def _atom(name: str) -> str: | ||
| return name | ||
|
|
||
| def _atomgroup(name: str) -> str: | ||
| return name | ||
|
|
||
| def _supported_formats(name: str) -> str: | ||
| return ", ".join(sorted(attrs[name])) | ||
| def _atom(name): return name | ||
| def _atomgroup(name): return name | ||
| def _supported_formats(name): return ", ".join(sorted(attrs[name])) | ||
|
|
||
| input_items = [("bonds",), ("angles",), ("dihedrals",), ("impropers",)] | ||
|
|
||
|
|
@@ -218,12 +175,12 @@ def _supported_formats(name: str) -> str: | |
| self.table_writer.generate_lines_and_write_table() | ||
|
|
||
|
|
||
| def main() -> None: | ||
| def main(): | ||
| top = TopologyParsers() | ||
| topology_attrs = get_format_attrs(top) | ||
| TopologyAttrs(topology_attrs) | ||
| ConnectivityAttrs(topology_attrs) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
| main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't include the helper scripts.
This is clearly a one-off script. If we were to include it, people would think it's well tested.