Skip to content

Commit 78f47cb

Browse files
authored
Fix build components (#10)
* Deprecate setup.py build and transit to pyproject. * Fix some tests * Fix dependencies * Add build command to makefile
1 parent 8f6ae94 commit 78f47cb

File tree

10 files changed

+301
-68
lines changed

10 files changed

+301
-68
lines changed

Diff for: .coveragerc

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[report]
2+
show_missing=true

Diff for: .github/workflows/python-package.yml

+17-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2-
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3-
41
name: Python package
52

63
on:
@@ -12,34 +9,45 @@ on:
129
jobs:
1310
build:
1411

15-
runs-on: ubuntu-latest
12+
runs-on: ${{ matrix.os }}
1613
strategy:
1714
fail-fast: false
1815
matrix:
19-
python-version: ["3.10", "3.11"]
16+
os: [ubuntu-latest, windows-latest]
17+
python-version: ["3.10", "3.11", "3.12"]
2018

2119
steps:
2220
- uses: actions/checkout@v3
21+
2322
- name: Set up Python ${{ matrix.python-version }}
2423
uses: actions/setup-python@v3
2524
with:
2625
python-version: ${{ matrix.python-version }}
26+
2727
- name: Install dependencies
2828
run: |
2929
make install
30+
3031
- name: Check code style with black
3132
run: |
3233
make code-style
34+
3335
- name: Check import order with isort
3436
run: |
3537
make import-check
38+
3639
- name: Lint with flake8
3740
run: |
3841
make linting
42+
3943
- name: Check static type checking with mypy
4044
run: |
4145
make typecheck
42-
# FIXME when C backend will be added to CI cache
43-
# - name: Test with pytest
44-
# run: |
45-
# make tests
46+
47+
- name: Test with pytest
48+
run: |
49+
make tests
50+
51+
- name: Test package build
52+
run: |
53+
make build

Diff for: Makefile

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ install :
2121
pip-compile requirements.txt -o final_requirements.txt --allow-unsafe --rebuild --verbose
2222
pip install -e . -r final_requirements.txt
2323

24+
.PHONY : build
25+
build :
26+
python -m build
27+
2428
# Testing
2529

2630
.PHONY : code-style
@@ -41,7 +45,10 @@ typecheck :
4145

4246
.PHONY : tests
4347
tests :
44-
pytest --color=yes -v -rf
48+
pytest --color=yes -v -rf --durations=40 \
49+
--cov-config=.coveragerc \
50+
--cov=$(SRC) \
51+
--cov-report=html
4552

4653
# Cleaning
4754

Diff for: arrayfire_wrapper/defines.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,26 @@
55
from dataclasses import dataclass
66
from typing import Type, TypeVar
77

8+
# def is_arch_x86() -> bool:
9+
# machine = platform.machine()
10+
# return platform.architecture()[0][0:2] == "32" and (machine[-2:] == "86" or machine[0:3] == "arm")
811

12+
13+
# BUG
914
def is_arch_x86() -> bool:
15+
"""
16+
Check if the current system architecture is 32-bit and either x86 or ARM.
17+
18+
Returns:
19+
bool: True if the architecture is 32-bit and x86 or ARM, False otherwise.
20+
"""
21+
architecture_bits, _ = platform.architecture()
1022
machine = platform.machine()
11-
return platform.architecture()[0][0:2] == "32" and (machine[-2:] == "86" or machine[0:3] == "arm")
23+
24+
is_32_bit = architecture_bits.startswith("32")
25+
is_x86_or_arm = machine.endswith("86") or machine.startswith("arm")
26+
27+
return is_32_bit and is_x86_or_arm
1228

1329

1430
# Define a generic type variable for the base class
@@ -51,6 +67,6 @@ def __repr__(self) -> str:
5167
return f"{self.__class__.__name__}{self.x1, self.x2, self.x3, self.x4}"
5268

5369
@property
54-
def c_array(self): # type: ignore[no-untyped-def]
70+
def c_array(self) -> ctypes.Array:
5571
c_shape = CDimT * 4 # ctypes.c_int | ctypes.c_longlong * 4
5672
return c_shape(CDimT(self.x1), CDimT(self.x2), CDimT(self.x3), CDimT(self.x4))

Diff for: arrayfire_wrapper/dtypes.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,6 @@ def __repr__(self) -> str:
6868
)
6969

7070

71-
def is_complex_dtype(dtype: Dtype) -> _python_bool:
72-
return dtype in {complex32, complex64}
73-
74-
7571
def to_str(c_str: ctypes.c_char_p | ctypes.Array[ctypes.c_char]) -> str:
7672
return str(c_str.value.decode("utf-8")) # type: ignore[union-attr]
7773

@@ -88,11 +84,15 @@ def implicit_dtype(number: int | float | _python_bool | complex, array_dtype: Dt
8884
else:
8985
raise TypeError(f"{type(number)} is not supported and can not be converted to af.Dtype.")
9086

87+
if array_dtype not in supported_dtypes:
88+
raise ValueError(f"{array_dtype} is not in supported dtypes.")
89+
9190
if not (array_dtype == float32 or array_dtype == complex32):
9291
return number_dtype
9392

94-
if number_dtype == float64:
95-
return float32
93+
# FIXME
94+
# if number_dtype == float64:
95+
# return float32
9696

9797
if number_dtype == complex64:
9898
return complex64

Diff for: dev-requirements.txt

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
# Testing-related packages
22

33
# Checks style, syntax, etc.
4-
flake8>=4.0.1
4+
flake8>=6.1.0
55

66
# Static type checking
7-
mypy==1.3.0
7+
mypy==1.7.1
88

99
# Check import order style
10-
isort>=5.10.1
10+
isort>=5.13.2
1111

1212
# Automatic code formatting
13-
black>=23.3.0
13+
black>=23.12.0
1414

1515
# Allows generation of coverage reports with pytest.
16-
pytest-cov>=3.0.0
16+
pytest>=7.4.3
17+
pytest-cov>=4.1.0
18+
pytest-mock>=3.11.1
1719

1820
# Allows codecov to generate coverage reports
1921
coverage[toml]>=6.4
2022
codecov>=2.1.12
2123

22-
# Package-related packages
24+
# Package building
2325
build>=1.0.3
24-
setuptools
25-
wheel
26+
27+
# Package publishing
28+
twine>=4.0.2

Diff for: pyproject.toml

+50-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,54 @@ exclude = '''
1919
'''
2020

2121
[build-system]
22-
requires = ["setuptools", "wheel", "scikit-build", "cmake", "ninja"]
22+
requires = [
23+
"setuptools >= 68.0",
24+
"wheel >= 0.38.4",
25+
"scikit-build >= 0.17.6",
26+
"cmake >= 3.28.1",
27+
]
2328
build-backend = "setuptools.build_meta"
29+
30+
[tool.setuptools.dynamic]
31+
version = { attr = "arrayfire_wrapper.__version__" }
32+
33+
[project]
34+
name = "arrayfire-python-wrapper"
35+
dynamic = ["version"]
36+
requires-python = ">=3.10"
37+
authors = [
38+
{ name = "Anton Chernyatevich", email = "[email protected]" },
39+
]
40+
maintainers = [{ name = "ArrayFire", email = "[email protected]" }]
41+
description = "ArrayFire Python Wrapper"
42+
readme = "README.md"
43+
license = { file = "LICENCE" }
44+
keywords = [
45+
"arrayfire",
46+
"c",
47+
"python",
48+
"wrapper",
49+
"parallel computing",
50+
"gpu",
51+
"cpu",
52+
"opencl",
53+
"oneapi",
54+
]
55+
classifiers = [
56+
"Intended Audience :: Science/Research",
57+
"Intended Audience :: Developers",
58+
"Development Status :: 4 - Beta",
59+
"License :: OSI Approved :: BSD License",
60+
"Programming Language :: Python",
61+
"Programming Language :: Python :: 3",
62+
"Programming Language :: Python :: 3.10",
63+
"Topic :: Scientific/Engineering",
64+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
65+
"Topic :: Scientific/Engineering :: Information Analysis",
66+
"Topic :: Scientific/Engineering :: Mathematics",
67+
"Topic :: Software Development :: Libraries",
68+
]
69+
70+
[project.urls]
71+
Website = "http://arrayfire.com"
72+
"General Documentation" = "https://arrayfire.org/docs/index.htm"

Diff for: setup.py

-39
This file was deleted.

Diff for: tests/test_defines.py

+72-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,78 @@
11
import ctypes
2+
from unittest.mock import patch
23

3-
from arrayfire_wrapper.defines import AFArray
4+
import pytest
5+
6+
from arrayfire_wrapper.defines import AFArray, ArrayBuffer, CDimT, CShape, _AFBase, is_arch_x86
47

58

69
def test_null_pointer_value() -> None:
710
assert AFArray.create_null_pointer().value == AFArray(0).value == ctypes.c_void_p(0).value
11+
12+
13+
def test_af_base_create_null_pointer() -> None:
14+
af_base = _AFBase()
15+
null_pointer = af_base.create_null_pointer()
16+
assert isinstance(null_pointer, _AFBase)
17+
18+
19+
def test_af_array_create_null_pointer() -> None:
20+
af_array = AFArray()
21+
null_pointer = af_array.create_null_pointer()
22+
assert isinstance(null_pointer, AFArray)
23+
24+
25+
def test_array_buffer_creation() -> None:
26+
array_buffer = ArrayBuffer(address=0x1000, length=10)
27+
28+
assert array_buffer.address == 0x1000
29+
assert array_buffer.length == 10
30+
31+
32+
def test_array_buffer_immutable() -> None:
33+
array_buffer = ArrayBuffer(address=0x2000, length=5)
34+
35+
with pytest.raises(AttributeError):
36+
array_buffer.address = 0x3000 # type: ignore[misc]
37+
38+
with pytest.raises(AttributeError):
39+
array_buffer.length = 8 # type: ignore[misc]
40+
41+
42+
def test_cshape_creation() -> None:
43+
c_shape = CShape(1, 2, 3, 4)
44+
assert c_shape.x1 == 1
45+
assert c_shape.x2 == 2
46+
assert c_shape.x3 == 3
47+
assert c_shape.x4 == 4
48+
49+
50+
def test_cshape_repr() -> None:
51+
c_shape = CShape(1, 2, 3, 4)
52+
assert repr(c_shape) == "CShape(1, 2, 3, 4)"
53+
54+
55+
def test_cshape_c_array() -> None:
56+
c_shape = CShape(1, 2, 3, 4)
57+
c_array = c_shape.c_array
58+
assert isinstance(c_array, ctypes.Array)
59+
assert len(c_array) == 4
60+
assert c_array[0] == CDimT(1).value
61+
assert c_array[1] == CDimT(2).value
62+
assert c_array[2] == CDimT(3).value
63+
assert c_array[3] == CDimT(4).value
64+
65+
66+
@pytest.mark.parametrize(
67+
"architecture, machine, expected_result",
68+
[
69+
("32bit", "x86", True),
70+
("32bit", "arm", True),
71+
("64bit", "x86", False),
72+
("32bit", "other", False),
73+
("64bit", "other", False),
74+
],
75+
)
76+
def test_is_arch_x86(architecture: str, machine: str, expected_result: bool) -> None:
77+
with patch("platform.architecture", lambda: (architecture, "")), patch("platform.machine", lambda: machine):
78+
assert is_arch_x86() == expected_result

0 commit comments

Comments
 (0)