Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace mdtraj with biotraj #627

Merged
merged 12 commits into from
Aug 20, 2024
Merged
3 changes: 3 additions & 0 deletions .github/workflows/test_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ jobs:
with:
mamba-version: "*"
environment-file: environment.yml
# TODO: Re-enable DSSP tests as soon as issues with libboost in CI are resolved
- name: "TEMP: Remove DSSP from environment"
run: mamba remove dssp -y
- name: Build distribution
run: pip wheel --no-deps -w dist .
- name: Install distribution
Expand Down
3 changes: 1 addition & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This package bundles popular tasks in computational molecular biology
into a uniform *Python* library.
It can handle a major part of the typical workflow
for sequence and biomolecular structure data:

- Searching and fetching data from biological databases
- Reading and writing popular sequence/structure file formats
- Analyzing and editing sequence/structure data
Expand Down Expand Up @@ -57,7 +57,6 @@ Installation

Some functions require some extra packages:

- **mdtraj** - Required for trajetory file I/O operations.
- **matplotlib** - Required for plotting purposes.

*Biotite* can be installed via *Conda*...
Expand Down
5 changes: 2 additions & 3 deletions doc/contribution/development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,8 @@ The import statement for the dependency should be located directly inside the
function or class, rather than module level, to ensure that the package is not
required for any other functionality or for building the API documentation.

An example for this approach is the support for trajectory files in
:mod:`biotite.structure.io`, that require `MDTraj <http://mdtraj.org/>`_.
The usage of these packages is not only allowed but even encouraged.
An example for this approach are the plotting functions in
:mod:`biotite.sequence.graphics`, that require *Matplotlib*.

Code efficiency
---------------
Expand Down
1 change: 0 additions & 1 deletion doc/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ dependencies if not already present.

Some functionalities require extra packages:

- ``mdtraj`` - Required for trajectory file I/O operations.
- ``matplotlib`` - Required for plotting purposes.


Expand Down
5 changes: 0 additions & 5 deletions doc/tutorial/structure/trajectories.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ If you like, you can even use the
seamless interaction between *Biotite* and the
`OpenMM <https://openmm.org/>`_ MD simulation toolkit.

.. note::

Reading/writing trajectory files currently requires the
`MDtraj <https://www.mdtraj.org>`_ package.

Reading trajectory files
------------------------

Expand Down
6 changes: 3 additions & 3 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ channels:
- bioconda

dependencies:
- python =3.10
- python =3.12
# Package building
- cython >=3.0
- pip >=10.0
- setuptools >=30.0
- wheel >=0.30
# Biotite dependencies
# - biotraj >=1.0,<2.0
- msgpack-python >=0.5.6
- networkx >=2.0
- numpy >=1.25
- numpy >=2.0
- requests >=2.12
# Testing
# - mdtraj >=1.9.3, <1.10 # tempoarily disabled due to incompatibility with numpy 2.0
- pytest >=7.0
# Code style
- ruff =0.5.2
Expand Down
9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ dependencies = [
# Wheels compiled with NumPy 2.0 are backward compatible with NumPy 1.x
# https://numpy.org/devdocs/dev/depending_on_numpy.html#numpy-2-0-specific-advice
"numpy >= 1.25",
"biotraj >= 1.0, < 2.0",
"requests >= 2.12",
"msgpack >= 0.5.6",
"networkx >= 2.0",
"requests >= 2.12",
Expand Down Expand Up @@ -75,6 +77,13 @@ no-lines-before = [
order-by-type = true
known-first-party = ["biotite"]

[tool.pytest.ini_options]
filterwarnings = [
# Appears in loading NetCDF trajectory files
"ignore:The 'netCDF4' Python package is not installed.",
"ignore:Input structure has no associated 'BondList'",
]

[tool.hatch.build.targets.sdist]
exclude = [
"tests",
Expand Down
5 changes: 4 additions & 1 deletion src/biotite/application/localapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,5 +301,8 @@ def cleanup_tempfile(temp_file):
The temporary file to be closed and deleted.
"""
temp_file.close()
if not temp_file.delete:
try:
remove(temp_file.name)
except FileNotFoundError:
# File was already deleted, e.g. due to `TemporaryFile(delete=True)`
pass
8 changes: 4 additions & 4 deletions src/biotite/sequence/align/cigar.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,10 @@ def write_alignment_to_cigar(

>>> op_tuples = write_alignment_to_cigar(semiglobal_alignment, as_string=False)
>>> for op, length in op_tuples:
... print(CigarOp(op), length)
CigarOp.MATCH 9
CigarOp.DELETION 2
CigarOp.MATCH 12
... print(CigarOp(op).name, length)
MATCH 9
DELETION 2
MATCH 12
"""
if not include_terminal_gaps:
alignment = _remove_terminal_segment_gaps(alignment, segment_index)
Expand Down
2 changes: 1 addition & 1 deletion src/biotite/sequence/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ class Annotation(Copyable):
... gene = f.qual["gene"]
... loc_str = "".join([f"{loc} {loc.defect}" for loc in f.locs])
... print(gene, loc_str)
test5 40-149 > Defect.MISS_RIGHT|MISS_LEFT
test5 40-149 > Defect.MISS_LEFT|MISS_RIGHT
test2 40-50 > Defect.MISS_LEFT
test3 100-130 > Defect.NONE
"""
Expand Down
2 changes: 1 addition & 1 deletion src/biotite/sequence/io/genbank/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class GenBankFile(TextFile):
>>> print(content)
['One line', 'A second line']
>>> print(subfields)
OrderedDict([('SUBFIELD1', ['Single Line']), ('SUBFIELD2', ['Two', 'lines'])])
OrderedDict({'SUBFIELD1': ['Single Line'], 'SUBFIELD2': ['Two', 'lines']})

Adding an additional field:

Expand Down
52 changes: 26 additions & 26 deletions src/biotite/structure/basepairs.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,19 +379,19 @@ def base_pairs_edge(atom_array, base_pairs):
The resulting integers can be interpreted as :class:`Edge` ``Enum``:

>>> for interaction in interacting_edges:
... print(Edge(interaction[0]), Edge(interaction[1]))
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
Edge.WATSON_CRICK Edge.WATSON_CRICK
... print(f"{Edge(interaction[0]).name} to {Edge(interaction[1]).name}")
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK
WATSON_CRICK to WATSON_CRICK

References
----------
Expand Down Expand Up @@ -531,19 +531,19 @@ def base_pairs_glycosidic_bond(atom_array, base_pairs):
``Enum``:

>>> for orientation in orientations:
... print(GlycosidicBond(orientation))
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
GlycosidicBond.CIS
... print(GlycosidicBond(orientation).name)
CIS
CIS
CIS
CIS
CIS
CIS
CIS
CIS
CIS
CIS
CIS
CIS

References
----------
Expand Down
48 changes: 24 additions & 24 deletions src/biotite/structure/bonds.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class BondType(IntEnum):
Examples
--------

>>> print(BondType.AROMATIC_DOUBLE.without_aromaticity())
BondType.DOUBLE
>>> print(BondType.AROMATIC_DOUBLE.without_aromaticity().name)
DOUBLE
"""
difference = BondType.AROMATIC_SINGLE - BondType.SINGLE
if self >= BondType.AROMATIC_SINGLE:
Expand Down Expand Up @@ -212,21 +212,21 @@ class BondList(Copyable):
... )
>>> for i, j, bond_type in benzene.bonds.as_array():
... print(
... f"{str(BondType(bond_type))} bond between "
... f"{BondType(bond_type).name} bond between "
... f"{benzene.atom_name[i]} and {benzene.atom_name[j]}"
... )
BondType.AROMATIC_SINGLE bond between C1 and C2
BondType.AROMATIC_DOUBLE bond between C2 and C3
BondType.AROMATIC_SINGLE bond between C3 and C4
BondType.AROMATIC_DOUBLE bond between C4 and C5
BondType.AROMATIC_SINGLE bond between C5 and C6
BondType.AROMATIC_DOUBLE bond between C1 and C6
BondType.SINGLE bond between C1 and H1
BondType.SINGLE bond between C2 and H2
BondType.SINGLE bond between C3 and H3
BondType.SINGLE bond between C4 and H4
BondType.SINGLE bond between C5 and H5
BondType.SINGLE bond between C6 and H6
AROMATIC_SINGLE bond between C1 and C2
AROMATIC_DOUBLE bond between C2 and C3
AROMATIC_SINGLE bond between C3 and C4
AROMATIC_DOUBLE bond between C4 and C5
AROMATIC_SINGLE bond between C5 and C6
AROMATIC_DOUBLE bond between C1 and C6
SINGLE bond between C1 and H1
SINGLE bond between C2 and H2
SINGLE bond between C3 and H3
SINGLE bond between C4 and H4
SINGLE bond between C5 and H5
SINGLE bond between C6 and H6

Obtain the bonded atoms for the :math:`C_1`:

Expand All @@ -248,14 +248,14 @@ class BondList(Copyable):
... ]
>>> for i, j, bond_type in half_benzene.bonds.as_array():
... print(
... f"{str(BondType(bond_type))} bond between "
... f"{BondType(bond_type).name} bond between "
... f"{half_benzene.atom_name[i]} and {half_benzene.atom_name[j]}"
... )
BondType.AROMATIC_DOUBLE bond between C4 and C5
BondType.AROMATIC_SINGLE bond between C5 and C6
BondType.SINGLE bond between C4 and H4
BondType.SINGLE bond between C5 and H5
BondType.SINGLE bond between C6 and H6
AROMATIC_DOUBLE bond between C4 and C5
AROMATIC_SINGLE bond between C5 and C6
SINGLE bond between C4 and H4
SINGLE bond between C5 and H5
SINGLE bond between C6 and H6
"""

def __init__(self, uint32 atom_count, np.ndarray bonds=None):
Expand Down Expand Up @@ -449,9 +449,9 @@ class BondList(Copyable):
>>> bond_list.add_bond(1, 2, BondType.AROMATIC_DOUBLE)
>>> bond_list.remove_aromaticity()
>>> for i, j, bond_type in bond_list.as_array():
... print(i, j, BondType(bond_type))
0 1 BondType.SINGLE
1 2 BondType.DOUBLE
... print(i, j, BondType(bond_type).name)
0 1 SINGLE
1 2 DOUBLE
"""
bonds = self._bonds
difference = BondType.AROMATIC_SINGLE - BondType.SINGLE
Expand Down
60 changes: 30 additions & 30 deletions src/biotite/structure/info/bonds.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ def bond_type(res_name, atom_name1, atom_name2):
Examples
--------

>>> print(bond_type("PHE", "CA", "CB"))
BondType.SINGLE
>>> print(bond_type("PHE", "CG", "CD1"))
BondType.AROMATIC_DOUBLE
>>> print(bond_type("PHE", "CA", "CG"))
>>> print(repr(bond_type("PHE", "CA", "CB")))
<BondType.SINGLE: 1>
>>> print(repr(bond_type("PHE", "CG", "CD1")))
<BondType.AROMATIC_DOUBLE: 6>
>>> print(repr(bond_type("PHE", "CA", "CG")))
None
>>> print(bond_type("PHE", "FOO", "BAR"))
>>> print(repr(bond_type("PHE", "FOO", "BAR")))
None
"""
bonds_for_residue = bonds_in_residue(res_name)
Expand Down Expand Up @@ -99,30 +99,30 @@ def bonds_in_residue(res_name):
>>> bonds = bonds_in_residue("PHE")
>>> for atoms, bond_type_int in sorted(bonds.items()):
... atom1, atom2 = sorted(atoms)
... print(f"{atom1:3} + {atom2:3} -> {str(BondType(bond_type_int))}")
C + O -> BondType.DOUBLE
C + OXT -> BondType.SINGLE
C + CA -> BondType.SINGLE
CA + CB -> BondType.SINGLE
CA + HA -> BondType.SINGLE
CB + CG -> BondType.SINGLE
CB + HB2 -> BondType.SINGLE
CB + HB3 -> BondType.SINGLE
CD1 + CE1 -> BondType.AROMATIC_SINGLE
CD1 + HD1 -> BondType.SINGLE
CD2 + CE2 -> BondType.AROMATIC_DOUBLE
CD2 + HD2 -> BondType.SINGLE
CE1 + CZ -> BondType.AROMATIC_DOUBLE
CE1 + HE1 -> BondType.SINGLE
CE2 + CZ -> BondType.AROMATIC_SINGLE
CE2 + HE2 -> BondType.SINGLE
CD1 + CG -> BondType.AROMATIC_DOUBLE
CD2 + CG -> BondType.AROMATIC_SINGLE
CZ + HZ -> BondType.SINGLE
CA + N -> BondType.SINGLE
H + N -> BondType.SINGLE
H2 + N -> BondType.SINGLE
HXT + OXT -> BondType.SINGLE
... print(f"{atom1:3} + {atom2:3} -> {BondType(bond_type_int).name}")
C + O -> DOUBLE
C + OXT -> SINGLE
C + CA -> SINGLE
CA + CB -> SINGLE
CA + HA -> SINGLE
CB + CG -> SINGLE
CB + HB2 -> SINGLE
CB + HB3 -> SINGLE
CD1 + CE1 -> AROMATIC_SINGLE
CD1 + HD1 -> SINGLE
CD2 + CE2 -> AROMATIC_DOUBLE
CD2 + HD2 -> SINGLE
CE1 + CZ -> AROMATIC_DOUBLE
CE1 + HE1 -> SINGLE
CE2 + CZ -> AROMATIC_SINGLE
CE2 + HE2 -> SINGLE
CD1 + CG -> AROMATIC_DOUBLE
CD2 + CG -> AROMATIC_SINGLE
CZ + HZ -> SINGLE
CA + N -> SINGLE
H + N -> SINGLE
H2 + N -> SINGLE
HXT + OXT -> SINGLE
"""
global _intra_bonds
if res_name not in _intra_bonds:
Expand Down
4 changes: 2 additions & 2 deletions src/biotite/structure/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
The recommended format for reading structure files is *BinaryCIF*.
It has by far the shortest parsing time and file size.

Besides the mentioned structure formats, Gromacs trajectory files can be
loaded, if `mdtraj` is installed.
Besides the mentioned structure formats, common trajectory formats can be
loaded as well.
"""

__name__ = "biotite.structure.io"
Expand Down
5 changes: 2 additions & 3 deletions src/biotite/structure/io/dcd/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
__author__ = "Patrick Kunzmann"
__all__ = ["DCDFile"]

import biotraj
import numpy as np
from biotite.structure.box import unitcell_from_vectors, vectors_from_unitcell
from biotite.structure.io.trajfile import TrajectoryFile
Expand All @@ -18,9 +19,7 @@ class DCDFile(TrajectoryFile):

@classmethod
def traj_type(cls):
import mdtraj.formats as traj

return traj.DCDTrajectoryFile
return biotraj.DCDTrajectoryFile

@classmethod
def process_read_values(cls, read_values):
Expand Down
Loading
Loading