NEON pro Python

Balíček nette-neon čte a zapisuje NEON v Pythonu, třeba váš config.neon nebo phpstan.neon projektu v PHP. Díky němu:

  • dekódujete konfigurační soubor do hodnot Pythonu a hodnoty zakódujete zpět do NEONu
  • upravíte soubor tak, že každý komentář a mezera, na které nesáhnete, zůstanou na svém místě
  • zkontrolujete soubory pomocí neon-lint v editoru, v CI nebo po AI agentovi

Instalace

pip install nette-neon

Nebo uv add nette-neon. Balíček se importuje jako neon. Vyžaduje Python 3.13 nebo novější, je plně typovaný a nemá žádné závislosti.

Dekódování a kódování

Funkce decode() převede NEON na hodnoty Pythonu, decode_file() udělá totéž se souborem a encode() hodnoty převede zpět:

from neon import decode, decode_file, encode

decode("roles: [guest, admin]")              # {'roles': ['guest', 'admin']}
config = decode_file("config.neon")
encode({"roles": ["guest", "admin"]})        # '{roles: [guest, admin]}'
encode({"roles": ["guest", "admin"]}, True)  # 'roles:\n\t- guest\n\t- admin\n\n'

Místo True může být druhým argumentem encode() funkce, která u každého pole rozhodne, zda ho zapsat jako blok. Dostane pole a seznam klíčů, které k němu vedou:

encode(config, lambda value, path: not path)  # bloky jen v první úrovni

Hodnoty formátu se převedou na tyto hodnoty Pythonu:

NEON Python
null, true, yes … None, bool
celé číslo int, libovolně velké
desetinné číslo float
řetězec str
datum neon.Date
entita, řetěz neon.Entity
sekvence list
mapování dict s řetězcovými klíči, v pořadí ze souboru

Převod je jedna ku jedné: 1.0 zůstane float, velké celé číslo zůstane přesné, {} je dict a [] je list. neon.Date drží datum tak, jak bylo zapsané, včetně chybějící časové zóny; to_datetime() ho převede na datetime. Při kódování se přijímají i datetime a date.

Chyby

Když vstup není platný NEON, decode() a parse() vyhodí neon.NeonError. Jeho zpráva říká, kde je problém, a atribut position obsahuje řádek a sloupec:

from neon import NeonError, decode

try:
    decode("database:\n\thost: localhost\n\thost: db")
except NeonError as e:
    print(e)                # Duplicated key 'host' on line 3 at column 2
    print(e.position.line)  # 3

Úpravy souborů

Funkce parse() vrátí syntaktický strom souboru a přes něj soubor změníte tak, že jeho zbytek zůstane, jak ho autor napsal:

from pathlib import Path
from neon import parse

file = Path("config.neon")
doc = parse(file.read_text(encoding="utf-8"))
doc.set_value(["database", "host"], "db.example.com")
file.write_text(doc.print(), encoding="utf-8")

Jak položky měnit, přidávat, odebírat a přejmenovávat a jak se vyznat ve stromu, popisuje stránka Úpravy souborů.

Kontrola souborů: neon-lint

Balíček obsahuje příkaz neon-lint. Předáte mu soubory nebo adresáře a on vypíše jeden řádek pro každý problém:

neon-lint config/
config/local.neon:3:2: Duplicated key 'user'

Příkaz, jeho volby i návratové kódy jsou stejné jako v knihovně pro PHP. Bez instalace balíčku ho spustíte jako uvx --from nette-neon neon-lint config/.

AI agent, který ho spustí po každé změně souboru .neon, se o rozbitém souboru dozví hned. Návod pro AI agenty ukazuje, jak ho nastavit.

Další příklady, každý se skutečným výstupem, najdete v repozitáři knihovny.