Skip to content

Commit 7b86ac0

Browse files
authored
Merge pull request #287 from Integration-Automation/feat/dotenv-batch
Add .env (dotenv) parsing and serialisation
2 parents 4881b29 + 9b749c7 commit 7b86ac0

15 files changed

Lines changed: 359 additions & 1 deletion

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
## Table of Contents
1515

16+
- [What's new (2026-06-21) — Dotenv (.env) Parsing](#whats-new-2026-06-21--dotenv-env-parsing)
1617
- [What's new (2026-06-21) — RFC 9457 Problem Details Parsing](#whats-new-2026-06-21--rfc-9457-problem-details-parsing)
1718
- [What's new (2026-06-21) — Data Profiling & Schema Inference](#whats-new-2026-06-21--data-profiling--schema-inference)
1819
- [What's new (2026-06-21) — W3C Trace Context Propagation](#whats-new-2026-06-21--w3c-trace-context-propagation)
@@ -131,6 +132,12 @@
131132

132133
---
133134

135+
## What's new (2026-06-21) — Dotenv (.env) Parsing
136+
137+
Read 12-factor `.env` files into config. Full reference: [`docs/source/Eng/doc/new_features/v79_features_doc.rst`](docs/source/Eng/doc/new_features/v79_features_doc.rst).
138+
139+
- **`parse_dotenv` / `load_dotenv` / `dotenv_values` / `dump_dotenv`** (`AC_parse_dotenv`, `AC_load_dotenv`): `load_vars_from_json` ingested flat JSON but nothing read the de-facto `.env` file. This parses `KEY=VALUE` lines (`export` prefixes, single/double quoting, `\n`/`\t` escapes, inline comments) into a plain dict — no `python-dotenv` dependency. The loader merges into a caller-supplied mapping rather than mutating `os.environ`, so it stays safe and deterministic. Pure-stdlib.
140+
134141
## What's new (2026-06-21) — RFC 9457 Problem Details Parsing
135142

136143
Read standardized API errors out of HTTP responses. Full reference: [`docs/source/Eng/doc/new_features/v78_features_doc.rst`](docs/source/Eng/doc/new_features/v78_features_doc.rst).

README/README_zh-CN.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目录
1414

15+
- [本次更新 (2026-06-21) — Dotenv (.env) 解析](#本次更新-2026-06-21--dotenv-env-解析)
1516
- [本次更新 (2026-06-21) — RFC 9457 Problem Details 解析](#本次更新-2026-06-21--rfc-9457-problem-details-解析)
1617
- [本次更新 (2026-06-21) — 数据剖析与结构推断](#本次更新-2026-06-21--数据剖析与结构推断)
1718
- [本次更新 (2026-06-21) — W3C Trace Context 传播](#本次更新-2026-06-21--w3c-trace-context-传播)
@@ -130,6 +131,12 @@
130131

131132
---
132133

134+
## 本次更新 (2026-06-21) — Dotenv (.env) 解析
135+
136+
把 12-factor `.env` 文件读进配置。完整参考:[`docs/source/Zh/doc/new_features/v79_features_doc.rst`](../docs/source/Zh/doc/new_features/v79_features_doc.rst)
137+
138+
- **`parse_dotenv` / `load_dotenv` / `dotenv_values` / `dump_dotenv`**(`AC_parse_dotenv``AC_load_dotenv`):`load_vars_from_json` 载入扁平 JSON,但没有任何东西读取 de-facto 的 `.env` 文件。本功能把 `KEY=VALUE` 行(`export` 前缀、单/双引号、`\n`/`\t` 转义、行内注释)解析成纯 dict —— 不依赖 `python-dotenv`。载入器合并进调用端提供的 mapping 而非变动 `os.environ`,因此安全且确定。纯标准库。
139+
133140
## 本次更新 (2026-06-21) — RFC 9457 Problem Details 解析
134141

135142
从 HTTP 响应读取标准化的 API 错误。完整参考:[`docs/source/Zh/doc/new_features/v78_features_doc.rst`](../docs/source/Zh/doc/new_features/v78_features_doc.rst)

README/README_zh-TW.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目錄
1414

15+
- [本次更新 (2026-06-21) — Dotenv (.env) 解析](#本次更新-2026-06-21--dotenv-env-解析)
1516
- [本次更新 (2026-06-21) — RFC 9457 Problem Details 解析](#本次更新-2026-06-21--rfc-9457-problem-details-解析)
1617
- [本次更新 (2026-06-21) — 資料剖析與結構推斷](#本次更新-2026-06-21--資料剖析與結構推斷)
1718
- [本次更新 (2026-06-21) — W3C Trace Context 傳播](#本次更新-2026-06-21--w3c-trace-context-傳播)
@@ -130,6 +131,12 @@
130131

131132
---
132133

134+
## 本次更新 (2026-06-21) — Dotenv (.env) 解析
135+
136+
把 12-factor `.env` 檔案讀進設定。完整參考:[`docs/source/Zh/doc/new_features/v79_features_doc.rst`](../docs/source/Zh/doc/new_features/v79_features_doc.rst)
137+
138+
- **`parse_dotenv` / `load_dotenv` / `dotenv_values` / `dump_dotenv`**(`AC_parse_dotenv``AC_load_dotenv`):`load_vars_from_json` 載入扁平 JSON,但沒有任何東西讀取 de-facto 的 `.env` 檔案。本功能把 `KEY=VALUE` 行(`export` 前綴、單/雙引號、`\n`/`\t` 轉義、行內註解)解析成純 dict —— 不依賴 `python-dotenv`。載入器合併進呼叫端提供的 mapping 而非變動 `os.environ`,因此安全且具決定性。純標準函式庫。
139+
133140
## 本次更新 (2026-06-21) — RFC 9457 Problem Details 解析
134141

135142
從 HTTP 回應讀取標準化的 API 錯誤。完整參考:[`docs/source/Zh/doc/new_features/v78_features_doc.rst`](../docs/source/Zh/doc/new_features/v78_features_doc.rst)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Dotenv (.env) Parsing
2+
=====================
3+
4+
``script_vars.load_vars_from_json`` ingests flat JSON, but nothing read the
5+
de-facto 12-factor ``.env`` file. This parses ``KEY=VALUE`` lines — honouring
6+
``export`` prefixes, single/double quoting, escapes, and inline comments — into
7+
a plain dict that can feed a config layer, with no ``python-dotenv`` dependency.
8+
9+
Pure standard library (``re``); imports no ``PySide6``. ``parse_dotenv`` is a
10+
pure string-to-dict function, and the loader merges into a caller-supplied
11+
mapping rather than mutating ``os.environ``, so it is safe and deterministic.
12+
13+
Headless API
14+
------------
15+
16+
.. code-block:: python
17+
18+
from je_auto_control import parse_dotenv, load_dotenv, dotenv_values, dump_dotenv
19+
20+
values = parse_dotenv('PLAIN=hello\nexport TOKEN="a\\nb" # comment')
21+
# {"PLAIN": "hello", "TOKEN": "a\nb"}
22+
23+
config = {}
24+
load_dotenv(".env", config) # merge file into a dict
25+
load_dotenv(".env.local", config, override=True)
26+
27+
``parse_dotenv`` skips blanks and ``#`` comment lines, strips an optional
28+
``export`` prefix, validates keys, and resolves values: single-quoted values
29+
are literal, double-quoted values process ``\n`` / ``\t`` / ``\\`` / ``\"``
30+
escapes, and unquoted values drop a trailing `` #`` comment and surrounding
31+
whitespace. ``dotenv_values`` reads and parses a file; ``load_dotenv`` merges a
32+
file into an explicit ``env`` mapping (keeping existing keys unless
33+
``override``); ``dump_dotenv`` serialises a mapping back to ``.env`` text,
34+
quoting values that need it.
35+
36+
Executor commands
37+
-----------------
38+
39+
``AC_parse_dotenv`` parses ``text`` into ``{values}``; ``AC_load_dotenv`` reads
40+
a file at ``path`` into a fresh ``{values}`` dict. Both are exposed as MCP tools
41+
(``ac_parse_dotenv`` / ``ac_load_dotenv``) and as Script Builder commands under
42+
**Data**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ Comprehensive guides for all AutoControl features.
101101
doc/new_features/v76_features_doc
102102
doc/new_features/v77_features_doc
103103
doc/new_features/v78_features_doc
104+
doc/new_features/v79_features_doc
104105
doc/ocr_backends/ocr_backends_doc
105106
doc/observability/observability_doc
106107
doc/operations_layer/operations_layer_doc
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Dotenv(.env)解析
2+
================
3+
4+
``script_vars.load_vars_from_json`` 可載入扁平 JSON,但沒有任何東西讀取 de-facto 12-factor 的
5+
``.env`` 檔案。本功能把 ``KEY=VALUE`` 行 —— 遵循 ``export`` 前綴、單/雙引號、轉義與行內註解 ——
6+
解析成可餵給設定層的純 dict,且不依賴 ``python-dotenv``。
7+
8+
純標準函式庫(``re``);不匯入 ``PySide6``。``parse_dotenv`` 為純字串轉 dict 函式,載入器會合併進
9+
呼叫端提供的 mapping 而非變動 ``os.environ``,因此安全且具決定性。
10+
11+
無頭 API
12+
--------
13+
14+
.. code-block:: python
15+
16+
from je_auto_control import parse_dotenv, load_dotenv, dotenv_values, dump_dotenv
17+
18+
values = parse_dotenv('PLAIN=hello\nexport TOKEN="a\\nb" # comment')
19+
# {"PLAIN": "hello", "TOKEN": "a\nb"}
20+
21+
config = {}
22+
load_dotenv(".env", config) # 把檔案合併進 dict
23+
load_dotenv(".env.local", config, override=True)
24+
25+
``parse_dotenv`` 略過空白與 ``#`` 註解行,去除選用的 ``export`` 前綴,驗證鍵,並解析值:單引號值為
26+
字面值,雙引號值處理 ``\n`` / ``\t`` / ``\\`` / ``\"`` 轉義,未加引號的值會去除結尾 `` #`` 註解與
27+
前後空白。``dotenv_values`` 讀取並解析檔案;``load_dotenv`` 把檔案合併進明確的 ``env`` mapping
28+
(預設保留既有鍵,除非 ``override``);``dump_dotenv`` 把 mapping 序列化回 ``.env`` 文字,並為需要的值
29+
加上引號。
30+
31+
執行器命令
32+
----------
33+
34+
``AC_parse_dotenv`` 把 ``text`` 解析成 ``{values}``;``AC_load_dotenv`` 從 ``path`` 讀檔載入到新的
35+
``{values}`` dict。兩者皆以 MCP 工具(``ac_parse_dotenv`` / ``ac_load_dotenv``)以及 Script Builder
36+
中 **Data** 分類下的命令提供。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ AutoControl 所有功能的完整使用指南。
101101
doc/new_features/v76_features_doc
102102
doc/new_features/v77_features_doc
103103
doc/new_features/v78_features_doc
104+
doc/new_features/v79_features_doc
104105
doc/ocr_backends/ocr_backends_doc
105106
doc/observability/observability_doc
106107
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@
270270
from je_auto_control.utils.assets import (
271271
Asset, AssetStore, AssetValue, active_environment,
272272
)
273+
# .env file parsing / serialisation (12-factor config ingestion)
274+
from je_auto_control.utils.dotenv import (
275+
dotenv_values, dump_dotenv, load_dotenv, parse_dotenv,
276+
)
273277
# Outbound CloudEvents emitter
274278
from je_auto_control.utils.events import (
275279
EventEmitter, post_cloudevent, to_cloudevent,
@@ -851,6 +855,7 @@ def start_autocontrol_gui(*args, **kwargs):
851855
"find_repeated_sequences", "mine_action_log",
852856
"rank_automation_candidates",
853857
"Asset", "AssetStore", "AssetValue", "active_environment",
858+
"dotenv_values", "dump_dotenv", "load_dotenv", "parse_dotenv",
854859
"EventEmitter", "post_cloudevent", "to_cloudevent",
855860
"WebhookChannel", "WebhookResult", "notify_webhook", "set_default_poster",
856861
"json_extract", "json_query", "json_query_one",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,6 +1654,22 @@ def _add_resilience_specs(specs: List[CommandSpec]) -> None:
16541654
),
16551655
description="Parse an application/problem+json error response.",
16561656
))
1657+
specs.append(CommandSpec(
1658+
"AC_parse_dotenv", "Data", "Dotenv: Parse Text",
1659+
fields=(
1660+
FieldSpec("text", FieldType.STRING,
1661+
placeholder='KEY=value\nexport TOKEN="abc" # comment'),
1662+
),
1663+
description="Parse .env text (KEY=VALUE, quotes, escapes) into values.",
1664+
))
1665+
specs.append(CommandSpec(
1666+
"AC_load_dotenv", "Data", "Dotenv: Load File",
1667+
fields=(
1668+
FieldSpec("path", FieldType.STRING, placeholder=".env"),
1669+
FieldSpec("override", FieldType.BOOL, optional=True, default=False),
1670+
),
1671+
description="Load a .env file into a values dict.",
1672+
))
16571673
specs.append(CommandSpec(
16581674
"AC_rate_limit", "Flow", "Rate Limit (Token Bucket)",
16591675
fields=(
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
""".env file parsing and serialisation for AutoControl configuration."""
2+
from je_auto_control.utils.dotenv.dotenv import (
3+
dotenv_values, dump_dotenv, load_dotenv, parse_dotenv,
4+
)
5+
6+
__all__ = ["dotenv_values", "dump_dotenv", "load_dotenv", "parse_dotenv"]

0 commit comments

Comments
 (0)