Skip to content

Commit

Permalink
Updated project files
Browse files Browse the repository at this point in the history
  • Loading branch information
Arman committed Sep 25, 2024
1 parent ea21ec8 commit ca9e5fa
Show file tree
Hide file tree
Showing 23 changed files with 1,226 additions and 36 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ __pycache__/
examples/

venv/
data/
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ __pycache__/
.vscode/

venv/
data
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
FROM docker.io/python:3.12.1-slim-bookworm

LABEL org.opencontainers.image.authors="FNNDSC <[email protected]>" \
org.opencontainers.image.title="Multiple image registration" \
org.opencontainers.image.description="A ChRIS plugin to do multiple image registration"
org.opencontainers.image.title="Images registration" \
org.opencontainers.image.description="A ChRIS plugin to do image registration"

ARG SRCDIR=/usr/local/src/pl-images-register
WORKDIR ${SRCDIR}
Expand Down
177 changes: 177 additions & 0 deletions archives/Trash/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# _ChRIS_ Plugin Template

[![test status](https://github.com/FNNDSC/python-chrisapp-template/actions/workflows/src.yml/badge.svg)](https://github.com/FNNDSC/python-chrisapp-template/actions/workflows/src.yml)
[![MIT License](https://img.shields.io/github/license/FNNDSC/python-chrisapp-template)](LICENSE)

This is a minimal template repository for _ChRIS_ plugin applications in Python.

## About _ChRIS_ Plugins

A _ChRIS_ plugin is a scientific data-processing software which can run anywhere all-the-same:
in the cloud via a [web app](https://github.com/FNNDSC/ChRIS_ui/), or on your own laptop
from the terminal. They are easy to build and easy to understand: most simply, a
_ChRIS_ plugin is a command-line program which processes data from an input directory
and creates data to an output directory with the usage
`commandname [options...] inputdir/ outputdir/`.

For more information, visit our website https://chrisproject.org

## How to Use This Template

Go to https://github.com/FNNDSC/python-chrisapp-template and click "Use this template".
The newly created repository is ready to use right away.

A script `bootstrap.sh` is provided to help fill in and rename values for your new project.
It is optional to use.

1. Edit the variables in `bootstrap.sh`
2. Run `./bootstrap.sh`
3. Follow the instructions it will print out

## Example Plugins

Here are some good, complete examples of _ChRIS_ plugins created from this template.

- https://github.com/FNNDSC/pl-dcm2niix (basic command wrapper example)
- <https://github.com/FNNDSC/pl-adapt_object_mesh> (parallelizes a command)
- https://github.com/FNNDSC/pl-mri-preview (uses [NiBabel](https://nipy.org/nibabel/))
- https://github.com/FNNDSC/pl-pyvista-volume (example using Python package project structure and pytest)
- https://github.com/FNNDSC/pl-fetal-cp-surface-extract (has a good README.md)

## What's Inside

| Path | Purpose |
|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `app.py` | Main script: start editing here! |
| `tests/` | Unit tests |
| `setup.py` | [Python project metadata and installation script](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#setup-py) |
| `requirements.txt` | List of Python dependencies |
| `Dockerfile` | [Container image build recipe](https://docs.docker.com/engine/reference/builder/) |
| `.github/workflows/ci.yml` | "continuous integration" using [Github Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions): automatic testing, building, and uploads to https://chrisstore.co |

## Contributing

The source code for the `main` branch of this repository is on the
[src](https://github.com/fnndsc/python-chrisapp-template/tree/src)
branch, which has an additional file
[`.github/workflows/src.yml`](https://github.com/FNNDSC/python-chrisapp-template/blob/src/.github/workflows/src.yml)
When tests pass, changes are automatically merged into `main`.
Developers should commit to or make pull requests targeting `src`.
Do not push directly to `main`.

This is a workaround in order to do automatic testing of this template
without including the `.github/workflows/src.yml` file in the template itself.

<!-- BEGIN README TEMPLATE
# ChRIS Plugin Title
[![Version](https://img.shields.io/docker/v/fnndsc/pl-appname?sort=semver)](https://hub.docker.com/r/fnndsc/pl-appname)
[![MIT License](https://img.shields.io/github/license/fnndsc/pl-appname)](https://github.com/FNNDSC/pl-appname/blob/main/LICENSE)
[![ci](https://github.com/FNNDSC/pl-appname/actions/workflows/ci.yml/badge.svg)](https://github.com/FNNDSC/pl-appname/actions/workflows/ci.yml)
`pl-appname` is a [_ChRIS_](https://chrisproject.org/)
_ds_ plugin which takes in ... as input files and
creates ... as output files.
## Abstract
...
## Installation
`pl-appname` is a _[ChRIS](https://chrisproject.org/) plugin_, meaning it can
run from either within _ChRIS_ or the command-line.
## Local Usage
To get started with local command-line usage, use [Apptainer](https://apptainer.org/)
(a.k.a. Singularity) to run `pl-appname` as a container:
```shell
apptainer exec docker://fnndsc/pl-appname commandname [--args values...] input/ output/
```
To print its available options, run:
```shell
apptainer exec docker://fnndsc/pl-appname commandname --help
```
## Examples
`commandname` requires two positional arguments: a directory containing
input data, and a directory where to create output data.
First, create the input directory and move input data into it.
```shell
mkdir incoming/ outgoing/
mv some.dat other.dat incoming/
apptainer exec docker://fnndsc/pl-appname:latest commandname [--args] incoming/ outgoing/
```
## Development
Instructions for developers.
### Building
Build a local container image:
```shell
docker build -t localhost/fnndsc/pl-appname .
```
### Running
Mount the source code `app.py` into a container to try out changes without rebuild.
```shell
docker run --rm -it --userns=host -u $(id -u):$(id -g) \
-v $PWD/app.py:/usr/local/lib/python3.12/site-packages/app.py:ro \
-v $PWD/in:/incoming:ro -v $PWD/out:/outgoing:rw -w /outgoing \
localhost/fnndsc/pl-appname commandname /incoming /outgoing
```
### Testing
Run unit tests using `pytest`.
It's recommended to rebuild the image to ensure that sources are up-to-date.
Use the option `--build-arg extras_require=dev` to install extra dependencies for testing.
```shell
docker build -t localhost/fnndsc/pl-appname:dev --build-arg extras_require=dev .
docker run --rm -it localhost/fnndsc/pl-appname:dev pytest
```
## Release
Steps for release can be automated by [Github Actions](.github/workflows/ci.yml).
This section is about how to do those steps manually.
### Increase Version Number
Increase the version number in `setup.py` and commit this file.
### Push Container Image
Build and push an image tagged by the version. For example, for version `1.2.3`:
```
docker build -t docker.io/fnndsc/pl-appname:1.2.3 .
docker push docker.io/fnndsc/pl-appname:1.2.3
```
### Get JSON Representation
Run [`chris_plugin_info`](https://github.com/FNNDSC/chris_plugin#usage)
to produce a JSON description of this plugin, which can be uploaded to _ChRIS_.
```shell
docker run --rm docker.io/fnndsc/pl-appname:1.2.3 chris_plugin_info -d docker.io/fnndsc/pl-appname:1.2.3 > chris_plugin_info.json
```
Intructions on how to upload the plugin to _ChRIS_ can be found here:
https://chrisproject.org/docs/tutorials/upload_plugin
END README TEMPLATE -->
70 changes: 70 additions & 0 deletions archives/Trash/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env python

from pathlib import Path
from argparse import ArgumentParser, Namespace, ArgumentDefaultsHelpFormatter

from chris_plugin import chris_plugin, PathMapper

__version__ = '1.0.0'

DISPLAY_TITLE = r"""
ChRIS Plugin Template Title
"""


parser = ArgumentParser(description='!!!CHANGE ME!!! An example ChRIS plugin which '
'counts the number of occurrences of a given '
'word in text files.',
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-w', '--word', required=True, type=str,
help='word to count')
parser.add_argument('-p', '--pattern', default='**/*.txt', type=str,
help='input file filter glob')
parser.add_argument('-V', '--version', action='version',
version=f'%(prog)s {__version__}')


# The main function of this *ChRIS* plugin is denoted by this ``@chris_plugin`` "decorator."
# Some metadata about the plugin is specified here. There is more metadata specified in setup.py.
#
# documentation: https://fnndsc.github.io/chris_plugin/chris_plugin.html#chris_plugin
@chris_plugin(
parser=parser,
title='My ChRIS plugin',
category='', # ref. https://chrisstore.co/plugins
min_memory_limit='100Mi', # supported units: Mi, Gi
min_cpu_limit='1000m', # millicores, e.g. "1000m" = 1 CPU core
min_gpu_limit=0 # set min_gpu_limit=1 to enable GPU
)
def main(options: Namespace, inputdir: Path, outputdir: Path):
"""
*ChRIS* plugins usually have two positional arguments: an **input directory** containing
input files and an **output directory** where to write output files. Command-line arguments
are passed to this main method implicitly when ``main()`` is called below without parameters.
:param options: non-positional arguments parsed by the parser given to @chris_plugin
:param inputdir: directory containing (read-only) input files
:param outputdir: directory where to write output files
"""

print(DISPLAY_TITLE)

# Typically it's easier to think of programs as operating on individual files
# rather than directories. The helper functions provided by a ``PathMapper``
# object make it easy to discover input files and write to output files inside
# the given paths.
#
# Refer to the documentation for more options, examples, and advanced uses e.g.
# adding a progress bar and parallelism.
mapper = PathMapper.file_mapper(inputdir, outputdir, glob=options.pattern, suffix='.count.txt')
for input_file, output_file in mapper:
# The code block below is a small and easy example of how to use a ``PathMapper``.
# It is recommended that you put your functionality in a helper function, so that
# it is more legible and can be unit tested.
data = input_file.read_text()
frequency = data.count(options.word)
output_file.write_text(str(frequency))


if __name__ == '__main__':
main()
29 changes: 29 additions & 0 deletions archives/Trash/qodana.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#-------------------------------------------------------------------------------#
# Qodana analysis is configured by qodana.yaml file #
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
#-------------------------------------------------------------------------------#
version: "1.0"

#Specify inspection profile for code analysis
profile:
name: qodana.starter

#Enable inspections
#include:
# - name: <SomeEnabledInspectionId>

#Disable inspections
#exclude:
# - name: <SomeDisabledInspectionId>
# paths:
# - <path/where/not/run/inspection>

#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
#bootstrap: sh ./prepare-qodana.sh

#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
#plugins:
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)

#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
linter: jetbrains/qodana-python:latest
1 change: 1 addition & 0 deletions archives/Trash/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
chris_plugin==0.4.0
48 changes: 48 additions & 0 deletions archives/Trash/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from setuptools import setup
import re

_version_re = re.compile(r"(?<=^__version__ = (\"|'))(.+)(?=\"|')")

def get_version(rel_path: str) -> str:
"""
Searches for the ``__version__ = `` line in a source code file.
https://packaging.python.org/en/latest/guides/single-sourcing-package-version/
"""
with open(rel_path, 'r') as f:
matches = map(_version_re.search, f)
filtered = filter(lambda m: m is not None, matches)
version = next(filtered, None)
if version is None:
raise RuntimeError(f'Could not find __version__ in {rel_path}')
return version.group(0)


setup(
name='chris-plugin-template',
version=get_version('archives/Trash/app.py'),
description='A ChRIS DS plugin template',
author='FNNDSC',
author_email='[email protected]',
url='https://github.com/FNNDSC/python-chrisapp-template',
py_modules=['app'],
install_requires=['chris_plugin'],
license='MIT',
entry_points={
'console_scripts': [
'commandname = app:main'
]
},
classifiers=[
'License :: OSI Approved :: MIT License',
'Topic :: Scientific/Engineering',
'Topic :: Scientific/Engineering :: Bio-Informatics',
'Topic :: Scientific/Engineering :: Medical Science Apps.'
],
extras_require={
'none': [],
'dev': [
'pytest~=7.1'
]
}
)
21 changes: 21 additions & 0 deletions archives/Trash/tests/test_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from pathlib import Path

from archives.Trash.app import parser, main


def test_main(tmp_path: Path):
# setup example data
inputdir = tmp_path / 'incoming'
outputdir = tmp_path / 'outgoing'
inputdir.mkdir()
outputdir.mkdir()
(inputdir / 'plaintext.txt').write_text('hello ChRIS, I am a ChRIS plugin')

# simulate run of main function
options = parser.parse_args(['--word', 'ChRIS', '--pattern', '*.txt'])
main(options, inputdir, outputdir)

# assert behavior is expected
expected_output_file = outputdir / 'plaintext.count.txt'
assert expected_output_file.exists()
assert expected_output_file.read_text() == '2'
Loading

0 comments on commit ca9e5fa

Please sign in to comment.