From 43927d2f429d640b17391c222f4d33c352d0f53e Mon Sep 17 00:00:00 2001 From: Markus Cozowicz Date: Fri, 17 Sep 2021 18:18:55 +0200 Subject: [PATCH] Build fixes (#1) * fix build * fix dependencies * fix more dependencies * pytest? * fix pip? * more fixing? * remove apt install * pybind11 * add to toml * fix mac/windows * just linux * use codecov token * enable windows * fix coverage * fix codecov, remove mac for publish * fix windows build * fix build * fix setup.py * more fixes * fix more build * removed windows --- .github/workflows/build.yml | 43 +++++++++++++++ .github/workflows/code-coverage.yml | 34 ------------ .github/workflows/publish-to-test-pypi.yml | 63 ++++++++++++++++------ README.md | 8 ++- pyproject.toml | 2 +- setup.py | 31 +++++++++-- src/pycbm.cpp | 11 ++-- 7 files changed, 130 insertions(+), 62 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/code-coverage.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..852faa1 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,43 @@ +name: Build +on: [push] +jobs: + build: + name: Build + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] # , windows-latest] + python: [3.7, 3.8] + env: + OS: ${{ matrix.os }} + steps: + - uses: actions/checkout@master + - name: Setup Python + uses: actions/setup-python@master + with: + python-version: ${{ matrix.python }} + + - name: Install dependencies + run: python -m pip install pytest pytest-cov pybind11 numpy pandas scikit-learn lightgbm interpret + + - name: Install dependency for lightgbm + if: matrix.os == 'macos-latest' + run: brew install libomp + + - name: Install package + run: python -m pip install -e . + + - name: Generate coverage report + run: pytest --cov=./ --cov-report=xml tests/ + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v2 + with: + token: ${{ secrets.CODECOV_TOKEN }} + directory: ./coverage/reports/ + env_vars: OS,PYTHON + fail_ci_if_error: true + files: ./coverage.xml + flags: unittests + name: codecov-umbrella + path_to_write_report: ./coverage/codecov_report.txt + verbose: true \ No newline at end of file diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml deleted file mode 100644 index 7338e84..0000000 --- a/.github/workflows/code-coverage.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Generate Codecov -on: [push] -jobs: - run: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - env: - OS: ${{ matrix.os }} - PYTHON: '3.8' - steps: - - uses: actions/checkout@master - - name: Setup Python - uses: actions/setup-python@master - with: - python-version: 3.8 - - name: Generate coverage report - run: | - pip install pytest - pip install pytest-cov - pytest --cov=./ --cov-report=xml - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v2 - with: - # token: ${{ secrets.CODECOV_TOKEN }} - directory: ./coverage/reports/ - env_vars: OS,PYTHON - fail_ci_if_error: true - files: ./coverage1.xml,./coverage2.xml - flags: unittests - name: codecov-umbrella - path_to_write_report: ./coverage/codecov_report.txt - verbose: true \ No newline at end of file diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index 5a0c6ee..9f67927 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -3,9 +3,31 @@ name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI on: push jobs: - build-n-publish: - name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI - runs-on: ubuntu-18.04 + # build-windows: + # name: Build on Windows + # runs-on: windows-latest + # steps: + # - uses: actions/checkout@master + # - name: Set up Python 3.8 + # uses: actions/setup-python@v1 + # with: + # python-version: 3.8 + + # - name: Install pypa/build + # run: python -m pip install build --user + + # - name: Build a binary wheel and a source tarball (Windows) + # run: python -m build --sdist --wheel --outdir dist/ . + + # - name: Store the binary wheel + # uses: actions/upload-artifact@v2 + # with: + # name: python-package-distributions + # path: dist + + build-linux: + name: Build on Linux + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@master - name: Set up Python 3.8 @@ -14,20 +36,29 @@ jobs: python-version: 3.8 - name: Install pypa/build - run: >- - python -m - pip install - build - --user + run: python -m pip install build --user - - name: Build a binary wheel and a source tarball - run: >- - python -m - build - --sdist - --wheel - --outdir dist/ - . + - name: Build a source tarball + run: python -m build --sdist --outdir dist/ . + + - name: Store the binary wheel + uses: actions/upload-artifact@v2 + with: + name: python-package-distributions + path: dist + + publish: + name: Publish to PyPI and TestPyPI + runs-on: ubuntu-20.04 + needs: + # - build-windows + - build-linux + steps: + - name: Download all the dists + uses: actions/download-artifact@v2 + with: + name: python-package-distributions + path: dist/ - name: Publish distribution 📦 to Test PyPI uses: pypa/gh-action-pypi-publish@master diff --git a/README.md b/README.md index 82d643c..1e7d06d 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,18 @@ # Cyclic Boosting Machines -[![PyPI version](https://badge.fury.io/py/pysarplus.svg)](https://badge.fury.io/py/cyclicbm) +![Build](https://github.com/Microsoft/cbm/actions/workflows/build.yml/badge.svg) +[![codecov](https://codecov.io/gh/microsoft/CBM/branch/main/graph/badge.svg?token=VRppFx2o8v)](https://codecov.io/gh/microsoft/CBM) +[![PyPI version](https://badge.fury.io/py/cyclicbm.svg)](https://badge.fury.io/py/cyclicbm) [![Academic Paper](https://img.shields.io/badge/academic-paper-7fdcf7)](https://arxiv.org/abs/2002.03425) This is an efficient and Scikit-learn compatible implementation of the machine learning algorithm [Cyclic Boosting -- an explainable supervised machine learning algorithm](https://arxiv.org/abs/2002.03425), specifically for predicting count-data, such as sales and demand. ## Usage +```bash +pip install cyclicbm +``` + ```python import cbm import numpy as np diff --git a/pyproject.toml b/pyproject.toml index 88a94d6..1866685 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] # These are the assumed default build requirements from pip: # https://pip.pypa.io/en/stable/reference/pip/#pep-517-and-518-support -requires = ["setuptools>=40.8.0", "wheel"] +requires = ["setuptools>=40.8.0", "wheel", "pybind11", "numpy", "pandas", "scikit-learn", "lightgbm", "interpret"] build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/setup.py b/setup.py index c8aff07..a8ec8ed 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ import sysconfig from setuptools import setup from setuptools.extension import Extension - +import platform class get_pybind_include(object): def __init__(self, user=False): @@ -13,11 +13,33 @@ class get_pybind_include(object): return pybind11.get_include(self.user) +def get_extra_compile_args(): + if platform.system() == "Windows": + return "" + + cflags = sysconfig.get_config_var("CFLAGS") + if cflags is None: + cflags = "" + + return cflags.split() \ + + ["-std=c++11", "-Wall", "-Wextra", "-march=native", "-msse2", "-ffast-math", "-mfpmath=sse"] + +def get_libraries(): + if platform.system() == "Windows": + return [] + + return ["stdc++"] + +from pathlib import Path +this_directory = Path(__file__).parent +long_description = (this_directory / "README.md").read_text() setup( name="cyclicbm", - version="0.0.1", + version="0.0.2", description="Cyclic Boosting Machines", + long_description=long_description, + long_description_content_type='text/markdown', url="https://github.com/Microsoft/CBM", author="Markus Cozowicz", author_email="marcozo@microsoft.com", @@ -41,9 +63,8 @@ setup( "cbm_cpp", ["src/pycbm.cpp", "src/cbm.cpp"], include_dirs=[get_pybind_include(), get_pybind_include(user=True)], - extra_compile_args=sysconfig.get_config_var("CFLAGS").split() - + ["-std=c++11", "-Wall", "-Wextra", "-march=native", "-msse2", "-ffast-math", "-mfpmath=sse"], - libraries=["stdc++"], + extra_compile_args=get_extra_compile_args(), + libraries=get_libraries(), language="c++11", ) ], diff --git a/src/pycbm.cpp b/src/pycbm.cpp index 0ee3cee..65d3fc5 100644 --- a/src/pycbm.cpp +++ b/src/pycbm.cpp @@ -20,24 +20,25 @@ namespace cbm { double epsilon_early_stopping, bool single_update_per_iteration) { - // TODO: fix error messages py::buffer_info y_info = y_b.request(); + + // this is broken on windows if (y_info.format != py::format_descriptor::format()) - throw std::runtime_error("Incompatible format: expected a y array!"); + throw std::runtime_error("Incompatible format: expected a uint32 array for y!"); if (y_info.ndim != 1) - throw std::runtime_error("Incompatible buffer dimension!"); + throw std::runtime_error("y must be 1-dimensional!"); py::buffer_info x_info = x_b.request(); if (x_info.format != py::format_descriptor::format()) - throw std::runtime_error("Incompatible format: expected a x array!"); + throw std::runtime_error("Incompatible format: expected a uint8 array x!"); if (x_info.ndim != 2) throw std::runtime_error("Incompatible buffer dimension!"); py::buffer_info x_max_info = x_max_b.request(); if (x_max_info.format != py::format_descriptor::format()) - throw std::runtime_error("Incompatible format: expected a x array!"); + throw std::runtime_error("Incompatible format: expected a uint8 array for x_max!"); if (x_max_info.ndim != 1) throw std::runtime_error("Incompatible buffer dimension!");