Loading repository data…
Loading repository data…
Sofia-Rdv / repository
Практический проект на Python для работы с API. Включает два инструмента: получение информации о пользователях GitHub и конвертер валют с использованием актуальных курсов.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Данный проект представляет собой набор инструментов для работы с внешними API(GitHub и ExchangeRate-API). Он включает в себя два сервиса: анализатор репозиториев GitHub и конвертер курсов валют.
Проект выполнен с соблюдением принципов модульности, надежной обработки ошибок и полного покрытия unit-тестами.
1. GitHub Repository Analyzer
2. Currency Exchange Tool
WorkWithAPI/
└── logging_module/
├── my_logger_config.py # Модуль с настройками логирования и инициализацией логгеров
├── my_logging_config.yaml # YAML-файл конфигурации для логирования
└── my_color_formatter.py # Кастомный форматтер для цветного вывода логов в консоль
└── logs/ # Директория для логов
└── task_1 # Директория с файлами для логов первого задания
├── app.log # Информационные логи приложения
└── error.log # Логи ошибок и исключений
└── task_2 # Директория с файлами для логов второго задания
├── app.log # Информационные логи приложения
└── error.log # Логи ошибок и исключений
└── task_1_github_service/ # Директория с файлами программы первого задания
├── analytics.py # Логика расчетов статистики (analyze_repos)
├── github_api.py # Логика взаимодействия с GitHub (get_repos)
├── main.py # Запуск программы
├── test_github.py # unit-тесты для analyze_repos и get_repos
└── task_2_exchangerate_service/ # Директория с файлами программы второго задания
├── exchangerate_api.py # Логика взаимодействия с ExchangeRate-API (get_exchange_rates)
├── main_and_display_rates.py # Запуск программы и функция вывода данных (display_rates)
├── test_exchangerate.py # unit-тесты для get_exchange_rates и display_rates
├── .env.example # Пример переменной окружения
└── requirements.txt # Список библиотек необходимых для работы программы
Python 3.10+python-dotenv (для работы с переменной окружения)requests (для работы с HTTP-запросами)pytest и pytest-mock (для тестирования и имитации ответов сервера)PyYAML (для загрузки конфигурации логирования)Colorama - (для цветного вывода логов в консоль)git clone <URL_РЕПОЗИТОРИЯ>
cd <ИМЯ_ПАПКИ_ПРОЕКТА>
python main.py
python main_and_display_rates.py
pip install -r requirements.txt - Для установки всех библиотекДля работы сервиса конвертации валют (Currency Exchange Tool) необходимо получить API-ключ.
EXCHANGE_API_KEY=ваш_секретный_ключ
Важно: Никогда не фиксируйте файл .env в системе контроля версий (Git). Убедитесь, что он добавлен в Ваш .gitignore.
Приложение реализует комплексную систему логирования, которая:
logs/, но в разных папках для каждого задания.ERROR и выше, включая ошибки выполнения запросов к API, исключения и критические сбои.Настройка системы логирования осуществляется через следующие файлы:
В проекте реализовано полное покрытие тестами всех модулей, включая успешные сценарии, сетевые ошибки (Timeout, ConnectionError) и ошибки бизнес-логики API.
Файл с тестированием можно запустить как и обычный код, через кнопку run.
Также юнит-тесты можно запустить из командной строки:
pytest - Краткий вариант результата юнит-тестовpytest -v - Более детальный вывод результата юнит-тестовimport pytest
import requests.exceptions
from pytest_mock import MockerFixture
from task_1_github_service.github_api import get_repos, GithubError, UserNotFoundError, RateLimitError
from task_1_github_service.analytics import analyze_repos
def test_analyze_repos_success():
"""
Проверка успешного анализа списка репозиториев.
Проверяет корректность подсчета звезд, общего количества и лучшего репозитория.
"""
# Готовим тестовые данные (имитируем ответ от GitHub)
test_data = [
{"name": "repo1", "stargazers_count": 10, "language": "Python"},
{"name": "repo2", "stargazers_count": 5, "language": "Python"},
{"name": "repo3", "stargazers_count": 20, "language": "JavaScript"}
]
stats = analyze_repos(test_data)
assert stats['total_repos'] == 3
assert stats['total_stars'] == 35
assert stats['best_repo'] == ("repo3", 20)
assert stats['languages'][0] == ("Python", 2)
def test_get_repos_timeout_error(mocker: MockerFixture):
"""
Проверка обработки превышения времени ожидания.
:param mocker: MockerFixture: Объект для имитации ошибок (mocking).
"""
# Вместо возврата ответа, заставляем requests.get выбросить исключение Timeout
mocker.patch("requests.get", side_effect=requests.exceptions.Timeout)
with pytest.raises(GithubError) as excinfo:
get_repos("testuser")
# Проверяем, что в тексте ошибки есть нужные слова
assert "Сервер GitHub слишком долго не отвечает" in str(excinfo.value)
import pytest
import requests
from pytest_mock import MockerFixture
from task_2_exchangerate_service.exchangerate_api import get_exchange_rates, CurrencyAPIError
from task_2_exchangerate_service.main_and_display_rates import display_rates
def test_get_exchange_rates_api_business_error(mocker: MockerFixture):
"""
Проверка ошибки, которую возвращает сам API (unsupported-code).
:param mocker: MockerFixture: Объект для имитации ответа от requests (mocking).
"""
mock_resp = mocker.MagicMock()
# API часто присылает 200, но с текстом ошибки внутри
mock_resp.status_code = 200
mock_resp.json.return_value = {
"result": "error",
"error-type": "unsupported-code"
}
mocker.patch("requests.get", return_value=mock_resp)
with pytest.raises(CurrencyAPIError) as excinfo:
get_exchange_rates("ABC")
assert "не поддерживается сервисом" in str(excinfo.value)
@pytest.mark.parametrize("setup_type", ["valid_code", "invalid_codes_all"])
def test_display_rates_with_invalid_codes(capsys: pytest.CaptureFixture, setup_type: str):
"""
Проверка вывода сообщения о некорректных кодах.
:param capsys: pytest.CaptureFixture: Фикстура pytest для перехвата и анализа вывода данных.
:param setup_type: str: Ключ сценария подготовки данных (из parametrize).
"""
data = {
"base_code": "USD",
"conversion_rates": {"EUR": 0.84}
}
if setup_type == "valid_code":
# EUR - корректно, WWW - нет
target_currencies = ["EUR", "WWW"]
expected_text = "[!] Не удалось найти или некорректные коды валют: WWW"
elif setup_type == "invalid_codes_all":
# Все не корректные
target_currencies = ["AAA", "RUS", "888"]
expected_text = "[!] Ни одна из указанных валют не была найдена."
display_rates(data, target_currencies)
captured = capsys.readouterr()
assert expected_text in captured.out
if setup_type == "valid_code":
assert "1 USD = 0.84 EUR" in captured.out
assert expected_text in captured.out