2025, Dec 26 18:03

Баг в todo на Python: пропущен перевод строки, show склеивает записи

Почему в CLI‑todo на Python add/show склеивают записи и как это исправить: пропущен перевод строки. Решение простое — добавляйте \n при записи в файл.

Когда пишешь простое CLI‑приложение для списка дел на Python, легко забыть, что файлы устроены построчно. Стоит пропустить один перевод строки — и вывод команды «show» внезапно склеивает несколько записей. Именно это и происходит, когда добавляешь пункт вроде «add bro», а затем вызываешь «show»: последние два задания оказываются в одной строке, вместо того чтобы отображаться отдельными элементами.

Как воспроизвести проблему

Основной цикл читает и записывает задачи в обычный текстовый файл. Логика показа убирает символы перевода строки перед печатью, а вот ветка add добавляет новый пункт без завершающего переноса. В итоге две соседние записи могут «склеиться» в файле и, как следствие, в выводе.

while True:

    cmd_text = input("type add, show, edit, remove or exit ")
    cmd_text = cmd_text.strip()

    if 'add' in cmd_text:
        entry_text = cmd_text[4:]

        with open('todos.txt', 'r') as fh:
            items_list = fh.readlines()

        items_list.append(entry_text)

        with open('todos.txt', 'w') as fh:
            fh.writelines(items_list)

    elif 'show' in cmd_text:

        with open('todos.txt', 'r') as fh:
            items_list = fh.readlines()

        for pos, line_item in enumerate(items_list):
            line_item = line_item.strip("\n")
            pos = pos + 1
            line_out = f"{pos}-{line_item}"
            print(line_out)

    elif 'edit' in cmd_text:
        idx_num = int(cmd_text[5:])
        print(idx_num)
        idx_num = idx_num - 1

        with open('todos.txt', 'r') as fh:
            items_list = fh.readlines()

        updated_entry = input("Type the new todo:")
        items_list[idx_num] = updated_entry + "\n"

        with open('todos.txt', 'w') as fh:
            fh.writelines(items_list)

    elif 'remove' in cmd_text:
        idx_num = int(cmd_text[6:])
        with open('todos.txt', 'r') as fh:
            items_list = fh.readlines()
        pos = idx_num - 1
        removed_entry = items_list[pos].strip("\n")
        items_list.pop(pos)
        with open('todos.txt', 'w') as fh:
            fh.writelines(items_list)
        feedback = f"todo {removed_entry} was removed from the list"
        print(feedback)

    elif 'exit' in cmd_text:
        break
    else:
        print("Command is not valid ")

print("bye!")

Что именно ломается и почему

Ветка вывода удаляет завершающие переводы строк с помощью strip("\n"), чтобы элементы аккуратно смотрелись в консоли. Это нормально. Проблема в ветке add: она добавляет новую строку задачи без конца строки и затем перезаписывает весь список через writelines. Если у предыдущего последнего элемента уже не осталось перевода строки или у только что добавленного его нет, следующая запись поместит их в одну физическую строку. Так записи «hii» и «bro» превращаются в одну строку «hiibro», а последующие добавления продолжают сливаться.

Как исправить

Гарантируйте, что каждый новый пункт сохраняется с переводом строки. Больше ничего менять не нужно. Если при добавлении дописывать «\n», каждая задача окажется отдельной строкой в todos.txt. Ветка show по‑прежнему может убирать перевод строки для аккуратного вывода, а структура файла останется корректной.

if 'add' in cmd_text:
    entry_text = cmd_text[4:]

    with open('todos.txt', 'r') as fh:
        items_list = fh.readlines()

    items_list.append(entry_text + '\n')

    with open('todos.txt', 'w') as fh:
        fh.writelines(items_list)

Почему это важно

Если вы работаете с файлом как с набором строк, согласованность концов строк — это основа. readlines полагается на «\n», чтобы находить границы. writelines записывает ровно то, что вы ему передаёте. Если при сохранении записи опустить перевод строки, у следующей записи не будет разделителя, и простое хранение в виде списка даёт сбой. Исправление крошечное, но оно предотвращает скрытую порчу списка дел и делает поведение вашего CLI предсказуемым.

Практические заметки напоследок

Всегда завершайте каждую сохранённую запись переводом строки, чтобы сохранить семантику «одна запись — одна строка». Если позже захотите упростить логику вывода, можно сразу начинать нумерацию с единицы или ужесточить разбор команд так, чтобы ветка add срабатывала только на точное «add», а не на adding или hello add. Для более продвинутого поведения CLI существуют специализированные модули, которые управляют командными циклами и удобствами вроде запоминания предыдущих команд и подсветки; к ним можно перейти, когда базовое хранение будет надёжным.

Итог прост: при записи новых задач добавляйте «\n». Тогда «show» выведет каждый элемент на своей строке — ровно как задумано.