Skip to content
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
11 changes: 5 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,22 @@ jobs:
export LD_LIBRARY_PATH="$BOOST_ROOT/lib:$LD_LIBRARY_PATH"
test_py_project

mypy:
name: Mypy
basedpyright:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
-
uses: actions/setup-python@v5
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: "Main Script"
run: |
EXTRA_INSTALL="mypy pytest pybind11"
EXTRA_INSTALL="basedpyright pytest pybind11"
curl -L -O https://tiker.net/ci-support-v0
. ./ci-support-v0

build_py_project_in_venv
python -m mypy codepy test examples
basedpyright

docs:
name: Documentation
Expand Down
31 changes: 18 additions & 13 deletions codepy/bpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ def __init__(self,
name: str = "module",
max_arity: int | str | None = None,
use_private_namespace: bool = True) -> None:
self.name = name
self.max_arity = max_arity
self.use_private_namespace = use_private_namespace
self.name: str = name
self.max_arity: int | str | None = max_arity
self.use_private_namespace: bool = use_private_namespace

self.preamble: list[Generable] = []
self.mod_body: list[Generable] = []
self.init_body: list[Generable] = []
self.has_codepy_include = False
self.has_raw_function_include = False
self.has_codepy_include: bool = False
self.has_raw_function_include: bool = False

def add_to_init(self, body: Iterable[Generable]) -> None:
"""Add the blocks or statements contained in the iterable *body* to the
Expand Down Expand Up @@ -125,32 +125,37 @@ def add_struct(

from cgen import Block, Line, Statement, Typedef, Value

tpname = struct.tpname
if tpname is None:
raise TypeError("Struct with no name is not supported")

if py_name is None:
py_name = struct.tpname
py_name = tpname

self.mod_body.append(struct)

member_defs = []
member_defs: list[str] = []
for f in struct.fields:
if not hasattr(f, "name"):
name = getattr(f, "name", None)
if name is None:
raise TypeError(
f"Invalid type {type(f)} of struct field. Only named fields "
"are supported for code generation")

py_f_name = py_member_name_transform(f.name)
py_f_name = py_member_name_transform(name)
tp_lines, _ = f.get_decl_pair()
if f.name in by_value_members or tp_lines[0].startswith("numpy_"):
if name in by_value_members or tp_lines[0].startswith("numpy_"):
member_defs.append(
".def(pyublas::by_value_rw_member"
f'("{py_f_name}", &cl::{f.name}))')
f'("{py_f_name}", &cl::{name}))')
else:
member_defs.append(
f'.def_readwrite("{py_f_name}", &cl::{f.name})'
f'.def_readwrite("{py_f_name}", &cl::{name})'
)

self.init_body.append(
Block([
Typedef(Value(struct.tpname, "cl")),
Typedef(Value(tpname, "cl")),
Line(),
Statement(
'boost::python::class_<cl>("{}"){}'.format(
Expand Down
6 changes: 3 additions & 3 deletions codepy/cuda.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ def __init__(self,
CUDA code to be compiled by nvcc, as well as bridges between the CUDA
code and the BoostPythonModule.
"""
self.name = name
self.name: str = name

self.preamble: list[cgen.Generable] = []
self.body: list[cgen.Generable] = []
self.boost_module = boost_module
self.boost_module: BoostPythonModule = boost_module
self.boost_module.add_to_preamble([cgen.Include("cuda.h")])

def add_to_preamble(self, pa: Iterable[cgen.Generable]) -> None:
Expand All @@ -53,7 +53,7 @@ def generate(self) -> cgen.Module:
"""Generate (i.e. yield) the source code of the
module line-by-line.
"""
body = []
body: list[cgen.Generable] = []
body += [*self.preamble, cgen.Line(), *self.body]
return cgen.Module(body)

Expand Down
21 changes: 15 additions & 6 deletions codepy/elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import Any

import numpy as np
from typing_extensions import override

from cgen import POD, Declarator, Value, dtype_to_ctype
from pytools import memoize
Expand All @@ -18,8 +19,8 @@

class Argument(ABC):
def __init__(self, dtype: Any, name: str) -> None:
self.dtype = np.dtype(dtype)
self.name = name
self.dtype: np.dtype[Any] = np.dtype(dtype)
self.name: str = name

@abstractmethod
def declarator(self) -> Declarator:
Expand All @@ -34,6 +35,7 @@ def arg_name(self) -> str:
def struct_char(self) -> str:
pass

@override
def __repr__(self) -> str:
return "{}({!r}, {})".format(
self.__class__.__name__,
Expand All @@ -42,27 +44,33 @@ def __repr__(self) -> str:


class VectorArg(Argument):
@override
def declarator(self) -> Value:
return Value(
"numpy_array<{} >".format(dtype_to_ctype(self.dtype)),
f"{self.name}_ary")

@override
def arg_name(self) -> str:
return f"{self.name}_ary"

@property
@override
def struct_char(self) -> str:
return "P"


class ScalarArg(Argument):
@override
def declarator(self) -> POD:
return POD(self.dtype, self.name)

@override
def arg_name(self) -> str:
return self.name

@property
@override
def struct_char(self) -> str:
return str(self.dtype.char)

Expand Down Expand Up @@ -164,11 +172,12 @@ def __init__(self,
operation: str,
name: str = "kernel",
toolchain: Toolchain | None = None) -> None:
self.arguments = arguments
self.module = get_elwise_module_binary(arguments, operation, name, toolchain)
self.func = getattr(self.module, name)
self.arguments: tuple[Argument, ...] = tuple(arguments)
self.module: ModuleType = (
get_elwise_module_binary(arguments, operation, name, toolchain))
self.func: Callable[..., Any] = getattr(self.module, name)

self.vec_arg_indices = [
self.vec_arg_indices: list[int] = [
i for i, arg in enumerate(arguments)
if isinstance(arg, VectorArg)]

Expand Down
67 changes: 33 additions & 34 deletions codepy/jit.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,25 @@
"""

import logging
import os
from abc import ABC, abstractmethod
from dataclasses import dataclass
from types import ModuleType
from typing import Any, NamedTuple

from typing_extensions import override

from codepy.toolchain import GCCLikeToolchain, Toolchain


logger = logging.getLogger(__name__)


def _erase_dir(dir: str) -> None:
from os import listdir, rmdir, unlink
from os.path import join

for name in listdir(dir):
unlink(join(dir, name))
for name in os.listdir(dir):
os.unlink(os.path.join(dir, name))

rmdir(dir)
os.rmdir(dir)


def extension_file_from_string(
Expand All @@ -70,11 +70,9 @@ def extension_file_from_string(
from tempfile import mkdtemp
src_dir = mkdtemp()

from os.path import join

source_file = join(src_dir, source_name)
source_file = os.path.join(src_dir, source_name)
with open(source_file, "w") as outf:
outf.write(str(source_string))
_ = outf.write(str(source_string))

try:
toolchain.build_extension(ext_file, [source_file], debug=debug)
Expand All @@ -99,10 +97,12 @@ def __init__(self) -> None:
def register(self, c: CleanupBase) -> None:
self.cleanups.insert(0, c)

@override
def clean_up(self) -> None:
for c in self.cleanups:
c.clean_up()

@override
def error_clean_up(self) -> None:
for c in self.cleanups:
c.error_clean_up()
Expand All @@ -111,34 +111,35 @@ def error_clean_up(self) -> None:
class TempDirManager(CleanupBase):
def __init__(self, cleanup_m: CleanupManager) -> None:
from tempfile import mkdtemp
self.path = mkdtemp()

self.path: str = mkdtemp()
cleanup_m.register(self)

def sub(self, n: str) -> str:
from os.path import join
return join(self.path, n)
return os.path.join(self.path, n)

@override
def clean_up(self) -> None:
_erase_dir(self.path)

@override
def error_clean_up(self) -> None:
pass


class CacheLockManager(CleanupBase):
def __init__(self,
cleanup_m: CleanupManager,
cache_dir: str,
cache_dir: str | None = None,
sleep_delay: int = 1) -> None:
import os

if cache_dir is not None:
self.lock_file = os.path.join(cache_dir, "lock")
self.lock_file: str = os.path.join(cache_dir, "lock")

attempts = 0
while True:
try:
self.fd = os.open(self.lock_file,
self.fd: int = os.open(
self.lock_file,
os.O_CREAT | os.O_WRONLY | os.O_EXCL)
break
except OSError:
Expand All @@ -156,39 +157,40 @@ def __init__(self,

cleanup_m.register(self)

@override
def clean_up(self) -> None:
import os
os.close(self.fd)
os.unlink(self.lock_file)

@override
def error_clean_up(self) -> None:
pass


class ModuleCacheDirManager(CleanupBase):
def __init__(self, cleanup_m: CleanupManager, path: str) -> None:
from os import mkdir

self.path = path
try:
mkdir(self.path)
os.mkdir(path)
cleanup_m.register(self)
self.existed = False
existed = False
except OSError:
self.existed = True
existed = True

self.path: str = path
self.existed: bool = existed

def sub(self, n: str) -> str:
from os.path import join
return join(self.path, n)
return os.path.join(self.path, n)

def reset(self) -> None:
import os
_erase_dir(self.path)
os.mkdir(self.path)

@override
def clean_up(self) -> None:
pass

@override
def error_clean_up(self) -> None:
_erase_dir(self.path)

Expand Down Expand Up @@ -311,8 +313,6 @@ def compile_from_string(
if isinstance(source_name, str):
source_name = [source_name]

import os

if cache_dir is None:
import sys

Expand Down Expand Up @@ -347,7 +347,7 @@ def get_dep_structure(source_paths: list[str]) -> list[_Dependency]:
def write_source(name: list[str]) -> None:
for i, source in enumerate(source_string):
with open(name[i], "w" if not source_is_binary else "wb") as outf:
outf.write(source)
_ = outf.write(source)

def calculate_hex_checksum() -> str:
import hashlib
Expand Down Expand Up @@ -424,7 +424,7 @@ def check_source(source_path: list[str]) -> bool:
try:
# Variable 'lock_m' is used for no other purpose than
# to keep lock manager alive.
lock_m = CacheLockManager(cleanup_m, cache_dir, sleep_delay) # noqa
lock_m = CacheLockManager(cleanup_m, cache_dir, sleep_delay) # noqa: F841 # pyright: ignore[reportUnusedVariable]

hex_checksum = calculate_hex_checksum()
mod_name = f"codepy.temp.{hex_checksum}.{name}"
Expand Down Expand Up @@ -465,7 +465,7 @@ def check_source(source_path: list[str]) -> bool:
else:
toolchain.build_extension(ext_file, source_paths, debug=debug)

if info_path is not None:
if info_path:
import pickle

with open(info_path, "wb") as info_file:
Expand All @@ -491,7 +491,6 @@ def link_extension(
if not isinstance(toolchain, GCCLikeToolchain):
raise TypeError(f"Unsupported toolchain type: {type(toolchain)}")

import os.path
if cache_dir is not None:
destination = os.path.join(cache_dir, mod_name + toolchain.so_ext)
else:
Expand Down
Loading
Loading