| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- # Much of this is borrowed from Python's ``Lib/dis.py``.
- from math import copysign
- from typing import Dict
- def code2num(code, i):
- if isinstance(code, str):
- return ord(code[i])
- else:
- return code[i]
- def num2code(num):
- return num & 0xFF, num >> 8
- # The `inspect` module interrogates this dictionary to build its
- # list of CO_* constants. It is also used by pretty_flags to
- # turn the co_flags field into a human-readable list.
- COMPILER_FLAG_NAMES = {
- 0x00000001: "OPTIMIZED",
- 0x00000002: "NEWLOCALS",
- 0x00000004: "VARARGS",
- 0x00000008: "VARKEYWORDS",
- 0x00000010: "NESTED",
- 0x00000020: "GENERATOR",
- 0x00000040: "NOFREE",
- # These are in Python 3.5 +
- 0x00000080: "COROUTINE",
- 0x00000100: "ITERABLE_COROUTINE",
- # These are in Python 3.6+
- 0x00000200: "ASYNC_GENERATOR",
- # These are used only in Python 2.x */
- 0x00001000: "GENERATOR_ALLOWED",
- 0x00002000: "FUTURE_DIVISION",
- 0x00004000: "ABSOLUTE_IMPORT",
- 0x00008000: "FUTURE_WITH_STATEMENT",
- 0x00010000: "FUTURE_PRINT_FUNCTION",
- 0x00020000: "FUTURE_UNICODE_LITERALS",
- 0x00040000: "FUTURE_BARRY_AS_DBFL",
- 0x00080000: "FUTURE_GENERATOR_STOP",
- 0x00100000: "FUTURE_ANNOTATIONS",
- }
- # These are PYPY specific
- PYPY_COMPILER_FLAG_NAMES = {
- 0x00100000: "PYPY_KILL_DOCSTRING",
- 0x00200000: "PYPY_YIELD_INSIDE_TRY",
- 0x00000400: "PYPY_ONLY_AST",
- 0x00000800: "PYPY_IGNORE_COOKIE",
- 0x10000000: "PYPY_ACCEPT_NULL_BYTES",
- }
- # Invert above dictionary, so we can look up a bit value
- # from the "compile" flag name
- COMPILER_FLAG_BIT: Dict[str, int] = dict(
- (v, k) for (k, v) in COMPILER_FLAG_NAMES.items()
- )
- # Allow us to access by just name, prefixed with CO., e.g.,
- # CO_OPTIMIZED, CO_NOFREE.
- globals().update(dict(("CO_" + k, v) for (k, v) in COMPILER_FLAG_BIT.items()))
- def co_flags_is_async(co_flags):
- """
- Return True iff co_flags indicates an async function.
- """
- return co_flags & (
- COMPILER_FLAG_BIT["COROUTINE"]
- | COMPILER_FLAG_BIT["ITERABLE_COROUTINE"]
- | COMPILER_FLAG_BIT["ASYNC_GENERATOR"]
- )
- def code_has_star_arg(code) -> bool:
- """
- Return True iff the code object has a variable positional parameter
- (*args-like)
- """
- return (code.co_flags & 4) != 0
- def code_has_star_star_arg(code):
- """Return True iff
- The code object has a variable keyword parameter (**kwargs-like)."""
- return (code.co_flags & 8) != 0
- def is_negative_zero(n: float) -> bool:
- """Returns true if n is -0.0"""
- return n == 0.0 and copysign(1, n) == -1
- def better_repr(v: float) -> str:
- """Work around Python's not orthogonal and unhelpful repr() for primitive float
- and complex."""
- if isinstance(v, float):
- # Float values 'nan' and 'inf' are not directly
- # representable in Python before Python 3.5. In Python 3.5
- # it is accessible via a library constant math.inf. We
- # will canonicalize representation of these value as
- # float('nan') and float('inf')
- if str(v) in frozenset(["nan", "-nan", "inf", "-inf"]):
- return "float('%s')" % v
- elif is_negative_zero(v):
- return "-0.0"
- return repr(v)
- elif isinstance(v, complex):
- real = better_repr(v.real)
- imag = better_repr(v.imag)
- # FIXME: we could probably use repr() in most cases
- # sort out when that's possible.
- # The below round trips, and Python's repr() isn't.
- return "complex(%s, %s)" % (real, imag)
- elif isinstance(v, tuple):
- if len(v) == 1:
- return "(%s,)" % better_repr(v[0])
- return "(%s)" % ", ".join(better_repr(i) for i in v)
- elif isinstance(v, list):
- if len(v) == 1:
- return "[%s,]" % better_repr(v[0])
- return "[%s]" % ", ".join(better_repr(i) for i in v)
- # TODO: elif deal with sets and dicts
- else:
- return repr(v)
|