You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

56 lines
1.6 KiB

4 years ago
  1. from decimal import Decimal
  2. from uuid import UUID
  3. import datetime
  4. from dateutil.parser import parse as parse_date
  5. from requests.compat import urlparse
  6. TRUTHY_VALS = {'true', 'yes', '1'}
  7. DT_RET = {'char', 'string', 'bin.base64', 'bin.hex'}
  8. DT_INT = {'ui1', 'ui2', 'ui4', 'i1', 'i2', 'i4'}
  9. DT_DECIMAL = {'r4', 'r8', 'number', 'float', 'fixed.14.4'}
  10. DT_DATE = {'date'}
  11. DT_DATETIME = {'dateTime', 'dateTime.tz'}
  12. DT_TIME = {'time', 'time.tz'}
  13. DT_BOOL = {'boolean'}
  14. DT_URI = {'uri'}
  15. DT_UUID = {'uuid'}
  16. def parse_time(val):
  17. """
  18. Parse a time to a `datetime.time` value.
  19. Can't just use `dateutil.parse.parser(val).time()` because that doesn't preserve tzinfo.
  20. """
  21. dt = parse_date(val)
  22. if dt.tzinfo is None:
  23. return dt.time()
  24. return datetime.time(dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
  25. MARSHAL_FUNCTIONS = (
  26. (DT_RET, lambda x: x),
  27. (DT_INT, int),
  28. (DT_DECIMAL, Decimal),
  29. (DT_DATE, lambda x: parse_date(x).date()),
  30. (DT_DATETIME, parse_date),
  31. (DT_TIME, parse_time),
  32. (DT_BOOL, lambda x: x.lower() in TRUTHY_VALS),
  33. (DT_URI, urlparse),
  34. (DT_UUID, UUID)
  35. )
  36. def marshal_value(datatype, value):
  37. """
  38. Marshal a given string into a relevant Python type given the uPnP datatype.
  39. Assumes that the value has been pre-validated, so performs no checks.
  40. Returns a tuple pair of a boolean to say whether the value was marshalled and the (un)marshalled
  41. value.
  42. """
  43. for types, func in MARSHAL_FUNCTIONS:
  44. if datatype in types:
  45. return True, func(value)
  46. return False, value