Source code for gerrytools.utilities.JSON

import json
from typing import Any

from pydantic import BaseModel, field_validator


[docs] class JSONtoObject(BaseModel): """ Plan specification models. To better work with multiple plans at once, this plan specification allows users to specify information which should remain consistent across all operations; for example, the `column` field should be the name of the column in which the corresponding plan's assignment is stored across all data products. """ column: str """ Column on all data products which contains district assignment information for this districting plan. """ locator: str """ File/directory name for all resources which contain information about this districting plan. """ title: Any = None """ Official title of the plan. """ type: str = None """ The "type" of plan; could denote a party affiliation, a chamber, whatever. """ @field_validator("column") def _validate_column(cls, column): """ Validates the specified column name. For most of our purposes, we cannot include spaces, hyphens, percent signs, and other commonly-used special characters. Furthermore, because these plans are often saved in shapefiles, which have a 10-character column name limit, we force column names to be 10 or fewer characters. """ # Check for column length. if len(column) > 10: raise ValueError(f"Column name {column} exceeds 10-character limit.") # Check for illegal characters. illegal = {"/", "%", "-", "–", "—", " "} for c in illegal: if c in column: raise ValueError(f"Character {c} cannot be in column name.") return column
[docs] def jsonify(location) -> list: """ Reads in JSON data and creates a Python object out of it. If the JSON data read in is a list of JSON objects, a list of Python objects are returned. Args: location (string): Filepath. Returns: A list of pydantic dot-notation-accesible objects, which should contain information about districting plans. """ with open(location) as r: data = json.load(r) # First, check whether `data` is a list; if it is, deal with all the # plans individually and return the list. if isinstance(data, list): return [ JSONtoObject( column=p["column"], locator=p["locator"], title=p["title"] if p.get("title", False) else None, type=p["type"] if p.get("type", False) else None, ) for p in data ] # Otherwise, return a singleton list with a single plan. return [ JSONtoObject( column=data["column"], locator=data["locator"], title=data["title"] if data.get("title", False) else None, ) ]