К содержимому

Документация

Среда Python: импорты, типы и ограничения

Исполняется CPython 3.13. Сценарий является ограниченной программой обработки данных. Он не получает файловую систему сервера, сеть, переменные окружения и инструменты установки пакетов.

Точка входа и обычный код

Объявите одну функцию def run(ctx): с одним аргументом. Вне функций допустимы разрешённые импорты, определения вспомогательных функций, строка документации и константы, вычисляемые как литералы. Сетевой вызов и другое выполнение помещайте внутрь run. Например, items = ctx.param(...) на верхнем уровне не допускается.

from decimal import Decimal, ROUND_HALF_UP
import json

CURRENCY = 'RUB'

def run(ctx):
    amount = Decimal('12.345').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
    record = {'currency': CURRENCY, 'price': float(amount)}
    ctx.emit(record, 'A-1')
    ctx.log('Запись подготовлена', {'bytes': len(json.dumps(record))})

Можно использовать обычные функции, условия, циклы, включения списков/словарей, генераторы и исключения, которые пропускает валидатор. При этом async, await, классы, декораторы, global, nonlocal и доступ к внутренним атрибутам запрещены. Имена сценария и его аргументов не должны начинаться с _. Аннотации типов не подключают библиотеку и не дают новые права.

Разрешённые модули

Разрешён не весь модуль, а только открытый набор безопасных имён. from module import *, относительные импорты и произвольные подпакеты запрещены. Используйте import json, from decimal import Decimal или from urllib.parse import urljoin.

Модуль Открытые возможности
json loads, dumps, JSONDecodeError
re compile, search, match, fullmatch, findall, finditer, split, sub, subn, escape; флаги I/IGNORECASE, M/MULTILINE, S/DOTALL, X/VERBOSE, A/ASCII, U/UNICODE, NOFLAG, error
math Открытые математические функции и константы без внутренних имён
decimal Decimal, Context, getcontext, localcontext, InvalidOperation, DivisionByZero; ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_DOWN, ROUND_UP, ROUND_CEILING, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_05UP
datetime datetime, date, time, timedelta, timezone, MINYEAR, MAXYEAR
statistics mean, fmean, geometric_mean, harmonic_mean, median, median_low, median_high, median_grouped, mode, multimode, quantiles, pstdev, pvariance, stdev, variance, StatisticsError
collections Counter, defaultdict, deque, OrderedDict
itertools accumulate, chain, combinations, combinations_with_replacement, compress, count, cycle, dropwhile, filterfalse, groupby, islice, pairwise, permutations, product, repeat, starmap, takewhile, tee, zip_longest, batched
functools reduce, partial, cmp_to_key
html escape, unescape
base64 b64encode, b64decode, urlsafe_b64encode, urlsafe_b64decode, b32encode, b32decode, b16encode, b16decode
csv reader, writer, DictReader, DictWriter, QUOTE_ALL, QUOTE_MINIMAL, QUOTE_NONNUMERIC, QUOTE_NONE, Error
io StringIO, BytesIO (только буферы в памяти)
hashlib sha256, sha384, sha512, sha3_256, sha3_512, blake2b, blake2s
unicodedata normalize, category, decimal, digit, numeric, name, lookup, combining, east_asian_width
urllib.parse urljoin, urlparse, urlsplit, urlunparse, urlunsplit, parse_qs, parse_qsl, urlencode, quote, quote_plus, unquote, unquote_plus

urllib.parse только разбирает ссылки, не делает запросы. datetime.time является типом времени, не модулем time для пауз. itertools.count/cycle/repeat могут быть бесконечны, ограничивайте их islice и общим пределом работы. Регулярные выражения используют Python re; сложное выражение может расходовать вычислительное время, поэтому ограничивайте вход.

Собственные dict, list, set, bytearray, Counter, defaultdict, OrderedDict и deque поддерживают обычные изменения данных. У изменяемых индексируемых контейнеров работают присваивание элемента и операции вида counts[key] += 1. У этих операций сохраняется обычный порядок вычисления Python. Разрешены именно стандартные типы, а не произвольные подклассы или объекты SDK. Возможность изменить словарь данных не позволяет изменить служебный объект контекста.

Встроенные функции

Для обычных преобразований доступны abs, all, any, bin, bool, bytes, bytearray, callable, chr, complex, dict, divmod, enumerate, filter, float, format, frozenset, hex, int, isinstance, issubclass, iter, len, list, map, max, min, next, oct, ord, pow, range, repr, reversed, round, set, slice, sorted, str, sum, tuple, zip. Стандартные безопасные классы исключений также доступны. Наличие типа complex, bytes, set или Decimal не делает его JSON-совместимым.

print() преобразуется в сообщение журнала. Для дополнительных полей и уровня используйте ctx.log(). print(file=...) запрещён. Форматируйте строки через конкатенацию, f-строки и разрешённый встроенный format; методы строк format/format_map ограничены из соображений безопасности.

Сериализация результата

ctx.emit() принимает только dict со строковыми ключами. Ключ записи передавайте строкой. Значения должны сериализоваться в JSON без NaN и бесконечности. Decimal преобразуйте в нужный числовой/строковый формат явно; время через .isoformat(), байты через .decode('utf-8') только если это текст. Не передавайте документ или DOM-узел целиком.

def run(ctx):
    ctx.emit({'collected_at': ctx.now().isoformat(), 'price': 1250.5}, 'A-1')

Запрещённые действия

Нельзя импортировать os, sys, socket, subprocess, pathlib, importlib, ctypes, pickle, marshal, HTTP-клиенты и сторонние пакеты. eval, exec, compile, open, input, рефлексия через globals/locals/vars/dir/getattr/setattr/delattr, внутренние и frame-атрибуты недоступны. Не пытайтесь менять объект SDK и его служебное состояние. Собственные словари, списки, множества и bytearray можно менять обычным способом.

Синтаксическая политика дополняется ограничениями процесса и контейнера: адресное пространство и CPU ограничены, открытие файла или сокета, создание процесса и повышение привилегий запрещены. Доступ к внешним сервисам возможен только платформенным hostcall из SDK с общей проверкой прав и лимитов. Если изоляция не может быть включена, запуск не должен продолжаться в менее защищённом режиме.

Лимит CPU и показатель процессорного времени относятся к пользовательскому выполнению после подготовки интерпретатора. Общее время запуска и ожидания внешних сервисов дополнительно ограничивает wall-time. Из-за секундной точности системного ограничения CPU момент остановки может округляться вверх.

Диагностика

Ошибка проверки сообщает строку, правило и причину: синтаксис, точка входа, импорт, размер или политика. Исправьте исходник, затем повторите проверку и пробу. ValueError/TypeError обычно указывают на неверные аргументы или данные, RuntimeError также используется для отказа платформенного сервиса. Ограничение CPU, памяти и общего времени даёт неуспешное завершение. Оно не доказывает отсутствие уже переданных записей, поэтому повтор должен использовать стабильные ключи.

CSV в памяти и стабильные отпечатки

StringIO/BytesIO не дают доступа к файловой системе. Используйте их для небольших разрешённых данных в памяти. Base64 не шифрует содержимое. Хэш подходит для стабильного отпечатка, но хэш случайного значения создаёт новый ключ каждый прогон и не решает задачу обновления записей.

from io import StringIO
import csv
import hashlib

def run(ctx):
    text = ctx.param('csv_text', 'sku;price\nA-1;1250\n')
    for row in csv.DictReader(StringIO(text), delimiter=';'):
        sku = row.get('sku', '').strip()
        if not sku:
            continue
        key = hashlib.sha256(sku.encode('utf-8')).hexdigest()
        ctx.emit({'sku': sku, 'price': ctx.text().money(row.get('price'))}, key)