Python: парсим аргументы командной строки
Сегодня разберемся с сабпарсерами объекта argparse.ArgumentParser
, которые передаются через параметр parents
.
В общем случае при попытке распарсить аргументы командной строки мы создаем объект и начинаем методично добавлять к нему все известные нам параметры.
Иногда можно встретить очень большие листинги. Но существует механизм, который позволяет разбивать парсеры на более мелкие составляющие и сцеплять их между собой для более простого понимания (кстати, очень полезно при создании системы плагинов).
При этом мы можем управлять тем, какие аргументы будут парсится.
Для этого в параметры parents
можно передать те объекты, от которых надо унаследоваться.
Рассмотрим на примерах.
В первом случае создается ArgumentParser
с одним аргументом. И он сразу же разбирает командную строку на известные параметры и хвост при помощи parse_known_args
.
В зависимости от значения -l
мы либо продолжим работу, либо остановимся.
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-l', '--list', help="List something", action='store_true')
args, remaining = parser.parse_known_args()
if args.list:
print('List')
exit(0)
parser = argparse.ArgumentParser(
description="Chained parsers",
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parser])
parser.add_argument('-t', '--test', help="Test", action='store_true')
other_args = parser.parse_args(remaining)
print('Args: {}'.format(other_args))
Второй пример чуть более сложный.
Допустим, что код обрабатывает видеофайлы и аудиофайлы. В зависимости от этого у него меняется поведение атрибута -r
.
import argparse
import enum
class Formats(enum.Enum):
VIDEO='video'
AUDIO='audio'
def __str__(self):
return self.value
def parser_common():
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
'-f', '--format', help="Specify format", type=Formats, choices=list(Formats)
)
return parser
def parser_video(parent_parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Video parser",
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parent_parser])
parser.add_argument(
'-r',
'--resolution',
help="Resolution",
type=int,
nargs=2,
metavar=('WIDTH', 'HEIGHT'),
required=True,
)
return parser
def parser_audio(parent_parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Audio parser",
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parent_parser])
parser.add_argument(
'-r',
'--resolution',
help="Audit resolution",
type=int,
required=True,
)
return parser
def main():
parser = parser_common()
args, remaining = parser.parse_known_args()
if args.format == Formats.AUDIO:
parser = parser_audio(parser)
elif args.format == Formats.VIDEO:
parser = parser_video(parser)
else:
parser.print_help()
exit(1)
other_args = parser.parse_args(remaining)
print(2)
print('Args: {}'.format(other_args))
if __name__ == '__main__':
main()
Запустите и посмотрите, как ведёт себя данный код.
$ python argsparser.py
usage: argsparser.py [-f {video,audio}]
options:
-f {video,audio}, --format {video,audio}
Specify format
$ python argsparser.py -f audio
usage: argsparser.py [-h] [-f {video,audio}] -r RESOLUTION
argsparser.py: error: the following arguments are required: -r/--resolution
$ python argsparser.py -f video
usage: argsparser.py [-h] [-f {video,audio}] -r WIDTH HEIGHT
argsparser.py: error: the following arguments are required: -r/--resolution
$ python argsparser.py -f video -h
usage: argsparser.py [-h] [-f {video,audio}] -r WIDTH HEIGHT
Video parser
options:
-h, --help show this help message and exit
-f {video,audio}, --format {video,audio}
Specify format
-r WIDTH HEIGHT, --resolution WIDTH HEIGHT
Resolution
$ python argsparser.py -f audio -h
usage: argsparser.py [-h] [-f {video,audio}] -r RESOLUTION
Audio parser
options:
-h, --help show this help message and exit
-f {video,audio}, --format {video,audio}
Specify format
-r RESOLUTION, --resolution RESOLUTION
Audit resolution
SDDM: Переключаем раскладку автоматически при блокировании экрана
Продолжаем разбираться с окном логина (sddm, gdm и прочие *dm).
В предудущей части мы научились переключать раскладку из консоли минуя кнопки и мышки.
А теперь мы научимся менять раскладку автоматически при блокировании экрана.
Зачем это нужно? Чаще всего пароль у нас на латинице. А заблокировать экран можно при любой включенной раскладке. Это приводит к тому, что на экране логина эту самую раскладку на до менать. Неудобно!
1. Определяем, когда система была заблокирована
#!/usr/bin/env bash
dbus-monitor --session "type='signal',interface='org.freedesktop.ScreenSaver'" |
while read x; do
case "$x" in
*"boolean true"*) echo SCREEN_LOCKED;;
*"boolean false"*) echo SCREEN_UNLOCKED;;
esac
done
Если запустить скрипт, заблокировать, а потом разблокировать экран, то мы увидим его работу.
SCREEN_LOCKED
SCREEN_LOCKED
SCREEN_UNLOCKED
SCREEN_UNLOCKED
Два сообщения из-за особенностей интерфейса. Можно привязываться к другому интерфейсу, но в данном случае это некритично.
2. Учимся запускать скрипт фоном через systemd
Делаем скрипт /.local/bin/set-layout-on-lock
. Не забывайте поставить на него `+x .
#!/usr/bin/env bash
dbus-monitor --session "type='signal',interface='org.freedesktop.ScreenSaver'" |
while read x; do
case "$x" in
*"boolean true"*) qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.setLayout 0;;
*"boolean false"*) echo SCREEN_UNLOCKED;;
esac
done
Создаём каталог для сервисов systemd.
$ mkdir -p ${HOME}/.config/systemd/user
Пишем сервис в ${HOME}/.config/systemd/user/set-kbd-layout-on-lock.service
.
[Unit]
Description=Set custom locale on screen lock
[Service]
Restart=always
ExecStart=%h/.local/bin/set-layout-on-lock
[Install]
WantedBy=graphical-session.target
%h
- означает директорию текущего пользователя.graphical-session.target
- означает, что сервис будет запускаться только с графическим интерфейсом (не нужен он нам в консоли).
3. Включаем
$ systemctl --user enable --now set-kbd-layout-on-lock
Сервис будет включен и тут же запущен.
Посмотреть состояние можно командой status
.
$ systemctl --user status set-kbd-layout-on-lock
Литература
KDE: Переключаем раскладку из консоли
Очень полезной штукой является возможность переключить раскладку из консоли.
Зачем? Например, при блокировании сеанса надо сделать так, чтобы раскладка стала английской.
Так как дистрибутивы очень сильно видоизменились и стали поставляться с wayland и производными systemd (keyboad, logind, …), то переключать стандартными линуксовыми средствами вроде setxkbmap, xkb-switch и прочими способами не получиться.
Теперь раскладка в дистрибутивах переключается при помощи dbus и сигналов.
Для kde это делается вызовом метода org.kde.KeyboardLayouts.setLayout
в сервисе org.kde.keyboard
.
$ qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.setLayout 1
Последний аргумент - это номер раскладки в списке.
Посмотреть список раскладок можно через другой метод.
$ qdbus --literal org.kde.keyboard /Layouts org.kde.KeyboardLayouts.getLayoutsList
[Argument: a(sss) {[Argument: (sss) "us", "", "Английская (США)"], [Argument: (sss) "ru", "", "Русская"]}]
Обязательный аргумент в нашем случае - это --literal
. Без него команда просто выведет сообщение о том, что не может отобразить нестандарный тип данных.
$ qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.getLayoutsList
qdbus: I don't know how to display an argument of type 'a(sss)', run with --literal.
Linux: Система засыпает при заблокированном сеансе
Gnome и Kde страдают тем, что на экране логина за электропитание отвечает не утилита управления электропитанием, а logind из состава systemd и настроить поведение компьютера в этом режиме в панелях управления нельзя.
Проблема наблюдается как в gdm, так и sddm.
Проявляется в следующих случаях:
- Включили машину, но не вошли в систему -> компьютер ушел в спячку
- Включили ноутбук с внешним монитором, поработали и заблокировали сеанс -> система ушла в спячку если закрыть крышку
Есть даже много отчетов об ошибках и информация от разработчиков о том, что это сделано “ради прохождения сертификации энергопотребления”.
Чтобы избежать засыпания системы после включения нужно сконфигурировать gdm отключив ему спячку (sddm, lxdm и т.п. работают нормально).
sudo -u gdm dbus-run-session gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0
Чтобы избежать проблемы засыпания ноутбука при закрытой крышке нужно дополнительно прописать настройки в /etc/systemd/login.conf.d/00-lid.conf
или же в /etc/systemd/login.conf
.
[Login]
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore
IDEA: Не работает превью для Markdown
Есть вероятность, что возможность смотреть превью markdown-файлов в соответствующем плагине отсутствует.
Скорее всего проблема в jdk и jfx, которые вы используете. Чаще всего используются те, что идут бандлом с самое ide.
Нужно поменять:
- идем в быстрый поиск (двойное нажатие shift)
- вбиваем choose boot java runtime for ide
- выбираем другую версию jdk c jcef
- плагин должен заработать корректно
- если не случилось - повторяем (можно использовать системный jre)