mcpField
F
fcode-python

fcode-python

github.com/factorialco开发1399 次安装今天更新
代码仓库

关于 fcode-python

fcode-python 是面向 Factorial Code 的 Python 3.13 开发指南,供在该平台编写流程的开发者使用。内容涵盖入口约定、平台 API、数据存储及运行注意事项。

主要功能

  1. 01Python 3.13 流程约定
  2. 02Factorial Code 上下文与模块 API
  3. 03数据存储和密钥处理指南
  4. 04日志与错误处理实践
  5. 05依赖包、邮件和返回值

适用场景

  1. 01开始编写 Factorial Code Python 流程
  2. 02持久化结构化数据或凭据
  3. 03通过共享日志追踪故障
  4. 04从流程发送邮件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/factorialco/factorial-code-skills --skill fcode-python

安装后在 Claude Code 中输入/fcode-python确认已加载。

详细介绍

Factorial Code — Python

在 Factorial Code 上运行的 Python 编写指南。运行时为 Python 3.13。关于平台模型(进程、模块、数据存储),请参阅 fcode-core-concepts。

方面指南
运行时Python 3.13
进程入口文件main.py
入口点def main()
参数fcode.context.parameters
变量os.getenv("X") 或 fcode.env.X
导入模块fcode.import_module("module-slug")

注意事项

  • 将 main() 定义为入口点,但绝不要自行调用它 — Factorial Code 会调用它。
  • fcode.import_module() 的名称必须是硬编码的字符串字面量,不能 使用变量:fcode.import_module("shopify-client") ✅, fcode.import_module(name) ❌。
  • 绝不要为 fcode.i18n 设置别名 — 必须直接调用(fcode.i18n("key") ✅, t = fcode.i18n ❌):使用别名调用会在运行时抛出 "i18n is disabled"。 请参阅 fcode-i18n。
  • 数据存储仅保存字符串/数字 — 在 set 前对对象使用 json.dumps, 在 get 后使用 json.loads。
  • 对保存在数据存储中的机密进行加密 — 将 True 作为 set 的第三个 参数传入(fcode.datastore.set(key, token, True));get 会自动解密。 普通的 set 会以明文保存值。
  • 使用 snake_case,不要使用 camelCase;遵循 PEP 8;在适当时添加类型提示。
  • 将主流程封装在 try/except 中,通过 fcode-logs(参见“日志记录”)记录 捕获的错误及其上下文,并抛出可采取行动的错误。不要依赖全局变量保存状态 — 应通过参数传递状态,或通过返回值返回状态。
  • 绝不要硬编码或记录机密 — 从 os.getenv 读取。

进程模板

def main():
    parameters = fcode.context.parameters

    # Your code here

    return { "message": "Success!" }

辅助工具

import os

# Execution / process / schedule metadata
execution_id = fcode.execution.id
process_id = fcode.execution.process.id
schedule_id = fcode.execution.schedule.id   # when run from a schedule
timezone = fcode.execution.timezone

# Workspace (team) metadata
team_slug = fcode.team.slug

# Environment variables (secrets/config)
api_key = os.getenv("API_KEY")  # or fcode.env.API_KEY

# Import a Factorial Code module (hardcoded name only)
client = fcode.import_module("module-name")
client_v1 = fcode.import_module("module-name", "v1.0.0")  # pinned version tag or alias

# Run another process
fcode.processes.run("process-identifier", options)

# Translations (workspace locales — see fcode-i18n)
greeting = fcode.i18n("greetings.hello", {"name": "Ada"})  # %{name} filled in
fcode.i18n("greetings.hello", {"name": "Ada"}, {"locale": "es"})  # another locale, this lookup only (value may be dynamic)
locale = fcode.i18n.locale  # the execution's locale

日志记录

通过共享的 fcode-logs 模块记录日志 — 日志级别由工作区继承并统一控制。 该模块读取团队变量 LOG_LEVEL (debug | info | warn | error,默认值为 info),并将日志转发给 print( debug/info 输出到 stdout,warn/error 输出到 stderr),因此调用处看起来就像普通的 print:

log = fcode.import_module("fcode-logs")  # import once; reuse `log` everywhere, including `except`

log.info("sync started", process_slug)  # stdout when LOG_LEVEL ≤ info
log.debug(request_payload)               # stdout only when LOG_LEVEL=debug
log.warn("token missing — skipping")      # stderr when LOG_LEVEL ≤ warn
log.error("sync failed", str(err))         # stderr — always emitted

记录详细日志 — 日志策略(在 info 级别记录开始/结束、外部调用和决策; 在 debug 级别记录负载;始终在 except 中重新抛出前记录包含上下文的日志) 详见 fcode-core-concepts §通用规则。在本地或开发工作区中设置 LOG_LEVEL=debug,以跟踪完整运行过程;生产环境保持为 info。 绝不要记录机密。每次执行最多保留 500 行日志 / 500 KB — 后续条目 将被丢弃(fcode-core-concepts › 计划与限制)。

依赖项

外部 pip 包会自动安装 — 只需 import 即可。当包名与导入名不同时,使用 @add-package 声明:

# @add-package requests
import requests

父工作区提供的包在此处已安装 — 不要重复声明(参见 fcode-core-concepts)。

数据存储与存储

import json, os

# Datastore (strings/numbers only)
fcode.datastore.set("key", "value")
fcode.datastore.set("key", json.dumps({ "name": "John", "age": 30 }))
value = fcode.datastore.get("key")
fcode.datastore.delete("key")
# Encrypted at rest with a key owned by the workspace — for tokens, credentials,
# personal data. The third argument must be a bool; get() is transparent.
# Keys (entry names) are never encrypted.
fcode.datastore.set("oauth.token", access_token, True)
token = fcode.datastore.get("oauth.token")

# Storage (files)
local_path = os.path.join(os.environ.get("TMP_DATA_DIR"), "localfile.txt")

with open(local_path, "rb") as f:
    obj = fcode.storage.upload("path/myfile.txt", f)

objects = fcode.storage.list()

content = fcode.storage.download("path/myfile.txt")
with open(local_path, "wb") as f:
    f.write(content)

# Form file params arrive as "fcode.storage://…" references — strip the
# prefix before download; see fcode-forms.

# Signed download URL — { "url", "expiresAt" }. A real HTTPS link in the
# cloud, a file:// URL locally (same shape, no special-casing).
signed = fcode.storage.create_signed_url("path/myfile.txt")

fcode.storage.delete("path/myfile.txt")

本地磁盘: 将临时文件写入 os.environ.get("TMP_DATA_DIR") 下。

变量、计划任务与 OAuth

在运行时读取/写入团队变量并管理进程计划任务 — 仅限你自己的团队,无需 API 令牌(与数据存储/存储类似):

# Team variables (config/secrets)
# Default is SENSITIVE: fcode.variables.set(key, value) creates a sensitive
# (masked, immutable-sensitivity) variable. Pass sensitive=False for plain
# config values.
fcode.variables.set("API_KEY", "secret")  # sensitive by default
fcode.variables.set("BASE_URL", "https://api.acme.com", sensitive=False)  # required for non-secret config
v = fcode.variables.get("API_KEY")  # TeamVariable (has resolving_team_slug) or None
all_vars = fcode.variables.list()   # includes variables inherited from parents
fcode.variables.delete("API_KEY")   # no-op on an inherited variable

# Schedules (cron or one-off date_time) for a process
schedule = fcode.schedule.create(
    "my-process",
    cron="0 0 6 * * SUN",  # or: date_time="2026-04-24T12:30:00.000"
    parameters={"foo": "bar"},
    allow_concurrent_executions=False,  # optional
)
schedules = fcode.schedule.list(process_id=fcode.execution.process.id)
current = fcode.schedule.get(schedule["id"])
fcode.schedule.update(schedule["id"], cron="0 0 7 * * SUN")
fcode.schedule.pause(schedule["id"])
fcode.schedule.resume(schedule["id"])
fcode.schedule.delete(schedule["id"])
# delete every schedule for a process (pass the process UUID)
fcode.schedule.delete_for_process(fcode.execution.process.id)

# Start a third-party OAuth authorization. The platform holds the state, the PKCE
# verifier and the one redirect_uri registered with the provider, and invokes
# `on_complete` when the provider redirects back -- so never build an authorization
# URL or a state by hand, and never expose a callback webhook.
flow = fcode.oauth.start(
    authorize_url="https://login.example.com/authorize",
    client_id=fcode.env.PROVIDER_CLIENT_ID,
    scope=["openid", "offline_access"],
    on_complete="oauth-callback",      # the process that receives the code
    data={"companyId": company_id},    # carried back untouched; never a secret
    extra_params={"nonce": nonce},     # optional, provider-specific
    pkce=True,                         # default
)
flow.authorization_url  # hand this to the form's oauth widget

on_complete 会收到 code、codeVerifier、redirectUri、data 和 state,这些值位于 fcode.context.parameters 中(如果提供方拒绝请求,则会收到 error / errorDescription)。在令牌交换中重放 redirectUri — 提供方会逐字节比较。 请参阅 fcode-examples references/oauth-connect.md。

fcode.variables.set/delete 只会在服务端持久化;在同一次运行中,它们不会反映到 fcode.env 中(fcode.env 是启动时获取的快照)。

继承的变量

list()/get() 会包含从父工作区继承的变量(模型见 fcode-core-concepts);继承的变量带有 resolving_team_slug,用于标识 其所有者。对继承的键调用 set() 会在此工作区创建覆盖值——这是 在此处更改该值的唯一方式;对其调用 delete() 则会静默地不执行任何操作, 因此卸载过程绝不会删除父级的凭据(如果必须报告实际删除的内容,请检查 resolving_team_slug)。fcode.env.set_env_var / del_env_var 的行为相同。

发送电子邮件

使用内置的 fcode.send_mail 发送电子邮件——无需配置 SMTP(模型见 fcode-core-concepts):

info = fcode.send_mail(
    to="[email protected]",   # string or list[str]
    subject="Report ready",
    text="Plain-text body",  # provide text, html, or both
    html="<b>HTML body</b>",
)
# info => { "messageId", "accepted", "rejected" }
  • From 地址由平台固定;你传入的 from 会被忽略。
  • 默认情况下,每次执行最多可以发送 3 封电子邮件;达到上限后,后续调用会抛出异常。
  • 在本地(fcode run)运行时没有管理器,因此电子邮件会被记录,而不会发送。
  • 可接受用途——哪些人可以作为收件人、正文可以包含哪些内容——属于 平台规则;违反规则会阻止发布。请参阅 fcode-core-concepts §发送电子邮件。

返回值

# Standard
return { "message": "Success!" }

# Custom HTTP status (webhooks)
return { "status": 404, "body": { "message": "Not found" }, "headers": { "Content-Type": "application/json" } }

# Transient (not persisted in execution results)
return { "transient": True, "data": sensitive_data }

# Synchronous UI trigger button inside Factorial (see fcode-ui-triggers).
# Returned unchanged to the page; signal a failure with an error, not in the body.
return { "synced": 42 }

返回值上限为 500 KB——结果超出上限会导致执行失败;请将结果存入存储空间, 并返回引用(fcode-core-concepts › 计划与限制)。

评论

支持 Markdown