Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-48788: Use ruff format #116

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4
Expand Down
16 changes: 0 additions & 16 deletions .github/workflows/lint.yaml

This file was deleted.

27 changes: 6 additions & 21 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,34 +1,19 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black
# It is recommended to specify the latest version of Python
# supported by your project here, or alternatively use
# pre-commit's default_language_version, see
# https://pre-commit.com/#top_level-default_language_version
language_version: python3.10
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
name: isort (python)
- repo: https://github.com/PyCQA/flake8
rev: 7.1.0
hooks:
- id: flake8
- id: check-toml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.5.1
rev: v0.9.4
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/numpy/numpydoc
rev: "v1.7.0"
rev: "v1.8.0"
hooks:
- id: numpydoc-validation
2 changes: 1 addition & 1 deletion doc/changes/DM-48074.feature.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Introduced the `keyCheck` callback to `DictField` and `ConfigDictField`, allowing custom key validation during assignment. Added unit tests to ensure functionality.
Introduced the `keyCheck` callback to `DictField` and `ConfigDictField`, allowing custom key validation during assignment. Added unit tests to ensure functionality.
12 changes: 12 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ target-version = ["py310"]
[tool.isort]
profile = "black"
line_length = 110
known_first_party = ["lsst"]

[tool.towncrier]
package = "lsst.pex.config"
Expand Down Expand Up @@ -149,6 +150,9 @@ select = [
"W", # pycodestyle
"D", # pydocstyle
"UP", # pyupgrade
"I", # isort
"RUF022", # sort __all__
"C4", # comprehensions
]
extend-select = [
"RUF100", # Warn about unused noqa
Expand All @@ -157,12 +161,20 @@ extend-select = [
[tool.ruff.lint.per-file-ignores]
"tests/testLib.py" = ["F403", "F405"] # Wildcard imports.

[tool.ruff.lint.isort]
known-first-party = ["lsst"]

[tool.ruff.lint.pycodestyle]
max-doc-length = 79

[tool.ruff.lint.pydocstyle]
convention = "numpy"

[tool.ruff.format]
docstring-code-format = true
# Formatter does not know about indenting.
docstring-code-line-length = 69

[tool.numpydoc_validation]
checks = [
"all", # All except the rules listed below.
Expand Down
4 changes: 2 additions & 2 deletions python/lsst/pex/config/callStack.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

__all__ = ["getCallerFrame", "getStackFrame", "StackFrame", "getCallStack"]
__all__ = ["StackFrame", "getCallStack", "getCallerFrame", "getStackFrame"]

import inspect
import linecache
Expand All @@ -50,7 +50,7 @@ def getCallerFrame(relative=0):
This function is excluded from the frame.
"""
frame = inspect.currentframe().f_back.f_back # Our caller's caller
for ii in range(relative):
for _ in range(relative):
frame = frame.f_back
return frame

Expand Down
2 changes: 1 addition & 1 deletion python/lsst/pex/config/comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
writing messages as well as floating-point comparisons and shortcuts.
"""

__all__ = ("getComparisonName", "compareScalars", "compareConfigs")
__all__ = ("compareConfigs", "compareScalars", "getComparisonName")

import numpy

Expand Down
40 changes: 20 additions & 20 deletions python/lsst/pex/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
"Config",
"ConfigMeta",
"Field",
"FieldTypeVar",
"FieldValidationError",
"UnexpectedProxyUsageError",
"FieldTypeVar",
)

import copy
Expand Down Expand Up @@ -390,7 +390,6 @@
>>> class Example(Config):
... myInt = Field("An integer field.", int, default=0)
... name = Field[str](doc="A string Field")
...
>>> print(config.myInt)
0
>>> config.myInt = 5
Expand Down Expand Up @@ -730,13 +729,14 @@
# try statements are almost free in python if they succeed
try:
return instance._storage[self.name]
except AttributeError:
except AttributeError as e:

Check warning on line 732 in python/lsst/pex/config/config.py

View check run for this annotation

Codecov / codecov/patch

python/lsst/pex/config/config.py#L732

Added line #L732 was not covered by tests
if not isinstance(instance, Config):
return self
else:
raise AttributeError(
e.add_note(

Check warning on line 736 in python/lsst/pex/config/config.py

View check run for this annotation

Codecov / codecov/patch

python/lsst/pex/config/config.py#L736

Added line #L736 was not covered by tests
f"Config {instance} is missing _storage attribute, likely incorrectly initialized"
)
raise

Check warning on line 739 in python/lsst/pex/config/config.py

View check run for this annotation

Codecov / codecov/patch

python/lsst/pex/config/config.py#L739

Added line #L739 was not covered by tests

def __set__(
self, instance: Config, value: FieldTypeVar | None, at: Any = None, label: str = "assignment"
Expand Down Expand Up @@ -791,7 +791,7 @@
try:
self._validateValue(value)
except BaseException as e:
raise FieldValidationError(self, instance, str(e))
raise FieldValidationError(self, instance, str(e)) from e

instance._storage[self.name] = value
if at is None:
Expand Down Expand Up @@ -943,23 +943,25 @@
>>> from lsst.pex.config import Config, Field, ListField
>>> class DemoConfig(Config):
... intField = Field(doc="An integer field", dtype=int, default=42)
... listField = ListField(doc="List of favorite beverages.", dtype=str,
... default=['coffee', 'green tea', 'water'])
...
... listField = ListField(
... doc="List of favorite beverages.",
... dtype=str,
... default=["coffee", "green tea", "water"],
... )
>>> config = DemoConfig()

Configs support many `dict`-like APIs:

>>> config.keys()
['intField', 'listField']
>>> 'intField' in config
>>> "intField" in config
True

Individual fields can be accessed as attributes of the configuration:

>>> config.intField
42
>>> config.listField.append('earl grey tea')
>>> config.listField.append("earl grey tea")
>>> print(config.listField)
['coffee', 'green tea', 'water', 'earl grey tea']
"""
Expand Down Expand Up @@ -1102,30 +1104,27 @@

>>> from lsst.pex.config import Config, Field
>>> class DemoConfig(Config):
... fieldA = Field(doc='Field A', dtype=int, default=42)
... fieldB = Field(doc='Field B', dtype=bool, default=True)
... fieldC = Field(doc='Field C', dtype=str, default='Hello world')
...
... fieldA = Field(doc="Field A", dtype=int, default=42)
... fieldB = Field(doc="Field B", dtype=bool, default=True)
... fieldC = Field(doc="Field C", dtype=str, default="Hello world")
>>> config = DemoConfig()

These are the default values of each field:

>>> for name, value in config.iteritems():
... print(f"{name}: {value}")
...
fieldA: 42
fieldB: True
fieldC: 'Hello world'

Using this method to update ``fieldA`` and ``fieldC``:

>>> config.update(fieldA=13, fieldC='Updated!')
>>> config.update(fieldA=13, fieldC="Updated!")

Now the values of each field are:

>>> for name, value in config.iteritems():
... print(f"{name}: {value}")
...
fieldA: 13
fieldB: True
fieldC: 'Updated!'
Expand All @@ -1137,8 +1136,9 @@
try:
field = self._fields[name]
field.__set__(self, value, at=at, label=label)
except KeyError:
raise KeyError(f"No field of name {name} exists in config type {_typeStr(self)}")
except KeyError as e:
e.add_note(f"No field of name {name} exists in config type {_typeStr(self)}")
raise

Check warning on line 1141 in python/lsst/pex/config/config.py

View check run for this annotation

Codecov / codecov/patch

python/lsst/pex/config/config.py#L1139-L1141

Added lines #L1139 - L1141 were not covered by tests

def load(self, filename, root="config"):
"""Modify this config in place by executing the Python code in a
Expand Down Expand Up @@ -1415,7 +1415,7 @@
class.
"""
self._imports.add(self.__module__)
for name, field in self._fields.items():
for field in self._fields.values():
field._collectImports(self, self._imports)

def toDict(self):
Expand Down
16 changes: 7 additions & 9 deletions python/lsst/pex/config/configChoiceField.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@
if v not in self._dict:
# invoke __getitem__ to ensure it's present
self._dict.__getitem__(v, at=at)
except TypeError:
except TypeError as e:
msg = f"Value {value} is of incorrect type {_typeStr(value)}. Sequence type expected"
raise FieldValidationError(self._field, self._config, msg)
raise FieldValidationError(self._field, self._config, msg) from e

Check warning on line 81 in python/lsst/pex/config/configChoiceField.py

View check run for this annotation

Codecov / codecov/patch

python/lsst/pex/config/configChoiceField.py#L81

Added line #L81 was not covered by tests
self._set = set(value)
else:
self._set = set()
Expand Down Expand Up @@ -293,10 +293,10 @@
except KeyError:
try:
dtype = self.types[k]
except Exception:
except Exception as e:
raise FieldValidationError(
self._field, self._config, f"Unknown key {k!r} in Registry/ConfigChoiceField"
)
) from e
name = _joinNamePath(self._config._name, self._field.name, k)
if at is None:
at = getCallStack()
Expand All @@ -310,8 +310,8 @@

try:
dtype = self.types[k]
except Exception:
raise FieldValidationError(self._field, self._config, f"Unknown key {k!r}")
except Exception as e:
raise FieldValidationError(self._field, self._config, f"Unknown key {k!r}") from e

Check warning on line 314 in python/lsst/pex/config/configChoiceField.py

View check run for this annotation

Codecov / codecov/patch

python/lsst/pex/config/configChoiceField.py#L313-L314

Added lines #L313 - L314 were not covered by tests

if value != dtype and type(value) is not dtype:
msg = (
Expand Down Expand Up @@ -443,15 +443,13 @@
>>> from lsst.pex.config import Config, ConfigChoiceField, Field
>>> class AaaConfig(Config):
... somefield = Field("doc", int)
...

The ``MyConfig`` config has a ``ConfigChoiceField`` field called ``choice``
that maps the ``AaaConfig`` type to the ``"AAA"`` key:

>>> TYPEMAP = {"AAA", AaaConfig}
>>> class MyConfig(Config):
... choice = ConfigChoiceField("doc for choice", TYPEMAP)
...

Creating an instance of ``MyConfig``:

Expand All @@ -460,7 +458,7 @@
Setting value of the field ``somefield`` on the "AAA" key of the ``choice``
field:

>>> instance.choice['AAA'].somefield = 5
>>> instance.choice["AAA"].somefield = 5

**Selecting the active configuration**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations

__all__ = ["ConfigurableAction", "ActionTypeVar"]
__all__ = ["ActionTypeVar", "ConfigurableAction"]

from typing import Any, TypeVar

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations

__all__ = ("ConfigurableActionStructField", "ConfigurableActionStruct")
__all__ = ("ConfigurableActionStruct", "ConfigurableActionStructField")

import weakref
from collections.abc import Iterable, Iterator, Mapping
Expand Down Expand Up @@ -55,7 +55,7 @@
value = value._attrs
else:
raise ValueError(
"Can only update a ConfigurableActionStruct with an instance of such, or a " "mapping"
"Can only update a ConfigurableActionStruct with an instance of such, or a mapping"
)
for name, action in value.items():
setattr(instance, name, action)
Expand Down Expand Up @@ -196,7 +196,7 @@
setHistory=False,
) -> None:
if hasattr(self._config, "_frozen") and self._config._frozen:
msg = "Cannot modify a frozen Config. " f"Attempting to set item {attr} to value {value}"
msg = f"Cannot modify a frozen Config. Attempting to set item {attr} to value {value}"
raise FieldValidationError(self._field, self._config, msg)

# verify that someone has not passed a string with a space or leading
Expand Down Expand Up @@ -315,7 +315,7 @@
label: str = "assigment",
):
if instance._frozen:
msg = "Cannot modify a frozen Config. " f"Attempting to set field to value {value}"
msg = f"Cannot modify a frozen Config. Attempting to set field to value {value}"

Check warning on line 318 in python/lsst/pex/config/configurableActions/_configurableActionStructField.py

View check run for this annotation

Codecov / codecov/patch

python/lsst/pex/config/configurableActions/_configurableActionStructField.py#L318

Added line #L318 was not covered by tests
raise FieldValidationError(self, instance, msg)

if at is None:
Expand Down
2 changes: 1 addition & 1 deletion python/lsst/pex/config/configurableActions/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
"ActionTest1",
"ActionTest2",
"ActionTest3",
"TestConfig",
"TestDivideAction",
"TestSingleColumnAction",
"TestConfig",
)

from lsst.pex.config import Config, Field
Expand Down
Loading
Loading