From 543535f3953f5a2f72818d11bd9c2055405987e6 Mon Sep 17 00:00:00 2001 From: Alexandru Fikl Date: Wed, 17 Jul 2024 15:14:46 +0300 Subject: [PATCH 1/6] pyproject: move project metadata --- pyproject.toml | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 18 ---------- setup.py | 42 ----------------------- 3 files changed, 92 insertions(+), 60 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..cf7c89f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,92 @@ +[build-system] +build-backend = "setuptools.build_meta" +requires = [ + "setuptools>=63", +] + +[project] +name = "codepy" +version = "2019.1" +description = "Generate and execute native code at run time." +readme = "README.rst" +license = { text = "MIT" } +authors = [ + { name = "Andreas Kloeckner", email = "inform@tiker.net" }, +] +requires-python = ">=3.8" +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Intended Audience :: Other Audience", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python", + "Topic :: Scientific/Engineering", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities", +] +dependencies = [ + "numpy>=1.6", + "pytools>=2022.1.14", + "platformdirs>=2.2.0", + "cgen>=2020.1" +] + +[project.optional-dependencies] +test = [ + "pytest", + "ruff", +] + +[project.urls] +Documentation = "https://documen.tician.de/codepy" +Homepage = "https://github.com/inducer/codepy" + +[tool.setuptools.packages.find] +include = [ + "codepy*", +] + +[tool.setuptools.package-data] +codepy = [ + "include/codepy/bpl.hpp", +] + +[tool.ruff] +preview = true + +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "C", # flake8-comprehensions + "E", # pycodestyle + "F", # pyflakes + "G", # flake8-logging-format + "I", # flake8-isort + "N", # pep8-naming + "Q", # flake8-quotes + "RUF", # ruff + "UP", # pyupgrade + "W", # pycodestyle +] +extend-ignore = [ + "C90", # McCabe complexity + "E226", # missing whitespace around arithmetic operator + "E241", # multiple spaces after comma + "E242", # tab after comma + "E402", # module level import not at the top of file + "UP031", # use f-strings instead of % + "UP032", # use f-strings instead of .format +] + +[tool.ruff.lint.flake8-quotes] +docstring-quotes = "double" +inline-quotes = "double" +multiline-quotes = "double" + +[tool.ruff.lint.isort] +combine-as-imports = true +known-first-party = [ "cgen", "pytools" ] +known-local-folder = [ "codepy" ] +lines-after-imports = 2 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 6b47f35..0000000 --- a/setup.cfg +++ /dev/null @@ -1,18 +0,0 @@ -[flake8] -ignore = E126,E127,E128,E123,E226,E241,E242,E265,W503,E402,B028 -max-line-length=85 - -inline-quotes = " -docstring-quotes = """ -multiline-quotes = """ - -# enable-flake8-bugbear -# enable-flake8-isort - -[isort] -known_firstparty=pytools -known_local_folder=codepy -line_length = 85 -lines_after_imports = 2 -combine_as_imports = True -multi_line_output = 4 diff --git a/setup.py b/setup.py deleted file mode 100644 index 6da6b6f..0000000 --- a/setup.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -from setuptools import find_packages, setup - - -setup( - name="codepy", - version="2019.1", - description="Generate and execute native code at run time.", - long_description=open("README.rst").read(), - classifiers=[ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "Intended Audience :: Other Audience", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: MIT License", - "Natural Language :: English", - "Programming Language :: Python", - "Topic :: Scientific/Engineering", - "Topic :: Software Development :: Libraries", - "Topic :: Utilities", - ], - author="Andreas Kloeckner", - url="http://mathema.tician.de/software/codepy", - author_email="inform@tiker.net", - license="MIT", - packages=find_packages(), - python_requires="~=3.8", - install_requires=[ - "pytools>=2015.1.2", - "numpy>=1.6", - "platformdirs>=2.2.0", - "cgen", - ], - include_package_data=True, - package_data={ - "codepy": [ - "include/codepy/*.hpp", - ] - }, - zip_safe=False, -) From de9db8a8d7d3b646fbc4b91ac49e5a2a75c0bf23 Mon Sep 17 00:00:00 2001 From: Alexandru Fikl Date: Wed, 17 Jul 2024 15:15:19 +0300 Subject: [PATCH 2/6] ruff: fix isort issues --- codepy/elementwise.py | 16 +++++++++++++--- doc/conf.py | 3 +++ examples/nvcc-test.py | 1 + test/test_identical_symbols.py | 9 ++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/codepy/elementwise.py b/codepy/elementwise.py index 1d882c1..ded7349 100644 --- a/codepy/elementwise.py +++ b/codepy/elementwise.py @@ -5,8 +5,8 @@ import numpy -from cgen import POD, Value, dtype_to_ctype +from cgen import POD, Value, dtype_to_ctype from pytools import memoize @@ -48,8 +48,18 @@ def struct_char(self): def get_elwise_module_descriptor(arguments, operation, name="kernel"): from cgen import ( - POD, Block, For, FunctionBody, FunctionDeclaration, Include, Initializer, - Line, Statement, Struct, Value) + POD, + Block, + For, + FunctionBody, + FunctionDeclaration, + Include, + Initializer, + Line, + Statement, + Struct, + Value, + ) from codepy.bpl import BoostPythonModule diff --git a/doc/conf.py b/doc/conf.py index 0da73a1..d59ea4d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,5 +1,6 @@ from urllib.request import urlopen + _conf_url = \ "https://raw.githubusercontent.com/inducer/sphinxconfig/main/sphinxconfig.py" with urlopen(_conf_url) as _inf: @@ -9,6 +10,8 @@ # The short X.Y version. import re + + ver_re = re.compile(r'version\s*=\s*"([0-9a-z.]+)"') version = [ver_re.search(line).group(1) for line in open("../setup.py").readlines() diff --git a/examples/nvcc-test.py b/examples/nvcc-test.py index 1ebf7d1..c7a32af 100644 --- a/examples/nvcc-test.py +++ b/examples/nvcc-test.py @@ -14,6 +14,7 @@ host_mod = BoostPythonModule() import math + # Are we on a 32 or 64 bit platform? import sys diff --git a/test/test_identical_symbols.py b/test/test_identical_symbols.py index 98f1678..33881e0 100644 --- a/test/test_identical_symbols.py +++ b/test/test_identical_symbols.py @@ -3,7 +3,14 @@ def make_greet_mod(greeting): from cgen import ( - Block, Const, FunctionBody, FunctionDeclaration, Pointer, Statement, Value) + Block, + Const, + FunctionBody, + FunctionDeclaration, + Pointer, + Statement, + Value, + ) from codepy.bpl import BoostPythonModule From 5729f4daa77ffb0d783e1cb37380995567c1fe8d Mon Sep 17 00:00:00 2001 From: Alexandru Fikl Date: Wed, 17 Jul 2024 15:24:45 +0300 Subject: [PATCH 3/6] ruff: fix remaining issues --- codepy/bpl.py | 16 ++++++++++------ codepy/cuda.py | 8 ++++---- codepy/elementwise.py | 21 +++++++++++++-------- codepy/jit.py | 31 ++++++++++++++++--------------- codepy/libraries.py | 12 +++++++----- codepy/toolchain.py | 24 ++++++------------------ codepy/tools.py | 2 +- doc/conf.py | 4 ++-- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/codepy/bpl.py b/codepy/bpl.py index bf39830..b4b74a8 100644 --- a/codepy/bpl.py +++ b/codepy/bpl.py @@ -110,7 +110,7 @@ def add_struct(self, member_defs = [] for f in struct.fields: py_f_name = py_member_name_transform(f.name) - tp_lines, declarator = f.get_decl_pair() + tp_lines, _ = f.get_decl_pair() if f.name in by_value_members or tp_lines[0].startswith("numpy_"): member_defs.append( ".def(pyublas::by_value_rw_member" @@ -146,11 +146,15 @@ def generate(self): else: mod_body = self.mod_body - body += ([Include("boost/python.hpp")] - + self.preamble + [Line()] - + mod_body - + [Line(), Line(f"BOOST_PYTHON_MODULE({self.name})")] - + [Block(self.init_body)]) + body += [ + Include("boost/python.hpp"), + *self.preamble, + Line(), + *mod_body, + Line(), + Line(f"BOOST_PYTHON_MODULE({self.name})"), + Block(self.init_body), + ] return Module(body) diff --git a/codepy/cuda.py b/codepy/cuda.py index ddeee5a..dad15f3 100644 --- a/codepy/cuda.py +++ b/codepy/cuda.py @@ -45,7 +45,7 @@ def generate(self): module line-by-line. """ body = [] - body += (self.preamble + [cgen.Line()] + self.body) + body += [*self.preamble, cgen.Line(), *self.body] return cgen.Module(body) def compile(self, host_toolchain, nvcc_toolchain, @@ -81,11 +81,11 @@ def compile(self, host_toolchain, nvcc_toolchain, # Don't compile shared objects, just normal objects # (on some platforms, they're different) - host_checksum, host_mod_name, host_object, host_compiled = \ + host_checksum, _host_mod_name, host_object, host_compiled = \ compile_from_string( host_toolchain, self.boost_module.name, host_code, object=True, **local_host_kwargs) - device_checksum, device_mod_name, device_object, device_compiled = \ + device_checksum, _device_mod_name, device_object, device_compiled = \ compile_from_string( nvcc_toolchain, "gpu", device_code, "gpu.cu", object=True, **local_nvcc_kwargs) @@ -101,7 +101,7 @@ def compile(self, host_toolchain, nvcc_toolchain, else: import os.path - destination_base, first_object = os.path.split(host_object) + destination_base, _ = os.path.split(host_object) module_path = os.path.join(destination_base, mod_name + host_toolchain.so_ext) try: diff --git a/codepy/elementwise.py b/codepy/elementwise.py index ded7349..2838332 100644 --- a/codepy/elementwise.py +++ b/codepy/elementwise.py @@ -171,15 +171,20 @@ def __call__(self, *args): @memoize def make_linear_comb_kernel_with_result_dtype( result_dtype, scalar_dtypes, vector_dtypes): - comp_count = len(vector_dtypes) from pytools import flatten - return ElementwiseKernel([VectorArg(result_dtype, "result")] + list(flatten( - (ScalarArg(scalar_dtypes[i], f"a{i}_fac"), - VectorArg(vector_dtypes[i], f"a{i}")) - for i in range(comp_count))), - "result[i] = " + " + ".join( - f"a{i}_fac*a{i}[i]" for i in range(comp_count) - )) + + comp_count = len(vector_dtypes) + + args = flatten( + (ScalarArg(scalar_dtypes[i], f"a{i}_fac"), + VectorArg(vector_dtypes[i], f"a{i}")) + for i in range(comp_count) + ) + return ElementwiseKernel( + [VectorArg(result_dtype, "result"), *args], + "result[i] = " + " + ".join( + f"a{i}_fac*a{i}[i]" for i in range(comp_count) + )) @memoize diff --git a/codepy/jit.py b/codepy/jit.py index 3b987dc..9e0d12a 100644 --- a/codepy/jit.py +++ b/codepy/jit.py @@ -128,8 +128,8 @@ def __init__(self, cleanup_m, cache_dir, sleep_delay=1): if attempts > 10: from warnings import warn - warn("could not obtain lock -- " - f"delete '{self.lock_file}' if necessary") + warn(f"could not obtain lock -- delete '{self.lock_file}' " + "if necessary", stacklevel=2) cleanup_m.register(self) @@ -201,16 +201,17 @@ def extension_from_string(toolchain, name, source_string, If *debug_recompile*, messages are printed indicating whether a recompilation is taking place. """ - checksum, mod_name, ext_file, recompiled = \ + _checksum, mod_name, ext_file, _recompiled = ( compile_from_string(toolchain, name, source_string, source_name, cache_dir, debug, wait_on_error, debug_recompile, - False, sleep_delay=sleep_delay) + False, sleep_delay=sleep_delay)) + # try loading it from codepy.tools import load_dynamic return load_dynamic(mod_name, ext_file) -class _InvalidInfoFile(RuntimeError): +class _InvalidInfoFileError(RuntimeError): pass @@ -280,7 +281,7 @@ def compile_from_string(toolchain, name, source_string, if wait_on_error is not None: from warnings import warn warn("wait_on_error is deprecated and has no effect", - DeprecationWarning) + DeprecationWarning, stacklevel=2) import os @@ -351,13 +352,13 @@ def load_info(info_path): try: info_file = open(info_path, "rb") - except OSError: - raise _InvalidInfoFile() + except OSError as exc: + raise _InvalidInfoFileError() from exc try: return pickle.load(info_file) - except EOFError: - raise _InvalidInfoFile() + except EOFError as exc: + raise _InvalidInfoFileError() from exc finally: info_file.close() @@ -399,7 +400,7 @@ def check_source(source_path): if not valid: from warnings import warn - warn("hash collision in compiler cache") + warn("hash collision in compiler cache", stacklevel=2) return valid cleanup_m = CleanupManager() @@ -424,7 +425,7 @@ def check_source(source_path): if mod_cache_dir_m.existed: try: info = load_info(info_path) - except _InvalidInfoFile: + except _InvalidInfoFileError: mod_cache_dir_m.reset() if debug_recompile: @@ -472,7 +473,7 @@ def link_extension(toolchain, objects, mod_name, cache_dir=None, destination = os.path.join(cache_dir, mod_name + toolchain.so_ext) else: # put the linked object in the same directory as the first object - destination_base, first_object = os.path.split(objects[0]) + destination_base, _ = os.path.split(objects[0]) destination = os.path.join( destination_base, mod_name + toolchain.so_ext) @@ -488,9 +489,9 @@ def link_extension(toolchain, objects, mod_name, cache_dir=None, return load_dynamic(mod_name, destination) -from pytools import MovedFunctionDeprecationWrapper # noqa: E402 +from pytools import MovedFunctionDeprecationWrapper -from codepy.toolchain import guess_toolchain as _gtc # noqa: E402 +from codepy.toolchain import guess_toolchain as _gtc guess_toolchain = MovedFunctionDeprecationWrapper(_gtc) diff --git a/codepy/libraries.py b/codepy/libraries.py index 7736317..2c093c4 100644 --- a/codepy/libraries.py +++ b/codepy/libraries.py @@ -99,11 +99,13 @@ def add_boost_python(toolchain): "boost-python", aksetup.get("BOOST_INC_DIR", []), aksetup.get("BOOST_LIB_DIR", []), - get_boost_libname("python-py{}{}".format(*sys.version_info[:2]), aksetup) - + ["python{}.{}{}".format( - *sys.version_info[:2], - "m" if sys.version_info[0] >= 3 else "")] - ) + [ + *get_boost_libname("python-py{}{}".format(*sys.version_info[:2]), + aksetup), + "python{}.{}{}".format( + *sys.version_info[:2], + "m" if sys.version_info[0] >= 3 else "") + ]) def add_boost_numeric_bindings(toolchain): diff --git a/codepy/toolchain.py b/codepy/toolchain.py index 624d7a8..6669032 100644 --- a/codepy/toolchain.py +++ b/codepy/toolchain.py @@ -194,10 +194,7 @@ def get_dependencies(self, source_files): line.split()[2:] for line in lines)) def build_object(self, ext_file, source_files, debug=False): - cc_cmdline = ( - self._cmdline(source_files, True) - + ["-o", ext_file] - ) + cc_cmdline = [*self._cmdline(source_files, True), "-o", ext_file] from pytools.prefork import call if debug: @@ -212,10 +209,7 @@ def build_object(self, ext_file, source_files, debug=False): raise CompileError("module compilation failed") def build_extension(self, ext_file, source_files, debug=False): - cc_cmdline = ( - self._cmdline(source_files, False) - + ["-o", ext_file] - ) + cc_cmdline = [*self._cmdline(source_files, False), "-o", ext_file] from pytools.prefork import call if debug: @@ -230,10 +224,7 @@ def build_extension(self, ext_file, source_files, debug=False): raise CompileError("module compilation failed") def link_extension(self, ext_file, object_files, debug=False): - cc_cmdline = ( - self._cmdline(object_files, False) - + ["-o", ext_file] - ) + cc_cmdline = [*self._cmdline(object_files, False), "-o", ext_file] from pytools.prefork import call if debug: @@ -290,7 +281,7 @@ def _cmdline(self, files, object=False): ) def abi_id(self): - return Toolchain.abi_id(self) + [self._cmdline([])] + return [*Toolchain.abi_id(self), self._cmdline([])] def with_optimization_level(self, level, debug=False, **extra): def remove_prefix(flags, prefix): @@ -353,13 +344,10 @@ def _cmdline(self, files, object=False): ) def abi_id(self): - return Toolchain.abi_id(self) + [self._cmdline([])] + return [*Toolchain.abi_id(self), self._cmdline([])] def build_object(self, ext_file, source_files, debug=False): - cc_cmdline = ( - self._cmdline(source_files, True) - + ["-o", ext_file] - ) + cc_cmdline = [*self._cmdline(source_files, True), "-o", ext_file] if debug: print(" ".join(cc_cmdline)) diff --git a/codepy/tools.py b/codepy/tools.py index 921e4d8..af2780f 100644 --- a/codepy/tools.py +++ b/codepy/tools.py @@ -27,7 +27,7 @@ def join_continued_lines(lines): except StopIteration: if append_line: from warnings import warn - warn("line continuation at end of file") + warn("line continuation at end of file", stacklevel=2) return result diff --git a/doc/conf.py b/doc/conf.py index d59ea4d..b7f9605 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -13,9 +13,9 @@ ver_re = re.compile(r'version\s*=\s*"([0-9a-z.]+)"') -version = [ver_re.search(line).group(1) +version = next(ver_re.search(line).group(1) for line in open("../setup.py").readlines() - if ver_re.search(line)][0] + if ver_re.search(line)) # The full version, including alpha/beta/rc tags. release = version From 9f6a88101926ceae1fcb3e2bd3ac77d651e9c9b5 Mon Sep 17 00:00:00 2001 From: Alexandru Fikl Date: Wed, 17 Jul 2024 15:27:03 +0300 Subject: [PATCH 4/6] version: use importlib --- doc/conf.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index b7f9605..0a1f88c 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,3 +1,4 @@ +from importlib import metadata from urllib.request import urlopen @@ -6,18 +7,9 @@ with urlopen(_conf_url) as _inf: exec(compile(_inf.read(), _conf_url, "exec"), globals()) -copyright = "2009-21, Andreas Kloeckner" - -# The short X.Y version. -import re - - -ver_re = re.compile(r'version\s*=\s*"([0-9a-z.]+)"') -version = next(ver_re.search(line).group(1) - for line in open("../setup.py").readlines() - if ver_re.search(line)) -# The full version, including alpha/beta/rc tags. -release = version +copyright = "2009-2024, Andreas Kloeckner" +release = metadata.version("codepy") +version = ".".join(release.split(".")[:2]) intersphinx_mapping = { "python": ("https://docs.python.org/dev", None), From ce3e06180ea8d7e7d8ab94bd894c316364c04ab4 Mon Sep 17 00:00:00 2001 From: Alexandru Fikl Date: Wed, 17 Jul 2024 15:27:52 +0300 Subject: [PATCH 5/6] ci: replace flake8 with ruff job --- .github/workflows/ci.yml | 15 +++++---------- .gitlab-ci.yml | 10 +++++----- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f10a48c..f3eca59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,21 +10,16 @@ on: - cron: '17 3 * * 0' jobs: - flake8: - name: Flake8 + ruff: + name: Ruff runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 - with: - # matches compat target in setup.py - python-version: '3.8' + - uses: actions/setup-python@v5 - name: "Main Script" run: | - curl -L -O https://gitlab.tiker.net/inducer/ci-support/raw/main/prepare-and-run-flake8.sh - . ./prepare-and-run-flake8.sh "$(basename $GITHUB_REPOSITORY)" ./test - + pip install ruff + ruff check pytest: name: Pytest on Py${{ matrix.python-version }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c31af05..af28173 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,9 +1,9 @@ -Flake8: - script: - - curl -L -O https://gitlab.tiker.net/inducer/ci-support/raw/main/prepare-and-run-flake8.sh - - ". ./prepare-and-run-flake8.sh codepy test" +Ruff: + script: | + pipx install ruff + ruff check tags: - - python3 + - docker-runner except: - tags From dbc38f721b6438b0fad7bbd8142f16984bd9af56 Mon Sep 17 00:00:00 2001 From: Alexandru Fikl Date: Wed, 17 Jul 2024 15:29:57 +0300 Subject: [PATCH 6/6] MANIFEST: ignore git files --- MANIFEST.in | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 5470a15..2842650 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,12 +1,10 @@ -include test/*.py - -include doc/source/*.rst +include doc/*.rst include doc/Makefile -include doc/source/conf.py -include doc/source/_static/*.css -include doc/source/_templates/*.html +include LICENSE include README.rst +include codepy/include/codepy/bpl.hpp -include Makefile.in -include codepy/include/codepy/*.hpp +prune .github +exclude .gitlab-ci.yml +exclude .gitignore