Python-клиент для ФИАС Public API — федеральной информационной адресной системы Российской Федерации. Поддерживает синхронные и асинхронные операции.
⚠️ Это неофициальный клиент. Проект не связан с ФНС России и не поддерживается разработчиками ФИАС — независимая обёртка над публичным API. Актуальную документацию по API смотрите на официальном сайте ФИАС.
pip install fias-public-apipip install git+https://github.com/quonaro/fias-public-api| Пакет | Версия | Описание |
|---|---|---|
requests |
>=2.32.5 |
HTTP библиотека для API запросов |
httpx |
>=0.28.1 |
Асинхронная HTTP библиотека |
from fias_public_api import get_token_sync, SyncFPA, AddressType
# Получаем токен автоматически
token = get_token_sync()
# Создаем клиент (address_type обязателен: 1 — административный, 2 — муниципальный)
api = SyncFPA(token, AddressType.ADMINISTRATIVE)
# Ищем адрес
results = api.search("Москва, Красная площадь")
print(f"Найдено: {len(results)} результатов")
# Получаем детали первого результата
if results:
details = api.details_by_id(results[0]['id'])
print(f"Адрес: {details.get('address', 'N/A')}")import asyncio
from fias_public_api import get_token_async, AsyncFPA, AddressType
async def main():
token = await get_token_async()
async with AsyncFPA(token, AddressType.ADMINISTRATIVE) as api:
results = await api.search("Москва, Красная площадь")
print(f"Найдено: {len(results)} результатов")
if results:
details = await api.details_by_id(results[0]['id'])
print(f"Адрес: {details.get('address', 'N/A')}")
asyncio.run(main())# Простой поиск (используется address_type из конструктора)
results = api.search("Москва")
# Поиск с переопределением address_type для конкретного вызова
results = api.search("Санкт-Петербург", address_type=AddressType.MUNICIPALITY)
# Обработка результатов
for result in results:
print(f"ID: {result['id']}")
print(f"Адрес: {result['address']}")
print(f"Тип: {result['type']}")regions = api.get_regions()
for region in regions:
print(region['name'])from fias_public_api import AddressType
object_id = 12345
# address_type можно переопределить для конкретного вызова
details = api.details_by_id(object_id, address_type=AddressType.MUNICIPALITY)object_guid = "some-guid-string"
details = api.details_by_guid(object_guid, address_type=AddressType.ADMINISTRATIVE)location = api.get_location_by_ip("8.8.8.8")
print(location)items = api.get_address_items(
path="7700000000000",
address_level=7,
name_part="Тверская"
)hints = api.get_address_hint(
search_string="Москва",
up_to_level=5
)from fias_public_api import AddressType
api = SyncFPA(
token,
address_type=AddressType.ADMINISTRATIVE,
enable_logging=True,
timeout=30.0, # таймаут каждого HTTP запроса, по умолчанию 15 секунд
)timeout применяется к каждому запросу, включая get_token_sync() / get_token_async().
from fias_public_api import retry_on_error
from requests.exceptions import ConnectionError, HTTPError
@retry_on_error(
max_retries=5,
delay=1.0,
backoff=2.0,
exceptions=(ConnectionError, HTTPError)
)
def search_with_retry(search_string):
return api.search_address_items(search_string)По умолчанию (exceptions не задан) повторяются ошибки транспорта обеих
библиотек: OSError (покрывает всё дерево requests) и httpx.HTTPError
(у httpx исключения наследуются от Exception, а не от OSError, поэтому их
нужно перечислять явно). Программные ошибки — ValueError на пустой запрос,
KeyError, TypeError — не повторяются: повторять заведомо неуспешный запрос
бессмысленно.
Любой ответ с кодом 4xx/5xx поднимает исключение, а не возвращается как данные:
- синхронный клиент —
requests.HTTPError - асинхронный клиент —
httpx.HTTPStatusError
from requests.exceptions import HTTPError, RequestException, Timeout
try:
results = api.search("Несуществующий адрес")
except HTTPError as e:
if e.response.status_code == 404:
print("Адрес не найден")
elif e.response.status_code == 401:
print("Неверный токен")
else:
print(f"HTTP ошибка: {e}")
except Timeout:
print("Превышен таймаут запроса")
except RequestException as e:
print(f"Ошибка сети: {e}")Пустой поисковый запрос — это ValueError, он поднимается до обращения к сети:
api.search(" ") # ValueError: search_string cannot be emptysearch(search_string, address_type)— поиск адресов по текстовой строкеdetails_by_id(object_id, address_type)— детали по IDdetails_by_guid(object_guid, address_type)— детали по GUIDget_regions()— список регионовget_address_items(...)— фильтрация адресных объектовget_details(object_id)— дополнительные сведенияis_descendant(ancestor, descendant, address_type)— проверка вложенностиhas_descendants(parent, up_to_level, address_type)— проверка наличия потомковget_address_item_by_cadastral_number(number, address_type)— по кадастровому номеруget_fias_object_types()— типы объектов ФИАСsearch_address_items(search_string, address_type)— поиск по строкеget_address_hint(...)— подсказки по адресуsearch_address_item(search_string, address_type)— поиск одного объектаget_location_by_ip(ip, address_type)— местоположение по IP
Все методы из SyncFPA доступны в асинхронной версии с поддержкой async/await.
get_token_sync(url, timeout)— получить токен (синхронно)get_token_async(url, timeout)— получить токен (асинхронно)STANDARD_HEADERS(token)— стандартные HTTP-заголовки (STANDART_HEADERSоставлен как алиас)AddressType— перечисление типов адресов (ADMINISTRATIVE = 1,MUNICIPALITY = 2)retry_on_error(...)— декоратор для повторных попыток при ошибкахDEFAULT_RETRY_EXCEPTIONS— что повторяется по умолчанию (OSError,httpx.HTTPError)DEFAULT_TIMEOUT— таймаут запросов по умолчанию (15 секунд)
Все примеры доступны в папке examples/:
- 01_basic_usage.py — базовое использование API
- 02_address_types.py — работа с типами адресов
- 03_async_usage.py — асинхронное использование
- 04_retry_decorator.py — использование retry декоратора
- 05_address_info_methods.py — методы AddressInfo
- 06_search_methods.py — методы поиска
- 07_location_methods.py — определение локации по IP
- 08_error_handling.py — обработка ошибок
# Установка зависимостей для разработки
pip install -e ".[dev]"
# Юнит-тесты: без сети, все HTTP вызовы замоканы
pytest
# Покрытие (branch coverage, порог fail_under задан в pyproject.toml)
pytest --cov --cov-report=term-missing
# Живые тесты против реального API ФИАС (нужна сеть, по умолчанию отключены)
pytest -m integration
# Линтер
ruff check .
# Запуск конкретного теста
pytest tests/test_sync.py::TestSyncFPA::test_get_regionsОба клиента прогоняются через общую таблицу эндпоинтов (tests/endpoints.py),
поэтому метод, который разъедется по URL, HTTP-методу или вообще появится
только в одном из клиентов, роняет тест, а не проходит незамеченным.
Тесты, обращающиеся к боевому сервису, помечены маркером integration и не
входят в обычный прогон pytest, поэтому сборка не зависит от доступности
fias.nalog.ru.
Версия 1.1.0 исправляет ошибки обработки HTTP, поэтому часть поведения намеренно изменилась:
- HTTP-ошибки поднимают исключение. Раньше ответ 4xx/5xx возвращался как
обычный JSON, теперь это
requests.HTTPError/httpx.HTTPStatusError. Код, проверявшийresult.get("error"), получит исключение вместо данных. - Таймаут по умолчанию — 15 секунд. Запросы больше не могут висеть
бесконечно; меняется через
SyncFPA(..., timeout=30.0). get_token_sync/get_token_asyncна ошибке HTTP бросаютValueError, а неHTTPError— sync и async приведены к одному поведению.retry_on_error(max_retries=0)теперь сразу бросаетValueError(раньше молча возвращалNoneиз обёрнутой функции).details()выводитDeprecationWarning, а неprintв stdout.SYNC_RETRY_EXCEPTIONSиASYNC_RETRY_EXCEPTIONSсохранены как алиасы общегоDEFAULT_RETRY_EXCEPTIONS;STANDART_HEADERS— алиасSTANDARD_HEADERS. Старые импорты не ломаются.
Релиз публикует тег, а не коммит. Версия задаётся явно через lota push:
lota push v1.1.0Это запишет version = "1.1.0" в pyproject.toml, закоммитит изменение,
создаст тег и запушит ветку и тег. lota push без аргумента — обычный
git push origin main.
Пуш тега v* запускает .github/workflows/publish.yml: тесты и линтер,
сборка, публикация на PyPI (trusted publishing, fallback на
PYPI_API_TOKEN) и проверка, что версия реально появилась на PyPI — если
публикация не состоялась, workflow падает красным, а не молча завершается
зелёным. Дёргать версию руками не нужно: workflow берёт её из тега.
MIT. Подробности см. в файле LICENSE.