json.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. # json.py/Open GoPro, Version 2.0 (C) Copyright 2021 GoPro, Inc. (http://gopro.com/OpenGoPro).
  2. # This copyright was auto-generated on Mon Apr 21 22:24:00 UTC 2025
  3. """JSON Parser and Transformer implementations"""
  4. from __future__ import annotations
  5. import logging
  6. from typing import Callable, TypeVar, cast
  7. from construct import FormatFieldError
  8. from pydantic import BaseModel
  9. from open_gopro.domain.communicator_interface import GlobalParsers
  10. from open_gopro.domain.parser_interface import JsonParser, JsonTransformer
  11. from open_gopro.models.constants import SettingId, StatusId
  12. from open_gopro.models.types import CameraState, JsonDict, ResponseType
  13. from open_gopro.util import map_keys
  14. T = TypeVar("T")
  15. logger = logging.getLogger()
  16. class CameraStateJsonParser(JsonParser):
  17. """Parse integer numbers into Enums"""
  18. def parse(self, data: JsonDict) -> CameraState:
  19. """Parse dict of integer values into human readable (i.e. enum'ed) setting / status map
  20. Args:
  21. data (JsonDict): input dict to parse
  22. Returns:
  23. CameraState: output human readable dict
  24. """
  25. parsed: dict = {}
  26. # Parse status and settings values into nice human readable things
  27. for name, id_map in [("status", StatusId), ("settings", SettingId)]:
  28. for k, v in data[name].items():
  29. try:
  30. identifier = cast(ResponseType, id_map(int(k)))
  31. if not (parser_builder := GlobalParsers.get_query_container(identifier)):
  32. parsed[identifier] = v
  33. else:
  34. parsed[identifier] = parser_builder(v)
  35. except (ValueError, FormatFieldError) as e:
  36. logger.trace(f"Error Parsing {name}::{k}, value: {v} ==> {repr(e)}") # type: ignore
  37. continue
  38. return parsed
  39. class PydanticAdapterJsonParser(JsonParser[BaseModel]):
  40. """Parse Json using a Pydantic model
  41. Args:
  42. model (type[BaseModel]): model to use for parsing
  43. """
  44. def __init__(self, model: type[BaseModel]) -> None:
  45. self.model = model
  46. def parse(self, data: JsonDict) -> BaseModel:
  47. """Parse json dict into model
  48. Args:
  49. data (JsonDict): data to parse
  50. Returns:
  51. BaseModel: parsed model
  52. """
  53. return self.model(**data)
  54. class LambdaJsonParser(JsonParser[T]):
  55. """Helper class to allow parser definition using a lambda
  56. Args:
  57. parser (Callable[[JsonDict], T]): lambda to parse input
  58. """
  59. def __init__(self, parser: Callable[[JsonDict], T]) -> None:
  60. self._parser = parser
  61. def parse(self, data: JsonDict) -> T:
  62. """Use stored lambda parse for parsing
  63. Args:
  64. data (JsonDict): input dict to parse
  65. Returns:
  66. T: parsed output
  67. """
  68. return self._parser(data)
  69. class MapJsonKey(JsonTransformer):
  70. """Map all matching keys using the input function"""
  71. def __init__(self, key: str, func: Callable) -> None:
  72. self.key = key
  73. self.func = func
  74. super().__init__()
  75. def transform(self, data: JsonDict) -> JsonDict:
  76. """Transform json, mapping keys
  77. Args:
  78. data (JsonDict): json data to transform
  79. Returns:
  80. JsonDict: transformed json data
  81. """
  82. map_keys(data, self.key, self.func)
  83. return data