util.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. # Python repr() for complex numbers, and a little broken for floats.
  2. # Until such time it is fixed, we'll do a better.
  3. # More could be done here though.
  4. from math import copysign
  5. from xdis.cross_types import UnicodeForPython3
  6. from xdis.version_info import PYTHON_VERSION_TRIPLE
  7. def get_code_name(code) -> str:
  8. code_name = code.co_name
  9. if isinstance(code_name, UnicodeForPython3):
  10. return code_name.value.decode("utf-8")
  11. return code_name
  12. def is_negative_zero(n):
  13. """Returns true if n is -0.0"""
  14. return n == 0.0 and copysign(1, n) == -1
  15. def better_repr(v, version):
  16. """Work around Python's unorthogonal and unhelpful repr() for primitive float
  17. and complex."""
  18. if isinstance(v, float):
  19. # float values 'nan' and 'inf' are not directly
  20. # representable in Python before Python 3.5. In Python 3.5
  21. # it is accessible via a library constant math.inf. We
  22. # will canonicalize representation of these value as
  23. # float('nan') and float('inf')
  24. if str(v) in frozenset(["nan", "-nan", "inf", "-inf"]):
  25. return "float('%s')" % v
  26. elif is_negative_zero(v):
  27. return "-0.0"
  28. return repr(v)
  29. elif isinstance(v, complex):
  30. real = better_repr(v.real, version)
  31. imag = better_repr(v.imag, version)
  32. # FIXME: we could probably use repr() in most cases
  33. # sort out when that's possible.
  34. # The below is however round-tripable, and Python's repr() isn't.
  35. return "complex(%s, %s)" % (real, imag)
  36. elif isinstance(v, tuple):
  37. if len(v) == 1:
  38. return "(%s,)" % better_repr(v[0], version)
  39. return "(%s)" % ", ".join(better_repr(i, version) for i in v)
  40. elif PYTHON_VERSION_TRIPLE < (3, 0) and isinstance(v, long):
  41. s = repr(v)
  42. if version >= 3.0 and s[-1] == "L":
  43. return s[:-1]
  44. else:
  45. return s
  46. elif isinstance(v, list):
  47. if len(v) == 1:
  48. return "[%s,]" % better_repr(v[0], version)
  49. return "[%s]" % ", ".join(better_repr(i) for i in v)
  50. # TODO: elif deal with sets and dicts
  51. else:
  52. return repr(v)