Hacker News new | ask | show | jobs
by wowi42 41 days ago
Hey, fair pushback, let me try to clear up a couple of points because I think there are some genuine misconceptions worth untangling.

On footguns. Totally hear you that "Python lets you do anything" feels like a footgun. The flip side that I think gets missed: because it is real Python, you can actually test it. Pytest, mypy, ruff, jump-to-definition, refactor-rename, all of it just works. Unit-testing a 400-line YAML role with nested Jinja conditionals is genuinely hard, and that gap is what pushed me toward PyInfra in the first place.

On "importing Python libraries introduces bugs". This one I think is worth a closer look, because the mechanics are not what they appear. PyInfra does not run Python on your servers. It runs Python on your control node to plan the change, then transpiles each operation to plain POSIX shell and pipes that over SSH. If you run with `-vvv` you can see it: `sh -c '...'` and nothing else on the wire. The target needs zero Python, zero agent, zero runtime. So whatever library you imported into your deploy script ran locally, produced a string of shell, and that string is what touches the box. A bug in some PyPI dependency cannot throw mid-operation on the host, because there is no Python on the host to throw it. Worth noting that Ansible, by contrast, ships a Python interpreter and module code to the target for most tasks, so if anything the library exposure on the executing side is larger there, not smaller.

On the control node, sure, you have dependencies, same as Ansible has Jinja2, PyYAML, paramiko, cryptography, and a long tail of Galaxy collections of varying quality. PyInfra has a stable API, solid test coverage, idempotent operations, and a real two-phase model (gather facts, then apply) so the apply phase is deterministic generated shell rather than arbitrary code running on the box.

On YAML keeping you on the paved path. I really wanted this to be true for years, honestly. In practice, the moment you need a conditional you end up writing `{% if %}` inside a quoted string inside a map inside a list inside a role, with no type system, no debugger, and a few sharp edges in the parser (`no` as boolean, leading zeros as octal in YAML 1.1, tab/space mixing failing without a useful pointer). And the escape hatch when Jinja-in-YAML cannot express what you need is... writing a custom Python module. So you end up writing Python anyway, just with worse tooling around it.

The way I would put it: PyInfra is Python where Python helps (writing, testing, planning) and shell where shell belongs (executing on the host). Happy to dig into any specific footgun you have run into though, those are usually the most useful conversations.