text: from __future__ import annotations
  
  from dataclasses import dataclass
  from typing import Any, Mapping, Optional
  
  from .util import parse_option_field
  
  # replace these dataclass models with pydantic
  # if this gets too complex
  
  
  @dataclass(frozen=True)
  class CoverageSummaryModel:
      covered_lines: int
      num_statements: int
      num_branches: Optional[int] = None
      covered_branches: Optional[int] = None
  
      @staticmethod
      def parse(obj: Any) -> CoverageSummaryModel:
          return CoverageSummaryModel(
              covered_lines=int(obj["covered_lines"]),
              num_statements=int(obj["num_statements"]),
              num_branches=parse_option_field(obj, int, "num_branches"),
              covered_branches=parse_option_field(obj, int, "covered_branches"),
          )
  
  
  @dataclass(frozen=True)
  class FileCoverageModel:
      summary: CoverageSummaryModel
  
      @staticmethod
      def parse(obj: Any) -> FileCoverageModel:
          return FileCoverageModel(summary=CoverageSummaryModel.parse(obj["summary"]))
  
  
  @dataclass(frozen=True)
  class ReportMetadata:
      branch_coverage: bool
  
      @staticmethod
      def parse(obj: Any) -> ReportMetadata:
          return ReportMetadata(branch_coverage=bool(obj["branch_coverage"]))
  
  
  @dataclass(frozen=True)
  class ReportModel:
      files: Mapping[str, FileCoverageModel]
      totals: CoverageSummaryModel
      meta: ReportMetadata
  
      @staticmethod
      def parse(obj: Any) -> ReportModel:
          return ReportModel(
              files={
                  filename: FileCoverageModel.parse(value)
                  for filename, value in obj["files"].items()
              },
              totals=CoverageSummaryModel.parse(obj["totals"]),
              meta=ReportMetadata.parse(obj["meta"]),
          )
  