mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-09 22:25:09 +00:00
[syntax-errors] Document behavior of global
declarations in try
nodes before 3.13 (#17285)
Summary -- This PR extends the documentation of the `LoadBeforeGlobalDeclaration` check to specify the behavior on versions of Python before 3.13. Namely, on Python 3.12, the `else` clause of a `try` statement is visited before the `except` handlers: ```pycon Python 3.12.9 (main, Feb 12 2025, 14:50:50) [Clang 19.1.6 ] on linux Type "help", "copyright", "credits" or "license" for more information. >>> a = 10 >>> def g(): ... try: ... 1 / 0 ... except: ... a = 1 ... else: ... global a ... >>> def f(): ... try: ... pass ... except: ... global a ... else: ... print(a) ... File "<stdin>", line 5 SyntaxError: name 'a' is used prior to global declaration ``` The order is swapped on 3.13 (see [CPython#111123](https://github.com/python/cpython/issues/111123)): ```pycon Python 3.13.2 (main, Feb 5 2025, 08:05:21) [GCC 14.2.1 20250128] on linux Type "help", "copyright", "credits" or "license" for more information. >>> a = 10 ... def g(): ... try: ... 1 / 0 ... except: ... a = 1 ... else: ... global a ... File "<python-input-0>", line 8 global a ^^^^^^^^ SyntaxError: name 'a' is assigned to before global declaration >>> def f(): ... try: ... pass ... except: ... global a ... else: ... print(a) ... >>> ``` The current implementation of PLE0118 is correct for 3.13 but not 3.12: [playground](https://play.ruff.rs/d7467ea6-f546-4a76-828f-8e6b800694c9) (it flags the first case regardless of Python version). We decided to maintain this incorrect diagnostic for Python versions before 3.13 because the pre-3.13 behavior is very unintuitive and confirmed to be a bug, although the bug fix was not backported to earlier versions. This can lead to false positives and false negatives for pre-3.13 code, but we also expect that to be very rare, as demonstrated by the ecosystem check (before the version-dependent check was reverted here). Test Plan -- N/a
This commit is contained in:
parent
73399029b2
commit
2fbc4d577e
1 changed files with 37 additions and 0 deletions
|
@ -1011,6 +1011,43 @@ pub enum SemanticSyntaxErrorKind {
|
|||
/// global counter
|
||||
/// counter += 1
|
||||
/// ```
|
||||
///
|
||||
/// ## Known Issues
|
||||
///
|
||||
/// Note that the order in which the parts of a `try` statement are visited was changed in 3.13,
|
||||
/// as tracked in Python issue [#111123]. For example, this code was valid on Python 3.12:
|
||||
///
|
||||
/// ```python
|
||||
/// a = 10
|
||||
/// def g():
|
||||
/// try:
|
||||
/// 1 / 0
|
||||
/// except:
|
||||
/// a = 1
|
||||
/// else:
|
||||
/// global a
|
||||
/// ```
|
||||
///
|
||||
/// While this more intuitive behavior aligned with the textual order was a syntax error:
|
||||
///
|
||||
/// ```python
|
||||
/// a = 10
|
||||
/// def f():
|
||||
/// try:
|
||||
/// pass
|
||||
/// except:
|
||||
/// global a
|
||||
/// else:
|
||||
/// a = 1 # SyntaxError: name 'a' is assigned to before global declaration
|
||||
/// ```
|
||||
///
|
||||
/// This was reversed in version 3.13 to make the second case valid and the first case a syntax
|
||||
/// error. We intentionally enforce the 3.13 ordering, regardless of the Python version, which
|
||||
/// will lead to both false positives and false negatives on 3.12 code that takes advantage of
|
||||
/// the old behavior. However, as mentioned in the Python issue, we expect code relying on this
|
||||
/// to be very rare and not worth the additional complexity to detect.
|
||||
///
|
||||
/// [#111123]: https://github.com/python/cpython/issues/111123
|
||||
LoadBeforeGlobalDeclaration { name: String, start: TextSize },
|
||||
|
||||
/// Represents the use of a starred expression in an invalid location, such as a `return` or
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue