From 09743d0f97d81fdbf8c6d0bd34ca6c1d1e0b21b3 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 9 Jul 2024 11:10:00 -0500 Subject: [PATCH] Switch to, configure ruff, fix lint --- .github/workflows/ci.yml | 13 ++-- .gitlab-ci.yml | 8 +-- doc/conf.py | 1 - doc/tutorial.rst | 9 +-- loopy/auto_test.py | 2 +- loopy/cli.py | 6 +- loopy/codegen/loop.py | 4 +- loopy/diagnostic.py | 10 ++-- loopy/frontend/fortran/__init__.py | 5 +- loopy/frontend/fortran/translator.py | 2 +- loopy/frontend/fortran/tree.py | 2 +- loopy/kernel/array.py | 5 +- loopy/kernel/data.py | 2 +- loopy/kernel/tools.py | 6 +- loopy/library/reduction.py | 2 +- loopy/match.py | 2 +- loopy/options.py | 4 +- loopy/preprocess.py | 4 +- loopy/statistics.py | 10 ++-- loopy/symbolic.py | 2 +- loopy/target/c/codegen/expression.py | 2 +- loopy/target/c/compyte | 2 +- loopy/target/execution.py | 2 +- loopy/target/pyopencl.py | 2 +- loopy/transform/arithmetic.py | 2 +- loopy/transform/data.py | 18 +++--- loopy/transform/iname.py | 2 +- loopy/transform/precompute.py | 4 +- loopy/transform/realize_reduction.py | 15 ++--- loopy/type_inference.py | 4 +- loopy/types.py | 2 +- pyproject.toml | 88 ++++++++++++++++++++++++++++ setup.cfg | 66 --------------------- setup.py | 2 +- test/gnuma_loopy_transforms.py | 2 +- test/test_apps.py | 2 +- test/test_expression.py | 5 +- test/test_loopy.py | 4 +- test/test_misc.py | 10 ++-- test/test_reduction.py | 2 +- test/test_statistics.py | 4 +- test/test_target.py | 2 +- 42 files changed, 176 insertions(+), 165 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.cfg diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86afce8a2..32707fe86 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,20 +8,17 @@ 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' + submodules: true - 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 examples proto-tests contrib + pipx install ruff + ruff check pylint: name: Pylint diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3b9817a2b..2c314752e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -147,12 +147,12 @@ Documentation: tags: - python3 -Flake8: +Ruff: script: - - curl -L -O https://gitlab.tiker.net/inducer/ci-support/raw/main/prepare-and-run-flake8.sh - - . ./prepare-and-run-flake8.sh "$CI_PROJECT_NAME" test examples + - pipx install ruff + - ruff check tags: - - python3 + - docker-runner except: - tags diff --git a/doc/conf.py b/doc/conf.py index 98c0fc02a..d31748d6d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -31,7 +31,6 @@ intersphinx_mapping = { "pyopencl": ("https://documen.tician.de/pyopencl", None), "cgen": ("https://documen.tician.de/cgen", None), "pymbolic": ("https://documen.tician.de/pymbolic", None), - "pytools": ("https://documen.tician.de/pytools", None), "pyrsistent": ("https://pyrsistent.readthedocs.io/en/latest/", None), } diff --git a/doc/tutorial.rst b/doc/tutorial.rst index 269dfdb5f..a697bed30 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -242,6 +242,7 @@ inspect that code, too, using :attr:`loopy.Options.write_wrapper`: if n is None: if a is not None: n = a.shape[0] + elif out is not None: n = out.shape[0] @@ -1630,7 +1631,6 @@ together into keys containing only the specified fields: >>> op_map_dtype = op_map.group_by('dtype') >>> print(op_map_dtype) Op(np:dtype('float32'), None, None): ... - >>> f32op_count = op_map_dtype[lp.Op(dtype=np.float32) ... ].eval_with_dict(param_dict) >>> print(f32op_count) @@ -1656,7 +1656,6 @@ we'll continue using the kernel from the previous example: >>> mem_map = lp.get_mem_access_map(knl, subgroup_size=32) >>> print(mem_map) MemAccess(global, np:dtype('float32'), {}, {}, load, a, None, subgroup, 'stats_knl'): ... - Each line of output will look roughly like:: @@ -1727,13 +1726,11 @@ using :func:`loopy.ToCountMap.to_bytes` and :func:`loopy.ToCountMap.group_by`: >>> bytes_map = mem_map.to_bytes() >>> print(bytes_map) MemAccess(global, np:dtype('float32'), {}, {}, load, a, None, subgroup, 'stats_knl'): ... - >>> global_ld_st_bytes = bytes_map.filter_by(mtype=['global'] ... ).group_by('direction') >>> print(global_ld_st_bytes) MemAccess(None, None, None, None, load, None, None, None, None): ... MemAccess(None, None, None, None, store, None, None, None, None): ... - >>> loaded = global_ld_st_bytes[lp.MemAccess(direction='load') ... ].eval_with_dict(param_dict) >>> stored = global_ld_st_bytes[lp.MemAccess(direction='store') @@ -1775,7 +1772,6 @@ this time. MemAccess(global, np:dtype('float64'), {0: 1, 1: 128}, {}, load, g, None, workitem, 'stats_knl'): ... MemAccess(global, np:dtype('float64'), {0: 1, 1: 128}, {}, load, h, None, workitem, 'stats_knl'): ... MemAccess(global, np:dtype('float64'), {0: 1, 1: 128}, {}, store, e, None, workitem, 'stats_knl'): ... - With this parallelization, consecutive work-items will access consecutive array elements in memory. The polynomials are a bit more complicated now due to the @@ -1820,7 +1816,6 @@ we'll switch the inner and outer tags in our parallelization of the kernel: MemAccess(global, np:dtype('float64'), {0: 128, 1: 1}, {}, load, g, None, workitem, 'stats_knl'): ... MemAccess(global, np:dtype('float64'), {0: 128, 1: 1}, {}, load, h, None, workitem, 'stats_knl'): ... MemAccess(global, np:dtype('float64'), {0: 128, 1: 1}, {}, store, e, None, workitem, 'stats_knl'): ... - With this parallelization, consecutive work-items will access *nonconsecutive* array elements in memory. The total number of array accesses still has not @@ -1873,7 +1868,6 @@ kernel from the previous example: >>> sync_map = lp.get_synchronization_map(knl) >>> print(sync_map) Sync(kernel_launch, stats_knl): [l, m, n] -> { 1 } - We can evaluate this polynomial using :meth:`islpy.PwQPolynomial.eval_with_dict`: @@ -1934,7 +1928,6 @@ count the barriers using :func:`loopy.get_synchronization_map`: >>> print(sync_map) Sync(barrier_local, loopy_kernel): { 1000 } Sync(kernel_launch, loopy_kernel): { 1 } - Based on the kernel code printed above, we would expect each work-item to encounter 50x10x2 barriers, which matches the result from diff --git a/loopy/auto_test.py b/loopy/auto_test.py index 2b5ccb54d..2ac138f58 100644 --- a/loopy/auto_test.py +++ b/loopy/auto_test.py @@ -364,7 +364,7 @@ def _enumerate_cl_devices_for_ref_test(blacklist_ref_vendors, need_image_support if not cpu_devs: warn("No CPU device found for running reference kernel. The reference " "computation will either fail because of a timeout " - "or take a *very* long time.") + "or take a *very* long time.", stacklevel=1) for dev in cpu_devs: yield dev diff --git a/loopy/cli.py b/loopy/cli.py index 426fb2e3e..4f2804f39 100644 --- a/loopy/cli.py +++ b/loopy/cli.py @@ -88,7 +88,7 @@ def main(): from loopy.target.cuda import CudaTarget target = CudaTarget else: - raise ValueError("unknown target: %s" % target) + raise ValueError(f"unknown target: {args.target}") lp.set_default_target(target) @@ -155,9 +155,9 @@ def main(): try: kernel = data_dic["lp_knl"] - except KeyError: + except KeyError as err: raise RuntimeError("loopy-lang requires 'lp_knl' " - "to be defined on exit") + "to be defined on exit") from err t_unit = [kernel] diff --git a/loopy/codegen/loop.py b/loopy/codegen/loop.py index d76ffc121..e9230c867 100644 --- a/loopy/codegen/loop.py +++ b/loopy/codegen/loop.py @@ -143,7 +143,7 @@ def generate_unroll_loop(codegen_state, sched_index): bounds.lower_bound_pw_aff.coalesce(), constants_only=False) except Exception as e: - raise type(e)("while finding lower bound of '%s': " % iname) + raise type(e)("while finding lower bound of '%s': " % iname) from None result = [] @@ -186,7 +186,7 @@ def generate_vectorize_loop(codegen_state, sched_index): bounds.lower_bound_pw_aff.coalesce(), constants_only=False) except Exception as e: - raise type(e)("while finding lower bound of '%s': " % iname) + raise type(e)("while finding lower bound of '%s': " % iname) from None if not lower_bound_aff.plain_is_zero(): warn(kernel, "vec_lower_not_0", diff --git a/loopy/diagnostic.py b/loopy/diagnostic.py index e7a93cd11..39e2fa591 100644 --- a/loopy/diagnostic.py +++ b/loopy/diagnostic.py @@ -82,15 +82,15 @@ class LoopyIndexError(LoopyError): pass -class CannotBranchDomainTree(LoopyError): +class CannotBranchDomainTree(LoopyError): # noqa: N818 pass -class TypeInferenceFailure(LoopyError): +class TypeInferenceFailure(LoopyError): # noqa: N818 pass -class AutomaticTestFailure(LoopyError): +class AutomaticTestFailure(LoopyError): # noqa: N818 pass @@ -135,11 +135,11 @@ class ExpressionToAffineConversionError(LoopyError): pass -class VariableAccessNotOrdered(LoopyError): +class VariableAccessNotOrdered(LoopyError): # noqa: N818 pass -class DependencyCycleFound(LoopyError): +class DependencyCycleFound(LoopyError): # noqa: N818 pass diff --git a/loopy/frontend/fortran/__init__.py b/loopy/frontend/fortran/__init__.py index fa5c5050f..5a5d628a5 100644 --- a/loopy/frontend/fortran/__init__.py +++ b/loopy/frontend/fortran/__init__.py @@ -37,8 +37,9 @@ def c_preprocess(source, defines=None, filename=None, include_paths=None): try: import ply.lex as lex import ply.cpp as cpp - except ImportError: - raise LoopyError("Using the C preprocessor requires PLY to be installed") + except ImportError as err: + raise LoopyError( + "Using the C preprocessor requires PLY to be installed") from err input_dirname = None if filename is None: diff --git a/loopy/frontend/fortran/translator.py b/loopy/frontend/fortran/translator.py index c23563c83..9340aa465 100644 --- a/loopy/frontend/fortran/translator.py +++ b/loopy/frontend/fortran/translator.py @@ -199,7 +199,7 @@ class Scope: raise TranslationError( "no type for '%s' found in 'implict none' routine" - % name) + % name) from None return self.implicit_types.get(name[0], np.dtype(np.int32)) diff --git a/loopy/frontend/fortran/tree.py b/loopy/frontend/fortran/tree.py index 9a703a794..e5c3fa489 100644 --- a/loopy/frontend/fortran/tree.py +++ b/loopy/frontend/fortran/tree.py @@ -123,7 +123,7 @@ class FTreeWalkerBase: except Exception as e: raise LoopyError( "Error parsing expression '%s' on line %d of '%s': %s" - % (expr_str, node.item.span[0], self.filename, str(e))) + % (expr_str, node.item.span[0], self.filename, str(e))) from e # }}} diff --git a/loopy/kernel/array.py b/loopy/kernel/array.py index 165727e6b..48231abdb 100644 --- a/loopy/kernel/array.py +++ b/loopy/kernel/array.py @@ -368,7 +368,8 @@ def parse_array_dim_tags(dim_tags, n_axes=None, use_increasing_target_axes=False try: dim_idx = dim_names.index(dim_name) except ValueError: - raise LoopyError("'%s' does not name an array axis" % dim_name) + raise LoopyError( + "'%s' does not name an array axis" % dim_name) from None dim_tags[dim_idx] = val @@ -1204,7 +1205,7 @@ def get_access_info(kernel: "LoopKernel", "%d (tagged '%s'), the index was not a compile-time " "constant (but it has to be in order for code to be " "generated). You likely want to unroll the iname(s) '%s'." - % (ary.name, i, ary.dim_tags[i], str(e))) + % (ary.name, i, ary.dim_tags[i], str(e))) from None if not is_integer(result): raise LoopyError("subscript '%s[%s]' has non-constant " diff --git a/loopy/kernel/data.py b/loopy/kernel/data.py index e4267ab6d..fdd0ad248 100644 --- a/loopy/kernel/data.py +++ b/loopy/kernel/data.py @@ -510,7 +510,7 @@ class ArrayArg(ArrayBase, KernelArgument): # Making this a function prevents incorrect use in isinstance. # Note: This is *not* deprecated, as it is super-common and # incrementally more convenient to use than ArrayArg directly. -def GlobalArg(*args, **kwargs): +def GlobalArg(*args, **kwargs): # noqa: N802 address_space = kwargs.pop("address_space", None) if address_space is not None: raise TypeError("may not pass 'address_space' to GlobalArg") diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index a86173fdc..01e0fcec6 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -520,7 +520,7 @@ def get_dot_dependency_graph(kernel, callables_table, iname_cluster=True, from warnings import warn warn("error encountered during scheduling for dep graph -- " "cannot perform iname clustering: %s(%s)" - % (type(e).__name__, e)) + % (type(e).__name__, e), stacklevel=1) dep_graph = {} lines = [] @@ -749,7 +749,7 @@ def get_auto_axis_iname_ranking_by_stride(kernel, insn): if arg.dim_tags is None: from warnings import warn warn("Strides for '%s' are not known. Local axis assignment " - "is likely suboptimal." % arg.name) + "is likely suboptimal." % arg.name, stacklevel=1) ary_strides = [1] * len(index_expr) else: ary_strides = [] @@ -1048,7 +1048,7 @@ def guess_var_shape(kernel, var_names): "shape/strides for variables '%s'. " "Specifying the shape manually should get rid of this. " "The following error occurred: %s" - % (",".join(var_names), str(e))) + % (",".join(var_names), str(e))) from e result = [] for var_name in var_names: diff --git a/loopy/library/reduction.py b/loopy/library/reduction.py index a4952d776..c4374eee1 100644 --- a/loopy/library/reduction.py +++ b/loopy/library/reduction.py @@ -553,7 +553,7 @@ def parse_reduction_op(name): from warnings import warn warn("Reductions with forced result types are no longer supported. " f"Encountered '{name}', which might be one.", - DeprecationWarning) + DeprecationWarning, stacklevel=1) return None if name in _REDUCTION_OPS: diff --git a/loopy/match.py b/loopy/match.py index 423c4ecec..e2a81f2b7 100644 --- a/loopy/match.py +++ b/loopy/match.py @@ -407,7 +407,7 @@ def parse_match(expr): .format( match_expr=expr, err_type=type(e).__name__, - err_str=str(e))) + err_str=str(e))) from e if pstate.is_at_end(): pstate.raise_parse_error("unexpected end of input") diff --git a/loopy/options.py b/loopy/options.py index 64667463a..073145bb1 100644 --- a/loopy/options.py +++ b/loopy/options.py @@ -47,7 +47,7 @@ def _apply_legacy_map(lmap, kwargs): if lmap_value is None: # ignore this warn("option '%s' is deprecated and was ignored" % name, - DeprecationWarning) + DeprecationWarning, stacklevel=1) continue new_name, translator = lmap_value @@ -57,7 +57,7 @@ def _apply_legacy_map(lmap, kwargs): warn(f"Loopy option '{name}' is deprecated. '{new_name}' should be " "used instead. The old option will stop working in 2022.", - DeprecationWarning) + DeprecationWarning, stacklevel=1) if translator is not None: val = translator(val) diff --git a/loopy/preprocess.py b/loopy/preprocess.py index 54311d789..f6f42be59 100644 --- a/loopy/preprocess.py +++ b/loopy/preprocess.py @@ -656,7 +656,7 @@ def infer_arg_descr(program): program.entrypoints) for e in program.entrypoints: - def _tuple_or_None(s): + def _tuple_or_none(s): if isinstance(s, tuple): return s elif s in [None, auto]: @@ -669,7 +669,7 @@ def infer_arg_descr(program): if isinstance(arg, ArrayBase): if arg.shape not in (None, auto): arg_id_to_descr[arg.name] = ArrayArgDescriptor( - _tuple_or_None(arg.shape), arg.address_space, + _tuple_or_none(arg.shape), arg.address_space, arg.dim_tags) elif isinstance(arg, ValueArg): arg_id_to_descr[arg.name] = ValueArgDescriptor() diff --git a/loopy/statistics.py b/loopy/statistics.py index a88aef50a..76d95454b 100755 --- a/loopy/statistics.py +++ b/loopy/statistics.py @@ -1076,7 +1076,7 @@ class _IndexStrideCoefficientCollector(CoefficientCollector): def map_floor_div(self, expr): from warnings import warn warn("_IndexStrideCoefficientCollector encountered FloorDiv, ignoring " - "denominator in expression %s" % (expr)) + "denominator in expression %s" % (expr), stacklevel=1) return self.rec(expr.numerator) # }}} @@ -1375,19 +1375,19 @@ class AccessFootprintGatherer(CombineMapper): try: access_range = get_access_map(self.domain, subscript, self.kernel.assumptions).range() - except isl.Error: + except isl.Error as err: # Likely: index was non-linear, nothing we can do. if self.ignore_uncountable: return {} else: - raise LoopyError("failed to gather footprint: %s" % expr) + raise LoopyError("failed to gather footprint: %s" % expr) from err - except TypeError: + except TypeError as err: # Likely: index was non-linear, nothing we can do. if self.ignore_uncountable: return {} else: - raise LoopyError("failed to gather footprint: %s" % expr) + raise LoopyError("failed to gather footprint: %s" % expr) from err from pymbolic.primitives import Variable assert isinstance(expr.aggregate, Variable) diff --git a/loopy/symbolic.py b/loopy/symbolic.py index 2ea506efa..548b2107d 100644 --- a/loopy/symbolic.py +++ b/loopy/symbolic.py @@ -2511,7 +2511,7 @@ def get_access_map(domain, subscript, assumptions=None, shape=None, "(encountered %s: %s)" % (", ".join(str(si) for si in subscript), # intentionally using 'outer' err - type(err).__name__, str(err))) + type(err).__name__, str(err))) from err # successfully converted shape[idim] to aff, but not subscript[idim] diff --git a/loopy/target/c/codegen/expression.py b/loopy/target/c/codegen/expression.py index d6793de4a..8f0213bf1 100644 --- a/loopy/target/c/codegen/expression.py +++ b/loopy/target/c/codegen/expression.py @@ -434,7 +434,7 @@ class ExpressionToCExpressionMapper(IdentityMapper): " this leads to problems with cache retrieval." " Consider using `pymbolic.primitives.NaN` instead of `math.nan`." " The generated code will be equivalent with the added benefit" - " of sound pickling/unpickling of kernel objects.") + " of sound pickling/unpickling of kernel objects.", stacklevel=1) from pymbolic.primitives import NaN data_type = expr.dtype.type if isinstance(expr, np.generic) else None return self.map_nan(NaN(data_type), type_context) diff --git a/loopy/target/c/compyte b/loopy/target/c/compyte index d4549d4c7..fcb59401c 160000 --- a/loopy/target/c/compyte +++ b/loopy/target/c/compyte @@ -1 +1 @@ -Subproject commit d4549d4c711513e2cc098d3f5d4e918eac53ee7a +Subproject commit fcb59401cd61704037002b714519d0f7af2c4c59 diff --git a/loopy/target/execution.py b/loopy/target/execution.py index 8d45bf723..dcf162ae7 100644 --- a/loopy/target/execution.py +++ b/loopy/target/execution.py @@ -296,7 +296,7 @@ class ExecutionWrapperGeneratorBase(ABC): warn("Unable to generate code to automatically " f"find '{unknown_name}' " f"from '{', '.join(eqn.based_on_names)}':\n" - f"{e}", ParameterFinderWarning) + f"{e}", ParameterFinderWarning, stacklevel=1) continue # Do not use more than one bit of data from each of the diff --git a/loopy/target/pyopencl.py b/loopy/target/pyopencl.py index 9f4c875a0..edf3c9d93 100644 --- a/loopy/target/pyopencl.py +++ b/loopy/target/pyopencl.py @@ -916,7 +916,7 @@ class PyOpenCLPythonASTBuilder(PythonASTBuilderBase): from warnings import warn warn("Your kernel invocation will likely fail because your " "version of PyOpenCL does not support allow_empty_ndrange. " - "Please upgrade to version 2020.2 or newer.") + "Please upgrade to version 2020.2 or newer.", stacklevel=2) # TODO: Generate finer-grained dependency structure return Suite([ diff --git a/loopy/transform/arithmetic.py b/loopy/transform/arithmetic.py index f6ad10826..65576bad2 100644 --- a/loopy/transform/arithmetic.py +++ b/loopy/transform/arithmetic.py @@ -87,7 +87,7 @@ def collect_common_factors_on_increment(kernel, var_name, vary_by_axes=()): try: return name_to_index[ax] except KeyError: - raise LoopyError("axis name '%s' not understood " % ax) + raise LoopyError("axis name '%s' not understood " % ax) from None else: return ax diff --git a/loopy/transform/data.py b/loopy/transform/data.py index d96faf1be..cb5fe829d 100644 --- a/loopy/transform/data.py +++ b/loopy/transform/data.py @@ -666,9 +666,8 @@ def set_argument_order(kernel, arg_names): for arg_name in arg_names: try: arg = old_arg_dict.pop(arg_name) - except KeyError: - raise LoopyError("unknown argument '%s'" - % arg_name) + except KeyError as err: + raise LoopyError("unknown argument '%s'" % arg_name) from err new_args.append(arg) @@ -775,8 +774,8 @@ def set_temporary_address_space(kernel, temp_var_names, address_space): if isinstance(address_space, str): try: address_space = getattr(AddressSpace, address_space.upper()) - except AttributeError: - raise LoopyError("address_space '%s' unknown" % address_space) + except AttributeError as err: + raise LoopyError("address_space '%s' unknown" % address_space) from err if not isinstance(address_space, int) or address_space not in [ AddressSpace.PRIVATE, @@ -789,7 +788,7 @@ def set_temporary_address_space(kernel, temp_var_names, address_space): try: tv = new_temp_vars[tv_name] except KeyError: - raise LoopyError("temporary '%s' not found" % tv_name) + raise LoopyError("temporary '%s' not found" % tv_name) from None new_temp_vars[tv_name] = tv.copy(address_space=address_space) @@ -797,7 +796,6 @@ def set_temporary_address_space(kernel, temp_var_names, address_space): def set_temporary_scope(kernel, temp_var_names, address_space): - from warnings import warn warn("set_temporary_scope is deprecated and will stop working in " "July 2022. Use set_temporary_address_space instead.", DeprecationWarning, stacklevel=2) @@ -943,16 +941,14 @@ def add_padding_to_avoid_bank_conflicts(kernel, device): good_incr = increment if min_mult != 1: - from warnings import warn from loopy.diagnostic import LoopyAdvisory warn("could not find a conflict-free mem layout " "for local variable '%s' " "(currently: %dx conflict, increment: %s, reason: %s)" % (temp_var.name, min_mult, good_incr, min_why_not), - LoopyAdvisory) + LoopyAdvisory, stacklevel=4) else: - from warnings import warn - warn("unknown type of local memory") + warn("unknown type of local memory", stacklevel=4) new_storage_shape = storage_shape diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 51f970253..c44720f91 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -583,7 +583,7 @@ def join_inames(kernel, inames, new_iname=None, tag=None, within=None): bounds.lower_bound_pw_aff.coalesce(), constants_only=False) except Exception as e: - raise type(e)("while finding lower bound of '%s': " % iname) + raise type(e)("while finding lower bound of '%s': " % iname) from e my_val = var(new_iname) // base_divisor if i+1 < len(inames): diff --git a/loopy/transform/precompute.py b/loopy/transform/precompute.py index 6ae5139f5..617df3b24 100644 --- a/loopy/transform/precompute.py +++ b/loopy/transform/precompute.py @@ -186,7 +186,7 @@ class RuleInvocationGatherer(RuleAwareIdentityMapper): name, ", ".join(str(arg) for arg in arguments), ", ".join(arg_deps - self.kernel.all_inames()), - )) + ), stacklevel=1) return super().map_substitution( name, tag, arguments, expn_state) @@ -539,7 +539,7 @@ def precompute_for_single_kernel( subst = kernel.substitutions[subst_name] except KeyError: raise LoopyError("substitution rule '%s' not found" - % subst_name) + % subst_name) from None c_subst_name = subst_name.replace(".", "_") diff --git a/loopy/transform/realize_reduction.py b/loopy/transform/realize_reduction.py index 7ef773408..3aca4634e 100644 --- a/loopy/transform/realize_reduction.py +++ b/loopy/transform/realize_reduction.py @@ -377,7 +377,7 @@ def _try_infer_scan_candidate_from_expr( except ValueError as v: raise ValueError( "Couldn't determine a sweep iname for the scan " - "expression '%s': %s" % (expr, v)) + "expression '%s': %s" % (expr, v)) from None try: sweep_lower_bound, sweep_upper_bound, scan_lower_bound = ( @@ -387,7 +387,7 @@ def _try_infer_scan_candidate_from_expr( raise ValueError( "Couldn't determine bounds for the scan with expression '%s' " "(sweep iname: '%s', scan iname: '%s'): %s" - % (expr, sweep_iname, scan_iname, v)) + % (expr, sweep_iname, scan_iname, v)) from None try: stride = _try_infer_scan_stride( @@ -396,7 +396,7 @@ def _try_infer_scan_candidate_from_expr( raise ValueError( "Couldn't determine a scan stride for the scan with expression '%s' " "(sweep iname: '%s', scan iname: '%s'): %s" - % (expr, sweep_iname, scan_iname, v)) + % (expr, sweep_iname, scan_iname, v)) from None return _ScanCandidateParameters( sweep_iname=sweep_iname, @@ -473,7 +473,7 @@ def _try_infer_scan_and_sweep_bounds(kernel, scan_iname, sweep_iname, within_ina sweep_upper_bound = domain.dim_max(sweep_idx) scan_lower_bound = domain.dim_min(scan_idx) except isl.Error as e: - raise ValueError("isl error: %s" % e) + raise ValueError("isl error: %s" % e) from e return (sweep_lower_bound, sweep_upper_bound, scan_lower_bound) @@ -503,7 +503,7 @@ def _try_infer_scan_stride(kernel, scan_iname, sweep_iname, sweep_lower_bound): - domain_with_sweep_param.dim_min(scan_iname_idx) ).gist(domain_with_sweep_param.params()) except isl.Error as e: - raise ValueError("isl error: '%s'" % e) + raise ValueError("isl error: '%s'" % e) from e scan_iname_pieces = scan_iname_range.get_pieces() @@ -525,8 +525,9 @@ def _try_infer_scan_stride(kernel, scan_iname, sweep_iname, sweep_lower_bound): if len(coeffs) == 0: try: scan_iname_aff.get_constant_val() - except Exception: - raise ValueError("range for aff isn't constant: '%s'" % scan_iname_aff) + except Exception as err: + raise ValueError( + "range for aff isn't constant: '%s'" % scan_iname_aff) from err # If this point is reached we're assuming the domain is of the form # {[i,j]: i=0 and j=0}, so the stride is technically 1 - any value diff --git a/loopy/type_inference.py b/loopy/type_inference.py index 2919ca798..53ee91a75 100644 --- a/loopy/type_inference.py +++ b/loopy/type_inference.py @@ -516,7 +516,7 @@ class TypeInferenceMapper(CombineMapper): except KeyError: raise LoopyError("cannot look up attribute '%s' in " "aggregate expression '%s' of dtype '%s'" - % (expr.aggregate, expr.name, numpy_dtype)) + % (expr.aggregate, expr.name, numpy_dtype)) from None dtype = field[0] return [NumpyType(dtype)] @@ -1095,7 +1095,7 @@ def infer_arg_and_reduction_dtypes_for_reduction_expression( arg_dtypes = [None] else: raise LoopyError("failed to determine type of accumulator for " - "reduction '%s'" % expr) + "reduction '%s'" % expr) from None reduction_dtypes = expr.operation.result_dtypes(*arg_dtypes) diff --git a/loopy/types.py b/loopy/types.py index 4c3b74ea6..acc941037 100644 --- a/loopy/types.py +++ b/loopy/types.py @@ -84,7 +84,7 @@ class NumpyType(LoopyType): if dtype is None: raise TypeError("may not pass None to construct NumpyType") - if dtype == object: + if dtype == object: # noqa: E721 raise TypeError("loopy does not directly support object arrays") self.dtype = np.dtype(dtype) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..a3d19c2cf --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,88 @@ + +[tool.ruff] +preview = true + +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "C", # flake8-comprehensions + "E", # pycodestyle + "F", # pyflakes + + # TODO + # "I", # flake8-isort + + "N", # pep8-naming + "NPY", # numpy + "Q", # flake8-quotes + "W", # pycodestyle + + # TODO + # "UP", # pyupgrade + # "RUF", # ruff +] +extend-ignore = [ + "C90", # McCabe complexity + "E221", # multiple spaces before operator + "E241", # multiple spaces after comma + "E402", # module level import not at the top of file + "E226", # missing whitespace around operator + "N817", # CamelCase `SubstitutionRuleMappingContext` imported as acronym `SRMC` + + # FIXME + "NPY002", # numpy rng + "C408", # unnecssary dict() -> literal + "E265", # block comment should start with + "F841", # local variable unused +] + +[tool.ruff.lint.per-file-ignores] +"test/test_loopy.py" = ["B023"] +"loopy/target/c/compyte/ndarray/**/*.py" = ["Q", "B", "E", "F", "N", "C4"] +"loopy/frontend/fortran/translator.py" = ["N802", "B028"] +"proto-tests/*.py" = ["B"] + +[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 = [ + "pytools", + "pymbolic", +] +known-local-folder = [ + "modepy", +] +lines-after-imports = 2 + +[tool.mypy] +python_version = 3.8 +warn_unused_ignores = true + +# TODO +# check_untyped_defs = true + +exclude = [ + "loopy/target/c/compyte/ndarray/.*", + "loopy/target/c/compyte/array.py", +] + +[[tool.mypy.overrides]] +module = [ + "islpy.*", + "pymbolic.*", + "cgen.*", + "genpy.*", + "pyopencl.*", + "colorama.*", + "codepy.*", + "mako.*", + "fparser.*", + "ply.*", + "pygments.*", + "IPython.*", +] +ignore_missing_imports = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 822df80d7..000000000 --- a/setup.cfg +++ /dev/null @@ -1,66 +0,0 @@ -[flake8] -ignore = E126,E127,E128,E123,E226,E241,E242,E265,N802,W503,E402,N814,N817,W504 -max-line-length=85 -exclude= - loopy/target/c/compyte/ndarray, - loopy/target/c/compyte/array.py - -inline-quotes = " -docstring-quotes = """ -multiline-quotes = """ - -per-file-ignores = - test/test_loopy.py:B023,C408, - test/*.py:C408, - proto-tests/*.py:C408 - -# enable-flake8-bugbear - -[tool:pytest] -doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ELLIPSIS -addopts = --ignore=proto-tests --ignore=loopy/target/c/compyte/ndarray - -[mypy] -python_version = 3.8 -warn_unused_ignores = True - -exclude = (?x)( - loopy/target/c/compyte/ndarray/.* - | loopy/target/c/compyte/array\.py - ) - -[mypy-islpy.*] -ignore_missing_imports = True - -[mypy-pymbolic.*] -ignore_missing_imports = True - -[mypy-cgen.*] -ignore_missing_imports = True - -[mypy-genpy.*] -ignore_missing_imports = True - -[mypy-pyopencl.*] -ignore_missing_imports = True - -[mypy-pygments.*] -ignore_missing_imports = True - -[mypy-colorama.*] -ignore_missing_imports = True - -[mypy-codepy.*] -ignore_missing_imports = True - -[mypy-mako.*] -ignore_missing_imports = True - -[mypy-fparser.*] -ignore_missing_imports = True - -[mypy-ply.*] -ignore_missing_imports = True - -[mypy-IPython.*] -ignore_missing_imports = True diff --git a/setup.py b/setup.py index dc1ef4cbf..b0853937f 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ def find_git_revision(tree_root): assert retcode is not None if retcode != 0: from warnings import warn - warn("unable to find git revision") + warn("unable to find git revision", stacklevel=1) return None return git_rev diff --git a/test/gnuma_loopy_transforms.py b/test/gnuma_loopy_transforms.py index bb521bd2c..9c4400406 100644 --- a/test/gnuma_loopy_transforms.py +++ b/test/gnuma_loopy_transforms.py @@ -32,7 +32,7 @@ def set_q_storage_format(kernel, name): return kernel -def set_D_storage_format(kernel): +def set_D_storage_format(kernel): # noqa: N802 return lp.tag_array_axes(kernel, "D", "f,f") diff --git a/test/test_apps.py b/test/test_apps.py index ca0b38404..6b6b65bf4 100644 --- a/test/test_apps.py +++ b/test/test_apps.py @@ -492,7 +492,7 @@ def test_lbm(ctx_factory): f_new[i, j, 11] = + 0.25*m[8] - 0.125*m[10] - 0.25*m[11] end end - """) + """) # noqa: E501 knl = lp.add_and_infer_dtypes(knl, {"f": np.float32}) diff --git a/test/test_expression.py b/test/test_expression.py index 8b74852a6..9af21cab8 100644 --- a/test/test_expression.py +++ b/test/test_expression.py @@ -343,7 +343,8 @@ def test_fuzz_expression_code_gen(ctx_factory, expr_type, random_seed, target_cl from warnings import warn warn("Using default C compiler because gcc-10 was not found. " "These tests may take a long time, because of " - "https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107127.") + "https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107127.", + stacklevel=1) target = target_cls() else: @@ -391,7 +392,7 @@ def test_fuzz_expression_code_gen(ctx_factory, expr_type, random_seed, target_cl print("reference=%r" % ref_value) print("loopy=%r" % lp_value) print(80*"-") - 1/0 + 1/0 # noqa: B018 print(lp.generate_code_v2(knl).device_code()) diff --git a/test/test_loopy.py b/test/test_loopy.py index 8e1ce26ba..5637c1187 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -876,9 +876,9 @@ def test_atomic(ctx_factory, dtype): and "cl_khr_int64_base_atomics" not in ctx.devices[0].extensions): pytest.skip("64-bit atomics not supported on device") - import pyopencl.version # noqa + import pyopencl.version if ( - cl.version.VERSION < (2015, 2) + pyopencl.version.VERSION < (2015, 2) and dtype == np.int64): pytest.skip("int64 RNG not supported in PyOpenCL < 2015.2") diff --git a/test/test_misc.py b/test/test_misc.py index 7feb5ae73..c8fc7e5f6 100644 --- a/test/test_misc.py +++ b/test/test_misc.py @@ -44,7 +44,7 @@ def test_kernel_pickling_and_hashing(): assert LoopyKeyBuilder()(knl) == LoopyKeyBuilder()(reconst_knl) -def test_SetTrie(): +def test_set_trie(): from loopy.kernel.tools import SetTrie s = SetTrie() @@ -83,7 +83,7 @@ class PickleDetectorForLazilyUnpicklingDict(PickleDetector): self.state = None -def test_LazilyUnpicklingDict(): +def test_lazily_unpickling_dict(): from loopy.tools import LazilyUnpicklingDict cls = PickleDetectorForLazilyUnpicklingDict @@ -136,7 +136,7 @@ class PickleDetectorForLazilyUnpicklingList(PickleDetector): self.state = None -def test_LazilyUnpicklingList(): +def test_lazily_unpickling_list(): from loopy.tools import LazilyUnpicklingList cls = PickleDetectorForLazilyUnpicklingList @@ -193,7 +193,7 @@ class PickleDetectorForLazilyUnpicklingListWithEqAndPersistentHashing( key_builder.rec(key_hash, repr(self)) -def test_LazilyUnpicklingListWithEqAndPersistentHashing(): +def test_lazily_unpickling_list_eq_and_persistent_hashing(): from loopy.tools import LazilyUnpicklingListWithEqAndPersistentHashing cls = PickleDetectorForLazilyUnpicklingListWithEqAndPersistentHashing @@ -256,7 +256,7 @@ def test_Optional(): # noqa opt = Optional() assert not opt.has_value with pytest.raises(AttributeError): - opt.value + opt.value # noqa: B018 opt = Optional(1) assert opt.has_value diff --git a/test/test_reduction.py b/test/test_reduction.py index 804f14667..b56940a72 100644 --- a/test/test_reduction.py +++ b/test/test_reduction.py @@ -26,6 +26,7 @@ import loopy as lp import pyopencl as cl import pyopencl.clmath # noqa import pyopencl.clrandom # noqa +import pyopencl.version import pytest import logging @@ -253,7 +254,6 @@ def test_global_parallel_reduction(ctx_factory, size): def test_global_mc_parallel_reduction(ctx_factory, size): ctx = ctx_factory() - import pyopencl.version # noqa if cl.version.VERSION < (2016, 2): pytest.skip("Random123 RNG not supported in PyOpenCL < 2016.2") diff --git a/test/test_statistics.py b/test/test_statistics.py index 8b384e3e4..75dac2e55 100644 --- a/test/test_statistics.py +++ b/test/test_statistics.py @@ -267,7 +267,7 @@ def test_op_counter_triangular_domain(): expect_fallback = False import islpy as isl try: - isl.BasicSet.card + isl.BasicSet.card # noqa: B018 except AttributeError: expect_fallback = True else: @@ -698,7 +698,7 @@ def test_mem_access_counter_mixed(): expect_fallback = False import islpy as isl try: - isl.BasicSet.card + isl.BasicSet.card # noqa: B018 except AttributeError: expect_fallback = True else: diff --git a/test/test_target.py b/test/test_target.py index c53cf3199..6026b6192 100644 --- a/test/test_target.py +++ b/test/test_target.py @@ -28,6 +28,7 @@ import pyopencl as cl import pyopencl.clmath import pyopencl.clrandom import pyopencl.tools +import pyopencl.version import pytest import pymbolic.primitives as prim @@ -191,7 +192,6 @@ def test_random123(ctx_factory, tp): ctx = ctx_factory() queue = cl.CommandQueue(ctx) - import pyopencl.version # noqa if cl.version.VERSION < (2016, 2): pytest.skip("Random123 RNG not supported in PyOpenCL < 2016.2") -- GitLab