##// END OF EJS Templates
More informative failure when passing bytes to a Unicode traitlet
More informative failure when passing bytes to a Unicode traitlet

File last commit:

r9140:06edb0ca
r13734:6c5e8f35
Show More
compilerop.py
144 lines | 5.8 KiB | text/x-python | PythonLexer
Fernando Perez
Complete implementation of interactive traceback support....
r3175 """Compiler tools with improved interactive support.
Provides compilation machinery similar to codeop, but with caching support so
we can provide interactive tracebacks.
Authors
-------
* Robert Kern
* Fernando Perez
Thomas Kluyver
Change integer options to string options for interactivity.
r3533 * Thomas Kluyver
Fernando Perez
Complete implementation of interactive traceback support....
r3175 """
# Note: though it might be more natural to name this module 'compiler', that
# name is in the stdlib and name collisions with the stdlib tend to produce
# weird problems (often with third-party tools).
#-----------------------------------------------------------------------------
Matthias BUSSONNIER
update copyright to 2011/20xx-2011...
r5390 # Copyright (C) 2010-2011 The IPython Development Team.
Fernando Perez
Complete implementation of interactive traceback support....
r3175 #
# Distributed under the terms of the BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from __future__ import print_function
# Stdlib imports
Bradley M. Froehle
embed(): Default to the future compile flags of the calling frame.
r7894 import __future__
Thomas Kluyver
Parse user code to AST using compiler flags....
r4795 from ast import PyCF_ONLY_AST
Fernando Perez
Complete implementation of interactive traceback support....
r3175 import codeop
Bradley M. Froehle
embed(): Default to the future compile flags of the calling frame.
r7894 import functools
Fernando Perez
Complete implementation of interactive traceback support....
r3175 import hashlib
import linecache
Bradley M. Froehle
embed(): Default to the future compile flags of the calling frame.
r7894 import operator
Fernando Perez
Complete implementation of interactive traceback support....
r3175 import time
#-----------------------------------------------------------------------------
Bradley M. Froehle
embed(): Default to the future compile flags of the calling frame.
r7894 # Constants
#-----------------------------------------------------------------------------
# Roughtly equal to PyCF_MASK | PyCF_MASK_OBSOLETE as defined in pythonrun.h,
# this is used as a bitmask to extract future-related code flags.
PyCF_MASK = functools.reduce(operator.or_,
(getattr(__future__, fname).compiler_flag
for fname in __future__.all_feature_names))
#-----------------------------------------------------------------------------
Fernando Perez
Complete implementation of interactive traceback support....
r3175 # Local utilities
#-----------------------------------------------------------------------------
def code_name(code, number=0):
""" Compute a (probably) unique name for code for caching.
Thomas Kluyver
Fix compilerop to handle unicode input.
r3442
This now expects code to be unicode.
Fernando Perez
Complete implementation of interactive traceback support....
r3175 """
Thomas Kluyver
Fix compilerop to handle unicode input.
r3442 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
Fernando Perez
Complete implementation of interactive traceback support....
r3175 # Include the number and 12 characters of the hash in the name. It's
# pretty much impossible that in a single session we'll have collisions
# even with truncated hashes, and the full one makes tracebacks too long
return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
#-----------------------------------------------------------------------------
# Classes and functions
#-----------------------------------------------------------------------------
Thomas Kluyver
Replace run_cell method, and fix up caching compiler so we can cache a string, then compile AST nodes.
r3529 class CachingCompiler(codeop.Compile):
Fernando Perez
Complete implementation of interactive traceback support....
r3175 """A compiler that caches code compiled from interactive statements.
"""
def __init__(self):
Thomas Kluyver
Replace run_cell method, and fix up caching compiler so we can cache a string, then compile AST nodes.
r3529 codeop.Compile.__init__(self)
Fernando Perez
Complete implementation of interactive traceback support....
r3175
# This is ugly, but it must be done this way to allow multiple
# simultaneous ipython instances to coexist. Since Python itself
# directly accesses the data structures in the linecache module, and
# the cache therein is global, we must work with that data structure.
# We must hold a reference to the original checkcache routine and call
# that in our own check_cache() below, but the special IPython cache
# must also be shared by all IPython instances. If we were to hold
# separate caches (one in each CachingCompiler instance), any call made
# by Python itself to linecache.checkcache() would obliterate the
# cached data from the other IPython instances.
if not hasattr(linecache, '_ipython_cache'):
linecache._ipython_cache = {}
if not hasattr(linecache, '_checkcache_ori'):
linecache._checkcache_ori = linecache.checkcache
# Now, we must monkeypatch the linecache directly so that parts of the
# stdlib that call it outside our control go through our codepath
# (otherwise we'd lose our tracebacks).
Thomas Kluyver
Better support compiling cells with separate __future__ environments
r9140 linecache.checkcache = check_linecache_ipython
Thomas Kluyver
Parse user code to AST using compiler flags....
r4795
def ast_parse(self, source, filename='<unknown>', symbol='exec'):
Thomas Kluyver
Describe arguments for CachingCompiler.ast_parse
r4796 """Parse code to an AST with the current compiler flags active.
Arguments are exactly the same as ast.parse (in the standard library),
and are passed to the built-in compile function."""
Thomas Kluyver
Parse user code to AST using compiler flags....
r4795 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
def reset_compiler_flags(self):
"""Reset compiler flags to default state."""
# This value is copied from codeop.Compile.__init__, so if that ever
# changes, it will need to be updated.
self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
Fernando Perez
Complete implementation of interactive traceback support....
r3175
@property
def compiler_flags(self):
"""Flags currently active in the compilation process.
"""
Thomas Kluyver
Replace run_cell method, and fix up caching compiler so we can cache a string, then compile AST nodes.
r3529 return self.flags
def cache(self, code, number=0):
"""Make a name for a block of code, and cache the code.
Fernando Perez
Complete implementation of interactive traceback support....
r3175
Parameters
----------
code : str
Thomas Kluyver
Replace run_cell method, and fix up caching compiler so we can cache a string, then compile AST nodes.
r3529 The Python source code to cache.
number : int
A number which forms part of the code's name. Used for the execution
counter.
Returns
-------
The name of the cached code (as a string). Pass this as the filename
argument to compilation, so that tracebacks are correctly hooked up.
Fernando Perez
Complete implementation of interactive traceback support....
r3175 """
name = code_name(code, number)
entry = (len(code), time.time(),
[line+'\n' for line in code.splitlines()], name)
linecache.cache[name] = entry
linecache._ipython_cache[name] = entry
Thomas Kluyver
Replace run_cell method, and fix up caching compiler so we can cache a string, then compile AST nodes.
r3529 return name
Fernando Perez
Complete implementation of interactive traceback support....
r3175
Thomas Kluyver
Better support compiling cells with separate __future__ environments
r9140 def check_linecache_ipython(*args):
"""Call linecache.checkcache() safely protecting our cached values.
"""
# First call the orignal checkcache as intended
linecache._checkcache_ori(*args)
# Then, update back the cache with our data, so that tracebacks related
# to our compiled codes can be produced.
linecache.cache.update(linecache._ipython_cache)