| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
A small pipeline for turning Public Use File (PUF) survey data into a structured YAML codebook and a human-readable TXT frequency report.
It combines:
...into a single YAML codebook describing every variable's format, description, value distributions, related survey questions, and notes. That YAML can then be rendered into a clean text report.
This tool automates the labor-intensive process of documenting survey Public Use Files. Rather than hand-building a codebook for every new year's data release, the pipeline reads the raw survey CSV alongside format/label/notes lookup files and produces a consistent, auditable YAML codebook and companion TXT report — reducing manual transcription errors and making it straightforward to regenerate documentation whenever a new year's data arrives.
An automated, metadata pipeline where every Medicare Current Beneficiary Survey (MCBS) Public Use File (PUF) release is accompanied by an accurate, reproducible, and machine-readable codebook, eliminating manual documentation drift, reducing reliance on legacy SAS environments, and empowering researchers with open-access data standards.
Deliver a maintainable and version-controlled Python workflow that ingests raw, open-format CSV survey data and structured, human-editable YAML metadata to generate standardized, machine-readable codebooks and researcher-ready human-readable documentation.
This project supports the broader federal initiative of open source software development and transparency in government, aligning with the Federal Source Code Policy (M-16-21) which requires agencies to improve their code sharing practices.
Our team is committed to building tools that make open source compliance easier for federal development teams, focusing on automation and accuracy to reduce manual overhead.
A list of core team members responsible for the code and documentation in this repository can be found in COMMUNITY.md.
.
├── makeYaml.py # Step 1: builds the YAML codebook from source files
├── makeCodebook.py # Step 2: converts a YAML codebook into a TXT report
├── makeAll.py # Runs both steps end-to-end in one command
├── requirements.txt
├── codebook_SF_PUF_FALL_2023.txt # Sample TXT output generated from the new pipeline
├── codebook_SF_PUF_FALL_2023.yaml # Sample YAML intermediate generated from the new pipeline
├── reference_codebooks/ # Legacy SAS-generated reference codebooks for validation
│ ├── MCBSPUF_2023_1_fall.txt
│ ├── MCBSPUF_2023_2_winter.txt
│ └── MCBSPUF_2023_3_summer.txt
├── tests/
│ └── test_makeYaml.py # Unit tests for makeYaml.py
├── sample1/ # First sample input set (default argument paths)
│ ├── sfpuf2023_1_fall.csv # Source survey data (-f)
│ ├── puf_formats_2023.txt # Format/value catalog (-c)
│ ├── sfpuf2023_1_fall_formats.xlsx # Variable format lookup (--format-excel)
│ ├── sfpuf2023_1_fall_labels.xlsx # Variable label lookup (--label-excel)
│ └── PUFNotes2023.xlsx # Variable notes lookup (--notes-excel)
└── sample2/ # Second sample input set
├── cspuf2023.csv # Source survey data (-f)
├── cspuf_formats_2023.txt # Format/value catalog (-c)
├── cspuf2023_formats.xlsx # Variable format lookup (--format-excel)
├── cspuf2023_labels.xlsx # Variable label lookup (--label-excel)
└── PUFNotes2023.xlsx # Variable notes lookup (--notes-excel)
pandas>=3.0.3 pytest>=9.1.1 PyYAML>=6.0.3 openpyxl>=3.1.5
openpyxl is required because the Excel lookup files are read via pandas.read_excel(..., engine="openpyxl").
Install with:
pip install -r requirements.txt{
"-f, --file": {
"type": ".csv",
"description": "Source survey response data. Any filename is accepted as long as it has a .csv extension — there is no required naming pattern. Use -s/--file-name to control the tag baked into the output filename(s)."
},
"-c, --catalog": {
"type": ".txt",
"description": "PUF format catalog listing 'value <FORMAT_NAME>' blocks with 'code = \"label\"' mappings."
},
"--format-excel": {
"type": ".xlsx / .xls",
"description": "Maps each Variable to its Format name."
},
"--label-excel": {
"type": ".xlsx / .xls",
"description": "Maps each Variable to its descriptive Label."
},
"--notes-excel": {
"type": ".xlsx / .xls",
"description": "Contains per-variable notes (var_nm, qnbr, notes, notes2, notes3), matched on variable name only."
},
"-s, --file-name": {
"type": "string (optional)",
"description": "Optional tag used to name the output file(s), e.g. 'PUFFALL_2023' produces codebook_PUFFALL_2023.yaml. If omitted, a timestamp (YYYY-MM-DD_HHMMSS) is used instead. Present on makeYaml.py and makeAll.py."
},
"-o, --output-dir": {
"type": "directory",
"description": "Where the generated file(s) should be saved. Defaults to '.' (the current directory). Present on all three scripts — makeYaml.py, makeCodebook.py, and makeAll.py — and in makeAll.py it controls where both the .yaml and .txt outputs land."
}
}python makeYaml.py \
-f "sample1/sfpuf2023_1_fall.csv" \
-c "sample1/puf_formats_2023.txt" \
--format-excel "sample1/sfpuf2023_1_fall_formats.xlsx" \
--label-excel "sample1/sfpuf2023_1_fall_labels.xlsx" \
--notes-excel "sample1/PUFNotes2023.xlsx" \
-s "PUFFALL_2023" \
-o .Produces codebook_PUFFALL_2023.yaml in the output directory. The -s/--file-name flag is optional — it's just a tag used to name the output file. If you leave it off, the output falls back to a timestamped name (e.g. codebook_2026-07-27_193000.yaml), since the tool no longer derives a season/year from the input filename. All other arguments have defaults matching the paths above (all found in the sample1 folder), so running python makeYaml.py with no flags will use those defaults (and produce a timestamped output name).
python makeCodebook.py codebook_PUFFALL_2023.yamlProduces codebook_PUFFALL_2023.txt in the current directory — the output filename always mirrors the input YAML's basename with a .txt extension. Pass -o if you want it saved somewhere.
python makeAll.py \
-f "sample1/sfpuf2023_1_fall.csv" \
-c "sample1/puf_formats_2023.txt" \
--format-excel "sample1/sfpuf2023_1_fall_formats.xlsx" \
--label-excel "sample1/sfpuf2023_1_fall_labels.xlsx" \
--notes-excel "sample1/PUFNotes2023.xlsx" \
-s "PUFFALL_2023" \
-o .This runs makeYaml's codebook-building logic and immediately feeds the result into makeCodebook's report generator, producing both the .yaml and .txt outputs (sharing the same base filename) in one pass.
Like makeYaml.py, all of makeAll.py's arguments have defaults matching the paths above, so python makeAll.py with no flags at all will also work as long as your files live at those default locations — you'll just get a timestamped output name instead of a tagged one.
build_codebook_data() in makeYaml.py processes each column in the survey data as follows:
The result is dumped to YAML with one entry per variable, e.g.:
INT_SPPROXY:
format: PROXY
description: Self - respondent or proxy
value_distributions:
- code: 1
label: Self
frequency: 11437
- code: 2
label: Proxy
frequency: 1579
qnbr:
- IN4
notes: Results include all respondents.makeCodebook.py then walks that YAML and renders it as a formatted, fixed-width TXT report with a header, one section per variable, a code/label/frequency table, and any associated question numbers or notes.
If you need to add a variable, change a label, or add a code, edit the underlying source files directly — nothing is meant to be hand-edited in the generated YAML/TXT, since those are regenerated from scratch each run.
Note on multi-sheet workbooks: --format-excel, --label-excel, and --notes-excel are all loaded with pandas.read_excel() without a sheet_name argument, which defaults to reading only the first sheet in the workbook. If any of these files have more than one tab (e.g. one sheet per season, or a leftover "old data" tab), every sheet after the first is silently ignored — there's no warning if the data you actually need is sitting on sheet 2. Keep the data you want processed on the first sheet of each workbook.
Parsed line-by-line by parse_catalog(). The expected shape is:
value FORMAT_NAME
1 = "Yes"
2 = "No"
. = "Missing";
Rules to know when editing:
Must have at least two columns: Variable and Format. One row per survey column, mapping it to the format name that should match a value block in the catalog (periods are stripped and the value is uppercased before matching, so contin. and Contin both resolve to CONTIN).
Must have at least two columns: Variable and Label. One row per survey column with its human-readable description.
Must have at least these columns: var_nm, qnbr, notes, notes2, notes3. (file and yr columns may still exist in the sheet for your own record-keeping, but the pipeline no longer reads or filters on them.)
There's no year-specific logic hardcoded into the scripts, and the source CSV's filename is no longer parsed for anything — everything is driven purely by the file paths you pass in plus the optional -s/--file-name tag. To process a new year:
For example -
python makeAll.py \
-f "2024Data/sfpuf2024_1_fall.csv" \
-c "2024Data/puf_formats_2024.txt" \
--format-excel "2024Data/sfpuf2024_1_fall_formats.xlsx" \
--label-excel "2024Data/sfpuf2024_1_fall_labels.xlsx" \
--notes-excel "2024Data/PUFNotes2024.xlsx" \
-s "PUFFALL_2024" \
-o .Leaving off -s still works — you'll just get a timestamped filename like codebook_2026-07-27_193000.yaml instead of codebook_PUFFALL_2024.yaml. 7. Check the console output — any KeyError means a survey column is missing from the format or label Excel, or a format name isn't defined in the catalog. Fix the relevant lookup file and re-run.
pytest tests/The test suite covers:
python -m venv .venv
source .venv/bin/activate # on Windows: .venv\Scripts\activatepip install -r requirements.txtThis project uses Ruff for Python code linting and formatting to maintain consistent code quality, clean imports, and standard styling across the codebase.
Before committing your changes, ensure you have ruff installed in your Python environment:
pip install ruffThen, run the following commands in the root of the repository:
Check for lint errors and autofix common issues:
ruff check . --fixThis checks your code for syntax errors, unused imports, and style violations, automatically fixing what it can.
Format your code (rules matching Black):
ruff format .This automatically rewrites your files to match standard Python formatting rules.
This project follows GitHub Actions development practices. For information on contributing, see CONTRIBUTING.md.
This project follows trunk-based development:
Make small changes in short-lived feature branches and merge to main frequently Each change merged to main should be immediately deployable Pull requests are required for all changes Changes are deployed automatically via GitHub Actions
Thank you for considering contributing to an Open Source project of the US Government! For more information about our contribution guidelines, see CONTRIBUTING.md.
The contents of this repository are managed by DSACMS. Those responsible for the code and documentation in this repository can be found in COMMUNITY.md.
The PUF Codebook Generator team is taking a community-first and open source approach to the product development of this tool. We believe government software should be made in the open and be built and licensed such that anyone can download the code, run it themselves without paying money to third parties or using proprietary software, and use it as they will.
We know that we can learn from a wide variety of communities, including those who will use or will be impacted by the tool, who are experts in technology, or who have experience with similar technologies deployed in other spaces. We are dedicated to creating forums for continuous conversation and feedback to help shape the design and development of the tool.
We also recognize capacity building as a key part of involving a diverse open source community. We are doing our best to use accessible language, provide technical and process documents, and offer support to community members with a wide variety of backgrounds and skillsets.
Principles and guidelines for participating in our open source community can be found in COMMUNITY.md. Please read them before joining or starting a conversation in this repo or one of the channels listed below. All community members and participants are expected to adhere to the community guidelines and code of conduct when participating in community spaces including: code repositories, communication channels and venues, and events.
This project is governed by our Community Guidelines and Code of Conduct. We expect all contributors and maintainers to adhere to these standards to help ensure a welcoming, collaborative, and respectful environment for everyone.
If you have ideas for improvements or encounter any issues, please open an issue on our GitHub repository.
To help new contributors and researchers get up to speed, here are the key domain-specific terms used throughout this repository:
We adhere to the CMS Open Source Policy. If you have any questions, just shoot us an email.
For more information about our Security, Vulnerability, and Responsible Disclosure Policies, see SECURITY.md.
This project is in the public domain within the United States, and copyright and related rights in the work worldwide are waived through the CC0 1.0 Universal public domain dedication as indicated in LICENSE.
All contributions to this project will be released under the CC0 dedication. By submitting a pull request or issue, you are agreeing to comply with this waiver of copyright interest.
A Software Bill of Materials (SBOM) is a formal record containing the details and supply chain relationships of various components used in building software.
In the spirit of Executive Order 14028 - Improving the Nation's Cyber Security, a SBOM for this repository is provided here: https://github.com/DSACMS/code-book/network/dependencies.
For more information and resources about SBOMs, visit: https://www.cisa.gov/sbom.
| Back | FazBrowse Home | New Git URL |