(อัปเดตเมื่อวันที่ 28 พฤษภาคม 2016) การใช้ RealGUD ใน Emacs
สำหรับทุกคนใน Emacs เธรดนี้แสดงวิธีการทำทุกอย่างที่อธิบายไว้ใน OP (และอื่น ๆ ) โดยใช้
- ดีบักเกอร์สำคัญใหม่ใน Emacs ที่เรียกว่าRealGUDซึ่งสามารถทำงานกับดีบักเกอร์ใด ๆ (รวมถึง
ipdb
)
isend-mode
แพคเกจ Emacs
การรวมกันของสองแพ็คเกจนี้มีประสิทธิภาพสูงมากและทำให้สามารถสร้างพฤติกรรมที่อธิบายไว้ใน OP และทำสิ่งต่างๆได้มากขึ้น
ข้อมูลเพิ่มเติมเกี่ยวกับบทความ wikiของ RealGUD สำหรับ ipdb
คำตอบเดิม:
หลังจากลองใช้วิธีต่างๆมากมายในการดีบัก Python รวมถึงทุกอย่างที่กล่าวถึงในเธรดนี้หนึ่งในวิธีที่ฉันต้องการในการดีบัก Python กับ IPython คือการใช้เชลล์ฝังตัว
การกำหนดเปลือก IPython แบบฝังที่กำหนดเอง:
เพิ่มสคริปต์ต่อไปนี้ในของคุณPYTHONPATH
เพื่อให้วิธีการipsh()
ใช้งานได้
import inspect
# First import the embed function
from IPython.terminal.embed import InteractiveShellEmbed
from IPython.config.loader import Config
# Configure the prompt so that I know I am in a nested (embedded) shell
cfg = Config()
prompt_config = cfg.PromptManager
prompt_config.in_template = 'N.In <\\#>: '
prompt_config.in2_template = ' .\\D.: '
prompt_config.out_template = 'N.Out<\\#>: '
# Messages displayed when I drop into and exit the shell.
banner_msg = ("\n**Nested Interpreter:\n"
"Hit Ctrl-D to exit interpreter and continue program.\n"
"Note that if you use %kill_embedded, you can fully deactivate\n"
"This embedded instance so it will never turn on again")
exit_msg = '**Leaving Nested interpreter'
# Wrap it in a function that gives me more context:
def ipsh():
ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)
frame = inspect.currentframe().f_back
msg = 'Stopped at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)
# Go back one level!
# This is needed because the call to ipshell is inside the function ipsh()
ipshell(msg,stack_depth=2)
จากนั้นเมื่อใดก็ตามที่ฉันต้องการตรวจแก้จุดบกพร่องบางอย่างในรหัสของฉันฉันวางipsh()
ขวาที่ตำแหน่งที่ฉันต้องทำการตรวจสอบวัตถุ ฯลฯ ตัวอย่างเช่นฉันต้องการตรวจแก้จุดบกพร่องmy_function
ด้านล่าง
ใช้มัน:
def my_function(b):
a = b
ipsh() # <- This will embed a full-fledged IPython interpreter
a = 4
และจากนั้นฉันเรียกใช้my_function(2)
หนึ่งในวิธีต่อไปนี้:
- ไม่ว่าโดยการรันโปรแกรม Python ที่เรียกใช้ฟังก์ชันนี้จาก Unix shell
- หรือโดยการเรียกใช้โดยตรงจาก IPython
ipsh()
โดยไม่คำนึงถึงวิธีการที่ฉันเรียกมันล่ามหยุดที่บรรทัดที่ระบุว่า เมื่อเสร็จแล้วคุณสามารถทำได้Ctrl-D
และ Python จะกลับมาทำงานต่อ (พร้อมกับการปรับปรุงตัวแปรที่คุณทำ) โปรดทราบว่าถ้าคุณเรียกใช้รหัสจาก IPython ปกติ IPython shell (กรณีที่ 2 ด้านบน), IPython shell ใหม่จะซ้อนอยู่ภายในรหัสที่คุณเรียกใช้ซึ่งดีมาก แต่ก็ควรระวัง เมื่อล่ามหยุดที่ตำแหน่งของipsh
ฉันฉันสามารถตรวจสอบค่าของa
(ซึ่ง2
), ดูฟังก์ชั่นและวัตถุที่มีการกำหนด ฯลฯ
ปัญหา:
วิธีการแก้ปัญหาข้างต้นสามารถใช้เพื่อให้ Python หยุดทุกที่ที่คุณต้องการในรหัสของคุณจากนั้นนำคุณไปสู่ล่าม IPython น่าเสียดายที่มันไม่ยอมให้คุณเพิ่มหรือลบเบรกพอยต์เมื่อคุณเรียกใช้สคริปต์ซึ่งน่าผิดหวังอย่างมาก ในความเห็นของฉันนี่เป็นเพียงสิ่งเดียวเท่านั้นสิ่งที่ทำให้ IPython กลายเป็นเครื่องมือดีบั๊กสำหรับ Python
สิ่งที่ดีที่สุดที่คุณสามารถทำได้ในตอนนี้:
วิธีแก้ปัญหาคือการวางipsh()
นิรนัยที่ตำแหน่งต่าง ๆ ที่คุณต้องการให้ Python interpreter เปิดใช้เชลล์ IPython (เช่น a breakpoint
) จากนั้นคุณสามารถ "ข้าม" ระหว่าง "เบรกพอยต์" ที่กำหนดไว้ล่วงหน้าแบบกำหนดรหัสล่วงหน้าด้วยCtrl-D
ซึ่งจะออกจากเชลล์ IPython ที่ฝังอยู่ในปัจจุบันและหยุดอีกครั้งเมื่อใดก็ตามที่ล่ามกดการโทรครั้งต่อไปipsh()
เปลือกและหยุดอีกครั้งเมื่อใดก็ตามที่ล่ามฮิตโทรไปเพื่อ
หากคุณไปที่เส้นทางนี้วิธีหนึ่งในการออกจาก "โหมดแก้ไขจุดบกพร่อง" และละเว้นจุดพักที่ตามมาทั้งหมดคือการใช้ipshell.dummy_mode = True
ซึ่งจะทำให้ Python ไม่สนใจอินสแตนซ์ของipshell
วัตถุที่เราสร้างขึ้นด้านบน
!
คำสั่งที่รันคำสั่ง python ใด ๆ ที่เบรกพอยต์