#configuration-language #json #serde-json #language #pest #serde #config-file

nightly bin+lib conflag

一个简单而强大的配置语言,通过声明性和函数性语言特性扩展 JSON

2 个版本

0.1.1 2023 年 4 月 14 日
0.1.0 2023 年 4 月 14 日

399配置

每月 32 次下载

MIT/Apache

79KB
2K SLoC

Conflag 🔥🏁

Auto-deploy

Conflag 是一种数据语言。它非常适合应用配置,一旦这些配置超出几个命令行标志或一个 5 行的 JSON 文件。

Conflag 的示例用例

  • 服务部署 -- 例如,用 json/yaml 替换 Kubernetes 或 nginx 配置
  • 持续集成 -- 例如,用 yaml 替换 Github Actions
  • 机器学习实验 -- 例如,用代码替换可重复和可复制的实验参数
  • 开发者工具 -- 例如,用 JSON 替换 VS Code 或 Sublime text 配置

以声明方式编写您的数据,但具有像引用、注释和多个文件这样的基本功能。

任何有效的 JSON 文件都是有效的 Conflag 文件,因此迁移很容易,语法清晰且易于阅读。只需几分钟即可开始,并告别 JSON。

入门指南

Rust 与 Serde

cargo add conflag --features serde

Python

git clone https://github.com/bethebunny/conflag
cd conflag
cargo build --release --features python
cp target/release/libconflag.so conflag.so

了解该语言

编写配置文件:object.cfg

{
    hello: (name) => "Hello, " + name,
    name: "Stef",
    message: hello(name),
    double: (x) => x + x,
    data: map(double, [1, 2, 3, 4, 5]),
}

使用 Serde 读取到 Rust 结构体

#[derive(serde::Deserializer, Debug)]
struct Stuff {
    message: String,
    data: Vec<u64>,
}

fn main() {
    let raw: &str = fs::read_to_string("object.cfg").unwrap();
    let stuff: Stuff = conflag::serde::from_str(raw).unwrap();
    println!("{stuff:?}");
}

从 Python 读取

>>> import conflag
>>> s = conflag.loads(open("object.cfg").read())
>>> s.name
"Stef"
>>> s.message
"Hello, Stef"
>>> s.data
[2, 4, 6, 8, 10]

更多语言细节

更复杂的示例

以下配置将加载到模型超参数配置列表中,运行 dropout 参数的参数扫描。

它展示了几个功能,例如

  • 内置的 ifmap 函数
  • 匿名作用域 -- 输出是一个数组,而不是对象,并查看 arange 函数如何创建匿名作用域
  • 修补 -- 注意我们如何可以轻松地使用精细粒度的调整制作 model_params 的变体
{
    // Base hyperparams for a simple model
    model_params: {
        decoder_mlp: {
            hidden_layers: [1024, 512, 256],
            dropout: 0.2,
            activation: "relu",
            norm: null,
        }
    },
    
    // Let's make a helper function to help us with the sweep.
    // Like numpy's arange, create a list with a range of float values
    arange: (start, stop, step) => {
        // Name an internal computation in an anonymous scope
        done: if(step > 0, start >= stop, start <= stop),
        // Recursive calls allow building any necessary helpers
        result: if(done, [], [start] + arange(start + step, stop, step)),
    }.result,
    
    // Create a list that contains a copy of model_params for each value in our sweep
    experiments: map(
        // & is the patch operator, letting us override just the parts we want to change
        (_dropout) => model_params + {decoder_mlp: &{dropout: _dropout}},
        arange(0, 0.4, 0.01),
    ),

// We don't need to expose any of the other junk to our program!
// The data hides it in this anonymous scope and only produces the output.
}.experiments

依赖项

~2.1–9MB
~71K SLoC