Skip to content

Commit

Permalink
Add name, public_repo, dock_image to JSON description
Browse files Browse the repository at this point in the history
  • Loading branch information
jennydaman committed Oct 12, 2023
1 parent 8ab3feb commit bd253d3
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 78 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ env:
jobs:
pypi:
name: Upload to PyPI
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.10'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
local:
name: Unit tests
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: [ '3.8.2', '3.9', '3.10', '3.11' ]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ After developing a plugin, use the command `chris_plugin_info`
to produce a JSON description of your *ChRIS* plugin.

```shell
chris_plugin_info [module_name]
chris_plugin_info --dock-image {registry}/{repo}/{name}:{version} [module_name]
```

If `module_name` is not given, then `chris_plugin_info`
Expand Down
26 changes: 11 additions & 15 deletions examples/pl-copy/setup.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
from setuptools import setup

setup(
name = 'simple_copy',
version = '1.0.0',
description = 'A ChRIS ds plugin that copies data',
author = 'FNNDSC',
author_email = 'dev@babyMRI.org',
url = 'https://github.com/FNNDSC/chris_plugin/tree/master/examples/pl-copy',
py_modules = ['simple_copy'],
install_requires = ['chris_plugin'],
license = 'MIT',
python_requires = '>=3.10.2',
entry_points = {
'console_scripts': [
'simple_copy = simple_copy:main'
]
}
name="simple_copy",
version="1.0.0",
description="A ChRIS ds plugin that copies data",
author="FNNDSC",
author_email="dev@babyMRI.org",
url="https://github.com/FNNDSC/chris_plugin/tree/master/examples/pl-copy",
py_modules=["simple_copy"],
install_requires=["chris_plugin"],
license="MIT",
python_requires=">=3.10.2",
entry_points={"console_scripts": ["simple_copy = simple_copy:main"]},
)
6 changes: 3 additions & 3 deletions examples/pl-copy/simple_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@


def copy(input_file, output_file):
print(f'Copying {input_file} to {output_file}')
print(f"Copying {input_file} to {output_file}")
shutil.copyfile(input_file, output_file)


@chris_plugin
def main(_, inputdir, outputdir):
print('Program started')
print("Program started")
for input_file, output_file in PathMapper.file_mapper(inputdir, outputdir):
copy(input_file, output_file)
print('Complete!~')
print("Complete!~")
9 changes: 4 additions & 5 deletions examples/pl-git-clone/git_clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from chris_plugin import chris_plugin


parser = ArgumentParser(description='A ChRIS fs plugin wrapper for git clone')
parser.add_argument('-r', '--repo', required=True, type=str,
help='repository URI')
parser = ArgumentParser(description="A ChRIS fs plugin wrapper for git clone")
parser.add_argument("-r", "--repo", required=True, type=str, help="repository URI")


@chris_plugin(parser=parser, title='Git Clone')
@chris_plugin(parser=parser, title="Git Clone")
def main(options, outputdir):
sp.run(['git', 'clone', options.repo, outputdir], check=True)
sp.run(["git", "clone", options.repo, outputdir], check=True)
26 changes: 11 additions & 15 deletions examples/pl-git-clone/setup.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
from setuptools import setup

setup(
name = 'git-clone',
version = '1.0.0',
description = 'A ChRIS fs plugin for git clone',
author = 'FNNDSC',
author_email = 'dev@babyMRI.org',
url = 'https://github.com/FNNDSC/chris_plugin/tree/master/examples/pl-git-clone',
py_modules = ['git_clone'],
install_requires = ['chris_plugin'],
license = 'MIT',
python_requires = '>=3.10.2',
entry_points = {
'console_scripts': [
'git_clone_wrapper = git_clone:main'
]
}
name="git-clone",
version="1.0.0",
description="A ChRIS fs plugin for git clone",
author="FNNDSC",
author_email="dev@babyMRI.org",
url="https://github.com/FNNDSC/chris_plugin/tree/master/examples/pl-git-clone",
py_modules=["git_clone"],
install_requires=["chris_plugin"],
license="MIT",
python_requires=">=3.10.2",
entry_points={"console_scripts": ["git_clone_wrapper = git_clone:main"]},
)
46 changes: 27 additions & 19 deletions examples/pl-replace/replace.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,27 @@
from tqdm.contrib.logging import logging_redirect_tqdm

# configure logging output to show time and thread name
logging.basicConfig(format='[%(asctime)s]%(threadName)s:%(message)s', level=logging.DEBUG)
logging.basicConfig(
format="[%(asctime)s]%(threadName)s:%(message)s", level=logging.DEBUG
)
logger = logging.getLogger(__name__)

# add command-line arguments
parser = ArgumentParser(description='multi-threaded find-and-replace tool',
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-i', '--inputPathFilter',
default='**/*.txt',
help='pattern of files to process')
parser.add_argument('-f', '--find', required=True, help='string to find')
parser.add_argument('-r', '--replace', required=False, default='REDACTED', help='word to replace with')
parser.add_argument('-t', '--threads', type=int, default=4, help='number of threads to use')
parser.add_argument('-s', '--slow', action='store_true', help='throttle performance')
parser = ArgumentParser(
description="multi-threaded find-and-replace tool",
formatter_class=ArgumentDefaultsHelpFormatter,
)
parser.add_argument(
"-i", "--inputPathFilter", default="**/*.txt", help="pattern of files to process"
)
parser.add_argument("-f", "--find", required=True, help="string to find")
parser.add_argument(
"-r", "--replace", required=False, default="REDACTED", help="word to replace with"
)
parser.add_argument(
"-t", "--threads", type=int, default=4, help="number of threads to use"
)
parser.add_argument("-s", "--slow", action="store_true", help="throttle performance")


@dataclass
Expand All @@ -50,8 +58,8 @@ def process_file(self, input_file: Path, output_file: Path):
"""
with logging_redirect_tqdm():
logger.debug('Started "%s"', input_file)
with input_file.open('r') as i:
with output_file.open('w') as o:
with input_file.open("r") as i:
with output_file.open("w") as o:
for line in i:
o.write(line.replace(self.find, self.replace))
if self.slow:
Expand All @@ -61,17 +69,17 @@ def process_file(self, input_file: Path, output_file: Path):

@chris_plugin(
parser=parser,
category='Text',
title='Simple Find and Replace Utility',
min_cpu_limit='2000m'
category="Text",
title="Simple Find and Replace Utility",
min_cpu_limit="2000m",
)
def main(options, inputdir: Path, outputdir: Path):

mapper = PathMapper.file_mapper(inputdir, outputdir, glob=options.inputPathFilter)
r = Replacer(find=options.find, replace=options.replace, slow=options.slow)

# create a progress bar with the total being the number of input files to process
with tqdm(desc='Processing', total=mapper.count()) as bar:
with tqdm(desc="Processing", total=mapper.count()) as bar:

# a wrapper function which calls the processing function and updates the process bar
def process_and_progress(i, o):
Expand All @@ -80,16 +88,16 @@ def process_and_progress(i, o):

# create a thread pool with the specified number of workers
with ThreadPoolExecutor(max_workers=options.threads) as pool:
logger.debug(f'Using %d threads', options.threads)
logger.debug(f"Using %d threads", options.threads)
# call the function on every input/output path pair
results = pool.map(lambda t: process_and_progress(*t), mapper)

# if any job failed, an exception will be raised when it's iterated over
for _ in results:
pass

logger.debug('done')
logger.debug("done")


if __name__ == '__main__':
if __name__ == "__main__":
main()
26 changes: 11 additions & 15 deletions examples/pl-replace/setup.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
from setuptools import setup

setup(
name = 'replace',
version = '1.0.0',
description = 'A ChRIS ds plugin that does a find-and-replace in text files.',
author = 'FNNDSC',
author_email = 'dev@babyMRI.org',
url = 'https://github.com/FNNDSC/chris_plugin/tree/master/examples/pl-replace',
py_modules = ['replace'],
install_requires = ['chris_plugin', 'tqdm'],
license = 'MIT',
python_requires = '>=3.10.2',
entry_points = {
'console_scripts': [
'replace = replace:main'
]
}
name="replace",
version="1.0.0",
description="A ChRIS ds plugin that does a find-and-replace in text files.",
author="FNNDSC",
author_email="dev@babyMRI.org",
url="https://github.com/FNNDSC/chris_plugin/tree/master/examples/pl-replace",
py_modules=["replace"],
install_requires=["chris_plugin", "tqdm"],
license="MIT",
python_requires=">=3.10.2",
entry_points={"console_scripts": ["replace = replace:main"]},
)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setup(
name="chris_plugin",
version="0.2.1",
version="0.3.0",
packages=find_packages(where="src"),
package_dir={"": "src", "chris_plugin": "src/chris_plugin"},
url="https://github.com/FNNDSC/chris_plugin",
Expand Down
36 changes: 35 additions & 1 deletion src/chris_plugin/tool/chris_plugin_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

from importlib.metadata import Distribution, distribution

from chris_plugin.tool.image import ImageTag, InvalidTag

try:
# new in Python 3.10
from importlib.metadata import packages_distributions
Expand All @@ -23,6 +25,21 @@


parser = argparse.ArgumentParser(description="Get ChRIS plugin description")
parser.add_argument("-n", "--name", required=False, type=str, help="Name of the plugin")
parser.add_argument(
"-r",
"--public-repo",
required=False,
type=str,
help="URL of web repository where source code of the plugin can be found",
)
parser.add_argument(
"-d",
"--dock-image",
required=True,
type=str,
help="Container image tag of the plugin",
)
parser.add_argument(
"distribution",
nargs="?",
Expand Down Expand Up @@ -174,10 +191,27 @@ def main():
mods, dist = get_or_guess(args.distribution)
for module_name in mods:
importlib.import_module(module_name)
details = get_registered()
setup = dist.metadata

try:
image = ImageTag(args.dock_image, setup["Version"])
except InvalidTag as e:
print("\n".join(e.args), file=sys.stderr)
sys.exit(1)

details = get_registered()
command = Path(shutil.which(entrypoint_of(dist)))
plugin_name = args.name if args.name is not None else image.name
public_repo = (
args.public_repo
if args.public_repo is not None
else f"https://github.com/{image.repo}"
)

info = {
"name": plugin_name,
"dock_image": args.dock_image,
"public_repo": public_repo,
"type": details.type,
"parameters": serialize(details.parser),
"icon": details.icon,
Expand Down
46 changes: 46 additions & 0 deletions src/chris_plugin/tool/image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import sys


class InvalidTag(Exception):
pass


class ImageTag:
def __init__(self, tag: str, version: str, warnings=True):
if "@" in tag:
raise InvalidTag("Digest tags are not currently supported.")
if len(split_on_colon := tag.split(":", maxsplit=1)) == 2:
before_colon, after_colon = split_on_colon
else:
before_colon = tag
after_colon = ""

if warnings and version not in after_colon:
_warn(
f"You should specify the image version in the tag, e.g. {before_colon}:{version}"
)

parts = before_colon.split("/")
if len(parts) == 2:
if warnings:
_warn(f"You should specify the registry, e.g. docker.io/{tag}")
registry = ""
user, name = parts
elif len(parts) == 3:
registry, user, name = parts
else:
raise InvalidTag(
f"{tag} is not a valid OCI image tag: must be in the form <registry>/<repo>/<name>:<version>"
)

self.full_name = tag
self.registry = registry
self.user = user
self.name = name
self.repo = f"{user}/{name}"
self.tag = after_colon


def _warn(msg: str):
print("\033[1;33mWARNING\033[22;39m", end=": ", file=sys.stderr)
print(msg, file=sys.stderr)

0 comments on commit bd253d3

Please sign in to comment.