[Python] Add ruff as Python linter (#32384)
* Add ruff as Python linter
* Add ruff to linter workflow
* Remove flake8
* Set default line-length and explicitly select rules
* Address REPL Test issue
* Explicitly set line lenght for autopep8
* Fix restyled config
diff --git a/.flake8 b/.flake8
deleted file mode 100644
index 65b1c2a..0000000
--- a/.flake8
+++ /dev/null
@@ -1,6 +0,0 @@
-[flake8]
-max-line-length = 132
-exclude = third_party
- .*
- out/*
- ./examples/common/QRCode/*
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 70edd53..8e67de5 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -29,7 +29,7 @@
if: github.actor != 'restyled-io[bot]'
container:
- image: ghcr.io/project-chip/chip-build:35
+ image: ghcr.io/project-chip/chip-build:39
steps:
- name: Checkout
@@ -267,12 +267,11 @@
run: |
git grep -I -n 'emberAfWriteAttribute' -- './*' ':(exclude).github/workflows/lint.yml' ':(exclude)src/app/util/af.h' ':(exclude)zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp' ':(exclude)src/app/zap-templates/templates/app/attributes/Accessors-src.zapt' ':(exclude)src/app/util/attribute-table.cpp' ':(exclude)examples/common/pigweed/rpc_services/Attributes.h' ':(exclude)src/app/util/attribute-table.h' ':(exclude)src/app/util/ember-compatibility-functions.cpp' && exit 1 || exit 0
- # Run python Linter (flake8) and verify python files
- # ignore some style errors, restyler should do that
- - name: Check for errors using flake8 Python linter
+ # Run ruff python linter
+ - name: Check for errors using ruff Python linter
if: always()
run: |
- flake8 --extend-ignore=E501,W391
+ ruff check
# git grep exits with 0 if it finds a match, but we want
# to fail (exit nonzero) on match. And we want to exclude this file,
diff --git a/.restyled.yaml b/.restyled.yaml
index 56ed306..9acbe8e 100644
--- a/.restyled.yaml
+++ b/.restyled.yaml
@@ -230,6 +230,8 @@
command:
- autopep8
- "--in-place"
+ - "--max-line-length"
+ - "132"
arguments: []
include:
- "**/*.py"
diff --git a/integrations/docker/images/base/chip-build/Dockerfile b/integrations/docker/images/base/chip-build/Dockerfile
index 39aada6..a2f83fc 100644
--- a/integrations/docker/images/base/chip-build/Dockerfile
+++ b/integrations/docker/images/base/chip-build/Dockerfile
@@ -144,7 +144,6 @@
click \
coloredlogs \
cxxfilt \
- flake8 \
future \
ghapi \
mobly \
diff --git a/ruff.toml b/ruff.toml
new file mode 100644
index 0000000..fec7608
--- /dev/null
+++ b/ruff.toml
@@ -0,0 +1,19 @@
+exclude = [
+ ".environment",
+ ".git",
+ ".github",
+ ".*",
+ "build",
+ "out",
+ "third_party",
+ "examples/common/QRCode/",
+]
+target-version = "py37"
+
+line-length = 132
+
+[lint]
+select = ["E4", "E7", "E9", "F"]
+ignore = [
+ "E721" # We use is for good reasons
+]
diff --git a/scripts/py_matter_idl/matter_idl/generators/java/__init__.py b/scripts/py_matter_idl/matter_idl/generators/java/__init__.py
index da7eef2..96fa37c 100644
--- a/scripts/py_matter_idl/matter_idl/generators/java/__init__.py
+++ b/scripts/py_matter_idl/matter_idl/generators/java/__init__.py
@@ -114,7 +114,6 @@
'event_no': 'chip::EventNumber',
'fabric_id': 'chip::FabricId',
'fabric_idx': 'chip::FabricIndex',
- 'fabric_idx': 'chip::FabricIndex',
'field_id': 'chip::FieldId',
'group_id': 'chip::GroupId',
'node_id': 'chip::NodeId',
diff --git a/scripts/py_matter_idl/matter_idl/generators/kotlin/__init__.py b/scripts/py_matter_idl/matter_idl/generators/kotlin/__init__.py
index b069319..17e5136 100644
--- a/scripts/py_matter_idl/matter_idl/generators/kotlin/__init__.py
+++ b/scripts/py_matter_idl/matter_idl/generators/kotlin/__init__.py
@@ -114,7 +114,6 @@
'event_no': 'chip::EventNumber',
'fabric_id': 'chip::FabricId',
'fabric_idx': 'chip::FabricIndex',
- 'fabric_idx': 'chip::FabricIndex',
'field_id': 'chip::FieldId',
'group_id': 'chip::GroupId',
'node_id': 'chip::NodeId',
diff --git a/scripts/py_matter_yamltests/matter_yamltests/parser.py b/scripts/py_matter_yamltests/matter_yamltests/parser.py
index cb0a89c..9612d57 100644
--- a/scripts/py_matter_yamltests/matter_yamltests/parser.py
+++ b/scripts/py_matter_yamltests/matter_yamltests/parser.py
@@ -1086,7 +1086,7 @@
break
received_value = received_response.get('value')
- if not self.is_attribute and not self.is_event and not (self.command in ANY_COMMANDS_LIST):
+ if not self.is_attribute and not self.is_event and self.command not in ANY_COMMANDS_LIST:
expected_name = value.get('name')
if expected_name not in received_value:
result.error(check_type, error_name_does_not_exist.format(
@@ -1173,7 +1173,7 @@
continue
received_value = received_response.get(default_target)
- if not self.is_attribute and not self.is_event and not (self.command in ANY_COMMANDS_LIST):
+ if not self.is_attribute and not self.is_event and self.command not in ANY_COMMANDS_LIST:
expected_name = value.get('name')
if received_value is None or expected_name not in received_value:
result.error(check_type, error_name_does_not_exist.format(
diff --git a/scripts/tests/yaml/extensions/wildcard_response_extractor_cluster.py b/scripts/tests/yaml/extensions/wildcard_response_extractor_cluster.py
index a0e34cc..2f60a52 100644
--- a/scripts/tests/yaml/extensions/wildcard_response_extractor_cluster.py
+++ b/scripts/tests/yaml/extensions/wildcard_response_extractor_cluster.py
@@ -113,7 +113,7 @@
if arguments is None:
return None
- if not type(arguments) is list:
+ if type(arguments) is not list:
return None
for argument in arguments:
diff --git a/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py b/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py
index 7cddb76..7244840 100644
--- a/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py
+++ b/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py
@@ -246,7 +246,7 @@
"Cannot find paths to DAC or PAI certificates .der files. To generate a new ones please provide a path to chip-cert executable (--chip_cert_path) and add --gen_certs argument"
assert self._args.output.endswith(".json"), \
"Output path doesn't contain .json file path. ({})".format(self._args.output)
- assert not (self._args.passcode in INVALID_PASSCODES), \
+ assert self._args.passcode not in INVALID_PASSCODES, \
"Provided invalid passcode!"
def generate_json(self):
diff --git a/scripts/tools/silabs/FactoryDataProvider.py b/scripts/tools/silabs/FactoryDataProvider.py
index 8cb4895..3ff8ece 100644
--- a/scripts/tools/silabs/FactoryDataProvider.py
+++ b/scripts/tools/silabs/FactoryDataProvider.py
@@ -140,7 +140,7 @@
assert (bool(arguments.gen_spake2p_path) != bool(arguments.spake2_verifier)
), "Provide either the spake2_verifier string or the path to the spake2 generator"
- assert not (arguments.passcode in INVALID_PASSCODES), "The provided passcode is invalid"
+ assert arguments.passcode not in INVALID_PASSCODES, "The provided passcode is invalid"
self._args = arguments
diff --git a/src/python_testing/TestSpecParsingSupport.py b/src/python_testing/TestSpecParsingSupport.py
index 2ff80e5..2fdfcdc 100644
--- a/src/python_testing/TestSpecParsingSupport.py
+++ b/src/python_testing/TestSpecParsingSupport.py
@@ -262,7 +262,7 @@
0, "Unexpected number of unknown commands in base")
asserts.assert_equal(len(clusters[0xFFFF].unknown_commands), 2, "Unexpected number of unknown commands in derived cluster")
- combine_derived_clusters_with_base(clusters, pure_base_clusters, ids_by_name)
+ combine_derived_clusters_with_base(clusters, pure_base_clusters, ids_by_name, problems)
# Ensure the base-only attribute (1) was added to the derived cluster
asserts.assert_equal(set(clusters[0xFFFF].attributes.keys()), set(
[0, 1, 2, 3] + expected_global_attrs), "Unexpected attribute list")
diff --git a/src/python_testing/spec_parsing_support.py b/src/python_testing/spec_parsing_support.py
index 6a9d1f8..ac34463 100644
--- a/src/python_testing/spec_parsing_support.py
+++ b/src/python_testing/spec_parsing_support.py
@@ -487,7 +487,7 @@
clusters[action_id].accepted_commands[c].conformance = optional()
remove_problem(CommandPathLocation(endpoint_id=0, cluster_id=action_id, command_id=c))
- combine_derived_clusters_with_base(clusters, pure_base_clusters, ids_by_name)
+ combine_derived_clusters_with_base(clusters, pure_base_clusters, ids_by_name, problems)
for alias_base_name, aliased_clusters in CLUSTER_ALIASES.items():
for id, (alias_name, pics) in aliased_clusters.items():
@@ -547,10 +547,10 @@
return clusters, problems
-def combine_derived_clusters_with_base(xml_clusters: dict[int, XmlCluster], pure_base_clusters: dict[str, XmlCluster], ids_by_name: dict[str, int]) -> None:
+def combine_derived_clusters_with_base(xml_clusters: dict[int, XmlCluster], pure_base_clusters: dict[str, XmlCluster], ids_by_name: dict[str, int], problems: list[ProblemNotice]) -> None:
''' Overrides base elements with the derived cluster values for derived clusters. '''
- def combine_attributes(base: dict[uint, XmlAttribute], derived: dict[uint, XmlAttribute], cluster_id: uint) -> dict[uint, XmlAttribute]:
+ def combine_attributes(base: dict[uint, XmlAttribute], derived: dict[uint, XmlAttribute], cluster_id: uint, problems: list[ProblemNotice]) -> dict[uint, XmlAttribute]:
ret = deepcopy(base)
extras = {k: v for k, v in derived.items() if k not in base.keys()}
overrides = {k: v for k, v in derived.items() if k in base.keys()}
@@ -590,7 +590,7 @@
command_map.update(c.command_map)
features = deepcopy(base.features)
features.update(c.features)
- attributes = combine_attributes(base.attributes, c.attributes, id)
+ attributes = combine_attributes(base.attributes, c.attributes, id, problems)
accepted_commands = deepcopy(base.accepted_commands)
accepted_commands.update(c.accepted_commands)
generated_commands = deepcopy(base.generated_commands)
diff --git a/src/test_driver/linux-cirque/helper/CHIPTestBase.py b/src/test_driver/linux-cirque/helper/CHIPTestBase.py
index 036ba25..7fd0c81 100644
--- a/src/test_driver/linux-cirque/helper/CHIPTestBase.py
+++ b/src/test_driver/linux-cirque/helper/CHIPTestBase.py
@@ -299,13 +299,13 @@
assert(Not)Equal
python unittest style functions that raise exceptions when condition not met
'''
- if not (exp is True):
+ if exp is not True:
if note:
self.logger.error(note)
raise AssertionError
def assertFalse(self, exp, note=None):
- if not (exp is False):
+ if exp is not False:
if note:
self.logger.error(note)
raise AssertionError