zenmoney-python
Самостоятельная Python-библиотека публичного HTTP API ZenMoney. Проект находится
рядом с ZenImport и развивается независимо. Distribution: zenmoney-python,
импорт: zenmoney_api, версия 0.7.0. Python 3.12+, HTTPX 0.28.x, simplejson для точных JSON-чисел.
Возможности
- Синхронный и асинхронный клиент: полная и инкрементальная синхронизация diff, forceFetch, создание/обновление/удаление пользовательских сущностей.
- Счета, категории, получатели, операции, бюджеты, напоминания и планируемые
операции; чтение системных справочников. Типы полей для редактора в
models. - Функции создания дохода, расхода, перевода, долговой операции; сохранение оригинальных сумм/валют, нескольких категорий и неизвестных полей при обновлении.
- Suggest: один объект или список; OAuth code exchange и явное обновление токена.
- Без автоматических повторов записи, скрытого хранения данных или зависимости
от UI/банков. Единственный публичный namespace —
zenmoney_api.
Область покрытия и честные ограничения: docs/coverage.md. Сценарии расходов, возвратов, долгов и переводов: docs/basic-operations.md.
Установка
Готовые wheel, sdist и SHA256SUMS доступны в GitHub Releases. Установка версии 0.7.0 из GitHub (Python 3.12+):
python -m pip install "https://github.com/vaslv/zenmoney-python/releases/download/v0.7.0/zenmoney_python-0.7.0-py3-none-any.whl"
Пакет ещё не загружен в PyPI. Установка из исходников: python -m pip install ..
Для собственной сборки выполните sh scripts/build.sh: в dist/ появятся wheel,
sdist и SHA256SUMS. Twine проверяет метаданные; wheel собирается из sdist.
Имя репозитория и дистрибутива — zenmoney-python, Python-import — zenmoney_api.
Прежнее локальное имя zenmoney-api-client больше не используется; перед
переходом в существующем окружении удалите старый дистрибутив или создайте чистое
окружение, чтобы два пакета не владели одним namespace.
Порядок первого GitHub-релиза и интеграции приложений: docs/publication.md.
Чтение
import os
from zenmoney_api import Client
with Client(os.environ['ZENMONEY_TOKEN']) as api:
initial = api.read_diff() # cursor=0 — первоначальная синхронизация
# Сначала атомарно сохраните сущности и удаления, затем курсор в своей БД.
cursor = initial['serverTimestamp']
changes = api.read_diff(cursor)
accounts = api.read_diff(cursor, force_fetch=['account'])
Клиент сохраняет неизвестные поля в словарях; Diff.raw_json содержит исходный
ответ. Целые числа читаются как int, десятичные — как Decimal. Для денег
используйте Decimal('1.23') или целые числа VND: при отправке они остаются
JSON-числами без округления через float. float принимается, но уже возникшую
в нём погрешность SDK исправить не может. NaN/Infinity и не-JSON объекты отклоняются
до запроса. SDK не пересчитывает валюты. Обычный json.dumps не сериализует Decimal;
для исходного ответа используйте Diff.raw_json, для подготовленных объектов —
zenmoney_api.protocol.encode_json.
from zenmoney_api import AsyncClient
async def load(token):
async with AsyncClient(token) as api:
return await api.read_diff()
Используйте контекстный менеджер либо close() / aclose() для освобождения
соединений. Закрытый клиент не используется повторно: он вызывает ClientClosedError;
создайте новый экземпляр. is_closed показывает состояние. Один экземпляр
асинхронного клиента используйте в одном event loop. Параметр timeout принимает
секунды, httpx.Timeout или явно отключённый таймаут None.
Подготовка и отправка
from zenmoney_api import transactions as tx
operation = tx.expense(user=123, account='account-id', instrument=1,
amount=100000, date='2026-10-13', categories=['category-id'], payee='Shop')
# Сохраните operation и его UUID до отправки. Повтор не должен создавать новый UUID.
# Выполнить запись, когда вызывающее приложение готово:
# result = api.upsert('transaction', [operation], cursor)
# Затем повторно получите данные и проверьте наличие/содержимое операции.
transaction(...) формирует общий объект; income, expense, transfer, debt
упрощают типовые случаи. Примеры: examples/operations.py.
update(fetched_object, tag=[...]) копирует полный объект с сохранением полей.
api.diff(cursor, changes={'account': [...], 'tag': [...], 'transaction': [...]}, deletions=[...]) позволяет передать несколько типов сущностей одним запросом.
upsert(kind, entities, cursor) — удобная обёртка.
Для новых объектов каталога есть полные формы с актуальными полями:
entities.account(user=..., title=..., instrument=...), entities.tag(...),
entities.merchant(...). Полученный объект можно передать в upsert.
Для loan/deposit задайте параметры срока и процентов; системный debt-счёт
следует получать из diff, а не создавать повторно. Передавайте полные сущности,
не patch. Низкоуровневый интерфейс проверяет структуру, идентификаторы, timestamps
и JSON, но не подменяет серверную проверку всех полей. Ограничения/пакетирование
определяет вызывающее приложение, скрытого лимита в 20 записей в общем SDK нет.
deletion(kind, id, user=..., now=...) создаёт удаление по ID. Для бюджета с
составным ключом используйте clear_budget и upsert('budget', ...).
Мягкое удаление операции — update(operation, deleted=True).
api.suggest({'payee': 'Shop'}) или список объектов возвращает подсказки API,
не изменяя записи.
OAuth (необязательно)
Для diff/suggest достаточно готового Bearer-токена в Client/AsyncClient. Регистрация приложения и собственный OAuth не требуются для использования SDK. Методы ниже предназначены для владельцев уже выданных реквизитов приложения; их живая проверка не является условием приёмки основного API.
import secrets
from zenmoney_api import OAuthClient, callback_code
with OAuthClient('registered-client-id', 'client-secret', 'https://your-app/callback') as oauth:
state = secrets.token_urlsafe(32) # сохраните в сессии до открытия URL
url = oauth.authorization_url(state=state)
# code = callback_code(received_callback_url, expected_state=state)
# token = oauth.exchange_code(code)
# if token.refresh_token is not None:
# refreshed = oauth.refresh(token.refresh_token)
Для async есть независимый AsyncOAuthClient с теми же аргументами:
используйте async with, а exchange_code и refresh вызывайте с await.
OAuth-клиенты переиспользуют HTTPX-клиент и переданный транспорт между запросами.
При работе без контекстного менеджера вызовите close() / await aclose().
Оба способа освобождают открытый HTTPX-клиент и его транспорт; повторное закрытие
безопасно. После закрытия is_closed равен True, а обмен кода, обновление токена
и повторный вход в контекст вызывают ClientClosedError. Создайте новый экземпляр
для следующего сеанса. AsyncOAuthClient используйте в рамках одного event loop.
SDK не поднимает callback-сервер, не регистрирует приложение, не хранит токены
и не обновляет их автоматически. Если refresh-ответ не содержит нового
refresh_token, приложение сохраняет прежний. Token.__repr__ скрывает токены.
State проверяется до обмена code; привязка callback к сессии — задача приложения.
Ошибки и подтверждение записи
HTTPError.status_code, TransportError, ResponseError не включают тело ответа
и токен. HTTP 200 не гарантирует принятия всех изменений: более новый changed
на сервере может победить. После записи требуется отдельное чтение и сверка;
при неопределённом результате нельзя создавать другой UUID и слепо повторять.
Синхронизация БД, пользовательское подтверждение, журнал отправок и reconciliation
принадлежат приложению, а не SDK.
Разработка и Docker
sh scripts/test.sh
sh scripts/build.sh
Тесты используют установленный wheel без дерева исходников, без сети и без настоящих токенов. Есть проверка реального HTTP на локальном тестовом сервере. Тестовый образ проверяет строгую типизацию mypy, типовые примеры использования публичного API и выводит покрытие. Сборка требует доступа к реестру образов и PyPI.
Переход с 0.4
Версия 0.5 намеренно меняет контракт: zenimport_zenmoney удалён, десятичные
числа ответа теперь Decimal, закрытый клиент не открывается повторно. Для записи
используйте diff/upsert, для типовых объектов — transactions.
Старые приложения следует адаптировать после приёмки SDK; их ограничения
не определяют дизайн библиотеки.
Архитектура · Покрытие API ·
Проверка на настоящем API · История.
Живая приёмка
Результаты проверки на тестовом аккаунте.
Для собственного отдельного тестового аккаунта скопируйте .env.example в .env
и заполните ZENMONEY_TEST_TOKEN. Шаблон содержит также все необязательные переменные
OAuth. Файл не попадает в Git и образ Docker.
sh scripts/live-check.sh выполняет только чтение. --write явно включает запись
искусственных данных и требует первоначально пустого отдельного аккаунта;
--soft-delete и --cleanup работают только с UUID сохранённого тестового журнала.
После ошибки автоматического повтора нет. --resume разрешает только повторную
сверку и продолжение подтверждённых шагов, без повторения неизвестной записи.
Завершённый очищенный журнал не используется для нового запуска.
Для нового запуска задайте другой путь --journal /state/new-run.json.
--write --basic --journal /state/basic-run.json проверяет согласованный базовый
набор операций, баланс после каждого шага, долговые движения и отсутствие дубля
при явной записи того же UUID. --cleanup --journal /state/basic-run.json
убирает тестовые объекты; --inspect выводит только названия отличающихся полей.
Metadata
Release files for zenmoney-python 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| zenmoney_python-0.7.0.tar.gz | 63.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| zenmoney_python-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 84.6 kB
Release files / zenmoney_python-0.7.0.tar.gz
| Download URL | zenmoney_python-0.7.0.tar.gz |
|---|---|
| Size | 63.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9a70d3eb14b96bd61811644bfbbf019b42097a4ad0ff4a5a6b920b60c5f3de50
|
|
BLAKE2b-256 checksum How to use checksums |
c0fcc26b5abc99c0c01f7b0779a422e814192288c6df4c3ec7636411e739d241
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Release files / zenmoney_python-0.7.0-py3-none-any.whl
| Download URL | zenmoney_python-0.7.0-py3-none-any.whl |
|---|---|
| Size | 20.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
529cd89ce941ddfabbe8a08c4ab5c587389680cda0e0b9b1f1abaf3e5f2734b7
|
|
BLAKE2b-256 checksum How to use checksums |
c4670a58fea1cb691d20c3ed9dbaed2b908fd61e766f69b32b4f210044071fe6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|