Поймать предупреждение в Python 2.7, не останавливая часть программы

В настоящее время я работаю над программой Python, которая включает вход в систему с именем пользователя и паролем. Для этого я использую модуль getpass. Моя проблема в том, что в случае, если getpass не может контролировать эхо, он выдает следующее в терминал, прежде чем продолжить работу с программой.

Warning (from warnings module):
  File "C:\Python27\lib\getpass.py", line 92
    return fallback_getpass(prompt, stream)
GetPassWarning: Can not control echo on the terminal.
Warning: Password input may be echoed.

Что я хотел бы сделать, так это поймать предупреждение и вместо этого напечатать свое собственное сообщение. Единственный код, который я могу придумать, это следующий, который предотвращает отображение трассировки, но вообще не печатает пользовательское сообщение.

import getpass

try:
    getpass.getpass("Password: ")
except getpass.GetPassWarning:
    print "Oh no!"

Выход:

Warning: Password input may be echoed.
Password: 

В идеале я хотел бы заменить текст Warning: Password input may be echoed. своим собственным сообщением.


person GarethPW    schedule 15.02.2016    source источник
comment
Этот вопрос: Как отключить предупреждения Python обсуждает, как подавить предупреждения, и содержит ссылку на документы для модуля warnings. . FWIW, вот исходный код Python для getpass.   -  person PM 2Ring    schedule 15.02.2016
comment
@ PM2Ring Позволяет ли это мне распечатать собственное сообщение перед подсказкой?   -  person GarethPW    schedule 15.02.2016
comment
Я так не думаю (но я никогда не использовал модуль warnings). Я думаю, вы могли бы заменить импортированный getpass.fallback_getpass своей собственной функцией, хотя такое исправление стандартных функций модуля действительно должно выполняться только в крайнем случае, ИМХО.   -  person PM 2Ring    schedule 15.02.2016


Ответы (2)


getpass использует встроенный модуль Python warnings для отображения этого предупреждающего сообщения. Вы можете фильтровать/игнорировать их, используя различные методы (Python Docs / PyMOTW).

Вы можете поймать предупреждение следующим образом:

import getpass
import warnings

# the context manager resets the original
# filterwarnings after it has exited
with warnings.catch_warnings():
    # this will raise warnings of type (or inherited of type)
    # 'getpass.GetPassWarning' in the module 'getpass'
    warnings.filterwarnings(
        'error',
        category=getpass.GetPassWarning,
        module='getpass'
    )
    try:
        password = getpass.getpass('Password: ')
    except getpass.GetPassWarning:
        print 'Cannot get password on insecure platform'
person Chive    schedule 15.02.2016
comment
К сожалению, кажется, что оба этих решения имеют тот же эффект, что и моя попытка. Трассировка заблокирована, но пользовательское сообщение не отображается. :/ - person GarethPW; 15.02.2016
comment
На самом деле я не смог воспроизвести GetPassWarning, во-первых, на какой платформе вы его получаете? - person Chive; 15.02.2016
comment
Я использую Python 2.7.11 в Windows 10. Проще всего воспроизвести в IDLE. - person GarethPW; 15.02.2016
comment
Я обновил код - у меня это работает как в Windows 10/py 2.7/IDLE, так и в OS X с py 2.7. - person Chive; 16.02.2016
comment
Теперь текст печатается успешно, но трассировка и текст Warning: ... все еще остаются. :/ - person GarethPW; 16.02.2016

Метод, предложенный @PM2Ring, кажется лучшим решением, которое я нашел до сих пор. Ради других, проходящих мимо и с целью ответа на вопрос, я завершу все в этом посте.

Следующий метод перезаписывает функцию fallback_getpass в модуле getpass, позволяя точно контролировать, что происходит в случае необходимости отката. Это немного очень хакерски, но выполняет свою работу.

import getpass

def custom_fallback(prompt="Password: ",stream=None): #Clone of parameters from getpass.fallback_getpass
    print "Custom message." #Custom message goes here
    return getpass._raw_input(prompt) #Use getpass' custom raw_input function for security

getpass.fallback_getpass = custom_fallback #Replace the getpass.fallback_getpass function with our equivalent

password = getpass.getpass("Password: ") #Prompt for password

Выход:

Custom message.
Password: 
person GarethPW    schedule 16.02.2016