Skip to content

Commit

Permalink
Improved documentation
Browse files Browse the repository at this point in the history
+ Style changes to make Sphinx generate nice looking docs
+ Added information
  • Loading branch information
michaelschwier committed Aug 13, 2018
1 parent c7e7715 commit f7efca8
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 46 deletions.
6 changes: 3 additions & 3 deletions framework/modelhubapi/pythonapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def get_config(self):
- model: Model specifics.
- publication: Publication specifics.
Todo:
TODO
* Put sample config file here.
* Put link to config.json schema when we have it.
"""
Expand Down Expand Up @@ -87,8 +87,8 @@ def predict(self, file_path, numpyToList = False):
Args:
file_path (string): Path to file tp run inference on.
numpyToArray: Indicates if numpy outputs should be converted to
standard python lists.
numpyToList: Indicates if numpy outputs should be converted to
standard python lists.
Returns:
A dictionary with a list of prediction outputs plus some meta
Expand Down
12 changes: 6 additions & 6 deletions framework/modelhubapi/restapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ def get_model_files(self):
The get_model_files HTTP method allows you to download all the model
itself and all its associated files in a single zip folder.
Todo:
TODO
* This returns a error: [Errno 32] Broken pipe when url is typed
into chrome and before hitting enter - chrome sends request earlier,
and this messes up with flask.
into chrome and before hitting enter - chrome sends request earlier,
and this messes up with flask.
* Currently no mechanism for catching errors (except what flask
will catch).
will catch).
"""
try:
model_name = self.api.get_config()["meta"]["name"].lower()
Expand Down Expand Up @@ -166,9 +166,9 @@ def _jsonify(self, content):
api._get_txt_file() function that returns a dict key "error" in case
the file is not found.
Todo:
TODO
* All errors are returned as 400. Would be better to customize the error
code based on the actual error.
code based on the actual error.
"""
response = self._addCORS(jsonify(content))
# response = jsonify(content)
Expand Down
35 changes: 33 additions & 2 deletions framework/modelhublib/imageconverters/imageConverter.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
class ImageConverter(object):
"""
Abstract base class for image converters, following chain of responsibility design pattern.
For each image loader derived from :class:`~modelhublib.imageloaders.imageLoader.ImageLoader`
you should implement a corresponding image converter using this as base class.
Args:
sucessor (ImageConverter): Next converter in chain to attempt loading the image if this one fails.
"""
def __init__(self, successor = None):
self._successor = successor


def setSuccessor(self, successor):
"""
Setting the next converter in chain of responsibility.
Args:
sucessor (ImageConverter): Next converter in chain to attempt loading the image if this one fails.
"""
self._successor = successor


def convert(self, image):
"""
Tries to convert image and on fail forwards convert request to next handler
Tries to convert image to numpy and on fail forwards convert request to next handler
until sucess or final fail.
There should be no need to overwrite this. Overwrite only
:func:`~_convert` to convert the image type you want to support and
let this function as it is to handle the chain of responsibility and errors.
Args:
image: Image object to convert.
Returns:
Numpy array as converted by :func:`~_convert` or a successor converter.
Raises:
IOError if image could not be converted by any converter in the chain.
"""
try:
npArr = self._convert(image)
Expand All @@ -27,9 +51,16 @@ def convert(self, image):

def _convert(self, image):
"""
Returns image converted to Numpy array.
Abstract method. Overwrite to implement image conversion to numpy array
from the image object type you want to support.
When overwriting this, make sure to raise IOError if image cannot
be converted.
Args:
image: Image object to convert.
Returns:
Should return image object converted to numpy array with 4 dimensions [batchsize, z/color, height, width]
"""
raise NotImplementedError("This is a method of an abstract class.")
12 changes: 11 additions & 1 deletion framework/modelhublib/imageconverters/pilToNumpyConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@

class PilToNumpyConverter(ImageConverter):
"""
Converts PIL.Images to Numpy
Converts PIL.Image objects to Numpy
"""

def _convert(self, image):
"""
Args:
image (PIL.Image): Image object to convert.
Returns:
Input image object converted to numpy array with 4 dimensions [batchsize, z/color, height, width]
Raises:
IOError if input is not of type PIL.Image or cannot be converted for other reasons.
"""
if isinstance(image, PIL.Image.Image):
return self.__convertToNumpy(image)
else:
Expand Down
12 changes: 11 additions & 1 deletion framework/modelhublib/imageconverters/sitkToNumpyConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@

class SitkToNumpyConverter(ImageConverter):
"""
Converts SimpltITK images to Numpy
Converts SimpltITK.Image objects to Numpy
"""

def _convert(self, image):
"""
Args:
image (SimpleITK.Image): Image object to convert.
Returns:
Input image object converted to numpy array with 4 dimensions [batchsize, z/color, height, width]
Raises:
IOError if input is not of type SimpleITK.Image or cannot be converted for other reasons.
"""
if isinstance(image, SimpleITK.Image):
return self.__convertToNumpy(image)
else:
Expand Down
55 changes: 49 additions & 6 deletions framework/modelhublib/imageloaders/imageLoader.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,44 @@
class ImageLoader(object):
"""
Abstract base class for image loaders, following chain of responsibility design pattern.
For each image loader you should implement a corresponding image converter using
:class:`~modelhublib.imageconverters.imageConverter.ImageConverter` as base class.
Args:
sucessor (ImageLoader): Next loader in chain to attempt loading the image if this one fails.
"""
def __init__(self, config, successor = None):
self._config = config
self._successor = successor


def setSuccessor(self, successor):
"""
Setting the next loader in chain of responsibility.
Args:
sucessor (ImageLoader): Next loader in chain to attempt loading the image if this one fails.
"""
self._successor = successor


def load(self, input):
"""
Tries to load input and on fail forwards load request to next handler
until sucess or final fail.
until success or final fail.
There should be no need to overwrite this. Overwrite only
:func:`~_load` to load the image type you want to support and
let this function as it is to handle the chain of responsibility and errors.
Args:
input (str): Name of the input file to be loaded.
Returns:
Image object as loaded by :func:`~_load` or a successor load handler.
Raises:
IOError if input could not be loaded by any load handler in the chain.
"""
try:
image = self._load(input)
Expand All @@ -35,20 +59,33 @@ def load(self, input):

def _load(self, input):
"""
Loads and return the image of given input.
Abstract method. Overwrite to implement loading of the input format you want to support.
When overwriting this, make sure to raise IOError if input cannot
be loaded.
Args:
input (str): Name of the input file to be loaded.
Returns:
Should return image object in the native format of the library using to load it.
"""
raise NotImplementedError("This is a method of an abstract class.")


def _checkConfigCompliance(self, image):
"""
Check if image complies with configuration.
Checks if image complies with configuration.
There should be no need to overwrite this. Overwrite only
"_getImageDimensions" to supply the image dims to check against config.
:func:`~_getImageDimensions`
to supply the image dims to check against config.
Args:
image: Image object as loaded by :func:`~_load`
Raises:
IOError if image dimensions do not comply with configuration.
"""
imageDims = self._getImageDimensions(image)
limits = self._config["model"]["io"]["input"]["dim_limits"]
Expand All @@ -61,9 +98,15 @@ def _checkConfigCompliance(self, image):

def _getImageDimensions(self, image):
"""
Returns the dimensions of the loaded image, should be a 3 tuple (z, y, x).
Abstract method. Should return the dimensions of the loaded image, should be a 3 tuple (z, y, x).
Overwrite this in an implementation of this interface. This function
is used by "_checkConfigCompliance".
is used by :func:`~modelhublib.imageloaders.imageLoader.ImageLoader._checkConfigCompliance`.
Args:
image: Image object as loaded by :func:`~modelhublib.imageloaders.imageLoader.ImageLoader._load`
Returns:
Should return image dimensions of the image object.
"""
raise NotImplementedError("This is a method of an abstract class.")
16 changes: 16 additions & 0 deletions framework/modelhublib/imageloaders/pilImageLoader.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,26 @@ class PilImageLoader(ImageLoader):
"""

def _load(self, input):
"""
Loads input using PIL.
Args:
input (str): Name of the input file to be loaded
Returns:
PIL.Image object
"""
return Image.open(input)


def _getImageDimensions(self, image):
"""
Args:
image (PIL.Image): Image as loaded by :func:`_load`
Returns:
Image dimensions from PIL image object
"""
imageDims = [len(image.getbands())]
imageDims.extend(list(image.size)[::-1])
return imageDims
18 changes: 17 additions & 1 deletion framework/modelhublib/imageloaders/sitkImageLoader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,30 @@

class SitkImageLoader(ImageLoader):
"""
Loads image formatd supported by SimpleITK
Loads image formats supported by SimpleITK
"""

def _load(self, input):
"""
Loads input using SimpleITK.
Args:
input (str): Name of the input file to be loaded
Returns:
SimpleITK.Image object
"""
return sitk.ReadImage(input)


def _getImageDimensions(self, image):
"""
Args:
image (SimpleITK.Image): Image as loaded by :func:`_load`
Returns:
Image dimensions from SimpleITK image object
"""
imageDims = list(image.GetSize())
if len(imageDims) == 2:
imageDims.append(1)
Expand Down
13 changes: 12 additions & 1 deletion framework/modelhublib/model.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
class ModelBase(object):
"""
Base class for contributer models. Currently this is merely an interface
Abstract base class for contributer models. Currently this is merely an interface
definition that all contributer implemented models have to follow.
"""

def __init__(self):
pass

def infer(self, input):
"""
Abstract method. Overwrite this method to implement the inference of a model.
Args:
input (str): Input file name.
Returns:
Converted inference results into format as defined in the model configuration.
Usually should return the result of
:func:`\<YourImageProcessor\>.computeOutput<modelhublib.processor.ImageProcessorBase.computeOutput>`
"""
raise NotImplementedError("This is a method of an abstract class.")

0 comments on commit f7efca8

Please sign in to comment.