diff --git a/IPython/core/application.py b/IPython/core/application.py index 048c766..ee9ada8 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -46,18 +46,22 @@ class IPythonArgParseConfigLoader(ArgParseConfigLoader): """Default command line options for IPython based applications.""" def _add_other_arguments(self): - self.parser.add_argument('-ipythondir',dest='Global.ipythondir',type=str, + self.parser.add_argument('-ipythondir', '--ipythondir', + dest='Global.ipythondir',type=str, help='Set to override default location of Global.ipythondir.', default=NoConfigDefault, metavar='Global.ipythondir') - self.parser.add_argument('-p','-profile',dest='Global.profile',type=str, + self.parser.add_argument('-p','-profile', '--profile', + dest='Global.profile',type=str, help='The string name of the ipython profile to be used.', default=NoConfigDefault, metavar='Global.profile') - self.parser.add_argument('-log_level',dest="Global.log_level",type=int, + self.parser.add_argument('-log_level', '--log-level', + dest="Global.log_level",type=int, help='Set the log level (0,10,20,30,40,50). Default is 30.', default=NoConfigDefault) - self.parser.add_argument('-config_file',dest='Global.config_file',type=str, + self.parser.add_argument('-config_file', '--config-file', + dest='Global.config_file',type=str, help='Set the config file name to override default.', default=NoConfigDefault, metavar='Global.config_file') diff --git a/IPython/core/display_trap.py b/IPython/core/display_trap.py index 2f9fc3b..78b9762 100644 --- a/IPython/core/display_trap.py +++ b/IPython/core/display_trap.py @@ -46,11 +46,11 @@ class DisplayTrap(Component): # Only turn off the trap when the outermost call to __exit__ is made. self._nested_level = 0 - @auto_attr - def shell(self): - return Component.get_instances( - root=self.root, - klass='IPython.core.iplib.InteractiveShell')[0] + # @auto_attr + # def shell(self): + # return Component.get_instances( + # root=self.root, + # klass='IPython.core.iplib.InteractiveShell')[0] def __enter__(self): if self._nested_level == 0: diff --git a/IPython/core/iplib.py b/IPython/core/iplib.py index 20eaaa4..c0bf8e0 100644 --- a/IPython/core/iplib.py +++ b/IPython/core/iplib.py @@ -1602,10 +1602,10 @@ class InteractiveShell(Component, Magic): else: magic_args = self.var_expand(magic_args,1) with nested(self.builtin_trap,): - result = fn(magic_args) + return fn(magic_args) # Unfortunately, the return statement is what will trigger # the displayhook, but it is no longer set! - return result + # return result def define_magic(self, magicname, func): """Expose own function as magic function for ipython diff --git a/IPython/core/magic.py b/IPython/core/magic.py index d06c9ab..75fd680 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -1268,7 +1268,6 @@ Currently the magic system has the following functions:\n""" If you want IPython to automatically do this on every exception, see the %pdb magic for more details. """ - self.shell.debugger(force=True) @testdec.skip_doctest diff --git a/IPython/kernel/fcutil.py b/IPython/kernel/fcutil.py index 9f7c730..4d6b310 100644 --- a/IPython/kernel/fcutil.py +++ b/IPython/kernel/fcutil.py @@ -1,27 +1,56 @@ +#!/usr/bin/env python # encoding: utf-8 +""" +Foolscap related utilities. +""" -"""Foolscap related utilities.""" - -__docformat__ = "restructuredtext en" - -#------------------------------------------------------------------------------- -# Copyright (C) 2008 The IPython Development Team +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. -#------------------------------------------------------------------------------- +#----------------------------------------------------------------------------- -#------------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # Imports -#------------------------------------------------------------------------------- +#----------------------------------------------------------------------------- import os +import tempfile + +from twisted.internet import reactor, defer +from twisted.python import log from foolscap import Tub, UnauthenticatedTub +from IPython.config.loader import Config + +from IPython.kernel.configobjfactory import AdaptedConfiguredObjectFactory + +from IPython.kernel.error import SecurityError + +from IPython.utils.traitlets import Int, Str, Bool, Instance +from IPython.utils.importstring import import_item + +#----------------------------------------------------------------------------- +# Code +#----------------------------------------------------------------------------- + + +# We do this so if a user doesn't have OpenSSL installed, it will try to use +# an UnauthenticatedTub. But, they will still run into problems if they +# try to use encrypted furls. +try: + import OpenSSL +except: + Tub = UnauthenticatedTub + have_crypto = False +else: + have_crypto = True + + def check_furl_file_security(furl_file, secure): """Remove the old furl_file if changing security modes.""" - if os.path.isfile(furl_file): f = open(furl_file, 'r') oldfurl = f.read().strip() @@ -29,7 +58,9 @@ def check_furl_file_security(furl_file, secure): if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure): os.remove(furl_file) + def is_secure(furl): + """Is the given FURL secure or not.""" if is_valid(furl): if furl.startswith("pb://"): return True @@ -38,14 +69,18 @@ def is_secure(furl): else: raise ValueError("invalid furl: %s" % furl) + def is_valid(furl): + """Is the str a valid furl or not.""" if isinstance(furl, str): if furl.startswith("pb://") or furl.startswith("pbu://"): return True else: return False + def find_furl(furl_or_file): + """Find, validate and return a FURL in a string or file.""" if isinstance(furl_or_file, str): if is_valid(furl_or_file): return furl_or_file @@ -55,15 +90,120 @@ def find_furl(furl_or_file): return furl raise ValueError("not a furl or a file containing a furl: %s" % furl_or_file) -# We do this so if a user doesn't have OpenSSL installed, it will try to use -# an UnauthenticatedTub. But, they will still run into problems if they -# try to use encrypted furls. -try: - import OpenSSL -except: - Tub = UnauthenticatedTub - have_crypto = False -else: - have_crypto = True +def get_temp_furlfile(filename): + """Return a temporary furl file.""" + return tempfile.mktemp(dir=os.path.dirname(filename), + prefix=os.path.basename(filename)) + + +def make_tub(ip, port, secure, cert_file): + """Create a listening tub given an ip, port, and cert_file location. + + Parameters + ---------- + ip : str + The ip address or hostname that the tub should listen on. + Empty means all interfaces. + port : int + The port that the tub should listen on. A value of 0 means + pick a random port + secure: bool + Will the connection be secure (in the Foolscap sense). + cert_file: str + A filename of a file to be used for theSSL certificate. + + Returns + ------- + A tub, listener tuple. + """ + if secure: + if have_crypto: + tub = Tub(certFile=cert_file) + else: + raise SecurityError("OpenSSL/pyOpenSSL is not available, so we " + "can't run in secure mode. Try running without " + "security using 'ipcontroller -xy'.") + else: + tub = UnauthenticatedTub() + + # Set the strport based on the ip and port and start listening + if ip == '': + strport = "tcp:%i" % port + else: + strport = "tcp:%i:interface=%s" % (port, ip) + listener = tub.listenOn(strport) + + return tub, listener + + +class FCServiceFactory(AdaptedConfiguredObjectFactory): + """This class creates a tub with various services running in it. + + The basic idea is that :meth:`create` returns a running :class:`Tub` + instance that has a number of Foolscap references registered in it. + This class is a subclass of :class:`IPython.core.component.Component` + so the IPython configuration and component system are used. + + Attributes + ---------- + Interfaces : Config + A Config instance whose values are sub-Config objects having two + keys: furl_file and interface_chain. + + The other attributes are the standard ones for Foolscap. +""" + + ip = Str('', config=True) + port = Int(0, config=True) + secure = Bool(True, config=True) + cert_file = Str('', config=True) + location = Str('', config=True) + Interfaces = Instance(klass=Config, kw={}, allow_none=False, config=True) + + def _ip_changed(self, name, old, new): + if new == 'localhost' or new == '127.0.0.1': + self.location = '127.0.0.1' + + def create(self): + """Create and return the Foolscap tub with everything running.""" + + self.tub, self.listener = make_tub( + self.ip, self.port, self.secure, self.cert_file) + if not self.secure: + log.msg("WARNING: running with no security: %s" % self.__class__.__name__) + reactor.callWhenRunning(self.set_location_and_register) + return self.tub + + def set_location_and_register(self): + """Set the location for the tub and return a deferred.""" + + if self.location == '': + d = self.tub.setLocationAutomatically() + else: + d = defer.maybeDeferred(self.tub.setLocation, + "%s:%i" % (self.location, self.listener.getPortnum())) + self.adapt_to_interfaces(d) + + def adapt_to_interfaces(self, d): + """Run through the interfaces, adapt and register.""" + + for ifname, ifconfig in self.Interfaces.iteritems(): + log.msg("Adapting %r to interface: %s" % (self.adaptee, ifname)) + log.msg("Saving furl for interface [%s] to file: %s" % (ifname, ifconfig.furl_file)) + check_furl_file_security(ifconfig.furl_file, self.secure) + adaptee = self.adaptee + for i in ifconfig.interface_chain: + adaptee = import_item(i)(adaptee) + d.addCallback(self.register, adaptee, furl_file=ifconfig.furl_file) + + def register(self, empty, ref, furl_file): + """Register the reference with the FURL file. + + The FURL file is created and then moved to make sure that when the + file appears, the buffer has been flushed and the file closed. + """ + temp_furl_file = get_temp_furlfile(furl_file) + self.tub.registerReference(ref, furlFile=temp_furl_file) + os.rename(temp_furl_file, furl_file) diff --git a/IPython/utils/traitlets.py b/IPython/utils/traitlets.py index 960c19c..30d6211 100644 --- a/IPython/utils/traitlets.py +++ b/IPython/utils/traitlets.py @@ -151,6 +151,26 @@ class _SimpleTest: return self.__repr__() +def getmembers(object, predicate=None): + """A safe version of inspect.getmembers that handles missing attributes. + + This is useful when there are descriptor based attributes that for + some reason raise AttributeError even though they exist. This happens + in zope.inteface with the __provides__ attribute. + """ + results = [] + for key in dir(object): + try: + value = getattr(object, key) + except AttributeError: + pass + else: + if not predicate or predicate(value): + results.append((key, value)) + results.sort() + return results + + #----------------------------------------------------------------------------- # Base TraitletType for all traitlets #----------------------------------------------------------------------------- @@ -316,6 +336,9 @@ class MetaHasTraitlets(type): This instantiates all TraitletTypes in the class dict and sets their :attr:`name` attribute. """ + # print "MetaHasTraitlets (mcls, name): ", mcls, name + # print "MetaHasTraitlets (bases): ", bases + # print "MetaHasTraitlets (classdict): ", classdict for k,v in classdict.iteritems(): if isinstance(v, TraitletType): v.name = k @@ -354,9 +377,16 @@ class HasTraitlets(object): # Here we tell all the TraitletType instances to set their default # values on the instance. for key in dir(cls): - value = getattr(cls, key) - if isinstance(value, TraitletType): - value.instance_init(inst) + # Some descriptors raise AttributeError like zope.interface's + # __provides__ attributes even though they exist. This causes + # AttributeErrors even though they are listed in dir(cls). + try: + value = getattr(cls, key) + except AttributeError: + pass + else: + if isinstance(value, TraitletType): + value.instance_init(inst) return inst # def __init__(self): @@ -475,7 +505,7 @@ class HasTraitlets(object): exists, but has any value. This is because get_metadata returns None if a metadata key doesn't exist. """ - traitlets = dict([memb for memb in inspect.getmembers(self.__class__) if \ + traitlets = dict([memb for memb in getmembers(self.__class__) if \ isinstance(memb[1], TraitletType)]) if len(metadata) == 0: