Как гарантировать, что мой сценарий Python и его дочерние процессы правильно обрабатывают сочетание клавиш Ctrl-C?Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Как гарантировать, что мой сценарий Python и его дочерние процессы правильно обрабатывают сочетание клавиш Ctrl-C?

Сообщение Anonymous »

Система: Проблема:

При запуске программы Python через окно терминала , CTL-C не всегда обеспечивает желаемое завершение работы.  При запуске внутри Thonny он работает всегда.

Обратите внимание на следующий скрипт Python, который был дословно взят с веб-сайта Adafruit для тестирования их «Bonnet» OLED Raspberry Pi 128x32.
Я изменил его, добавив некоторый код для захвата и обработки прерываний сигналов, чтобы он очищал и закрывал дисплей по завершении программы.
А именно:

Код: Выделить всё

#!/usr/bin/python3.7

# SPDX-FileCopyrightText:  2020 Tony DiCola, James DeVito,
# and 2020 Melissa LeBlanc-Williams, for Adafruit Industries 

# SPDX-License-Identifier: MIT

# This example is for use on (Linux) computers that are using CPython with
# Adafruit Blinka to support CircuitPython libraries. CircuitPython does
# not support PIL/pillow (python imaging library)!

# Modified 2024/10/12 by Jim Harris to allow for signal capture
# and a graceful shutdown

import os
import signal
import sys
from threading import Condition, Thread, Event
import time
import subprocess
from board import SCL, SDA, D4
import busio
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1305

# check if it's ran with Python3
assert sys.version_info[0:1] == (3,)

# for triggering the shutdown procedure when a signal is detected
keyboard_trigger = Event()
def signal_handler(signal, frame):
print('\nSignal detected. Stopping threads.')
keyboard_trigger.set()

# registering both types of signals
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

# Get PID of this running script
pid = os.getpid()

# Define the Reset Pin
oled_reset = digitalio.DigitalInOut(D4)

# Create the I2C interface.
i2c = busio.I2C(SCL, SDA)

# Create the SSD1305 OLED class.
# The first two parameters are the pixel width and pixel height.  Change these
# to the right size for your display!
disp = adafruit_ssd1305.SSD1305_I2C(128, 32, i2c, reset=oled_reset)

# Clear display.
disp.fill(0)
disp.show()

# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new("1", (width, height))

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=0)

# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height - padding
# Move left to right keeping track of the current x position for drawing shapes.
x = 0

# Load default font.
#font = ImageFont.load_default()

# Alternatively load a TTF font.   Make sure the .ttf font file is in the
# same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 9)
print("Started system statistics printout as PID", pid)

# Main drawing routine
#while True:
while not keyboard_trigger.is_set():
# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=0)

# Shell scripts for system monitoring from here:
# https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-load
cmd = "hostname -I | cut -d' ' -f1"
IP = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'"
CPU = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%s MB  %.2f%%\", $3,$2,$3*100/$2 }'"
MemUsage = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = 'df -h | awk \'$NF=="/"{printf "Disk: %d/%d GB  %s", $3,$2,$5}\''
Disk = subprocess.check_output(cmd, shell=True).decode("utf-8")

# Write four lines of text.

draw.text((x, top + 0), "IP: " + IP, font=font, fill=255)
draw.text((x, top + 8), CPU, font=font, fill=255)
draw.text((x, top + 16), MemUsage, font=font, fill=255)
draw.text((x, top + 25), Disk, font=font, fill=255)

# Display image.
disp.image(image)
disp.show()
time.sleep(0.1)

# until some keyboard event is detected
print("\nA keyboard event was detected.")
print("Clearing and shutting down display")

# Clear display.
disp.fill(0)
disp.show()
sys.exit(0)
Случай 1: Запуск изнутри Thonny

Запуск изнутри Thonny всегда приводит к следующему выводу внутри Окно терминала Тонни (REPL).

Код: Выделить всё

Python 3.7.3 (/usr/bin/python3)
>>> %cd /home/pi/startup_scripts
>>> %Run Stats.py
Started system statistics printout as PID 24225

Signal detected. Stopping threads.

A keyboard event was detected.
Clearing and shutting down display

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.3 (/usr/bin/python3)
>>>
Каждый раз сценарий отвечает на CTL-C полным завершением работы и очисткой дисплея, что является желаемым и ожидаемым поведением.
Случай 2: Запуск в окне терминала.

При запуске в терминале я получаю следующее:
Попытка 1: Отправка явного сигнала уничтожения из другое окно терминала:

Код: Выделить всё

pi@Adafruit128x32:~/startup_scripts $ ./Stats.py
Started system statistics printout as PID 15893

Signal detected. Stopping threads.

A keyboard event was detected.
Clearing and shutting down display
pi@Adafruit128x32:~/startup_scripts $
Это происходило каждый раз, когда я «убивал» процесс через другой терминал.
Попытка 2: завершение в работающем окне терминала с помощью CTL-C
Попытка 1:

Код: Выделить всё

pi@Adafruit128x32:~/startup_scripts $ ./Stats.py
Started system statistics printout as PID 16921
^C
Signal detected. Stopping threads.

A keyboard event was detected.
Clearing and shutting down display
pi@Adafruit128x32:~/startup_scripts $
Попытка 2:

Код: Выделить всё

pi@Adafruit128x32:~/startup_scripts $ ./Stats.py
Started system statistics printout as PID 17587
^C
Signal detected. Stopping threads.
Traceback (most recent call last):
File "./Stats.py", line 104, in 
Disk = subprocess.check_output(cmd, shell=True).decode("utf-8")
File "/usr/lib/python3.7/subprocess.py", line 395, in check_output
**kwargs).stdout
File "/usr/lib/python3.7/subprocess.py", line 487, in run
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'df -h | awk '$NF=="/"{printf "Disk: %d/%d GB  %s", $3,$2,$5}'' died with .
pi@Adafruit128x32:~/startup_scripts $
Здесь у меня возникло необработанное исключение, и это наиболее распространенный результат. (попытка, где это сработало, на самом деле была для меня неожиданностью.)
Я подозреваю, что происходит то, что выполняются другие фрагменты библиотечного кода, которые улавливают сигнал клавиатуры CTL-C, и «куски библиотечного кода» не передают исключение «вверх по лестнице» процессу, в котором я обрабатываю ошибку.
Вопрос:
  • Почему это происходит?
  • Есть ли способ гарантировать, что мой код захватывает сигнал клавиатуры, чтобы его можно было завершить без проблем, без необработанных исключений, которые обычно случаются?


Подробнее здесь: https://stackoverflow.com/questions/790 ... trl-c-prop
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»