Практикум · сборка проектаРабота 2
03 / 02 Самостоятельная работа

Разделите один файл на модули

Программа работает, но весь код лежит в одном файле: строки, числа, даты и проверка данных вперемешку. Задача — разложить функции по модулям и папкам, не меняя их тел.

Результат работыОдин main.py → четыре модуля и точка запуска
Для работы вместе с преподавателем

Что в архиве

Text Kit — набор небольших функций, которые пригождаются почти в любой программе: убрать лишние пробелы, сделать инициалы, посчитать среднее и медиану, проверить почту и телефон, прочитать дату из строки. Всего шестнадцать функций, и все они лежат в одном файле main.py.

Рядом лежит папка tests с четырьмя файлами проверок. Сейчас тесты не проходят: они написаны под структуру, которой ещё нет.

↓Скачать работу 2ZIP · main.py, четыре файла тестов и задание

Сначала запустите программу как есть: python main.py. Запомните вывод — после разделения он должен остаться прежним. Полный текст задания лежит в архиве в файле ЗАДАНИЕ.md; его же можно скачать отдельно.

Куда какие функции

Где должна оказаться функция, написано в тестах. Первая строка каждого файла проверок — это импорт, а импорт повторяет путь к файлу.

tests/test_statistics.py
from app.services.statistics import average, count_values, median, spread

Строка означает: четыре функции расчётов лежат в файле app/services/statistics.py. Так же читаются остальные три файла тестов. Всего получается четыре модуля:

ТемаФункции
строкиclean_spaces, shorten, initials, slug
датыparse_date, format_date, is_weekend, days_between
расчёты по числамaverage, median, spread, count_values
проверка данныхis_email, normalize_phone, is_phone, password_problems

Строки и даты — мелкие функции, которые можно перенести в другой проект без изменений: они идут в app/utils/. Расчёты и проверка данных — правила именно этого проекта: они идут в app/services/. Это то же деление, что и в первой работе.

Порядок работы

Выполните в своей папке
Где
Новая папка text-kit.
Действие
Перенести функции из main.py в четыре модуля, оставив в точке запуска только запуск.
Результат
app/utils/, app/services/, app/main.py и прежний вывод программы.
Проверка
Девятнадцать тестов проходят, вывод программы не изменился.
  1. Создайте дерево. Папки app, app/utils, app/services и пустой __init__.py в каждой из них. Папку tests оставьте на месте.
  2. Перенесите функции по темам. Тело каждой функции переносится как есть: менять код не нужно.
  3. Оставьте в каждом модуле только нужные импорты. Строка from datetime import date нужна только модулю дат.
  4. Найдите связь между модулями. Одна функция проверки данных пользуется функцией из модуля строк. Допишите импорт в том модуле, который её вызывает.
  5. Соберите точку запуска. main.py переезжает в app/ и оставляет себе константы с примерами данных, функцию main и строку if __name__ == "__main__":. Всё остальное он импортирует.
  6. Запустите и проверьте. Обе команды выполняются из корня проекта.
  7. Напишите README. Назначение программы, дерево проекта, команды запуска, ожидаемый вывод и признак, по которому функции разделены на четыре модуля.
ТЕРМИНАЛ · text-kit/
python -m app.main
python -m unittest discover -s tests -v
КРИТЕРИЙ ГОТОВНОСТИ
Вывод программы совпадает с выводом исходного main.py

Ran 19 tests ...
OK

Как переносить функцию

Перенос одной функции состоит из трёх действий: вырезать её из main.py, вставить в нужный модуль, дописать импорт там, где она вызывается. Пока функция вызывается только из main, импорт нужен один.

app/main.py
from app.services.statistics import average, count_values, median, spread
from app.utils.text import clean_spaces, initials, shorten, slug

Переносите функции по одной теме за раз и после каждой темы запускайте тесты этой темы:

ТЕРМИНАЛ · text-kit/
python -m unittest tests.test_text -v

Тогда ошибка относится к одному модулю и находится сразу.

Если не работает

ImportError: cannot import name

Функция лежит не в том файле, которого ждёт тест, либо в имени функции есть опечатка. Сверьте имя в импорте и имя после def.

NameError: name 'clean_spaces' is not defined

Функция вызывается из другого модуля, а импорт не дописан. Модуль видит только то, что определено в нём самом или импортировано в него.

ModuleNotFoundError: No module named 'app'

Команда запускается не из корня проекта или в папке нет файла __init__.py.

Программа ничего не печатает

В app/main.py потерялась строка if __name__ == "__main__": с вызовом main(). Без неё функция определена, но не вызвана.

Тесты проходят, но остался старый main.py в корне

Исходный файл после переноса удаляется: иначе в проекте остаются две копии одного кода.

Сверка после собственной попытки

Показать готовое дерево

text-kit/
├ README.md
├ app/
│ ├ __init__.py
│ ├ main.py
│ ├ services/
│ │ ├ __init__.py
│ │ ├ statistics.py
│ │ └ validation.py
│ └ utils/
│   ├ __init__.py
│   ├ dates.py
│   └ text.py
└ tests/

Связь между модулями одна: validation.py импортирует clean_spaces из utils/text.py.

↓Скачать эталонZIP · четыре модуля, точка запуска, README и тесты

Что сдать

Папку text-kit в вашем репозитории дисциплины. В README.md — раздел о том, по какому признаку функции разделены на четыре модуля.

Баллы: раскладка функций по модулям — 3, запуск с прежним выводом — 3, тесты — 2, README — 2. Всего 10.