Skip to content

Commit

Permalink
Create python-package.yml with pytests. Fix code by different python …
Browse files Browse the repository at this point in the history
…versions tests tests
  • Loading branch information
nxexox authored and Deys Timofey committed Sep 22, 2023
1 parent 54e7f09 commit d916042
Show file tree
Hide file tree
Showing 42 changed files with 207 additions and 100 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: PyTests

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:

runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8 mypy pytest
if [ -f requirements-test.txt ]; then pip install -r requirements-test.txt; fi
pip install .[tests]
- name: flake8
run: |
flake8 --count --show-source --statistics mlup tests examples
# - name: mypy
# run: |
# - mypy .
- name: Unit tests
run: |
pytest tests/unit_tests
- name: Integration tests
run: |
pytest tests/integration_tests
2 changes: 1 addition & 1 deletion mlup/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def get_config_dict(self) -> Dict:
return config

def load_from_dict(self, conf: Dict):
logger.info(f'Load config from dict')
logger.info('Load config from dict')
self.set_config_from_dict(conf)

def load_from_json(self, file_path: Union[str, Path]):
Expand Down
6 changes: 3 additions & 3 deletions mlup/console_scripts/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
options:
-h, --help show this help message and exit
{AVAILABLE_COMMANDS}
"""


def run_command(args: List[str]):
try:
command, command_args = args[0], args[1:]
command, _ = args[0], args[1:]
except IndexError:
print(HELP)
sys.exit(1)
Expand All @@ -37,7 +37,7 @@ def run_command(args: List[str]):

try:
module = importlib.import_module(f'mlup.console_scripts.{command}')
except ModuleNotFoundError as e:
except ModuleNotFoundError:
print(f'Invalid command {command} - mlup.console_scripts.{command}.')
print(AVAILABLE_COMMANDS)
sys.exit(1)
Expand Down
2 changes: 1 addition & 1 deletion mlup/ml/binarization/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from mlup.constants import LoadedFile


@dataclass(kw_only=True)
@dataclass
class BaseBinarizer(metaclass=abc.ABCMeta):
@classmethod
@abc.abstractmethod
Expand Down
2 changes: 1 addition & 1 deletion mlup/ml/binarization/joblib.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
class JoblibBinarizer(PickleBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization joblib data.')
logger.info('Run deserialization joblib data.')
if joblib is None:
logger.error('For use joblib, please install it. pip install joblib.')
raise ModelBinarizationError('For use joblib, please install it. pip install joblib.')
Expand Down
2 changes: 1 addition & 1 deletion mlup/ml/binarization/lightgbm.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
class LightGBMBinarizer(BaseBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization lightgbm data.')
logger.info('Run deserialization lightgbm data.')
with TimeProfiler('Time to deserialization lightgbm data:'):
try:
if data.path:
Expand Down
2 changes: 1 addition & 1 deletion mlup/ml/binarization/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
class MemoryBinarizer(BaseBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization memory data.')
logger.info('Run deserialization memory data.')
return data.raw_data
2 changes: 1 addition & 1 deletion mlup/ml/binarization/onnx.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def predict(self, input_data):
class InferenceSessionBinarizer(BaseBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization onnxruntime data.')
logger.info('Run deserialization onnxruntime data.')
with TimeProfiler('Time to deserialization onnxruntime data:'):
try:
_data = data.raw_data
Expand Down
2 changes: 1 addition & 1 deletion mlup/ml/binarization/pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class PickleBinarizer(BaseBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization pickle data.')
logger.info('Run deserialization pickle data.')
with TimeProfiler('Time to deserialization pickle data:'):
try:
if isinstance(data.raw_data, BufferedIOBase):
Expand Down
4 changes: 2 additions & 2 deletions mlup/ml/binarization/tensorflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
class TensorFlowBinarizer(BaseBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization tensorflow data.')
logger.info('Run deserialization tensorflow data.')
with TimeProfiler('Time to deserialization tensorflow data:'):
try:
_data = data.raw_data
Expand Down Expand Up @@ -63,7 +63,7 @@ def is_this_type(cls, loaded_file: LoadedFile) -> float:
class TensorFlowSavedBinarizer(BaseBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization tensorflow SavedModel data.')
logger.info('Run deserialization tensorflow SavedModel data.')
with TimeProfiler('Time to deserialization tensorflow SavedModel data:'):
try:
_data = data.raw_data
Expand Down
4 changes: 2 additions & 2 deletions mlup/ml/binarization/torch.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class TorchBinarizer(BaseBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization torch data.')
logger.info('Run deserialization torch data.')
with TimeProfiler('Time to deserialization torch data:'):
try:
_data = data.raw_data
Expand Down Expand Up @@ -64,7 +64,7 @@ def is_this_type(cls, loaded_file: LoadedFile) -> float:
class TorchJITBinarizer(BaseBinarizer):
@classmethod
def deserialize(cls, data: LoadedFile):
logger.info(f'Run deserialization torch JIT data.')
logger.info('Run deserialization torch JIT data.')
with TimeProfiler('Time to deserialization torch JIT data:'):
try:
_data = data.raw_data
Expand Down
9 changes: 4 additions & 5 deletions mlup/ml/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
logger = logging.getLogger('mlup')


@dataclass(kw_only=True)
@dataclass
class ModelConfig:
"""
MlupModel config class. This class have settings for model.
Expand Down Expand Up @@ -149,7 +149,7 @@ def ml_str(self, need_spaces: bool = False):
return '\n'.join(res)


@dataclass(kw_only=True, repr=True)
@dataclass(repr=True)
class MLupModel(ModelConfig):
"""This is main UP model class.
Create object UP with your ML model, set your settings and run your app.
Expand Down Expand Up @@ -274,7 +274,7 @@ def _transform_predicted_data(self, predicted_data: Any):
try:
processing_data = self._data_transformer_for_predicted.transform_to_json_format(predicted_data)
except Exception as e:
logger.exception(f'Fail transform predicted data to response format.')
logger.exception('Fail transform predicted data to response format.')
raise PredictTransformDataError(str(e))
finally:
logger.debug('Finish transform predicted data to response format.')
Expand Down Expand Up @@ -302,7 +302,7 @@ async def _predict(self, data_for_predict: Optional[Any] = None, **other_predict
*_predict_args
)
else:
logger.debug(f'Running sync predict.')
logger.debug('Running sync predict.')
with self._lock:
result = self._prepare_predict_method(**other_predict_args)(*_predict_args)
except Exception as e:
Expand Down Expand Up @@ -423,4 +423,3 @@ async def predict_from(self, **predict_data):
raise
except Exception as e:
raise PredictError(e)

4 changes: 2 additions & 2 deletions mlup/up.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ def generate_default_config(path_to_file: Optional[str] = None) -> Optional[Dict
up.to_yaml(path_to_file)


@dataclass(kw_only=True)
@dataclass
class Config(ModelConfig, WebAppConfig):
pass


@dataclass(kw_only=True, repr=False)
@dataclass(repr=False)
class UP:
"""This is main UP class.
Create object UP with your ML model, set your settings and run your web app.
Expand Down
5 changes: 3 additions & 2 deletions mlup/utils/interspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from mlup.constants import IS_X, THERE_IS_ARGS, DEFAULT_X_ARG_NAME, BinarizationType, LoadedFile
from mlup.utils.profiling import TimeProfiler


logger = logging.getLogger('mlup')


Expand Down Expand Up @@ -107,7 +108,7 @@ def example(a, b = 100, *, c: float = 123):
param_data['type'] = types[type(param_obj.default)]

if param_name.lower().strip() == 'x' and auto_detect_predict_params:
logger.info(f'Found X param in model params. Set List type')
logger.info('Found X param in model params. Set List type')
param_data['type'] = 'List'
param_data[IS_X] = True
_found_X = True
Expand Down Expand Up @@ -145,7 +146,7 @@ def auto_search_binarization_type(loaded_file: LoadedFile) -> Optional[Type[Bina
:rtype: Optional[Type[BinarizationType]]
"""
logger.info(f'Run auto search binarizer.')
logger.info('Run auto search binarizer.')
probabilities = []
with TimeProfiler('Time to auto search binarizer:', log_level='info'):
for binarizer_path in BinarizationType:
Expand Down
4 changes: 3 additions & 1 deletion mlup/utils/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ def __init__(self, fmt: Optional[str] = None, *args, **kwargs):
def set_fmt(self, fmt_name: str = 'default'):
fmt = self._fmts[fmt_name]
self._style = logging.PercentStyle(fmt)
self._style.validate()
# This "if" for python3.7-
if hasattr(self._style, 'validate'):
self._style.validate()
self._fmt = self._style._fmt


Expand Down
8 changes: 8 additions & 0 deletions mlup/utils/loop.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import sys
import threading


Expand Down Expand Up @@ -29,3 +30,10 @@ def run_async(func, *args, **kwargs):
return thread.result
else:
return asyncio.run(func(*args, **kwargs))


def create_async_task(coro, *, name=None):
task_kwargs = {}
if sys.version_info.minor >= 8:
task_kwargs['name'] = name
return asyncio.create_task(coro, **task_kwargs)
2 changes: 1 addition & 1 deletion mlup/web/api_validators.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from typing import List, Any, Dict, Tuple, Optional, Type

from pydantic import BaseModel, validator, create_model, Field
from pydantic import BaseModel, create_model, Field

from mlup.constants import IS_X, DEFAULT_X_ARG_NAME
from mlup.ml.model import MLupModel
Expand Down
4 changes: 2 additions & 2 deletions mlup/web/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async def wrap(*args, response: FastAPIResponse, **kwargs):
return wrap


@dataclass(kw_only=True)
@dataclass
class WebAppConfig:
"""
WebAppConfig config class. This class have settings for web app.
Expand Down Expand Up @@ -227,7 +227,7 @@ def wb_str(self, need_spaces: bool = False):
return '\n'.join(res)


@dataclass(kw_only=True, repr=True)
@dataclass(repr=True)
class MLupWebApp:
"""This is main UP web app class.
Create object UP with your ML model, set your settings and run your web app.
Expand Down
4 changes: 2 additions & 2 deletions mlup/web/architecture/batching.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _save_predicted_data_from_batch(self, predicted_data: List, error: Optional[
local_result = []

async def _predict(self):
logger.debug(f'Run predict for batch')
logger.debug('Run predict for batch')
predicted_data = self.batch_queue
error = None
try:
Expand All @@ -112,7 +112,7 @@ async def _predict(self):
self._save_predicted_data_from_batch(predicted_data, error)
self.batch_queue.clear()
self.batch_predict_ids.clear()
logger.debug(f'End predict for batch')
logger.debug('End predict for batch')

async def _start_worker(self, sleep_time: float = 0.1):
self._running = True
Expand Down
3 changes: 2 additions & 1 deletion mlup/web/architecture/worker_and_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from mlup.errors import WebAppLoadError, PredictError, PredictWaitResultError
from mlup.ml.model import MLupModel
from mlup.utils.collections import TTLOrderedDict
from mlup.utils.loop import create_async_task
from mlup.web.architecture.base import BaseWebAppArchitecture
from mlup.constants import WebAppArchitecture

Expand Down Expand Up @@ -102,7 +103,7 @@ async def run(self):
logger.info('Run model in worker')
if self.results_storage is None or self.queries_queue is None:
raise WebAppLoadError('Not called .load() in web.load()')
self.worker_process = asyncio.create_task(self._start_worker())
self.worker_process = create_async_task(self._start_worker())

@property
def is_running(self) -> bool:
Expand Down
26 changes: 18 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,19 @@ Documentation = "https://github.com/nxexox/pymlup/docs"
Repository = "https://github.com/nxexox/pymlup"

[project.optional-dependencies]
scikit-learn = ["scikit-learn>=1.2.0,<1.3.0"]
scikit-learn = [
"scikit-learn>=1.2.0,<1.3.0;python_version>='3.8'",
"scikit-learn;python_version<'3.8'",
]
lightgbm = ["lightgbm>=4.0.0,<5.0.0"]
tensorflow = ["tensorflow>=2.0.0,<3.0.0"]
torch = ["torch>=2.0.0,<3.0.0"]
torch = [
"torch>=2.0.0,<3.0.0;python_version>='3.8'",
"torch;python_version<'3.8'",
]
onnx = [
"onnx>=1.0.0,<2.0.0",
"onnxruntime>=1.0.0,<2.0.0",
"onnxruntime<1.16",
]
tests = [
# Tests
Expand All @@ -70,13 +76,17 @@ tests = [

# Tests models
"joblib>=1.2.0,<1.3.0",
"pandas>=2.0.0,<3.0.0",
"scikit-learn>=1.2.0,<1.3.0",
"tensorflow>=2.0.0,<3.0.0",
"pandas>=2.0.0,<3.0.0;python_version>='3.8'",
"pandas;python_version<'3.8'",
"scikit-learn>=1.2.0,<1.3.0;python_version>='3.8'",
"scikit-learn;python_version<'3.8'",
"tensorflow>=2.0.0,<3.0.0;python_version>='3.8'",
"tensorflow;python_version<'3.8'",
"lightgbm>=4.0.0,<5.0.0",
"torch>=2.0.0,<3.0.0",
"torch>=2.0.0,<3.0.0;python_version>='3.8'",
"torch;python_version<'3.8'",
"onnx>=1.0.0,<2.0.0",
"onnxruntime>=1.0.0,<2.0.0",
"onnxruntime<1.16",
"tf2onnx>=1.0.0,<2.0.0",
"skl2onnx>=1.0.0,<2.0.0",

Expand Down
Loading

0 comments on commit d916042

Please sign in to comment.