Skip to content

Commit

Permalink
Pre-commit: Migrate to ruff
Browse files Browse the repository at this point in the history
This replaces the `pylint`, `isort`, `yapf` and `pydocstyle` tools.
  • Loading branch information
sphuber committed Nov 27, 2023
1 parent f3d3278 commit 97867d2
Show file tree
Hide file tree
Showing 16 changed files with 129 additions and 174 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/validate_release_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ def get_version_from_module(content: str) -> str:

try:
return next(
ast.literal_eval(statement.value) for statement in module.body if isinstance(statement, ast.Assign)
for target in statement.targets if isinstance(target, ast.Name) and target.id == '__version__'
ast.literal_eval(statement.value)
for statement in module.body
if isinstance(statement, ast.Assign)
for target in statement.targets
if isinstance(target, ast.Name) and target.id == '__version__'
)
except StopIteration as exception:
raise IOError('Unable to find the `__version__` attribute in the module.') from exception
Expand Down
29 changes: 5 additions & 24 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,12 @@ repos:
hooks:
- id: flynt

- repo: https://github.com/pycqa/isort
rev: '5.12.0'
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.1.6'
hooks:
- id: isort

- repo: https://github.com/pre-commit/mirrors-yapf
rev: 'v0.32.0'
hooks:
- id: yapf
name: yapf
types: [python]
args: ['-i']
additional_dependencies: ['toml']

- repo: https://github.com/PyCQA/pydocstyle
rev: '6.1.1'
hooks:
- id: pydocstyle
additional_dependencies: ['toml']
- id: ruff-format
- id: ruff
args: [--fix, --exit-non-zero-on-fix, --show-fixes]

- repo: local
hooks:
Expand All @@ -47,9 +34,3 @@ repos:
(?x)^(
src/.*py|
)$
- id: pylint
name: pylint
entry: pylint
types: [python]
language: system
60 changes: 23 additions & 37 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ Source = 'https://github.com/microsoft/aiida-pyscf'
pre-commit = [
'mypy==1.3.0',
'pre-commit~=2.17',
'pylint~=2.16.0',
'pylint-aiida~=0.1.1',
]
tests = [
'packaging',
Expand All @@ -75,11 +73,29 @@ exclude = [
line-length = 120
fail-on-change = true

[tool.isort]
force_sort_within_sections = true
include_trailing_comma = true
line_length = 120
multi_line_output = 3
[tool.ruff]
line-length = 120
select = [
'E', # pydocstyle
'W', # pydocstyle
'F', # pyflakes
'I', # isort
'N', # pep8-naming
'D', # pydocstyle
'PLC', # pylint-convention
'PLE', # pylint-error
'PLR', # pylint-refactor
'PLW', # pylint-warning
'RUF', # ruff
]
ignore = [
'D203', # Incompatible with D211 `no-blank-line-before-class`
'D213', # Incompatible with D212 `multi-line-summary-second-line`
'PLR2004', # Magic value used in comparison
]

[tool.ruff.format]
quote-style = 'single'

[tool.mypy]
show_error_codes = true
Expand All @@ -105,37 +121,7 @@ module = [
]
ignore_missing_imports = true

[tool.pydocstyle]
ignore = [
'D104',
'D203',
'D213'
]

[tool.pylint.master]
load-plugins = ['pylint_aiida']

[tool.pylint.format]
max-line-length = 120

[tool.pylint.messages_control]
disable = [
'duplicate-code',
'import-outside-toplevel',
'inconsistent-return-statements',
'too-many-ancestors',
]

[tool.pytest.ini_options]
filterwarnings = [
'ignore:Creating AiiDA configuration folder.*:UserWarning'
]

[tool.yapf]
align_closing_bracket_with_visual_indent = true
based_on_style = 'google'
coalesce_brackets = true
column_limit = 120
dedent_closing_brackets = true
indent_dictionary_value = false
split_arguments_when_comma_terminated = true
12 changes: 6 additions & 6 deletions src/aiida_pyscf/calculations/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
import pathlib
import typing as t

import numpy as np
from aiida.common.datastructures import CalcInfo, CodeInfo
from aiida.common.folders import Folder
from aiida.engine import CalcJob, CalcJobProcessSpec
from aiida.orm import ArrayData, Dict, SinglefileData, StructureData, TrajectoryData
from aiida_shell.data import PickledData
from ase.io.xyz import write_xyz
from jinja2 import Environment, PackageLoader, PrefixLoader
import numpy as np
from plumpy.utils import AttributesFrozendict

__all__ = ('PyscfCalculation',)
Expand Down Expand Up @@ -69,7 +69,7 @@ def define(cls, spec: CalcJobProcessSpec): # type: ignore[override]
'parameters',
valid_type=Dict,
required=False,
help='Various computed properties parsed from the `FILENAME_RESULTS` output file.'
help='Various computed properties parsed from the `FILENAME_RESULTS` output file.',
)
spec.output(
'structure',
Expand Down Expand Up @@ -106,7 +106,7 @@ def define(cls, spec: CalcJobProcessSpec): # type: ignore[override]
'cubegen.mep',
valid_type=SinglefileData,
required=False,
help='The molecular electrostatic potential (MEP) in `.cube` format.'
help='The molecular electrostatic potential (MEP) in `.cube` format.',
)
spec.output(
'hessian',
Expand All @@ -120,16 +120,16 @@ def define(cls, spec: CalcJobProcessSpec): # type: ignore[override]
spec.exit_code(
410,
'ERROR_ELECTRONIC_CONVERGENCE_NOT_REACHED',
message='The electronic minimization cycle did not reach self-consistency.'
message='The electronic minimization cycle did not reach self-consistency.',
)
spec.exit_code(
500,
'ERROR_IONIC_CONVERGENCE_NOT_REACHED',
message='The ionic minimization cycle did not converge for the given thresholds.'
message='The ionic minimization cycle did not converge for the given thresholds.',
)

@classmethod
def validate_parameters(cls, value: Dict | None, _) -> str | None: # pylint: disable=too-many-return-statements,too-many-branches,too-many-locals
def validate_parameters(cls, value: Dict | None, _) -> str | None: # noqa: PLR0911, PLR0912
"""Validate the parameters input."""
if not value:
return None
Expand Down
2 changes: 2 additions & 0 deletions src/aiida_pyscf/parsers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
"""Module for :mod:`aiida_pyscf.parsers`."""
14 changes: 7 additions & 7 deletions src/aiida_pyscf/parsers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import json
import pathlib

import dill
import numpy
from aiida.engine import ExitCode
from aiida.orm import ArrayData, Dict, SinglefileData, TrajectoryData
from aiida.parsers.parser import Parser
from aiida_shell.data import PickledData
from ase.io.extxyz import read_extxyz
import dill
import numpy
from pint import UnitRegistry

from aiida_pyscf.calculations.base import PyscfCalculation
Expand All @@ -27,7 +27,7 @@ def __init__(self, *args, **kwargs):
self.dirpath_temporary: pathlib.Path | None = None
super().__init__(*args, **kwargs)

def parse(self, retrieved_temporary_folder: str | None = None, **kwargs): # pylint: disable=arguments-differ,too-many-locals,too-many-branches,too-many-statements
def parse(self, retrieved_temporary_folder: str | None = None, **kwargs): # noqa: PLR0912, PLR0915
"""Parse the contents of the output files stored in the ``retrieved`` output node.
:returns: An exit code if the job failed.
Expand All @@ -41,7 +41,7 @@ def parse(self, retrieved_temporary_folder: str | None = None, **kwargs): # pyl

try:
with self.retrieved.base.repository.open(PyscfCalculation.FILENAME_STDOUT, 'r') as handle:
stdout = handle.read() # pylint: disable=unused-variable
handle.read()
except FileNotFoundError:
return self.handle_failure('ERROR_OUTPUT_STDOUT_MISSING')

Expand Down Expand Up @@ -133,7 +133,7 @@ def build_output_trajectory(self, filepath_trajectory: pathlib.Path) -> Trajecto

def batch(iterable, batch_size):
"""Split an iterable into a list of elements which size ``batch_size."""
return [iterable[i:i + batch_size] for i in range(0, len(iterable), batch_size)]
return [iterable[i : i + batch_size] for i in range(0, len(iterable), batch_size)]

with filepath_trajectory.open() as handle:
for atoms in read_extxyz(handle, index=slice(None, None)):
Expand All @@ -155,8 +155,8 @@ def batch(iterable, batch_size):
symbols=[site.kind_name for site in self.node.inputs.structure.sites],
positions=numpy.array(positions),
)
energies = (numpy.array(energies) * ureg.hartree).to(ureg.electron_volt).magnitude # type: ignore[attr-defined]
trajectory.set_array('energies', energies)
energies = (numpy.array(energies) * ureg.hartree).to(ureg.electron_volt).magnitude
trajectory.set_array('energies', energies) # type: ignore[arg-type]

return trajectory

Expand Down
2 changes: 2 additions & 0 deletions src/aiida_pyscf/workflows/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
"""Module for :mod:`aiida_pyscf.workflows`."""
10 changes: 5 additions & 5 deletions src/aiida_pyscf/workflows/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def define(cls, spec):
spec.exit_code(
310,
'ERROR_NO_CHECKPOINT_TO_RESTART',
message='The calculation failed and did not retrieve a checkpoint file from which can be restarted.'
message='The calculation failed and did not retrieve a checkpoint file from which can be restarted.',
)

def setup(self):
Expand Down Expand Up @@ -68,7 +68,7 @@ def handle_unrecoverable_failure(self, node):
priority=500,
exit_codes=[
PyscfCalculation.exit_codes.ERROR_IONIC_CONVERGENCE_NOT_REACHED, # type: ignore[union-attr]
]
],
)
def handle_ionic_convergence_not_reached(self, node):
"""Handle ``ERROR_IONIC_CONVERGENCE_NOT_REACHED`` error.
Expand All @@ -95,7 +95,7 @@ def handle_ionic_convergence_not_reached(self, node):
priority=410,
exit_codes=[
PyscfCalculation.exit_codes.ERROR_ELECTRONIC_CONVERGENCE_NOT_REACHED, # type: ignore[union-attr]
]
],
)
def handle_electronic_convergence_not_reached(self, node):
"""Handle ``ERROR_ELECTRONIC_CONVERGENCE_NOT_REACHED`` error.
Expand All @@ -110,7 +110,7 @@ def handle_electronic_convergence_not_reached(self, node):
priority=110,
exit_codes=[
PyscfCalculation.exit_codes.ERROR_SCHEDULER_NODE_FAILURE, # type: ignore[union-attr]
]
],
)
def handle_scheduler_node_failure(self, node):
"""Handle ``ERROR_SCHEDULER_NODE_FAILURE`` error.
Expand All @@ -128,7 +128,7 @@ def handle_scheduler_node_failure(self, node):
priority=100,
exit_codes=[
PyscfCalculation.exit_codes.ERROR_SCHEDULER_OUT_OF_WALLTIME, # type: ignore[union-attr]
]
],
)
def handle_out_of_walltime(self, node):
"""Handle ``ERROR_SCHEDULER_OUT_OF_WALLTIME`` error.
Expand Down
2 changes: 2 additions & 0 deletions tests/calculations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
"""Tests for :mod:`aiida_pyscf.calculations`."""
43 changes: 17 additions & 26 deletions tests/calculations/test_base.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# -*- coding: utf-8 -*-
"""Tests for the :mod:`aiida_pyscf.calculations.base` module."""
# pylint: disable=redefined-outer-name
import io
import textwrap

import pytest
from aiida.manage.tests.pytest_fixtures import recursive_merge
from aiida.orm import Dict, SinglefileData
from jinja2 import BaseLoader, Environment
import pytest

from aiida_pyscf.calculations.base import PyscfCalculation
from jinja2 import BaseLoader, Environment


@pytest.fixture
Expand All @@ -24,13 +22,7 @@ def factory(**kwargs):
'code': aiida_local_code_factory('pyscf.base', 'python'),
'structure': generate_structure(),
'parameters': Dict(parameters),
'metadata': {
'options': {
'resources': {
'num_machines': 1
}
}
},
'metadata': {'options': {'resources': {'num_machines': 1}}},
}
inputs.update(**kwargs)
return inputs
Expand All @@ -43,15 +35,19 @@ def test_default(generate_calc_job, generate_inputs_pyscf, file_regression):
inputs = generate_inputs_pyscf()
tmp_path, calc_info = generate_calc_job(PyscfCalculation, inputs=inputs)

assert sorted(calc_info.retrieve_list) == sorted([
PyscfCalculation.FILENAME_RESULTS,
PyscfCalculation.FILENAME_MODEL,
PyscfCalculation.FILENAME_STDOUT,
])
assert sorted(calc_info.retrieve_list) == sorted(
[
PyscfCalculation.FILENAME_RESULTS,
PyscfCalculation.FILENAME_MODEL,
PyscfCalculation.FILENAME_STDOUT,
]
)

assert sorted(calc_info.retrieve_temporary_list) == sorted([
PyscfCalculation.FILENAME_CHECKPOINT,
])
assert sorted(calc_info.retrieve_temporary_list) == sorted(
[
PyscfCalculation.FILENAME_CHECKPOINT,
]
)

content_input_file = (tmp_path / PyscfCalculation.FILENAME_SCRIPT).read_text()
file_regression.check(content_input_file, encoding='utf-8', extension='.pyr')
Expand All @@ -61,10 +57,7 @@ def test_parameters_structure(generate_calc_job, generate_inputs_pyscf, file_reg
"""Test the ``structure`` key of the ``parameters`` input."""
parameters = {
'structure': {
'basis': {
'O': 'sto-3g',
'H': 'cc-pvdz'
},
'basis': {'O': 'sto-3g', 'H': 'cc-pvdz'},
'cart': True,
'charge': 1,
'spin': 2,
Expand All @@ -83,9 +76,7 @@ def test_parameters_mean_field(generate_calc_job, generate_inputs_pyscf, file_re
'mean_field': {
'diis_start_cycle': 2,
'method': 'RHF',
'grids': {
'level': 3
},
'grids': {'level': 3},
'xc': 'PBE',
},
}
Expand Down
Loading

0 comments on commit 97867d2

Please sign in to comment.