diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index 32b23127a..84f8d7a5e 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -6,6 +6,7 @@ on: - "**.py" - "**.pxd" - "**.pyx" + - "**" push: branches: [main] workflow_dispatch: @@ -77,29 +78,82 @@ jobs: - uses: actions/upload-artifact@v3 with: - path: ./wheelhouse/*.whl + path: ./wheelhouse/ name: ${{ matrix.python[0] }}-${{ matrix.os[1] }} - # TODO: let's figure out how to build these wheels? - # build_wheels_macos: - # name: Build wheels on macos-11 - # runs-on: macos-11 - # steps: - # - uses: actions/checkout@v3 - - # - uses: actions/setup-python@v4.6.1 - # with: - # python-version: 3.9 - - # - name: macosx_arm64 - setup builddir - # run: | - # python -m pip wheel --config-settings builddir=build . - - # - name: Build wheels - # uses: pypa/cibuildwheel@v2.13.1 - # env: - # CIBW_ARCHS_MACOS: arm64 - - # - uses: actions/upload-artifact@v3 - # with: - # path: ./wheelhouse/*.whl \ No newline at end of file + build-wheels-m1: + name: Build wheels on Arm M1 with Python ${{ matrix.python[0] }} + runs-on: macos-latest + + strategy: + # Ensure that a wheel builder finishes even if another fails + fail-fast: false + matrix: + python: [["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"]] + # python[0] is used to specify the python versions made by cibuildwheel + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4.6.1 + with: + python-version: 3.9 # Replace with the desired Python version + + - name: Install cibuildwheel dependencies + run: | + python -m pip install cibuildwheel + python -m pip install -r build_requirements.txt + python -m pip install spin + python spin setup-submodule + + - name: Build wheels + uses: pypa/cibuildwheel@v2.13.1 + env: + CIBW_BUILD: ${{ matrix.python[0] }}-macosx_arm64 + CIBW_ARCHS_MACOS: arm64 + + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse + name: ${{ matrix.python[0] }}-arm + + # Build the source distribution under Linux + build_sdist: + name: Source distribution + runs-on: ubuntu-latest + + steps: + - name: Checkout scikit-tree + uses: actions/checkout@v3 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' # update once build dependencies are available + + - name: Build source distribution + run: | + python -m pip install -r build_requirements.txt + python -m pip install spin + python spin setup-submodule + python spin sdist + # run: bash build_tools/github/build_source.sh + # env: + # SKLEARN_BUILD_PARALLEL: 3 + + # - name: Test source distribution + # run: bash build_tools/github/test_source.sh + # env: + # SKLEARN_SKIP_NETWORK_TESTS: 1 + + - name: Store artifacts + uses: actions/upload-artifact@v3 + with: + path: dist/*.tar.gz + + - uses: actions/upload-artifact@v3 + with: + path: dist + name: ${{ matrix.python[0] }}-${{ matrix.os[1] }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b40779893..8de9488bc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,7 +31,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, macos-latest] - python-version: [3.8, 3.9, "3.10"] + python-version: [3.9, "3.10", "3.11"] poetry-version: [1.3.0] runs-on: ${{ matrix.os }} defaults: @@ -171,7 +171,9 @@ jobs: - name: pip-packages run: | pip install -r build_requirements.txt + pip install -r test_requirements.txt pip install spin + pip install numpy==1.22.4 - name: openblas-libs # shell: bash diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index eee448e21..ea0aa809a 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -32,10 +32,10 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 - - name: Setup Python 3.9 + - name: Setup Python 3.10 uses: actions/setup-python@v4.6.1 with: - python-version: "3.9" + python-version: "3.10" architecture: "x64" - name: Install packages for Ubuntu diff --git a/.gitmodules b/.gitmodules index 76600eff2..c1ef0ca16 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "sktree/_lib/sklearn"] path = sktree/_lib/sklearn_fork url = https://github.com/neurodata/scikit-learn - branch = submodulev2 + branch = v1.3 diff --git a/.spin/cmds.py b/.spin/cmds.py index c1179be04..95e379d82 100644 --- a/.spin/cmds.py +++ b/.spin/cmds.py @@ -160,3 +160,9 @@ def build(ctx, meson_args, jobs=None, clean=False, forcesubmodule=False, verbose # run build as normal ctx.invoke(meson.build, meson_args=meson_args, jobs=jobs, clean=clean, verbose=verbose) + + +@click.command() +def sdist(): + """📦 Build a source distribution in `dist/`""" + util.run(["python", "-m", "build", ".", "--sdist"]) diff --git a/DEVELOPING.md b/DEVELOPING.md index 4c151f233..a9d64457c 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -57,3 +57,23 @@ In order for any code to be added to the repository, we require unit tests to pa The general design of scikit-tree follows that of the tree-models inside scikit-learn, where tree-based models are inherently Cythonized, or written with C++. Then the actual forest (e.g. RandomForest, or ExtraForest) is just a Python API wrapper that creates an ensemble of the trees. In order to develop new tree models, generally Cython and C++ code will need to be written in order to optimize the tree building process, otherwise fitting a single forest model would take very long. + +# Making a Release + +Scikit-tree is in-line with scikit-learn and thus relies on each new version released there. Moreover, scikit-tree relies on compiled code, so releases are a bit more complex than the typical Python package. + +1. Download wheels from GH Actions and put all wheels into a ``dist/`` folder + +https://github.com/neurodata/scikit-tree/actions/workflows/build_wheels.yml will have all the wheels for common OSes built for each Python version. + +2. Upload wheels to test PyPi + + twine upload --repository-url https://test.pypi.org/legacy/ dist/* + +Verify that installations work as expected on your machine. + +3. Upload wheels + + twine upload dist/* + +4. Update version number on ``meson.build`` and ``_version.py`` to the relevant version. \ No newline at end of file diff --git a/build_requirements.txt b/build_requirements.txt index b18d3ce9f..9d5aa5e6e 100644 --- a/build_requirements.txt +++ b/build_requirements.txt @@ -9,3 +9,4 @@ rich-click doit pydevtool spin +build diff --git a/examples/overlapping_gaussians.png b/examples/overlapping_gaussians.png index 0a2157136..635b01fb2 100644 Binary files a/examples/overlapping_gaussians.png and b/examples/overlapping_gaussians.png differ diff --git a/meson.build b/meson.build index 48f0cc04b..2e605ea54 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,7 @@ project( # Note that the git commit hash cannot be added dynamically here # That only happens when importing from a git repository. # See `sktree/__init__.py` - version: '0.0.0.dev0', + version: '0.1.3', license: 'BSD-3', meson_version: '>= 0.64.0', default_options: [ @@ -45,7 +45,8 @@ if not cython.found() error('MESON_BUILD_FAILED: Cython3 not found. Please install it.') endif -run_command('git', 'submodule', 'update', '--init', check: true) +# r = run_command('git', 'submodule', 'update', '--init', check: false) +r = run_command('mv', 'sktree/_lib/sklearn_fork/sklearn', 'sktree/_lib/sklearn', check: false) # Setup Python: # https://mesonbuild.com/Python-module.html @@ -62,8 +63,8 @@ py3 = py3_mod.find_installation( # print some debugging output message(py3.full_path()) message(py3.get_install_dir()) -if py3.language_version().version_compare('<3.8') - error('At least Python 3.8 is required.') +if py3.language_version().version_compare('<3.9') + error('At least Python 3.9 is required.') endif py3_dep = py3.dependency() diff --git a/pyproject.toml b/pyproject.toml index 4ba1b109b..166edf6ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,41 @@ +[project] +name = "sktree" +# +# 0.0.0 is standard placeholder for poetry-dynamic-versioning +# any changes to this should not be checked in +# +version = "0.1.3" +description = "Modern decision trees in Python" +maintainers = [ + {name="Neurodata", email="adam.li@columbia.edu"} +] +documentation = "https://scikit-tree.neurodata.io" +repository = "https://github.com/neurodata/scikit-tree" +readme = "README.md" +requires-python = ">=3.9" +classifiers = [ + 'Development Status :: 4 - Beta', + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Programming Language :: C", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + "Topic :: Scientific/Engineering", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS", +] +keywords = ['tree', 'oblique trees', 'manifold-learning', 'scikit-learn'] +include = [ + { path = "meson.build", format = "sdist" }, +] + [tool.poetry] name = "sktree" # @@ -13,8 +51,6 @@ repository = "https://github.com/neurodata/scikit-tree" readme = "README.md" classifiers = [ 'Development Status :: 4 - Beta', - 'License :: OSI Approved :: BSD-3 License', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', @@ -216,6 +252,7 @@ Build = [ # "spin.cmds.meson.build", ".spin/cmds.py:build", ".spin/cmds.py:setup_submodule", + ".spin/cmds.py:sdist", "spin.cmds.meson.test", ] Environments = [ diff --git a/sktree/__init__.py b/sktree/__init__.py index d5b18b805..901ffcd06 100644 --- a/sktree/__init__.py +++ b/sktree/__init__.py @@ -3,7 +3,7 @@ import os import sys -__version__ = "0.0.0dev0" +__version__ = "0.1.3" logger = logging.getLogger(__name__)