lucid.page Keep notice excerpts intact when converting CSV records to JSON Lines
Text size
Read time2 min

# Keep notice excerpts intact when converting CSV records to JSON Lines

Save this Python program as notice_csv_to_jsonl.py to turn a CSV of notice-source notes into JSON Lines. Text stays unchanged in each parsed cell, including line breaks within a quoted cell.

Contents

# Set up your source-note CSV

Include county, source_url, quoted_text, read_date and open_question as exact header names. Additional columns are retained in the JSON records. Empty or duplicate header names are rejected, and every nonblank record needs the same number of cells as the header.

The converter accepts empty cell values. It preserves surrounding whitespace in values. Blank CSV records are skipped; a header-only file produces no JSON records.

# Write the converted records

Run python3 notice_csv_to_jsonl.py notes.csv. The program reads UTF-8 files, including files with a byte-order mark. Use a single hyphen in place of notes.csv to read standard input.

The program reads the complete input before writing output. Each output line contains one JSON object with the column names as keys. Valid input returns exit status 0. Read, CSV or validation errors return status 1 and print a message to standard error.

Save output to a new filename with your shell’s normal redirection. Redirection can truncate an existing destination file before the converter checks the input; keep a separate copy of any output you need to retain.

# Review the source separately

The converter checks the record structure. It does not validate dates, visit URLs or compare an excerpt with a notice. A JSON record does not establish that a notice is current or sufficient. This software is not legal or financial advice.

# Publisher

Tax Sale Atlas publishes this notice-record converter. Keep the complete source and its MIT license together when copying it.

Source record: Notice-source CSV converter; publisher: Tax Sale Atlas; publication date: undated authored software, copyright 2026; source: complete original Python below.

# Complete source

python
#!/usr/bin/env python3
"""Convert county-notice source-note CSV rows to JSON Lines without changing cells."""
import argparse
import csv
import json
import sys

FIELDS = {'county', 'source_url', 'quoted_text', 'read_date', 'open_question'}


def convert(stream):
    reader = csv.reader(stream, strict=True)
    header = next(reader, None)
    if header is None:
        raise ValueError('CSV header is missing')
    if any(not name.strip() for name in header):
        raise ValueError('CSV header contains an empty field name')
    if len(header) != len(set(header)):
        raise ValueError('CSV header contains a duplicate field name')
    missing = sorted(FIELDS - set(header))
    if missing:
        raise ValueError('Missing source-note columns: ' + ', '.join(missing))
    output = []
    for index, row in enumerate(reader, 2):
        if not row:
            continue
        if len(row) != len(header):
            raise ValueError(f'CSV record {index} has {len(row)} cells; expected {len(header)}')
        output.append(json.dumps(dict(zip(header, row)), ensure_ascii=False))
    return output


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('csv_file', help='UTF-8 CSV file, or - for standard input')
    args = parser.parse_args()
    try:
        if args.csv_file == '-':
            lines = convert(sys.stdin)
        else:
            with open(args.csv_file, encoding='utf-8-sig', newline='') as stream:
                lines = convert(stream)
    except (OSError, UnicodeError, csv.Error, ValueError) as error:
        print(f'notice-csv-to-jsonl: {error}', file=sys.stderr)
        return 1
    if lines:
        sys.stdout.write('\n'.join(lines) + '\n')
    return 0


if __name__ == '__main__':
    sys.exit(main())

# License

text
MIT License

Copyright (c) 2026 Tax Sale Atlas Tools

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
End