← Python мануфактура

Після цього уроку ви зможете

Конспект і таймкоди

0:00

`.env` як локальна конфігурація

Автотести розглядаються як застосунок, якому потрібна конфігурація: базові URL, email, пароль та інші параметри запуску. У корені проєкту створюється .env, а імена незмінних конфігурацій записуються в UPPER_SNAKE_CASE, наприклад BASE_URL, EMAIL, PASSWORD.

.env і .venv додаються до .gitignore. Сірий файл в IDE означає, що Git його не відстежує. Важливе уточнення: .gitignore діє лише на невідстежувані файли. Якщо .env уже був закомічений, його треба прибрати з індексу; якщо секрет уже опублікований — також відкликати або змінити сам секрет.

Приклад коду

Fail-fast завантаження локальної конфігурації

import os
from pathlib import Path

from dotenv import load_dotenv

load_dotenv(Path(__file__).with_name(".env"))

required = ("BASE_URL", "EMAIL", "PASSWORD")
missing = [name for name in required if not os.getenv(name)]
if missing:
    raise RuntimeError(f"Missing configuration: {', '.join(missing)}")

print(os.environ["BASE_URL"])

Приклад завантажує сусідній .env, перевіряє всі обов’язкові keys і завершується з явною помилкою, якщо конфігурація неповна.

Очікуваний результат: Для підготовленого .env друкується https://example.test; при відсутньому key виникає RuntimeError.

Потрібно: python-dotenv

Практика

Перевірити повну й неповну конфігурацію

  1. Створіть локальний .env лише з test placeholders.
  2. Запустіть loader з усіма required keys.
  3. Видаліть один key і перевірте, що запуск падає з назвою відсутньої конфігурації.

Результат: Повна конфігурація проходить, неповна зупиняє тести до відкриття браузера.

4:00

Читання змінних через `os.getenv()`

Хардкоджені значення замінюються на os.getenv("BASE_URL"), os.getenv("EMAIL") і os.getenv("PASSWORD"). Для цього імпортується стандартний модуль os.

Плагін підтримки .env може дати IDE автодоповнення й підсвічування, але не є частиною виконання тестів. Реальне джерело значень — середовище процесу після завантаження .env.

6:00

Один домен чи готові URL

Розглядаються два підходи: зберегти базовий домен і збирати адреси через f-string або одразу зберігати готові BASE_URL та BASE_APP_URL. Другий варіант обрано як простіший для поточної потреби: немає зайвої конкатенації та прихованих правил побудови адрес.

Приклад f-string — f"https://app.{domain}". Він корисний, коли частини адреси справді комбінуються у багатьох конфігураціях; створювати такий механізм лише «на майбутнє» суперечило б YAGNI.

Уточнення

Environment variables мають вищий пріоритет

Оскільки load_dotenv() не override-ить наявні environment variables за замовчуванням, CI або shell може без зміни .env надати іншу конфігурацію.

Термін

load_dotenv

load_dotenv() читає key-value pairs з .env і додає їх до environment; за замовчуванням уже наявні environment variables не перезаписуються.

9:00

`python-dotenv` і `load_dotenv()`

Сам файл .env не потрапляє в os.environ автоматично. Додається пакет python-dotenv, викликається load_dotenv(), після чого os.getenv() бачить локальні значення. Версію залежності фіксують у requirements.txt.

Після зміни запускаються всі наявні тести. Їх успішне проходження підтверджує, що перенесення конфігурації не змінило поточну поведінку сценаріїв.

12:00

Константи й помірний DRY

Повторювані звернення до environment variables піднімаються у зрозумілі константи на рівні файлу: LOGIN_URL, EMAIL, PASSWORD. IDE Replace використовується для послідовної заміни старих виразів.

Автор свідомо не додає YAML, кілька конфігураційних класів чи систему environment-профілів. Поточна потреба — один передпродакшн стенд, тому достатньо .env. Розширення потрібне лише тоді, коли реально з’являться різні середовища з відмінними наборами параметрів.

16:00

Безпечний коміт конфігураційних змін

Перед комітом створюється окрема гілка. До diff входять код завантаження конфігурації, .gitignore і залежність, але не локальний .env. Перед push ще раз перевіряється, що email і пароль не відстежуються.

Це важлива межа: .env захищає локальні секрети від випадкового Git tracking, але не є менеджером секретів для CI. У CI значення мають надходити з захищених variables/secrets платформи.

18:00

Централізація в `conftest.py`

Щоб не повторювати load_dotenv() і читання змінних у кожному тестовому файлі, конфігурація переноситься в conftest.py. Pytest автоматично знаходить цей файл у відповідній директорії та робить fixtures доступними тестам нижче по дереву.

Створюється fixture конфігурації зі scope session. Вона обчислюється один раз на весь тестовий запуск і повертає набір значень, потрібних сценаріям.

Термін

Fixture scope

Pytest fixture зі scope session створюється один раз на test session, тому підходить для незмінної конфігурації всього запуску.

21:00

Передавання fixture в тести

Тест отримує config як параметр так само, як page. На цьому етапі fixture повертає dictionary, тому значення читаються за ключами: URL для відкриття сторінки, email і пароль для авторизації.

Зміна проходить через реальний запуск тестів. Помилки на кшталт невірного імені fixture або відсутнього ключа знаходяться лише тоді, коли відповідний шлях справді виконується.

24:00

Виправлення помилок і повний прогін

Під час запуску виправляються пропущене передавання config і неправильне звернення до значення. До залежностей додається відсутній пакет, код форматується, після чого спершу запускається цільовий тест, а потім весь наявний набір.

Цикл уроку: маленька зміна → запуск найближчого тесту → виправлення → ширший прогін. Так легше локалізувати причину, ніж накопичити кілька незалежних рефакторингів до першої перевірки.

27:00

Amend і межа force-push

Amend замінює останній коміт новою версією, що дозволяє додати забутий файл без окремого шумового коміту. Якщо попередній коміт уже запушено, його hash змінився, тому звичайний push відхиляється як non-fast-forward.

У відео показано force-push у власну feature-гілку й окремо застережено не робити цього в main. Практичне уточнення: безпечніший варіант — --force-with-lease, і лише коли правила репозиторію дозволяють переписування гілки та ніхто інший не базує на ній роботу. Якщо це не погоджено, простіше додати новий виправний коміт.

Що змінилося після запису

Force-push після amend

АктуальноДля вже опублікованої feature branch поточна Git documentation надає --force-with-lease як захисний варіант. Він не робить history rewrite безпечним автоматично: branch має бути персональною, а переписування — дозволеним командними правилами.

Перевірено 2026-07-31

Термін

--force-with-lease

--force-with-lease дозволяє update лише якщо remote ref має очікуване значення; це зменшує ризик затерти чужі commits порівняно з безумовним --force.

Джерела та додаткові матеріали

  • python-dotenv documentation ↗python-dotenv maintainers · перевірено 2026-07-31

    Підтверджує й актуалізує поняття уроку: Getting Started.

  • How to use fixtures ↗pytest · перевірено 2026-07-31

    Підтверджує й актуалізує поняття уроку: Fixture scopes.

  • git-push ↗Git project · перевірено 2026-07-31

    Підтверджує й актуалізує поняття уроку: --force-with-lease.