Contributing
Dev setup, test conventions, and style guide for KynML.
Dev Environment
git clone <repo>
cd kynml
python3.11 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev,serving,mcp,hf,objectstore]'
Python 3.11+ is required (the codebase uses X | Y union type hints throughout).
The dev extra installs pytest. The other extras are needed to run the full test suite, which includes connectivity tests for the serving and MCP modules.
Running Tests
.venv/bin/python -m pytest -q
The suite must stay green. The target is 83+ passing tests. Check before and after every change:
.venv/bin/python -m pytest -q --tb=short
Run a single test file:
.venv/bin/python -m pytest tests/test_codegen.py -v
Test Files
| File | Covers |
|---|---|
tests/test_parser.py |
Tokenisation, all value types, error paths |
tests/test_semantic.py |
All validation rules, typo suggestions |
tests/test_codegen.py |
Generated script content, layer rendering, optimizer/loss/scheduler/AMP/checkpoint/early_stop snippets |
tests/test_core_features.py |
End-to-end compile from example specs |
tests/test_examples.py |
Roundtrip parse+validate on all examples/*.kyn files |
tests/test_connectivity.py |
kynml.serving, kynml.mcp, kynml.integrations module contracts (no heavy deps needed — imports are mocked where necessary) |
tests/test_cli_train.py |
CLI commands via subprocess |
Adding a Test
New behaviour must come with at least one test. Place tests in the most specific existing file. If a test file does not exist for your area, create one under tests/.
Follow the existing style:
def test_new_activation_renders_correctly() -> None:
spec = """
dataset D:
source = csv("data.csv")
target = "y"
model M:
input 4
dense 8 silu
dense 1 linear
train:
model = M
data = D
loss = mse
optimizer = adam(lr=0.001)
epochs = 1
batch = 8
""".strip()
from kynml.parser import parse_text
from kynml.semantic import validate_program
from kynml.codegen.pytorch import generate_pytorch
program = parse_text(spec)
validate_program(program)
script = generate_pytorch(program)
assert "nn.SiLU()" in script
Code Style
- No type: ignore except for third-party imports that lack stubs. Annotate all public functions.
- Frozen dataclasses for all AST nodes — no mutable state in the AST.
- Pure functions in parser, semantic, and codegen where possible — all I/O lives in the thin wrappers (
parse_file,write_pytorch,generate_service). - f-strings for code generation — do not use
%or.format(). - Lazy imports for optional dependencies — import inside the function, not at module top level, in
serving/,mcp/, andintegrations/. This is enforced by the architectural boundary:import kynmlwithout extras must not pull in fastapi or the MCP SDK. KynMLErrorhierarchy — all user-visible errors must be a subclass ofKynMLError.
Extending the Language
See Compiler Internals for the exact files and functions to modify when adding activations, losses, optimizers, schedulers, layer types, or export formats.
The change checklist for a new activation (the simplest change):
- [ ] Add to
SUPPORTED_ACTIVATIONSinkynml/semantic.py - [ ] Add mapping entry in
_activation_expr()inkynml/codegen/pytorch.py - [ ] Add a test in
tests/test_codegen.pyasserting the emittednn.*class - [ ] Add an example or entry in the Cookbook if the feature warrants one
- [ ] Run
pytest -qand confirm green
Commit Style
One logical change per commit. Short imperative subject line (≤72 chars). No AI attribution trailers, no robot emoji, no "Generated with" footers.
feat: add silu activation and nn.SiLU() codegen
fix: reject batchnorm before first input layer
docs: add onecycle scheduler cookbook recipe
test: cover fp16 AMP codegen path
Docs
Wiki pages live in docs/wiki/. Update the relevant page when changing user-visible behaviour. Keep code examples verified — paste the spec into the compiler and confirm it validates before committing.