Перейти к содержимому

Python ↔ JavaScript

Cloudflare Workers исполняют JavaScript/WebAssembly на edge-серверах. Python-код работает через Pyodide — CPython, скомпилированный в WebAssembly. Cloudflare предоставляет интеграцию через compatibility_flags = ["python_workers"].

В Workers Python и JavaScript сосуществуют в одном рантайме. Pyodide автоматически оборачивает JS-объекты в JsProxy, но некоторые API требуют конвертации.

Pyodide по умолчанию конвертирует Python dict в JS Map. Но API Cloudflare (KV, D1, R2) ожидают обычный Object:

# ❌ Не работает — Map вместо Object
from pyodide.ffi import to_js
options = to_js({"expirationTtl": 3600})
await env.KV.put("key", "value", options) # Error!
# ✅ Работает — Object
from edgebot import to_js_object
options = to_js_object({"expirationTtl": 3600})
await env.KV.put("key", "value", options) # OK

to_js_object использует Object.fromEntries для конвертации:

from pyodide.ffi import to_js
from js import Object
def to_js_object(value):
return to_js(value, dict_converter=Object.fromEntries)

JS имеет два «пустых» значения: null и undefined. В Pyodide они представлены как JsNull и JsUndefined — это не Python None:

value = await env.KV.get("missing_key")
# value — это JsNull, не None!
# value is None → False
# value == None → может вернуть True, может нет

to_py нормализует nullish-значения:

from edgebot import to_py
value = to_py(await env.KV.get("missing_key"))
# value is None → True ✓
ЗадачаБез SDKС SDK
Dict → JS Objectto_js(d, dict_converter=Object.fromEntries)to_js_object(d)
JS null → NoneПроверка type(v).__name__to_py(v)
HTTP fetchawait js_fetch(url, options)await fetch(url, options) (+ ретраи)
Паузаawait Promise.new(lambda r,_: setTimeout(…))await sleep(1000)
console.*js.console.info(msg)log.info(msg, source=...)
  • Нет файловой системыopen() не работает
  • Нет subprocess — нельзя запускать внешние процессы
  • Нет threading — только async/await
  • Ограниченные пакеты — только чистый Python (без C-расширений), либо пакеты из Pyodide packages
  • CPU-лимит — 10ms (бесплатный план) или 30s (платный) на запрос
  • Размер бандла — до 10 MB

SDK оборачивает js.fetch в edgebot.utils.http.fetch с:

  • Автоматическими ретраями при 408, 429, 5xx
  • Уважением заголовка Retry-After для 429
  • Логированием попыток

Все вызовы Telegram API (send_message, edit_message_text и т.д.) проходят через эту обёртку.