Skip to content

Comments

Update pyproject-toml to support PEP 639#13902

Merged
MichaReiser merged 1 commit intoruff-0.8from
konsti/pep639
Nov 18, 2024
Merged

Update pyproject-toml to support PEP 639#13902
MichaReiser merged 1 commit intoruff-0.8from
konsti/pep639

Conversation

@konstin
Copy link
Member

@konstin konstin commented Oct 24, 2024

PEP 639 is provisionally accepted, we were previously shipping definitions from an earlier draft.

We don't validate all that's in the PEP (license vs. license-files compatibility, SPDX expressions), only the overall structure of pyproject.toml.

Updates pep440_rs in the process.

Fixes #13869

@konstin konstin requested a review from MichaReiser October 24, 2024 09:26
@@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/ruff/mod.rs
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now became a valid example

---
source: crates/ruff_linter/src/rules/ruff/mod.rs
---
pyproject.toml:10:16: RUF200 Failed to parse pyproject.toml: Expected package name starting with an alphanumeric character, found '.'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, we only emit a single error when various things are broken

source: crates/ruff_linter/src/rules/ruff/mod.rs
---
pyproject.toml:6:84: RUF200 Failed to parse pyproject.toml: invalid type: integer `1`, expected a string
pyproject.toml:5:11: RUF200 Failed to parse pyproject.toml: a table with 'name' and/or 'email' keys
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message isn't ideal but the span should sufficiently prompt users to fix their authors table

@konstin konstin added the rule Implementing or modifying a lint rule label Oct 24, 2024
@codspeed-hq
Copy link

codspeed-hq bot commented Oct 24, 2024

CodSpeed Performance Report

Merging #13902 will improve performances by 4.48%

Comparing konsti/pep639 (7def8f1) with ruff-0.8 (ad14692)

Summary

⚡ 1 improvements
✅ 31 untouched benchmarks

Benchmarks breakdown

Benchmark ruff-0.8 konsti/pep639 Change
red_knot_check_file[incremental] 4.2 ms 4 ms +4.48%

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. This looks good. Unfortunately, we need to find a solution for wasm :(

@github-actions
Copy link
Contributor

github-actions bot commented Oct 24, 2024

ruff-ecosystem results

Linter (stable)

ℹ️ ecosystem check detected linter changes. (+218 -0 violations, +0 -0 fixes in 2 projects; 1 project error; 51 projects unchanged)

apache/airflow (+2 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --no-preview --select ALL

+ clients/python/pyproject.toml:27:1: RUF200 Failed to parse pyproject.toml: invalid type: map, expected a sequence
+ pyproject.toml:58:1: RUF200 Failed to parse pyproject.toml: invalid type: map, expected a sequence

lnbits/lnbits (+216 -0 violations, +0 -0 fixes)

+ lnbits/app.py:257:6: UP006 Use `list` instead of `List` for type annotation
+ lnbits/app.py:9:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/commands.py:235:23: UP006 Use `list` instead of `List` for type annotation
+ lnbits/commands.py:465:6: UP006 Use `tuple` instead of `Tuple` for type annotation
+ lnbits/commands.py:494:6: UP006 Use `tuple` instead of `Tuple` for type annotation
+ lnbits/commands.py:6:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/commands.py:6:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead
+ lnbits/core/crud.py:1018:6: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:1235:43: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:1285:6: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:433:6: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:460:6: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:485:6: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:4:1: UP035 `typing.Dict` is deprecated, use `dict` instead
+ lnbits/core/crud.py:4:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/core/crud.py:654:75: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:772:13: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:773:13: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:893:21: UP006 Use `dict` instead of `Dict` for type annotation
+ lnbits/core/crud.py:953:17: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:954:20: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/services.py:121:21: UP006 Use `dict` instead of `Dict` for type annotation
+ lnbits/core/services.py:125:6: UP006 Use `tuple` instead of `Tuple` for type annotation
+ lnbits/core/services.py:192:21: UP006 Use `dict` instead of `Dict` for type annotation
+ lnbits/core/services.py:234:29: UP006 Use `dict` instead of `Dict` for type annotation
+ lnbits/core/services.py:517:21: UP006 Use `dict` instead of `Dict` for type annotation
+ lnbits/core/services.py:78:21: UP006 Use `dict` instead of `Dict` for type annotation
+ lnbits/core/services.py:7:1: UP035 `typing.Dict` is deprecated, use `dict` instead
+ lnbits/core/services.py:7:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/core/services.py:7:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead
+ lnbits/core/services.py:80:26: UP006 Use `dict` instead of `Dict` for type annotation
+ lnbits/core/services.py:80:6: UP006 Use `tuple` instead of `Tuple` for type annotation
+ lnbits/core/services.py:856:34: UP006 Use `list` instead of `List` for type annotation
... 121 additional changes omitted for rule UP006
+ lnbits/core/tasks.py:2:1: UP035 `typing.Dict` is deprecated, use `dict` instead
+ lnbits/core/views/api.py:5:1: UP035 `typing.Dict` is deprecated, use `dict` instead
+ lnbits/core/views/api.py:5:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/core/views/extension_api.py:3:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/core/views/generic.py:3:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/core/views/node_api.py:2:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/core/views/payment_api.py:6:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/core/views/user_api.py:2:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/decorators.py:2:1: UP035 `typing.Type` is deprecated, use `type` instead
+ lnbits/extension_manager.py:9:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/extension_manager.py:9:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead
+ lnbits/helpers.py:5:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/helpers.py:5:1: UP035 `typing.Type` is deprecated, use `type` instead
+ lnbits/middleware.py:2:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/middleware.py:2:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead
+ lnbits/tasks.py:7:1: UP035 [*] Import from `collections.abc` instead: `Coroutine`
... 167 additional changes omitted for project

pypa/setuptools (error)

ruff failed
  Cause: Failed to parse /home/runner/work/ruff/ruff/checkouts/pypa:setuptools/ruff.toml
  Cause: TOML parse error at line 8, column 1
  |
8 | [lint]
  | ^^^^^^
Unknown rule selector: `UP027`

Changes by rule (3 rules affected)

code total + violation - violation + fix - fix
UP006 145 145 0 0 0
UP035 71 71 0 0 0
RUF200 2 2 0 0 0

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+8559 -8359 violations, +0 -66 fixes in 10 projects; 1 project error; 43 projects unchanged)

apache/airflow (+6178 -6179 violations, +0 -58 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

- airflow/api/__init__.py:32:5: DOC201 `return` is not documented in docstring
- airflow/api/__init__.py:32:5: DOC501 Raised exception `AirflowException` missing from docstring
+ airflow/api/__init__.py:43:15: DOC501 Raised exception `AirflowException` missing from docstring
+ airflow/api/__init__.py:44:5: DOC201 `return` is not documented in docstring
- airflow/api/auth/backend/deny_all.py:38:5: DOC201 `return` is not documented in docstring
+ airflow/api/auth/backend/deny_all.py:44:5: DOC201 `return` is not documented in docstring
- airflow/api/client/__init__.py:27:5: DOC201 `return` is not documented in docstring
+ airflow/api/client/__init__.py:38:5: DOC201 `return` is not documented in docstring
... 9019 additional changes omitted for rule DOC201
- airflow/api/common/delete_dag.py:43:5: DOC501 Raised exception `AirflowException` missing from docstring
- airflow/api/common/delete_dag.py:43:5: DOC501 Raised exception `DagNotFound` missing from docstring
+ airflow/api/common/delete_dag.py:61:15: DOC501 Raised exception `AirflowException` missing from docstring
+ airflow/api/common/delete_dag.py:64:15: DOC501 Raised exception `DagNotFound` missing from docstring
... 2949 additional changes omitted for rule DOC501
- airflow/api/common/mark_tasks.py:186:5: DOC402 `yield` is not documented in docstring
+ airflow/api/common/mark_tasks.py:190:13: DOC402 `yield` is not documented in docstring
- airflow/api_fastapi/common/db/common.py:33:5: DOC402 `yield` is not documented in docstring
+ airflow/api_fastapi/common/db/common.py:47:9: DOC402 `yield` is not documented in docstring
+ airflow/assets/__init__.py:128:8: PLR1714 Consider merging multiple comparisons: `value in ("self", "context")`. Use a `set` if the elements are hashable.
- airflow/assets/__init__.py:128:8: PLR1714 Consider merging multiple comparisons: `value in {"self", "context"}`.
- airflow/assets/__init__.py:238:9: DOC402 `yield` is not documented in docstring
+ airflow/assets/__init__.py:243:9: DOC402 `yield` is not documented in docstring
... 329 additional changes omitted for rule DOC402
+ airflow/decorators/__init__.pyi:117:25: PYI041 Use `float` instead of `int | float`
- airflow/decorators/__init__.pyi:117:25: PYI041 [*] Use `float` instead of `int | float`
+ airflow/decorators/__init__.pyi:256:25: PYI041 Use `float` instead of `int | float`
- airflow/decorators/__init__.pyi:256:25: PYI041 [*] Use `float` instead of `int | float`
+ airflow/jobs/job.py:308:39: PYI041 Use `float` instead of `int | float`
- airflow/jobs/job.py:308:39: PYI041 [*] Use `float` instead of `int | float`
... 53 additional changes omitted for rule PYI041
- airflow/models/dag.py:1038:36: PYI061 `Literal[None, ...]` can be replaced with `Literal[...] | None`
- airflow/models/dagrun.py:1317:23: RUF038 `Literal[True, False]` can be replaced with `bool`
- airflow/models/dagrun.py:1439:23: RUF038 `Literal[True, False]` can be replaced with `bool`
+ airflow/www/decorators.py:55:27: PLR1714 Consider merging multiple comparisons: `k in ("val", "value")`. Use a `set` if the elements are hashable.
- airflow/www/decorators.py:55:27: PLR1714 Consider merging multiple comparisons: `k in {"val", "value"}`.
+ airflow/www/views.py:4340:21: PLR1714 Consider merging multiple comparisons: `parsed_url.scheme in ("http", "https")`. Use a `set` if the elements are hashable.
- airflow/www/views.py:4340:21: PLR1714 Consider merging multiple comparisons: `parsed_url.scheme in {"http", "https"}`.
... 35 additional changes omitted for rule PLR1714
+ clients/python/pyproject.toml:27:1: RUF200 Failed to parse pyproject.toml: invalid type: map, expected a sequence
+ pyproject.toml:58:1: RUF200 Failed to parse pyproject.toml: invalid type: map, expected a sequence
... 12380 additional changes omitted for project

apache/superset (+1170 -1172 violations, +0 -8 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ RELEASING/changelog.py:104:9: DOC201 `return` is not documented in docstring
- RELEASING/changelog.py:107:9: DOC201 `return` is not documented in docstring
+ RELEASING/changelog.py:113:13: DOC201 `return` is not documented in docstring
- RELEASING/changelog.py:52:9: DOC201 `return` is not documented in docstring
+ RELEASING/changelog.py:54:13: DOC201 `return` is not documented in docstring
- RELEASING/changelog.py:87:9: DOC201 `return` is not documented in docstring
... 1824 additional changes omitted for rule DOC201
- scripts/benchmark_migration.py:43:5: DOC501 Raised exception `Exception` missing from docstring
+ scripts/benchmark_migration.py:51:11: DOC501 Raised exception `Exception` missing from docstring
- scripts/cancel_github_workflows.py:162:5: DOC501 Raised exception `ClickException` missing from docstring
+ scripts/cancel_github_workflows.py:164:15: DOC501 Raised exception `ClickException` missing from docstring
... 2340 additional changes omitted for project

aws/aws-sam-cli (+1 -1 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ tests/integration/publish/publish_app_integ_base.py:60:16: PLR1714 Consider merging multiple comparisons: `f.suffix in (".yaml", ".json")`. Use a `set` if the elements are hashable.
- tests/integration/publish/publish_app_integ_base.py:60:16: PLR1714 Consider merging multiple comparisons: `f.suffix in {".yaml", ".json"}`.

bokeh/bokeh (+407 -406 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ examples/advanced/extensions/parallel_plot/parallel_plot.py:107:5: DOC201 `return` is not documented in docstring
- examples/advanced/extensions/parallel_plot/parallel_plot.py:15:5: DOC201 `return` is not documented in docstring
- examples/basic/data/server_sent_events_source.py:53:9: DOC402 `yield` is not documented in docstring
+ examples/basic/data/server_sent_events_source.py:60:13: DOC402 `yield` is not documented in docstring
- examples/interaction/js_callbacks/js_on_event.py:16:5: DOC201 `return` is not documented in docstring
+ examples/interaction/js_callbacks/js_on_event.py:21:5: DOC201 `return` is not documented in docstring
+ examples/models/daylight.py:83:12: DTZ901 Use of `datetime.datetime.min` without timezone information
- examples/models/gauges.py:33:5: DOC201 `return` is not documented in docstring
+ examples/models/gauges.py:34:5: DOC201 `return` is not documented in docstring
... 395 additional changes omitted for rule DOC201
- src/bokeh/__init__.py:63:5: DOC202 Docstring should not have a returns section because the function doesn't return anything
... 803 additional changes omitted for project

latchbio/latch (+2 -3 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

- src/latch/types/metadata.py:500:45: PYI061 `Literal[None, ...]` can be replaced with `Literal[...] | None`
+ src/latch_cli/services/stop_pod.py:22:8: PLR1714 Consider merging multiple comparisons: `res.status_code in (403, 404)`. Use a `set` if the elements are hashable.
- src/latch_cli/services/stop_pod.py:22:8: PLR1714 Consider merging multiple comparisons: `res.status_code in {403, 404}`.
+ src/latch_cli/snakemake/single_task_snakemake.py:362:8: PLR1714 Consider merging multiple comparisons: `parsed.scheme not in ("", "docker")`. Use a `set` if the elements are hashable.
- src/latch_cli/snakemake/single_task_snakemake.py:362:8: PLR1714 Consider merging multiple comparisons: `parsed.scheme not in {"", "docker"}`.

lnbits/lnbits (+216 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ lnbits/app.py:257:6: UP006 Use `list` instead of `List` for type annotation
+ lnbits/app.py:9:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/commands.py:235:23: UP006 Use `list` instead of `List` for type annotation
+ lnbits/commands.py:465:6: UP006 Use `tuple` instead of `Tuple` for type annotation
+ lnbits/commands.py:494:6: UP006 Use `tuple` instead of `Tuple` for type annotation
+ lnbits/commands.py:6:1: UP035 `typing.List` is deprecated, use `list` instead
+ lnbits/commands.py:6:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead
+ lnbits/core/crud.py:1018:6: UP006 Use `list` instead of `List` for type annotation
+ lnbits/core/crud.py:1235:43: UP006 Use `list` instead of `List` for type annotation
... 140 additional changes omitted for rule UP006
+ lnbits/core/crud.py:4:1: UP035 `typing.Dict` is deprecated, use `dict` instead
... 206 additional changes omitted for project

pandas-dev/pandas (+0 -4 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

- pandas/core/groupby/groupby.py:4069:39: PYI061 `Literal[None, ...]` can be replaced with `Literal[...] | None`
- pandas/core/groupby/indexing.py:299:39: PYI061 `Literal[None, ...]` can be replaced with `Literal[...] | None`
- pandas/io/html.py:1027:28: PYI061 `Literal[None, ...]` can be replaced with `Literal[...] | None`
- pandas/io/html.py:223:32: PYI061 `Literal[None, ...]` can be replaced with `Literal[...] | None`

python/typeshed (+4 -4 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select E,F,FA,I,PYI,RUF,UP,W

- stdlib/ast.pyi:1480:16: RUF038 `Literal[True, False]` can be replaced with `bool`
- stdlib/ast.pyi:1481:35: RUF038 `Literal[True, False]` can be replaced with `bool`
- stdlib/ast.pyi:1484:45: RUF038 `Literal[True, False]` can be replaced with `bool`
+ stdlib/random.pyi:45:31: PYI041 Use `float` instead of `int | float`
+ stdlib/random.pyi:52:27: PYI041 Use `float` instead of `int | float`
+ stdlib/turtle.pyi:443:16: PYI041 Use `float` instead of `int | float`
+ stdlib/turtle.pyi:444:17: PYI041 Use `float` instead of `int | float`
- stubs/pyxdg/xdg/Menu.pyi:97:11: RUF038 `Literal[True, False, ...]` can be replaced with `Literal[...] | bool`

... Truncated remaining completed project reports due to GitHub comment length restrictions

pypa/setuptools (error)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

ruff failed
  Cause: Failed to parse /home/runner/work/ruff/ruff/checkouts/pypa:setuptools/ruff.toml
  Cause: TOML parse error at line 8, column 1
  |
8 | [lint]
  | ^^^^^^
Unknown rule selector: `UP027`

Changes by rule (15 rules affected)

code total + violation - violation + fix - fix
DOC201 12115 6057 6058 0 0
DOC501 3924 1962 1962 0 0
DOC402 408 204 204 0 0
DOC202 158 79 79 0 0
UP006 145 145 0 0 0
UP035 71 71 0 0 0
PYI041 70 4 0 0 66
PLR1714 62 31 31 0 0
PYI061 14 0 14 0 0
RUF038 7 0 7 0 0
DOC502 4 2 2 0 0
RUF200 2 2 0 0 0
DOC403 2 1 1 0 0
DTZ901 1 1 0 0 0
RUF100 1 0 1 0 0

Formatter (stable)

ℹ️ ecosystem check detected format changes. (+111 -85 lines in 16 files in 4 projects; 1 project error; 49 projects unchanged)

aws/aws-sam-cli (+34 -30 lines across 4 files)

tests/integration/pipeline/test_init_command.py~L98

 
         self.assertEqual(init_process_execute.process.returncode, 0)
 
-        with open(EXPECTED_JENKINS_FILE_PATH, "r") as expected, open(
-            os.path.join(".aws-sam", "pipeline", "generated-files", "Jenkinsfile"), "r"
-        ) as output:
+        with (
+            open(EXPECTED_JENKINS_FILE_PATH, "r") as expected,
+            open(os.path.join(".aws-sam", "pipeline", "generated-files", "Jenkinsfile"), "r") as output,
+        ):
             self.assertEqual(expected.read(), output.read())
 
         # also check the Jenkinsfile is not overridden

tests/unit/commands/samconfig/test_samconfig.py~L1066

         }
 
         # NOTE: Because we don't load the full Click BaseCommand here, this is mounted as top-level command
-        with samconfig_parameters(
-            ["start-lambda"], self.scratch_dir, **config_values
-        ) as config_path, tempfile.NamedTemporaryFile() as key_file, tempfile.NamedTemporaryFile() as cert_file:
+        with (
+            samconfig_parameters(["start-lambda"], self.scratch_dir, **config_values) as config_path,
+            tempfile.NamedTemporaryFile() as key_file,
+            tempfile.NamedTemporaryFile() as cert_file,
+        ):
             from samcli.commands.local.start_lambda.cli import cli
 
             LOG.debug(Path(config_path).read_text())

tests/unit/commands/samconfig/test_samconfig.py~L1171

         }
 
         # NOTE: Because we don't load the full Click BaseCommand here, this is mounted as top-level command
-        with samconfig_parameters(
-            ["start-lambda"], self.scratch_dir, **config_values
-        ) as config_path, tempfile.NamedTemporaryFile() as key_file, tempfile.NamedTemporaryFile() as cert_file:
+        with (
+            samconfig_parameters(["start-lambda"], self.scratch_dir, **config_values) as config_path,
+            tempfile.NamedTemporaryFile() as key_file,
+            tempfile.NamedTemporaryFile() as cert_file,
+        ):
             from samcli.commands.local.start_lambda.cli import cli
 
             LOG.debug(Path(config_path).read_text())

tests/unit/lib/build_module/test_build_strategy.py~L747

     def test_will_call_incremental_build_strategy(self, mocked_read, mocked_write, runtime):
         build_definition = FunctionBuildDefinition(runtime, "codeuri", None, "package_type", X86_64, {}, "handler")
         self.build_graph.put_function_build_definition(build_definition, Mock(full_path="function_full_path"))
-        with patch.object(
-            self.build_strategy, "_incremental_build_strategy"
-        ) as patched_incremental_build_strategy, patch.object(
-            self.build_strategy, "_cached_build_strategy"
-        ) as patched_cached_build_strategy:
+        with (
+            patch.object(self.build_strategy, "_incremental_build_strategy") as patched_incremental_build_strategy,
+            patch.object(self.build_strategy, "_cached_build_strategy") as patched_cached_build_strategy,
+        ):
             self.build_strategy.build()
 
             patched_incremental_build_strategy.build_single_function_definition.assert_called_with(build_definition)

tests/unit/lib/build_module/test_build_strategy.py~L767

     def test_will_call_cached_build_strategy(self, mocked_read, mocked_write, runtime):
         build_definition = FunctionBuildDefinition(runtime, "codeuri", None, "package_type", X86_64, {}, "handler")
         self.build_graph.put_function_build_definition(build_definition, Mock(full_path="function_full_path"))
-        with patch.object(
-            self.build_strategy, "_incremental_build_strategy"
-        ) as patched_incremental_build_strategy, patch.object(
-            self.build_strategy, "_cached_build_strategy"
-        ) as patched_cached_build_strategy:
+        with (
+            patch.object(self.build_strategy, "_incremental_build_strategy") as patched_incremental_build_strategy,
+            patch.object(self.build_strategy, "_cached_build_strategy") as patched_cached_build_strategy,
+        ):
             self.build_strategy.build()
 
             patched_cached_build_strategy.build_single_function_definition.assert_called_with(build_definition)

tests/unit/lib/build_module/test_build_strategy.py~L841

 
         build_definition = FunctionBuildDefinition(runtime, "codeuri", None, "package_type", X86_64, {}, "handler")
         self.build_graph.put_function_build_definition(build_definition, Mock(full_path="function_full_path"))
-        with patch.object(
-            build_strategy, "_incremental_build_strategy"
-        ) as patched_incremental_build_strategy, patch.object(
-            build_strategy, "_cached_build_strategy"
-        ) as patched_cached_build_strategy:
+        with (
+            patch.object(build_strategy, "_incremental_build_strategy") as patched_incremental_build_strategy,
+            patch.object(build_strategy, "_cached_build_strategy") as patched_cached_build_strategy,
+        ):
             build_strategy.build()
 
             if not use_container:

tests/unit/lib/remote_invoke/test_remote_invoke_executors.py~L79

         given_output_format = "text"
         test_execution_info = RemoteInvokeExecutionInfo(given_payload, None, given_parameters, given_output_format)
 
-        with patch.object(self.boto_action_executor, "_execute_action") as patched_execute_action, patch.object(
-            self.boto_action_executor, "_execute_action_file"
-        ) as patched_execute_action_file:
+        with (
+            patch.object(self.boto_action_executor, "_execute_action") as patched_execute_action,
+            patch.object(self.boto_action_executor, "_execute_action_file") as patched_execute_action_file,
+        ):
             given_result = Mock()
             patched_execute_action.return_value = given_result
 

tests/unit/lib/remote_invoke/test_remote_invoke_executors.py~L96

         given_output_format = "json"
         test_execution_info = RemoteInvokeExecutionInfo(None, given_payload_file, given_parameters, given_output_format)
 
-        with patch.object(self.boto_action_executor, "_execute_action") as patched_execute_action, patch.object(
-            self.boto_action_executor, "_execute_action_file"
-        ) as patched_execute_action_file:
+        with (
+            patch.object(self.boto_action_executor, "_execute_action") as patched_execute_action,
+            patch.object(self.boto_action_executor, "_execute_action_file") as patched_execute_action_file,
+        ):
             given_result = Mock()
             patched_execute_action_file.return_value = given_result
 

langchain-ai/langchain (+32 -23 lines across 5 files)

libs/community/tests/unit_tests/document_loaders/test_mongodb.py~L50

     mock_collection.find = mock_find
     mock_collection.count_documents = mock_count_documents
 
-    with patch(
-        "motor.motor_asyncio.AsyncIOMotorClient", return_value=MagicMock()
-    ), patch(
-        "langchain_community.document_loaders.mongodb.MongodbLoader.aload",
-        new=mock_async_load,
+    with (
+        patch("motor.motor_asyncio.AsyncIOMotorClient", return_value=MagicMock()),
+        patch(
+            "langchain_community.document_loaders.mongodb.MongodbLoader.aload",
+            new=mock_async_load,
+        ),
     ):
         loader = MongodbLoader(
             "mongodb://localhost:27017",

libs/community/tests/unit_tests/tools/audio/test_tools.py~L44

 def test_huggingface_tts_run_with_requests_mock() -> None:
     os.environ["HUGGINGFACE_API_KEY"] = "foo"
 
-    with tempfile.TemporaryDirectory() as tmp_dir, patch(
-        "uuid.uuid4"
-    ) as mock_uuid, patch("requests.post") as mock_inference, patch(
-        "builtins.open", mock_open()
-    ) as mock_file:
+    with (
+        tempfile.TemporaryDirectory() as tmp_dir,
+        patch("uuid.uuid4") as mock_uuid,
+        patch("requests.post") as mock_inference,
+        patch("builtins.open", mock_open()) as mock_file,
+    ):
         input_query = "Dummy input"
 
         mock_uuid_value = uuid.UUID("00000000-0000-0000-0000-000000000000")

libs/community/tests/unit_tests/vectorstores/test_azure_search.py~L220

     ]
     ids_provided = [i.metadata.get("id") for i in documents]
 
-    with patch.object(
-        SearchClient, "upload_documents", mock_upload_documents
-    ), patch.object(SearchIndexClient, "get_index", mock_default_index):
+    with (
+        patch.object(SearchClient, "upload_documents", mock_upload_documents),
+        patch.object(SearchIndexClient, "get_index", mock_default_index),
+    ):
         vector_store = create_vector_store()
         ids_used_at_upload = vector_store.add_documents(documents, ids=ids_provided)
         assert len(ids_provided) == len(ids_used_at_upload)

libs/langchain/tests/unit_tests/smith/evaluation/test_runner_utils.py~L316

         proj.id = "123"
         return proj
 
-    with mock.patch.object(
-        Client, "read_dataset", new=mock_read_dataset
-    ), mock.patch.object(Client, "list_examples", new=mock_list_examples), mock.patch(
-        "langchain.smith.evaluation.runner_utils._arun_llm_or_chain",
-        new=mock_arun_chain,
-    ), mock.patch.object(Client, "create_project", new=mock_create_project):
+    with (
+        mock.patch.object(Client, "read_dataset", new=mock_read_dataset),
+        mock.patch.object(Client, "list_examples", new=mock_list_examples),
+        mock.patch(
+            "langchain.smith.evaluation.runner_utils._arun_llm_or_chain",
+            new=mock_arun_chain,
+        ),
+        mock.patch.object(Client, "create_project", new=mock_create_project),
+    ):
         client = Client(api_url="http://localhost:1984", api_key="123")
         chain = mock.MagicMock()
         chain.input_keys = ["foothing"]

libs/partners/huggingface/tests/unit_tests/test_chat_models.py~L231

 
 def test_bind_tools(chat_hugging_face: Any) -> None:
     tools = [MagicMock(spec=BaseTool)]
-    with patch(
-        "langchain_huggingface.chat_models.huggingface.convert_to_openai_tool",
-        side_effect=lambda x: x,
-    ), patch("langchain_core.runnables.base.Runnable.bind") as mock_super_bind:
+    with (
+        patch(
+            "langchain_huggingface.chat_models.huggingface.convert_to_openai_tool",
+            side_effect=lambda x: x,
+        ),
+        patch("langchain_core.runnables.base.Runnable.bind") as mock_super_bind,
+    ):
         chat_hugging_face.bind_tools(tools, tool_choice="auto")
         mock_super_bind.assert_called_once()
         _, kwargs = mock_super_bind.call_args

prefecthq/prefect (+38 -27 lines across 5 files)

src/integrations/prefect-dbt/prefect_dbt/cloud/jobs.py~L752

         run_status = DbtCloudJobRunStatus(run_data.get("status"))
         if run_status == DbtCloudJobRunStatus.SUCCESS:
             try:
-                async with self._dbt_cloud_credentials.get_administrative_client() as client:  # noqa
+                async with (
+                    self._dbt_cloud_credentials.get_administrative_client() as client
+                ):  # noqa
                     response = await client.list_run_artifacts(
                         run_id=self.run_id, step=step
                     )

tests/runner/test_webserver.py~L151

             webserver = await build_server(runner)
             client = TestClient(webserver)
 
-            with mock.patch(
-                "prefect.runner.server.get_client", new=mock_get_client
-            ), mock.patch.object(runner, "execute_in_background"):
+            with (
+                mock.patch("prefect.runner.server.get_client", new=mock_get_client),
+                mock.patch.object(runner, "execute_in_background"),
+            ):
                 with client:
                     response = client.post(f"/deployment/{deployment_id}/run")
                 assert response.status_code == 201, response.json()

tests/server/orchestration/api/test_task_run_subscriptions.py~L326

             )
             await queue.put(task_run)
 
-        with patch("asyncio.sleep", return_value=None), pytest.raises(
-            asyncio.TimeoutError
+        with (
+            patch("asyncio.sleep", return_value=None),
+            pytest.raises(asyncio.TimeoutError),
         ):
             extra_task_run = ServerTaskRun(
                 id=uuid4(),

tests/server/orchestration/api/test_task_run_subscriptions.py~L356

         )
         await queue.retry(task_run)
 
-        with patch("asyncio.sleep", return_value=None), pytest.raises(
-            asyncio.TimeoutError
+        with (
+            patch("asyncio.sleep", return_value=None),
+            pytest.raises(asyncio.TimeoutError),
         ):
             extra_task_run = ServerTaskRun(
                 id=uuid4(),

tests/test_task_worker.py~L106

 async def test_handle_sigterm(mock_create_subscription):
     task_worker = TaskWorker(...)
 
-    with patch("sys.exit") as mock_exit, patch.object(
-        task_worker, "stop", new_callable=AsyncMock
-    ) as mock_stop:
+    with (
+        patch("sys.exit") as mock_exit,
+        patch.object(task_worker, "stop", new_callable=AsyncMock) as mock_stop,
+    ):
         await task_worker.start()
 
         mock_create_subscription.assert_called_once()

tests/test_task_worker.py~L120

 
 
 async def test_task_worker_client_id_is_set():
-    with patch("socket.gethostname", return_value="foo"), patch(
-        "os.getpid", return_value=42
+    with (
+        patch("socket.gethostname", return_value="foo"),
+        patch("os.getpid", return_value=42),
     ):
         task_worker = TaskWorker(...)
         task_worker._client = MagicMock(api_url="http://localhost:4200")

tests/workers/test_base_worker.py~L1905

     ):
         async with WorkerTestImpl(work_pool_name=work_pool.name) as worker:
             await worker.start(run_once=True)
-            with mock.patch(
-                "prefect.workers.base.load_prefect_collections"
-            ) as mock_load_prefect_collections, mock.patch(
-                "prefect.client.orchestration.PrefectHttpxAsyncClient.post"
-            ) as mock_send_worker_heartbeat_post, mock.patch(
-                "prefect.workers.base.distributions"
-            ) as mock_distributions:
+            with (
+                mock.patch(
+                    "prefect.workers.base.load_prefect_collections"
+                ) as mock_load_prefect_collections,
+                mock.patch(
+                    "prefect.client.orchestration.PrefectHttpxAsyncClient.post"
+                ) as mock_send_worker_heartbeat_post,
+                mock.patch("prefect.workers.base.distributions") as mock_distributions,
+            ):
                 mock_load_prefect_collections.return_value = {
                     "prefect_aws": "1.0.0",
                 }

tests/workers/test_base_worker.py~L1963

 
         async with CustomWorker(work_pool_name=work_pool.name) as worker:
             await worker.start(run_once=True)
-            with mock.patch(
-                "prefect.workers.base.load_prefect_collections"
-            ) as mock_load_prefect_collections, mock.patch(
-                "prefect.client.orchestration.PrefectHttpxAsyncClient.post"
-            ) as mock_send_worker_heartbeat_post, mock.patch(
-                "prefect.workers.base.distributions"
-            ) as mock_distributions:
+            with (
+                mock.patch(
+                    "prefect.workers.base.load_prefect_collections"
+                ) as mock_load_prefect_collections,
+                mock.patch(
+                    "prefect.client.orchestration.PrefectHttpxAsyncClient.post"
+                ) as mock_send_worker_heartbeat_post,
+                mock.patch("prefect.workers.base.distributions") as mock_distributions,
+            ):
                 mock_load_prefect_collections.return_value = {
                     "prefect_aws": "1.0.0",
                 }

yandex/ch-backup (+7 -5 lines across 2 files)

tests/unit/test_backup_tables.py~L65

     read_bytes_mock = Mock(return_value=creation_statement.encode())
 
     # Backup table
-    with patch("os.path.getmtime", side_effect=mtime), patch(
-        "ch_backup.logic.table.Path", read_bytes=read_bytes_mock
+    with (
+        patch("os.path.getmtime", side_effect=mtime),
+        patch("ch_backup.logic.table.Path", read_bytes=read_bytes_mock),
     ):
         table_backup.backup(
             context,

tests/unit/test_pipeline.py~L164

         forward_file_path, backward_file_name, read_conf, encrypt_conf, write_conf
     )
 
-    with open(original_file_path, "rb") as orig_fobj, open(
-        backward_file_name, "rb"
-    ) as res_fobj:
+    with (
+        open(original_file_path, "rb") as orig_fobj,
+        open(backward_file_name, "rb") as res_fobj,
+    ):
         orig_contents = orig_fobj.read()
         res_contents = res_fobj.read()
 

pypa/setuptools (error)

ruff failed
  Cause: Failed to parse /home/runner/work/ruff/ruff/checkouts/pypa:setuptools/ruff.toml
  Cause: TOML parse error at line 8, column 1
  |
8 | [lint]
  | ^^^^^^
Unknown rule selector: `UP027`

Formatter (preview)

ℹ️ ecosystem check detected format changes. (+110 -86 lines in 16 files in 4 projects; 1 project error; 49 projects unchanged)

aws/aws-sam-cli (+34 -30 lines across 4 files)

ruff format --preview

tests/integration/pipeline/test_init_command.py~L98

 
         self.assertEqual(init_process_execute.process.returncode, 0)
 
-        with open(EXPECTED_JENKINS_FILE_PATH, "r") as expected, open(
-            os.path.join(".aws-sam", "pipeline", "generated-files", "Jenkinsfile"), "r"
-        ) as output:
+        with (
+            open(EXPECTED_JENKINS_FILE_PATH, "r") as expected,
+            open(os.path.join(".aws-sam", "pipeline", "generated-files", "Jenkinsfile"), "r") as output,
+        ):
             self.assertEqual(expected.read(), output.read())
 
         # also check the Jenkinsfile is not overridden

tests/unit/commands/samconfig/test_samconfig.py~L1066

         }
 
         # NOTE: Because we don't load the full Click BaseCommand here, this is mounted as top-level command
-        with samconfig_parameters(
-            ["start-lambda"], self.scratch_dir, **config_values
-        ) as config_path, tempfile.NamedTemporaryFile() as key_file, tempfile.NamedTemporaryFile() as cert_file:
+        with (
+            samconfig_parameters(["start-lambda"], self.scratch_dir, **config_values) as config_path,
+            tempfile.NamedTemporaryFile() as key_file,
+            tempfile.NamedTemporaryFile() as cert_file,
+        ):
             from samcli.commands.local.start_lambda.cli import cli
 
             LOG.debug(Path(config_path).read_text())

tests/unit/commands/samconfig/test_samconfig.py~L1171

         }
 
         # NOTE: Because we don't load the full Click BaseCommand here, this is mounted as top-level command
-        with samconfig_parameters(
-            ["start-lambda"], self.scratch_dir, **config_values
-        ) as config_path, tempfile.NamedTemporaryFile() as key_file, tempfile.NamedTemporaryFile() as cert_file:
+        with (
+            samconfig_parameters(["start-lambda"], self.scratch_dir, **config_values) as config_path,
+            tempfile.NamedTemporaryFile() as key_file,
+            tempfile.NamedTemporaryFile() as cert_file,
+        ):
             from samcli.commands.local.start_lambda.cli import cli
 
             LOG.debug(Path(config_path).read_text())

tests/unit/lib/build_module/test_build_strategy.py~L723

     def test_will_call_incremental_build_strategy(self, mocked_read, mocked_write, runtime):
         build_definition = FunctionBuildDefinition(runtime, "codeuri", None, "package_type", X86_64, {}, "handler")
         self.build_graph.put_function_build_definition(build_definition, Mock(full_path="function_full_path"))
-        with patch.object(
-            self.build_strategy, "_incremental_build_strategy"
-        ) as patched_incremental_build_strategy, patch.object(
-            self.build_strategy, "_cached_build_strategy"
-        ) as patched_cached_build_strategy:
+        with (
+            patch.object(self.build_strategy, "_incremental_build_strategy") as patched_incremental_build_strategy,
+            patch.object(self.build_strategy, "_cached_build_strategy") as patched_cached_build_strategy,
+        ):
             self.build_strategy.build()
 
             patched_incremental_build_strategy.build_single_function_definition.assert_called_with(build_definition)

tests/unit/lib/build_module/test_build_strategy.py~L741

     def test_will_call_cached_build_strategy(self, mocked_read, mocked_write, runtime):
         build_definition = FunctionBuildDefinition(runtime, "codeuri", None, "package_type", X86_64, {}, "handler")
         self.build_graph.put_function_build_definition(build_definition, Mock(full_path="function_full_path"))
-        with patch.object(
-            self.build_strategy, "_incremental_build_strategy"
-        ) as patched_incremental_build_strategy, patch.object(
-            self.build_strategy, "_cached_build_strategy"
-        ) as patched_cached_build_strategy:
+        with (
+            patch.object(self.build_strategy, "_incremental_build_strategy") as patched_incremental_build_strategy,
+            patch.object(self.build_strategy, "_cached_build_strategy") as patched_cached_build_strategy,
+        ):
             self.build_strategy.build()
 
             patched_cached_build_strategy.build_single_function_definition.assert_called_with(build_definition)

tests/unit/lib/build_module/test_build_strategy.py~L813

 
         build_definition = FunctionBuildDefinition(runtime, "codeuri", None, "package_type", X86_64, {}, "handler")
         self.build_graph.put_function_build_definition(build_definition, Mock(full_path="function_full_path"))
-        with patch.object(
-            build_strategy, "_incremental_build_strategy"
-        ) as patched_incremental_build_strategy, patch.object(
-            build_strategy, "_cached_build_strategy"
-        ) as patched_cached_build_strategy:
+        with (
+            patch.object(build_strategy, "_incremental_build_strategy") as patched_incremental_build_strategy,
+            patch.object(build_strategy, "_cached_build_strategy") as patched_cached_build_strategy,
+        ):
             build_strategy.build()
 
             if not use_container:

tests/unit/lib/remote_invoke/test_remote_invoke_executors.py~L79

         given_output_format = "text"
         test_execution_info = RemoteInvokeExecutionInfo(given_payload, None, given_parameters, given_output_format)
 
-        with patch.object(self.boto_action_executor, "_execute_action") as patched_execute_action, patch.object(
-            self.boto_action_executor, "_execute_action_file"
-        ) as patched_execute_action_file:
+        with (
+            patch.object(self.boto_action_executor, "_execute_action") as patched_execute_action,
+            patch.object(self.boto_action_executor, "_execute_action_file") as patched_execute_action_file,
+        ):
             given_result = Mock()
             patched_execute_action.return_value = given_result
 

tests/unit/lib/remote_invoke/test_remote_invoke_executors.py~L96

         given_output_format = "json"
         test_execution_info = RemoteInvokeExecutionInfo(None, given_payload_file, given_parameters, given_output_format)
 
-        with patch.object(self.boto_action_executor, "_execute_action") as patched_execute_action, patch.object(
-            self.boto_action_executor, "_execute_action_file"
-        ) as patched_execute_action_file:
+        with (
+            patch.object(self.boto_action_executor, "_execute_action") as patched_execute_action,
+            patch.object(self.boto_action_executor, "_execute_action_file") as patched_execute_action_file,
+        ):
             given_result = Mock()
             patched_execute_action_file.return_value = given_result
 

langchain-ai/langchain (+32 -23 lines across 5 files)

ruff format --preview

libs/community/tests/unit_tests/document_loaders/test_mongodb.py~L50

     mock_collection.find = mo...*[Comment body truncated]*

@MichaReiser
Copy link
Member

I went ahead and disabled the pyproject_toml linting for wasm to unblock this PR. That's why I request review from someone else.

@dhruvmanila
Copy link
Member

Looking at the ecosystem changes, it seems that we'll now create diagnostic for the old definition related to license-files: https://github.com/apache/airflow/blob/476e77d9aba492a2159b256bc7a4aa86e560dee5/clients/python/pyproject.toml#L27. Do we want to maintain backwards compatibility?

@konstin
Copy link
Member Author

konstin commented Oct 25, 2024

I don't think so, that syntax was only part of a draft and never of any (provisionally) accepted PEP. It makes sense to lint against it to migrate the early adopters to the final version (and i'm expecting that hatch will migrate, too).

@MichaReiser
Copy link
Member

Let's make this a breaking change.

@MichaReiser MichaReiser added the breaking Breaking API change label Oct 26, 2024
@MichaReiser MichaReiser added this to the v0.8 milestone Oct 26, 2024
@MichaReiser
Copy link
Member

@konstin added wasm upstream. We can roll-back my rule exclusion once the new version is out. See PyO3/pyproject-toml-rs@2ed4df2

@AlexWaygood AlexWaygood changed the base branch from main to ruff-0.8 November 16, 2024 19:39
@MichaReiser MichaReiser force-pushed the konsti/pep639 branch 2 times, most recently from e35a647 to 2a6da87 Compare November 18, 2024 13:44
PEP 639 is provisionally accepted, we were previously shipping definitions from an earlier draft.

We don't validate all that's in the PEP (`license` vs. `license-files` compatibility, SPDX expressions), only the overall structure of pyproject.toml.

Updates pep440_rs in the process.

Fixes #13869
@MichaReiser MichaReiser merged commit 1d1a14a into ruff-0.8 Nov 18, 2024
@MichaReiser MichaReiser deleted the konsti/pep639 branch November 18, 2024 14:16
@AlexWaygood AlexWaygood mentioned this pull request Nov 18, 2024
MichaReiser pushed a commit that referenced this pull request Nov 19, 2024
AlexWaygood pushed a commit that referenced this pull request Nov 19, 2024
MichaReiser pushed a commit that referenced this pull request Nov 20, 2024
MichaReiser pushed a commit that referenced this pull request Nov 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Breaking API change rule Implementing or modifying a lint rule

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for PEP 639 in RUF200

3 participants