Skip to content

Add Cython utils needed for zero-copy import and export. #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
suitesparse_graphblas/_version.py export-subst
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

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

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
8 changes: 8 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include setup.py
include README.md
include LICENSE
include suitesparse_graphblas/*.pxd
include suitesparse_graphblas/*.pyx
include suitesparse_graphblas/*.h
include versioneer.py
include suitesparse_graphblas/_version.py
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[build-system]
requires = ["setuptools", "wheel", "numpy>=1.15"]

[tool.black]
line-length = 100
37 changes: 37 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[aliases]
test=pytest

[flake8]
max-line-length = 100
exclude =
versioneer.py,
ignore =
E203, # whitespace before ':'
E231, # Multiple spaces around ","
W503, # line break before binary operator

[coverage:run]
source = suitesparse_graphblas
plugins = Cython.Coverage
omit =
suitesparse_graphblas/_version.py

[coverage:report]
# Regexes for lines to exclude from consideration
exclude_lines =
pragma: no cover

raise AssertionError
raise NotImplementedError

[versioneer]
VCS = git
style = pep440
versionfile_source = suitesparse_graphblas/_version.py
versionfile_build = suitesparse_graphblas/_version.py
tag_prefix=
parentdir_prefix=suitesparse_graphblas-

[tool:pytest]
testpaths = suitesparse_graphblas/tests

69 changes: 62 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,69 @@
from setuptools import setup, find_packages
from setuptools import setup, find_packages, Extension
from glob import glob

try:
from Cython.Build import cythonize
from Cython.Compiler.Options import get_directive_defaults

use_cython = True
except ImportError:
use_cython = False
import numpy as np
import os
import sys
import versioneer

define_macros = [("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]

if use_cython:
suffix = ".pyx"
directive_defaults = get_directive_defaults()
directive_defaults["binding"] = True
directive_defaults["language_level"] = 3
if os.environ.get("CYTHON_COVERAGE"):
directive_defaults["linetrace"] = True
define_macros.append(("CYTHON_TRACE_NOGIL", "1"))
else:
suffix = ".c"

include_dirs = [np.get_include(), os.path.join(sys.prefix, "include")]
ext_modules = [
Extension(
name[: -len(suffix)].replace("/", ".").replace("\\", "."),
[name],
include_dirs=include_dirs,
define_macros=define_macros,
)
for name in glob(f"suitesparse_graphblas/**/*{suffix}", recursive=True)
]
if use_cython:
ext_modules = cythonize(ext_modules, include_path=include_dirs)

with open("README.md") as f:
long_description = f.read()

package_data = {"suitesparse_graphblas": ["*.pyx", "*.pxd", "*.h"]}
if sys.platform == "win32":
package_data["suitesparse_graphblas"].append("*.dll")

setup(
name='suitesparse-graphblas',
version='4.0.3',
description='SuiteSparse:GraphBLAS Python bindings.',
name="suitesparse-graphblas",
version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
description="SuiteSparse:GraphBLAS Python bindings.",
long_description=long_description,
long_description_content_type="text/markdown",
packages=find_packages(),
author='Michel Pelletier, James Kitchen, Erik Welch',
author="Michel Pelletier, James Kitchen, Erik Welch",
author_email="[email protected],[email protected],[email protected]",
url="https://github.com/GraphBLAS/python-suitesparse-graphblas",
ext_modules=ext_modules,
cffi_modules=["suitesparse_graphblas/build.py:ffibuilder"],
install_requires=["cffi>=1.0.0"],
python_requires=">=3.7",
install_requires=["cffi>=1.0.0", "numpy>=1.15"],
setup_requires=["cffi>=1.0.0", "pytest-runner"],
tests_require=["pytest"],
license="Apache License 2.0",
package_data=package_data,
include_package_data=True,
)

45 changes: 44 additions & 1 deletion suitesparse_graphblas/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,44 @@
from ._graphblas import ffi, lib
from ._graphblas import ffi, lib # noqa
from . import utils
from ._version import get_versions


def is_initialized():
"""Is GraphBLAS initialized via GrB_init or GxB_init?"""
return lib.GxB_Global_Option_get(lib.GxB_MODE, ffi.new("GrB_Mode*")) != lib.GrB_PANIC


def initialize(*, blocking=False, memory_manager="numpy"):
"""Initialize GraphBLAS via GrB_init or GxB_init.

This must be called before any other GraphBLAS functions are called.
A RuntimeError will be raised if called more than once.

Parameters
----------
blocking : bool, optional
Whether to call init with GrB_BLOCKING or GrB_NONBLOCKING.
Default is False.
memory_manager : {'numpy', 'c'}, optional
Choose which malloc/free functions to use. 'numpy' uses numpy's
allocators, which makes it safe to perform zero-copy to and from numpy,
and allows Python to track memory usage via tracemalloc (if enabled).
'c' uses the default allocators. Default is 'numpy'.

The global variable `suitesparse_graphblas.is_initialized` indicates whether
GraphBLAS has been initialized.
"""
if is_initialized():
raise RuntimeError("GraphBLAS is already initialized! Unable to initialize again.")
blocking = lib.GrB_BLOCKING if blocking else lib.GrB_NONBLOCKING
memory_manager = memory_manager.lower()
if memory_manager == "numpy":
utils.call_gxb_init(ffi, lib, blocking)
elif memory_manager == "c":
lib.GrB_init(blocking)
else:
raise ValueError(f'memory_manager argument must be "numpy" or "c"; got: {memory_manager!r}')


__version__ = get_versions()["version"]
del get_versions
Loading