attrs.py 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. from __future__ import annotations
  2. from typing import List
  3. def get_attr(obj, path: str | List[str]):
  4. """
  5. Get an attribute from an object using a dot-separated path.
  6. :param obj: The object to get the attribute from.
  7. :param path: A string representing the path to the attribute (e.g., 'a.b.c', 'a.b.0.c').
  8. :return: The value of the attribute.
  9. """
  10. if obj is None:
  11. return None
  12. if isinstance(path, str):
  13. return get_attr(obj, path.split('.'))
  14. p = path[0]
  15. if (p.isdigit() or p == "-1") and isinstance(obj, list):
  16. obj = obj[int(p)]
  17. elif isinstance(obj, dict):
  18. obj = obj.get(p, None)
  19. else:
  20. obj = getattr(obj, p, None)
  21. return get_attr(obj, path[1:]) if len(path) > 1 else obj
  22. def set_attr(obj, path: str | List[str], value):
  23. """
  24. Set an attribute on an object using a dot-separated path.
  25. :param obj: The object to set the attribute on.
  26. :param path: A string representing the path to the attribute (e.g., 'a.b.c', 'a.b.0.c').
  27. :param value: The value to set the attribute to.
  28. """
  29. if isinstance(path, str):
  30. set_attr(obj, path.split('.'), value)
  31. return
  32. if obj is None:
  33. return None
  34. if len(path) > 1:
  35. obj = get_attr(obj, path[:-1])
  36. if obj is None:
  37. return None
  38. p = path[-1]
  39. if (p.isdigit() or p == "-1") and isinstance(obj, list):
  40. while len(obj) <= int(p):
  41. obj.append(None)
  42. obj[int(p)] = value
  43. elif isinstance(obj, dict):
  44. obj[p] = value
  45. elif hasattr(obj, p):
  46. setattr(obj, p, value)