mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:53 +00:00

## Summary This PR updates the `StringLike::FString` variant to use `ExprFString` instead of `FStringLiteralElement`. For context, the reason it used `FStringLiteralElement` is that the node is actually the string part of an f-string ("foo" in `f"foo{x}"`). But, this is inconsistent with other variants where the captured value is the _entire_ string. This is also problematic w.r.t. implicitly concatenated strings. Any rules which work with `StringLike::FString` doesn't account for the string part in an implicitly concatenated f-strings. For example, we don't flag confusable character in the first part of `"𝐁ad" f"𝐁ad string"`, but only the second part (https://play.ruff.rs/16071c4c-a1dd-4920-b56f-e2ce2f69c843). ### Update `PYI053` _This is included in this PR because otherwise it requires a temporary workaround to be compatible with the old logic._ This PR also updates the `PYI053` (`string-or-bytes-too-long`) rule for f-string to consider _all_ the visible characters in a f-string, including the ones which are implicitly concatenated. This is consistent with implicitly concatenated strings and bytes. For example, ```python def foo( # We count all the characters here arg1: str = '51 character ' 'stringgggggggggggggggggggggggggggggggg', # But not here because of the `{x}` replacement field which _breaks_ them up into two chunks arg2: str = f'51 character {x} stringgggggggggggggggggggggggggggggggggggggggggggg', ) -> None: ... ``` This PR fixes it to consider all _visible_ characters inside an f-string which includes expressions as well. fixes: #10310 fixes: #10307 ## Test Plan Add new test cases and update the snapshots. ## Review To facilitate the review process, the change have been split into two commits: one which has the code change while the other has the test cases and updated snapshots.
42 lines
870 B
Python
42 lines
870 B
Python
# ok
|
|
with open("/abc/tmp", "w") as f:
|
|
f.write("def")
|
|
|
|
with open("/tmp/abc", "w") as f:
|
|
f.write("def")
|
|
|
|
with open(f"/tmp/abc", "w") as f:
|
|
f.write("def")
|
|
|
|
with open("/var/tmp/123", "w") as f:
|
|
f.write("def")
|
|
|
|
with open("/dev/shm/unit/test", "w") as f:
|
|
f.write("def")
|
|
|
|
# not ok by config
|
|
with open("/foo/bar", "w") as f:
|
|
f.write("def")
|
|
|
|
# Implicit string concatenation
|
|
with open("/tmp/" "abc", "w") as f:
|
|
f.write("def")
|
|
|
|
with open("/tmp/abc" f"/tmp/abc", "w") as f:
|
|
f.write("def")
|
|
|
|
# Using `tempfile` module should be ok
|
|
import tempfile
|
|
from tempfile import TemporaryDirectory
|
|
|
|
with tempfile.NamedTemporaryFile(dir="/tmp") as f:
|
|
f.write(b"def")
|
|
|
|
with tempfile.NamedTemporaryFile(dir="/var/tmp") as f:
|
|
f.write(b"def")
|
|
|
|
with tempfile.TemporaryDirectory(dir="/dev/shm") as d:
|
|
pass
|
|
|
|
with TemporaryDirectory(dir="/tmp") as d:
|
|
pass
|