diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f1781a74..bc78a2ae 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,7 +35,7 @@ jobs: python -m pip install -e .[dev,torch,statsmodels,xgboost] - name: Run Tests run: | - pytest -m 'not rsc_test' --cov --cov-report xml + pytest -m 'not rsc_test and not docker' --cov --cov-report xml - name: Upload coverage uses: codecov/codecov-action@v2 @@ -80,13 +80,16 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -e ".[dev]" - - name: run Docker + - name: Run Docker run: | python script/setup-docker/docker.py docker build -t mock . docker run -d -v $PWD/pinsboard:/vetiver/pinsboard -p 8080:8080 mock sleep 5 curl -s --retry 10 --retry-connrefused http://0.0.0.0:8080 + - name: Run tests + run: | + pytest vetiver -m 'docker' test-no-extras: name: "Test no exra ml frameworks" diff --git a/Makefile b/Makefile index 5fe52656..89950f5a 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ lint: flake8 vetiver test: clean-test - pytest -m 'not rsc_test' + pytest -m 'not rsc_test and not docker' test-rsc: clean-test pytest diff --git a/pyproject.toml b/pyproject.toml index 1bd94acb..11d3da9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ addopts = "--doctest-modules" doctest_optionflags = "NORMALIZE_WHITESPACE" markers = [ "rsc_test: tests for rstudio connect", + "docker: tests for docker deployments" ] [tool.setuptools_scm] diff --git a/script/setup-docker/docker.py b/script/setup-docker/docker.py index b612a0fb..50ba36ae 100644 --- a/script/setup-docker/docker.py +++ b/script/setup-docker/docker.py @@ -1,5 +1,8 @@ import vetiver import pins +import numpy as np + +np.random.seed(500) X, y = vetiver.get_mock_data() model = vetiver.get_mock_model().fit(X, y) @@ -9,6 +12,5 @@ v = vetiver.VetiverModel(model, "mymodel", ptype_data=X) vetiver.vetiver_pin_write(board, v) -vetiver.load_pkgs(v, path="vetiver_") -vetiver.write_app(board, "mymodel") -vetiver.write_docker() + +vetiver.prepare_docker(board, "mymodel") diff --git a/vetiver/__init__.py b/vetiver/__init__.py index 899bdb5a..dcd1d597 100644 --- a/vetiver/__init__.py +++ b/vetiver/__init__.py @@ -9,7 +9,7 @@ from .pin_read_write import vetiver_pin_write # noqa from .attach_pkgs import * # noqa from .meta import * # noqa -from .write_docker import write_docker # noqa +from .write_docker import write_docker, prepare_docker # noqa from .write_fastapi import write_app, vetiver_write_app # noqa from .handlers.base import BaseHandler, create_handler, InvalidModelError # noqa from .handlers.sklearn import SKLearnHandler # noqa diff --git a/vetiver/tests/test_prepare_docker.py b/vetiver/tests/test_prepare_docker.py new file mode 100644 index 00000000..f9c4bc14 --- /dev/null +++ b/vetiver/tests/test_prepare_docker.py @@ -0,0 +1,19 @@ +import pytest +import vetiver +import pandas as pd +import numpy as np + +DOCKER_URL = "http://0.0.0.0:8080/predict" + +pytestmark = pytest.mark.docker # noqa + + +def test_predict_sklearn_df_check_ptype(): + np.random.seed(500) + + X, y = vetiver.mock.get_mock_data() + response = vetiver.predict(endpoint=DOCKER_URL, data=X) + + assert isinstance(response, pd.DataFrame), response + assert response.iloc[0, 0] == 44.47 + assert len(response) == 100 diff --git a/vetiver/write_docker.py b/vetiver/write_docker.py index d35752ec..9e2743d9 100644 --- a/vetiver/write_docker.py +++ b/vetiver/write_docker.py @@ -1,5 +1,10 @@ import sys import warnings +from pathlib import Path + +from .write_fastapi import write_app +from .attach_pkgs import load_pkgs +from .vetiver_model import VetiverModel def vetiver_write_docker( @@ -88,5 +93,43 @@ def write_docker( CMD ["uvicorn", "app.app:api", "--host", "{host}", "--port", "{port}"] """ - f = open(f"{path}Dockerfile", "x") + f = open(Path(path, "Dockerfile"), "x") f.write(docker_script) + + +def prepare_docker( + board, + pin_name: str, + path: str = "./", + version=None, + rspm_env: bool = False, + host: str = "0.0.0.0", + port: str = "8080", +): + """Create all files needed for Docker + + Parameters + ---------- + board : + Pin board for model + pin_name : str + Name of pin + path : + Path to output + version : + Pin version to be used + rspm_env: bool + Whether or not RStudio Package Manager should be used + host: str + Host address to run VetiverAPI from Dockerfile + port: str + Port to run VetiverAPI from Dockerfile + + """ + + v = VetiverModel.from_pin(board=board, name=pin_name, version=version) + write_app( + board=board, pin_name=pin_name, version=version, file=Path(path, "app.py") + ) + load_pkgs(v, path=Path(path, "vetiver_")) + write_docker(path=path, rspm_env=rspm_env, host=host, port=port)