From c007b175bad7ea05c5369ddcf11e6b5f41267398 Mon Sep 17 00:00:00 2001
From: Jeremy Hiatt <jeremy.hiatt@gmail.com>
Date: Fri, 1 Mar 2024 20:02:44 -0800
Subject: [PATCH] Check for use of `debugpy` and `ptvsd` debug modules (#10177)
 (#10194)

## Summary

This addresses https://github.com/astral-sh/ruff/issues/10177.

## Test Plan

I added additional lines to the existing test file for T100.
---
 .../test/fixtures/flake8_debugger/T100.py     |  12 ++
 .../rules/flake8_debugger/rules/debugger.rs   |   4 +-
 ..._flake8_debugger__tests__T100_T100.py.snap | 127 +++++++++++++++---
 3 files changed, 127 insertions(+), 16 deletions(-)

diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_debugger/T100.py b/crates/ruff_linter/resources/test/fixtures/flake8_debugger/T100.py
index d0f173db57303..8154f1a4cd19f 100644
--- a/crates/ruff_linter/resources/test/fixtures/flake8_debugger/T100.py
+++ b/crates/ruff_linter/resources/test/fixtures/flake8_debugger/T100.py
@@ -7,7 +7,19 @@
 from celery.contrib.rdb import set_trace
 from celery.contrib import rdb
 import celery.contrib.rdb
+from debugpy import wait_for_client
+import debugpy
+from ptvsd import break_into_debugger
+from ptvsd import enable_attach
+from ptvsd import wait_for_attach
+import ptvsd
 
 breakpoint()
 st()
 set_trace()
+debugpy.breakpoint()
+wait_for_client()
+debugpy.listen(1234)
+enable_attach()
+break_into_debugger()
+wait_for_attach()
diff --git a/crates/ruff_linter/src/rules/flake8_debugger/rules/debugger.rs b/crates/ruff_linter/src/rules/flake8_debugger/rules/debugger.rs
index 5cfc68a2bfea7..3656bbb52bd46 100644
--- a/crates/ruff_linter/src/rules/flake8_debugger/rules/debugger.rs
+++ b/crates/ruff_linter/src/rules/flake8_debugger/rules/debugger.rs
@@ -109,6 +109,8 @@ fn is_debugger_call(call_path: &CallPath) -> bool {
             ]
             | ["celery", "contrib", "rdb", "set_trace"]
             | ["builtins" | "", "breakpoint"]
+            | ["debugpy", "breakpoint" | "listen" | "wait_for_client"]
+            | ["ptvsd", "break_into_debugger" | "wait_for_attach"]
     )
 }
 
@@ -119,7 +121,7 @@ fn is_debugger_import(call_path: &CallPath) -> bool {
     // than (e.g.) `import celery.contrib.rdb`.
     matches!(
         call_path.as_slice(),
-        ["pdb" | "pudb" | "ipdb"]
+        ["pdb" | "pudb" | "ipdb" | "debugpy" | "ptvsd"]
             | ["IPython", "terminal", "embed"]
             | ["IPython", "frontend", "terminal", "embed",]
             | ["celery", "contrib", "rdb"]
diff --git a/crates/ruff_linter/src/rules/flake8_debugger/snapshots/ruff_linter__rules__flake8_debugger__tests__T100_T100.py.snap b/crates/ruff_linter/src/rules/flake8_debugger/snapshots/ruff_linter__rules__flake8_debugger__tests__T100_T100.py.snap
index 6bc248c15b977..9fe528f183080 100644
--- a/crates/ruff_linter/src/rules/flake8_debugger/snapshots/ruff_linter__rules__flake8_debugger__tests__T100_T100.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_debugger/snapshots/ruff_linter__rules__flake8_debugger__tests__T100_T100.py.snap
@@ -55,34 +55,131 @@ T100.py:9:1: T100 Import for `celery.contrib.rdb` found
  8 | from celery.contrib import rdb
  9 | import celery.contrib.rdb
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ T100
-10 | 
-11 | breakpoint()
+10 | from debugpy import wait_for_client
+11 | import debugpy
    |
 
-T100.py:11:1: T100 Trace found: `builtins.breakpoint` used
+T100.py:10:1: T100 Import for `debugpy.wait_for_client` found
+   |
+ 8 | from celery.contrib import rdb
+ 9 | import celery.contrib.rdb
+10 | from debugpy import wait_for_client
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ T100
+11 | import debugpy
+12 | from ptvsd import break_into_debugger
+   |
+
+T100.py:11:1: T100 Import for `debugpy` found
    |
  9 | import celery.contrib.rdb
-10 | 
-11 | breakpoint()
+10 | from debugpy import wait_for_client
+11 | import debugpy
+   | ^^^^^^^^^^^^^^ T100
+12 | from ptvsd import break_into_debugger
+13 | from ptvsd import enable_attach
+   |
+
+T100.py:12:1: T100 Import for `ptvsd.break_into_debugger` found
+   |
+10 | from debugpy import wait_for_client
+11 | import debugpy
+12 | from ptvsd import break_into_debugger
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ T100
+13 | from ptvsd import enable_attach
+14 | from ptvsd import wait_for_attach
+   |
+
+T100.py:14:1: T100 Import for `ptvsd.wait_for_attach` found
+   |
+12 | from ptvsd import break_into_debugger
+13 | from ptvsd import enable_attach
+14 | from ptvsd import wait_for_attach
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ T100
+15 | import ptvsd
+   |
+
+T100.py:15:1: T100 Import for `ptvsd` found
+   |
+13 | from ptvsd import enable_attach
+14 | from ptvsd import wait_for_attach
+15 | import ptvsd
    | ^^^^^^^^^^^^ T100
-12 | st()
-13 | set_trace()
+16 | 
+17 | breakpoint()
    |
 
-T100.py:12:1: T100 Trace found: `pdb.set_trace` used
+T100.py:17:1: T100 Trace found: `builtins.breakpoint` used
+   |
+15 | import ptvsd
+16 | 
+17 | breakpoint()
+   | ^^^^^^^^^^^^ T100
+18 | st()
+19 | set_trace()
    |
-11 | breakpoint()
-12 | st()
+
+T100.py:18:1: T100 Trace found: `pdb.set_trace` used
+   |
+17 | breakpoint()
+18 | st()
    | ^^^^ T100
-13 | set_trace()
+19 | set_trace()
+20 | debugpy.breakpoint()
    |
 
-T100.py:13:1: T100 Trace found: `celery.contrib.rdb.set_trace` used
+T100.py:19:1: T100 Trace found: `celery.contrib.rdb.set_trace` used
    |
-11 | breakpoint()
-12 | st()
-13 | set_trace()
+17 | breakpoint()
+18 | st()
+19 | set_trace()
    | ^^^^^^^^^^^ T100
+20 | debugpy.breakpoint()
+21 | wait_for_client()
+   |
+
+T100.py:20:1: T100 Trace found: `debugpy.breakpoint` used
+   |
+18 | st()
+19 | set_trace()
+20 | debugpy.breakpoint()
+   | ^^^^^^^^^^^^^^^^^^^^ T100
+21 | wait_for_client()
+22 | debugpy.listen(1234)
    |
 
+T100.py:21:1: T100 Trace found: `debugpy.wait_for_client` used
+   |
+19 | set_trace()
+20 | debugpy.breakpoint()
+21 | wait_for_client()
+   | ^^^^^^^^^^^^^^^^^ T100
+22 | debugpy.listen(1234)
+23 | enable_attach()
+   |
 
+T100.py:22:1: T100 Trace found: `debugpy.listen` used
+   |
+20 | debugpy.breakpoint()
+21 | wait_for_client()
+22 | debugpy.listen(1234)
+   | ^^^^^^^^^^^^^^^^^^^^ T100
+23 | enable_attach()
+24 | break_into_debugger()
+   |
+
+T100.py:24:1: T100 Trace found: `ptvsd.break_into_debugger` used
+   |
+22 | debugpy.listen(1234)
+23 | enable_attach()
+24 | break_into_debugger()
+   | ^^^^^^^^^^^^^^^^^^^^^ T100
+25 | wait_for_attach()
+   |
+
+T100.py:25:1: T100 Trace found: `ptvsd.wait_for_attach` used
+   |
+23 | enable_attach()
+24 | break_into_debugger()
+25 | wait_for_attach()
+   | ^^^^^^^^^^^^^^^^^ T100
+   |