diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 328f06c6..8f1ba108 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,27 +19,6 @@ repos: # Don't commit to main branch. - id: no-commit-to-branch -- repo: https://github.com/psf/black - rev: 24.8.0 - hooks: - - id: black - types: [file, python] - args: [--config=./pyproject.toml] - -- repo: https://github.com/PyCQA/flake8 - rev: 7.1.1 - hooks: - - id: flake8 - types: [file, python] - args: [--config=./setup.cfg] - -- repo: https://github.com/PyCQA/isort - rev: 5.13.2 - hooks: - - id: isort - types: [file, python] - args: [--filter-files] - - repo: https://github.com/aio-libs/sort-all rev: v1.2.0 hooks: @@ -52,3 +31,19 @@ repos: - id: sp-repo-review additional_dependencies: ["repo-review[cli]"] # TODO: Only neededed if extra dependencies are required #args: ["--show=errskip"] # show everything for the moment + +- repo: https://github.com/adamchainz/blacken-docs + rev: 1.16.0 + hooks: + - id: blacken-docs + types: [file, rst] + +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.4.10" + hooks: + # Run the linter + - id: ruff + types: [file, python] + args: [--fix, --show-fixes] + # Run the formatter. + - id: ruff-format diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 34ff409c..97b5dbda 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -189,10 +189,10 @@ def suppress_errors(): try: _ud_system = _ud.read_xml(config.get_xml_path()) except _ud.UdunitsError as e: - error_msg = ': "%s"' % e.error_msg() if e.errnum else "" + error_msg = f': "{e.error_msg():s}"' if e.errnum else "" raise OSError( - "[%s] Failed to open UDUNITS-2 XML unit database%s" - % (e.status_msg(), error_msg) + f"[{e.status_msg()}] " + f"Failed to open UDUNITS-2 XML unit database{error_msg}" ) @@ -498,7 +498,7 @@ def as_unit(unit): result = unit else: result = None - use_cache = isinstance(unit, (str,)) or unit is None + use_cache = isinstance(unit, str) or unit is None if use_cache: result = _CACHE.get(unit) if result is None: @@ -566,11 +566,9 @@ def _ud_value_error(ud_err, message): ud_msg = ud_err.error_msg() if ud_msg: - message = "{}: {}".format(message, ud_msg) + message = f"{message}: {ud_msg}" - message = "[{status}] {message}".format( - status=ud_err.status_msg(), message=message - ) + message = f"[{ud_err.status_msg()}] {message}" return ValueError(message) @@ -594,7 +592,7 @@ class Unit(_OrderedHashable): def _init_from_tuple(self, values): # Implements the required interface for an _OrderedHashable. # This will also ensure a Unit._init(*Unit.names) method exists. - for name, value in zip(self._names, values): + for name, value in zip(self._names, values, strict=False): object.__setattr__(self, name, value) # Provide hash semantics @@ -614,12 +612,12 @@ def __lt__(self, other): def __setattr__(self, name, value): raise AttributeError( - "Instances of %s are immutable" % type(self).__name__ + f"Instances of {type(self).__name__:s} are immutable" ) def __delattr__(self, name): raise AttributeError( - "Instances of %s are immutable" % type(self).__name__ + f"Instances of {type(self).__name__:s} are immutable" ) # Declare the attribute names relevant to the ordered and hashable @@ -727,13 +725,13 @@ def __init__(self, unit, calendar=None): ut_unit = _ud.parse(_ud_system, unit.encode("utf8"), encoding) except _ud.UdunitsError as exception: value_error = _ud_value_error( - exception, 'Failed to parse unit "{}"'.format(str_unit) + exception, f'Failed to parse unit "{str_unit}"' ) raise value_error from None if _OP_SINCE in unit.lower(): if calendar is None: calendar_ = CALENDAR_STANDARD - elif isinstance(calendar, (str,)): + elif isinstance(calendar, str): calendar_ = calendar.lower() if calendar_ in CALENDAR_ALIASES: calendar_ = CALENDAR_ALIASES[calendar_] @@ -932,7 +930,7 @@ def title(self, value): dt = self.num2date(value) result = dt.strftime("%Y-%m-%d %H:%M:%S") else: - result = "%s %s" % (str(value), self) + result = f"{value} {self}" return result @property @@ -1220,15 +1218,15 @@ def offset_by_time(self, origin): """ - if not isinstance(origin, (float, (int,))): + if not isinstance(origin, float | int): raise TypeError( - "a numeric type for the origin argument is" " required" + "a numeric type for the origin argument is required" ) try: ut_unit = _ud.offset_by_time(self.ut_unit, origin) except _ud.UdunitsError as exception: value_error = _ud_value_error( - exception, "Failed to offset {!r}".format(self) + exception, f"Failed to offset {self!r}" ) raise value_error from None calendar = None @@ -1300,7 +1298,7 @@ def root(self, root): except _ud.UdunitsError as exception: value_error = _ud_value_error( exception, - "Failed to take the root of {!r}".format(self), + f"Failed to take the root of {self!r}", ) raise value_error from None calendar = None @@ -1338,13 +1336,12 @@ def log(self, base): ut_unit = _ud.log(base, self.ut_unit) except TypeError: raise TypeError( - "A numeric type for the base argument is " " required" + "A numeric type for the base argument is required" ) except _ud.UdunitsError as exception: value_err = _ud_value_error( exception, - "Failed to calculate logorithmic base " - "of {!r}".format(self), + f"Failed to calculate logorithmic base of {self!r}", ) raise value_err from None calendar = None @@ -1386,10 +1383,11 @@ def __repr__(self): """ if self.calendar is None: - result = "{}('{}')".format(self.__class__.__name__, self) + result = f"{self.__class__.__name__}('{self}')" else: - result = "{}('{}', calendar='{}')".format( - self.__class__.__name__, self, self.calendar + result = ( + f"{self.__class__.__name__}" + f"('{self}', calendar='{self.calendar}')" ) return result @@ -1430,7 +1428,7 @@ def _op_common(self, other, op_func): other = as_unit(other) if self.is_no_unit() or other.is_no_unit(): - raise ValueError("Cannot %s a 'no-unit'." % op_label) + raise ValueError(f"Cannot {op_label:s} a 'no-unit'.") if self.is_unknown() or other.is_unknown(): result = Unit(_UNKNOWN_UNIT_STRING) @@ -1440,7 +1438,7 @@ def _op_common(self, other, op_func): except _ud.UdunitsError as exception: value_err = _ud_value_error( exception, - "Failed to {} {!r} by {!r}".format(op_label, self, other), + f"Failed to {op_label} {self!r} by {other!r}", ) raise value_err from None calendar = None @@ -1583,10 +1581,10 @@ def __pow__(self, power): root = int(round(1 / power)) result = self.root(root) else: - # Failing that, check for powers which are (very nearly) simple - # integer values. + # Failing that, check for powers which are (very nearly) + # simple integer values. if not math.isclose(power, round(power)): - msg = "Cannot raise a unit by a decimal (got %s)." % power + msg = f"Cannot raise a unit by a decimal (got {power:s})." raise ValueError(msg) power = int(round(power)) @@ -1595,7 +1593,7 @@ def __pow__(self, power): except _ud.UdunitsError as exception: value_err = _ud_value_error( exception, - "Failed to raise the power of {!r}".format(self), + f"Failed to raise the power of {self!r}", ) raise value_err from None result = Unit._new_from_existing_ut(_CATEGORY_UDUNIT, ut_unit) @@ -1662,10 +1660,10 @@ def __ne__(self, other): def change_calendar(self, calendar): """ - Returns a new unit with the requested calendar, modifying the reference - date if necessary. Only works with calendars that represent the real - world (standard, proleptic_gregorian, julian) and with short time - intervals (days or less). + Returns a new unit with the requested calendar, modifying the + reference date if necessary. Only works with calendars that + represent the real world (standard, proleptic_gregorian, julian) + and with short time intervals (days or less). For example: @@ -1674,7 +1672,7 @@ def change_calendar(self, calendar): >>> u.change_calendar('standard') Unit('days since 1499-12-23T00:00:00', calendar='standard') - """ + """ # NOQA E501 if not self.is_time_reference(): raise ValueError("unit is not a time reference") @@ -1772,7 +1770,7 @@ def convert(self, value, other, ctype=FLOAT64, inplace=False): except _ud.UdunitsError as exception: value_err = _ud_value_error( exception, - "Failed to convert {!r} to {!r}".format(self, other), + f"Failed to convert {self!r} to {other!r}", ) raise value_err from None if isinstance(result, np.ndarray): @@ -1796,9 +1794,8 @@ def convert(self, value, other, ctype=FLOAT64, inplace=False): # Strict type check of numpy array. if result.dtype.type not in (np.float32, np.float64): raise TypeError( - "Expect a numpy array of '%s' or '%s'" - % np.float32, - np.float64, + "Expect a numpy array of " + f"'{np.float32}' or '{np.float64}'" ) ctype = result.dtype.type # Utilise global convenience dictionary @@ -1830,7 +1827,7 @@ def convert(self, value, other, ctype=FLOAT64, inplace=False): return result else: raise ValueError( - "Unable to convert from '%r' to '%r'." % (self, other) + f"Unable to convert from '{self!r}' to '{other!r}'." ) @property diff --git a/cf_units/_udunits2_parser/__init__.py b/cf_units/_udunits2_parser/__init__.py index 0c7c0111..aec51503 100644 --- a/cf_units/_udunits2_parser/__init__.py +++ b/cf_units/_udunits2_parser/__init__.py @@ -169,7 +169,7 @@ def __init__(self, unit_string): def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): # https://stackoverflow.com/a/36367357/741316 - context = ("inline", line, column + 2, "'{}'".format(self.unit_string)) + context = ("inline", line, column + 2, f"'{self.unit_string}'") syntax_error = SyntaxError(msg, context) raise syntax_error from None @@ -192,7 +192,7 @@ def _debug_tokens(unit_string): continue token_type_idx = token.type rule = TOKEN_ID_NAMES[token_type_idx] - print("%s: %s" % (token.text, rule)) + print(f"{token.text}: {rule}") def normalize(unit_string): diff --git a/cf_units/_udunits2_parser/compile.py b/cf_units/_udunits2_parser/compile.py index b52719c4..5cd4d3b2 100644 --- a/cf_units/_udunits2_parser/compile.py +++ b/cf_units/_udunits2_parser/compile.py @@ -41,7 +41,7 @@ def expand_lexer(source, target): MODE_P = re.compile(r"mode ([A-Z_]+)\;") TOKEN_P = re.compile(r"([A-Z_]+) ?\:.*") - with open(source, "r") as fh: + with open(source) as fh: content = fh.read() template = jinja2.Environment(loader=jinja2.BaseLoader).from_string( diff --git a/cf_units/_udunits2_parser/graph.py b/cf_units/_udunits2_parser/graph.py index 32690230..561271aa 100644 --- a/cf_units/_udunits2_parser/graph.py +++ b/cf_units/_udunits2_parser/graph.py @@ -28,9 +28,9 @@ def __getattr__(self, name): def _repr_ctx(self): # Return a dictionary that is useful for passing to string.format. kwargs = ", ".join( - "{}={!r}".format(key, value) for key, value in self._attrs.items() + f"{key}={value!r}" for key, value in self._attrs.items() ) - return dict(cls_name=self.__class__.__name__, kwargs=kwargs) + return {"cls_name": self.__class__.__name__, "kwargs": kwargs} def __repr__(self): return "{cls_name}({kwargs})".format(**self._repr_ctx()) @@ -49,7 +49,7 @@ def children(self): return [] def __str__(self): - return "{}".format(self.content) + return f"{self.content}" class Operand(Terminal): diff --git a/cf_units/_udunits2_parser/parser/udunits2Lexer.py b/cf_units/_udunits2_parser/parser/udunits2Lexer.py index 320d5b63..0dc07819 100644 --- a/cf_units/_udunits2_parser/parser/udunits2Lexer.py +++ b/cf_units/_udunits2_parser/parser/udunits2Lexer.py @@ -1,4 +1,5 @@ # Generated from /home/ruth/git_stuff/cf-units/cf_units/_udunits2_parser/parser/udunits2Lexer.g4 by ANTLR 4.11.1 +# encoding: utf-8 import sys from io import StringIO diff --git a/cf_units/_udunits2_parser/parser/udunits2Parser.py b/cf_units/_udunits2_parser/parser/udunits2Parser.py index ee6d6d1f..1275018b 100644 --- a/cf_units/_udunits2_parser/parser/udunits2Parser.py +++ b/cf_units/_udunits2_parser/parser/udunits2Parser.py @@ -1,4 +1,4 @@ -# Generated from /home/ruth/git_stuff/cf-units/cf_units/_udunits2_parser/udunits2Parser.g4 by ANTLR 4.11.1 +# Generated from /home/ruth/git_stuff/cf-units/cf_units/_udunits2_parser/parser/udunits2Lexer.g4 by ANTLR 4.11.1 # encoding: utf-8 import sys from io import StringIO diff --git a/cf_units/tests/integration/parse/test_parse.py b/cf_units/tests/integration/parse/test_parse.py index d42b7a36..5a86371c 100644 --- a/cf_units/tests/integration/parse/test_parse.py +++ b/cf_units/tests/integration/parse/test_parse.py @@ -169,7 +169,7 @@ def test_invalid_units(_, unit_str): # Double check that udunits2 can't parse this. assert ( cf_valid is False - ), "Unit {!r} is unexpectedly valid in UDUNITS2".format(unit_str) + ), f"Unit {unit_str!r} is unexpectedly valid in UDUNITS2" try: normalize(unit_str) @@ -178,7 +178,7 @@ def test_invalid_units(_, unit_str): can_parse = False # Now confirm that we couldn't parse this either. - msg = "Parser unexpectedly able to deal with {}".format(unit_str) + msg = f"Parser unexpectedly able to deal with {unit_str}" assert can_parse is False, msg @@ -242,7 +242,7 @@ def test_known_issues(_, unit_str, expected): # These are the cases that don't work yet but which do work with udunits. # Make sure udunits can read it. - cf_units.Unit(unit_str).symbol + _ = cf_units.Unit(unit_str).symbol if isinstance(expected, type) and issubclass(expected, Exception): with pytest.raises(SyntaxError): @@ -293,7 +293,7 @@ def test_invalid_syntax_units(_, unit_str): # allowed with our grammar. with pytest.raises(ValueError): - cf_units.Unit(unit_str).symbol + _ = cf_units.Unit(unit_str).symbol with pytest.raises(SyntaxError): normalize(unit_str) diff --git a/cf_units/tests/integration/test__Unit_date2num.py b/cf_units/tests/integration/test__Unit_date2num.py index 32cbcff8..54a98c7f 100644 --- a/cf_units/tests/integration/test__Unit_date2num.py +++ b/cf_units/tests/integration/test__Unit_date2num.py @@ -4,7 +4,6 @@ # See LICENSE in the root of the repository for full licensing details. """Test method :meth:`cf_units.Unit.date2num`.""" - import cftime import pytest @@ -20,7 +19,8 @@ @pytest.mark.parametrize( - "calendar_const, calendar_str", zip(CALENDAR_CONSTANTS, CALENDAR_STRINGS) + "calendar_const, calendar_str", + zip(CALENDAR_CONSTANTS, CALENDAR_STRINGS, strict=False), ) def test_fractional_second(calendar_const, calendar_str): unit = cf_units.Unit("seconds since 1970-01-01", calendar_const) @@ -36,6 +36,6 @@ def test_fractional_second(calendar_const, calendar_str): ] nums = [0.25, 0.5, 0.75, 1.5, 2.5, 3.5, 4.5, 172804.5] - for num, date in zip(nums, dates): + for num, date in zip(nums, dates, strict=False): res = unit.date2num(date) assert num == pytest.approx(res) diff --git a/cf_units/tests/integration/test__Unit_num2date.py b/cf_units/tests/integration/test__Unit_num2date.py index 11d4c1c3..e97cc238 100644 --- a/cf_units/tests/integration/test__Unit_num2date.py +++ b/cf_units/tests/integration/test__Unit_num2date.py @@ -21,13 +21,13 @@ def setup_units(self, calendar): self.udays = cf_units.Unit("days since 1970-01-01", calendar) def check_dates(self, nums, units, expected, only_cftime=True): - for num, unit, exp in zip(nums, units, expected): + for num, unit, exp in zip(nums, units, expected, strict=False): res = unit.num2date(num, only_use_cftime_datetimes=only_cftime) assert exp == res assert isinstance(res, type(exp)) def check_timedelta(self, nums, units, expected): - for num, unit, exp in zip(nums, units, expected): + for num, unit, exp in zip(nums, units, expected, strict=False): epoch = cftime.num2date(0, unit.cftime_unit, unit.calendar) res = unit.num2date(num) delta = res - epoch @@ -186,7 +186,8 @@ def test_simple_360_day(self): self.udays, self.udays, ] - # Expected results in (days, seconds, microseconds) delta from unit epoch. + # Expected results in (days, seconds, microseconds) delta from unit + # epoch. expected = [ (0, nums[0], 0), (0, nums[1], 0), @@ -218,7 +219,8 @@ def test_fractional_360_day(self): self.udays, self.udays, ] - # Expected results in (days, seconds, microseconds) delta from unit epoch. + # Expected results in (days, seconds, microseconds) delta from unit + # epoch. expected = [ (0, nums[0] * 60, 0), (0, nums[1] * 60, 0), @@ -234,7 +236,8 @@ def test_fractional_second_360_day(self): self.setup_units("360_day") nums = [0.25, 0.5, 0.75, 1.5, 2.5, 3.5, 4.5] units = [self.useconds] * 7 - # Expected results in (days, seconds, microseconds) delta from unit epoch. + # Expected results in (days, seconds, microseconds) delta from unit + # epoch. expected = [ (0, 0, 250000), (0, 0, 500000), @@ -273,7 +276,8 @@ def test_simple_365_day(self): self.udays, self.udays, ] - # Expected results in (days, seconds, microseconds) delta from unit epoch. + # Expected results in (days, seconds, microseconds) delta from unit + # epoch. expected = [ (0, nums[0], 0), (0, nums[1], 0), @@ -305,7 +309,8 @@ def test_fractional_365_day(self): self.udays, self.udays, ] - # Expected results in (days, seconds, microseconds) delta from unit epoch. + # Expected results in (days, seconds, microseconds) delta from unit + # epoch. expected = [ (0, nums[0] * 60, 0), (0, nums[1] * 60, 0), @@ -321,7 +326,8 @@ def test_fractional_second_365_day(self): self.setup_units("365_day") nums = [0.25, 0.5, 0.75, 1.5, 2.5, 3.5, 4.5] units = [self.useconds] * 7 - # Expected results in (days, seconds, microseconds) delta from unit epoch. + # Expected results in (days, seconds, microseconds) delta from unit + # epoch. expected = [ (0, 0, 250000), (0, 0, 500000), diff --git a/cf_units/tests/integration/test_num2date.py b/cf_units/tests/integration/test_num2date.py index 4f067e7b..8cd9ae4c 100644 --- a/cf_units/tests/integration/test_num2date.py +++ b/cf_units/tests/integration/test_num2date.py @@ -4,7 +4,6 @@ # See LICENSE in the root of the repository for full licensing details. """Test function :func:`cf_units.num2date`.""" - import pytest from cf_units import num2date diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index e1a74d9d..dce86a11 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -95,7 +95,7 @@ def test_license_headers(self): last_change_by_fname = self.last_change_by_fname() failed = False - for fname, last_change in sorted(last_change_by_fname.items()): + for fname in sorted(last_change_by_fname): full_fname = REPO_DIR / fname if ( full_fname.suffix == ".py" @@ -137,9 +137,7 @@ def test_python_versions(): text_searches: list[tuple[Path, str]] = [ ( pyproject_toml_file, - "target-version = [" - + ", ".join([f'"py{p}"' for p in supported_strip]) - + "]", + f'target-version = "py{supported_strip[0]}"', ), ( setup_cfg_file, @@ -193,15 +191,16 @@ def test_python_versions(): tox_text = tox_file.read_text() for version in supported_strip: - # A fairly lazy implementation, but should catch times when the section - # header does not match the conda_spec for the `tests` section. - # (Note that Tox does NOT provide its own helpful error in these cases). + # A fairly lazy implementation, but should catch times when the + # section header does not match the conda_spec for the `tests` + # section. (Note that Tox does NOT provide its own helpful + # error in these cases). py_version = f"py{version}" assert tox_text.count(f" {py_version}-") == 3 assert tox_text.count(f"{py_version}-lock") == 3 ci_wheels_text = ci_wheels_file.read_text() - (cibw_line,) = [ + (cibw_line,) = ( line for line in ci_wheels_text.splitlines() if "CIBW_SKIP" in line - ] - assert all([p not in cibw_line for p in supported_strip]) + ) + assert all(p not in cibw_line for p in supported_strip) diff --git a/cf_units/tests/test_unit.py b/cf_units/tests/test_unit.py index 6bc1ad82..10326239 100644 --- a/cf_units/tests/test_unit.py +++ b/cf_units/tests/test_unit.py @@ -833,7 +833,7 @@ def test_time_unit(self): class Test__immutable: def _set_attr(self, unit, name): setattr(unit, name, -999) - raise ValueError("'Unit' attribute {!r} is mutable!".format(name)) + raise ValueError(f"'Unit' attribute {name!r} is mutable!") def test_immutable(self): u = Unit("m") diff --git a/cf_units/tests/unit/test__udunits2.py b/cf_units/tests/unit/test__udunits2.py index 973c8a31..941b6a1d 100644 --- a/cf_units/tests/unit/test__udunits2.py +++ b/cf_units/tests/unit/test__udunits2.py @@ -67,12 +67,12 @@ def test_parse(self): assert unit is not None def test_parse_latin1(self): - angstrom = _ud.parse(self.system, b"\xe5ngstr\xF6m", _ud.UT_LATIN1) + angstrom = _ud.parse(self.system, b"\xe5ngstr\xf6m", _ud.UT_LATIN1) assert angstrom is not None def test_parse_ISO_8859_1(self): - angstrom = _ud.parse(self.system, b"\xe5ngstr\xF6m", _ud.UT_ISO_8859_1) + angstrom = _ud.parse(self.system, b"\xe5ngstr\xf6m", _ud.UT_ISO_8859_1) assert angstrom is not None diff --git a/cf_units/tests/unit/unit/test_Unit.py b/cf_units/tests/unit/unit/test_Unit.py index 2293cbae..dc44d6ff 100644 --- a/cf_units/tests/unit/unit/test_Unit.py +++ b/cf_units/tests/unit/unit/test_Unit.py @@ -4,7 +4,6 @@ # See LICENSE in the root of the repository for full licensing details. """Unit tests for the `cf_units.Unit` class.""" - import numpy as np import pytest diff --git a/cf_units/tests/unit/unit/test_as_unit.py b/cf_units/tests/unit/unit/test_as_unit.py index 245ceb22..d40c9212 100644 --- a/cf_units/tests/unit/unit/test_as_unit.py +++ b/cf_units/tests/unit/unit/test_as_unit.py @@ -9,7 +9,7 @@ from cf_units import Unit, as_unit -class StubUnit(object): +class StubUnit: def __init__(self, calendar=None): self.calendar = str(calendar) if calendar is not None else None # udunit category diff --git a/cf_units/util.py b/cf_units/util.py index 2f5841bf..8977c351 100644 --- a/cf_units/util.py +++ b/cf_units/util.py @@ -64,8 +64,8 @@ def __new__(cls, name, bases, namespace): if "__init__" not in namespace: # Create a default __init__ method for the class method_source = ( - "def __init__(self, %s):\n " - "self._init_from_tuple((%s,))" % (args, args) + f"def __init__(self, {args}):\n " + f"self._init_from_tuple(({args},))" ) exec(method_source, namespace) @@ -74,14 +74,12 @@ def __new__(cls, name, bases, namespace): if "_init" not in namespace: # Create a default _init method for the class method_source = ( - "def _init(self, %s):\n " - "self._init_from_tuple((%s,))" % (args, args) + f"def _init(self, {args}):\n " + f"self._init_from_tuple(({args},))" ) exec(method_source, namespace) - return super(_MetaOrderedHashable, cls).__new__( - cls, name, bases, namespace - ) + return super().__new__(cls, name, bases, namespace) class _OrderedHashable(Hashable, metaclass=_MetaOrderedHashable): diff --git a/pyproject.toml b/pyproject.toml index a0b9188b..ce92d7bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,34 +45,40 @@ testpaths = "cf_units" write_to = "cf_units/_version.py" local_scheme = "dirty-tag" -[tool.black] +[tool.ruff] +# Ignore generated code. +exclude = [ + "cf_units/_udunits2_parser/parser", +] line-length = 79 -target-version = ["py310", "py311", "py312"] -include = '\.pyi?$' -exclude = ''' -( - /( - \.eggs # exclude a few common directories in the - | \.git # root of the project - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - )/ - | _version.py -) -''' +target-version = "py310" + +[tool.ruff.lint] +select = [ + # pyflakes + "F", + # pycodestyle + "E", + "W", + # flake8-bugbear + "B", + # flake8-comprehensions + "C4", + # isort + "I", + # pyupgrade + "UP", +] +ignore = ["B904", "F403", "F405"] + +[tool.ruff.lint.isort] +known-first-party = ["cf_units"] + +[tool.ruff.lint.mccabe] +max-complexity = 22 -[tool.isort] -known_first_party = "cf_units" -line_length = 79 -profile = "black" -skip_gitignore = "True" -verbose = "False" +[tool.ruff.lint.pydocstyle] +convention = "numpy" [tool.repo-review] # These are a list of the currently failing tests: diff --git a/setup.cfg b/setup.cfg index 9face95d..686837b0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -61,38 +61,5 @@ all = %(docs)s %(test)s -[flake8] -# References: -# https://flake8.readthedocs.io/en/latest/user/configuration.html -# https://flake8.readthedocs.io/en/latest/user/error-codes.html -# https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes - -select = C,E,F,W,B,B950 -ignore = - # E203: whitespace before ':' - E203, - # E226: missing whitespace around arithmetic operator - E226, - # E231: missing whitespace after ',', ';', or ':' - E231, - # E402: module level imports on one line - E402, - # E501: line too long - E501, - # E731: do not assign a lambda expression, use a def - E731, - # W503: line break before binary operator - W503, - # W504: line break after binary operator - W504 -exclude = - .eggs, - .git, - build, - cf_units/_version.py, - doc, - etc, - cf_units/_udunits2_parser/parser/* - [aliases] test = pytest diff --git a/setup.py b/setup.py index 9745ede4..95a90521 100644 --- a/setup.py +++ b/setup.py @@ -144,17 +144,17 @@ def _set_builtin(name, value): [udunits_ext] = cythonize( udunits_ext, compiler_directives=COMPILER_DIRECTIVES, - # Assert python 3 source syntax: Currently required to suppress a warning, - # even though this is now the default (as-of Cython v3). + # Assert python 3 source syntax: Currently required to suppress a + # warning, even though this is now the default (as-of Cython v3). language_level="3str", ) cmdclass = {"clean_cython": CleanCython, "build_ext": numpy_build_ext} -kwargs = dict( - cmdclass=cmdclass, - ext_modules=[udunits_ext], - package_data=get_package_data(), -) +kwargs = { + "cmdclass": cmdclass, + "ext_modules": [udunits_ext], + "package_data": get_package_data(), +} setup(**kwargs)