From 4e3f4f11fa35983ddb163fa06bc97ac7200611f5 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Wed, 3 May 2023 09:42:10 +0100 Subject: [PATCH 01/28] config changes from #353 --- .pre-commit-config.yaml | 21 ++++++---------- pyproject.toml | 56 +++++++++++++++++++++++------------------ 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7bfa4f59..d120c97e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,22 +25,15 @@ repos: types: [file, python] args: [--config=./pyproject.toml] -- repo: https://github.com/PyCQA/flake8 - rev: 7.0.0 - 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: - id: sort-all types: [file, python] + +- repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.0.260" + hooks: + - id: ruff + types: [file, python] + args: [--fix] diff --git a/pyproject.toml b/pyproject.toml index 3fd0732b..74009406 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,30 +46,36 @@ write_to = "cf_units/_version.py" local_scheme = "dirty-tag" [tool.black] -line-length = 79 -target-version = ["py39", "py310", "py311"] +line-length = 88 +target-version = ["py38", "py39", "py310", "py311"] 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 -) -''' -[tool.isort] -known_first_party = "cf_units" -line_length = 79 -profile = "black" -skip_gitignore = "True" -verbose = "False" +[tool.ruff] +line-length = 88 +target-version = "py38" +select = [ + # pyflakes + "F", + # pycodestyle + "E", + "W", + # flake8-bugbear + "B", + # flake8-comprehensions + "C4", + # isort + "I", + # pyupgrade + "UP", +] +ignore = ["B904", "F403", "F405"] + +[tool.ruff.isort] +force-sort-within-sections = true +known-first-party = ["cf_units"] + +[tool.ruff.mccabe] +max-complexity = 22 + +[tool.ruff.pydocstyle] +convention = "numpy" From 6eea3df3390a2cedd8816cc823cc71d46c8f2435 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Wed, 3 May 2023 09:46:35 +0100 Subject: [PATCH 02/28] keep existing line length and import sort order --- pyproject.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 74009406..350ea694 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,12 +46,12 @@ write_to = "cf_units/_version.py" local_scheme = "dirty-tag" [tool.black] -line-length = 88 +line-length = 79 target-version = ["py38", "py39", "py310", "py311"] include = '\.pyi?$' [tool.ruff] -line-length = 88 +line-length = 79 target-version = "py38" select = [ # pyflakes @@ -71,7 +71,6 @@ select = [ ignore = ["B904", "F403", "F405"] [tool.ruff.isort] -force-sort-within-sections = true known-first-party = ["cf_units"] [tool.ruff.mccabe] From a440dfb98988749635f972cb7e7388d4d1d804c0 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Wed, 3 May 2023 15:25:24 +0100 Subject: [PATCH 03/28] remove flake8 config --- setup.cfg | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/setup.cfg b/setup.cfg index 092f5205..fac2d536 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 From e943de337cca758cb45f6634704d3756c6a85280 Mon Sep 17 00:00:00 2001 From: Ruth Comer <10599679+rcomer@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:34:35 +0000 Subject: [PATCH 04/28] Drop black; update ruff version and add formatter --- .pre-commit-config.yaml | 12 ++++-------- pyproject.toml | 5 ----- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d120c97e..f51515ae 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,13 +18,6 @@ repos: # Don't commit to main branch. - id: no-commit-to-branch -- repo: https://github.com/psf/black - rev: 24.4.0 - hooks: - - id: black - types: [file, python] - args: [--config=./pyproject.toml] - - repo: https://github.com/aio-libs/sort-all rev: v1.2.0 hooks: @@ -32,8 +25,11 @@ repos: types: [file, python] - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: "v0.0.260" + rev: "v0.1.5" hooks: + # Run the linter - id: ruff types: [file, python] args: [--fix] + # Run the formatter. + - id: ruff-format diff --git a/pyproject.toml b/pyproject.toml index 350ea694..880fe99a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,11 +45,6 @@ testpaths = "cf_units" write_to = "cf_units/_version.py" local_scheme = "dirty-tag" -[tool.black] -line-length = 79 -target-version = ["py38", "py39", "py310", "py311"] -include = '\.pyi?$' - [tool.ruff] line-length = 79 target-version = "py38" From 8ca2c812abc130b66df25cee76a726bfe4813aef Mon Sep 17 00:00:00 2001 From: Ruth Comer <10599679+rcomer@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:50:37 +0000 Subject: [PATCH 05/28] ruff autofixes --- cf_units/__init__.py | 22 +++++++++---------- cf_units/_udunits2_parser/__init__.py | 2 +- cf_units/_udunits2_parser/compile.py | 2 +- cf_units/_udunits2_parser/graph.py | 4 ++-- .../_udunits2_parser/parser/udunits2Lexer.py | 1 - .../_udunits2_parser/parser/udunits2Parser.py | 2 -- .../tests/integration/parse/test_parse.py | 4 ++-- cf_units/tests/test_coding_standards.py | 2 +- cf_units/tests/test_unit.py | 2 +- cf_units/tests/unit/unit/test_as_unit.py | 2 +- 10 files changed, 19 insertions(+), 24 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 33366729..a6050caf 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -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) @@ -727,7 +725,7 @@ 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(): @@ -1228,7 +1226,7 @@ def offset_by_time(self, origin): 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 @@ -1344,7 +1342,7 @@ def log(self, base): value_err = _ud_value_error( exception, "Failed to calculate logorithmic base " - "of {!r}".format(self), + f"of {self!r}", ) raise value_err from None calendar = None @@ -1386,7 +1384,7 @@ 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 @@ -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 @@ -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) @@ -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): diff --git a/cf_units/_udunits2_parser/__init__.py b/cf_units/_udunits2_parser/__init__.py index 0c7c0111..25f32c76 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 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..4022563d 100644 --- a/cf_units/_udunits2_parser/graph.py +++ b/cf_units/_udunits2_parser/graph.py @@ -28,7 +28,7 @@ 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) @@ -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..3d4c33df 100644 --- a/cf_units/_udunits2_parser/parser/udunits2Lexer.py +++ b/cf_units/_udunits2_parser/parser/udunits2Lexer.py @@ -1,6 +1,5 @@ # Generated from /home/ruth/git_stuff/cf-units/cf_units/_udunits2_parser/parser/udunits2Lexer.g4 by ANTLR 4.11.1 import sys -from io import StringIO from antlr4 import * diff --git a/cf_units/_udunits2_parser/parser/udunits2Parser.py b/cf_units/_udunits2_parser/parser/udunits2Parser.py index ee6d6d1f..67371300 100644 --- a/cf_units/_udunits2_parser/parser/udunits2Parser.py +++ b/cf_units/_udunits2_parser/parser/udunits2Parser.py @@ -1,7 +1,5 @@ # Generated from /home/ruth/git_stuff/cf-units/cf_units/_udunits2_parser/udunits2Parser.g4 by ANTLR 4.11.1 -# encoding: utf-8 import sys -from io import StringIO from antlr4 import * diff --git a/cf_units/tests/integration/parse/test_parse.py b/cf_units/tests/integration/parse/test_parse.py index d42b7a36..ecec5bb8 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 diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index 98cf40e7..b8f458db 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -75,7 +75,7 @@ def last_change_by_fname(): """ # Check the ".git" folder exists at the repo dir. if not os.path.isdir(os.path.join(REPO_DIR, ".git")): - raise ValueError("{} is not a git repository.".format(REPO_DIR)) + raise ValueError(f"{REPO_DIR} is not a git repository.") # Call "git whatchanged" to get the details of all the files and when # they were last changed. 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/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 From e4c389d4c53b760607925fd3ce276c3394c235eb Mon Sep 17 00:00:00 2001 From: Ruth Comer <10599679+rcomer@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:56:55 +0000 Subject: [PATCH 06/28] ruff formatter fix --- cf_units/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index a6050caf..4b96bc1e 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -1341,8 +1341,7 @@ def log(self, base): except _ud.UdunitsError as exception: value_err = _ud_value_error( exception, - "Failed to calculate logorithmic base " - f"of {self!r}", + "Failed to calculate logorithmic base " f"of {self!r}", ) raise value_err from None calendar = None From 5044a17e9125c179310b0a204c93a38a74c6ac63 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Tue, 14 Nov 2023 15:34:40 +0000 Subject: [PATCH 07/28] ruff 'unsafe' autofixes --- cf_units/__init__.py | 10 ++++------ cf_units/_udunits2_parser/__init__.py | 2 +- cf_units/_udunits2_parser/graph.py | 2 +- cf_units/_udunits2_parser/parser/udunits2Parser.py | 4 ++-- cf_units/tests/test_coding_standards.py | 2 +- cf_units/util.py | 10 +++++----- setup.py | 10 +++++----- 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 4b96bc1e..06debc0c 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -191,8 +191,7 @@ def suppress_errors(): except _ud.UdunitsError as e: error_msg = ': "%s"' % e.error_msg() 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()}] Failed to open UDUNITS-2 XML unit database{error_msg}" ) @@ -930,7 +929,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"{str(value)} {self}" return result @property @@ -1793,8 +1792,7 @@ 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, + "Expect a numpy array of '{}' or '{}'".format(*np.float32), np.float64, ) ctype = result.dtype.type @@ -1827,7 +1825,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 25f32c76..aec51503 100644 --- a/cf_units/_udunits2_parser/__init__.py +++ b/cf_units/_udunits2_parser/__init__.py @@ -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/graph.py b/cf_units/_udunits2_parser/graph.py index 4022563d..561271aa 100644 --- a/cf_units/_udunits2_parser/graph.py +++ b/cf_units/_udunits2_parser/graph.py @@ -30,7 +30,7 @@ def _repr_ctx(self): kwargs = ", ".join( 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()) diff --git a/cf_units/_udunits2_parser/parser/udunits2Parser.py b/cf_units/_udunits2_parser/parser/udunits2Parser.py index 67371300..bd197034 100644 --- a/cf_units/_udunits2_parser/parser/udunits2Parser.py +++ b/cf_units/_udunits2_parser/parser/udunits2Parser.py @@ -2223,8 +2223,8 @@ def timezone_offset(self): return localctx def sempred(self, localctx: RuleContext, ruleIndex: int, predIndex: int): - if self._predicates == None: - self._predicates = dict() + if self._predicates is None: + self._predicates = {} self._predicates[2] = self.product_sempred pred = self._predicates.get(ruleIndex, None) if pred is None: diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index b8f458db..ff4d0364 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -109,7 +109,7 @@ def test_license_headers(self): ) failed = False - for fname, last_change in sorted(last_change_by_fname.items()): + for fname, _last_change in sorted(last_change_by_fname.items()): full_fname = os.path.join(REPO_DIR, fname) if ( full_fname.endswith(".py") diff --git a/cf_units/util.py b/cf_units/util.py index 2f5841bf..adf5e40b 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,12 +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__( + return super().__new__( cls, name, bases, namespace ) diff --git a/setup.py b/setup.py index d508892c..5699c46b 100644 --- a/setup.py +++ b/setup.py @@ -147,10 +147,10 @@ def _set_builtin(name, value): 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) From 253f8f52c7502aeb4692116fd971b4a4b724a999 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Tue, 14 Nov 2023 15:52:47 +0000 Subject: [PATCH 08/28] Ruth fixes for unsafe fixes --- cf_units/__init__.py | 7 +++---- cf_units/tests/test_coding_standards.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 06debc0c..214503a1 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -929,7 +929,7 @@ def title(self, value): dt = self.num2date(value) result = dt.strftime("%Y-%m-%d %H:%M:%S") else: - result = f"{str(value)} {self}" + result = f"{value} {self}" return result @property @@ -1792,9 +1792,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 '{}' or '{}'".format(*np.float32), - np.float64, - ) + "Expect a numpy array of " + f"'{np.float32}' or '{np.float64}'") ctype = result.dtype.type # Utilise global convenience dictionary # _cv_convert_array to convert our array in 1d form diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index ff4d0364..660293aa 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -109,7 +109,7 @@ def test_license_headers(self): ) failed = False - for fname, _last_change in sorted(last_change_by_fname.items()): + for fname in sorted(last_change_by_fname): full_fname = os.path.join(REPO_DIR, fname) if ( full_fname.endswith(".py") From 2a5ceb395b7849fda5790f8fbedf07c78ee6b2d8 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Tue, 14 Nov 2023 16:40:05 +0000 Subject: [PATCH 09/28] re-run ruff formatter --- cf_units/__init__.py | 3 ++- cf_units/util.py | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 214503a1..2b1a25eb 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -1793,7 +1793,8 @@ def convert(self, value, other, ctype=FLOAT64, inplace=False): if result.dtype.type not in (np.float32, np.float64): raise TypeError( "Expect a numpy array of " - f"'{np.float32}' or '{np.float64}'") + f"'{np.float32}' or '{np.float64}'" + ) ctype = result.dtype.type # Utilise global convenience dictionary # _cv_convert_array to convert our array in 1d form diff --git a/cf_units/util.py b/cf_units/util.py index adf5e40b..8977c351 100644 --- a/cf_units/util.py +++ b/cf_units/util.py @@ -79,9 +79,7 @@ def __new__(cls, name, bases, namespace): ) exec(method_source, namespace) - return super().__new__( - cls, name, bases, namespace - ) + return super().__new__(cls, name, bases, namespace) class _OrderedHashable(Hashable, metaclass=_MetaOrderedHashable): From 6ab312721e869935f42e5512e76801e19d8fce77 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Tue, 14 Nov 2023 16:55:31 +0000 Subject: [PATCH 10/28] Manually address E501 and B018 --- cf_units/__init__.py | 5 +++-- .../_udunits2_parser/parser/udunits2Lexer.py | 3 ++- .../_udunits2_parser/parser/udunits2Parser.py | 2 +- .../parser/udunits2ParserVisitor.py | 5 +++-- cf_units/tests/integration/parse/test_parse.py | 4 ++-- .../tests/integration/test__Unit_num2date.py | 18 ++++++++++++------ 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 2b1a25eb..bb639962 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -191,7 +191,8 @@ def suppress_errors(): except _ud.UdunitsError as e: error_msg = ': "%s"' % e.error_msg() if e.errnum else "" raise OSError( - f"[{e.status_msg()}] Failed to open UDUNITS-2 XML unit database{error_msg}" + f"[{e.status_msg()}] " + f"Failed to open UDUNITS-2 XML unit database{error_msg}" ) @@ -1670,7 +1671,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") diff --git a/cf_units/_udunits2_parser/parser/udunits2Lexer.py b/cf_units/_udunits2_parser/parser/udunits2Lexer.py index 3d4c33df..d8742bdb 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 +# Generated from cf_units/_udunits2_parser/parser/udunits2Lexer.g4 by +# ANTLR 4.11.1 import sys from antlr4 import * diff --git a/cf_units/_udunits2_parser/parser/udunits2Parser.py b/cf_units/_udunits2_parser/parser/udunits2Parser.py index bd197034..5cff5fe4 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 cf_units/_udunits2_parser/udunits2Parser.g4 by ANTLR 4.11.1 import sys from antlr4 import * diff --git a/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py b/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py index f83c692e..6bac1ac0 100644 --- a/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py +++ b/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.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 cf_units/_udunits2_parser/udunits2Parser.g4 by ANTLR 4.11.1 from antlr4 import * if __name__ is not None and "." in __name__: @@ -6,7 +6,8 @@ else: from udunits2Parser import udunits2Parser -# This class defines a complete generic visitor for a parse tree produced by udunits2Parser. +# This class defines a complete generic visitor for a parse tree produced by +# udunits2Parser. class udunits2ParserVisitor(ParseTreeVisitor): diff --git a/cf_units/tests/integration/parse/test_parse.py b/cf_units/tests/integration/parse/test_parse.py index ecec5bb8..bc0498f5 100644 --- a/cf_units/tests/integration/parse/test_parse.py +++ b/cf_units/tests/integration/parse/test_parse.py @@ -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 # noqa: B018 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 # noqa: B018 with pytest.raises(SyntaxError): normalize(unit_str) diff --git a/cf_units/tests/integration/test__Unit_num2date.py b/cf_units/tests/integration/test__Unit_num2date.py index 11d4c1c3..0f39225f 100644 --- a/cf_units/tests/integration/test__Unit_num2date.py +++ b/cf_units/tests/integration/test__Unit_num2date.py @@ -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), From 48bdcdc48a76cba0c93eaad3660544c93ab91b80 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Wed, 15 Nov 2023 11:33:30 +0000 Subject: [PATCH 11/28] point to astral-sh organisation; tidy some broken strings --- .pre-commit-config.yaml | 2 +- cf_units/__init__.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f51515ae..5bdde7fe 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: - id: sort-all types: [file, python] -- repo: https://github.com/charliermarsh/ruff-pre-commit +- repo: https://github.com/astral-sh/ruff-pre-commit rev: "v0.1.5" hooks: # Run the linter diff --git a/cf_units/__init__.py b/cf_units/__init__.py index bb639962..fdd5b4ec 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -1220,7 +1220,7 @@ def offset_by_time(self, origin): 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) @@ -1336,12 +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 " f"of {self!r}", + f"Failed to calculate logorithmic base of {self!r}", ) raise value_err from None calendar = None From 23c47fb80236bd4b8cd549270afd0b8491878ae1 Mon Sep 17 00:00:00 2001 From: Ruth Comer Date: Mon, 26 Feb 2024 16:04:24 +0000 Subject: [PATCH 12/28] review actions --- cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py | 3 +-- cf_units/tests/integration/parse/test_parse.py | 4 ++-- pyproject.toml | 4 ++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py b/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py index 6bac1ac0..428d5978 100644 --- a/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py +++ b/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py @@ -6,8 +6,7 @@ else: from udunits2Parser import udunits2Parser -# This class defines a complete generic visitor for a parse tree produced by -# udunits2Parser. +# This class defines a complete generic visitor for a parse tree produced by udunits2Parser. class udunits2ParserVisitor(ParseTreeVisitor): diff --git a/cf_units/tests/integration/parse/test_parse.py b/cf_units/tests/integration/parse/test_parse.py index bc0498f5..5a86371c 100644 --- a/cf_units/tests/integration/parse/test_parse.py +++ b/cf_units/tests/integration/parse/test_parse.py @@ -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 # noqa: B018 + _ = 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 # noqa: B018 + _ = cf_units.Unit(unit_str).symbol with pytest.raises(SyntaxError): normalize(unit_str) diff --git a/pyproject.toml b/pyproject.toml index 880fe99a..67d0778d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,3 +73,7 @@ max-complexity = 22 [tool.ruff.pydocstyle] convention = "numpy" + +[tool.ruff.per-file-ignores] +# Allow the longer comment lines that the generated code produces. +"cf_units/_udunits2_parser/parser/*.py" = ["E501"] From b318ace02787d090b2db4f1a59cc20a1b57a23e2 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 24 Sep 2024 14:02:38 +0100 Subject: [PATCH 13/28] update ruff-pre-commit version --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 266d35e7..88575f8b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: #args: ["--show=errskip"] # show everything for the moment - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.1.5" + rev: "v0.4.10" hooks: # Run the linter - id: ruff From cfe6fdc379493013c017b65e7d044851837d81eb Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 24 Sep 2024 14:28:58 +0100 Subject: [PATCH 14/28] fix pyproject.toml --- pyproject.toml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ca40ffb8..45aeef31 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,9 @@ local_scheme = "dirty-tag" [tool.ruff] line-length = 79 -target-version = ["py310", "py311", "py312"] +target-version = ">=3.10" + +[tool.ruff.lint] select = [ # pyflakes "F", @@ -65,16 +67,16 @@ select = [ ] ignore = ["B904", "F403", "F405"] -[tool.ruff.isort] +[tool.ruff.lint.isort] known-first-party = ["cf_units"] -[tool.ruff.mccabe] +[tool.ruff.lint.mccabe] max-complexity = 22 -[tool.ruff.pydocstyle] +[tool.ruff.lint.pydocstyle] convention = "numpy" -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] # Allow the longer comment lines that the generated code produces. "cf_units/_udunits2_parser/parser/*.py" = ["E501"] From 2613ef9fb9d3e02c5a679e856ab7a57ea871ecc5 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 24 Sep 2024 14:34:06 +0100 Subject: [PATCH 15/28] fix pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 45aeef31..7aa3d6a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ local_scheme = "dirty-tag" [tool.ruff] line-length = 79 -target-version = ">=3.10" +target-version = "py310" [tool.ruff.lint] select = [ From 94f6cb52080a6e794c3b71f3bb0beb432235d70e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:34:19 +0000 Subject: [PATCH 16/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cf_units/__init__.py | 6 ++---- cf_units/tests/integration/test__Unit_date2num.py | 6 +++--- cf_units/tests/integration/test__Unit_num2date.py | 4 ++-- cf_units/tests/integration/test_num2date.py | 1 - cf_units/tests/test_coding_standards.py | 4 ++-- cf_units/tests/unit/test__udunits2.py | 4 ++-- cf_units/tests/unit/unit/test_Unit.py | 1 - 7 files changed, 11 insertions(+), 15 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index fdd5b4ec..ffb6fbe5 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -592,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 @@ -1385,9 +1385,7 @@ def __repr__(self): if self.calendar is None: result = f"{self.__class__.__name__}('{self}')" else: - result = "{}('{}', calendar='{}')".format( - self.__class__.__name__, self, self.calendar - ) + result = f"{self.__class__.__name__}('{self}', calendar='{self.calendar}')" return result def _offset_common(self, offset): 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 0f39225f..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 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 7cc0aa26..04c54346 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -201,7 +201,7 @@ def test_python_versions(): 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]) 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 From e5b3f710b9039cf740d859b632d526d3a3c3cf26 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 24 Sep 2024 15:21:00 +0100 Subject: [PATCH 17/28] ruff fixes --- cf_units/__init__.py | 16 ++++++++-------- cf_units/tests/test_coding_standards.py | 11 ++++++----- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index fdd5b4ec..9c434080 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -189,7 +189,7 @@ 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( 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: @@ -612,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 @@ -731,7 +731,7 @@ def __init__(self, unit, calendar=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_] @@ -1218,7 +1218,7 @@ 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" ) @@ -1427,7 +1427,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) @@ -1583,7 +1583,7 @@ def __pow__(self, power): # 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)) diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index 7cc0aa26..64590e37 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -193,15 +193,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]) From e4324825b6fa3464d063a71aef159c79afdc131f Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 24 Sep 2024 15:24:49 +0100 Subject: [PATCH 18/28] fix parantheses --- cf_units/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index ef672c6e..0a40f0c8 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -592,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, strict=False): + for name, value in zip(self._names, values): object.__setattr__(self, name, value) # Provide hash semantics @@ -1218,7 +1218,7 @@ 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" ) @@ -1385,7 +1385,9 @@ def __repr__(self): if self.calendar is None: result = f"{self.__class__.__name__}('{self}')" else: - result = f"{self.__class__.__name__}('{self}', calendar='{self.calendar}')" + result = "{}('{}', calendar='{}')".format( + self.__class__.__name__, self, self.calendar + ) return result def _offset_common(self, offset): From 5dfccb20fc602d3800ac710b2c5b4f2a4a39d8ba Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:25:06 +0000 Subject: [PATCH 19/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cf_units/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 0a40f0c8..81b67815 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -592,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 @@ -1385,9 +1385,7 @@ def __repr__(self): if self.calendar is None: result = f"{self.__class__.__name__}('{self}')" else: - result = "{}('{}', calendar='{}')".format( - self.__class__.__name__, self, self.calendar - ) + result = f"{self.__class__.__name__}('{self}', calendar='{self.calendar}')" return result def _offset_common(self, offset): From f73d4665643b9db2097291b70e5d76e99451b981 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 24 Sep 2024 15:44:55 +0100 Subject: [PATCH 20/28] more lint fixes --- cf_units/__init__.py | 12 ++++++------ cf_units/tests/test_coding_standards.py | 2 +- setup.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 0a40f0c8..f3c024bf 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -1580,8 +1580,8 @@ 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 = f"Cannot raise a unit by a decimal (got {power:s})." raise ValueError(msg) @@ -1659,10 +1659,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: diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index 64590e37..643a1451 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -202,7 +202,7 @@ def test_python_versions(): assert tox_text.count(f"{py_version}-lock") == 3 ci_wheels_text = ci_wheels_file.read_text() - (cibw_line,) = ( + cibw_line = next( 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]) diff --git a/setup.py b/setup.py index 864a2c31..95a90521 100644 --- a/setup.py +++ b/setup.py @@ -144,8 +144,8 @@ 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", ) From bb2d5dc19ec36a3b8f2f55b033c12f1a8a490308 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 25 Sep 2024 12:17:02 +0100 Subject: [PATCH 21/28] linting + pre-commit fixes --- .pre-commit-config.yaml | 8 +++++++- cf_units/__init__.py | 3 ++- cf_units/tests/test_coding_standards.py | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 88575f8b..cd90cea5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,12 +32,18 @@ repos: 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/asottile/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] + args: [--fix, --show-fixes] # Run the formatter. - id: ruff-format diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 01f4d5c3..7032efb7 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -1385,7 +1385,8 @@ def __repr__(self): if self.calendar is None: result = f"{self.__class__.__name__}('{self}')" else: - result = f"{self.__class__.__name__}('{self}', calendar='{self.calendar}')" + result = (f"{self.__class__.__name__}" + f"('{self}', calendar='{self.calendar}')") return result def _offset_common(self, offset): diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index 643a1451..e6bed081 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -202,7 +202,7 @@ def test_python_versions(): assert tox_text.count(f"{py_version}-lock") == 3 ci_wheels_text = ci_wheels_file.read_text() - cibw_line = next( + (cibw_line,) = [ line for line in ci_wheels_text.splitlines() if "CIBW_SKIP" in line - ) + ] # NOQA C419 assert all([p not in cibw_line for p in supported_strip]) From 889c4bd90e26f9e51fc8b2cf6783f93a990e6a28 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 11:17:17 +0000 Subject: [PATCH 22/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cf_units/__init__.py | 6 ++++-- cf_units/tests/test_coding_standards.py | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cf_units/__init__.py b/cf_units/__init__.py index 7032efb7..454bd51c 100644 --- a/cf_units/__init__.py +++ b/cf_units/__init__.py @@ -1385,8 +1385,10 @@ def __repr__(self): if self.calendar is None: result = f"{self.__class__.__name__}('{self}')" else: - result = (f"{self.__class__.__name__}" - f"('{self}', calendar='{self.calendar}')") + result = ( + f"{self.__class__.__name__}" + f"('{self}', calendar='{self.calendar}')" + ) return result def _offset_common(self, offset): diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index e6bed081..b0cd6320 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -202,7 +202,7 @@ def test_python_versions(): 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 - ] # NOQA C419 + ) # NOQA C419 assert all([p not in cibw_line for p in supported_strip]) From b15e3531492719ff15661375155bc0d4ad636c8a Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 25 Sep 2024 12:22:59 +0100 Subject: [PATCH 23/28] linting + pre-commit fixes --- .pre-commit-config.yaml | 2 +- cf_units/tests/test_coding_standards.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cd90cea5..8f1ba108 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,7 +32,7 @@ repos: 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/asottile/blacken-docs +- repo: https://github.com/adamchainz/blacken-docs rev: 1.16.0 hooks: - id: blacken-docs diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index e6bed081..d1c71fac 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.py @@ -204,5 +204,5 @@ def test_python_versions(): ci_wheels_text = ci_wheels_file.read_text() (cibw_line,) = [ line for line in ci_wheels_text.splitlines() if "CIBW_SKIP" in line - ] # NOQA C419 - assert all([p not in cibw_line for p in supported_strip]) + ] + assert all(p not in cibw_line for p in supported_strip) From 59e3f106da0f6aac43261b7dda98f98f6458a1d1 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 25 Sep 2024 14:07:19 +0100 Subject: [PATCH 24/28] fix test --- cf_units/tests/test_coding_standards.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cf_units/tests/test_coding_standards.py b/cf_units/tests/test_coding_standards.py index 2091833f..dce86a11 100644 --- a/cf_units/tests/test_coding_standards.py +++ b/cf_units/tests/test_coding_standards.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, From 3fccd63fe76c095f6552349c82ad35ed36e5c49d Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 25 Sep 2024 14:43:28 +0100 Subject: [PATCH 25/28] revert ruff fix --- cf_units/tests/unit/test__udunits2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cf_units/tests/unit/test__udunits2.py b/cf_units/tests/unit/test__udunits2.py index 941b6a1d..973c8a31 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 From a1cd41fc556c104003f9cad2f46e6005055799c1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:43:41 +0000 Subject: [PATCH 26/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cf_units/tests/unit/test__udunits2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From e0b930c34acdece06f3be4a772ab4bd3f5562391 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 25 Sep 2024 15:32:07 +0100 Subject: [PATCH 27/28] ignore generated code --- cf_units/_udunits2_parser/parser/udunits2Lexer.py | 5 +++-- cf_units/_udunits2_parser/parser/udunits2Parser.py | 8 +++++--- cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py | 2 +- pyproject.toml | 3 +++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cf_units/_udunits2_parser/parser/udunits2Lexer.py b/cf_units/_udunits2_parser/parser/udunits2Lexer.py index d8742bdb..0dc07819 100644 --- a/cf_units/_udunits2_parser/parser/udunits2Lexer.py +++ b/cf_units/_udunits2_parser/parser/udunits2Lexer.py @@ -1,6 +1,7 @@ -# Generated from cf_units/_udunits2_parser/parser/udunits2Lexer.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 from antlr4 import * diff --git a/cf_units/_udunits2_parser/parser/udunits2Parser.py b/cf_units/_udunits2_parser/parser/udunits2Parser.py index 5cff5fe4..1275018b 100644 --- a/cf_units/_udunits2_parser/parser/udunits2Parser.py +++ b/cf_units/_udunits2_parser/parser/udunits2Parser.py @@ -1,5 +1,7 @@ -# Generated from 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 from antlr4 import * @@ -2223,8 +2225,8 @@ def timezone_offset(self): return localctx def sempred(self, localctx: RuleContext, ruleIndex: int, predIndex: int): - if self._predicates is None: - self._predicates = {} + if self._predicates == None: + self._predicates = dict() self._predicates[2] = self.product_sempred pred = self._predicates.get(ruleIndex, None) if pred is None: diff --git a/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py b/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py index 428d5978..f83c692e 100644 --- a/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py +++ b/cf_units/_udunits2_parser/parser/udunits2ParserVisitor.py @@ -1,4 +1,4 @@ -# Generated from cf_units/_udunits2_parser/udunits2Parser.g4 by ANTLR 4.11.1 +# Generated from /home/ruth/git_stuff/cf-units/cf_units/_udunits2_parser/udunits2Parser.g4 by ANTLR 4.11.1 from antlr4 import * if __name__ is not None and "." in __name__: diff --git a/pyproject.toml b/pyproject.toml index 7aa3d6a5..8734acf9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,9 @@ write_to = "cf_units/_version.py" local_scheme = "dirty-tag" [tool.ruff] +exclude = [ + "cf_units/_udunits2_parser/parser", +] line-length = 79 target-version = "py310" From f82ea4b57ff09ac3cc56cdcdd6eb95ce4c7b8ec9 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 25 Sep 2024 16:17:42 +0100 Subject: [PATCH 28/28] remove redundant ignore --- pyproject.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8734acf9..ce92d7bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ write_to = "cf_units/_version.py" local_scheme = "dirty-tag" [tool.ruff] +# Ignore generated code. exclude = [ "cf_units/_udunits2_parser/parser", ] @@ -79,10 +80,6 @@ max-complexity = 22 [tool.ruff.lint.pydocstyle] convention = "numpy" -[tool.ruff.lint.per-file-ignores] -# Allow the longer comment lines that the generated code produces. -"cf_units/_udunits2_parser/parser/*.py" = ["E501"] - [tool.repo-review] # These are a list of the currently failing tests: ignore = [