Skip to content
Open
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
4 changes: 3 additions & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ per-file-ignores =
mkl_fft/interfaces/scipy_fft.py: F401
mkl_fft/interfaces/numpy_fft.py: F401

exclude = _vendored/conv_template.py
exclude =
_vendored/conv_template.py
_vendored/process_src_template.py

filename = *.py, *.pyx, *.pxi, *.pxd
max_line_length = 80
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/build-with-clang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ jobs:
- name: Install Intel OneAPI
run: |
sudo apt-get install intel-oneapi-compiler-dpcpp-cpp
sudo apt-get install intel-oneapi-tbb
sudo apt-get install intel-oneapi-mkl-devel

- name: Setup Python
Expand All @@ -56,7 +55,7 @@ jobs:

- name: Install mkl_fft dependencies
run: |
pip install cython setuptools">=77"
pip install meson-python ninja cython cmake
pip install ${{ matrix.numpy_version }}

- name: List oneAPI folder content
Expand All @@ -73,5 +72,6 @@ jobs:
- name: Run mkl_fft tests
run: |
source ${{ env.ONEAPI_ROOT }}/setvars.sh
pip install scipy mkl-service pytest
pip install scipy pytest
pip install mkl-service --no-deps
pytest -s -v --pyargs mkl_fft
64 changes: 64 additions & 0 deletions .github/workflows/build-with-standard-clang.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Build project with standard clang compiler

on:
pull_request:
push:
branches: [master]

permissions: read-all

jobs:
build-with-standard-clang:
runs-on: ubuntu-latest

strategy:
matrix:
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
numpy_version: ["numpy'>=2'"]

env:
COMPILER_ROOT: /usr/bin

defaults:
run:
shell: bash -el {0}

steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@3155a141048f8f89c06b4cdae32e7853e97536bc # 0.13.0
with:
access_token: ${{ github.token }}

- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang

- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ matrix.python }}
architecture: x64

- name: Checkout repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- name: Install mkl_fft dependencies
run: |
pip install meson-python ninja cmake cython mkl-devel
pip install ${{ matrix.numpy_version }}

- name: Build mkl_fft
run: |
export CC=${{ env.COMPILER_ROOT }}/clang
pip install . --no-build-isolation --no-deps --verbose

- name: Run mkl_fft tests
run: |
pip install pytest mkl-service scipy
# mkl_fft cannot be installed in editable mode, we need
# to change directory before importing it and running tests
cd ..
python -m pytest -sv --pyargs mkl_fft
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ jobs:
use_pre: ["", "--pre"]

steps:
- name: Install jq
shell: bash -l {0}
run: |
sudo apt-get install jq

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
Expand All @@ -48,10 +43,8 @@ jobs:

- name: Build conda package
run: |
pip install --no-cache-dir cython setuptools
pip install --no-cache-dir meson-python ninja cmake cython
pip install --no-cache-dir numpy ${{ matrix.use_pre }}
echo "CONDA_PREFFIX is '${CONDA_PREFIX}'"
export MKLROOT=${CONDA_PREFIX}
pip install -e ".[test]" --no-build-isolation --verbose
pip list
python -m pytest -v mkl_fft/tests
4 changes: 1 addition & 3 deletions _vendored/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
## Vendored files

File `conv_template.py` is copied from NumPy's numpy/distutils folder, since
`numpy.distutils` is absent from the installation layout starting with
Python 3.12
Files `conv_template.py` and `process_src_template.py` are copied from NumPy's numpy/numpy/_build_utils folder
58 changes: 32 additions & 26 deletions _vendored/conv_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
__all__ = ['process_str', 'process_file']

import os
import sys
import re
import sys

# names for replacement that are already global.
global_names = {}
Expand All @@ -106,12 +106,12 @@ def parse_structure(astr, level):
at zero. Returns an empty list if no loops found.

"""
if level == 0 :
if level == 0:
loopbeg = "/**begin repeat"
loopend = "/**end repeat**/"
else :
loopbeg = "/**begin repeat%d" % level
loopend = "/**end repeat%d**/" % level
else:
loopbeg = f"/**begin repeat{level}"
loopend = f"/**end repeat{level}**/"

ind = 0
line = 0
Expand All @@ -124,9 +124,9 @@ def parse_structure(astr, level):
start2 = astr.find("\n", start2)
fini1 = astr.find(loopend, start2)
fini2 = astr.find("\n", fini1)
line += astr.count("\n", ind, start2+1)
spanlist.append((start, start2+1, fini1, fini2+1, line))
line += astr.count("\n", start2+1, fini2)
line += astr.count("\n", ind, start2 + 1)
spanlist.append((start, start2 + 1, fini1, fini2 + 1, line))
line += astr.count("\n", start2 + 1, fini2)
ind = fini2
spanlist.sort()
return spanlist
Expand All @@ -135,10 +135,13 @@ def parse_structure(astr, level):
def paren_repl(obj):
torep = obj.group(1)
numrep = obj.group(2)
return ','.join([torep]*int(numrep))
return ','.join([torep] * int(numrep))


parenrep = re.compile(r"\(([^)]*)\)\*(\d+)")
plainrep = re.compile(r"([^*]+)\*(\d+)")


def parse_values(astr):
# replaces all occurrences of '(a,b,c)*4' in astr
# with 'a,b,c,a,b,c,a,b,c,a,b,c'. Empty braces generate
Expand All @@ -155,7 +158,7 @@ def parse_values(astr):
named_re = re.compile(r"#\s*(\w*)\s*=([^#]*)#")
exclude_vars_re = re.compile(r"(\w*)=(\w*)")
exclude_re = re.compile(":exclude:")
def parse_loop_header(loophead) :
def parse_loop_header(loophead):
"""Find all named replacements in the header

Returns a list of dictionaries, one for each loop iteration,
Expand All @@ -179,14 +182,13 @@ def parse_loop_header(loophead) :
name = rep[0]
vals = parse_values(rep[1])
size = len(vals)
if nsub is None :
if nsub is None:
nsub = size
elif nsub != size :
elif nsub != size:
msg = "Mismatch in number of values, %d != %d\n%s = %s"
raise ValueError(msg % (nsub, size, name, vals))
names.append((name, vals))


# Find any exclude variables
excludes = []

Expand All @@ -200,30 +202,33 @@ def parse_loop_header(loophead) :

# generate list of dictionaries, one for each template iteration
dlist = []
if nsub is None :
if nsub is None:
raise ValueError("No substitution variables found")
for i in range(nsub):
tmp = {name: vals[i] for name, vals in names}
dlist.append(tmp)
return dlist


replace_re = re.compile(r"@(\w+)@")
def parse_string(astr, env, level, line) :
lineno = "#line %d\n" % line


def parse_string(astr, env, level, line):
lineno = f"#line {line}\n"

# local function for string replacement, uses env
def replace(match):
name = match.group(1)
try :
try:
val = env[name]
except KeyError:
msg = 'line %d: no definition of key "%s"'%(line, name)
msg = f'line {line}: no definition of key "{name}"'
raise ValueError(msg) from None
return val

code = [lineno]
struct = parse_structure(astr, level)
if struct :
if struct:
# recurse over inner loops
oldend = 0
newlevel = level + 1
Expand All @@ -234,18 +239,18 @@ def replace(match):
oldend = sub[3]
newline = line + sub[4]
code.append(replace_re.sub(replace, pref))
try :
try:
envlist = parse_loop_header(head)
except ValueError as e:
msg = "line %d: %s" % (newline, e)
msg = f"line {newline}: {e}"
raise ValueError(msg)
for newenv in envlist :
for newenv in envlist:
newenv.update(env)
newcode = parse_string(text, newenv, newlevel, newline)
code.extend(newcode)
suff = astr[oldend:]
code.append(replace_re.sub(replace, suff))
else :
else:
# replace keys
code.append(replace_re.sub(replace, astr))
code.append('\n')
Expand Down Expand Up @@ -284,8 +289,8 @@ def process_file(source):
try:
code = process_str(''.join(lines))
except ValueError as e:
raise ValueError('In "%s" loop at %s' % (sourcefile, e)) from None
return '#line 1 "%s"\n%s' % (sourcefile, code)
raise ValueError(f'In "{sourcefile}" loop at {e}') from None
return f'#line 1 "{sourcefile}"\n{code}'


def unique_key(adict):
Expand Down Expand Up @@ -321,9 +326,10 @@ def main():
try:
writestr = process_str(allstr)
except ValueError as e:
raise ValueError("In %s loop at %s" % (file, e)) from None
raise ValueError(f"In {file} loop at {e}") from None

outfile.write(writestr)


if __name__ == "__main__":
main()
66 changes: 66 additions & 0 deletions _vendored/process_src_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
import argparse
import importlib.util
import os


def get_processor():
# Convoluted because we can't import from numpy
# (numpy is not yet built)
conv_template_path = os.path.join(
os.path.dirname(__file__),
'conv_template.py'
)
spec = importlib.util.spec_from_file_location(
'conv_template', conv_template_path
)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod.process_file


def process_and_write_file(fromfile, outfile):
"""Process tempita templated file and write out the result.

The template file is expected to end in `.src`
(e.g., `.c.src` or `.h.src`).
Processing `npy_somefile.c.src` generates `npy_somefile.c`.

"""
process_file = get_processor()
content = process_file(fromfile)
with open(outfile, 'w') as f:
f.write(content)


def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"infile",
type=str,
help="Path to the input file"
)
parser.add_argument(
"-o",
"--outfile",
type=str,
help="Path to the output file"
)
parser.add_argument(
"-i",
"--ignore",
type=str,
help="An ignored input - may be useful to add a "
"dependency between custom targets",
)
args = parser.parse_args()

if not args.infile.endswith('.src'):
raise ValueError(f"Unexpected extension: {args.infile}")

outfile_abs = os.path.join(os.getcwd(), args.outfile)
process_and_write_file(args.infile, outfile_abs)


if __name__ == "__main__":
main()
3 changes: 1 addition & 2 deletions conda-recipe-cf/bld.bat
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
set MKLROOT=%PREFIX%
%PYTHON% setup.py build --force install --old-and-unmanageable
%PYTHON% -m pip install --no-build-isolation --no-deps .
if errorlevel 1 exit 1
5 changes: 1 addition & 4 deletions conda-recipe-cf/build.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
#!/bin/bash -x

# make sure that compiler has been sourced, if necessary

export MKLROOT=${PREFIX}
$PYTHON setup.py build --force install --old-and-unmanageable
$PYTHON -m pip install --no-build-isolation --no-deps .
Loading
Loading