From b0524e9779ee2fa809178c3700c8c1cefd821891 Mon Sep 17 00:00:00 2001 From: "Josef M. Gallmetzer" <64498081+galjos@users.noreply.github.com> Date: Mon, 24 Aug 2026 09:12:57 +0200 Subject: [PATCH] fix: keep constructor topology when read() gets none TrajectoryReader.read() unconditionally assigned its optional topology argument to self.topology, so calling read() without an argument reset the topology passed to the constructor back to None. As a consequence, read_trajectory(file, topology=...) silently ignored the given topology and rebuilt a guessed one from the file, replacing user-supplied atom types and residue ids. read() now only overrides the stored topology when one is explicitly given. --- PQAnalysis/io/traj_file/trajectory_reader.py | 3 +- tests/io/test_trajectoryReader.py | 45 +++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/PQAnalysis/io/traj_file/trajectory_reader.py b/PQAnalysis/io/traj_file/trajectory_reader.py index 6a7a18e0..ccb0643b 100644 --- a/PQAnalysis/io/traj_file/trajectory_reader.py +++ b/PQAnalysis/io/traj_file/trajectory_reader.py @@ -118,7 +118,8 @@ def read(self, topology: Topology | None = None) -> Trajectory: """ self.with_progress_bar = with_progress_bar - self.topology = topology + if topology is not None: + self.topology = topology traj = Trajectory() for frame in self.frame_generator(): diff --git a/tests/io/test_trajectoryReader.py b/tests/io/test_trajectoryReader.py index 76e0b8f8..5be8963b 100644 --- a/tests/io/test_trajectoryReader.py +++ b/tests/io/test_trajectoryReader.py @@ -5,8 +5,9 @@ from PQAnalysis.io import TrajectoryReader import PQAnalysis.io.traj_file.frame_reader as frame_reader from PQAnalysis.io.traj_file.exceptions import FrameReaderError, TrajectoryReaderError -from PQAnalysis.io.traj_file.api import calculate_frames_of_trajectory_file +from PQAnalysis.io.traj_file.api import calculate_frames_of_trajectory_file, read_trajectory from PQAnalysis.core import Cell, Atom +from PQAnalysis.topology import Topology from PQAnalysis.atomic_system import AtomicSystem from PQAnalysis.exceptions import PQIndexError, PQFileNotFoundError @@ -282,6 +283,48 @@ def test_read(self): assert traj == ref_traj + @pytest.mark.usefixtures("tmpdir") + def test_read_keeps_constructor_topology(self): + file = open("tmp.xyz", "w") + print("2 1.0 1.0 1.0", file=file) + print("", file=file) + print("h 0.0 0.0 0.0", file=file) + print("o 0.0 1.0 0.0", file=file) + print("2", file=file) + print("", file=file) + print("h 1.0 0.0 0.0", file=file) + print("o 0.0 1.0 1.0", file=file) + file.close() + + topology = Topology( + atoms=[Atom("C"), Atom("N")], + residue_ids=np.array([7, 7]), + check_residues=False, + ) + + reader = TrajectoryReader("tmp.xyz", topology=topology) + traj = reader.read() + + assert traj[0].topology.atoms == topology.atoms + assert np.array_equal(traj[0].topology.residue_ids, [7, 7]) + assert traj[1].topology.atoms == topology.atoms + + traj = read_trajectory("tmp.xyz", topology=topology) + + assert traj[0].topology.atoms == topology.atoms + assert np.array_equal(traj[0].topology.residue_ids, [7, 7]) + assert traj[1].topology.atoms == topology.atoms + + other = Topology( + atoms=[Atom("F"), Atom("Cl")], + residue_ids=np.array([3, 3]), + check_residues=False, + ) + traj = reader.read(topology=other) + + assert traj[0].topology.atoms == other.atoms + assert np.array_equal(traj[0].topology.residue_ids, [3, 3]) + # -------------------------------------------------------------------------------- # @pytest.mark.usefixtures("tmpdir")