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
16 changes: 16 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every day
interval: "daily"
time: "09:00"
timezone: "UTC"
assignees:
- "jimboid"
185 changes: 185 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
name: ci/cd
on:
pull_request:
repository_dispatch:
types: [build]
workflow_dispatch:

jobs:
build:
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-24.04' || matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' }}
name: build ${{ matrix.platform }}
outputs:
tag: ${{ steps.envvars.outputs.tag }}
steps:
- name: checkout
uses: actions/checkout@v5.0.0

- name: Prepare env
id: envvars
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
if [ ${{ github.event.client_payload.tag }} != 'null' ]; then
echo "tag=${{ github.event.client_payload.tag }}" >> $GITHUB_OUTPUT
else
echo "tag=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
fi

- name: Metadata
id: meta
uses: docker/metadata-action@v5.8.0
with:
images: ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}

- name: Authenticate with GHCR
id: auth
uses: docker/login-action@v3.5.0
with:
registry: ghcr.io
username: ${{github.actor}}
password: ${{secrets.BUILD_TOKEN}}

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3.11.1

- name: Build and push by digest
id: build
uses: docker/build-push-action@v6.18.0
with:
file: ./docker/Dockerfile
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
tags: ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true

- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v4.6.2
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1

merge:
runs-on: ubuntu-24.04
name: merge into multiarch manifest
needs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v5.0.0
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true

- name: Authenticate with GHCR
id: auth
uses: docker/login-action@v3.5.0
with:
registry: ghcr.io
username: ${{github.actor}}
password: ${{secrets.BUILD_TOKEN}}

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3.11.1

- name: Metadata
id: meta
uses: docker/metadata-action@v5.8.0
with:
images: ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}
tags: dev

- name: Create manifest list and push
id: annotate
continue-on-error: true
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
--annotation='index:org.opencontainers.image.description=${{ github.event.repository.description }}' \
--annotation='index:org.opencontainers.image.licenses=MIT' \
--annotation='index:org.opencontainers.image.created=${{ steps.timestamp.outputs.timestamp }}' \
--annotation='index:org.opencontainers.image.url=${{ github.event.repository.url }}' \
--annotation='index:org.opencontainers.image.source=${{ github.event.repository.url }}' \
$(printf 'ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}@sha256:%s ' *)

- name: Create manifest list and push without annotations
if: steps.annotate.outcome == 'failure'
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf 'ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}@sha256:%s ' *)

- name: Inspect image
run: |
docker buildx imagetools inspect ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:dev

tests:
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' }}
name: testing on ${{ matrix.platform }}
timeout-minutes: 360
needs:
- build
- merge
steps:

- name: Test notebooks
shell: bash
run: |
docker run -t ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:dev bash -c "\
pip install pytest nbmake; \
find . -name '*.ipynb' | pytest --nbmake --nbmake-timeout=3600 --ignore=answers; "

tags:
runs-on: ubuntu-24.04
if: github.event_name != 'pull_request'
name: add tags
needs:
- build
- tests
steps:
- name: Authenticate with GHCR
id: auth
uses: docker/login-action@v3.5.0
with:
registry: "ghcr.io"
username: ${{github.actor}}
password: ${{secrets.BUILD_TOKEN}}

- name: tag release versions
shell: bash
run: |
docker buildx imagetools create \
--tag ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:latest \
--tag ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:${{ needs.build.outputs.tag }} \
ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:dev

- name: Post version update to dash
uses: peter-evans/repository-dispatch@v3.0.0
with:
token: ${{ secrets.BUILD_TOKEN }}
repository: jimboid/biosim-workshops-dash
event-type: build
client-payload: '{"repo": "${{ github.event.repository.name }}", "tag": "${{ needs.build.outputs.tag }}"}'
148 changes: 11 additions & 137 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,143 +1,17 @@
## Aimed at:
Anyone interested in using Python for Biomodelling. The material in
this workshop will help you get the most out of the other workshops
run during the week.
# CCPBioSim Basic Python Workshop

## Requirements:
Basic knowledge of Python e.g. as in [https://chryswoods.com/beginning_python](https://chryswoods.com/beginning_python)
[![build](https://github.com/ccpbiosim/python-workshop/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/ccpbiosim/python-workshop/actions/workflows/build.yaml)

## Abstract:
This workshop will introduce more intermediate features of Python that
are useful for biomolecular modellers. This will include the use of
Jupyter notebooks, how to write Python functions and classes, and
how to properly structure, document and test code. The second
part will introduce you to data analysis tools such as Pandas,
NumPy and MatplotLib.
## Docker

## Training Material
This container is derived from the CCPBioSim JupyterHub image. This container
adds the necessary software packages and notebook content to form a deployable
course container. The source content for this course can be found at
https://github.com/CCPBioSim/python-and-data-workshop

The workshop consists of a series of Jupyter notebooks. These are available
below, and can be run using the
<a href="https://notebook.biosimspace.org" target="_blank">workshop Jupyter server</a>.
## How to Use

Once you have started the server, navigate to the `python_and_data` directory
and you will find all workshop material there.
In our containers we are using the JupyterHub default port 8888, so you should
forward this port when deploying locally::

The workshops are numbered sequentially from `01_jupyter_howto.ipynb` to
`17_regular_expressions.ipynb`. They cover a variety of useful Python topics,
and are *mostly* independent. Feel free to go through them in the order you
prefer, and to skip topics that you feel you are already comfortable with.

There are exercises in many of the topics. You can find answers in the
equivalent notebook in the `answers` directory.

Below is a summary of each topic, together with links to view html versions
of the notebooks the their answers, and to download the notebooks.

## Contents

### [01_jupyter_howto.ipynb](html/01_jupyter_howto.html) ([answers](html/answers/01_jupyter_howto.html))

Introduction to Jupyter notebooks, including how to use the interface,
how to view molecules, draw graphs, download files, and start a bash
terminal.

[download](01_jupyter_howto.ipynb) | [download answers](answers/01_jupyter_howto.ipynb)

### [02_lists.ipynb](html/02_lists.html) ([answers](html/answers/02_lists.html))

Learn how to use Python Lists

[download](02_lists.ipynb) | [download answers](answers/02_lists.ipynb)

### [03_dictionaries.ipynb](html/03_dictionaries.html) ([answers](html/answers/03_dictionaries.html))

Learn how to use Python dictionaries

[download](03_dictionaries.ipynb) | [download answers](answers/03_dictionaries.ipynb)

### [04_functions.ipynb](html/04_functions.html) ([answers](html/answers/04_functions.html))

Learn how to write a function in Python

[download](04_functions.ipynb) | [download answers](answers/04_functions.ipynb)

### [05_objects.ipynb](html/05_objects.html) ([answers](html/answers/05_objects.html))

Learn about objects and object orientated programming

[download](05_objects.ipynb) | [download answers](answers/05_objects.ipynb)

### [06_classes.ipynb](html/06_classes.html) ([answers](html/answers/06_classes.html))

Learn how to write your own Python classes

[download](06_classes.ipynb) | [download answers](answers/06_classes.ipynb)

### [07_documentation.ipynb](html/07_documentation.html) ([answers](html/answers/07_documentation.html))

Learn how to add documentation to your code

[download](07_documentation.ipynb) | [download answers](answers/07_documentation.ipynb)

### [08_class_documentation.ipynb](html/08_class_documentation.html) ([answers](html/answers/08_class_documentation.html))

Learn how to document Python classes, and protect hidden (private) functions
and data from view.

[download](08_class_documentation.ipynb) | [download answers](answers/08_class_documentation.ipynb)

### [09_exceptions.ipynb](html/09_exceptions.html) ([answers](html/answers/09_exceptions.html))

Learn about exceptions, and how they can be used to signify errors.

[download](09_exceptions.ipynb) | [download answers](answers/09_exceptions.ipynb)

### [10_error_handling.ipynb](html/10_error_handling.html) ([answers](html/answers/10_error_handling.html))

Learn how to handle errors by catching exceptions

[download](10_error_handling.ipynb) | [download answers](answers/10_error_handling.ipynb)

### [11_modules.ipynb](html/11_modules.html) ([answers](html/answers/11_modules.html))

Learn how to package and share your code as a module

[download](11_modules.ipynb) | [download answers](answers/11_modules.ipynb)

### [12_pandas.ipynb](html/12_pandas.html) ([answers](html/answers/12_pandas.html))

Learn how to use the pandas library for data analysis

[download](12_pandas.ipynb) | [download answers](answers/12_pandas.ipynb)

### [13_basic_numpy.ipynb](html/13_basic_numpy.html) ([answers](html/answers/13_basic_numpy.html))

Learn how to use the NumPy library for numeric calculation

[download](13_basic_numpy.ipynb) | [download answers](answers/13_basic_numpy.ipynb)

### [14_more_numpy.ipynb](html/14_more_numpy.html) ([answers](html/answers/14_more_numpy.html))

Learn more about how to use NumPy, including understanding copies and views

[download](14_more_numpy.ipynb) | [download answers](answers/14_more_numpy.ipynb)

### [15_matplotlib.ipynb](html/15_matplotlib.html) ([answers](html/answers/15_matplotlib.html))

Learn how to use the pandas with the MatPlotLib library to draw graphs

[download](15_matplotlib.ipynb) | [download answers](answers/15_matplotlib.ipynb)

### [16_viewing_molecules.ipynb](html/16_viewing_molecules.html) ([answers](html/answers/16_viewing_molecules.html))

Learn how to use the nglview and BioSimSpace libraries to create 3D
views of molecules.

[download](16_viewing_molecules.ipynb) | [download answers](answers/16_viewing_molecules.ipynb)

### [17_regular_expressions.ipynb](html/17_regular_expressions.html) ([answers](html/answers/17_regular_expressions.html))

Learn how to understand and write regular expressions for text/pattern matching.

[download](17_regular_expressions.ipynb) | [download answers](answers/17_regular_expressions.ipynb)
docker run -p 8888:8888 ghcr.io/jimboid/biosim-python-workshop:latest
3 changes: 0 additions & 3 deletions _config.yml

This file was deleted.

29 changes: 29 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Start with BioSim base image.
ARG BASE_IMAGE=latest
FROM ghcr.io/ccpbiosim/jupyterhub-base:$BASE_IMAGE

LABEL maintainer="James Gebbie-Rayet <james.gebbie@stfc.ac.uk>"
LABEL org.opencontainers.image.source=https://github.com/jimboid/biosim-python-workshop
LABEL org.opencontainers.image.description="A container environment for the ccpbiosim workshop on Python."
LABEL org.opencontainers.image.licenses=MIT

# Switch to jovyan user.
USER $NB_USER
WORKDIR $HOME

# Install workshop deps
RUN conda install matplotlib numpy pandas nglview ipywidgets -y
RUN pip install mdtraj

# Get workshop files and move them to jovyan directory.
COPY --chown=1000:100 . .
RUN rm -rf _config.yml AUTHORS README.md docker .git .github

# Copy lab workspace
COPY --chown=1000:100 docker/default-37a8.jupyterlab-workspace /home/jovyan/.jupyter/lab/workspaces/default-37a8.jupyterlab-workspace

# UNCOMMENT THIS LINE FOR REMOTE DEPLOYMENT
COPY docker/jupyter_notebook_config.py /etc/jupyter/

# Always finish with non-root user as a precaution.
USER $NB_USER
1 change: 1 addition & 0 deletions docker/default-37a8.jupyterlab-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"data":{"layout-restorer:data":{"main":{"dock":{"type":"tab-area","currentIndex":0,"widgets":["notebook:01_jupyter_howto.ipynb"]},"current":"notebook:01_jupyter_howto.ipynb"},"left":{"collapsed":false,"current":"filebrowser","widgets":["filebrowser","running-sessions","@jupyterlab/toc:plugin","extensionmanager.main-view"]},"right":{"collapsed":true,"widgets":["jp-property-inspector"]}},"notebook:01_jupyter_howto.ipynb":{"data":{"path":"01_jupyter_howto.ipynb","factory":"Notebook"}}},"metadata":{"id":"default"}}
2 changes: 2 additions & 0 deletions docker/jupyter_notebook_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

c.JupyterHub.authenticator_class = 'tmpauthenticator.TmpAuthenticator'
Loading