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

[INFRA] Python test automation #44

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
42 changes: 42 additions & 0 deletions .github/workflows/run_demos_python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: run python demos

on:
push:
branches: ["*"]
pull_request:
branches: ["*"]

jobs:
demos:
continue-on-error: true
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04]
python-version: ["3.7"]
Remi-Gau marked this conversation as resolved.
Show resolved Hide resolved

steps:
- name: Shallow clone GLMsingle
uses: actions/checkout@v3
with:
submodules: "recursive"
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools
pip install .
pip install -r requirements_dev.txt

- name: Display Python version and packages
run: |
python -c "import sys; print(sys.version)"
pip list

- name: Run tests and generate coverage report
run: pytest --nbmake --nbmake-timeout=3000 "./examples"
54 changes: 54 additions & 0 deletions .github/workflows/run_tests_python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: tests and coverage with python

on:
push:
branches: ["*"]
pull_request:
branches: ["*"]

jobs:
tests:
continue-on-error: true
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to test with different OS?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably higher priority is different python versions (since python versions seem to cause more problems)... I suppose, assuming that the tests can run pretty quickly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now set up to test in parallel python 3.7 to python 3.9 on ubuntu, mac, windows

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running the tests themselves takes about a minute in CI. But the whole takes a bit more time than this because of the set up and tear down

python-version: ["3.7", "3.8", "3.9", "3.10"]

steps:
- name: Shallow clone GLMsingle
uses: actions/checkout@v3
with:
submodules: "recursive"
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools
pip install .
pip install -r requirements_dev.txt

- name: Display Python version and packages
run: |
python -c "import sys; print(sys.version)"
pip list

- name: Prepare data
run: make tests/data/nsdcoreexampledataset.mat

- name: Run tests and generate coverage report
run: pytest -v --cov glmsingle --cov-report xml tests

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
file: ./coverage.xml
flags: python
name: codecov-umbrella
fail_ci_if_error: true
verbose: true
11 changes: 8 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#
# vscode files
.vscode/

# test related
tests/outputs/

# data folder
# data folders
data/

# example output folders
Expand All @@ -13,6 +15,9 @@ figures/
report.html
##*.png

# pyenv
Pipfile

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down Expand Up @@ -54,6 +59,7 @@ pip-delete-this-directory.txt
htmlcov/
.tox/
.coverage
coverage_html
.coverage.*
.cache
nosetests.xml
Expand Down Expand Up @@ -153,4 +159,3 @@ codegen/

# Octave session info
octave-workspace

7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
hooks:
- id: check-yaml
56 changes: 56 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# CONTRIBUTING

Information for anyone who would like to contribute to this repository.

## Repository map

```bash
├── .git
├── .github
│ └── workflows # Github continuous integration set up
├── examples
│ ├── data
│ ├── example1outputs
│ ├── example2outputs
├── glmsingle # Python implementation
│ ├── cod
│ ├── design
│ ├── gmm
│ ├── hrf
│ ├── ols
│ ├── ssq
│ └── utils
├── matlab # Matlab implementation
│ ├── examples
│ ├── fracridge
│ └── utilities
└── tests # Python and Matlab tests
└── data

```

## Generic

### Makefile

### pre-commit

## Matlab

### Style guide

### Tests

#### Demos

### Continuous integration

## Python

### Style guide

### Tests

#### Demos

### Continuous integration
116 changes: 116 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
.DEFAULT_GOAL := help

BROWSER := python -c "$$BROWSER_PYSCRIPT"

# TODO make more general to use the local matlab version
MATLAB = /usr/local/MATLAB/R2017a/bin/matlab
MATLAB_ARG = -nodisplay -nosplash -nodesktop

define BROWSER_PYSCRIPT
import os, webbrowser, sys

from urllib.request import pathname2url

webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
endef
export BROWSER_PYSCRIPT

# determines what "make help" will show
define PRINT_HELP_PYSCRIPT
import re, sys

for line in sys.stdin:
match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line)
if match:
target, help = match.groups()
print("%-20s %s" % (target, help))
endef
export PRINT_HELP_PYSCRIPT

################################################################################
# GENERIC
.PHONY: help clean clean-test lint install_dev

help:
@python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
clean: clean-build clean-pyc clean-test ## remove all build, test, coverage artifacts

clean-test: ## remove test and coverage artifacts
rm -rf .tox/
rm -rf .coverage
rm -rf htmlcov/
rm -rf .pytest_cache
rm -rf tests/data
rm -rf test/outputs

install_dev: ## install for both matlab and python developpers
pip install -e .
pip install -r requirements_dev.txt

lint: lint/black lint/flake8 lint/miss_hit ## check style

test: test-matlab test-python

tests/data/nsdcoreexampledataset.mat:
mkdir tests/data
curl -fsSL --retry 5 -o "tests/data/nsdcoreexampledataset.mat" https://osf.io/k89b2/download

################################################################################

################################################################################
# MATLAB

.PHONY: lint/miss_hit

lint/miss_hit: ## lint and checks matlab code
mh_style --fix tests && mh_metric --ci tests && mh_lint tests

test-matlab: tests/data/nsdcoreexampledataset.mat
$(MATLAB) $(MATLAB_ARG) -r "run_tests; exit()"

coverage-matlab: test-matlab
$(BROWSER) coverage_html/index.html

################################################################################

################################################################################
# PYTHON

.PHONY: clean-build clean-pyc coverage-python install lint/flake8 lint/black

clean-build: ## remove build artifacts
rm -fr build/
rm -fr dist/
rm -fr .eggs/
find . -name '*.egg-info' -exec rm -fr {} +
find . -name '*.egg' -exec rm -f {} +

clean-pyc: ## remove Python file artifacts
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
find . -name '__pycache__' -exec rm -fr {} +

lint/flake8: ## check style with flake8
flake8 tests
lint/black: ## check style with black
black tests

test-python: tests/data/nsdcoreexampledataset.mat ## run tests quickly with the default Python
pytest

test-notebooks:
pytest --nbmake --nbmake-timeout=3000 "./examples"
test-all: ## run tests on every Python version with tox
tox

coverage-python: ## check code coverage quickly with the default Python
coverage run --source glmsingle -m pytest
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html

install: clean ## install the package to the active Python's site-packages
python setup.py install

################################################################################
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,6 @@ This will also clone [`fracridge`](https://github.com/nrdg/fracridge) as a submo

To use the GLMsingle toolbox, add it and `fracridge` to your MATLAB path by running the `setup.m` script.

## Example scripts

We provide a number of example scripts that demonstrate usage of GLMsingle. You can browse these example scripts here:

(Python Example 1 - event-related design) https://htmlpreview.github.io/?https://github.com/kendrickkay/GLMsingle/blob/main/examples/example1.html

(Python Example 2 - block design) https://htmlpreview.github.io/?https://github.com/kendrickkay/GLMsingle/blob/main/examples/example2.html

(MATLAB Example 1 - event-related design) https://htmlpreview.github.io/?https://github.com/kendrickkay/GLMsingle/blob/main/matlab/examples/example1preview/example1.html

(MATLAB Example 2 - block design) https://htmlpreview.github.io/?https://github.com/kendrickkay/GLMsingle/blob/main/matlab/examples/example2preview/example2.html

If you would like to run these example scripts, the Python versions are available in `/GLMsingle/examples`, and the MATLAB versions are available in `/GLMsingle/matlab/examples`. Each notebook contains a full walkthrough of the process of loading an example dataset and design matrix, estimating neural responses using GLMsingle, estimating the reliability of responses at each voxel, and comparing those achieved via GLMsingle to those achieved using a baseline GLM.

## Python

To install:
Expand All @@ -63,12 +49,25 @@ Running the demos requires:
pip install jupyterlab
```

Code dependencies: see requirements.txt
Code dependencies: see [requirements.txt](./requirements.txt)

Notes:
* Please note that GLMsingle is not (yet) compatible with Python 3.9 (due to an incompatibility between scikit-learn and Python 3.9). Please use Python 3.8 or earlier.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed this since the tests pass with python 3.9.

But there seem to be a different issue with python 3.10 and numpy: I can investigate but I would not consider necessary for this PR

* Currently, numpy has a 4GB limit for the pickle files it writes; thus, GLMsingle will crash if the file outputs exceed that size. One workaround is to turn off "disk saving" and instead get the outputs of GLMsingle in your workspace and save the outputs yourself to HDF5 format.

## Example scripts

We provide a number of example scripts that demonstrate usage of GLMsingle. You can browse these example scripts here:

(Python Example 1 - event-related design) https://htmlpreview.github.io/?https://github.com/kendrickkay/GLMsingle/blob/main/examples/example1.html

(Python Example 2 - block design) https://htmlpreview.github.io/?https://github.com/kendrickkay/GLMsingle/blob/main/examples/example2.html

(MATLAB Example 1 - event-related design) https://htmlpreview.github.io/?https://github.com/kendrickkay/GLMsingle/blob/main/matlab/examples/example1preview/example1.html

(MATLAB Example 2 - block design) https://htmlpreview.github.io/?https://github.com/kendrickkay/GLMsingle/blob/main/matlab/examples/example2preview/example2.html

If you would like to run these example scripts, the Python versions are available in `/GLMsingle/examples`, and the MATLAB versions are available in `/GLMsingle/matlab/examples`. Each notebook contains a full walkthrough of the process of loading an example dataset and design matrix, estimating neural responses using GLMsingle, estimating the reliability of responses at each voxel, and comparing those achieved via GLMsingle to those achieved using a baseline GLM.

## Additional information

For additional information, please visit the Wiki page associated with this
Expand All @@ -80,6 +79,10 @@ If you use GLMsingle in your research, please cite the following paper:

* [Prince, J.S., Charest, I., Kurzawski, J.W., Pyles, J.A., Tarr, M.J., Kay, K.N. GLMsingle: a toolbox for improving single-trial fMRI response estimates. bioRxiv (2022).](https://www.biorxiv.org/content/10.1101/2022.01.31.478431v1)

## Contributing

If you want to contribute to GLMsingle see the [contributing](./CONTRIBUTING.md) documentation to help you know what is where and how to set things up.

## Change history

* 2021/10/12 - Version 1.0 of GLMsingle is now released. A git tag has been added to the repo.
Expand Down
16 changes: 8 additions & 8 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
numpy
scipy
sklearn
matplotlib
tqdm
fracridge
nibabel
h5py
fracridge>=1.4.3
h5py>=3.1.0
matplotlib>=3.3.4
nibabel>=3.2.2
numpy>=1.17.0
scikit-learn>=0.23.2
scipy>=1.5.4
tqdm>=4.63.1
Comment on lines +1 to +8
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have pinned the dependency minimum version for GLMsingle to be those that were installed by default when using python 3.6.

Loading