# pyyaml: the install line on the page is the one packaging stopped supporting

> PyYAML is the YAML parser and emitter most Python projects depend on without choosing it, and its repository is small, careful and slightly out of date. The page tells you to invoke the packaging script directly, the development version in that script is two majors past the newest tag, and the build system quietly clones a second repository and pins a commit before any target runs.

**yaml/pyyaml** — Canonical source repository for PyYAML

- Repository: https://github.com/yaml/pyyaml
- Stars: 2,954 · Forks: 616
- Language: Python
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/yaml-pyyaml

## The install line is the direct packaging-script invocation

The installation section is three paragraphs and the first sentence is the problem. To install, the page says, type the packaging script with an install argument. That is the direct invocation that the packaging ecosystem removed support for, which is why every question about installing this library is about pip and why the page never mentions pip even once. What the section does well is the optional C extension. By default the packaging script checks whether the C library is installed and, if so, builds and installs its bindings. There are two explicit switches: one forces the bindings to be built, the other disables the check and skips the bindings entirely. So the decision you have to make is whether you want the fast path or a pure Python install, and the page gives you a switch for each. What it does not give you is a modern install command, so the first task for a new user is working around the documentation rather than learning the library.

## Two independent axes: which loader, and whether it is compiled

The usage notes are four lines long and they carry the whole security story. When the C bindings are present you can ask for the fast C-based parser and emitter explicitly, by passing the C loader to the load function and the C dumper to the dump function. The next paragraph is the instruction that matters: if you do not trust the input stream, use the safe loader. The point worth drawing out is that the compiled-versus-interpreted axis and the safe-versus-dangerous axis are separate. The C loader is not the dangerous one. The danger lives in the general loader, because the packaging description advertises Python-specific tags that can represent an arbitrary Python object, and pickle support alongside them. So the library's headline feature and its main hazard are the same capability, reached through different function names, and a reader who confuses the fast loader with the unsafe one will draw the wrong conclusion in both directions. Compiling the extension does not make parsing safer, and using the safe loader does not require giving up the extension.

## Running make clones a repository and checks out a commit before anything runs

The build file opens by declaring three variables: the URL of a separate build-helper repository, a commit hash, and a cache directory inside this checkout. Then it runs two shell commands at parse time, not as a target. The first clones the helper repository into the cache directory if it is not already there. The second compares the current head of that clone against the pinned hash and, if it differs, fetches and force-checks-out the pinned commit. The rest of the file includes four make fragments from that clone. So invoking make for any reason, including a target that does nothing, may reach the network, write a hidden cache directory inside the source tree, and move a checkout to a commit somebody chose. The clean list does not mention that directory, and the page documents no offline mode. For a library whose entire job is reading and writing a text format, having its build fetch a build system over the network is the most surprising thing in the repository, and it is the one place where the source tree is not self-contained.

## Two ways to disable the extension, plus a generated C file

The build targets show how much duplication there is between the make layer and the packaging script. One target runs the plain build. One sets an environment variable to zero and passes the option that skips the bindings, so there are two independent switches for one decision. One target depends on the C library having been built first and then passes the option that forces the bindings, with the include and link paths and the library search path exported for that invocation. Two more force the build and force the extension build. The clean list is more informative than the targets, because it says what the project considers generated: the package metadata directory, several bytecode caches including one under the legacy tests, the test runner's cache, and the generated C file inside the package itself. That last entry is why a compiler for Python is a build requirement and not a runtime one. The environment tooling is a third choice again: a cache directory is exported, and the virtual environment is populated by a fast installer rather than by pip.

## The build backend is in the repository, and Cython is split by interpreter version

The project metadata points the build system at a backend that lives inside this tree, in a directory beside the manifest, instead of using the standard backend from the packaging tool. The build requirements are three lines and two of them are a conditional split: a compiler for Python on any interpreter below 3.13, and version 3 or newer of that compiler from 3.13 upwards. That boundary exists because the compiler's own API changed between those generations, so the same source tree builds against two different major versions of it depending on which interpreter you run it with. It is a reasonable solution and an unusual place to discover it, since the split lives in packaging metadata rather than in documentation. The third line is the packaging tool itself, unpinned, carrying an inline comment asking whether minimum and maximum versions should be declared. So the one dependency whose version range matters most for reproducibility is the one the file explicitly leaves open.

## The version in the packaging script is two majors ahead of the newest tag

This is the number to look at before installing from the default branch. The version constant in the packaging script is a development version numbered 7.0.0, while the newest published release is 6.0.3 from late 2025, the one before that is 6.0.2 from August 2024, and the tag list also contains a release candidate for that same 6.0.2 from mid 2024. So the branch has been working toward a major version that has never been cut, and the gap between the 6.0.2 and 6.0.3 releases is over a year, which is a slow release cadence for a library this widely depended on. Two details compound it. The classifier list in the same file declares the development status as production or stable, which sits oddly beside a development version string. And the supported interpreter list in those classifiers stops at 3.13, matching the boundary in the build metadata, so a newer interpreter is not merely untested: the compiler constraint changes underneath it.

## Two examples, both about displaying YAML rather than loading it

The repository root is small and each entry says something. There is a changelog file with no file extension at all, which is a holdover from an era when that mattered, and next to it a file that looks like a template for release announcements, committed alongside the code rather than kept in a release tool. There is a manifest file for source distributions, a directory for the packaging backend, and a tox configuration sitting next to the make file, so the project supports two ways of running its test matrix. The examples directory contains exactly two entries and neither loads a document. One is a lexer for a syntax highlighting library, so YAML can be coloured in a terminal or a notebook, and the other is a highlighter. So the worked examples this project offers are about reading YAML with your eyes, and the guidance for using the library itself lives on a separate tutorial site plus two chat networks, a room on one and a channel on another. Support requests go to an issue tracker, which is the only one of those four that is versioned with the code.

## Conclusion

Install PyYAML from a tagged release with your package manager rather than following the page, because the documented command is the direct packaging-script invocation that current packaging tooling no longer supports, and the version on the default branch is a development version two majors past the newest tag. When you read its source for the same reason, read the loader choice carefully rather than the build choice: the same library ships a fast C parser, a safe loader and a general loader that can construct arbitrary Python objects, and the page separates them by function name rather than by build option. If you are a maintainer, the highest-value fixes are on the build side, where the make file performs network access and a checkout at parse time with no documented offline path, and in the metadata, where the Cython requirement is split by interpreter version with a note asking whether the toolchain's own versions should be pinned at all.

## FAQ

### What is PyYAML used for?

It is the YAML parser and emitter for Python, described as a full-featured processing framework. The packaging description says it provides a complete version 1.1 parser with Unicode support, pickle support, a capable extension API, sensible error messages, the standard YAML tags, and Python-specific tags that can represent an arbitrary Python object. The stated range of work runs from configuration files to object serialisation and persistence.

### Is PyYAML the same as YAML?

No. YAML is the data serialisation format, designed for human readability and for interaction with scripting languages, and PyYAML is one implementation of it for Python. The project also builds an optional C library and its bindings, so there is a further split between the pure Python implementation and a compiled one, selected by loader and dumper class at the call site rather than at install time.

### how to install pyyaml

The page says to type the packaging script with an install argument, then explains the optional compiled bindings: the script checks for the C library by default, an option forces the bindings, and another skips them. It does not mention pip at all, which is why the command on the page is worth treating as historical rather than as instructions.

### What does YAML stand for?

The acronym is never expanded anywhere in this repository. What the page does say is what the format is for: a data serialisation format designed for human readability and interaction with scripting languages. The parser implements version 1.1 of the specification, which is named in the packaging description.

### Is there a pip package called PyYAML?

The project page for the package is the download address recorded in the packaging script, so the distribution is published on the standard Python package index under this name. What the page itself documents is different: a direct packaging-script install, with no mention of pip anywhere in the installation section.

### how to install pyyaml on windows

There is nothing platform-specific here. The install is the same packaging-script invocation on every platform, and the platform classifiers in the packaging script declare it independent of the operating system, listing both the reference interpreter and an alternative implementation as supported.

## Sources

- [Issues](https://github.com/yaml/pyyaml/issues)
- [License: MIT](https://github.com/yaml/pyyaml/blob/main/LICENSE)
- [README](https://github.com/yaml/pyyaml/blob/main/README.md)
- [Releases](https://github.com/yaml/pyyaml/releases)
- [yaml/pyyaml on GitHub](https://github.com/yaml/pyyaml)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yaml-pyyaml
