Skip to content
Permalink
Browse files

Remove opencv-python module from test dependency (#389)

* remove opencv-python dependency

* get rid of test image file in favor of imageio generated one

* test cleanups

* fix test in py2
  • Loading branch information
parano committed Nov 20, 2019
1 parent fb503a0 commit 484d3669ebcacd00e1ca3e420dad55974242562b
@@ -21,6 +21,7 @@
import base64
from io import BytesIO

from six import iteritems
from werkzeug.utils import secure_filename
from flask import Response

@@ -135,7 +136,7 @@ def handle_request(self, request, func):
if len(self.input_names) == 1 and len(request.files) == 1:
# Ignore multipart form input name when ImageHandler is intended to accept
# only one image file at a time
input_files = request.files.values()
input_files = [file for _, file in iteritems(request.files)]
else:
input_files = [
request.files.get(form_input_name)
@@ -3,7 +3,7 @@
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=cv2
extension-pkg-whitelist=

# Add files or directories to the blacklist. They should be base names, not
# paths.
@@ -48,7 +48,6 @@
]

imageio = ["imageio>=2.5.0"]
cv2 = ["opencv-python"]
pytorch = ["torch", "torchvision"]
fastai = ["fastai", "matplotlib"]
tensorflow = ["tensorflow"]
@@ -70,7 +69,6 @@
"moto",
]
+ imageio
+ cv2
+ fastai
)

@@ -1,8 +1,8 @@
import os
import tempfile
import json
from click.testing import CliRunner

from six import PY3
from bentoml.cli import create_bento_service_cli


@@ -14,7 +14,7 @@ def generate_test_input_file():
file_path = os.path.join(tempdir, random_id + ".json")

with open(file_path, "w") as f:
f.write('[{"age": 1}, {"age": 2}]')
f.write('[{"col1": 1}, {"col1": 2}]')
return file_path


@@ -25,9 +25,12 @@ def test_run_command_with_input_file(bento_bundle_path):
cli = create_bento_service_cli()
run_cmd = cli.commands["<API_NAME>"]
result = runner.invoke(
run_cmd, ["predict", bento_bundle_path, "--input", input_path, "-o", "json"]
run_cmd,
["predict_dataframe", bento_bundle_path, "--input", input_path, "-o", "json"],
)

assert result.exit_code == 0
result_json = json.loads(result.output)
assert result_json[0]["age"] == 6
if PY3:
assert result.output.strip() == '"3"'
else:
assert result.output.decode().strip() == "3"
@@ -14,23 +14,14 @@


class TestModel(object):
def predict(self, df):
df["age"] = df["age"].add(5)
return df
def predict_dataframe(self, df):
return df["col1"].sum()

def predictImage(self, input_data):
def predict_image(self, input_data):
assert input_data is not None
return [10, 24]
return input_data.shape

def predictJson(self, input_data):
assert input_data is not None
return {"ok": True}

def predictTF(self, input_data):
assert input_data is not None
return {"ok": True}

def predictTorch(self, input_data):
def predict_json(self, input_data):
assert input_data is not None
return {"ok": True}

@@ -41,32 +32,32 @@ class TestBentoService(bentoml.BentoService):
"""My RestServiceTestModel packaging with BentoML
"""

@bentoml.api(DataframeHandler, input_dtypes={"age": "int"})
def predict(self, df):
"""predict expects dataframe as input
@bentoml.api(DataframeHandler, input_dtypes={"col1": "int"})
def predict_dataframe(self, df):
"""predict_dataframe expects dataframe as input
"""
return self.artifacts.model.predict(df)
return self.artifacts.model.predict_dataframe(df)

@bentoml.api(ImageHandler)
def predictImage(self, input_data):
return self.artifacts.model.predictImage(input_data)
def predict_image(self, image):
return self.artifacts.model.predict_image(image)

@bentoml.api(ImageHandler, input_names=('original', 'compared'))
def predictImages(self, original, compared):
def predict_images(self, original, compared):
return original[0, 0] == compared[0, 0]

@bentoml.api(JsonHandler)
def predictJson(self, input_data):
return self.artifacts.model.predictJson(input_data)
def predict_json(self, input_data):
return self.artifacts.model.predict_json(input_data)

if six.PY3:

@bentoml.api(FastaiImageHandler)
def predictFastaiImage(self, input_data):
return self.artifacts.model.predictImage(input_data)
def predict_fastai_image(self, input_data):
return self.artifacts.model.predict_image(input_data)

@bentoml.api(FastaiImageHandler, input_names=('original', 'compared'))
def predictFastaiImages(self, original, compared):
def predict_fastai_images(self, original, compared):
return all(original.data[0, 0] == compared.data[0, 0])


@@ -17,11 +17,11 @@ def predict(self, image):

ms = ImageHandlerModelForFastai()

import cv2
import imageio
import numpy as np

img_file = tmpdir.join("img.png")
cv2.imwrite(str(img_file), np.zeros((10, 10)))
imageio.imwrite(str(img_file), np.zeros((10, 10)))
api = ms.get_service_apis()[0]
test_args = ["--input={}".format(img_file)]
api.handle_cli(test_args)
@@ -3,13 +3,16 @@
import json
from io import BytesIO


from six import PY3
from bentoml.server import BentoAPIServer

CUR_PATH = os.path.dirname(os.path.abspath(__file__))


def test_api_function_route(bento_service):
def test_api_function_route(bento_service, tmpdir):
import imageio
import numpy as np

rest_server = BentoAPIServer(bento_service)
test_client = rest_server.app.test_client()

@@ -26,25 +29,31 @@ def test_api_function_route(bento_service):
response = test_client.get("/docs.json")
assert 200 == response.status_code

assert "predict" in index_list
data = [{"age": 10}]

assert "predict_dataframe" in index_list
data = [{"col1": 10}, {"col1": 20}]
response = test_client.post(
"/predict", data=json.dumps(data), content_type="application/json"
"/predict_dataframe", data=json.dumps(data), content_type="application/json"
)

response_data = json.loads(response.data)
assert 15 == response_data[0]["age"]
if PY3:
assert response.data.decode().strip() == '"30"'
else:
assert response.data.decode().strip() == "30"

# Test Image handlers.
with open(os.path.join(CUR_PATH, "white-plane-sky.jpg"), "rb") as f:
img_file = tmpdir.join("test_img.png")
imageio.imwrite(str(img_file), np.zeros((10, 10)))

with open(str(img_file), "rb") as f:
img = f.read()

response = test_client.post("/predictImage", data=img, content_type="image/png")
response = test_client.post(
"/predict_image", data={'image': (BytesIO(img), 'test_img.png')}
)
assert 200 == response.status_code
assert "[10, 10, 3]" in str(response.data)

response = test_client.post(
"/predictImages",
"/predict_images",
data={
'original': (BytesIO(img), 'original.jpg'),
'compared': (BytesIO(img), 'compared.jpg'),
@@ -56,12 +65,12 @@ def test_api_function_route(bento_service):
if sys.version_info >= (3, 6):
# fast ai is required 3.6 or higher.
response = test_client.post(
"/predictFastaiImage", data=img, content_type="image/png"
"/predict_fastai_image", data=img, content_type="image/png"
)
assert 200 == response.status_code

response = test_client.post(
"/predictFastaiImages",
"/predict_fastai_images",
data={
'original': (BytesIO(img), 'original.jpg'),
'compared': (BytesIO(img), 'compared.jpg'),
Binary file not shown.
@@ -21,8 +21,8 @@ def test_pip_install_saved_bentoservice_bundle(bento_bundle_path, tmpdir):
sys.path.remove(install_path)

svc = TestBentoService.load()
df = svc.predict(pd.DataFrame(pd.DataFrame([1], columns=["age"])))
assert df["age"].values[0] == 6
res = svc.predict_dataframe(pd.DataFrame(pd.DataFrame([1], columns=["col1"])))
assert res == 1

# pip install should place cli entry script under target/bin directory
cli_bin_path = os.path.join(install_path, "bin/TestBentoService")
@@ -38,7 +38,7 @@ def test_pip_install_saved_bentoservice_bundle(bento_bundle_path, tmpdir):
output = json.loads(output)
assert output["name"] == "TestBentoService"
assert output["version"] == svc.version
assert "predict" in map(lambda x: x["name"], output["apis"])
assert "predict_dataframe" in map(lambda x: x["name"], output["apis"])

output = subprocess.check_output(
[cli_bin_path, "--quiet", "open-api-spec"], env=env
@@ -5,7 +5,6 @@ envlist = py27,py36,py37
deps =
pytest
mock
opencv-python
docker
pip
imageio

0 comments on commit 484d366

Please sign in to comment.
You can’t perform that action at this time.