From 05a6b25cfea25ce626e4812a474f288866df6a1b Mon Sep 17 00:00:00 2001 From: Richard Preen Date: Fri, 7 Jun 2024 21:59:39 +0100 Subject: [PATCH] add basic ruff linting/formatting --- .pre-commit-config.yaml | 32 ++++----------- aisdc/attacks/attack_report_formatter.py | 4 +- aisdc/attacks/likelihood_attack.py | 12 +++--- aisdc/attacks/report.py | 8 +--- .../classifiers/new_model_template.py | 6 +-- .../classifiers/safedecisiontreeclassifier.py | 4 +- aisdc/safemodel/classifiers/safekeras.py | 14 +++---- aisdc/safemodel/classifiers/safetf.py | 6 +-- pyproject.toml | 41 +++++++++++++++++++ tests/attacks/test_lira_attack.py | 6 +-- tests/safemodel/test_safemodel.py | 4 +- tests/safemodel/test_safetf.py | 2 +- 12 files changed, 74 insertions(+), 65 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 327f447e..a3c05604 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,35 +31,17 @@ repos: .*\.ipynb )$ - # Autoremoves unused imports - - repo: https://github.com/hadialqattan/pycln - rev: "v2.4.0" + # Ruff, the Python auto-correcting linter/formatter written in Rust + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.8 hooks: - - id: pycln - stages: [manual] - - # Sort includes - - repo: https://github.com/asottile/pyupgrade - rev: v3.15.2 - hooks: - - id: pyupgrade - - # Upgrade old Python syntax - - repo: https://github.com/PyCQA/isort - rev: 5.13.2 - hooks: - - id: isort - args: ["--profile", "black"] - - # Black format Python and notebooks - - repo: https://github.com/psf/black - rev: 24.4.2 - hooks: - - id: black-jupyter + - id: ruff + args: ["--fix", "--show-fixes"] + - id: ruff-format # Format docstrings - repo: https://github.com/DanielNoord/pydocstringformatter - rev: "v0.7.3" + rev: v0.7.3 hooks: - id: pydocstringformatter args: ["--style=numpydoc"] diff --git a/aisdc/attacks/attack_report_formatter.py b/aisdc/attacks/attack_report_formatter.py index 2a44d688..b694d01d 100644 --- a/aisdc/attacks/attack_report_formatter.py +++ b/aisdc/attacks/attack_report_formatter.py @@ -117,9 +117,7 @@ def __str__(self): raise NotImplementedError() -class FinalRecommendationModule( - AnalysisModule -): # pylint: disable=too-many-instance-attributes +class FinalRecommendationModule(AnalysisModule): # pylint: disable=too-many-instance-attributes """Module that generates the first layer of a recommendation report.""" def __init__(self, report: dict): diff --git a/aisdc/attacks/likelihood_attack.py b/aisdc/attacks/likelihood_attack.py index 29af0853..4c82e3ff 100644 --- a/aisdc/attacks/likelihood_attack.py +++ b/aisdc/attacks/likelihood_attack.py @@ -446,9 +446,9 @@ def _construct_metadata(self) -> None: if auc_p <= self.p_thresh else f"Not significant at p={self.p_thresh}" ) - self.metadata["global_metrics"][ - "null_auc_3sd_range" - ] = f"{0.5 - 3 * auc_std} -> {0.5 + 3 * auc_std}" + self.metadata["global_metrics"]["null_auc_3sd_range"] = ( + f"{0.5 - 3 * auc_std} -> {0.5 + 3 * auc_std}" + ) self.metadata["attack"] = str(self) @@ -498,9 +498,9 @@ def _get_attack_metrics_instances(self) -> dict: attack_metrics_instances = {} for rep, _ in enumerate(self.attack_metrics): - self.attack_metrics[rep][ - "n_shadow_models_trained" - ] = self.attack_failfast_shadow_models_trained + self.attack_metrics[rep]["n_shadow_models_trained"] = ( + self.attack_failfast_shadow_models_trained + ) attack_metrics_instances["instance_" + str(rep)] = self.attack_metrics[rep] attack_metrics_experiment["attack_instance_logger"] = attack_metrics_instances diff --git a/aisdc/attacks/report.py b/aisdc/attacks/report.py index fd55157c..178e3a73 100644 --- a/aisdc/attacks/report.py +++ b/aisdc/attacks/report.py @@ -111,18 +111,14 @@ def title(pdf, text, border=BORDER, font_size=24, font_style="B"): pdf.ln(h=5) -def subtitle( - pdf, text, indent=10, border=BORDER, font_size=12, font_style="B" -): # pylint: disable = too-many-arguments +def subtitle(pdf, text, indent=10, border=BORDER, font_size=12, font_style="B"): # pylint: disable = too-many-arguments """Write a subtitle block.""" pdf.cell(indent, border=border) pdf.set_font("arial", font_style, font_size) pdf.cell(75, 10, text, border, 1) -def line( - pdf, text, indent=0, border=BORDER, font_size=11, font_style="", font="arial" -): # pylint: disable = too-many-arguments +def line(pdf, text, indent=0, border=BORDER, font_size=11, font_style="", font="arial"): # pylint: disable = too-many-arguments """Write a standard block.""" if indent > 0: pdf.cell(indent, border=border) diff --git a/aisdc/safemodel/classifiers/new_model_template.py b/aisdc/safemodel/classifiers/new_model_template.py index 258a00fe..4f97dce4 100644 --- a/aisdc/safemodel/classifiers/new_model_template.py +++ b/aisdc/safemodel/classifiers/new_model_template.py @@ -1,7 +1,7 @@ """This is a template for implementing supplementary models - Obviously we have invented an sklearn ensemble called ModelToMakeSafer - Replace this with details of the model you wish to create a wrapper for - and then remove the comment which disables the pylint warning. +Obviously we have invented an sklearn ensemble called ModelToMakeSafer +Replace this with details of the model you wish to create a wrapper for +and then remove the comment which disables the pylint warning. """ # pylint: disable=duplicate-code diff --git a/aisdc/safemodel/classifiers/safedecisiontreeclassifier.py b/aisdc/safemodel/classifiers/safedecisiontreeclassifier.py index 868013d6..5095b2f9 100644 --- a/aisdc/safemodel/classifiers/safedecisiontreeclassifier.py +++ b/aisdc/safemodel/classifiers/safedecisiontreeclassifier.py @@ -127,9 +127,7 @@ def get_tree_k_anonymity(thetree: DecisionTreeClassifier, X: Any) -> int: return k_anonymity -class SafeDecisionTreeClassifier( - SafeModel, DecisionTreeClassifier -): # pylint: disable=too-many-ancestors +class SafeDecisionTreeClassifier(SafeModel, DecisionTreeClassifier): # pylint: disable=too-many-ancestors """Privacy protected Decision Tree classifier.""" def __init__(self, **kwargs: Any) -> None: diff --git a/aisdc/safemodel/classifiers/safekeras.py b/aisdc/safemodel/classifiers/safekeras.py index df45f517..7c7cdebc 100644 --- a/aisdc/safemodel/classifiers/safekeras.py +++ b/aisdc/safemodel/classifiers/safekeras.py @@ -1,11 +1,10 @@ """Safekeras.py: - Jim Smith, Andrew McCarty and Richard Preen - UWE 2022. +Jim Smith, Andrew McCarty and Richard Preen +UWE 2022. """ # general imports - import os import warnings @@ -219,10 +218,7 @@ def load_safe_keras_model(name: str = "undefined") -> Tuple[bool, Any]: class SafeKerasModel(KerasModel, SafeModel): - """Privacy Protected Wrapper around tf.keras.Model class from tensorflow 2.8 - disabling pylont warnings about number of instance attributes - as this is necessarily complex. - """ + """Privacy Protected Wrapper around tf.keras.Model class from tensorflow 2.8.""" # pylint: disable=too-many-instance-attributes def __init__(self, *args: Any, **kwargs: Any) -> None: @@ -236,6 +232,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: ##inputs = kwargs.get("inputs","notFound") ##if inputs=="notFound": ## inputs = args[0] if len(args) == 3 else None + inputs = None if "inputs" in kwargs.keys(): # pylint: disable=consider-iterating-dictionary inputs = the_kwargs["inputs"] elif len(args) == 3: # defaults is for Model(input,outputs,names) @@ -252,7 +249,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # call the keras super class first as this comes first in chain super().__init__( # pylint: disable=unexpected-keyword-arg - inputs=inputs, outputs=outputs # pylint: disable=used-before-assignment + inputs=inputs, + outputs=outputs, # pylint: disable=used-before-assignment ) # set values where the user has supplied them diff --git a/aisdc/safemodel/classifiers/safetf.py b/aisdc/safemodel/classifiers/safetf.py index 5ee5066c..3b685e51 100644 --- a/aisdc/safemodel/classifiers/safetf.py +++ b/aisdc/safemodel/classifiers/safetf.py @@ -1,6 +1,6 @@ """Work in progress to allow use of the DPModel classes - Jim smith 2022 - When ready, linting of the imports will be enabled. +Jim smith 2022 +When ready, linting of the imports will be enabled. """ # pylint: disable=unused-import @@ -28,7 +28,7 @@ def __init__( noise_multiplier: float, use_xla: bool, *args: any, - **kwargs: any + **kwargs: any, ) -> None: """Creates model and applies constraints to parameters.""" # safemodel.__init__(self) diff --git a/pyproject.toml b/pyproject.toml index 291b1373..333886ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,3 +30,44 @@ min-public-methods = 2 # Minimum number of public methods for a class (see R090 [tool.pylint.format] max-line-length = 100 # Maximum number of characters on a single line. max-module-lines = 1000 # Maximum number of lines in a module. + +[tool.ruff] +indent-width = 4 +line-length = 88 +target-version = "py39" + +lint.select = [ +# "ANN", # flake8-annotations +# "ARG", # flake8-unused-arguments +# "B", # flake8-bugbear +# "C4", # flake8-comprehensions +# "C90", # mccabe +# "D", # pydocstyle +# "DTZ", # flake8-datetimez +# "E", # pycodestyle +# "EM", # flake8-errmsg +# "ERA", # eradicate +# "F", # Pyflakes +# "I", # isort +# "ICN", # flake8-import-conventions +# "N", # pep8-naming +# "PD", # pandas-vet +# "PGH", # pygrep-hooks +# "PIE", # flake8-pie +# "PL", # Pylint +# "PLC", # Pylint +# "PLE", # Pylint +# "PLR", # Pylint +# "PLW", # Pylint +# "PT", # flake8-pytest-style +# "Q", # flake8-quotes +# "RET", # flake8-return +# "RUF100", # Ruff-specific +# "S", # flake8-bandit +# "SIM", # flake8-simplify +# "T20", # flake8-print +# "TID", # flake8-tidy-imports +# "UP", # pyupgrade +# "W", # pycodestyle +# "YTT", # flake8-2020 +] diff --git a/tests/attacks/test_lira_attack.py b/tests/attacks/test_lira_attack.py index 642ee95c..5c7b23cf 100644 --- a/tests/attacks/test_lira_attack.py +++ b/tests/attacks/test_lira_attack.py @@ -138,10 +138,8 @@ def test_check_and_update_dataset(self): ) unique_classes_pre = set(local_test_y) n_test_examples_pre = len(local_test_y) - local_target = ( - attack_obj._check_and_update_dataset( # pylint:disable=protected-access - local_target - ) + local_target = attack_obj._check_and_update_dataset( # pylint:disable=protected-access + local_target ) unique_classes_post = set(local_target.y_test) diff --git a/tests/safemodel/test_safemodel.py b/tests/safemodel/test_safemodel.py index e2761c8e..4514267e 100644 --- a/tests/safemodel/test_safemodel.py +++ b/tests/safemodel/test_safemodel.py @@ -52,9 +52,7 @@ def get_data(): return x, y -class SafeDummyClassifier( - SafeModel, DummyClassifier -): # pylint:disable=too-many-instance-attributes +class SafeDummyClassifier(SafeModel, DummyClassifier): # pylint:disable=too-many-instance-attributes """Privacy protected dummy classifier.""" def __init__(self, **kwargs) -> None: diff --git a/tests/safemodel/test_safetf.py b/tests/safemodel/test_safetf.py index a1d851a9..0f0dd86a 100644 --- a/tests/safemodel/test_safetf.py +++ b/tests/safemodel/test_safetf.py @@ -1,5 +1,5 @@ """Jim Smith 2022 - Not currently implemented. +Not currently implemented. """ from __future__ import annotations