Skip to content

Commit 09eb560

Browse files
authored
Merge pull request #9 from eriknw/cython_utils
Add Cython utils needed for zero-copy import and export.
2 parents 620bf5d + 225fb81 commit 09eb560

14 files changed

+2707
-29
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
suitesparse_graphblas/_version.py export-subst

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright 2021 Anaconda Inc., Graphegon, and contributors
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

MANIFEST.in

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
include setup.py
2+
include README.md
3+
include LICENSE
4+
include suitesparse_graphblas/*.pxd
5+
include suitesparse_graphblas/*.pyx
6+
include suitesparse_graphblas/*.h
7+
include versioneer.py
8+
include suitesparse_graphblas/_version.py

pyproject.toml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[build-system]
2+
requires = ["setuptools", "wheel", "numpy>=1.15"]
3+
4+
[tool.black]
5+
line-length = 100

setup.cfg

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[aliases]
2+
test=pytest
3+
4+
[flake8]
5+
max-line-length = 100
6+
exclude =
7+
versioneer.py,
8+
ignore =
9+
E203, # whitespace before ':'
10+
E231, # Multiple spaces around ","
11+
W503, # line break before binary operator
12+
13+
[coverage:run]
14+
source = suitesparse_graphblas
15+
plugins = Cython.Coverage
16+
omit =
17+
suitesparse_graphblas/_version.py
18+
19+
[coverage:report]
20+
# Regexes for lines to exclude from consideration
21+
exclude_lines =
22+
pragma: no cover
23+
24+
raise AssertionError
25+
raise NotImplementedError
26+
27+
[versioneer]
28+
VCS = git
29+
style = pep440
30+
versionfile_source = suitesparse_graphblas/_version.py
31+
versionfile_build = suitesparse_graphblas/_version.py
32+
tag_prefix=
33+
parentdir_prefix=suitesparse_graphblas-
34+
35+
[tool:pytest]
36+
testpaths = suitesparse_graphblas/tests
37+

setup.py

+62-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,69 @@
1-
from setuptools import setup, find_packages
1+
from setuptools import setup, find_packages, Extension
2+
from glob import glob
3+
4+
try:
5+
from Cython.Build import cythonize
6+
from Cython.Compiler.Options import get_directive_defaults
7+
8+
use_cython = True
9+
except ImportError:
10+
use_cython = False
11+
import numpy as np
12+
import os
13+
import sys
14+
import versioneer
15+
16+
define_macros = [("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]
17+
18+
if use_cython:
19+
suffix = ".pyx"
20+
directive_defaults = get_directive_defaults()
21+
directive_defaults["binding"] = True
22+
directive_defaults["language_level"] = 3
23+
if os.environ.get("CYTHON_COVERAGE"):
24+
directive_defaults["linetrace"] = True
25+
define_macros.append(("CYTHON_TRACE_NOGIL", "1"))
26+
else:
27+
suffix = ".c"
28+
29+
include_dirs = [np.get_include(), os.path.join(sys.prefix, "include")]
30+
ext_modules = [
31+
Extension(
32+
name[: -len(suffix)].replace("/", ".").replace("\\", "."),
33+
[name],
34+
include_dirs=include_dirs,
35+
define_macros=define_macros,
36+
)
37+
for name in glob(f"suitesparse_graphblas/**/*{suffix}", recursive=True)
38+
]
39+
if use_cython:
40+
ext_modules = cythonize(ext_modules, include_path=include_dirs)
41+
42+
with open("README.md") as f:
43+
long_description = f.read()
44+
45+
package_data = {"suitesparse_graphblas": ["*.pyx", "*.pxd", "*.h"]}
46+
if sys.platform == "win32":
47+
package_data["suitesparse_graphblas"].append("*.dll")
248

349
setup(
4-
name='suitesparse-graphblas',
5-
version='4.0.3',
6-
description='SuiteSparse:GraphBLAS Python bindings.',
50+
name="suitesparse-graphblas",
51+
version=versioneer.get_version(),
52+
cmdclass=versioneer.get_cmdclass(),
53+
description="SuiteSparse:GraphBLAS Python bindings.",
54+
long_description=long_description,
55+
long_description_content_type="text/markdown",
756
packages=find_packages(),
8-
author='Michel Pelletier, James Kitchen, Erik Welch',
57+
author="Michel Pelletier, James Kitchen, Erik Welch",
58+
59+
url="https://github.com/GraphBLAS/python-suitesparse-graphblas",
60+
ext_modules=ext_modules,
961
cffi_modules=["suitesparse_graphblas/build.py:ffibuilder"],
10-
install_requires=["cffi>=1.0.0"],
62+
python_requires=">=3.7",
63+
install_requires=["cffi>=1.0.0", "numpy>=1.15"],
1164
setup_requires=["cffi>=1.0.0", "pytest-runner"],
1265
tests_require=["pytest"],
66+
license="Apache License 2.0",
67+
package_data=package_data,
68+
include_package_data=True,
1369
)
14-

suitesparse_graphblas/__init__.py

+44-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,44 @@
1-
from ._graphblas import ffi, lib
1+
from ._graphblas import ffi, lib # noqa
2+
from . import utils
3+
from ._version import get_versions
4+
5+
6+
def is_initialized():
7+
"""Is GraphBLAS initialized via GrB_init or GxB_init?"""
8+
return lib.GxB_Global_Option_get(lib.GxB_MODE, ffi.new("GrB_Mode*")) != lib.GrB_PANIC
9+
10+
11+
def initialize(*, blocking=False, memory_manager="numpy"):
12+
"""Initialize GraphBLAS via GrB_init or GxB_init.
13+
14+
This must be called before any other GraphBLAS functions are called.
15+
A RuntimeError will be raised if called more than once.
16+
17+
Parameters
18+
----------
19+
blocking : bool, optional
20+
Whether to call init with GrB_BLOCKING or GrB_NONBLOCKING.
21+
Default is False.
22+
memory_manager : {'numpy', 'c'}, optional
23+
Choose which malloc/free functions to use. 'numpy' uses numpy's
24+
allocators, which makes it safe to perform zero-copy to and from numpy,
25+
and allows Python to track memory usage via tracemalloc (if enabled).
26+
'c' uses the default allocators. Default is 'numpy'.
27+
28+
The global variable `suitesparse_graphblas.is_initialized` indicates whether
29+
GraphBLAS has been initialized.
30+
"""
31+
if is_initialized():
32+
raise RuntimeError("GraphBLAS is already initialized! Unable to initialize again.")
33+
blocking = lib.GrB_BLOCKING if blocking else lib.GrB_NONBLOCKING
34+
memory_manager = memory_manager.lower()
35+
if memory_manager == "numpy":
36+
utils.call_gxb_init(ffi, lib, blocking)
37+
elif memory_manager == "c":
38+
lib.GrB_init(blocking)
39+
else:
40+
raise ValueError(f'memory_manager argument must be "numpy" or "c"; got: {memory_manager!r}')
41+
42+
43+
__version__ = get_versions()["version"]
44+
del get_versions

0 commit comments

Comments
 (0)