diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..9d4cdf180 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,223 @@ +version: 2.1 + +parameters: + nightly_build: + type: boolean + default: false + weekly_build: + type: boolean + default: false + +jobs: + linux_build_and_test: + docker: + - image: cimg/python:3.9 + + steps: + - checkout + - run: + name: Run style checks + command: | + pip install pre-commit + pre-commit run --all + if ! git diff --quiet; then echo 'Style checks failed, please install pre-commit and run pre-commit run --all and push the change'; exit 1; fi + - run: + name: Install dependencies + command: | + pip install --upgrade cmake + pip install --upgrade pybind11[global] + pip install numpy + sudo apt-get update + sudo apt-get install libblas-dev + - run: + name: Build python package + command: | + CMAKE_ARGS="-DMLX_BUILD_METAL=OFF" CMAKE_BUILD_PARALLEL_LEVEL="" python3 setup.py build_ext --inplace + CMAKE_ARGS="-DMLX_BUILD_METAL=OFF" CMAKE_BUILD_PARALLEL_LEVEL="" python3 setup.py develop + - run: + name: Run the python tests + command: | + python3 -m unittest discover python/tests + - run: + name: Build CPP only + command: | + mkdir -p build && cd build && cmake .. -DMLX_BUILD_METAL=OFF && make -j + - run: + name: Run CPP tests + command: ./build/tests/tests + + mac_build_and_test: + machine: true + resource_class: ml-explore/m-builder + steps: + - checkout + - run: + name: Install dependencies + command: | + eval "$(conda shell.bash hook)" + rm -r $CONDA_PREFIX/envs/runner-env + conda create -y -n runner-env python=3.9 + conda activate runner-env + pip install --upgrade cmake + pip install --upgrade pybind11[global] + pip install numpy + pip install torch + pip install unittest-xml-reporting + - run: + name: Build python package + command: | + eval "$(conda shell.bash hook)" + conda activate runner-env + CMAKE_BUILD_PARALLEL_LEVEL="" python setup.py build_ext --inplace + CMAKE_BUILD_PARALLEL_LEVEL="" python setup.py develop + - run: + name: Run the python tests + command: | + eval "$(conda shell.bash hook)" + conda activate runner-env + DEVICE=cpu python -m xmlrunner discover -v python/tests -o test-results/cpu + DEVICE=gpu python -m xmlrunner discover -v python/tests -o test-results/gpu + - store_test_results: + path: test-results + + build_release: + machine: true + resource_class: ml-explore/m-builder + parameters: + python_version: + type: string + default: "3.9" + macos_version: + type: string + default: "14" + steps: + - checkout + - run: + name: Install dependencies + command: | + eval "$(conda shell.bash hook)" + rm -r $CONDA_PREFIX/envs/runner-env + conda create -y -n runner-env python=<< parameters.python_version >> + conda activate runner-env + pip install --upgrade cmake + pip install --upgrade pybind11[global] + pip install numpy + pip install twine + - run: + name: Build pacakge + command: | + eval "$(conda shell.bash hook)" + conda activate runner-env + DEVELOPER_DIR=$(developer_dir_macos_<< parameters.macos_version >>) \ + PYPI_RELEASE=1 \ + CMAKE_BUILD_PARALLEL_LEVEL="" \ + python setup.py bdist_wheel + twine upload dist/* --repository mlx + - store_artifacts: + path: dist/ + + build_dev_release: + machine: true + resource_class: ml-explore/m-builder + parameters: + python_version: + type: string + default: "3.9" + macos_version: + type: string + default: "14" + steps: + - checkout + - run: + name: Install dependencies + command: | + eval "$(conda shell.bash hook)" + rm -r $CONDA_PREFIX/envs/runner-env + conda create -y -n runner-env python=<< parameters.python_version >> + conda activate runner-env + pip install --upgrade cmake + pip install --upgrade pybind11[global] + pip install numpy + pip install twine + - run: + name: Build pacakge + command: | + eval "$(conda shell.bash hook)" + conda activate runner-env + DEVELOPER_DIR=$(developer_dir_macos_<< parameters.macos_version >>) \ + DEV_RELEASE=1 \ + CMAKE_BUILD_PARALLEL_LEVEL="" \ + python setup.py bdist_wheel + twine upload dist/* --repository mlx + - store_artifacts: + path: dist/ + + build_package: + machine: true + resource_class: ml-explore/m-builder + parameters: + python_version: + type: string + default: "3.9" + macos_version: + type: string + default: "14" + steps: + - checkout + - run: + name: Install dependencies + command: | + eval "$(conda shell.bash hook)" + rm -r $CONDA_PREFIX/envs/runner-env + conda create -y -n runner-env python=<< parameters.python_version >> + conda activate runner-env + pip install --upgrade cmake + pip install --upgrade pybind11[global] + pip install numpy + pip install twine + - run: + name: Build pacakge + command: | + eval "$(conda shell.bash hook)" + conda activate runner-env + DEVELOPER_DIR=$(developer_dir_macos_<< parameters.macos_version >>) \ + CMAKE_BUILD_PARALLEL_LEVEL="" \ + python setup.py bdist_wheel + - store_artifacts: + path: dist/ + +workflows: + build_and_test: + when: + and: + - not: << pipeline.parameters.nightly_build >> + - not: << pipeline.parameters.weekly_build >> + jobs: + - linux_build_and_test + - mac_build_and_test + - build_release: + filters: + tags: + only: /^v.*/ + branches: + ignore: /.*/ + matrix: + parameters: + python_version: ["3.8", "3.9", "3.10", "3.11"] + macos_version: ["13", "14"] + nightly_build: + when: << pipeline.parameters.nightly_build >> + jobs: + - build_package: + matrix: + parameters: + python_version: ["3.8", "3.9", "3.10", "3.11"] + macos_version: ["13", "14"] + weekly_build: + when: << pipeline.parameters.weekly_build >> + jobs: + - build_dev_release: + matrix: + parameters: + python_version: ["3.8", "3.9", "3.10", "3.11"] + macos_version: ["13", "14"] diff --git a/python/tests/test_array.py b/python/tests/test_array.py index 16579742a..d3539ac55 100644 --- a/python/tests/test_array.py +++ b/python/tests/test_array.py @@ -14,9 +14,9 @@ class TestVersion(mlx_tests.MLXTestCase): def test_version(self): v = mx.__version__ vnums = v.split(".") - self.assertEqual(len(vnums), 3) - v = ".".join(str(int(vn)) for vn in vnums) - self.assertEqual(v, mx.__version__) + self.assertGreaterEqual(len(vnums), 3) + v = ".".join(str(int(vn)) for vn in vnums[:3]) + self.assertEqual(v, mx.__version__[: len(v)]) class TestDtypes(mlx_tests.MLXTestCase): @@ -905,7 +905,6 @@ class TestArray(mlx_tests.MLXTestCase): ) def test_slice_negative_step(self): - a_np = np.arange(20) a_mx = mx.array(a_np) diff --git a/python/tests/test_ops.py b/python/tests/test_ops.py index 7def06c29..4fdd48ac3 100644 --- a/python/tests/test_ops.py +++ b/python/tests/test_ops.py @@ -1084,7 +1084,7 @@ class TestOps(mlx_tests.MLXTestCase): a[-1] = 0.0 a = mx.softmax(mx.array(a)) self.assertFalse(np.any(np.isnan(a))) - self.assertTrue((a[:-1] == 0).all()) + self.assertTrue((a[:-1] < 1e-9).all()) self.assertEqual(a[-1], 1) def test_concatenate(self): diff --git a/setup.py b/setup.py index c5e6c1de2..295da0a30 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,38 @@ # Copyright © 2023 Apple Inc. +import datetime import os import re import subprocess import sys import sysconfig from pathlib import Path +from subprocess import run from setuptools import Extension, setup, find_namespace_packages from setuptools.command.build_ext import build_ext +def get_version(version): + if "PYPI_RELEASE" not in os.environ: + today = datetime.date.today() + version = f"{version}.dev{today.year}{today.month}{today.day}" + + if "DEV_RELEASE" not in os.environ: + git_hash = ( + run( + "git rev-parse --short HEAD".split(), + capture_output=True, + check=True, + ) + .stdout.strip() + .decode() + ) + version = f"{version}+{git_hash}" + + return version + + # A CMakeExtension needs a sourcedir instead of a file list. # The name must be the _single_ output extension from the CMake build. # If you need multiple extensions, see scikit-build. @@ -111,9 +133,10 @@ if __name__ == "__main__": ) package_dir = {"": "python"} package_data = {"mlx": ["lib/*", "include/*", "share/*"]} + setup( name="mlx", - version="0.0.2", + version=get_version("0.0.2"), author="MLX Contributors", author_email="mlx@group.apple.com", description="A framework for machine learning on Apple Silicon.",