Get the mapping of free variables to their current values. Returns a named tuple of dicts mapping the current nonlocal, global and builtin references as seen by the body of the function. A final set of unbound names that could not be resolved is also provided.
(func)
| 1508 | ClosureVars = namedtuple('ClosureVars', 'nonlocals globals builtins unbound') |
| 1509 | |
| 1510 | def getclosurevars(func): |
| 1511 | """ |
| 1512 | Get the mapping of free variables to their current values. |
| 1513 | |
| 1514 | Returns a named tuple of dicts mapping the current nonlocal, global |
| 1515 | and builtin references as seen by the body of the function. A final |
| 1516 | set of unbound names that could not be resolved is also provided. |
| 1517 | """ |
| 1518 | |
| 1519 | if ismethod(func): |
| 1520 | func = func.__func__ |
| 1521 | |
| 1522 | if not isfunction(func): |
| 1523 | raise TypeError("{!r} is not a Python function".format(func)) |
| 1524 | |
| 1525 | code = func.__code__ |
| 1526 | # Nonlocal references are named in co_freevars and resolved |
| 1527 | # by looking them up in __closure__ by positional index |
| 1528 | if func.__closure__ is None: |
| 1529 | nonlocal_vars = {} |
| 1530 | else: |
| 1531 | nonlocal_vars = { |
| 1532 | var : cell.cell_contents |
| 1533 | for var, cell in zip(code.co_freevars, func.__closure__) |
| 1534 | } |
| 1535 | |
| 1536 | # Global and builtin references are named in co_names and resolved |
| 1537 | # by looking them up in __globals__ or __builtins__ |
| 1538 | global_ns = func.__globals__ |
| 1539 | builtin_ns = global_ns.get("__builtins__", builtins.__dict__) |
| 1540 | if ismodule(builtin_ns): |
| 1541 | builtin_ns = builtin_ns.__dict__ |
| 1542 | global_vars = {} |
| 1543 | builtin_vars = {} |
| 1544 | unbound_names = set() |
| 1545 | global_names = set() |
| 1546 | for instruction in dis.get_instructions(code): |
| 1547 | opname = instruction.opname |
| 1548 | name = instruction.argval |
| 1549 | if opname == "LOAD_ATTR": |
| 1550 | unbound_names.add(name) |
| 1551 | elif opname == "LOAD_GLOBAL": |
| 1552 | global_names.add(name) |
| 1553 | for name in global_names: |
| 1554 | try: |
| 1555 | global_vars[name] = global_ns[name] |
| 1556 | except KeyError: |
| 1557 | try: |
| 1558 | builtin_vars[name] = builtin_ns[name] |
| 1559 | except KeyError: |
| 1560 | unbound_names.add(name) |
| 1561 | |
| 1562 | return ClosureVars(nonlocal_vars, global_vars, |
| 1563 | builtin_vars, unbound_names) |
| 1564 | |
| 1565 | # -------------------------------------------------- stack frame extraction |
| 1566 |
nothing calls this directly
no test coverage detected
searching dependent graphs…