mwapi_responses 0.3.2

Automatically generate strict types for MediaWiki API responses
Documentation
#!/usr/bin/env python3
"""
Copyright (C) 2020-2021 Kunal Mehta <legoktm@debian.org>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
"""
import json
from pathlib import Path
import subprocess

root = Path(__file__).parent
data_dir = root / '../mwapi_responses_derive/data'
test_dir = root / 'tests'


def handle_file(data: dict):
    params = {
        'action': 'query',
        data['mode']: data['name'][6:],
    }
    name = f"query_{data['name'][6:]}"
    props = set([field['prop'] for field in data['fields']])
    test = """
// Autogenerated by gen_tests.py
use mwapi_responses::prelude::*;

mod test_client;


"""
    counter = 0
    for prop in sorted(props):
        if "||" in prop:
            continue
        if prop == "=default":
            prop = "default"
        else:
            params[data['prop']] = prop
        test += write_test(params, f"{name}_{prop}", counter, data['test_extra'])
        counter += 1
    fname = test_dir / f"{name}.rs"
    fname.write_text(test)
    print(f"Wrote {fname}")


def write_test(params: dict, name: str, counter: int, extra: dict) -> str:
    macro = "#[query("
    for key, val in params.items():
        macro += f'{key}="{val}",'
    macro += ")]"
    extra_rs = ""
    mut = "mut "
    for key, value in sorted(extra['params'].items()):
        extra_rs += f'params.push(("{key}", "{value}"));'
    if not extra_rs:
        mut = ""
    # TODO: Use #[serde(deny_unknown_fields)]
    return f"""

{macro}
struct Response{counter};

#[tokio::test]
async fn {name}() {{
    let {mut}params = Response{counter}::params().to_vec();
    {extra_rs}
    let resp: Response{counter} = test_client::test(&params).await.unwrap();
    assert_eq!(resp.items().len(), {extra['assert'].get('length', 10)});
    assert!({"!" if extra["assert"].get("continue", True) else ""}resp.continue_.is_empty());
}}

"""


def main():
    for fname in data_dir.iterdir():
        with open(fname) as f:
            data = json.load(f)
        handle_file(data)
    subprocess.check_call(['cargo', 'fmt'])


if __name__ == '__main__':
    main()