From a2c848d5e70331e32782f117f02cc46f457983f7 Mon Sep 17 00:00:00 2001 From: Jan Domanski Date: Sun, 6 Aug 2023 14:18:43 +0100 Subject: [PATCH 01/15] feat: adding snapshot tests --- .github/workflows/gh-ci-tests.yaml | 9 +- .pre-commit-config.yaml | 2 +- .../scripts/gen_format_overview_classes.py | 2 +- doc/source/scripts/gen_unit_tables.py | 1 + .../test_gen_format_overview_classes.ambr | 677 ++++++++++++++++++ .../test_gen_selection_exporters.ambr | 35 + .../test_gen_standard_selections.ambr | 239 +++++++ .../test_gen_topology_groupmethods.ambr | 80 +++ .../test_gen_topologyattr_defaults.ambr | 285 ++++++++ .../test_gen_topologyparser_attrs.ambr | 369 ++++++++++ .../__snapshots__/test_gen_unit_tables.ambr | 352 +++++++++ .../test_gen_format_overview_classes.py | 30 + .../snapshot/test_gen_selection_exporters.py | 10 + .../snapshot/test_gen_standard_selections.py | 46 ++ .../test_gen_topology_groupmethods.py | 10 + .../test_gen_topologyattr_defaults.py | 10 + .../snapshot/test_gen_topologyparser_attrs.py | 24 + .../tests/snapshot/test_gen_unit_tables.py | 13 + environment.yml | 1 + 19 files changed, 2190 insertions(+), 5 deletions(-) create mode 100644 doc/source/scripts/tests/snapshot/__snapshots__/test_gen_format_overview_classes.ambr create mode 100644 doc/source/scripts/tests/snapshot/__snapshots__/test_gen_selection_exporters.ambr create mode 100644 doc/source/scripts/tests/snapshot/__snapshots__/test_gen_standard_selections.ambr create mode 100644 doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topology_groupmethods.ambr create mode 100644 doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyattr_defaults.ambr create mode 100644 doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyparser_attrs.ambr create mode 100644 doc/source/scripts/tests/snapshot/__snapshots__/test_gen_unit_tables.ambr create mode 100644 doc/source/scripts/tests/snapshot/test_gen_format_overview_classes.py create mode 100644 doc/source/scripts/tests/snapshot/test_gen_selection_exporters.py create mode 100644 doc/source/scripts/tests/snapshot/test_gen_standard_selections.py create mode 100644 doc/source/scripts/tests/snapshot/test_gen_topology_groupmethods.py create mode 100644 doc/source/scripts/tests/snapshot/test_gen_topologyattr_defaults.py create mode 100644 doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py create mode 100644 doc/source/scripts/tests/snapshot/test_gen_unit_tables.py diff --git a/.github/workflows/gh-ci-tests.yaml b/.github/workflows/gh-ci-tests.yaml index f1d443024..ab02e4dd0 100644 --- a/.github/workflows/gh-ci-tests.yaml +++ b/.github/workflows/gh-ci-tests.yaml @@ -43,7 +43,10 @@ jobs: micromamba info micromamba list + - name: "test snapshots" + working-directory: doc/source/scripts/ + run: python -m pytest + - name: "test notebooks" - run: | - cd ${GITHUB_WORKSPACE}/tests - pytest + working-directory: tests/ + run: python -m pytest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a7457a5a6..127e00933 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - exclude: ^.*\.(pdb)$ + exclude: ^.*\.(pdb|ambr)$ - repo: https://github.com/pycqa/isort rev: 5.12.0 hooks: diff --git a/doc/source/scripts/gen_format_overview_classes.py b/doc/source/scripts/gen_format_overview_classes.py index 383483c2d..fa0ad3e23 100644 --- a/doc/source/scripts/gen_format_overview_classes.py +++ b/doc/source/scripts/gen_format_overview_classes.py @@ -27,7 +27,7 @@ sorted_types = sorted(FILE_TYPES.items()) -SUCCESS = "\u2713" +SUCCESS = "\u2713" # checkmark FAIL = "" diff --git a/doc/source/scripts/gen_unit_tables.py b/doc/source/scripts/gen_unit_tables.py index 640a261ee..d8398eca2 100755 --- a/doc/source/scripts/gen_unit_tables.py +++ b/doc/source/scripts/gen_unit_tables.py @@ -37,6 +37,7 @@ def write_unit_table(filename): ) f.write("\n") print("Wrote ", filename) + return tables if __name__ == "__main__": diff --git a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_format_overview_classes.ambr b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_format_overview_classes.ambr new file mode 100644 index 000000000..b180d63ed --- /dev/null +++ b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_format_overview_classes.ambr @@ -0,0 +1,677 @@ +# serializer version: 1 +# name: test_CoordinateReaders + list([ + list([ + ':ref:`ARC `', + 'Tinker file', + '', + '', + ]), + list([ + ':ref:`CHEMFILES `', + 'use readers from `chemfiles `_ library', + '', + '', + ]), + list([ + ':ref:`CONFIG `', + 'DL_Poly CONFIG file', + '✓', + '', + ]), + list([ + ':ref:`COOR `', + 'NAMD binary restart file', + '', + '', + ]), + list([ + ':ref:`CRD `', + 'CHARMM CARD file', + '', + '', + ]), + list([ + ':ref:`CRDBOX `', + 'AMBER ASCII trajectories', + '', + '', + ]), + list([ + ':ref:`DATA `', + 'LAMMPS data file', + '✓', + '', + ]), + list([ + ':ref:`DCD `', + 'CHARMM, NAMD, or LAMMPS binary trajectory', + '', + '', + ]), + list([ + ':ref:`DMS `', + 'DESRES Molecular Structure file', + '✓', + '', + ]), + list([ + ':ref:`ENT `', + 'Standard PDB file', + '', + '', + ]), + list([ + ':ref:`FHIAIMS `', + 'FHI-aims input file', + '✓', + '', + ]), + list([ + ':ref:`GMS `', + 'GAMESS file', + '', + '', + ]), + list([ + ':ref:`GRO `', + 'GROMACS structure file', + '✓', + '', + ]), + list([ + ':ref:`GSD `', + 'HOOMD GSD file', + '', + '', + ]), + list([ + ':ref:`H5MD `', + '`H5MD `_ trajectory format', + '', + '', + ]), + list([ + ':ref:`HISTORY `', + 'DL_Poly HISTORY file', + '✓', + '', + ]), + list([ + ':ref:`IN `', + 'FHI-aims input file', + '✓', + '', + ]), + list([ + ':ref:`INPCRD `', + 'AMBER restart file', + '', + '', + ]), + list([ + ':ref:`LAMMPS `', + 'a LAMMPS DCD trajectory', + '', + '', + ]), + list([ + ':ref:`LAMMPSDUMP `', + 'LAMMPS ascii dump file', + '', + '', + ]), + list([ + ':ref:`MDCRD `', + 'AMBER ASCII trajectories', + '', + '', + ]), + list([ + ':ref:`MMTF `', + 'MMTF file', + '', + '', + ]), + list([ + ':ref:`MOL2 `', + 'Tripos MOL2 file', + '', + '', + ]), + list([ + ':ref:`NAMDBIN `', + 'NAMD binary restart file', + '', + '', + ]), + list([ + ':ref:`NC `', + 'AMBER NETCDF format', + '✓', + '✓', + ]), + list([ + ':ref:`NCDF `', + 'AMBER NETCDF format', + '✓', + '✓', + ]), + list([ + ':ref:`OPENMMAPP `', + '`OpenMM `_ Application layer objects', + '', + '', + ]), + list([ + ':ref:`OPENMMSIMULATION `', + '`OpenMM `_ Simulation objects', + '✓', + '✓', + ]), + list([ + ':ref:`PARMED `', + '`ParmEd `_ Structure', + '', + '', + ]), + list([ + ':ref:`PDB `', + 'Standard PDB file', + '', + '', + ]), + list([ + ':ref:`PDBQT `', + 'PDBQT file', + '', + '', + ]), + list([ + ':ref:`PQR `', + 'PQR file', + '', + '', + ]), + list([ + ':ref:`RDKIT `', + '`RDKit `_ Molecule', + '', + '', + ]), + list([ + ':ref:`RESTRT `', + 'AMBER restart file', + '', + '', + ]), + list([ + ':ref:`TNG `', + 'Trajectory Next Generation file', + '✓', + '✓', + ]), + list([ + ':ref:`TRJ `', + 'AMBER ASCII trajectories', + '', + '', + ]), + list([ + ':ref:`TRR `', + 'GROMACS TRR trajectory', + '✓', + '✓', + ]), + list([ + ':ref:`TRZ `', + 'IBIsCO or YASP binary trajectory', + '✓', + '', + ]), + list([ + ':ref:`TXYZ `', + 'Tinker file', + '', + '', + ]), + list([ + ':ref:`XPDB `', + 'Extended PDB file', + '', + '', + ]), + list([ + ':ref:`XTC `', + 'GROMACS compressed trajectory', + '', + '', + ]), + list([ + ':ref:`XYZ `', + 'XYZ file', + '', + '', + ]), + ]) +# --- +# name: test_FormatOverview + list([ + list([ + ':ref:`ARC `', + 'Tinker file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`CHEMFILES `', + 'use readers from `chemfiles `_ library', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`CONFIG `', + 'DL_Poly CONFIG file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`COOR `', + 'NAMD binary restart file', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`CRD `', + 'CHARMM CARD file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`CRDBOX `', + 'AMBER ASCII trajectories', + '', + '✓', + '✓', + '', + ]), + list([ + ':ref:`DATA `', + 'LAMMPS data file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`DCD `', + 'CHARMM, NAMD, or LAMMPS binary trajectory', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`DMS `', + 'DESRES Molecular Structure file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`ENT `', + 'Standard PDB file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`FHIAIMS `', + 'FHI-aims input file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`GMS `', + 'GAMESS file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`GRO `', + 'GROMACS structure file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`GSD `', + 'HOOMD GSD file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`H5MD `', + '`H5MD `_ trajectory format', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`HISTORY `', + 'DL_Poly HISTORY file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`IN `', + 'FHI-aims input file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`INPCRD `', + 'AMBER restart file', + '', + '✓', + '✓', + '', + ]), + list([ + ':ref:`ITP `', + 'GROMACS portable topology file', + '✓', + '', + '✓', + '', + ]), + list([ + ':ref:`LAMMPS `', + 'a LAMMPS DCD trajectory', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`LAMMPSDUMP `', + 'LAMMPS ascii dump file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`MDCRD `', + 'AMBER ASCII trajectories', + '', + '✓', + '✓', + '', + ]), + list([ + ':ref:`MMTF `', + 'MMTF file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`MOL2 `', + 'Tripos MOL2 file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`NAMDBIN `', + 'NAMD binary restart file', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`NC `', + 'AMBER NETCDF format', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`NCDF `', + 'AMBER NETCDF format', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`OPENMMAPP `', + '`OpenMM `_ Application layer objects', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`OPENMMSIMULATION `', + '`OpenMM `_ Simulation objects', + '', + '✓', + '✓', + '', + ]), + list([ + ':ref:`OPENMMTOPOLOGY `', + '`OpenMM `_ Topology object', + '✓', + '', + '✓', + '', + ]), + list([ + ':ref:`PARM7 `', + 'AMBER topology file', + '✓', + '', + '✓', + '', + ]), + list([ + ':ref:`PARMED `', + '`ParmEd `_ Structure', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`PDB `', + 'Standard PDB file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`PDBQT `', + 'PDBQT file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`PQR `', + 'PQR file', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`PRMTOP `', + 'AMBER topology file', + '✓', + '', + '✓', + '', + ]), + list([ + ':ref:`PSF `', + 'CHARMM, NAMD, or XPLOR PSF file', + '✓', + '', + '✓', + '', + ]), + list([ + ':ref:`RDKIT `', + '`RDKit `_ Molecule', + '✓', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`RESTRT `', + 'AMBER restart file', + '', + '✓', + '✓', + '', + ]), + list([ + ':ref:`TNG `', + 'Trajectory Next Generation file', + '', + '✓', + '✓', + '', + ]), + list([ + ':ref:`TOP `', + 'AMBER topology file', + '✓', + '', + '✓', + '', + ]), + list([ + ':ref:`TPR `', + 'GROMACS run topology file', + '✓', + '', + '✓', + '', + ]), + list([ + ':ref:`TRJ `', + 'AMBER ASCII trajectories', + '', + '✓', + '✓', + '', + ]), + list([ + ':ref:`TRR `', + 'GROMACS TRR trajectory', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`TRZ `', + 'IBIsCO or YASP binary trajectory', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`TXYZ `', + 'Tinker file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`XML `', + 'HOOMD XML file', + '✓', + '', + '✓', + '', + ]), + list([ + ':ref:`XPDB `', + 'Extended PDB file', + '✓', + '✓', + '✓', + '', + ]), + list([ + ':ref:`XTC `', + 'GROMACS compressed trajectory', + '', + '✓', + '✓', + '✓', + ]), + list([ + ':ref:`XYZ `', + 'XYZ file', + '✓', + '✓', + '✓', + '✓', + ]), + ]) +# --- +# name: test_SphinxClasses + list([ + list([ + '**Coordinate reader**', + ':class:`MDAnalysis.coordinates.PDB.PDBReader`', + ]), + list([ + '**Coordinate writer**', + ':class:`MDAnalysis.coordinates.PDB.PDBWriter`', + ]), + list([ + '**Topology parser**', + ':class:`MDAnalysis.topology.PDBParser.PDBParser`', + ]), + ]) +# --- diff --git a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_selection_exporters.ambr b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_selection_exporters.ambr new file mode 100644 index 000000000..13a83f079 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_selection_exporters.ambr @@ -0,0 +1,35 @@ +# serializer version: 1 +# name: test_SelectionExporterWriter + list([ + list([ + '`CHARMM`_', + 'str', + 'CHARMM selection of individual atoms', + ':class:`MDAnalysis.selections.charmm.SelectionWriter`', + ]), + list([ + '`Gromacs`_', + 'ndx', + 'GROMACS index file', + ':class:`MDAnalysis.selections.gromacs.SelectionWriter`', + ]), + list([ + '`Jmol`_', + 'spt', + 'Jmol selection commands', + ':class:`MDAnalysis.selections.jmol.SelectionWriter`', + ]), + list([ + '`PyMol`_', + 'pml', + 'PyMOL selection string', + ':class:`MDAnalysis.selections.pymol.SelectionWriter`', + ]), + list([ + '`VMD`_', + 'vmd', + 'VMD macros, available in Representations', + ':class:`MDAnalysis.selections.vmd.SelectionWriter`', + ]), + ]) +# --- diff --git a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_standard_selections.ambr b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_standard_selections.ambr new file mode 100644 index 000000000..fa39488d5 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_standard_selections.ambr @@ -0,0 +1,239 @@ +# serializer version: 1 +# name: test_StandardSelectionTable_base + list([ + list([ + 'C2', + 'C4', + 'C5', + 'C5M', + 'C6', + 'C8', + 'N1', + 'N2', + ]), + list([ + 'N3', + 'N4', + 'N6', + 'N7', + 'N9', + 'O2', + 'O4', + 'O6', + ]), + ]) +# --- +# name: test_StandardSelectionTable_nucleic + list([ + list([ + 'A', + 'ADE', + 'C', + 'CYT', + 'DA', + 'DA3', + 'DA5', + 'DC', + ]), + list([ + 'DC3', + 'DC5', + 'DG', + 'DG3', + 'DG5', + 'DT', + 'DT3', + 'DT5', + ]), + list([ + 'G', + 'GUA', + 'RA', + 'RA3', + 'RA5', + 'RC', + 'RC3', + 'RC5', + ]), + list([ + 'RG', + 'RG3', + 'RG5', + 'RU', + 'RU3', + 'RU5', + 'T', + 'THY', + ]), + list([ + 'U', + 'URA', + ]), + ]) +# --- +# name: test_StandardSelectionTable_nucleic_backbone + list([ + list([ + "C3'", + "C5'", + "O3'", + "O5'", + 'P', + ]), + ]) +# --- +# name: test_StandardSelectionTable_nucleic_sugar + list([ + list([ + "C1'", + "C2'", + "C3'", + "C4'", + "O4'", + ]), + ]) +# --- +# name: test_StandardSelectionTable_protein + list([ + list([ + 'ACE', + 'ALA', + 'ALAD', + 'ARG', + 'ARGN', + 'ASF', + 'ASH', + 'ASN', + ]), + list([ + 'ASN1', + 'ASP', + 'ASPH', + 'CALA', + 'CARG', + 'CASF', + 'CASN', + 'CASP', + ]), + list([ + 'CCYS', + 'CCYX', + 'CGLN', + 'CGLU', + 'CGLY', + 'CHID', + 'CHIE', + 'CHIP', + ]), + list([ + 'CILE', + 'CLEU', + 'CLYS', + 'CME', + 'CMET', + 'CPHE', + 'CPRO', + 'CSER', + ]), + list([ + 'CTHR', + 'CTRP', + 'CTYR', + 'CVAL', + 'CYM', + 'CYS', + 'CYS1', + 'CYS2', + ]), + list([ + 'CYSH', + 'CYX', + 'DAB', + 'GLH', + 'GLN', + 'GLU', + 'GLUH', + 'GLY', + ]), + list([ + 'HID', + 'HIE', + 'HIP', + 'HIS', + 'HIS1', + 'HIS2', + 'HISA', + 'HISB', + ]), + list([ + 'HISD', + 'HISE', + 'HISH', + 'HSD', + 'HSE', + 'HSP', + 'HYP', + 'ILE', + ]), + list([ + 'LEU', + 'LYN', + 'LYS', + 'LYSH', + 'MET', + 'MSE', + 'NALA', + 'NARG', + ]), + list([ + 'NASN', + 'NASP', + 'NCYS', + 'NCYX', + 'NGLN', + 'NGLU', + 'NGLY', + 'NHID', + ]), + list([ + 'NHIE', + 'NHIP', + 'NILE', + 'NLEU', + 'NLYS', + 'NME', + 'NMET', + 'NPHE', + ]), + list([ + 'NPRO', + 'NSER', + 'NTHR', + 'NTRP', + 'NTYR', + 'NVAL', + 'ORN', + 'PGLU', + ]), + list([ + 'PHE', + 'PRO', + 'QLN', + 'SER', + 'THR', + 'TRP', + 'TYR', + 'VAL', + ]), + ]) +# --- +# name: test_StandardSelectionTable_protein_backbone + list([ + list([ + 'C', + 'CA', + 'N', + 'O', + ]), + ]) +# --- diff --git a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topology_groupmethods.ambr b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topology_groupmethods.ambr new file mode 100644 index 000000000..42485804b --- /dev/null +++ b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topology_groupmethods.ambr @@ -0,0 +1,80 @@ +# serializer version: 1 +# name: test_TransplantedMethods + list([ + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Charges.center_of_charge`', + 'Center of (absolute) charge of (compounds of) the group .. math:: \\boldsymbol R = \\frac{\\sum_i \\vert q_i \\vert \\boldsymbol r_i} {\\sum_i \\vert q_i \\vert} where :math:`q_i` is the charge and :math:`\\boldsymbol r_i` the position of atom :math:`i` in the given :class:`MDAnalysis.core.groups.AtomGroup`', + 'charges', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Charges.dipole_moment`', + 'Dipole moment of the group or compounds in a group', + 'charges', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Charges.dipole_vector`', + 'Dipole vector of the group', + 'charges', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Charges.quadrupole_moment`', + 'Quadrupole moment of the group according to :cite:p:`Gray1984`', + 'charges', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Charges.quadrupole_tensor`', + 'Traceless quadrupole tensor of the group or compounds', + 'charges', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Charges.total_charge`', + 'Total charge of (compounds of) the group', + 'charges', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.align_principal_axis`', + 'Align principal axis with index `axis` with `vector`', + 'masses', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.asphericity`', + 'Asphericity', + 'masses', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.center_of_mass`', + 'Center of mass of (compounds of) the group .. math:: \\boldsymbol R = \\frac{\\sum_i m_i \\boldsymbol r_i}{\\sum m_i} where :math:`m_i` is the mass and :math:`\\boldsymbol r_i` the position of atom :math:`i` in the given :class:`MDAnalysis.core.groups.AtomGroup`', + 'masses', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.gyration_moments`', + 'Moments of the gyration tensor', + 'masses', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.moment_of_inertia`', + 'Moment of inertia tensor relative to center of mass', + 'masses', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.principal_axes`', + 'Calculate the principal axes from the moment of inertia', + 'masses', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.radius_of_gyration`', + 'Radius of gyration', + 'masses', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.shape_parameter`', + 'Shape parameter', + 'masses', + ]), + list([ + ':meth:`~MDAnalysis.core.topologyattrs.Masses.total_mass`', + 'Total mass of (compounds of) the group', + 'masses', + ]), + ]) +# --- diff --git a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyattr_defaults.ambr b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyattr_defaults.ambr new file mode 100644 index 000000000..7ed079ab4 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyattr_defaults.ambr @@ -0,0 +1,285 @@ +# serializer version: 1 +# name: test_TopologyDefaults + list([ + list([ + 'altLocs', + 'altLoc', + "''", + 'atom', + , + ]), + list([ + 'angles', + 'angles', + 'No default values', + 'atom', + None, + ]), + list([ + 'aromaticities', + 'aromaticity', + 'False', + 'atom', + , + ]), + list([ + 'atomiccharges', + 'atomiccharge', + 'No default values', + 'atom', + None, + ]), + list([ + 'atomnums', + 'atomnum', + 'No default values', + 'atom', + None, + ]), + list([ + 'bonds', + 'bonds', + 'No default values', + 'atom', + None, + ]), + list([ + 'chainIDs', + 'chainID', + "''", + 'atom', + , + ]), + list([ + 'chargegroups', + 'chargegroup', + 'No default values', + 'atom', + None, + ]), + list([ + 'charges', + 'charge', + '0.0', + 'atom', + , + ]), + list([ + 'chiralities', + 'chirality', + 'No default values', + 'atom', + 'U1', + ]), + list([ + 'cmaps', + 'cmaps', + 'No default values', + 'atom', + None, + ]), + list([ + 'dihedrals', + 'dihedrals', + 'No default values', + 'atom', + None, + ]), + list([ + 'elements', + 'element', + "''", + 'atom', + , + ]), + list([ + 'epsilon14s', + 'epsilon14', + '0.0', + 'atom', + , + ]), + list([ + 'epsilons', + 'epsilon', + '0.0', + 'atom', + , + ]), + list([ + 'formalcharges', + 'formalcharge', + '0.0', + 'atom', + , + ]), + list([ + 'gbscreens', + 'gbscreen', + '0.0', + 'atom', + , + ]), + list([ + 'icodes', + 'icode', + "''", + 'residue', + , + ]), + list([ + 'ids', + 'id', + 'continuous sequence from 1 to n_atoms', + 'atom', + , + ]), + list([ + 'impropers', + 'impropers', + 'No default values', + 'atom', + None, + ]), + list([ + 'masses', + 'mass', + '0.0', + 'atom', + , + ]), + list([ + 'models', + 'model', + 'No default values', + 'segment', + None, + ]), + list([ + 'molnums', + 'molnum', + 'No default values', + 'residue', + , + ]), + list([ + 'moltypes', + 'moltype', + "''", + 'residue', + , + ]), + list([ + 'names', + 'name', + "''", + 'atom', + , + ]), + list([ + 'nbindices', + 'nbindex', + '0', + 'atom', + , + ]), + list([ + 'occupancies', + 'occupancy', + '0.0', + 'atom', + , + ]), + list([ + 'radii', + 'radius', + '0.0', + 'atom', + , + ]), + list([ + 'record_types', + 'record_type', + "'ATOM'", + 'atom', + , + ]), + list([ + 'resids', + 'resid', + 'continuous sequence from 1 to n_residues', + 'residue', + , + ]), + list([ + 'resnames', + 'resname', + "''", + 'residue', + , + ]), + list([ + 'resnums', + 'resnum', + 'continuous sequence from 1 to n_residues', + 'residue', + , + ]), + list([ + 'rmin14s', + 'rmin14', + '0.0', + 'atom', + , + ]), + list([ + 'rmins', + 'rmin', + '0.0', + 'atom', + , + ]), + list([ + 'segids', + 'segid', + "''", + 'segment', + , + ]), + list([ + 'solventradii', + 'solventradius', + '0.0', + 'atom', + , + ]), + list([ + 'tempfactors', + 'tempfactor', + '0.0', + 'atom', + , + ]), + list([ + 'type_indices', + 'type_index', + 'No default values', + 'atom', + None, + ]), + list([ + 'types', + 'type', + "''", + 'atom', + , + ]), + list([ + 'ureybradleys', + 'ureybradleys', + 'No default values', + 'atom', + None, + ]), + ]) +# --- diff --git a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyparser_attrs.ambr b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyparser_attrs.ambr new file mode 100644 index 000000000..02369a9ce --- /dev/null +++ b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyparser_attrs.ambr @@ -0,0 +1,369 @@ +# serializer version: 1 +# name: test_ConnectivityAttrs + list([ + list([ + 'angles', + 'angles', + ':ref:`DATA `, :ref:`GSD `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`XML `', + ]), + list([ + 'bonds', + 'bonds', + ':ref:`DATA `, :ref:`DMS `, :ref:`GSD `, :ref:`MMTF `, :ref:`MOL2 `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`TXYZ, ARC `, :ref:`XML `', + ]), + list([ + 'dihedrals', + 'dihedrals', + ':ref:`DATA `, :ref:`GSD `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`XML `', + ]), + list([ + 'impropers', + 'impropers', + ':ref:`DATA `, :ref:`GSD `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`XML `', + ]), + ]) +# --- +# name: test_TopologyAttrs + list([ + list([ + 'altLoc', + 'altLocs', + 'Alternate location', + ':ref:`MMTF `, :ref:`PDB, ENT `, :ref:`PDBQT `, :ref:`XPDB `', + ]), + list([ + 'angles', + 'angles', + '', + ':ref:`DATA `, :ref:`GSD `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`XML `', + ]), + list([ + 'aromaticity', + 'aromaticities', + '', + '', + ]), + list([ + 'atomiccharge', + 'atomiccharges', + 'Atomic number', + ':ref:`GMS `', + ]), + list([ + 'atomnum', + 'atomnums', + '?', + ':ref:`DMS `', + ]), + list([ + 'bonds', + 'bonds', + '', + ':ref:`DATA `, :ref:`DMS `, :ref:`GSD `, :ref:`MMTF `, :ref:`MOL2 `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`TXYZ, ARC `, :ref:`XML `', + ]), + list([ + 'chainID', + 'chainIDs', + 'chain ID', + ':ref:`DMS `, :ref:`PDB, ENT `, :ref:`XPDB `', + ]), + list([ + 'charge', + 'charges', + 'partial atomic charge', + ':ref:`DATA `, :ref:`DMS `, :ref:`GSD `, :ref:`MMTF `, :ref:`MOL2 `, :ref:`PDBQT `, :ref:`PQR `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`XML `', + ]), + list([ + 'chargegroup', + 'chargegroups', + '', + '', + ]), + list([ + 'chirality', + 'chiralities', + '', + '', + ]), + list([ + 'cmaps', + 'cmaps', + '', + '', + ]), + list([ + 'dihedrals', + 'dihedrals', + '', + ':ref:`DATA `, :ref:`GSD `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`XML `', + ]), + list([ + 'element', + 'elements', + 'atom element', + ':ref:`IN, FHIAIMS `, :ref:`MOL2 `, :ref:`PDB, ENT `, :ref:`TPR `, :ref:`TXYZ, ARC `, :ref:`XYZ `', + ]), + list([ + 'epsilon', + 'epsilons', + '', + '', + ]), + list([ + 'epsilon14', + 'epsilon14s', + '', + '', + ]), + list([ + 'formalcharge', + 'formalcharges', + '', + '', + ]), + list([ + 'gbscreen', + 'gbscreens', + '', + '', + ]), + list([ + 'icode', + 'icodes', + 'atom insertion code', + ':ref:`MMTF `, :ref:`PDB, ENT `, :ref:`PDBQT `, :ref:`PQR `, :ref:`XPDB `', + ]), + list([ + 'impropers', + 'impropers', + '', + ':ref:`DATA `, :ref:`GSD `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`XML `', + ]), + list([ + 'model', + 'models', + 'model number (from 0)', + ':ref:`MMTF `', + ]), + list([ + 'molnum', + 'molnums', + '[molecules] number (from 0)', + ':ref:`TPR `', + ]), + list([ + 'moltype', + 'moltypes', + '[moleculetype] name', + ':ref:`TPR `', + ]), + list([ + 'name', + 'names', + 'atom names', + ':ref:`CONFIG `, :ref:`CRD `, :ref:`DMS `, :ref:`GMS `, :ref:`GRO `, :ref:`GSD `, :ref:`HISTORY `, :ref:`IN, FHIAIMS `, :ref:`MMTF `, :ref:`MOL2 `, :ref:`PDB, ENT `, :ref:`PDBQT `, :ref:`PQR `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`TXYZ, ARC `, :ref:`XPDB `, :ref:`XYZ `', + ]), + list([ + 'nbindex', + 'nbindices', + '', + '', + ]), + list([ + 'occupancy', + 'occupancies', + 'atom occupancy', + ':ref:`MMTF `, :ref:`PDB, ENT `, :ref:`PDBQT `, :ref:`XPDB `', + ]), + list([ + 'radius', + 'radii', + 'atomic radius', + ':ref:`GSD `, :ref:`PQR `, :ref:`XML `', + ]), + list([ + 'record_type', + 'record_types', + 'ATOM / HETATM', + ':ref:`PDB, ENT `, :ref:`PDBQT `, :ref:`PQR `, :ref:`XPDB `', + ]), + list([ + 'resname', + 'resnames', + 'residue name (except GSD has ints)', + ':ref:`CRD `, :ref:`DMS `, :ref:`GRO `, :ref:`GSD `, :ref:`MMTF `, :ref:`MOL2 `, :ref:`PDB, ENT `, :ref:`PDBQT `, :ref:`PQR `, :ref:`PSF `, :ref:`TOP, PRMTOP, PARM7 `, :ref:`TPR `, :ref:`XPDB `', + ]), + list([ + 'rmin', + 'rmins', + '', + '', + ]), + list([ + 'rmin14', + 'rmin14s', + '', + '', + ]), + list([ + 'solventradius', + 'solventradii', + '', + '', + ]), + list([ + 'tempfactor', + 'tempfactors', + 'B-factor', + ':ref:`CRD `, :ref:`MMTF `, :ref:`PDB, ENT `, :ref:`PDBQT `, :ref:`XPDB `', + ]), + list([ + 'type_index', + 'type_indices', + 'amber atom type number', + ':ref:`TOP, PRMTOP, PARM7 `', + ]), + list([ + 'ureybradleys', + 'ureybradleys', + '', + '', + ]), + ]) +# --- +# name: test_TopologyParsers + list([ + list([ + ':ref:`CONFIG `', + 'DL_Poly CONFIG file', + 'names', + 'masses, types', + ]), + list([ + ':ref:`CRD `', + 'CHARMM CARD file', + 'names, resnames, tempfactors', + 'masses, types', + ]), + list([ + ':ref:`DATA `', + 'LAMMPS data file', + 'angles, bonds, charges, dihedrals, impropers', + '', + ]), + list([ + ':ref:`DMS `', + 'DESRES Molecular Structure file', + 'atomnums, bonds, chainIDs, charges, names, resnames', + 'types', + ]), + list([ + ':ref:`GMS `', + 'GAMESS file', + 'atomiccharges, names', + 'masses, types', + ]), + list([ + ':ref:`GRO `', + 'GROMACS structure file', + 'names, resnames', + 'masses, types', + ]), + list([ + ':ref:`GSD `', + 'HOOMD GSD file', + 'angles, bonds, charges, dihedrals, impropers, names, radii, resnames', + '', + ]), + list([ + ':ref:`HISTORY `', + 'DL_Poly HISTORY file', + 'names', + 'masses, types', + ]), + list([ + ':ref:`IN, FHIAIMS `', + 'FHI-aims input file', + 'elements, names', + 'masses, types', + ]), + list([ + ':ref:`LAMMPSDUMP `', + 'LAMMPS ascii dump file', + '', + 'masses', + ]), + list([ + ':ref:`MMTF `', + 'MMTF file', + 'altLocs, bonds, charges, icodes, models, names, occupancies, resnames, tempfactors', + 'masses', + ]), + list([ + ':ref:`MOL2 `', + 'Tripos MOL2 file', + 'bonds, charges, elements, names, resnames', + 'masses', + ]), + list([ + ':ref:`PDB, ENT `', + 'Standard PDB file', + 'altLocs, chainIDs, elements, icodes, names, occupancies, record_types, resnames, tempfactors', + 'masses, types', + ]), + list([ + ':ref:`PDBQT `', + 'PDBQT file', + 'altLocs, charges, icodes, names, occupancies, record_types, resnames, tempfactors', + 'masses', + ]), + list([ + ':ref:`PQR `', + 'PQR file', + 'charges, icodes, names, radii, record_types, resnames', + 'masses, types', + ]), + list([ + ':ref:`PSF `', + 'CHARMM, NAMD, or XPLOR PSF file', + 'angles, bonds, charges, dihedrals, impropers, names, resnames', + '', + ]), + list([ + ':ref:`TOP, PRMTOP, PARM7 `', + 'AMBER topology file', + 'angles, bonds, charges, dihedrals, impropers, names, resnames, type_indices', + '', + ]), + list([ + ':ref:`TPR `', + 'GROMACS run topology file', + 'angles, bonds, charges, dihedrals, elements, impropers, molnums, moltypes, names, resnames', + '', + ]), + list([ + ':ref:`TXYZ, ARC `', + 'Tinker file', + 'bonds, elements, names', + 'masses', + ]), + list([ + ':ref:`XML `', + 'HOOMD XML file', + 'angles, bonds, charges, dihedrals, impropers, radii', + '', + ]), + list([ + ':ref:`XPDB `', + 'Extended PDB file', + 'altLocs, chainIDs, icodes, names, occupancies, record_types, resnames, tempfactors', + 'masses, types', + ]), + list([ + ':ref:`XYZ `', + 'XYZ file', + 'elements, names', + 'masses, types', + ]), + ]) +# --- diff --git a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_unit_tables.ambr b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_unit_tables.ambr new file mode 100644 index 000000000..d5515869b --- /dev/null +++ b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_unit_tables.ambr @@ -0,0 +1,352 @@ +# serializer version: 1 +# name: test_write_unit_table + list([ + tuple( + ''' + + ------ + + ''', + ), + tuple( + 'Length', + ), + tuple( + ''' + + ------ + + ''', + ), + tuple( + ''' + + + + ''', + ), + tuple( + ''' + ========== =================== + Unit Conversion factor + ========== =================== + A 1 + Angstrom 1 + angstrom 1 + femtometer 100000 + fm 100000 + nanometer 0.1 + nm 0.1 + picometer 100 + pm 100 + Å 1 + ========== =================== + ''', + ), + tuple( + ''' + + + ''', + ), + tuple( + ''' + + ------- + + ''', + ), + tuple( + 'Density', + ), + tuple( + ''' + + ------- + + ''', + ), + tuple( + ''' + + + + ''', + ), + tuple( + ''' + ============== =================== + Unit Conversion factor + ============== =================== + A^{-3} 1 + Angstrom^{-3} 1 + Molar 1660.54 + SPC 30.3718 + TIP3P 29.8566 + TIP4P 29.8864 + nanometer^{-3} 1000 + nm^{-3} 1000 + water 30.0063 + Å^{-3} 1 + ============== =================== + ''', + ), + tuple( + ''' + + + ''', + ), + tuple( + ''' + + ---- + + ''', + ), + tuple( + 'Time', + ), + tuple( + ''' + + ---- + + ''', + ), + tuple( + ''' + + + + ''', + ), + tuple( + ''' + =========== =================== + Unit Conversion factor + =========== =================== + AKMA 20.4548 + femtosecond 1000 + fs 1000 + microsecond 1e-06 + millisecond 1e-09 + ms 1e-09 + nanosecond 0.001 + ns 0.001 + picosecond 1 + ps 1 + s 1e-12 + sec 1e-12 + second 1e-12 + us 1e-06 + μs 1e-06 + =========== =================== + ''', + ), + tuple( + ''' + + + ''', + ), + tuple( + ''' + + ------ + + ''', + ), + tuple( + 'Charge', + ), + tuple( + ''' + + ------ + + ''', + ), + tuple( + ''' + + + + ''', + ), + tuple( + ''' + ====== =================== + Unit Conversion factor + ====== =================== + Amber 18.2223 + As 1.60218e-19 + C 1.60218e-19 + e 1 + ====== =================== + ''', + ), + tuple( + ''' + + + ''', + ), + tuple( + ''' + + ----- + + ''', + ), + tuple( + 'Speed', + ), + tuple( + ''' + + ----- + + ''', + ), + tuple( + ''' + + + + ''', + ), + tuple( + ''' + ==================== =================== + Unit Conversion factor + ==================== =================== + A/AKMA 0.0488882 + A/fs 1000 + A/ms 1e-09 + A/ps 1 + A/us 1e-06 + Angstrom/AKMA 0.0488882 + Angstrom/femtosecond 1000 + Angstrom/fs 1000 + Angstrom/microsecond 1e-06 + Angstrom/millisecond 1e-09 + Angstrom/ms 1e-09 + Angstrom/picosecond 1 + Angstrom/ps 1 + Angstrom/us 1e-06 + Angstrom/μs 1e-06 + angstrom/femtosecond 1000 + angstrom/fs 1000 + angstrom/microsecond 1e-06 + angstrom/millisecond 1e-09 + angstrom/ms 1e-09 + angstrom/picosecond 1 + angstrom/us 1e-06 + angstrom/μs 1e-06 + m/s 100 + nanometer/picosecond 0.1 + nanometer/ps 0.1 + nm/ns 100 + nm/ps 0.1 + pm/ps 100 + Å/ps 1 + ==================== =================== + ''', + ), + tuple( + ''' + + + ''', + ), + tuple( + ''' + + ----- + + ''', + ), + tuple( + 'Force', + ), + tuple( + ''' + + ----- + + ''', + ), + tuple( + ''' + + + + ''', + ), + tuple( + ''' + =================== =================== + Unit Conversion factor + =================== =================== + J/m 1.66054e-11 + N 1.66054e-11 + Newton 1.66054e-11 + kJ/(mol*A) 1 + kJ/(mol*Angstrom) 1 + kJ/(mol*nm) 10 + kJ/(mol*Å) 1 + kcal/(mol*Angstrom) 0.239006 + =================== =================== + ''', + ), + tuple( + ''' + + + ''', + ), + tuple( + ''' + + ------ + + ''', + ), + tuple( + 'Energy', + ), + tuple( + ''' + + ------ + + ''', + ), + tuple( + ''' + + + + ''', + ), + tuple( + ''' + ======== =================== + Unit Conversion factor + ======== =================== + J 1.66054e-21 + eV 0.0103643 + kJ/mol 1 + kcal/mol 0.239006 + ======== =================== + ''', + ), + tuple( + ''' + + + ''', + ), + ]) +# --- diff --git a/doc/source/scripts/tests/snapshot/test_gen_format_overview_classes.py b/doc/source/scripts/tests/snapshot/test_gen_format_overview_classes.py new file mode 100644 index 000000000..835e5d039 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/test_gen_format_overview_classes.py @@ -0,0 +1,30 @@ +from unittest.mock import patch + +from gen_format_overview_classes import ( + FILE_TYPES, + CoordinateReaders, + FormatOverview, + SphinxClasses, +) + + +def test_FILE_TYPES(): + assert FILE_TYPES.keys() >= {"DCD", "GRO", "XTC", "ITP"} + + +def test_FormatOverview(snapshot): + with patch("builtins.open"): + ov = FormatOverview() + assert ov.lines == snapshot + + +def test_CoordinateReaders(snapshot): + with patch("builtins.open"): + cr = CoordinateReaders() + assert cr.lines == snapshot + + +def test_SphinxClasses(snapshot): + with patch("builtins.open"): + sc = SphinxClasses("PDB") + assert sc.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_selection_exporters.py b/doc/source/scripts/tests/snapshot/test_gen_selection_exporters.py new file mode 100644 index 000000000..34d8a5616 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/test_gen_selection_exporters.py @@ -0,0 +1,10 @@ +from unittest.mock import patch + +from gen_selection_exporters import SelectionExporterWriter +from MDAnalysis.core import selection as sel + + +def test_SelectionExporterWriter(snapshot): + with patch("builtins.open"): + se = SelectionExporterWriter() + assert se.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_standard_selections.py b/doc/source/scripts/tests/snapshot/test_gen_standard_selections.py new file mode 100644 index 000000000..f8224b8c2 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/test_gen_standard_selections.py @@ -0,0 +1,46 @@ +from unittest.mock import patch + +from gen_standard_selections import StandardSelectionTable +from MDAnalysis.core import selection as sel + + +def test_StandardSelectionTable_protein(snapshot): + with patch("builtins.open"): + ss = StandardSelectionTable("protein", sel.ProteinSelection, "prot_res", True) + assert ss.lines == snapshot + + +def test_StandardSelectionTable_protein_backbone(snapshot): + with patch("builtins.open"): + ss = StandardSelectionTable( + "protein_backbone", sel.BackboneSelection, "bb_atoms", True + ) + assert ss.lines == snapshot + + +def test_StandardSelectionTable_nucleic(snapshot): + with patch("builtins.open"): + ss = StandardSelectionTable("nucleic", sel.NucleicSelection, "nucl_res", True) + assert ss.lines == snapshot + + +def test_StandardSelectionTable_nucleic_backbone(snapshot): + with patch("builtins.open"): + ss = StandardSelectionTable( + "nucleic_backbone", sel.NucleicBackboneSelection, "bb_atoms", True + ) + assert ss.lines == snapshot + + +def test_StandardSelectionTable_base(snapshot): + with patch("builtins.open"): + ss = StandardSelectionTable("base", sel.BaseSelection, "base_atoms", True) + assert ss.lines == snapshot + + +def test_StandardSelectionTable_nucleic_sugar(snapshot): + with patch("builtins.open"): + ss = StandardSelectionTable( + "nucleic_sugar", sel.NucleicSugarSelection, "sug_atoms", True + ) + assert ss.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_topology_groupmethods.py b/doc/source/scripts/tests/snapshot/test_gen_topology_groupmethods.py new file mode 100644 index 000000000..f585f489d --- /dev/null +++ b/doc/source/scripts/tests/snapshot/test_gen_topology_groupmethods.py @@ -0,0 +1,10 @@ +from unittest.mock import patch + +from gen_topology_groupmethods import TransplantedMethods +from MDAnalysis.core import selection as sel + + +def test_TransplantedMethods(snapshot): + with patch("builtins.open"): + tm = TransplantedMethods() + assert tm.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_topologyattr_defaults.py b/doc/source/scripts/tests/snapshot/test_gen_topologyattr_defaults.py new file mode 100644 index 000000000..bf461d275 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/test_gen_topologyattr_defaults.py @@ -0,0 +1,10 @@ +from unittest.mock import patch + +from gen_topologyattr_defaults import TopologyDefaults +from MDAnalysis.core import selection as sel + + +def test_TopologyDefaults(snapshot): + with patch("builtins.open"): + td = TopologyDefaults() + assert td.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py b/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py new file mode 100644 index 000000000..f13bc1ac0 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py @@ -0,0 +1,24 @@ +from unittest.mock import patch + +from gen_topologyparser_attrs import ConnectivityAttrs, TopologyAttrs, TopologyParsers +from MDAnalysis.core import selection as sel + + +def test_TopologyParsers(snapshot): + with patch("builtins.open"): + top = TopologyParsers() + assert top.lines == snapshot + + +def test_TopologyAttrs(snapshot): + with patch("builtins.open"): + top = TopologyParsers() + ta = TopologyAttrs(top.attrs) + assert ta.lines == snapshot + + +def test_ConnectivityAttrs(snapshot): + with patch("builtins.open"): + top = TopologyParsers() + ca = ConnectivityAttrs(top.attrs) + assert ca.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_unit_tables.py b/doc/source/scripts/tests/snapshot/test_gen_unit_tables.py new file mode 100644 index 000000000..e19a88f04 --- /dev/null +++ b/doc/source/scripts/tests/snapshot/test_gen_unit_tables.py @@ -0,0 +1,13 @@ +from pathlib import Path +from unittest.mock import mock_open, patch + +from gen_unit_tables import write_unit_table + + +def test_write_unit_table(snapshot): + with patch.object(Path, "open", mock_open()) as mock_open_file: + write_unit_table(filename=Path()) + + lines = [args[0] for args in mock_open_file.return_value.write.call_args_list] + # Exclude the first line, because it contains "Generated by /home/username/..." + assert lines[1:] == snapshot diff --git a/environment.yml b/environment.yml index 4321d58b3..7df96aa3b 100644 --- a/environment.yml +++ b/environment.yml @@ -57,3 +57,4 @@ dependencies: - git+https://github.com/MDAnalysis/mdanalysis@develop#egg=mdanalysis&subdirectory=package - git+https://github.com/MDAnalysis/mdanalysis@develop#egg=MDAnalysisTests&subdirectory=testsuite - git+https://github.com/MDAnalysis/MDAnalysisData@master#egg=MDAnalysisData + - syrupy # snapshot tests From c4991e99498934a8c851c336ce82610d3f27e078 Mon Sep 17 00:00:00 2001 From: Jan Domanski Date: Sun, 6 Aug 2023 16:38:18 +0100 Subject: [PATCH 02/15] allow snapshot tests to fail --- .github/workflows/gh-ci-tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/gh-ci-tests.yaml b/.github/workflows/gh-ci-tests.yaml index ab02e4dd0..78036dc8e 100644 --- a/.github/workflows/gh-ci-tests.yaml +++ b/.github/workflows/gh-ci-tests.yaml @@ -45,6 +45,7 @@ jobs: - name: "test snapshots" working-directory: doc/source/scripts/ + continue-on-error: true run: python -m pytest - name: "test notebooks" From b716c8ac7878db391131d18cd7ceefdb2e1906c9 Mon Sep 17 00:00:00 2001 From: Jan Domanski Date: Sun, 20 Aug 2023 15:05:02 +0200 Subject: [PATCH 03/15] more tests on ugly classes --- .../test_gen_topologyparser_attrs.ambr | 189 +++++++++++++++++- .../snapshot/test_gen_topologyparser_attrs.py | 8 +- 2 files changed, 195 insertions(+), 2 deletions(-) diff --git a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyparser_attrs.ambr b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyparser_attrs.ambr index 02369a9ce..8c8719734 100644 --- a/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyparser_attrs.ambr +++ b/doc/source/scripts/tests/snapshot/__snapshots__/test_gen_topologyparser_attrs.ambr @@ -231,7 +231,194 @@ ]), ]) # --- -# name: test_TopologyParsers +# name: test_TopologyParsers_attrs + defaultdict({ + 'altLocs': set({ + ':ref:`MMTF `', + ':ref:`PDB, ENT `', + ':ref:`PDBQT `', + ':ref:`XPDB `', + }), + 'angles': set({ + ':ref:`DATA `', + ':ref:`GSD `', + ':ref:`PSF `', + ':ref:`TOP, PRMTOP, PARM7 `', + ':ref:`TPR `', + ':ref:`XML `', + }), + 'atomiccharges': set({ + ':ref:`GMS `', + }), + 'atomnums': set({ + ':ref:`DMS `', + }), + 'bonds': set({ + ':ref:`DATA `', + ':ref:`DMS `', + ':ref:`GSD `', + ':ref:`MMTF `', + ':ref:`MOL2 `', + ':ref:`PSF `', + ':ref:`TOP, PRMTOP, PARM7 `', + ':ref:`TPR `', + ':ref:`TXYZ, ARC `', + ':ref:`XML `', + }), + 'chainIDs': set({ + ':ref:`DMS `', + ':ref:`PDB, ENT `', + ':ref:`XPDB `', + }), + 'charges': set({ + ':ref:`DATA `', + ':ref:`DMS `', + ':ref:`GSD `', + ':ref:`MMTF `', + ':ref:`MOL2 `', + ':ref:`PDBQT `', + ':ref:`PQR `', + ':ref:`PSF `', + ':ref:`TOP, PRMTOP, PARM7 `', + ':ref:`TPR `', + ':ref:`XML `', + }), + 'dihedrals': set({ + ':ref:`DATA `', + ':ref:`GSD `', + ':ref:`PSF `', + ':ref:`TOP, PRMTOP, PARM7 `', + ':ref:`TPR `', + ':ref:`XML `', + }), + 'elements': set({ + ':ref:`IN, FHIAIMS `', + ':ref:`MOL2 `', + ':ref:`PDB, ENT `', + ':ref:`TPR `', + ':ref:`TXYZ, ARC `', + ':ref:`XYZ `', + }), + 'icodes': set({ + ':ref:`MMTF `', + ':ref:`PDB, ENT `', + ':ref:`PDBQT `', + ':ref:`PQR `', + ':ref:`XPDB `', + }), + 'impropers': set({ + ':ref:`DATA `', + ':ref:`GSD `', + ':ref:`PSF `', + ':ref:`TOP, PRMTOP, PARM7 `', + ':ref:`TPR `', + ':ref:`XML `', + }), + 'masses': set({ + ':ref:`CONFIG `', + ':ref:`CRD `', + ':ref:`GMS `', + ':ref:`GRO `', + ':ref:`HISTORY `', + ':ref:`IN, FHIAIMS `', + ':ref:`LAMMPSDUMP `', + ':ref:`MMTF `', + ':ref:`MOL2 `', + ':ref:`PDB, ENT `', + ':ref:`PDBQT `', + ':ref:`PQR `', + ':ref:`TXYZ, ARC `', + ':ref:`XPDB `', + ':ref:`XYZ `', + }), + 'models': set({ + ':ref:`MMTF `', + }), + 'molnums': set({ + ':ref:`TPR `', + }), + 'moltypes': set({ + ':ref:`TPR `', + }), + 'names': set({ + ':ref:`CONFIG `', + ':ref:`CRD `', + ':ref:`DMS `', + ':ref:`GMS `', + ':ref:`GRO `', + ':ref:`GSD `', + ':ref:`HISTORY `', + ':ref:`IN, FHIAIMS `', + ':ref:`MMTF `', + ':ref:`MOL2 `', + ':ref:`PDB, ENT `', + ':ref:`PDBQT `', + ':ref:`PQR `', + ':ref:`PSF `', + ':ref:`TOP, PRMTOP, PARM7 `', + ':ref:`TPR `', + ':ref:`TXYZ, ARC `', + ':ref:`XPDB `', + ':ref:`XYZ `', + }), + 'occupancies': set({ + ':ref:`MMTF `', + ':ref:`PDB, ENT `', + ':ref:`PDBQT `', + ':ref:`XPDB `', + }), + 'radii': set({ + ':ref:`GSD `', + ':ref:`PQR `', + ':ref:`XML `', + }), + 'record_types': set({ + ':ref:`PDB, ENT `', + ':ref:`PDBQT `', + ':ref:`PQR `', + ':ref:`XPDB `', + }), + 'resnames': set({ + ':ref:`CRD `', + ':ref:`DMS `', + ':ref:`GRO `', + ':ref:`GSD `', + ':ref:`MMTF `', + ':ref:`MOL2 `', + ':ref:`PDB, ENT `', + ':ref:`PDBQT `', + ':ref:`PQR `', + ':ref:`PSF `', + ':ref:`TOP, PRMTOP, PARM7 `', + ':ref:`TPR `', + ':ref:`XPDB `', + }), + 'tempfactors': set({ + ':ref:`CRD `', + ':ref:`MMTF `', + ':ref:`PDB, ENT `', + ':ref:`PDBQT `', + ':ref:`XPDB `', + }), + 'type_indices': set({ + ':ref:`TOP, PRMTOP, PARM7 `', + }), + 'types': set({ + ':ref:`CONFIG `', + ':ref:`CRD `', + ':ref:`DMS `', + ':ref:`GMS `', + ':ref:`GRO `', + ':ref:`HISTORY `', + ':ref:`IN, FHIAIMS `', + ':ref:`PDB, ENT `', + ':ref:`PQR `', + ':ref:`XPDB `', + ':ref:`XYZ `', + }), + }) +# --- +# name: test_TopologyParsers_lines list([ list([ ':ref:`CONFIG `', diff --git a/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py b/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py index f13bc1ac0..36d7f4afc 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py +++ b/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py @@ -4,12 +4,18 @@ from MDAnalysis.core import selection as sel -def test_TopologyParsers(snapshot): +def test_TopologyParsers_lines(snapshot): with patch("builtins.open"): top = TopologyParsers() assert top.lines == snapshot +def test_TopologyParsers_attrs(snapshot): + with patch("builtins.open"): + top = TopologyParsers() + assert top.attrs == snapshot + + def test_TopologyAttrs(snapshot): with patch("builtins.open"): top = TopologyParsers() From 32699823b636295f75152e2a10035f21ad0a2e02 Mon Sep 17 00:00:00 2001 From: Jan Domanski Date: Sat, 19 Aug 2023 11:42:00 +0200 Subject: [PATCH 04/15] refactor away the document classes migrate gen_topology_groupmethods.py migrate gen_topologyattr_defaults.py migrate FormatOverview migrate CoordinateReaders migrate gen_format_overview_classes migrate TopologyParsers migrate TopologyAttrs migrate ConnectivityAttrs remove dead code, never executed remove all class attributes all non-strict mypy checks pass, mypy in pre-commit first nice simplification another nice simplification more simplifications further cleanups further trimmings continue to refactor update base.py harmonize to use private functions simpler code architecture more refactoring mypy strict mode on some files finish mypy changes flake8 on everything Update doc/source/scripts/base.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> Update doc/source/scripts/gen_format_overview_classes.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> Update doc/source/scripts/gen_format_overview_classes.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> Update doc/source/scripts/gen_format_overview_classes.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> Update doc/source/scripts/gen_format_overview_classes.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> review comments from Lily fixing mypy --- .pre-commit-config.yaml | 6 + doc/source/conf.py | 4 +- doc/source/scripts/.coverage | Bin 0 -> 53248 bytes doc/source/scripts/base.py | 201 ++++++++------- doc/source/scripts/core.py | 5 - .../scripts/gen_format_overview_classes.py | 216 ++++++++++------ doc/source/scripts/gen_selection_exporters.py | 60 +++-- doc/source/scripts/gen_standard_selections.py | 74 ++++-- .../scripts/gen_topology_groupmethods.py | 63 +++-- .../scripts/gen_topologyattr_defaults.py | 80 +++--- .../scripts/gen_topologyparser_attrs.py | 232 ++++++++++++------ doc/source/scripts/gen_unit_tables.py | 14 +- .../test_gen_format_overview_classes.py | 6 +- .../snapshot/test_gen_selection_exporters.py | 3 +- .../snapshot/test_gen_standard_selections.py | 48 +++- .../test_gen_topology_groupmethods.py | 3 +- .../test_gen_topologyattr_defaults.py | 3 +- .../snapshot/test_gen_topologyparser_attrs.py | 7 +- maintainer/update_json_stubs_sitemap.py | 6 +- mypy.ini | 4 + 20 files changed, 648 insertions(+), 387 deletions(-) create mode 100644 doc/source/scripts/.coverage create mode 100644 mypy.ini diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 127e00933..21af60744 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,3 +16,9 @@ repos: rev: 22.3.0 hooks: - id: black +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.5.1 + hooks: + - id: mypy + args: [--ignore-missing-imports, --install-types, --non-interactive, --strict] + exclude: "/tests/.*\\.py|clean_example_notebooks.py|update_json_stubs_sitemap.py" diff --git a/doc/source/conf.py b/doc/source/conf.py index 000f658cc..eb26b0c70 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -27,7 +27,7 @@ project = "MDAnalysis User Guide" -def sort_authors(filename): +def sort_authors(filename: str) -> list[str]: """Generate sorted list of authors from AUTHORS""" authors = [] with open(filename, "r") as f: @@ -207,7 +207,7 @@ def sort_authors(filename): } # nbsphinx -html_js_files = [ +html_js_files: list[str] = [ # 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js', # DEFAULT_EMBED_REQUIREJS_URL, ] diff --git a/doc/source/scripts/.coverage b/doc/source/scripts/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..94227d53309382f9cb9c0bb877ff5080f447ad67 GIT binary patch literal 53248 zcmeI4Z)_Y#6~K3I*SEKKdpBp2a7j(^R!VV9{0BD@B_NbKsZ~Wu34yezf_lAoH@4Tl zyFKsj`H!Fq*H%ghLP#x;HbT&EAR!_6Kr2CMkU&U)1XO&WLbMS9)%gH~5(v;FHSg^o zpU?5NmCkNc=dJE$W_M@aoA;YHGds7p`^lq+EsyKtwo^7eeUFe8L{Yd)*9AdP;hTnU zv?-8~qaBFF73o$&EzTI{lly~*B3jwhAemM!85?%QNK z1^A?ztbqd!Qx1-Upn~lbvG#e#tQ01>+ozk$78Y!%=e!qK>)7Q%&(=#;#W%C!TApQB zbUx1uHIEn9G_Vh$MH|3dX${C4LxaYGlA*2@bQ*=%C>drC3y(wPDt3gmQ4m!_VZY9m zS~(BMr)uRYHV%{s6nl27lC8>mc4+LIZksjQvSDvib4JLqMT1hciZxT?%Z=ZsH%j*T zW>oAx9gP4FxIGom?cE{@;FWydohiZfmSNUB+ut{!@r@w}v`0G=O0K(GJTc=t3gR*H zmgg=f)F!7{KHS1}@O*2(!CunrB-o2eCEXtPy9}1rgT?`GUfE{`BN(QG9Zk2xj8N0J z)!VSLPzOC*$RSMWuT(qHJ&vM6{-~-{=U|4v&9SK}#NR8)4 zx?8!ut#xNS4Ds$7VInhA!dV^$CqA^NF zeIz^s=JYG^+;CSbbHaSaP?$*66=^3vqSg(xb3 z>OGUDi=&X+qvvhA#LY@DH$aJlF6gve-LJ#-v(mnX40i!#Ow9K9b&4hz9OjQfr;GX* zB+6y8QVi!SoQ4CbF!p2TL_NVE0tNLR=#(yW(N!`dq2XB^u_E~cRbYZr%Vsg??${_R zB+gCp>%;}K(cPxUJ*&)h%;HzZcdR+n)e8=XlQ5U|_DHYi2H0B05Qex)PT-|ny<1dr zyLXHATG$zbamH|AQZJiPwZq+5las7E+3=SmFyO+~&PqQ)b}Mk;ZlD1Nx1a^{0fi`6 zc&(G{#Ra~|t_bj>>oT z5dk7V1c(3;AOb{y2oM1xKm>>Y5g-EZOafX=x|KzL@%R7}rLJ7~CxAN#?ijc;30B3} z1%X{)|9)p0NVO&cM1Tko0U|&IhyW2F0z`la5CI}U1R?^ObgLNs3J^<5U26Cv0N(%a zR6iuJlWb?^_nA|fcc-6D@7K<2B`ulyO6rc}kCUHK|DiqsS!g2yM1Tko0U|&Ih`>!v zV6;;f>cfNgx$unY;1oR53NK=qvz=+T3h%5Ky!YHwI=kBC2yf2eV89`1J%r^=7lq|xAnahfHA4@AH>tpD_6&U8$gIWZ zj6%tDU5>k0h69FPX1c(3;AOb`{5Dd9KEVg^S)_VQl`6;Sz1+5j zH!^Fr*3`P&wR$CsB0vO)01+SpM1Tko z0U|&IhyW2F0-J+CDl3cX_UvC?zWCa2RE5D#mVIq^cLox7W#m78d1>j|($dk{*JkH_ zw6x{LBQHIDt;fD{B&Mbz!`Aef#s7USqe1e$n*5)W30*k9^th5jA*nNxmW0GDN%^Du z_FUShDk>gU&nT$`B(^8y$)DSo-<4Ki=RL}q)2C0LefDZcI*z;XNB@4$=TH83X{XYG zWjfACoiZeL%2QXDU|U>T`q+KSRtXNhUwZXd+J%e9&%Jc*(sO5(#lyG6;OGZq^5s`Y z-QGQCpE(7N3!fklH^CRm<+!G`1k*X?2TeO z)q@BS0U|&IhyW2F0z`la5CI}U1c(3;*a!l6|DV?X8$p(25&>Y5x8*(;Pd~T>^u1X|I6$Z_E)yZ&a)Tc8GzrhU$bAp8v)L;AHs70--9f)5dk7V z1c(3;AOb{y2oM1xKm>>Y5g-B^PeAH~_w`Fz3>XF(4AK~A7^E;rVxVG>z(BzujzI?o OG6oU`F%0ni|NjSpLenGw literal 0 HcmV?d00001 diff --git a/doc/source/scripts/base.py b/doc/source/scripts/base.py index 7964ab11e..8b6dc0e73 100644 --- a/doc/source/scripts/base.py +++ b/doc/source/scripts/base.py @@ -1,15 +1,66 @@ -from __future__ import print_function - +import collections import os import pathlib import sys import textwrap -from collections import defaultdict +from collections.abc import Callable, Iterable +from typing import Any, Optional, Type +import pandas as pd import tabulate -class TableWriter(object): +def _run_method(method: Callable[..., str], *args: Any) -> str: + val = method(*args) + return val + + +def _generate_row( + *, column_spec: list[tuple[str, Callable[..., str]]], args: Iterable[Any] +) -> dict[str, str]: + row = {} + for heading, method in column_spec: + val = _run_method(method, *args) + row[heading] = val + return row + + +def _generate_table( + *, + input_items: Iterable[Any], + column_spec: list[tuple[str, Callable[..., str]]], +) -> pd.DataFrame: + rows = [] + for args in input_items: + if not isinstance(args, Iterable): + args = [args] + line = _generate_row(column_spec=column_spec, args=args) + rows.append(line) + df = pd.DataFrame(rows) + return df + + +def write_table( + *, + path: str, + headers: list[str], + lines: list[list[str]], + include_table: Optional[str] = None, +) -> None: + parent_directory = pathlib.Path(path).parent + parent_directory.mkdir(exist_ok=True, parents=True) + with open(path, "w") as f: + f.write(f'..\n Generated by {sys.argv[0].split("/")[-1]}\n\n') + if include_table: + f.write(f".. table:: {include_table}\n\n") + tabled = tabulate.tabulate(lines, headers=headers, tablefmt="rst") + if include_table: + tabled = textwrap.indent(tabled, " ") + f.write(tabled) + print("Wrote ", path) + + +class TableWriter: """ For writing tables with easy column switching. @@ -18,87 +69,73 @@ class TableWriter(object): Filename relative to source. """ - filename = "" - include_table = False - headings = [] - preprocess = [] - postprocess = [] - sort = True + def __init__( + self, + column_spec: list[tuple[str, Callable[..., str]]], + lines: list[list[str]], + filename: str = "", + include_table: Optional[str] = None, + sort: bool = True, + input_items: Optional[Iterable[Any]] = None, + ): + if column_spec: + assert input_items + assert (column_spec and not lines) or (lines and not column_spec) + stem = os.getcwd().split("source")[0] + self.path = os.path.join(stem, "source", filename) + self.filename = filename + self.include_table = include_table + self.sort = sort + self.input_items = input_items + self.column_spec = column_spec + self.lines = lines + self._df = pd.DataFrame() - def __getattr__(self, key: str) -> list: - return self.fields[key] + @property + def headers(self) -> list[str]: + return [column_name for column_name, _ in self.column_spec] - def __init__(self, *args, **kwargs): - stem = os.getcwd().split("source")[0] - self.path = os.path.join(stem, "source", self.filename) - self.fields = defaultdict(list) + @property + def fields(self) -> pd.DataFrame: + return self._df - parent_directory = pathlib.Path(self.path).parent - parent_directory.mkdir(exist_ok=True, parents=True) - self.get_lines(*args, **kwargs) - self.write_table() + def generate_lines_and_write_table(self) -> None: + df = _generate_table( + input_items=self.input_items or [], + column_spec=self.column_spec, + ) - def _run_method(self, method, *args, **kwargs): - sanitized = self.sanitize_name(method) - meth = getattr(self, sanitized) - val = meth(*args, **kwargs) - self.fields[method].append(val) - return val - - @staticmethod - def sanitize_name(name): - return "_" + name.replace(" ", "_").replace("/", "_").lower() - - def get_lines(self, *args, **kwargs): - lines = [] - for items in self._set_up_input(): - try: - lines.append(self.get_line(*items)) - except TypeError: # one argument - lines.append(self.get_line(items)) - if self.sort: - lines = sorted(lines) + lines = df.values.tolist() + lines = sorted(lines) if self.sort else lines self.lines = lines + self._df = df + self.write_table() + + def write_table(self) -> None: + write_table( + path=self.path, + headers=self.headers, + lines=self.lines, + include_table=self.include_table, + ) + + +# ==== HELPER FUNCTIONS ==== # + + +def sphinx_class(*, klass: Type[Any], tilde: bool = True) -> str: + prefix = "~" if tilde else "" + return f":class:`{prefix}{klass.__module__}.{klass.__name__}`" + + +def sphinx_method(*, method: Callable[..., Any], tilde: bool = True) -> str: + prefix = "~" if tilde else "" + return ":meth:`{}{}.{}`".format(prefix, method.__module__, method.__qualname__) + + +def sphinx_ref(*, txt: str, label: Optional[str] = None, suffix: str = "") -> str: + return f":ref:`{txt} <{label}{suffix}>`" + - def get_line(self, *args): - line = [] - for p in self.preprocess: - self._run_method(p, *args) - for h in self.headings: - line.append(self._run_method(h, *args)) - for p in self.postprocess: - self._run_method(p, *args) - return line - - def write_table(self): - with open(self.path, "w") as f: - f.write(f'..\n Generated by {sys.argv[0].split("/")[-1]}\n\n') - if self.include_table: - f.write(f".. table:: {self.include_table}\n\n") - tabled = tabulate.tabulate( - self.lines, headers=self.headings, tablefmt="rst" - ) - if self.include_table: - tabled = textwrap.indent(tabled, " ") - f.write(tabled) - print("Wrote ", self.filename) - - # ==== HELPER FUNCTIONS ==== # - - @staticmethod - def sphinx_class(klass, tilde=True): - prefix = "~" if tilde else "" - return ":class:`{}{}.{}`".format(prefix, klass.__module__, klass.__name__) - - @staticmethod - def sphinx_meth(meth, tilde=True): - prefix = "~" if tilde else "" - return ":meth:`{}{}.{}`".format(prefix, meth.__module__, meth.__qualname__) - - @staticmethod - def sphinx_ref(txt: str, label: str = None, suffix: str = "") -> str: - return f":ref:`{txt} <{label}{suffix}>`" - - @staticmethod - def sphinx_link(txt): - return "`{}`_".format(txt) +def sphinx_link(*, txt: str) -> str: + return "`{}`_".format(txt) diff --git a/doc/source/scripts/core.py b/doc/source/scripts/core.py index 84c6d3073..a8dd7116e 100644 --- a/doc/source/scripts/core.py +++ b/doc/source/scripts/core.py @@ -1,8 +1,3 @@ -from __future__ import print_function - -import os - -import tabulate from MDAnalysis import _TOPOLOGY_ATTRS # ====== TOPOLOGY ====== # diff --git a/doc/source/scripts/gen_format_overview_classes.py b/doc/source/scripts/gen_format_overview_classes.py index fa0ad3e23..8ce666e59 100644 --- a/doc/source/scripts/gen_format_overview_classes.py +++ b/doc/source/scripts/gen_format_overview_classes.py @@ -7,115 +7,171 @@ """ from collections import defaultdict +from collections.abc import Iterable +from typing import Any, Final, Literal, Type +import base from base import TableWriter from core import DESCRIPTIONS from MDAnalysis import _CONVERTERS, _PARSERS, _READERS, _SINGLEFRAME_WRITERS -FILE_TYPES = defaultdict(dict) +HANDLER_T = Literal[ + "Coordinate reader", "Coordinate writer", "Topology parser", "Converter" +] -for clstype, dct in ( +PAIR_T = tuple[HANDLER_T, dict[str, Any]] + +handlers: Iterable[PAIR_T] = [ ("Coordinate reader", _READERS), ("Coordinate writer", _SINGLEFRAME_WRITERS), ("Topology parser", _PARSERS), ("Converter", _CONVERTERS), -): - for fmt, klass in dct.items(): - if fmt in ("CHAIN", "MEMORY", "MINIMAL", "NULL"): +] + +FILE_TYPES: dict[str, dict[HANDLER_T, Any]] = defaultdict(dict) + +for handler, dct in handlers: + for format, klass in dct.items(): + if format in {"CHAIN", "MEMORY", "MINIMAL", "NULL"}: continue # get their own pages - FILE_TYPES[fmt][clstype] = klass + FILE_TYPES[format][handler] = klass -sorted_types = sorted(FILE_TYPES.items()) + +SORTED_FILE_TYPES: Final = sorted(FILE_TYPES.items()) SUCCESS = "\u2713" # checkmark FAIL = "" -class FormatOverview(TableWriter): - filename = "formats/format_overview.txt" - include_table = "Table of all supported formats in MDAnalysis" - preprocess = ["keys"] - headings = ["File type", "Description", "Topology", "Coordinates", "Read", "Write"] - - def _set_up_input(self): - return sorted_types - - def _file_type(self, fmt, handlers): - return self.sphinx_ref(fmt, self.keys[-1], suffix="-format") +def _create_key(fmt: str, handlers: dict[HANDLER_T, Type[Any]]) -> str: + if fmt in DESCRIPTIONS: + key = fmt + else: + key = list(handlers.values())[0].format[0] - def _keys(self, fmt, handlers): - if fmt in DESCRIPTIONS: + # raise an informative error + if key not in DESCRIPTIONS: key = fmt - else: - key = list(handlers.values())[0].format[0] + return key - # raise an informative error - if key not in DESCRIPTIONS: - key = fmt - return key - def _description(self, fmt, handlers): - return DESCRIPTIONS[self.keys[-1]] +def _file_type(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + return base.sphinx_ref(txt=fmt, label=key, suffix="-format") - def _topology(self, fmt, handlers): - if "Topology parser" in handlers: - return SUCCESS - return FAIL - - def _coordinates(self, fmt, handlers): - if "Coordinate reader" in handlers: - return SUCCESS - return FAIL - def _read(self, fmt, handlers): - return SUCCESS +def _description(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + return DESCRIPTIONS[key] - def _write(self, fmt, handlers): - if "Coordinate writer" in handlers: - return SUCCESS - if "Converter" in handlers: - return SUCCESS - return FAIL +class FormatOverview: + def __init__(self) -> None: + def _topology(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + if "Topology parser" in handlers: + return SUCCESS + return FAIL -class CoordinateReaders(FormatOverview): - filename = "formats/coordinate_readers.txt" - include_table = "Table of supported coordinate readers and the information read" - headings = ["File type", "Description", "Velocities", "Forces"] + def _coordinates( + fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str + ) -> str: + if "Coordinate reader" in handlers: + return SUCCESS + return FAIL - def _set_up_input(self): - return [(x, y) for x, y in sorted_types if "Coordinate reader" in y] - - def _velocities(self, fmt, handlers): - if handlers["Coordinate reader"].units.get("velocity", None): - return SUCCESS - return FAIL - - def _forces(self, fmt, handlers): - if handlers["Coordinate reader"].units.get("force", None): + def _read(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: return SUCCESS - return FAIL - - -class SphinxClasses(TableWriter): - filename = "formats/reference/classes/{}.txt" - def __init__(self, fmt): - self.filename = self.filename.format(fmt) - self.fmt = fmt - super(SphinxClasses, self).__init__() - - def get_lines(self): - lines = [] - for label, klass in sorted(FILE_TYPES[self.fmt].items()): - lines.append( - ["**{}**".format(label), self.sphinx_class(klass, tilde=False)] - ) - self.lines = lines + def _write(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + if "Coordinate writer" in handlers: + return SUCCESS + if "Converter" in handlers: + return SUCCESS + return FAIL + + input_items = [ + (format, handlers, _create_key(format, handlers)) + for format, handlers in SORTED_FILE_TYPES + ] + + self.table_writer = TableWriter( + filename="formats/format_overview.txt", + include_table="Table of all supported formats in MDAnalysis", + column_spec=[ + ("File type", _file_type), + ("Description", _description), + ("Topology", _topology), + ("Coordinates", _coordinates), + ("Read", _read), + ("Write", _write), + ], + input_items=input_items, + lines=[], + ) + self.table_writer.generate_lines_and_write_table() + self.table_writer.fields["keys"] = list(zip(*input_items))[2] + + +class CoordinateReaders: + def __init__(self) -> None: + def _velocities( + fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str + ) -> str: + if handlers["Coordinate reader"].units.get("velocity"): + return SUCCESS + return FAIL + + def _forces(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + if handlers["Coordinate reader"].units.get("force"): + return SUCCESS + return FAIL + + input_items = [ + (format, handlers, _create_key(format, handlers)) + for format, handlers in SORTED_FILE_TYPES + if "Coordinate reader" in handlers + ] + self.table_writer = TableWriter( + filename="formats/coordinate_readers.txt", + include_table="Table of supported coordinate readers and the information read", + input_items=input_items, + column_spec=[ + ("File type", _file_type), + ("Description", _description), + ("Velocities", _velocities), + ("Forces", _forces), + ], + lines=[], + ) + self.table_writer.generate_lines_and_write_table() + + +class SphinxClasses: + def __init__(self, fmt: str): + def _custom_get_lines() -> list[list[str]]: + lines = [] + for label, klass in sorted(FILE_TYPES[fmt].items()): + lines.append( + [ + f"**{label}**", + base.sphinx_class(klass=klass, tilde=False), + ] + ) + return lines + + lines = _custom_get_lines() + self.table_writer = TableWriter( + filename=f"formats/reference/classes/{fmt}.txt", + lines=lines, + column_spec=[], + ) + self.table_writer.write_table() + + +def main() -> None: + overview = FormatOverview() + CoordinateReaders() + for key in set(overview.table_writer.fields["keys"]): + SphinxClasses(key) if __name__ == "__main__": - ov = FormatOverview() - CoordinateReaders() - for key in set(ov.fields["keys"]): - SphinxClasses(key) + main() diff --git a/doc/source/scripts/gen_selection_exporters.py b/doc/source/scripts/gen_selection_exporters.py index f4ffbab04..01d7900e1 100644 --- a/doc/source/scripts/gen_selection_exporters.py +++ b/doc/source/scripts/gen_selection_exporters.py @@ -4,8 +4,10 @@ - ../formats/selection_exporters.txt """ +import base from base import TableWriter from MDAnalysis import _SELECTION_WRITERS +from MDAnalysis.selections.base import SelectionWriterBase SELECTION_DESCRIPTIONS = { "vmd": "VMD macros, available in Representations", @@ -16,31 +18,39 @@ } -class SelectionExporterWriter(TableWriter): - headings = ["Program", "Extension", "Description", "Class"] - filename = "formats/selection_exporter_formats.txt" - include_table = "Supported selection exporters" - sort = True - - def _set_up_input(self): - return set(_SELECTION_WRITERS.values()) - - def _program(self, klass): - # classes have multiple formats. - # First tends to be the program name, second is extension - p = klass.format - if isinstance(p, (list, tuple)): - p = p[0] - return self.sphinx_link(p) - - def _extension(self, klass): - return klass.ext - - def _description(self, klass): - return SELECTION_DESCRIPTIONS[klass.ext] - - def _class(self, klass): - return self.sphinx_class(klass, tilde=False) +class SelectionExporterWriter: + def __init__(self) -> None: + def _program(klass: SelectionWriterBase) -> str: + # classes have multiple formats. + # First tends to be the program name, second is extension + p = klass.format + if isinstance(p, (list, tuple)): + p = p[0] + return base.sphinx_link(txt=p) + + def _extension(klass: SelectionWriterBase) -> str: + return klass.ext # type: ignore + + def _description(klass: SelectionWriterBase) -> str: + return SELECTION_DESCRIPTIONS[klass.ext] + + def _class(klass: SelectionWriterBase) -> str: + return base.sphinx_class(klass=klass, tilde=False) + + self.table_writer = TableWriter( + filename="formats/selection_exporter_formats.txt", + include_table="Supported selection exporters", + sort=True, + input_items=set(_SELECTION_WRITERS.values()), + column_spec=[ + ("Program", _program), + ("Extension", _extension), + ("Description", _description), + ("Class", _class), + ], + lines=[], + ) + self.table_writer.generate_lines_and_write_table() if __name__ == "__main__": diff --git a/doc/source/scripts/gen_standard_selections.py b/doc/source/scripts/gen_standard_selections.py index 1498365b3..c50807a81 100755 --- a/doc/source/scripts/gen_standard_selections.py +++ b/doc/source/scripts/gen_standard_selections.py @@ -8,36 +8,68 @@ - nucleobase atoms - nucleic sugar atoms """ +from typing import Any + from base import TableWriter from MDAnalysis.core import selection as sel -def chunk_list(lst, n=8): - return [lst[i : i + n] for i in range(0, len(lst), n)] +def _chunk_list(lst: list[str], chunk_size: int = 8) -> list[list[str]]: + return [lst[i : i + chunk_size] for i in range(0, len(lst), chunk_size)] + +# override get_lines as there are no headings +def _custom_get_lines( + *, + klass: sel.Selection, + attribute_name: str, + sort: bool = False, + chunk_size: int = 8 +) -> list[list[str]]: + selected = getattr(klass, attribute_name) + if sort: + selected = sorted(selected) -class StandardSelectionTable(TableWriter): - sort = False - filename = "generated/selections/{}.txt" + table = _chunk_list(list(selected), chunk_size=chunk_size) + return table - def __init__(self, filename, *args, **kwargs): - self.filename = self.filename.format(filename) - super(StandardSelectionTable, self).__init__(*args, **kwargs) - # override get_lines as there are no headings - def get_lines(self, klass, attr, sort=False, n=8): - selected = getattr(klass, attr) - if sort: - selected = sorted(selected) +class StandardSelectionTable: + def __init__(self, filename: str, *args: Any, **kwargs: Any) -> None: - table = chunk_list(list(selected), n=n) - self.lines = table + lines = _custom_get_lines(*args, **kwargs) + self.table_writer = TableWriter( + sort=False, + filename="generated/selections/{}.txt".format(filename), + lines=lines, + column_spec=[], + ) + self.table_writer.write_table() if __name__ == "__main__": - StandardSelectionTable("protein", sel.ProteinSelection, "prot_res", True) - StandardSelectionTable("protein_backbone", sel.BackboneSelection, "bb_atoms") - StandardSelectionTable("nucleic", sel.NucleicSelection, "nucl_res") - StandardSelectionTable("nucleic_backbone", sel.NucleicBackboneSelection, "bb_atoms") - StandardSelectionTable("base", sel.BaseSelection, "base_atoms") - StandardSelectionTable("nucleic_sugar", sel.NucleicSugarSelection, "sug_atoms") + StandardSelectionTable( + "protein", + klass=sel.ProteinSelection, + attribute_name="prot_res", + sort=True, + ) + StandardSelectionTable( + "protein_backbone", + klass=sel.BackboneSelection, + attribute_name="bb_atoms", + ) + StandardSelectionTable( + "nucleic", klass=sel.NucleicSelection, attribute_name="nucl_res" + ) + StandardSelectionTable( + "nucleic_backbone", + klass=sel.NucleicBackboneSelection, + attribute_name="bb_atoms", + ) + StandardSelectionTable("base", klass=sel.BaseSelection, attribute_name="base_atoms") + StandardSelectionTable( + "nucleic_sugar", + klass=sel.NucleicSugarSelection, + attribute_name="sug_atoms", + ) diff --git a/doc/source/scripts/gen_topology_groupmethods.py b/doc/source/scripts/gen_topology_groupmethods.py index f6eb92ec9..b4bcf69ca 100644 --- a/doc/source/scripts/gen_topology_groupmethods.py +++ b/doc/source/scripts/gen_topology_groupmethods.py @@ -5,32 +5,51 @@ A table of transplanted methods. """ -from collections import defaultdict +from collections.abc import Callable +from typing import Any +import base from base import TableWriter from core import TOPOLOGY_CLS from MDAnalysis.core.groups import GroupBase - - -class TransplantedMethods(TableWriter): - headings = ["Method", "Description", "Requires"] - filename = "generated/topology/groupmethods.txt" - - def _set_up_input(self): - items = [] - for klass in TOPOLOGY_CLS: - for name, method in klass.transplants[GroupBase]: - items.append([name, klass, method]) - return [x[1:] for x in sorted(items)] - - def _method(self, klass, method): - return self.sphinx_meth(method) - - def _description(self, klass, method): - return " ".join(method.__doc__.split(".\n")[0].split()) - - def _requires(self, klass, method): - return klass.attrname +from MDAnalysis.core.topologyattrs import TopologyAttr + + +class TransplantedMethods: + def __init__(self) -> None: + def _generate_input_items() -> list[tuple[TopologyAttr, Any]]: + items = [] + for klass in TOPOLOGY_CLS: + for name, method in klass.transplants[GroupBase]: + items.append((name, klass, method)) + return [x[1:] for x in sorted(items)] + + def _method(klass: TopologyAttr, method: Callable[[TopologyAttr], str]) -> str: + return base.sphinx_method(method=method) + + def _description( + klass: TopologyAttr, method: Callable[[TopologyAttr], str] + ) -> str: + assert method.__doc__ + return " ".join(method.__doc__.split(".\n")[0].split()) + + def _requires( + klass: TopologyAttr, method: Callable[[TopologyAttr], str] + ) -> str: + return klass.attrname # type: ignore + + input_items = _generate_input_items() + self.table_writer = TableWriter( + filename="generated/topology/groupmethods.txt", + input_items=input_items, + column_spec=[ + ("Method", _method), + ("Description", _description), + ("Requires", _requires), + ], + lines=[], + ) + self.table_writer.generate_lines_and_write_table() if __name__ == "__main__": diff --git a/doc/source/scripts/gen_topologyattr_defaults.py b/doc/source/scripts/gen_topologyattr_defaults.py index 1990ea6ce..0ee5e3707 100644 --- a/doc/source/scripts/gen_topologyattr_defaults.py +++ b/doc/source/scripts/gen_topologyattr_defaults.py @@ -7,7 +7,12 @@ from base import TableWriter from core import TOPOLOGY_CLS -from MDAnalysis.core.topologyattrs import AtomAttr, ResidueAttr, SegmentAttr +from MDAnalysis.core.topologyattrs import ( + AtomAttr, + ResidueAttr, + SegmentAttr, + TopologyAttr, +) DEFAULTS = { "resids": "continuous sequence from 1 to n_residues", @@ -16,42 +21,51 @@ } -class TopologyDefaults(TableWriter): - filename = "generated/topology/defaults.txt" - headings = ("Atom", "AtomGroup", "default", "level", "type") - sort = True +class TopologyDefaults: + def __init__(self) -> None: + def _atom(klass: TopologyAttr) -> str: + return klass.attrname # type: ignore - def _set_up_input(self): - return TOPOLOGY_CLS + def _atomgroup(klass: TopologyAttr) -> str: + return klass.singular # type: ignore - def _atom(self, klass): - return klass.attrname + def _default(klass: TopologyAttr) -> str: + try: + return DEFAULTS[klass.attrname] + except KeyError: + try: + return repr(klass._gen_initial_values(1, 1, 1)[0]) + except NotImplementedError: + return "No default values" - def _atomgroup(self, klass): - return klass.singular + def _level(klass: TopologyAttr) -> str: + if issubclass(klass, AtomAttr): + level = "atom" + elif issubclass(klass, ResidueAttr): + level = "residue" + elif issubclass(klass, SegmentAttr): + level = "segment" + else: + raise ValueError + return level - def _default(self, klass): - try: - return DEFAULTS[klass.attrname] - except KeyError: - try: - return repr(klass._gen_initial_values(1, 1, 1)[0]) - except NotImplementedError: - return "No default values" - - def _level(self, klass): - if issubclass(klass, AtomAttr): - level = "atom" - elif issubclass(klass, ResidueAttr): - level = "residue" - elif issubclass(klass, SegmentAttr): - level = "segment" - else: - raise ValueError - return level - - def _type(self, klass): - return klass.dtype + def _type(klass: TopologyAttr) -> str: + return klass.dtype # type: ignore + + self.table_writer = TableWriter( + filename="generated/topology/defaults.txt", + sort=True, + input_items=TOPOLOGY_CLS, + column_spec=[ + ("Atom", _atom), + ("AtomGroup", _atomgroup), + ("default", _default), + ("level", _level), + ("type", _type), + ], + lines=[], + ) + self.table_writer.generate_lines_and_write_table() if __name__ == "__main__": diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index 340960a67..a40bfddea 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -7,12 +7,13 @@ This script imports the testsuite, which tests these. """ -import os -import sys 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 MDAnalysisTests.topology.base import mandatory_attrs from MDAnalysisTests.topology.test_crd import TestCRDParser from MDAnalysisTests.topology.test_dlpoly import ( @@ -64,101 +65,170 @@ ) -MANDATORY_ATTRS = set(mandatory_attrs) - - -parser_attrs = {} - - -for p in PARSER_TESTS: - e, g = set(p.expected_attrs) - MANDATORY_ATTRS, set(p.guessed_attrs) - # clunky hack for PDB - if p is TestPDBParser: - e.add("elements") - parser_attrs[p.parser] = (e, g) - - -class TopologyParsers(TableWriter): - headings = ["Format", "Description", "Attributes read", "Attributes guessed"] - preprocess = ["keys"] - filename = "formats/topology_parsers.txt" - include_table = "Table of supported topology parsers and the attributes read" - sort = True - - def __init__(self): - self.attrs = defaultdict(set) - super(TopologyParsers, self).__init__() - - def _set_up_input(self): - return [[x, *y] for x, y in parser_attrs.items()] - - def get_line(self, parser, expected, guessed): - line = super(TopologyParsers, self).get_line(parser, expected, guessed) - for a in expected | guessed: - self.attrs[a].add(self.fields["Format"][-1]) - return line - - def _keys(self, parser, *args): - f = parser.format - if isinstance(f, (list, tuple)): - key = f[0] - label = ", ".join(f) - else: - key = label = f - return (key, label) - - def _description(self, *args): - key, label = self.keys[-1] - return DESCRIPTIONS[key] +def create_parser_attributes() -> dict[Any, tuple[set[str], set[str]]]: + parser_attrs = {} + for test_parser_class in PARSER_TESTS: + expected, guessed = set(test_parser_class.expected_attrs) - set( + mandatory_attrs + ), 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) + return parser_attrs + + +class TopologyParsers: + def __init__(self) -> None: + def _keys(parser: TopologyReaderBase) -> tuple[str, str]: + f = parser.format + if isinstance(f, (list, tuple)): + key = f[0] + label = ", ".join(f) + else: + key = label = f + return (key, label) + + def _description( + parser: TopologyReaderBase, + expected: set[str], + guessed: set[str], + key_label: tuple[str, str], + ) -> str: + key, label = key_label + return DESCRIPTIONS[key] + + def _format( + parser: TopologyReaderBase, + expected: set[str], + guessed: set[str], + key_label: tuple[str, str], + ) -> str: + 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: + vals = sorted(expected - guessed) + return ", ".join(vals) + + def _attributes_guessed( + parser: TopologyReaderBase, + expected: set[str], + guessed: set[str], + key_label: tuple[str, str], + ) -> str: + 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", + sort=True, + input_items=input_items, + lines=[], + column_spec=[ + ("Format", _format), + ("Description", _description), + ("Attributes read", _attributes_read), + ("Attributes guessed", _attributes_guessed), + ], + ) + self.table_writer.generate_lines_and_write_table() + + attrs = defaultdict(set) + + def _get_attrs( + line: list[str], + format: str, + parser: TopologyReaderBase, + expected: set[str], + guessed: set[str], + key_label: tuple[str, str], + ) -> None: + for attribute in expected | guessed: + attrs[attribute].add(format) + + for line, format, args in zip( + self.table_writer.lines, + self.table_writer.fields["Format"], + input_items, + ): + _get_attrs(line, format, *args) - def _format(self, *args): - key, label = self.keys[-1] - return self.sphinx_ref(label, key, suffix="-format") + self.attrs = attrs - def _attributes_read(self, parser, expected, guessed): - vals = sorted(expected - guessed) - return ", ".join(vals) - def _attributes_guessed(self, parser, expected, guessed): - return ", ".join(sorted(guessed)) +class TopologyAttrs: + def __init__(self, attrs: dict[str, Any]) -> None: + def _atom(name: str, singular: str, description: str) -> str: + return singular + def _atomgroup(name: str, singular: str, description: str) -> str: + return name -class TopologyAttrs(TableWriter): - headings = ("Atom", "AtomGroup", "Description", "Supported formats") - filename = "generated/topology/topologyattrs.txt" + def _description(name: str, singular: str, description: str) -> str: + return description - def __init__(self, attrs): - self.attrs = attrs - super(TopologyAttrs, self).__init__() + def _supported_formats(name: str, singular: str, description: str) -> str: + return ", ".join(sorted(attrs[name])) - def _set_up_input(self): - return sorted( - [x, *y] for x, y in NON_CORE_ATTRS.items() if x not in MANDATORY_ATTRS + 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=[], + input_items=input_items, + column_spec=[ + ("Atom", _atom), + ("AtomGroup", _atomgroup), + ("Description", _description), + ("Supported formats", _supported_formats), + ], + ) + self.table_writer.generate_lines_and_write_table() - def _atom(self, name, singular, *args): - return singular - - def _atomgroup(self, name, *args): - return name - def _description(self, name, singular, description): - return description +class ConnectivityAttrs: + def __init__(self, attrs: dict[str, Any]) -> None: + def _atom(name: str) -> str: + return name - def _supported_formats(self, name, singular, description): - return ", ".join(sorted(self.attrs[name])) + def _atomgroup(name: str) -> str: + return name + def _supported_formats(name: str) -> str: + return ", ".join(sorted(attrs[name])) -class ConnectivityAttrs(TopologyAttrs): - headings = ("Atom", "AtomGroup", "Supported formats") - filename = "generated/topology/connectivityattrs.txt" + input_items = [("bonds",), ("angles",), ("dihedrals",), ("impropers",)] - def _set_up_input(self): - inp = [[x] * 3 for x in "bonds angles dihedrals impropers".split()] - return inp + self.table_writer = TableWriter( + filename="generated/topology/connectivityattrs.txt", + input_items=input_items, + lines=[], + column_spec=[ + ("Atom", _atom), + ("AtomGroup", _atomgroup), + ("Supported formats", _supported_formats), + ], + ) + self.table_writer.generate_lines_and_write_table() -if __name__ == "__main__": +def main() -> None: top = TopologyParsers() TopologyAttrs(top.attrs) ConnectivityAttrs(top.attrs) + + +if __name__ == "__main__": + main() diff --git a/doc/source/scripts/gen_unit_tables.py b/doc/source/scripts/gen_unit_tables.py index d8398eca2..8fffdf7c6 100755 --- a/doc/source/scripts/gen_unit_tables.py +++ b/doc/source/scripts/gen_unit_tables.py @@ -10,19 +10,20 @@ from MDAnalysis.units import conversion_factor -def write_unit_table(filename): +def write_unit_table( + filename: str, +) -> list[tuple[str, list[tuple[str, float]]]]: headings = ["Unit", "Conversion factor"] - table_heading = ".. table:: {}" tables = [] for data_type, items in conversion_factor.items(): - lines = sorted(list(items.items())) + lines = sorted(items.items()) tables.append((data_type, lines)) parent_directory = pathlib.Path(__file__).parent.parent parent_directory.mkdir(exist_ok=True, parents=True) - filename = parent_directory / filename + output = parent_directory / filename - with filename.open("w") as f: + with output.open("w") as f: f.write(".. Generated by {}\n".format(sys.argv[0])) for data_type, lines in tables: line = "\n" + "-" * len(data_type) + "\n" @@ -32,7 +33,8 @@ def write_unit_table(filename): f.write("\n\n") f.write( textwrap.indent( - tabulate.tabulate(lines, headers=headings, tablefmt="rst"), " " + tabulate.tabulate(lines, headers=headings, tablefmt="rst"), + " ", ) ) f.write("\n") diff --git a/doc/source/scripts/tests/snapshot/test_gen_format_overview_classes.py b/doc/source/scripts/tests/snapshot/test_gen_format_overview_classes.py index 835e5d039..647f4f89b 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_format_overview_classes.py +++ b/doc/source/scripts/tests/snapshot/test_gen_format_overview_classes.py @@ -15,16 +15,16 @@ def test_FILE_TYPES(): def test_FormatOverview(snapshot): with patch("builtins.open"): ov = FormatOverview() - assert ov.lines == snapshot + assert ov.table_writer.lines == snapshot def test_CoordinateReaders(snapshot): with patch("builtins.open"): cr = CoordinateReaders() - assert cr.lines == snapshot + assert cr.table_writer.lines == snapshot def test_SphinxClasses(snapshot): with patch("builtins.open"): sc = SphinxClasses("PDB") - assert sc.lines == snapshot + assert sc.table_writer.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_selection_exporters.py b/doc/source/scripts/tests/snapshot/test_gen_selection_exporters.py index 34d8a5616..fae8d5d68 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_selection_exporters.py +++ b/doc/source/scripts/tests/snapshot/test_gen_selection_exporters.py @@ -1,10 +1,9 @@ from unittest.mock import patch from gen_selection_exporters import SelectionExporterWriter -from MDAnalysis.core import selection as sel def test_SelectionExporterWriter(snapshot): with patch("builtins.open"): se = SelectionExporterWriter() - assert se.lines == snapshot + assert se.table_writer.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_standard_selections.py b/doc/source/scripts/tests/snapshot/test_gen_standard_selections.py index f8224b8c2..ff47ea158 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_standard_selections.py +++ b/doc/source/scripts/tests/snapshot/test_gen_standard_selections.py @@ -6,41 +6,65 @@ def test_StandardSelectionTable_protein(snapshot): with patch("builtins.open"): - ss = StandardSelectionTable("protein", sel.ProteinSelection, "prot_res", True) - assert ss.lines == snapshot + ss = StandardSelectionTable( + "protein", + klass=sel.ProteinSelection, + attribute_name="prot_res", + sort=True, + ) + assert ss.table_writer.lines == snapshot def test_StandardSelectionTable_protein_backbone(snapshot): with patch("builtins.open"): ss = StandardSelectionTable( - "protein_backbone", sel.BackboneSelection, "bb_atoms", True + "protein_backbone", + klass=sel.BackboneSelection, + attribute_name="bb_atoms", + sort=True, ) - assert ss.lines == snapshot + assert ss.table_writer.lines == snapshot def test_StandardSelectionTable_nucleic(snapshot): with patch("builtins.open"): - ss = StandardSelectionTable("nucleic", sel.NucleicSelection, "nucl_res", True) - assert ss.lines == snapshot + ss = StandardSelectionTable( + "nucleic", + klass=sel.NucleicSelection, + attribute_name="nucl_res", + sort=True, + ) + assert ss.table_writer.lines == snapshot def test_StandardSelectionTable_nucleic_backbone(snapshot): with patch("builtins.open"): ss = StandardSelectionTable( - "nucleic_backbone", sel.NucleicBackboneSelection, "bb_atoms", True + "nucleic_backbone", + klass=sel.NucleicBackboneSelection, + attribute_name="bb_atoms", + sort=True, ) - assert ss.lines == snapshot + assert ss.table_writer.lines == snapshot def test_StandardSelectionTable_base(snapshot): with patch("builtins.open"): - ss = StandardSelectionTable("base", sel.BaseSelection, "base_atoms", True) - assert ss.lines == snapshot + ss = StandardSelectionTable( + "base", + klass=sel.BaseSelection, + attribute_name="base_atoms", + sort=True, + ) + assert ss.table_writer.lines == snapshot def test_StandardSelectionTable_nucleic_sugar(snapshot): with patch("builtins.open"): ss = StandardSelectionTable( - "nucleic_sugar", sel.NucleicSugarSelection, "sug_atoms", True + "nucleic_sugar", + klass=sel.NucleicSugarSelection, + attribute_name="sug_atoms", + sort=True, ) - assert ss.lines == snapshot + assert ss.table_writer.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_topology_groupmethods.py b/doc/source/scripts/tests/snapshot/test_gen_topology_groupmethods.py index f585f489d..741bd1263 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_topology_groupmethods.py +++ b/doc/source/scripts/tests/snapshot/test_gen_topology_groupmethods.py @@ -1,10 +1,9 @@ from unittest.mock import patch from gen_topology_groupmethods import TransplantedMethods -from MDAnalysis.core import selection as sel def test_TransplantedMethods(snapshot): with patch("builtins.open"): tm = TransplantedMethods() - assert tm.lines == snapshot + assert tm.table_writer.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_topologyattr_defaults.py b/doc/source/scripts/tests/snapshot/test_gen_topologyattr_defaults.py index bf461d275..47b817b6d 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_topologyattr_defaults.py +++ b/doc/source/scripts/tests/snapshot/test_gen_topologyattr_defaults.py @@ -1,10 +1,9 @@ from unittest.mock import patch from gen_topologyattr_defaults import TopologyDefaults -from MDAnalysis.core import selection as sel def test_TopologyDefaults(snapshot): with patch("builtins.open"): td = TopologyDefaults() - assert td.lines == snapshot + assert td.table_writer.lines == snapshot diff --git a/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py b/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py index 36d7f4afc..031d91903 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py +++ b/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py @@ -1,13 +1,12 @@ from unittest.mock import patch from gen_topologyparser_attrs import ConnectivityAttrs, TopologyAttrs, TopologyParsers -from MDAnalysis.core import selection as sel def test_TopologyParsers_lines(snapshot): with patch("builtins.open"): top = TopologyParsers() - assert top.lines == snapshot + assert top.table_writer.lines == snapshot def test_TopologyParsers_attrs(snapshot): @@ -20,11 +19,11 @@ def test_TopologyAttrs(snapshot): with patch("builtins.open"): top = TopologyParsers() ta = TopologyAttrs(top.attrs) - assert ta.lines == snapshot + assert ta.table_writer.lines == snapshot def test_ConnectivityAttrs(snapshot): with patch("builtins.open"): top = TopologyParsers() ca = ConnectivityAttrs(top.attrs) - assert ca.lines == snapshot + assert ca.table_writer.lines == snapshot diff --git a/maintainer/update_json_stubs_sitemap.py b/maintainer/update_json_stubs_sitemap.py index 921dea637..b38549d3c 100644 --- a/maintainer/update_json_stubs_sitemap.py +++ b/maintainer/update_json_stubs_sitemap.py @@ -16,11 +16,7 @@ import shutil import textwrap import xml.etree.ElementTree as ET - -try: - from urllib.request import Request, urlopen -except ImportError: - from urllib2 import Request, urlopen +from urllib.request import Request, urlopen URL = os.environ["URL"] VERSION = os.environ["VERSION"] diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 000000000..0c95025b6 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,4 @@ +[mypy] +mypy_path = doc/source/scripts/ +exclude = + conf.py From 75e59a246e10f4111179ffcd02426de809ff14d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Doma=C5=84ski?= Date: Thu, 31 Aug 2023 11:30:32 +0100 Subject: [PATCH 05/15] Update doc/source/scripts/base.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> --- doc/source/scripts/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/scripts/base.py b/doc/source/scripts/base.py index 8b6dc0e73..d678b0df5 100644 --- a/doc/source/scripts/base.py +++ b/doc/source/scripts/base.py @@ -138,4 +138,4 @@ def sphinx_ref(*, txt: str, label: Optional[str] = None, suffix: str = "") -> st def sphinx_link(*, txt: str) -> str: - return "`{}`_".format(txt) + return f"`{txt}`_" From 37860b763a8d591d10af243655736bb36e2849c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Doma=C5=84ski?= Date: Thu, 31 Aug 2023 11:30:47 +0100 Subject: [PATCH 06/15] Update doc/source/scripts/gen_format_overview_classes.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> --- doc/source/scripts/gen_format_overview_classes.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/source/scripts/gen_format_overview_classes.py b/doc/source/scripts/gen_format_overview_classes.py index 8ce666e59..9ee88120f 100644 --- a/doc/source/scripts/gen_format_overview_classes.py +++ b/doc/source/scripts/gen_format_overview_classes.py @@ -66,9 +66,7 @@ def _description(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> st class FormatOverview: def __init__(self) -> None: def _topology(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: - if "Topology parser" in handlers: - return SUCCESS - return FAIL + return SUCCESS if "Topology parser" in handlers else FAIL def _coordinates( fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str From 74bf36d32168cfde4e7f212543b48d756f21e2e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Doma=C5=84ski?= Date: Fri, 1 Sep 2023 18:40:10 +0100 Subject: [PATCH 07/15] Update doc/source/scripts/gen_topologyparser_attrs.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> --- doc/source/scripts/gen_topologyparser_attrs.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index a40bfddea..b30407fdb 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -68,9 +68,8 @@ def create_parser_attributes() -> dict[Any, tuple[set[str], set[str]]]: parser_attrs = {} for test_parser_class in PARSER_TESTS: - expected, guessed = set(test_parser_class.expected_attrs) - set( - mandatory_attrs - ), set(test_parser_class.guessed_attrs) + 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") From d2e86db87cbfebb001bc099123a981ce61e66463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Doma=C5=84ski?= Date: Fri, 1 Sep 2023 18:40:32 +0100 Subject: [PATCH 08/15] Update doc/source/scripts/gen_topologyparser_attrs.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> --- .../scripts/gen_topologyparser_attrs.py | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index b30407fdb..d2ba664dc 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -143,25 +143,16 @@ def _attributes_guessed( ) self.table_writer.generate_lines_and_write_table() - attrs = defaultdict(set) - - def _get_attrs( - line: list[str], - format: str, - parser: TopologyReaderBase, - expected: set[str], - guessed: set[str], - key_label: tuple[str, str], - ) -> None: - for attribute in expected | guessed: - attrs[attribute].add(format) - - for line, format, args in zip( - self.table_writer.lines, - self.table_writer.fields["Format"], - input_items, - ): - _get_attrs(line, format, *args) +def _get_format_attrs(topology_parser: TopologyParser) -> dict[str, set[str]]: + attrs = defaultdict(set) + writer = topology_parser.table_writer + for format, (expected, guessed, _) in zip( + writer.fields["Format"], + input_items, + ): + for attribute in expected | guessed: + attrs[attribute].add(format) + return attrs self.attrs = attrs From b9c8aefd9e44400e9e9fc21826c0f51417eeeef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Doma=C5=84ski?= Date: Fri, 1 Sep 2023 18:40:37 +0100 Subject: [PATCH 09/15] Update doc/source/scripts/gen_topologyparser_attrs.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> --- doc/source/scripts/gen_topologyparser_attrs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index d2ba664dc..a3d041844 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -158,7 +158,7 @@ def _get_format_attrs(topology_parser: TopologyParser) -> dict[str, set[str]]: class TopologyAttrs: - def __init__(self, attrs: dict[str, Any]) -> None: + def __init__(self, attrs: dict[str, set[str]]) -> None: def _atom(name: str, singular: str, description: str) -> str: return singular From d44ceb6136d79580630a530b2275f99dbb692262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Doma=C5=84ski?= Date: Fri, 1 Sep 2023 18:40:44 +0100 Subject: [PATCH 10/15] Update doc/source/scripts/gen_topologyparser_attrs.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> --- doc/source/scripts/gen_topologyparser_attrs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index a3d041844..0c1978c8d 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -189,7 +189,7 @@ def _supported_formats(name: str, singular: str, description: str) -> str: class ConnectivityAttrs: - def __init__(self, attrs: dict[str, Any]) -> None: + def __init__(self, attrs: dict[str, set[str]]) -> None: def _atom(name: str) -> str: return name From 9f17ca4dceeeac9c1b70a85cf9c65f43898556c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Doma=C5=84ski?= Date: Fri, 1 Sep 2023 18:40:50 +0100 Subject: [PATCH 11/15] Update doc/source/scripts/gen_topologyparser_attrs.py Co-authored-by: Lily Wang <31115101+lilyminium@users.noreply.github.com> --- doc/source/scripts/gen_topologyparser_attrs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index 0c1978c8d..e36d08916 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -216,8 +216,9 @@ def _supported_formats(name: str) -> str: def main() -> None: top = TopologyParsers() - TopologyAttrs(top.attrs) - ConnectivityAttrs(top.attrs) + topology_attrs = _get_format_attrs(top) + TopologyAttrs(topology_attrs) + ConnectivityAttrs(topology_attrs) if __name__ == "__main__": From cfc3b1d05cda4baa42c99d85b663e4c5f5e0eee2 Mon Sep 17 00:00:00 2001 From: Jan Domanski Date: Fri, 1 Sep 2023 18:44:09 +0100 Subject: [PATCH 12/15] review: comments from Lily --- doc/source/scripts/gen_topologyparser_attrs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index e36d08916..3e2c720dc 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -143,19 +143,19 @@ def _attributes_guessed( ) self.table_writer.generate_lines_and_write_table() -def _get_format_attrs(topology_parser: TopologyParser) -> dict[str, set[str]]: + +def _get_format_attrs(topology_parsers: TopologyParsers) -> dict[str, set[str]]: attrs = defaultdict(set) - writer = topology_parser.table_writer + writer = topology_parsers.table_writer + assert writer.input_items for format, (expected, guessed, _) in zip( writer.fields["Format"], - input_items, + writer.input_items, ): for attribute in expected | guessed: attrs[attribute].add(format) return attrs - self.attrs = attrs - class TopologyAttrs: def __init__(self, attrs: dict[str, set[str]]) -> None: From f04ebed1f712e48d6bc02a16c0625ebde5a47dc0 Mon Sep 17 00:00:00 2001 From: Jan Domanski Date: Fri, 1 Sep 2023 19:23:24 +0100 Subject: [PATCH 13/15] fix tests --- doc/source/scripts/gen_topologyparser_attrs.py | 6 +++--- .../snapshot/test_gen_topologyparser_attrs.py | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index 3e2c720dc..6160bfd0b 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -144,11 +144,11 @@ def _attributes_guessed( self.table_writer.generate_lines_and_write_table() -def _get_format_attrs(topology_parsers: TopologyParsers) -> dict[str, set[str]]: +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( + for format, (_, expected, guessed, _) in zip( writer.fields["Format"], writer.input_items, ): @@ -216,7 +216,7 @@ def _supported_formats(name: str) -> str: def main() -> None: top = TopologyParsers() - topology_attrs = _get_format_attrs(top) + topology_attrs = get_format_attrs(top) TopologyAttrs(topology_attrs) ConnectivityAttrs(topology_attrs) diff --git a/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py b/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py index 031d91903..bf94a3aed 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py +++ b/doc/source/scripts/tests/snapshot/test_gen_topologyparser_attrs.py @@ -1,6 +1,11 @@ from unittest.mock import patch -from gen_topologyparser_attrs import ConnectivityAttrs, TopologyAttrs, TopologyParsers +from gen_topologyparser_attrs import ( + ConnectivityAttrs, + TopologyAttrs, + TopologyParsers, + get_format_attrs, +) def test_TopologyParsers_lines(snapshot): @@ -12,18 +17,21 @@ def test_TopologyParsers_lines(snapshot): def test_TopologyParsers_attrs(snapshot): with patch("builtins.open"): top = TopologyParsers() - assert top.attrs == snapshot + attrs = get_format_attrs(top) + assert attrs == snapshot def test_TopologyAttrs(snapshot): with patch("builtins.open"): top = TopologyParsers() - ta = TopologyAttrs(top.attrs) + attrs = get_format_attrs(top) + ta = TopologyAttrs(attrs) assert ta.table_writer.lines == snapshot def test_ConnectivityAttrs(snapshot): with patch("builtins.open"): top = TopologyParsers() - ca = ConnectivityAttrs(top.attrs) + attrs = get_format_attrs(top) + ca = ConnectivityAttrs(attrs) assert ca.table_writer.lines == snapshot From f2f8e1660c5e91e5ebbbf2a58736ac94f87f6b96 Mon Sep 17 00:00:00 2001 From: Jan Domanski Date: Sun, 3 Sep 2023 14:53:43 +0100 Subject: [PATCH 14/15] more flake8 goodies --- .pre-commit-config.yaml | 19 ++++++++++++++++++- doc/source/scripts/base.py | 1 - doc/source/scripts/core.py | 6 +++--- .../scripts/gen_format_overview_classes.py | 1 - doc/source/scripts/gen_selection_exporters.py | 1 - .../scripts/gen_topology_groupmethods.py | 1 - .../scripts/gen_topologyattr_defaults.py | 1 - pyproject.toml | 11 +++++++++++ 8 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 pyproject.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 21af60744..64d3d204d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,6 +2,12 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.2.0 hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-symlinks - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace @@ -11,7 +17,6 @@ repos: hooks: - id: isort name: isort (python) - args: ["--profile", "black"] - repo: https://github.com/psf/black rev: 22.3.0 hooks: @@ -22,3 +27,15 @@ repos: - id: mypy args: [--ignore-missing-imports, --install-types, --non-interactive, --strict] exclude: "/tests/.*\\.py|clean_example_notebooks.py|update_json_stubs_sitemap.py" +- repo: https://github.com/PyCQA/flake8 + rev: 6.1.0 + hooks: + - id: flake8 + additional_dependencies: [ + 'flake8-simplify', + 'flake8-comprehensions', + 'flake8-bugbear', + 'darglint', + 'flake8-pep585', + 'Flake8-pyproject', + ] diff --git a/doc/source/scripts/base.py b/doc/source/scripts/base.py index d678b0df5..97c96927c 100644 --- a/doc/source/scripts/base.py +++ b/doc/source/scripts/base.py @@ -1,4 +1,3 @@ -import collections import os import pathlib import sys diff --git a/doc/source/scripts/core.py b/doc/source/scripts/core.py index a8dd7116e..c75279d38 100644 --- a/doc/source/scripts/core.py +++ b/doc/source/scripts/core.py @@ -70,9 +70,9 @@ for c in _TOPOLOGY_ATTRS.values() } -base_attrnames = set(["atomattrs", "residueattrs", "segmentattrs", "topologyattrs"]) +base_attrnames = {"atomattrs", "residueattrs", "segmentattrs", "topologyattrs"} -core_attrnames = set(["indices", "resindices", "segindices"]) +core_attrnames = {"indices", "resindices", "segindices"} BASE_ATTRS = {k: v for k, v in ATTRS.items() if k in base_attrnames} @@ -81,6 +81,6 @@ NON_CORE_ATTRS = {k: v for k, v in NON_BASE_ATTRS.items() if k not in core_attrnames} TOPOLOGY_CLS = sorted( - set([x for x in _TOPOLOGY_ATTRS.values() if x.attrname in NON_CORE_ATTRS.keys()]), + {x for x in _TOPOLOGY_ATTRS.values() if x.attrname in NON_CORE_ATTRS}, key=lambda x: x.attrname, ) diff --git a/doc/source/scripts/gen_format_overview_classes.py b/doc/source/scripts/gen_format_overview_classes.py index 9ee88120f..8e70a3f7e 100644 --- a/doc/source/scripts/gen_format_overview_classes.py +++ b/doc/source/scripts/gen_format_overview_classes.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """ Generates: - ../formats/format_overview.txt : table of format overview diff --git a/doc/source/scripts/gen_selection_exporters.py b/doc/source/scripts/gen_selection_exporters.py index 01d7900e1..76acd5762 100644 --- a/doc/source/scripts/gen_selection_exporters.py +++ b/doc/source/scripts/gen_selection_exporters.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """ Generates: - ../formats/selection_exporters.txt diff --git a/doc/source/scripts/gen_topology_groupmethods.py b/doc/source/scripts/gen_topology_groupmethods.py index b4bcf69ca..f4906c5e8 100644 --- a/doc/source/scripts/gen_topology_groupmethods.py +++ b/doc/source/scripts/gen_topology_groupmethods.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """ Generate groupmethods.txt: diff --git a/doc/source/scripts/gen_topologyattr_defaults.py b/doc/source/scripts/gen_topologyattr_defaults.py index 0ee5e3707..4887cfa1d 100644 --- a/doc/source/scripts/gen_topologyattr_defaults.py +++ b/doc/source/scripts/gen_topologyattr_defaults.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """ Generate topology_defaults.txt: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..3790c0f32 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,11 @@ +[tool.isort] +profile = "black" + +[tool.flake8] +max-line-length = 130 +extend-ignore = ["E203", "PEA001"] +exclude = [ + "doc/source/conf.py", + "doc/source/scripts/clean_example_notebooks.py", + "maintainer/update_json_stubs_sitemap.py", +] From f05d986427410923d7ff764b7fcd1ae4d51476a6 Mon Sep 17 00:00:00 2001 From: Jan Domanski Date: Mon, 9 Oct 2023 20:33:49 +0100 Subject: [PATCH 15/15] run linter --- .pre-commit-config.yaml | 2 +- doc/source/conf.py | 2 +- doc/source/scripts/base.py | 8 +++++-- .../scripts/gen_format_overview_classes.py | 24 ++++++++++++++----- doc/source/scripts/gen_standard_selections.py | 4 +++- .../scripts/gen_topology_groupmethods.py | 4 +++- .../scripts/gen_topologyparser_attrs.py | 8 +++++-- .../tests/snapshot/test_gen_unit_tables.py | 4 +++- 8 files changed, 41 insertions(+), 15 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3e64d7c53..6c10d68b2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: rev: 22.3.0 hooks: - id: black - args: [--line-length=79] + args: [--line-length=79] - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.5.1 hooks: diff --git a/doc/source/conf.py b/doc/source/conf.py index 942f9b66d..c5ffa9b01 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -144,7 +144,7 @@ def sort_authors(filename: str) -> list[str]: # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] -html_css_files = [] +html_css_files: list[str] = [] # Custom sidebar templates, maps document names to template names. # alabaster sidebars diff --git a/doc/source/scripts/base.py b/doc/source/scripts/base.py index 97c96927c..18b68e6c5 100644 --- a/doc/source/scripts/base.py +++ b/doc/source/scripts/base.py @@ -129,10 +129,14 @@ def sphinx_class(*, klass: Type[Any], tilde: bool = True) -> str: def sphinx_method(*, method: Callable[..., Any], tilde: bool = True) -> str: prefix = "~" if tilde else "" - return ":meth:`{}{}.{}`".format(prefix, method.__module__, method.__qualname__) + return ":meth:`{}{}.{}`".format( + prefix, method.__module__, method.__qualname__ + ) -def sphinx_ref(*, txt: str, label: Optional[str] = None, suffix: str = "") -> str: +def sphinx_ref( + *, txt: str, label: Optional[str] = None, suffix: str = "" +) -> str: return f":ref:`{txt} <{label}{suffix}>`" diff --git a/doc/source/scripts/gen_format_overview_classes.py b/doc/source/scripts/gen_format_overview_classes.py index 8e70a3f7e..e733f0a9b 100644 --- a/doc/source/scripts/gen_format_overview_classes.py +++ b/doc/source/scripts/gen_format_overview_classes.py @@ -54,17 +54,23 @@ def _create_key(fmt: str, handlers: dict[HANDLER_T, Type[Any]]) -> str: return key -def _file_type(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: +def _file_type( + fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str +) -> str: return base.sphinx_ref(txt=fmt, label=key, suffix="-format") -def _description(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: +def _description( + fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str +) -> str: return DESCRIPTIONS[key] class FormatOverview: def __init__(self) -> None: - def _topology(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + def _topology( + fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str + ) -> str: return SUCCESS if "Topology parser" in handlers else FAIL def _coordinates( @@ -74,10 +80,14 @@ def _coordinates( return SUCCESS return FAIL - def _read(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + def _read( + fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str + ) -> str: return SUCCESS - def _write(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + def _write( + fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str + ) -> str: if "Coordinate writer" in handlers: return SUCCESS if "Converter" in handlers: @@ -116,7 +126,9 @@ def _velocities( return SUCCESS return FAIL - def _forces(fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str) -> str: + def _forces( + fmt: str, handlers: dict[HANDLER_T, Type[Any]], key: str + ) -> str: if handlers["Coordinate reader"].units.get("force"): return SUCCESS return FAIL diff --git a/doc/source/scripts/gen_standard_selections.py b/doc/source/scripts/gen_standard_selections.py index c50807a81..c54b0c7f4 100755 --- a/doc/source/scripts/gen_standard_selections.py +++ b/doc/source/scripts/gen_standard_selections.py @@ -67,7 +67,9 @@ def __init__(self, filename: str, *args: Any, **kwargs: Any) -> None: klass=sel.NucleicBackboneSelection, attribute_name="bb_atoms", ) - StandardSelectionTable("base", klass=sel.BaseSelection, attribute_name="base_atoms") + StandardSelectionTable( + "base", klass=sel.BaseSelection, attribute_name="base_atoms" + ) StandardSelectionTable( "nucleic_sugar", klass=sel.NucleicSugarSelection, diff --git a/doc/source/scripts/gen_topology_groupmethods.py b/doc/source/scripts/gen_topology_groupmethods.py index f4906c5e8..b6b32cf9e 100644 --- a/doc/source/scripts/gen_topology_groupmethods.py +++ b/doc/source/scripts/gen_topology_groupmethods.py @@ -23,7 +23,9 @@ def _generate_input_items() -> list[tuple[TopologyAttr, Any]]: items.append((name, klass, method)) return [x[1:] for x in sorted(items)] - def _method(klass: TopologyAttr, method: Callable[[TopologyAttr], str]) -> str: + def _method( + klass: TopologyAttr, method: Callable[[TopologyAttr], str] + ) -> str: return base.sphinx_method(method=method) def _description( diff --git a/doc/source/scripts/gen_topologyparser_attrs.py b/doc/source/scripts/gen_topologyparser_attrs.py index 6160bfd0b..ebeefbe76 100755 --- a/doc/source/scripts/gen_topologyparser_attrs.py +++ b/doc/source/scripts/gen_topologyparser_attrs.py @@ -168,11 +168,15 @@ def _atomgroup(name: str, singular: str, description: str) -> str: def _description(name: str, singular: str, description: str) -> str: return description - def _supported_formats(name: str, singular: str, description: str) -> str: + def _supported_formats( + name: str, singular: str, description: str + ) -> str: 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) + [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", diff --git a/doc/source/scripts/tests/snapshot/test_gen_unit_tables.py b/doc/source/scripts/tests/snapshot/test_gen_unit_tables.py index e19a88f04..fa90bc589 100644 --- a/doc/source/scripts/tests/snapshot/test_gen_unit_tables.py +++ b/doc/source/scripts/tests/snapshot/test_gen_unit_tables.py @@ -8,6 +8,8 @@ def test_write_unit_table(snapshot): with patch.object(Path, "open", mock_open()) as mock_open_file: write_unit_table(filename=Path()) - lines = [args[0] for args in mock_open_file.return_value.write.call_args_list] + lines = [ + args[0] for args in mock_open_file.return_value.write.call_args_list + ] # Exclude the first line, because it contains "Generated by /home/username/..." assert lines[1:] == snapshot