Сводный текст домашних заданий

План

  • Доделать задачу и опубликовать её по стандартным правилам

  • При публикации следовать рекомендациям оформления commit message

План

Для решения задач заводите виртуальные окружения с помощью pipenv в каждом отдельном каталоге с решениями (1, 2 и т п.)

  • <!> Задача_1: напишите программу, реализующую простейший multi-user dungeon (по ходу практикума, MUD будет усложняться)

    • имеется поле 10х10 клеток; рисовать поле и его наполнение - не нужно
      • по каждой оси нумерация с 0 по 9
      • первая координата задает координату по горизонтали, вторая - по вертикали
      • клетка (0, 0) находится в левом верхнем углу поля (важно для навигации)
    • в каждой клетке может либо быть пусто, либо находиться один монстр
    • по полю ходит игрок; когда он попадает на клетку с монстром, случается "происшествие" (encounter)
    • в начале игры игрок появляется в клетке (0, 0)
    • настройка поля и игровой процесс организованы при помощи командной строки
    • должен поддерживаться не только интерактивный режим (с консольным вводом), но и режим с получением команд из текстового файла (перенаправление ввода при помощи "<") - это нужно для автотестирования

    • начальная версия командного языка:
      • up, down, left, right

        • перемещение по полю на одну клетку в выбранном направлении
        • если игрок переходит через границу поля, он появляется у противоположной границы (например, left в позиции (0, 5) переводит в позицию (9, 5))

        • при выполнении команды выводится: "Moved to (<x>, <y>)", где <x>, <y> - координаты клетки, куда попал игрок

        • если игрок попал в клетку с монстром, случается "происшествие", логика которого описана ниже
      • addmon <x> <y> <hello>

        • добавление в клетку (x, y) монстра, при встрече говорящего слово-приветствие, заданное в <hello> (достаточно поддерживать слова без пробелов)

        • если в этой клетке уже есть монстр, новый монстр его заменяет (пока это сводится к замене слова-приветствия)
        • если в этой клетке находится игрок, происшествие при добавлении монстра не случается
        • при выполнении команды выводится: "Added monster to (<x>, <y>) saying <hello>"; если монстр заменяется, также выводится, с новой строки, "Replaced the old monster"

      • при вводе неверной команды должно выводиться "Invalid command"
      • при вводе команды с неверными аргументами должно выводиться "Invalid arguments", фанатично проверять корректность аргументов НЕ нужно
    • отработка происшествия (т.е. попадания игрока на клетку с монстром):
      • происшествие должно отрабатываться в функции encounter(x,y), вызываемой после вывода "Moved to ..."

      • вывести текстового монстра, произносящего слово-приветствие
      • для формирования монстра, говорящего текст, используется функция cowsay(text) из модуля python-cowsay

        • этот модуль нужно поставить в окружение с помощью pipenv install

        • для начала все монстры будут выглядеть как default'ная корова из cowsay
  • <!> Задача_2: добавьте в MUD (на параллельной ветке в git) поддержку именованных монстров, при этом пользуйтесь редактированием истории на ветке

    • Скопируйте решение Задачи_1.

    • новая функциональность (её нужно разбить на коммиты, как сказано ниже!):
      • поддержка команды addmon <name> <x> <y> <hello> , где <name> это имя монстра (строка без пробелов)

        • старый (без имени) формат команды больше не должен поддерживаться
      • для клетки (x, y) должно запоминаться имя монстра, в дополнение к строке-приветствию
      • строка, выводимая при успешном добавлении монстра, должна выглядеть так: "Added monster <name> to (<x>, <y>) saying <hello>"

      • когда игрок попадает на клетку с монстром, в функции encounter() должно выводиться существо из коллекции модуля python-cowsay, произносящее приветствие (использовать функцию cowsay(message,cow=name))

      • при выполнении команды addmon должно проверяться, что <name> это имя одного из "штатных" существ, доступных в python-cowsay (список имен см. list_cows). Если проверка неуспешна, добавление монстра не выполняется, и выводится "Cannot add unknown monster".

    • занесите новую функциональность на ветку namedmonster (создание ветки: git checkout -b) в виде следующих коммитов, именно в таком порядке:

      • а) доработка разбора и обработки команды addmon <x> <y> <name> <hello>, кроме проверки того, что <name> - имя "штатного" существа

        • порядок аргументов перепутан специально, чтобы потом редактировать историю
      • б) добавление передачи имени монстра в вызов cowsay() из функции encounter()

      • в) добавление в обработку команды addmon проверки того, что <name> - имя "штатного" существа

    • каждый коммит нужно выполнять после отладки соответствующей функциональности, удалив отладочный код; разработали+отладили а) => занесли а), потом переходим к б), и т.п.

    • отредактируйте историю (git rebase -i) на ветке namedmonster:

      • в коммите а) замените в разборе addmon порядок аргументов команды на правильный (опция edit)

      • переставьте местами коммиты б) и в)
      • содержание коммитов в истории удобно контролировать при помощи команды git log --patch

    • ещё раз отредактируйте историю на ветке namedmonster:

      • объедините коммиты а) и в)
    • FIXME: нужен ли merge на основную ветку, и если да, то когда? На занятии про merge?

План

<!> Задача_1: работа с ветками в git при разработке программы

  • В решении Задачи_2 с предыдущего занятия сделайте merge ветки namedmonster на ветку work

  • Скопируйте решение Задачи_2 с предыдущего занятия. Сделайте коммит. Далее этот коммит будет обозначаться как {1}

  • Продолжите историю на ветке work:

    • Реализуйте вывод, при старте программы, строки-приветствия "<<< Welcome to Python-MUD 0.1 >>>"

    • Сохраните вывод строки-приветствия в виде одного коммита
  • Создайте ветку shlex_parse на базе коммита {1} и переключитесь на неё (проверьте!)

  • Реализуйте на ветке shlex_parse:

    • разбор команд MUD при помощи shlex вместо ранее реализованного разбора

    • поддержку команды addmon с синтаксисом (взамен прежнего синтаксиса): addmon <monster_name> hello <hello_string> hp <hitpoints> coords <x> <y>, где:

      • hello, hp, coords - имена параметров команды, все параметры обязательные

      • <hello_string> - строка приветствия, которую "произносит" монстр при встрече; может быть строкой с пробелами, заключенной в кавычки

      • <hitpoints> - положительное целое, задающее количество очков здоровья монстра (должно запоминаться вместе с именем монстра и строкой приветствия)

      • <x>, <y> - координаты монстра

      • порядок следования именованных параметров произвольный, например: addmon dragon hp 999 coords 6 9 hello "Who goes there?"

    • разбиение на коммиты - на ваше усмотрение, но коммитов на ветке должно быть не менее двух
  • Посмотрите структуру веток в qgit

  • Сделайте merge ветки shlex_parse на ветку work

  • Посмотрите структуру веток в qgit; обратите внимание на merge-коммит и на порядок следования коммитов в "суммарной" истории до merge-коммита

  • Создайте ветку custom_monster на базе коммита {1} и переключитесь на неё (проверьте!)

  • Реализуйте на ветке custom_monster поддержку нового монстра

    • монстр выглядит так: (пожалуйста, не удаляйте инициалы jgs - это условие использования, заданное автором Joan G. Stark)

          ,_                    _,
          ) '-._  ,_    _,  _.-' (
          )  _.-'.|\\--//|.'-._  (
           )'   .'\/o\/o\/'.   `(
            ) .' . \====/ . '. (
             )  / <<    >> \  (
              '-._/``  ``\_.-'
        jgs     __\\'--'//__
               (((""`  `"")))
    • поддержка монстра реализуется при помощи read_dot_cow(), см. пример на https://pypi.org/project/python-cowsay/

    • имя монстра "jgsbat"

    • должна быть реализована поддержка добавления этого монстра на игровое поле по команде addmon, с указанием имени монстра (наравне со "стандартными" персонажами python-cowsay)

  • Добавьте историю (rebase) ветки custom_monster на ветку work (где к этому шагу будет merge-коммит)

  • Внимание! в результате именно ветка work должна вобрать в себя все коммиты (т.е. команда должна быть git rebase custom_monster work)

  • посмотрите структуру веток в qgit

План

<!> Задача_1: переход на cmd, разработка на ветке с конфликтом объединения

  • Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит.

  • Продолжите историю на ветке work:

  • Реорганизуйте уже имеющиеся команды с помощью cmd и do_команда()

    • При этом "из коробки" приедет автодополнение частично введенного имени команды по нажатию TAB
    • Решение оформить в виде серии коммитов
  • Реализуйте поддержку базовой команды attack (без параметров). Обработка команды:

    • Если в позиции, где находится игрок, нет монстра, вывести "No monster here" и завершить обработку команды

    • Атака наносит урон монстру в 10 очков здоровья, если у монстра не менее 10 о.з., в противном случае урон равен количеству о.з. монстра
    • Вывести: "Attacked <имя монстра>,  damage <урон> hp", где <имя монстра> - имя монстра в одной позиции с игроком (таких монстров ровно один), <урон> - число списанных о.з.

    • После корректировки здоровья монстра (как принято говорить, "отрицательного выздоровления") вывести:
      • если о.з. монстра равны 0: "<имя монстра> died"

      • в противном случае: "<имя монстра> now has <очки здоровья>", где <очки здоровья> - количество оставшихся о.з. у монстра

    • Если у монстра 0 о.з., удалить монстра с позиции
  • Далее последний коммит в реализации базовой команды attack обозначен как {1}

  • Создайте ветку weapon_name на базе коммита {1} и переключитесь на неё (проверьте!)

  • Реализуйте на ветке weapon_name атаку разными видами оружия, с указанием оружия в параметре with команды attack

    • синтаксис команды: attack with <имя оружия>

    • варианты для <имя оружия>: sword, spear, axe; наносимый урон, соответственно: 10, 15, 20

      • при указании неизвестного оружия выводить: "Unknown weapon", и завершать обработку команды

    • параметр with необязательный, значение по умолчанию: sword

    • для имени оружия должно работать автодополнение, а также пролистывание имен через TAB (используйте complete_команда())

    • если имя оружия указано правильно, продолжать обработку как для базовой команды attack, но с соответствующим оружию значением урона

  • Создайте ветку attack_by_name на базе коммита {1} и переключитесь на неё (проверьте!)

  • Реализуйте на ветке attack_by_name атаку с обязательным указанием имени монстра

    • синтаксис команды: attack <имя монстра>

    • если монстра с данным именем нет в позиции, где находится игрок, вывести "No <имя монстра> here" и завершить обработку команды

    • в противном случае (т.е. монстр с данным именем есть), продолжить обработку как для базовой команды attack

    • для имени монстра должно работать автодополнение, а также пролистывание имен через TAB (используйте complete_команда()); пролистываться должны имена ДОСТУПНЫХ В ИГРЕ монстров, т.е. тех, которые могут быть добавлены через команду addmon

  • сделайте merge ветки weapon_name на ветку work, он будет бесконфликтным (т.к. на work история не продвинулась дальше {1} )

  • сделайте merge ветки attack_by_name на ветку work, при этом разрешите конфликты из-за разных доработок команды attack

    • в результате должна появиться поддержка команды с синтаксисом "attack <имя монстра> with <имя оружия>", с поддержкой автодополнения и пролистывания как по имени монстра, так и по имени оружия

План

<!> Задача_1. MUD в формате клиент-сервер (однопользовательский), оформление изменений в виде патчсета.

  • Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит. Далее этот коммит будет обозначаться {1}

  • Продолжите историю на ветке work

  • Переведите монолитную реализацию MUD на схему "клиент+сервер" (однопользовательскую)
    • клиент отвечает за:
      • получение команд от пользователя, их разбор, проверку корректности (включая вывод сообщений о некорректных командах)
      • вывод информации, полученной от сервера
      • т.е. по сути клиент не имеет состояния
    • сервер работает по принципу echo-сервера, воспринимающего строки вида команда параметры

    • сервер отвечает за хранение и модификацию состояния игры, включая:
      • позицию игрока
      • расположение монстров, их типы и количество очков здоровья (о.з.)
    • организация протокола клиент->сервер:

      • по протоколу передаются только команды с гарантированно корректными параметрами; сервер не занимается их перепроверкой (в жизни - не так :) )

      • набор команд протокола следует сделать более простым, чем набор пользовательских команд:
        • не нужны опциональные параметры; если пользователь опустил опциональный параметр, клиентом в команду для сервера подставляется значение по умолчанию
        • можно все параметры сделать позиционными
        • однотипные команды можно объединять в одну, с различением по параметрам: например, единственная команда перемещения с указанием приращения по каждой координате (вместо up: move 0 -1, вместо right: move 1 0)

        • в целом, клиент выполняет "частичное переваривание" пользовательского ввода и передает серверу упрощенный и гарантированно корректный результат
    • организация протокола сервер->клиент:

      • сервер возвращает только те данные, которые нужны клиенту для вывода
      • сервер отвечает на каждую команду клиента без каких-либо задержек
      • клиент вправе ждать ответа сервера на отправленную команду, и возвращаться к приёму пользовательских команд только после получения ответа
    • по сути, параллелизма в работе клиента и сервера НЕТ
    • важные частные случаи:
      • "энкаунтер" (т.е. перемещение игрока в позицию с монстром): на сервер поступает команда перемещения, в ответ сервер шлёт имя монстра и его приветственный текст; рендерингом с помощью cowsay занимается клиент

      • атака: на сервер шлётся имя монстра и количество о.з., соответствующее выбранному оружию; сервер отвечает - либо что монстра с таким именем в позиции нет; либо (если монстр есть), то количеством списанных о.з. и количеством оставшихся о.з. (если второе равно 0, значит монстр убит)
    • ДИСКЛЕЙМЕР: вышесказанное - не готовый проект протокола, а намёки на то, как его имеет смысл построить!
  • оформите реализацию в виде набора коммитов на ветке work, желательно не менее 3 коммитов

  • сформируйте по этому набору коммитов патчсет:
    • создайте подкаталог patchdir

    • при помощи команды git format-patch с ключом --output-directory создайте в подкаталоге patchdir патчсет, включающий все коммиты, реализующие клиент-серверную схему

    • закоммитьте файлы патчсета
  • примените патчсет:
    • скопируйте каталог patchdir в место, находящееся вне git-репозитория (далее путь к этому месту обозначен как path_to_patchdir)

    • создайте ветку apply_patch от коммита {1} , переключитесь на неё (проверьте!)

    • при помощи команды git am path_to_patchdir/patchdir/* примените патчсет

  • проверка: посмотрите структуру веток при помощи gitk; на ветках work и apply_patch должны быть одинаковые наборы коммитов

План

  • <!> Задача_1. Многопользовательский MUD (multiuser multiuser dungeon)

    • Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит. Работайте на ветке work.

    • Сделайте (наконец-то!) MUD многопользовательским. Подробности ниже.
    • Многосессионность (поддержку работы с одним сервером одновременно нескольких клиентов) реализуйте по схеме "коровьего чата" из лекций.
    • Именованные сеансы:
      • При подключении клиента к серверу, клиент передаёт серверу имя пользователя (строка без пробелов, поступает клиенту при запуске - python mymud.py username).

      • Сервер проверяет, что подключенного пользователя с таким именем ещё нет; если есть - отказывает в подключении; если нет, то создает подключение (сообщая об этом клиенту) и запоминает имя пользователя.
    • Асинхронность работы клиента с сервером:
      • после отправки сообщения серверу, клиент НЕ ждёт ответа от сервера
      • все сообщения от сервера клиенту _после_ успешного подключения - "асинхронные", т.е. принимаются параллельно работе пользователя с командной строкой
      • все сообщения от сервера клиенту предназначены ДЛЯ ВЫВОДА "as is", никакого разбора в духе "набор параметров от сервера к клиенту" теперь не нужно; т.е. клиент отправляет команды на сервер без ожидания ответа и без "понимания", что сообщения от сервера приходят в ответ на конкретные команды
      • схема параллельного ожидания сообщений и обработки пользовательского ввода - см. лекцию (раздел "Cmd и асинхронные сообщения")

      • важно: после получения от сервера (и вывода) сообщения, клиент должен показать командную строку с набранным (но не введённым) пользователем текстом, чтобы результат ввода не исчезал (опять см. лекцию)
    • Частичная неделимость обработки пользовательской команды на сервере (для ограничения гонок):
      • помним, что сервер последовательный
      • получив команду от клиента, сервер обрабатывает её сразу (а не планирует обработку через async)
      • отправку сообщения клиенту (клиентам) сервер осуществляет асинхронно
    • Широковещательные сообщения от сервера клиентам:
      • сообщения о "знаковых событиях" сервер рассылает всем клиентам, в духе коровьего чата (где он транслирует всем клиентам полученное от клиента сообщение)
      • знаковые события:
        • атака на монстра (сообщать: кто атаковал (имя пользователя), чем, какого монстра, сколько очков здоровья снёс, сколько о.з. осталось; если монстр убит, то сообщить об этом [чтобы клиентам не пришлось выпарсивать число о.з.]) сколько включая результат)
        • установка монстра (кто поставил, имя монстра, кол-во о.з.)
        • заход пользователя (в т.ч. сообщить имя) в MUD
        • прекращения сеанса пользователя в MUD (тоже с указанием имени)
      • есть и не-широковещательные сообщения, например приветствие от встреченного монстра поступает одному конкретному пользователю
    • Прямого взаимодействия между пользователями нет
    • Возможны логические гонки: например, два пользователя более-менее одновременно отправили команду атаки на одного и того же монстра, "первый" убил монстра, а второму пришло индивидуальное сообщение о том, что монстра нет. Это терпимо.

План

Пример репозитория, соответствующего требованиям

  1. <!> Задача_1: MUD messaging

    • Скопируйте решение Задачи_1 с предыдущего занятия. Сделайте коммит. Работайте на ветке work.

    • Задайтесь вопросом: если MUD теперь многопользовательский, как пользователи (приключенцы) будут кооперироваться, чтобы вынести особо крутого монстра?
      • Спойлер: нужен чат
    • Реализуйте команду для передачи сообщения всем игрокам
      • Синтаксис: sayall <строка>, где <строка> - либо одно слово (без пробельных символов), либо строка в кавычках

      • Примеры:
        • sayall PREVED

        • sayall "Let's attack dragon at 5 9"

      • Сервер транслирует строку всем с указанием имени пользователя-источника. Пример: kobold702: Let's attack dragon at 5 9

  2. <!> Задача_2: MUDуляризация, применение flake8 и pydocstyle

    • Скопируйте решение Задачи_1. Сделайте коммит. Работайте на ветке work.

    • Оформите MUD в виде двух пакетов: клиент (moodclient), сервер (moodserver)

      • В силу cowsay-ориентированности, наш MUD обрёл официальное название - MOOD
    • Запуск для пакета — в __main__.py

    • Добейтесь полного отсутствия претензий со стороны flake8 и pydocstyle к содержимому пакетов

      • Разрешается настраивать ☺

План

<!> Задача_1. Бродячие монстры и Сфинкс

  • Скопировать решение Задачи_2 (где выделяются два модуля) с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • Добавить sphinx в pipenv

  • Добавить на сервере MUD поддержку бродячих монстров:
    • один раз в 30 секунд выбирается случайный монстр, и он перемещается на одну клетку в случайно выбранном направлении (вправо/влево/вверх/вниз; помним, что поле "закольцовано")
    • если в результате перемещения монстр попал бы на клетку, где уже есть монстр, то перемещение НЕ ПРОИСХОДИТ, и проводится повторный выбор монстра и направления; и так пока не будет выполнено успешное перемещение монстра
    • при перемещении сервер выдаёт всем игрокам сообщение "<имя_монстра> moved one cell <направление>", где <направление> это right, left, up, down. Например: "manticore moved one cell right"

    • если монстр попадает на клетку, где есть игрок (или игроки), происходит "энкаунтер" - как если бы игрок(и) сам зашел(ли) на клетку с монстром
      • в т.ч. монстр отрисовывается у столкнувшихся с ним игроков, с произнесением приветственной фразы
  • Для модуля-сервера задокументировать все функции, классы и модуль в формате autodoc
  • Добиться выгонки технической документации по этим классам/функциям/модулю
    • Следить за тем, чтобы генераты (html-документация) не хранились в git (.gitignore), а настойки shpinx — хранились

  • Оформить титульный лист документации (как минимум, скопипастить туда формулировку задачи)
  • Сделать в титульном листе ссылку на техническую документацию

План

<!> Задача_0. Доделать упражнения по русификации, т.к. они будут использоваться в упражнениях на занятии по автоматизации.

<!> Задача_1. Локализация сообщений на стороне сервера.

  • Почему на стороне сервера?
    • на сервере формируются сообщения, включающие числовые значения и соответствующие им слова в множественном числе
    • протокол от сервера к клиенту строится на сообщениях, НЕ ПОДЛЕЖАЩИХ интерпретации клиентом (т.е. они только выводятся клиентом в терминал), а значит числовые значения как отдельные параметры в нём передать невозможно
    • поскольку вариантов множественного числа в русском языке больше, чем в английском, полноценная русификация множественного числа на клиенте БЕЗ ЗНАНИЯ числового значения тоже невозможна (нельзя просто взять и перевести "points" как "очков", потому что "два очка")
  • Скопировать решение Задачи_1 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • добавить в клиент поддержку команды locale <имя_локали> (просто распознавание и передача на сервер)

  • добавить в сервер поддержку работы с локалями:
    • запоминание, для каждого клиента В ОТДЕЛЬНОСТИ, заданной клиентом локали
    • поддержка через babel перевода сообщений для единственной (у нас учебная задача) локали ru_RU.UTF8

    • отправка на клиент локализованных сообщений: если для установленной этим клиентом локали есть перевод, то отправляем переведенные сообщения, иначе - исходные сообщения: "Поскольку для каждого клиента отдельная корутина, локаль клиента — это просто переменная в ней. Надо просто не забывать каждый раз при отправки сообщеньки выставлять эту локаль" (с)
    • большинство сообщений от сервера клиенту - широковещательные (т.е. ко всем клиентам), и каждому клиенту это сообщение нужно отправлять с учетом выставленной ЭТИМ клиентом локали.
  • какие сообщения сервера нужно локализовывать:
    • реакция сервера на установку локали (сообщение только тому клиенту, который подал команду locale):

      • исходное: "Set up locale: <имя_локали>"

      • рус. локаль: "Установлена локаль: <имя_локали>"

    • сообщения о знаковых событиях: атака на монстра, установка монстра, заход пользователя, прекращение сеанса пользователя
      • подробности о знаковых событиях см. https://uneex.ru/LecturesCMC/PythonDevelopment2023/Prac/06_SocialProject

      • количество очков здоровья у монстра (имеющихся при установке, снятых при атаке, оставшихся после атаки) должно локализовываться с правильным применением множественного числа (1 очко / 2 очка / ... 5 очков / ... 21 очко и т.п.), то есть в файле локализации нужно задействовать формулу выбора множественного числа.
  • добавьте файлы локализации сервера в его модуль, проверьте что после установки модуля локализация "подхватывается" (при выставлении клиентом локали ru_RU.UTF8 этому клиенту выдаются русифицированные сообщения)

План

<!> Задача_1. Тестирование отработки сервером команд от клиента (проверяется связка клиент+сервер)

  • Скопировать решение Задачи_1 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • написать набор тестов для отработки сервером команд от клиента, организованный следующим образом:
  • setup: запуск сервера на локальном хосте, установка соединения

    • FIXME do not use subprocess пример запуска: proc = multiprocessing.Process(target=lambda: subprocess.run([sys.executable, 'server.py']))

  • teardown: закрытие соединения, прерывание работы сервера (proc.terminate())

  • каждый тест запускается на клиенте и имеет вид: <отправка команды; ожидание и проверка ответа>; команда - фиксированное сообщение в формате протокола клиент->сервер

  • проверяются команды:
    • установка монстра (недалеко от начального положения игрока)
    • подход к монстру; ожидаемый ответ: "появление" монстра и произнесение им приветствия
    • атака на монстра

<!> Задача_2. Тестирование клиента с использованем мокеров

  • Скопировать решение Задачи_1 с предыдущего занятия (не с этого; не будем смешивать два формата тестирования). Сделать коммит. Работать на ветке work.

  • написать набор тестов для преобразования клиентом команд из формата пользовательского ввода в формат протокола клиент->сервер

  • сервер не запускается, работает только клиент
  • для пользовательского ввода и для отправки сообщений к серверу используются мокеры (так можно протестировать всю цепочку действий от ввода до отправки)
    • мокер пользовательского ввода при последовательных обращениях возвращает заданную последовательность пользовательских команд
  • выбрать две команды, у каждой из которых формат пользовательского ввода НЕ совпадает с форматом протокола клиент->сервер

  • для каждой из этих команд протестировать преобразование правильной команды в формат протокола клиент->сервер (для двух разных значений параметров команды; если команда - движение, то для двух разных направлений)

  • хотя бы для одной команды протестировать обработку неправильно заданных параметров

План

<!> Задача_1. Автоматизация сборки для MUD.

  • Скопировать решение Задачи_1 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • реализовать цель i18n для полной генерации перевода

    • реализовать цели-шаги генерации перевода, как в описанном выше упражнении
    • цель i18n должна зависеть от этих целей-шагов

  • реализовать цель html для генерации html-документации

  • реализовать цель test для прогона тестов связки клиент+сервер (зависит от цели i18n, потому что проверяет русифицированные ответы сервера)

  • для каждой цели реализовать удаление генератов (использовать атрибут clean и функцию clean_targets; для удаления каталога с документацией использовать функцию shutil.rmtree)

  • цель по умолчанию: html

План

<!> Задача_1. Пакетирование для MUD

  • Скопировать решение Задачи_1 с предыдущего занятия. Сделать коммит. Работать на ветке work.

  • сделать описание пакетов для клиента и сервера, в формате setuptools

  • в пакете должно быть:
    • описание эксплуатационных зависимостей (cowsay-python и др. используемых пакетов)

    • описание сборочных зависимостей
    • описание собственно содержимого пакета:
      • для сервера - файл(ы) *.py, скомпилированный перевод, txt-файл с дополнительным монстром

      • для клиента - файл(ы) *.py

      • если в состав конкретной реализации входят ещё какие-то файлы, нужные для запуска, то и они
      • указание точки входа для генерации сценария (например, moodserver вместо python2 -m moodserver)

  • добавить в doit-файл цели для сборки пакетов:
    • whlserver: для сервера (зависит от цели-сборки перевода)

    • whlclient: для клиента

    • wheels: для обоих пакетов (зависит от обеих указанных выше целей)

    • файлы пакетов должны удаляться при очистке результатов сборки
  • проверить установку пакетов и запуск клиента и сервера:
    • в двух отдельных pipenv-окружениях

    • в едином pipenv-окружении

    • (в обоих случаях окружение создаётся заново)

План

(для преподавателей, на будущий год ☺):

  • pydocstyle / flake8 (просто забыли)
  • точки входа и скрипты

LecturesCMC/PythonDevelopment2023/Prac/MOOD (последним исправлял пользователь FrBrGeorge 2023-05-27 22:10:42)