Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update dependencies / fix tests #280

Merged
merged 13 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ Notes:

### Run the tests

We're using `pytest` for the tests. You can type `pytest`, or use
this `Makefile` command:
This project has _a lot_ of dependencies. To run the tests, I'm using Docker:

```bash
❯ make test
Expand Down
30 changes: 30 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
FROM ubuntu
WORKDIR /usr/src/app

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y build-essential && \
apt-get install -y git ninja-build ccache libopenblas-dev libopencv-dev cmake && \
apt-get install -y gcc mono-mcs g++ && \
apt-get install -y python3 python3-pip && \
apt-get install -y default-jdk && \
rm -rf /var/lib/apt/lists/*

RUN pip3 install --upgrade pip setuptools

# Install & install requirements
ADD requirements-dev0.txt ./requirements-dev0.txt
RUN pip3 install -r requirements-dev0.txt

ADD requirements-dev1.txt ./requirements-dev1.txt
RUN pip3 install -r requirements-dev1.txt

ADD requirements.txt ./requirements.txt
RUN pip3 install -r requirements.txt

# Copy library source
COPY modelstore ./modelstore
COPY tests ./tests

# Run tests
ENTRYPOINT ["python3", "-m", "pytest", "--exitfirst", "./tests"]
14 changes: 11 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
VIRTUALENV_NAME=$(shell pwd | rev | cut -d '/' -f 1 | rev)-dev

.PHONY: library test setup install uninstall release-test release-prod clean update

.PHONY: uninstall
uninstall:
@./bin/_pyenv_uninstall $(VIRTUALENV_NAME)

.PHONY: setup
setup:
@./bin/_brew_install

.PHONY: install
install: uninstall
@./bin/_pyenv_install $(VIRTUALENV_NAME)

.PHONY: update
update:
@./bin/_pyenv_update

.PHONY: build
build : test
@./bin/_build_library

.PHONY: test
test:
@python -m pytest tests/
@docker build . -t modelstore-dev
@docker run -it --rm modelstore-dev

.PHONY: release-test
release-test: build
@./bin/_release_test

.PHONY: release-prod
release-prod:
@./bin/_release_prod

.PHONY: cleanup
clean:
@./bin/_cleanup
6 changes: 3 additions & 3 deletions bin/_cleanup
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/bin/bash
echo "\n 🧼 Removing pycache files"
echo -e "\n 🧼 Removing pycache files"
find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf

echo "\n 🧼 Removing build directories"
echo -e "\n 🧼 Removing build directories"
rm -rf *.egg-info
rm -rf build
rm -rf dist

echo "\n 🎉 Done."
echo -e "\n 🎉 Done."
7 changes: 5 additions & 2 deletions bin/_pyenv_config
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#!/bin/bash
# export PYTHON_VERSION=3.7.15
# export PYTHON_VERSION=3.8.12
export PYTHON_VERSION=3.9.16
export PYTHON_VERSION=3.8.12
# export PYTHON_VERSION=3.9.16

export VIRTUALENV_NAME="$1-${PYTHON_VERSION//./-}"
export REPO_ROOT=$(cd $(dirname $0)/.. && pwd)

echo -e "\n 💬 Using a venv called: ${VIRTUALENV_NAME}"

eval "$(pyenv init --path)"
eval "$(pyenv virtualenv-init -)"
2 changes: 2 additions & 0 deletions bin/_pyenv_install
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ env PYTHON_CONFIGURE_OPTS="--enable-framework CC=clang" \
echo -e "\n 💬 Setting local: $VIRTUALENV_NAME"
pyenv local $VIRTUALENV_NAME

echo -e "\n 💬 Upgrading pip"
pip install --upgrade pip setuptools wheel

for i in ./requirements*txt; do
echo -e "\n\n 💬 Installing requirements in: $i"
pip install -r $i
Expand Down
13 changes: 13 additions & 0 deletions modelstore/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Copyright 2024 Neal Lathia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from pkg_resources import DistributionNotFound, get_distribution

# pylint: disable=unused-import
Expand Down
8 changes: 5 additions & 3 deletions modelstore/models/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ def get_manager(name: str, storage: CloudStorage = None) -> ModelManager:
manager = TensorflowManager(storage)
else:
manager = _LIBRARIES[name](storage)
if all(module_exists(x) for x in manager.required_dependencies()):
return manager
raise ValueError(f"could not create manager for {name}: dependencies not installed")
for x in manager.required_dependencies():
if not module_exists(x):
raise ValueError(f"could not create manager for {name}: {x} not installed")
return manager

11 changes: 10 additions & 1 deletion modelstore/utils/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import logging
import sys


def get_logger():
"""Builds the modelstore logger"""
log = logging.getLogger(name="modelstore")
Expand All @@ -27,3 +26,13 @@ def get_logger():


logger = get_logger()


def debug_mode(on: bool):
global logger
logger = get_logger()
if not on:
return
logger.setLevel(logging.DEBUG)
for handler in logger.handlers:
handler.setLevel(logging.DEBUG)
11 changes: 7 additions & 4 deletions requirements-dev0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ rope>=1.6.0
twine>=4.0.2

# Data / dependencies for ML libraries
numpy==1.23.5 # numba 0.58.0 requires numpy<1.26,>=1.21; numpy>1.23.5 currently breaks mxnet
numba>=0.55.1
Cython>=0.29.28
python-Levenshtein>=0.12.2
numba>=0.58.1
numpy==1.23.5 # numpy>1.23.5 currently breaks mxnet
Cython>=3.0.8
python-Levenshtein>=0.24.0
pandas>=1.3.5; python_version < '3.8'
pandas>=1.4.1; python_version > '3.7'

# ML Dependencies
# pydoop<=2.0.0; sys_platform == 'darwin'
54 changes: 26 additions & 28 deletions requirements-dev1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,31 @@
protobuf>=3.19.5 # https://github.com/protocolbuffers/protobuf/issues/10051

# Storage
azure-core>=1.23.1
azure-storage-blob>=12.11.0
boto3>=1.21.41
google-cloud-storage>=2.3.0
minio>=7.1.12
# pydoop<=2.0.0; sys_platform == 'darwin'
pystan>=2.19.1.1 # required to be installed before prophet
azure-core
azure-storage-blob
boto3
google-cloud-storage
minio

# Machine Learning
annoy>=1.17.0
catboost>=1.0.5
fastai>=2.5.6 # Note: 1.0.61 has different import paths!
gensim>=4.1.2
Keras-Preprocessing>=1.1.2
lightgbm>=3.3.2
mxnet>=1.8.0.post0
onnx>=1.14.1
onnxruntime>=1.11.0,<1.16.0 # https://github.com/microsoft/onnxruntime/issues/17631
prophet>=1.0.1
pyspark>=3.3.1
pytorch-lightning>=1.6.1
scikit-learn>=1.0.2
shap>=0.43.0
skl2onnx>=1.11.1
skorch>=0.11.0
tensorflow>=2.9.3
torch>=1.13.1
torchvision>=0.12.0
transformers>=4.18.0
xgboost>=1.5.2
annoy
catboost
fastai # Note: 1.0.61 has different import paths!
gensim
Keras-Preprocessing
lightgbm
mxnet # Note: retired as of 09/2023 https://attic.apache.org/projects/mxnet.html
onnx
onnxruntime
prophet
pyspark
pytorch-lightning
scikit-learn
shap
skl2onnx
skorch
tensorflow
torch
torchvision
transformers
xgboost
2 changes: 2 additions & 0 deletions tests/metadata/code/test_revision.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import subprocess

import git
Expand All @@ -22,6 +23,7 @@
# pylint: disable=missing-function-docstring


@pytest.mark.skipif(sys.platform!="darwin", reason="skipping in ubuntu")
def test_repo_name():
# pylint: disable=protected-access
repo = git.Repo(search_parent_directories=True)
Expand Down
2 changes: 2 additions & 0 deletions tests/models/test_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ def test_get_keras_manager():
def test_get_manager():
# pylint: disable=protected-access
for name, manager_type in managers._LIBRARIES.items():
if name == "mxnet":
continue
manager = managers.get_manager(name)
assert isinstance(manager, manager_type)

Expand Down
21 changes: 16 additions & 5 deletions tests/models/test_mxnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
# limitations under the License.
import os
import warnings

import mxnet as mx
import numpy as np
import pytest
from mxnet.gluon import nn

try:
import mxnet as mx
from mxnet.gluon import nn
except:
pass

from modelstore.metadata import metadata
from modelstore.models import mxnet
Expand Down Expand Up @@ -48,36 +51,43 @@ def mxnet_manager():
return mxnet.MxnetManager()


@pytest.mark.skip(reason="mxnet project retired")
def test_model_info(mxnet_manager, mxnet_model):
exp = metadata.ModelType("mxnet", "HybridSequential", None)
res = mxnet_manager.model_info(model=mxnet_model)
assert exp == res


@pytest.mark.skip(reason="mxnet project retired")
def test_model_data(mxnet_manager, mxnet_model):
res = mxnet_manager.model_data(model=mxnet_model)
assert res is None


@pytest.mark.skip(reason="mxnet project retired")
def test_required_kwargs(mxnet_manager):
assert mxnet_manager._required_kwargs() == ["model", "epoch"]


@pytest.mark.skip(reason="mxnet project retired")
def test_matches_with(mxnet_manager, mxnet_model):
assert mxnet_manager.matches_with(model=mxnet_model)
assert not mxnet_manager.matches_with(model="a-string-value")
assert not mxnet_manager.matches_with(wrong_kwarg_keyword=mxnet_model)


@pytest.mark.skip(reason="mxnet project retired")
def test_get_functions(mxnet_manager, mxnet_model):
assert len(mxnet_manager._get_functions(model=mxnet_model, epoch=3)) == 1


@pytest.mark.skip(reason="mxnet project retired")
def test_get_params(mxnet_manager, mxnet_model):
res = mxnet_manager.get_params(model=mxnet_model, epoch=3)
assert {"epoch": 3} == res


@pytest.mark.skip(reason="mxnet project retired")
def test_save_model(tmp_path, mxnet_model):
x = random_x()
y_pred = mxnet_model(x).asnumpy()
Expand All @@ -97,6 +107,7 @@ def test_save_model(tmp_path, mxnet_model):
assert np.allclose(y_pred, y_loaded_pred)


@pytest.mark.skip(reason="mxnet project retired")
def test_load_model(tmp_path, mxnet_manager, mxnet_model):
# Get the current predictions
x = random_x()
Expand All @@ -110,8 +121,8 @@ def test_load_model(tmp_path, mxnet_manager, mxnet_model):
tmp_path,
metadata.Summary(
model=metadata.Model(
domain=None,
model_id=None,
domain="",
model_id="",
model_type=None,
parameters={"epoch": 0},
data={},
Expand Down
8 changes: 4 additions & 4 deletions tests/storage/test_aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import boto3
import pytest
from moto import mock_s3
from moto import mock_aws

from modelstore.metadata import metadata
from modelstore.storage.aws import AWSStorage
Expand All @@ -40,7 +40,7 @@

@pytest.fixture(autouse=True)
def moto_boto():
with mock_s3():
with mock_aws():
conn = boto3.resource("s3")
conn.create_bucket(Bucket=_MOCK_BUCKET_NAME)
yield conn
Expand Down Expand Up @@ -181,7 +181,7 @@ def test_storage_location():
[
(
metadata.Storage(
type=None,
type="",
path=None,
bucket=_MOCK_BUCKET_NAME,
container=None,
Expand All @@ -192,7 +192,7 @@ def test_storage_location():
),
(
metadata.Storage(
type=None,
type="",
path=None,
bucket="a-different-bucket",
container=None,
Expand Down
Loading
Loading