Skip to content

Commit

Permalink
Merge pull request biotite-dev#16 from JHKru/master
Browse files Browse the repository at this point in the history
Separate for test data generation for compatibility with Biotite >= 1.0 and Numpy >= 2.0; Ruff formatting
  • Loading branch information
JHKru authored Sep 26, 2024
2 parents 914b997 + 1335b52 commit eb8382f
Show file tree
Hide file tree
Showing 121 changed files with 15,230 additions and 13,030 deletions.
16 changes: 15 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ name: Testing Springcraft
on: [push, pull_request]

jobs:
lint:
name: Check code style
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install ruff
run: pip install ruff==0.5.2
- name: Check code formatting
run: ruff format --diff
- name: Lint code base
run: ruff check
test:
name: Testing

Expand All @@ -19,7 +33,7 @@ jobs:
auto-update-conda: true
python-version: '3.10'
- name: Installing dependencies
run: conda install -c conda-forge poetry prody pytest r-bio3d rpy2
run: conda install -c conda-forge poetry pytest
- name: Building distribution
run: poetry build -f wheel
- name: Installing distribution
Expand Down
7 changes: 7 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ via *pip*:
$ git clone https://github.com/biotite-dev/springcraft.git
$ pip install ./springcraft
A development conda environment with all required dependencies for testing
can be installed from `environment.yml`

Scripts to generate reference files for tests are stored in tests/data;
a separate environment to rerun these locally can be found in `test_create_data_env.yml`.
BioPhysConnectoR has to be installed separately.

Example
=======

Expand Down
72 changes: 39 additions & 33 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,34 @@

__author__ = "Patrick Kunzmann"

from os.path import realpath, dirname, join
import types
import sys
import types
from os.path import dirname, join, realpath

import scraper
import springcraft

# Include 'src/' in PYTHONPATH
# in order to import the 'Ammolite' package
doc_path = dirname(realpath(__file__))
package_path = join(dirname(doc_path), "src")
sys.path.insert(0, package_path)
import springcraft

# Include springcraft/doc in PYTHONPATH
# in order to import modules for example generation etc.
sys.path.insert(0, doc_path)
import scraper


#### General ####

extensions = ["sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.doctest",
"sphinx.ext.mathjax",
"sphinx.ext.viewcode",
"sphinx_gallery.gen_gallery",
"numpydoc"]
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.doctest",
"sphinx.ext.mathjax",
"sphinx.ext.viewcode",
"sphinx_gallery.gen_gallery",
"numpydoc",
]

templates_path = ["templates"]
source_suffix = [".rst"]
Expand All @@ -42,9 +44,7 @@
exclude_patterns = ["build"]

numpydoc_show_class_members = False
autodoc_default_options = {
"show-inheritance": True
}
autodoc_default_options = {"show-inheritance": True}

pygments_style = "sphinx"

Expand All @@ -68,41 +68,47 @@
html_favicon = "static/assets/springcraft_logo_32p.png"
htmlhelp_basename = "SpringcraftDoc"
html_theme_options = {
"description" : "Investigate molecular dynamics by elastic network models",
"logo" : "assets/springcraft_logo.svg",
"logo_name" : "true",
"github_user" : "biotite-dev",
"github_repo" : "springcraft",
"github_banner" : "true",
"github_type" : "star",
"fixed_sidebar" : "true",
"page_width" : "1200px",
"description": "Investigate molecular dynamics by elastic network models",
"logo": "assets/springcraft_logo.svg",
"logo_name": "true",
"github_user": "biotite-dev",
"github_repo": "springcraft",
"github_banner": "true",
"github_type": "star",
"fixed_sidebar": "true",
"page_width": "1200px",
}
sphinx_gallery_conf = {
"examples_dirs" : "examples/scripts",
"gallery_dirs" : "examples/gallery",
'filename_pattern' : "",
"download_all_examples" : False,
"examples_dirs": "examples/scripts",
"gallery_dirs": "examples/gallery",
"filename_pattern": "",
"download_all_examples": False,
# Never report run time
"min_reported_time" : sys.maxsize,
"image_scrapers" : ("matplotlib", scraper.pymol_scraper,),
"min_reported_time": sys.maxsize,
"image_scrapers": (
"matplotlib",
scraper.pymol_scraper,
),
# Replace 'ammolite.show()'
"reset_modules" : (scraper.overwrite_display_func,),
"reset_modules": (scraper.overwrite_display_func,),
# Do not capture file path string output
# by the overwritten 'ammolite.show()'
"capture_repr" : (),
"capture_repr": (),
}


#### App setup ####


def skip_non_methods(app, what, name, obj, skip, options):
if skip:
return True
if what == "class":
# Functions
if type(obj) in [
types.FunctionType, types.BuiltinFunctionType, types.MethodType
types.FunctionType,
types.BuiltinFunctionType,
types.MethodType,
]:
return False
return True
Expand Down
17 changes: 8 additions & 9 deletions doc/examples/scripts/basic_nma.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
"""
Basic NMA of a Protein-ENM
==========================
In this example script, a basic normal mode analysis (NMA) of a protein
In this example script, a basic normal mode analysis (NMA) of a protein
coarse-grained elastic network model (ENM) is conducted.
"""


# Code source: Jan Krumbach
# License: BSD 3 clause

import numpy as np
import matplotlib.pyplot as plt
import biotite
import biotite.database.rcsb as rcsb
import biotite.structure as struc
import biotite.structure.io.mmtf as mmtf
import biotite.database.rcsb as rcsb
import matplotlib.pyplot as plt
import numpy as np
import springcraft


# Fetch G:T/U Mismatch-specific DNA glycosylase from E. coli
PDB_ID = "1MUG"
mmtf_file = mmtf.MMTFFile.read(rcsb.fetch(PDB_ID, "mmtf"))
Expand All @@ -30,7 +29,7 @@
eanm = springcraft.ANM(ca, ff)

## NMA
# Compute eigenvalues and eigenvectors.
# Compute eigenvalues and eigenvectors.
# The first 6 eigenvals./eigenvecs corresponding to trivial modes are omitted.
# -> analyse modes 7-107
eigenval, eigenvec = eanm.eigen()
Expand All @@ -49,9 +48,9 @@

biotite_c = biotite.colors["orange"]

ax00.bar(x=np.arange(7, len(eigenval)+7), height=eigenval, color=biotite_c)
ax01.bar(x=np.arange(7, len(freq)+7), height=freq, color=biotite_c)
ax1.bar(x=np.arange(1, len(msqf)+1), height=msqf, color=biotite_c)
ax00.bar(x=np.arange(7, len(eigenval) + 7), height=eigenval, color=biotite_c)
ax01.bar(x=np.arange(7, len(freq) + 7), height=freq, color=biotite_c)
ax1.bar(x=np.arange(1, len(msqf) + 1), height=msqf, color=biotite_c)

ax00.set_xlabel("Mode", size=16)
ax00.set_ylabel(r"Eigenvalue $\lambda$", size=16)
Expand Down
45 changes: 28 additions & 17 deletions doc/examples/scripts/normal_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
# Code source: Patrick Kunzmann
# License: BSD 3 clause

import numpy as np
import ammolite
import biotite.database.rcsb as rcsb
import biotite.structure as struc
import biotite.structure.io.mmtf as mmtf
import biotite.database.rcsb as rcsb
import ammolite
import numpy as np
import springcraft


PNG_SIZE = (800, 800)


Expand All @@ -37,8 +36,7 @@

# Filter first peptide chain
protein_chain = structure[
struc.filter_amino_acids(structure)
& (structure.chain_id == structure.chain_id[0])
struc.filter_amino_acids(structure) & (structure.chain_id == structure.chain_id[0])
]
# Filter CA atoms
ca_mask = (protein_chain.atom_name == "CA") & (protein_chain.element == "C")
Expand All @@ -57,15 +55,28 @@
pymol_object.show_as("cartoon")
# Show eigenvectors as arrows
ammolite.draw_arrows(
ca.coord, ca.coord + vector,
radius=0.2, head_radius=0.4, head_length=1.0
ca.coord, ca.coord + vector, radius=0.2, head_radius=0.4, head_length=1.0
)
ammolite.cmd.set_view(
(
0.605540633,
0.363677770,
-0.707855821,
-0.416691631,
0.902691007,
0.107316799,
0.678002179,
0.229972601,
0.698157668,
0.000000000,
0.000000000,
-115.912551880,
32.098876953,
31.005725861,
78.377349854,
89.280677795,
142.544403076,
-20.000000000,
)
)
ammolite.cmd.set_view((
0.605540633, 0.363677770, -0.707855821,
-0.416691631, 0.902691007, 0.107316799,
0.678002179, 0.229972601, 0.698157668,
0.000000000, 0.000000000, -115.912551880,
32.098876953, 31.005725861, 78.377349854,
89.280677795, 142.544403076, -20.000000000
))
ammolite.show(PNG_SIZE)
ammolite.show(PNG_SIZE)
29 changes: 15 additions & 14 deletions doc/scraper.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
from glob import glob
import datetime
import shutil
import tempfile
import datetime
import time
from os.path import getsize

from sphinx_gallery.scrapers import figure_rst

NO_ASSIGN = "___"


def pymol_scraper(block, block_vars, gallery_conf):
block_type,_, _ = block
block_type, _, _ = block
if block_type == "code":
globals = block_vars["example_globals"]
# Look for replaced show() output:
Expand All @@ -20,54 +21,54 @@ def pymol_scraper(block, block_vars, gallery_conf):
image_path = globals[NO_ASSIGN]
# Copy the images into the 'gallery' directory under a canonical
# sphinx-gallery name
image_path_iterator = block_vars['image_path_iterator']
image_path_iterator = block_vars["image_path_iterator"]
image_destination = image_path_iterator.next()
shutil.copy(image_path, image_destination)
return figure_rst([image_destination], gallery_conf['src_dir'])
return figure_rst([], gallery_conf['src_dir'])
return figure_rst([image_destination], gallery_conf["src_dir"])
return figure_rst([], gallery_conf["src_dir"])


def overwrite_display_func(gallery_conf, fname):
import ammolite

def show(size=None, use_ray=False, timeout=60.0, pymol_instance=None):
INTERVAL = 0.1

if size is None:
width = 0
height = 0
else:
width, height = size

if use_ray:
ray = 1
else:
ray = 0

image_file = tempfile.NamedTemporaryFile(
delete=False, prefix="ammolite_", suffix=".png"
)
image_file.close()

start_time = datetime.datetime.now()

ammolite.cmd.png(image_file.name, width, height, ray=ray)

while True:
# After 'timeout' seconds the loop exits with an error
if (datetime.datetime.now() - start_time).total_seconds() > timeout:
raise TimeoutError(
"No PNG image was output within the expected time limit"
)

# Check if PyMOL has already written image data to file
if getsize(image_file.name) > 0:
break

time.sleep(INTERVAL)

return image_file.name

ammolite.show = show
ammolite.cmd.reinitialize()
ammolite.setup_parameters(ammolite.pymol)
ammolite.setup_parameters(ammolite.pymol)
8 changes: 3 additions & 5 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ channels:
- conda-forge

dependencies:
- numpy >=1.15
- biotite >=0.32
- prody >=2.1
- numpy >=2.0
- biotite >=1.0.1
- pytest >=5.2
- matplotlib >=3.3
- poetry >=1.0
Expand All @@ -18,5 +17,4 @@ dependencies:
- sphinx-gallery =0.9.0
- numpydoc >=0.8
- ammolite >=0.8
- rpy2
- r-bio3d
- ruff >=0.6.7
Loading

0 comments on commit eb8382f

Please sign in to comment.