Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
add bandit (#33)
Browse files Browse the repository at this point in the history
L
  • Loading branch information
bdwyer2 committed Jun 1, 2020
1 parent eef6475 commit 97b82ea
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 39 deletions.
2 changes: 2 additions & 0 deletions .bandit
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[bandit]
exclude: /maxfw/tests/
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ matrix:
dist: xenial # required for Python >= 3.7 (travis-ci/travis-ci#9069)
install:
# - pip install -r requirements.txt
- pip install flake8
- pip install -r requirements-test.txt
before_script:
- flake8 . --max-line-length=127
- bandit -r .
script:
- python setup.py test # add other tests here
notifications:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Python package that contains common code shared across all MAX models.

## Dependencies
* [flask-restplus](https://pypi.org/project/flask-restplus/0.11.0/)
* [flask-restx](https://pypi.org/project/flask-restx/0.1.1/)
* [flask-cors](https://pypi.org/project/Flask-Cors/)

## Installation
Expand Down
2 changes: 1 addition & 1 deletion maxfw/core/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# limitations under the License.
#
from .app import MAX_API
from flask_restplus import Resource, fields
from flask_restx import Resource, fields

METADATA_SCHEMA = MAX_API.model('ModelMetadata', {
'id': fields.String(required=True, description='Model identifier'),
Expand Down
4 changes: 2 additions & 2 deletions maxfw/core/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#
import os
from flask import Flask
from flask_restplus import Api, Namespace
from flask_restx import Api, Namespace
from flask_cors import CORS
from .default_config import API_TITLE, API_DESC, API_VERSION

Expand Down Expand Up @@ -54,5 +54,5 @@ def mount_static(self, route):
def index():
return self.app.send_static_file('index.html')

def run(self, host='0.0.0.0'):
def run(self, host='0.0.0.0'): # nosec - binding to all interfaces
self.app.run(host)
10 changes: 5 additions & 5 deletions maxfw/tests/test_image_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def test_imageprocessor_standardize():
# Test standardize (RGBA)
# The `A` channel cannot be standardized, and will therefore prompt an error message when attempted.
transform_sequence = [ToPILImage('RGBA'), Standardize()]
with nose.tools.assert_raises_regexp(AssertionError, r".*must be converted to an image with 3 or fewer channels.*"):
with nose.tools.assert_raises_regexp(ValueError, r".*must be converted to an image with 3 or fewer channels*"):
ImageProcessor(transform_sequence).apply_transforms(test_input)

# Test standardize (RGB)
Expand Down Expand Up @@ -201,12 +201,12 @@ def test_imageprocessor_standardize():

# Test standardize error (RGB)
transform_sequence = [ToPILImage('RGB'), Standardize(mean=[127, 127], std=5)]
with nose.tools.assert_raises_regexp(AssertionError, r".*must correspond to the number of channels.*"):
with nose.tools.assert_raises_regexp(ValueError, r".*must correspond to the number of channels.*"):
ImageProcessor(transform_sequence).apply_transforms(test_input)

# Test standardize error (RGB)
transform_sequence = [ToPILImage('RGB'), Standardize(std=[5, 5, 5, 5])]
with nose.tools.assert_raises_regexp(AssertionError, r".*must correspond to the number of channels.*"):
with nose.tools.assert_raises_regexp(ValueError, r".*must correspond to the number of channels.*"):
ImageProcessor(transform_sequence).apply_transforms(test_input)

# Test standardize (L)
Expand Down Expand Up @@ -245,12 +245,12 @@ def test_imageprocessor_standardize():

# Test standardize error (L)
transform_sequence = [ToPILImage('L'), Standardize(mean=[127, 127], std=5)]
with nose.tools.assert_raises(AssertionError):
with nose.tools.assert_raises(ValueError):
ImageProcessor(transform_sequence).apply_transforms(test_input)

# Test standardize error (L)
transform_sequence = [ToPILImage('L'), Standardize(std=[5, 5, 5, 5])]
with nose.tools.assert_raises(AssertionError):
with nose.tools.assert_raises(ValueError):
ImageProcessor(transform_sequence).apply_transforms(test_input)

# Test for wrong use (L)
Expand Down
46 changes: 27 additions & 19 deletions maxfw/utils/image_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,15 @@ def to_pil_image(pic, target_mode, mode=None):
raise TypeError('Input type {} is not supported'.format(npimg.dtype))

# Verify that the target mode exists
assert target_mode in [1, 'L', 'P', 'RGB', 'RGBA', 'CMYK', 'YCbCr', 'LAB', 'HSV', 'I', 'F', 'RGBX', 'RGBBa']
if target_mode not in [1, 'L', 'P', 'RGB', 'RGBA', 'CMYK', 'YCbCr', 'LAB', 'HSV', 'I', 'F', 'RGBX', 'RGBBa']:
raise ValueError("invalid target_mode: %r" % target_mode)

return Image.fromarray(npimg, mode=mode).convert(target_mode)


def pil_to_array(pic):
assert _is_pil_image(pic), 'The input image for `PILtoarray` is not a PIL Image object.'
if not _is_pil_image(pic):
raise TypeError('The input image for `PILtoarray` is not a PIL Image object.')
return np.array(pic)


Expand All @@ -143,9 +145,10 @@ def standardize(img, mean=None, std=None):
# (this image has channels)
# calculate the number of channels
channels = img.shape[-1]
assert channels < 4, 'An image with more than 3 channels, ' \
'e.g. `RGBA`, must be converted to an image with 3 or fewer channels (e.g. `RGB` or `L`)' \
'before it can be standardized correctly.'
if channels >= 4:
raise ValueError('An image with more than 3 channels,'
'e.g. `RGBA`, must be converted to an image with 3 or fewer channels (e.g. `RGB` or `L`)'
'before it can be standardized correctly.')

if mean is None:
# calculate channel-wise mean
Expand All @@ -155,10 +158,10 @@ def standardize(img, mean=None, std=None):
mean = np.array([mean] * channels).reshape((1, 1, channels))
elif isinstance(mean, Sequence):
# convert a sequence to the right dimensions
assert np.sum([not isinstance(x, (int, float)) for x in mean]) == 0, \
'The sequence `mean` can only contain numbers.'
assert len(mean) == channels, \
'The size of the `mean` array must correspond to the number of channels in the image.'
if any(not isinstance(x, (int, float)) for x in mean):
raise ValueError('The sequence `mean` can only contain numbers.')
if len(mean) != channels:
raise ValueError('The size of the `mean` array must correspond to the number of channels in the image.')
mean = np.array(mean).reshape((1, 1, channels))
else:
# if the mean is not a number or a sequence
Expand All @@ -173,10 +176,10 @@ def standardize(img, mean=None, std=None):
std = np.array([std] * channels).reshape((channels,))
elif isinstance(std, Sequence):
# convert a sequence to the right dimensions
assert np.sum([not isinstance(x, (int, float)) for x in std]) == 0, \
'The sequence `std` can only contain numbers.'
assert len(std) == channels, \
'The size of the `std` array must correspond to the number of channels in the image.'
if any(not isinstance(x, (int, float)) for x in std):
raise ValueError('The sequence `std` can only contain numbers.')
if len(std) != channels:
raise ValueError('The size of the `std` array must correspond to the number of channels in the image.')
std = np.array(std).reshape((channels,))
else:
# if the std is not a number or a sequence
Expand All @@ -199,7 +202,8 @@ def standardize(img, mean=None, std=None):
if mean is None:
mean = np.mean(img)
elif isinstance(mean, Sequence):
assert len(mean) == 1
if len(mean) != 1:
raise ValueError("len(mean) is not 1")
mean = mean[0]
elif not isinstance(mean, (int, float)):
raise ValueError('The value for `mean` should be a number or `None` '
Expand All @@ -208,7 +212,8 @@ def standardize(img, mean=None, std=None):
if std is None:
std = np.std(img)
elif isinstance(std, Sequence):
assert len(std) == 1
if len(std) != 1:
raise ValueError("len(std) is not 1")
std = std[0]
elif not isinstance(std, (int, float)):
raise ValueError('The value for `std` should be a number or `None` '
Expand All @@ -227,7 +232,7 @@ def resize(img, size, interpolation=Image.BILINEAR):
img (PIL Image): Image to be resized.
size (sequence or int): Desired output size. If size is a sequence like
(h, w), the output size will be matched to this. If size is an int,
the smaller edge of the image will be matched to this number maintaing
the smaller edge of the image will be matched to this number maintaining
the aspect ratio. i.e, if height > width, then image will be rescaled to
:math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)`
interpolation (int, optional): Desired interpolation. Default is
Expand Down Expand Up @@ -301,7 +306,8 @@ def resized_crop(img, i, j, h, w, size, interpolation=Image.BILINEAR):
Returns:
PIL Image: Cropped image.
"""
assert _is_pil_image(img), 'img should be PIL Image'
if not _is_pil_image(img):
raise TypeError('img should be PIL Image')
img = crop(img, i, j, h, w)
img = resize(img, size, interpolation)
return img
Expand All @@ -314,7 +320,7 @@ def hflip(img):
img (PIL Image): Image to be flipped.
Returns:
PIL Image: Horizontall flipped image.
PIL Image: Horizontally flipped image.
"""
if not _is_pil_image(img):
raise TypeError('img should be PIL Image. Got {}'.format(type(img)))
Expand Down Expand Up @@ -501,7 +507,8 @@ def rotate(img, angle, resample=False, expand=False, center=None):
.. _filters: https://pillow.readthedocs.io/en/latest/handbook/concepts.html#filters
"""
assert isinstance(angle, (int, float)), "The angle must be either a float or int."
if not isinstance(angle, (int, float)):
raise ValueError("The angle must be either a float or int.")

if not _is_pil_image(img):
raise TypeError('img should be PIL Image. Got {}'.format(type(img)))
Expand All @@ -514,6 +521,7 @@ def to_grayscale(img, num_output_channels=1):
Args:
img (PIL Image): Image to be converted to grayscale.
num_output_channels (Int): Number of output channels.
Returns:
PIL Image: Grayscale version of the image.
Expand Down
13 changes: 6 additions & 7 deletions maxfw/utils/image_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class ImageProcessor(object):
"""

def __init__(self, transforms=[]):
assert isinstance(transforms, Sequence)
assert isinstance(transforms, Sequence) # nosec - assert
self.transforms = transforms

def apply_transforms(self, img):
Expand All @@ -59,9 +59,9 @@ def apply_transforms(self, img):
"""
# verify whether the Normalize or Standardize transformations are positioned at the end
encoding = [(isinstance(t, Normalize) or isinstance(t, Standardize)) for t in self.transforms]
assert sum(encoding[:-1]) == 0, \
'A Standardize or Normalize transformation must be positioned at the end of the pipeline.'

if sum(encoding[:-1]) != 0:
raise ValueError('A Standardize or Normalize transformation can only be positioned at the end of the'
'pipeline.')
# apply the transformations
for t in self.transforms:
img = t(img)
Expand Down Expand Up @@ -103,7 +103,7 @@ def __call__(self, pic):

class PILtoarray(object):
"""
onvert a PIL Image object to a numpy ndarray.
Convert a PIL Image object to a numpy ndarray.
"""

def __call__(self, pic):
Expand All @@ -113,7 +113,6 @@ def __call__(self, pic):
Returns:
numpy ndarray
"""
return F.pil_to_array(pic)

Expand Down Expand Up @@ -175,7 +174,7 @@ class Resize(object):
"""

def __init__(self, size, interpolation=Image.BILINEAR):
assert isinstance(size, int) or (isinstance(size, Sequence) and len(size) == 2)
assert isinstance(size, int) or (isinstance(size, Sequence) and len(size) == 2) # nosec - assert
self.size = size
self.interpolation = interpolation

Expand Down
2 changes: 2 additions & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
flake8
bandit
7 changes: 4 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@
packages=['maxfw', 'maxfw.core', 'maxfw.model', 'maxfw.utils'],
zip_safe=True,
install_requires=[
'flask-restplus==0.11.0',
'flask-cors',
'Pillow',
'flask-restx==0.1.1',
'flask-cors==3.0.7',
'Pillow==7.0.0',
'numpy==1.18.4',
],
test_suite='nose.collector',
tests_require=['nose']
Expand Down

0 comments on commit 97b82ea

Please sign in to comment.