Skip to content

Commit

Permalink
Simplify the build (#9)
Browse files Browse the repository at this point in the history
* test simpler setup.py

* Remove "python setup.py develop"

* add requests to pyprojects' build dependency

* update pre-commit config

* add setuptools_scm to pyproject.toml

* test wheel build

* Resurrect find_packages & add manual pb11 installation

* - Resurrect branch policy for wheels.yml
- rename doctests' job name
  • Loading branch information
tohtsky authored May 2, 2022
1 parent a009954 commit b23d246
Show file tree
Hide file tree
Showing 11 changed files with 41 additions and 132 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/doctest.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Doctest
on: [push]
jobs:
run_pytest_upload_coverage:
test_readme_and_sphinx_docs:
runs-on: ubuntu-latest
env:
OS: ubuntu-latest
Expand All @@ -17,7 +17,7 @@ jobs:
run: |
pip install --upgrade pip
pip install numpy scipy pandas scikit-learn
python setup.py install
pip install .
curl http://files.grouplens.org/datasets/movielens/ml-100k.zip -o ~/.ml-100k.zip
- name: Run pytest
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: pre-commit/[email protected].0
- uses: pre-commit/[email protected].3
2 changes: 1 addition & 1 deletion .github/workflows/run-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
pip install --upgrade pip
pip install numpy scipy pandas
sudo apt-get install lcov
TEST_BUILD=true python setup.py develop
CXXFLAGS="-O0 -g -coverage" pip install -e .
- name: Run pytest
run: |
pip install pytest pytest-cov pytest-mock
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ jobs:
- uses: actions/setup-python@v2
name: Install Python
with:
python-version: '3.7'
python-version: "3.7"
- name: Build sdist
run: python setup.py sdist
run: pip install pybind11 && python setup.py sdist
- uses: actions/upload-artifact@v2
with:
path: dist/*.tar.gz
Expand Down Expand Up @@ -126,7 +126,6 @@ jobs:
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse


- uses: actions/upload-artifact@v2
with:
path: ./wheelhouse/*.whl
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ repos:
- id: isort
name: isort
- repo: https://github.com/psf/black
rev: 20.8b1 # Replace by any tag/version: https://github.com/psf/black/tags
rev: 22.3.0
hooks:
- id: black
language_version: python3 # Should be a command that runs python3.6+
Expand Down
12 changes: 12 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
[build-system]
requires = [
"setuptools>=42",
"wheel",
"pybind11>=2.8.0",
"requests",
"setuptools_scm[toml]>=6.2",
]

build-backend = "setuptools.build_meta"

[tool.black]
ensure_newline_before_comments = true
force_grid_wrap = 0
Expand All @@ -10,6 +21,7 @@ use_parentheses = true
ensure_newline_before_comments = true
force_grid_wrap = 0
include_trailing_comma = true
known_third_party = ["pybind11"]
line_length = 88
multi_line_output = 3
use_parentheses = true
Expand Down
122 changes: 10 additions & 112 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
# Taken from
# https://github.com/wichert/pybind11-example/blob/master/setup.py
# and modified.

import os
import sys
from distutils.ccompiler import CCompiler
from pathlib import Path
from typing import Any, Dict, List
from typing import Any

import setuptools
from setuptools import Extension, find_packages, setup
from setuptools.command.build_ext import build_ext
from pybind11.setup_helpers import Pybind11Extension, build_ext
from setuptools import find_packages, setup

install_requires = [
"numpy>=1.11",
Expand All @@ -19,10 +12,7 @@
"pandas>=1.0.0",
"typing-extensions>=4.0.0",
]
setup_requires = ["pybind11>=2.5", "requests", "setuptools_scm"]


eigen_include_dir = os.environ.get("EIGEN3_INCLUDE_DIR", None)

TEST_BUILD = os.environ.get("TEST_BUILD", None) is not None

Expand All @@ -32,7 +22,7 @@ class get_eigen_include(object):
EIGEN3_DIRNAME = "eigen-3.4.0"

def __str__(self) -> str:

eigen_include_dir = os.environ.get("EIGEN3_INCLUDE_DIR", None)
if eigen_include_dir is not None:
return eigen_include_dir

Expand All @@ -59,22 +49,6 @@ def __str__(self) -> str:
return str(target_dir)


class get_pybind_include:
"""Helper class to determine the pybind11 include path
The purpose of this class is to postpone importing pybind11
until it is actually installed, so that the ``get_include()``
method can be invoked."""

def __init__(self, user: bool = False):
self.user = user

def __str__(self) -> str:
import pybind11

include_dir: str = pybind11.get_include(self.user)
return include_dir


headers = [
"include/myfm/definitions.hpp",
"include/myfm/util.hpp",
Expand All @@ -90,93 +64,18 @@ def __str__(self) -> str:


ext_modules = [
Extension(
Pybind11Extension(
"myfm._myfm",
["cpp_source/bind.cpp", "cpp_source/Faddeeva.cc"],
include_dirs=[
# Path to pybind11 headers
get_pybind_include(),
get_pybind_include(user=True),
get_eigen_include(),
"include",
],
language="c++",
),
]


def has_flag(compiler: CCompiler, flagname: str) -> bool:
"""Return a boolean indicating whether a flag name is supported on
the specified compiler.
"""
import tempfile

with tempfile.NamedTemporaryFile("w", suffix=".cpp") as f:
f.write("int main (int argc, char **argv) { return 0; }")
try:
compiler.compile([f.name], extra_postargs=[flagname])
except setuptools.distutils.errors.CompileError:
return False
return True


def cpp_flag(compiler: CCompiler) -> str:
"""Return the -std=c++[11/14/17] compiler flag.
The newer version is prefered over c++11 (when it is available).
"""
flags = ["-std=c++11"]

for flag in flags:
if has_flag(compiler, flag):
return flag

raise RuntimeError("Unsupported compiler -- at least C++11 support is needed!")


class BuildExt(build_ext):
"""A custom build extension for adding compiler-specific options."""

if TEST_BUILD:
c_opts: Dict[str, List[str]] = {
"msvc": ["/EHsc"],
"unix": ["-O0", "-coverage", "-g"],
}
l_opts: Dict[str, List[str]] = {
"msvc": [],
"unix": ["-coverage"],
}
else:
c_opts = {
"msvc": ["/EHsc"],
"unix": [],
}
l_opts = {
"msvc": [],
"unix": [],
}

if sys.platform == "darwin":
darwin_opts = ["-stdlib=libc++", "-mmacosx-version-min=10.7"]
c_opts["unix"] += darwin_opts
l_opts["unix"] += darwin_opts

def build_extensions(self) -> None:
ct = self.compiler.compiler_type
opts = self.c_opts.get(ct, [])
link_opts = self.l_opts.get(ct, [])
if ct == "unix":
opts.append('-DVERSION_INFO="%s"' % self.distribution.get_version())
opts.append(cpp_flag(self.compiler))
if has_flag(self.compiler, "-fvisibility=hidden"):
opts.append("-fvisibility=hidden")
elif ct == "msvc":
opts.append('/DVERSION_INFO=\\"%s\\"' % self.distribution.get_version())
for ext in self.extensions:
ext.extra_compile_args = opts
ext.extra_link_args = link_opts
build_ext.build_extensions(self)


def local_scheme(version: Any) -> str:
return ""

Expand All @@ -186,17 +85,16 @@ def local_scheme(version: Any) -> str:
use_scm_version={"local_scheme": local_scheme},
author="Tomoki Ohtsuki",
url="https://github.com/tohtsky/myfm",
author_email="tomoki.[email protected]",
description="Yet another factorization machine",
author_email="tomoki.[email protected]",
description="Yet another Bayesian factorization machines.",
long_description="",
ext_modules=ext_modules,
install_requires=install_requires,
setup_requires=setup_requires,
cmdclass={"build_ext": BuildExt},
packages=find_packages("src"),
cmdclass={"build_ext": build_ext},
package_dir={"": "src"},
zip_safe=False,
headers=headers,
python_requires=">=3.6.0",
python_requires=">=3.6",
packages=find_packages("src"),
package_data={"myfm": ["*.pyi"]},
)
2 changes: 1 addition & 1 deletion src/myfm/utils/dummy_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def gen_dummy_rating_df(
user_indices_all = np.arange(max(int(size / 3), 10))
item_indices_all = np.arange(max(int(size / 2), 10))
user_factor = rns.normal(
0, 1 / factor_rank ** 0.5, size=(user_indices_all.shape[0], factor_rank)
0, 1 / factor_rank**0.5, size=(user_indices_all.shape[0], factor_rank)
)
item_factor = rns.normal(0, 1, size=(item_indices_all.shape[0], factor_rank))

Expand Down
12 changes: 6 additions & 6 deletions tests/regression/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ def test_block_vfm() -> None:
[tm_column, user_block[user_indices], item_block[item_indices]]
)
X_flatten_squread = X_flatten.copy()
X_flatten_squread.data = X_flatten_squread.data ** 2
X_flatten_squread.data = X_flatten_squread.data**2
factor = rns.randn(X_flatten.shape[1], 3)
f2 = (factor ** 2).sum(axis=1)
f2 = (factor**2).sum(axis=1)
Xf = X_flatten.dot(factor)

gb = 3.0
linear_weights = rns.randn(X_flatten.shape[1])
y = (
gb
+ X_flatten.dot(linear_weights)
+ 0.5 * ((Xf ** 2).sum(axis=1) - X_flatten_squread.dot(f2))
+ 0.5 * ((Xf**2).sum(axis=1) - X_flatten_squread.dot(f2))
+ rns.normal(1.0, size=X_flatten.shape[0])
)

Expand Down Expand Up @@ -111,12 +111,12 @@ def test_block() -> None:
[tm_column, user_block[user_indices], item_block[item_indices]]
)
X_flatten_squread = X_flatten.copy()
X_flatten_squread.data = X_flatten_squread.data ** 2
X_flatten_squread.data = X_flatten_squread.data**2

weights = rns.randn(3, X_flatten.shape[1])
Xw = X_flatten.dot(weights.T)
X2w2 = X_flatten_squread.dot((weights ** 2).sum(axis=0))
y = 0.5 * ((Xw ** 2).sum(axis=1) - X2w2) + rns.randn(N_train)
X2w2 = X_flatten_squread.dot((weights**2).sum(axis=0))
y = 0.5 * ((Xw**2).sum(axis=1) - X2w2) + rns.randn(N_train)

blocks = [
RelationBlock(user_indices, user_block),
Expand Down
4 changes: 2 additions & 2 deletions tests/regression/test_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ def test_middle_reg(
vfm_weights = vfm.predictor_.weights()
hp_trance = fm.get_hyper_trace()
last_alphs = hp_trance["alpha"].iloc[-20:].values
assert np.all(last_alphs > ((1 / alpha_inv ** 2) / 2))
assert np.all(last_alphs < ((1 / alpha_inv ** 2) * 2))
assert np.all(last_alphs > ((1 / alpha_inv**2) / 2))
assert np.all(last_alphs < ((1 / alpha_inv**2) * 2))

last_samples = fm.predictor_.samples[-20:]
assert np.all([s.w0 < stub_weight.global_bias + 0.5 for s in last_samples])
Expand Down
6 changes: 3 additions & 3 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ class FMWeights(NamedTuple):

def prediction(X: sps.csr_matrix, weight: FMWeights) -> np.ndarray:
X2 = X.copy()
X2.data[:] = X2.data ** 2
X2.data[:] = X2.data**2
result = np.zeros(X.shape[0], dtype=np.float64)
result[:] = weight.global_bias
result += X.dot(weight.weight)
w2 = (weight.factors ** 2).sum(axis=0)
w2 = (weight.factors**2).sum(axis=0)
Xw = X.dot(weight.factors.T)
result += ((Xw ** 2).sum(axis=1) - (X2.dot(w2))) * 0.5
result += ((Xw**2).sum(axis=1) - (X2.dot(w2))) * 0.5
return result

0 comments on commit b23d246

Please sign in to comment.