Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ edition = "2018"
numpy = "0.27"
ndarray = "0.17"
num-traits = "0.2"
smallvec = "1"
itertools = "0.14"

[dependencies.pyo3]
version = "0.27"
Expand Down
3 changes: 3 additions & 0 deletions doc/apidoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ def _create_package_doc(pck, src_path, doc_path):
if attr[0] != "_"
# Check if object is a class
and isinstance(getattr(module, attr), type)
# Skip inner classes (e.g. CellList.Result), which have a dot in __qualname__
# They will still be documented as attribute of the enclosing class
and "." not in getattr(module, attr).__qualname__
]
func_list = [
attr
Expand Down
42 changes: 28 additions & 14 deletions doc/viewcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ def _index_rust_code(code_lines):
"""
Find the line position of structs and enums in *Rust* files.

This analyzer looks for `pub struct` and `pub enum` definitions
decorated with `#[pyclass]`.
This analyzer looks for *structs*, enums and functions
decorated with ``#[pyclass]`` or ``#[pyfunction]``.

Parameters
----------
Expand All @@ -47,8 +47,8 @@ def _index_rust_code(code_lines):
"""
line_index = {}

# Track pyclass decorator lines
pyclass_line = None
# Track pyclass/pyfunction decorator lines
decorator_line = None

for i, line in enumerate(code_lines):
stripped_line = line.strip()
Expand All @@ -57,19 +57,25 @@ def _index_rust_code(code_lines):
if len(stripped_line) == 0 or stripped_line.startswith("//"):
continue

# Check for #[pyclass] decorator
if stripped_line.startswith("#[pyclass"):
pyclass_line = i
# Check for #[pyclass] or #[pyfunction] decorator
if stripped_line.startswith("#[pyclass") or stripped_line.startswith(
"#[pyfunction"
):
decorator_line = i
continue

# Check for pub struct or pub enum after pyclass
if pyclass_line is not None:
match = re.match(r"pub\s+(struct|enum)\s+(\w+)", stripped_line)
# Other attributes (e.g. #[pyo3(...)], #[allow(...)]) keep the decorator active
if decorator_line is not None and stripped_line.startswith("#["):
continue

# Check for pub struct/enum (pyclass) or pub fn (pyfunction)
if decorator_line is not None:
match = re.match(r"pub\s+(struct|enum|fn)\s+(\w+)", stripped_line)
if match:
attr_name = match.group(2)
attr_line_start = pyclass_line
attr_line_start = decorator_line

# Find the end of the struct/enum by matching braces
# Find the end of the definition by matching braces
brace_count = 0
started = False
attr_line_stop = i + 1
Expand All @@ -91,7 +97,7 @@ def _index_rust_code(code_lines):
# 'One' based indexing and inclusive stop
attr_line_stop,
)
pyclass_line = None
decorator_line = None

return line_index

Expand Down Expand Up @@ -422,7 +428,15 @@ def linkcode_resolve(domain, info):
# order to fool Python's inspect module
obj.__module__ = module_name

source_lines, first = inspect.getsourcelines(obj)
try:
source_lines, first = inspect.getsourcelines(obj)
except OSError:
# Dynamically created classes (e.g. IntEnum from Rust members)
# have no source definition that inspect can find
return None
except TypeError:
# Non-callable attributes are not supported by inspect.getsourcelines
return None
last = first + len(source_lines) - 1

return base_url + f"{module_name.replace('.', '/')}.py#L{first}-L{last}"
2 changes: 1 addition & 1 deletion src/biotite/application/autodock/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import numpy as np
from biotite.application.application import AppState, requires_state
from biotite.application.localapp import LocalApp, cleanup_tempfile
from biotite.structure.bonds import find_connected
from biotite.structure.connect import find_connected
from biotite.structure.error import BadStructureError
from biotite.structure.io.pdbqt import PDBQTFile
from biotite.structure.residues import get_residue_masks, get_residue_starts_for
Expand Down
1 change: 1 addition & 0 deletions src/biotite/structure/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
from .chains import *
from .charges import *
from .compare import *
from .connect import *
from .density import *
from .dotbracket import *
from .error import *
Expand Down
10 changes: 5 additions & 5 deletions src/biotite/structure/basepairs.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,9 @@ class Edge(IntEnum):
This enum type represents the interacting edge for a given base.
"""

INVALID = (0,)
WATSON_CRICK = (1,)
HOOGSTEEN = (2,)
INVALID = 0
WATSON_CRICK = 1
HOOGSTEEN = 2
SUGAR = 3


Expand All @@ -305,8 +305,8 @@ class GlycosidicBond(IntEnum):
"""

INVALID = 0
CIS = (1,)
TRANS = (2,)
CIS = 1
TRANS = 2


def base_pairs_edge(atom_array, base_pairs):
Expand Down
67 changes: 67 additions & 0 deletions src/biotite/structure/bonds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# This source code is part of the Biotite package and is distributed
# under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
# information.

__name__ = "biotite.structure"
__author__ = "Patrick Kunzmann"
__all__ = [
"BondList",
"BondType",
]

from enum import IntEnum
from biotite.rust.structure import BondList, bond_type_members


def _without_aromaticity(self):
"""
Get the non-aromatic counterpart of this bond type.

If this bond type is already non-aromatic, it is returned unchanged.

Returns
-------
BondType
The non-aromatic counterpart of this bond type.

Examples
--------
>>> BondType.AROMATIC_DOUBLE.without_aromaticity()
<BondType.DOUBLE: 2>
>>> BondType.SINGLE.without_aromaticity()
<BondType.SINGLE: 1>
"""
match self:
case BondType.AROMATIC_SINGLE:
return BondType.SINGLE
case BondType.AROMATIC_DOUBLE:
return BondType.DOUBLE
case BondType.AROMATIC_TRIPLE:
return BondType.TRIPLE
case BondType.AROMATIC:
return BondType.ANY
case _:
return self


# Create BondType IntEnum dynamically from Rust enum members
BondType = IntEnum(
"BondType",
{name: value for name, value in bond_type_members().items()},
module=__name__,
)
BondType.__doc__ = """
This enum type represents the type of a chemical bond.

- ``ANY`` - Used if the actual type is unknown
- ``SINGLE`` - Single bond
- ``DOUBLE`` - Double bond
- ``TRIPLE`` - Triple bond
- ``QUADRUPLE`` - A quadruple bond
- ``AROMATIC_SINGLE`` - Aromatic bond with a single formal bond
- ``AROMATIC_DOUBLE`` - Aromatic bond with a double formal bond
- ``AROMATIC_TRIPLE`` - Aromatic bond with a triple formal bond
- ``COORDINATION`` - Coordination complex involving a metal atom
- ``AROMATIC`` - Aromatic bond without specification of the formal bond
"""
BondType.without_aromaticity = _without_aromaticity
Loading
Loading