Skip to content
Merged
2 changes: 1 addition & 1 deletion IPython/config/configurable.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class defaults.
final_help = []
final_help.append(u'%s options' % cls.__name__)
final_help.append(len(final_help[0])*u'-')
for k,v in cls.class_traits(config=True).iteritems():
for k,v in sorted(cls.class_traits(config=True).iteritems()):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this adds cost to all instances only for the benefit of a doctest. Instead, the test should be changed, to not depend on the order (it can do a set check on both keys and values, for example.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this affects how the options for help are printed - I think it's awkward to have the options displayed in a random order each time you do something like ipython --help-all.

Given that this method is only called to display help information (class_get_help()), I think the cost of Python's built in sort is going to be negligible compared to the speed with which output can be written. This was probably the place I was most confident that sorting was the right way to go.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't realize this was inside of a method called for interactive help, sorry. For some reason I thought it was in the constructor itself and that it would thus affect everything all the time.

Yes, I agree that if it's only invoked interactively at help time, it's OK. Sorry for the misfire.

help = cls.class_get_trait_help(v, inst)
final_help.append(help)
return '\n'.join(final_help)
Expand Down
5 changes: 3 additions & 2 deletions IPython/config/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,9 @@ def __init__(self, argv=None, aliases=None, flags=None):

>>> from IPython.config.loader import KeyValueConfigLoader
>>> cl = KeyValueConfigLoader()
>>> cl.load_config(["--A.name='brian'","--B.number=0"])
{'A': {'name': 'brian'}, 'B': {'number': 0}}
>>> d = cl.load_config(["--A.name='brian'","--B.number=0"])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following up with the previous line: if it's awkward for this to pass as a doctest, I'd rather just remove it from being a doctest (leave it as an example, mark it with @skip_doctest) than paying the price of a dict sort in the bottom-most class behind all our configurables.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no runtime cost in this case, because the sorting's in a docstring, but I can skip_doctest it if you prefer to keep the example clean.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, I only meant it if it would cause you extra grief to make the doctests pass. I don't think that is too bad in that mode, so I'm fine leaving it.

>>> sorted(d.items())
[('A', {'name': 'brian'}), ('B', {'number': 0})]
"""
self.clear()
if argv is None:
Expand Down
8 changes: 4 additions & 4 deletions IPython/core/excolors.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ def exception_colors():
>>> ec.set_active_scheme('NoColor')
>>> ec.active_scheme_name
'NoColor'
>>> ec.active_colors.keys()
['em', 'filenameEm', 'excName', 'valEm', 'nameEm', 'line', 'topline',
'name', 'caret', 'val', 'vName', 'Normal', 'filename', 'linenoEm',
'lineno', 'normalEm']
>>> sorted(ec.active_colors.keys())
['Normal', 'caret', 'em', 'excName', 'filename', 'filenameEm', 'line',
'lineno', 'linenoEm', 'name', 'nameEm', 'normalEm', 'topline', 'vName',
'val', 'valEm']
"""

ex_colors = ColorSchemeTable()
Expand Down
7 changes: 6 additions & 1 deletion IPython/core/magics/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,12 @@ def timeit(self, line='', cell=None):
setup = timeit.reindent(stmt, 4)
stmt = timeit.reindent(cell, 8)

src = timeit.template % dict(stmt=stmt, setup=setup)
# From Python 3.3, this template uses new-style string formatting.
if sys.version_info >= (3, 3):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why make this version dependent? It seems to me we could just move to the new form for all versions, since .format exists in 2.6, no?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But timeit.template uses the % style formatting syntax up to and including Python 3.2. I think it's better to keep using the stdlib code than to carry our own copy of the template.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got it. Then yes, leave it.

src = timeit.template.format(stmt=stmt, setup=setup)
else:
src = timeit.template % dict(stmt=stmt, setup=setup)

# Track compilation time so it can be reported if too long
# Minimum time above which compilation time will be reported
tc_min = 0.1
Expand Down
7 changes: 7 additions & 0 deletions IPython/core/tests/test_magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
from StringIO import StringIO
from unittest import TestCase

try:
from importlib import invalidate_caches # Required from Python 3.3
except ImportError:
def invalidate_caches():
pass

import nose.tools as nt

from IPython.core import magic
Expand Down Expand Up @@ -449,6 +455,7 @@ def test_extension():
url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
_ip.magic("install_ext %s" % url)
_ip.user_ns.pop('arq', None)
invalidate_caches() # Clear import caches
_ip.magic("load_ext daft_extension")
tt.assert_equal(_ip.user_ns['arq'], 185)
_ip.magic("unload_ext daft_extension")
Expand Down
1 change: 1 addition & 0 deletions IPython/extensions/autoreload.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ def superreload(module, reload=reload, old_objects={}):
old_name = module.__name__
module.__dict__.clear()
module.__dict__['__name__'] = old_name
module.__dict__['__loader__'] = old_dict['__loader__']
except (TypeError, AttributeError, KeyError):
pass

Expand Down
62 changes: 0 additions & 62 deletions IPython/testing/globalipapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,67 +84,6 @@ def _run_ns_sync(self,arg_s,runner=None):
return get_ipython().magic_run_ori(arg_s, runner, finder)


class ipnsdict(dict):
"""A special subclass of dict for use as an IPython namespace in doctests.

This subclass adds a simple checkpointing capability so that when testing
machinery clears it (we use it as the test execution context), it doesn't
get completely destroyed.

In addition, it can handle the presence of the '_' key in a special manner,
which is needed because of how Python's doctest machinery operates with
'_'. See constructor and :meth:`update` for details.
"""

def __init__(self,*a):
dict.__init__(self,*a)
self._savedict = {}
# If this flag is True, the .update() method will unconditionally
# remove a key named '_'. This is so that such a dict can be used as a
# namespace in doctests that call '_'.
self.protect_underscore = False

def clear(self):
dict.clear(self)
self.update(self._savedict)

def _checkpoint(self):
self._savedict.clear()
self._savedict.update(self)

def update(self,other):
self._checkpoint()
dict.update(self,other)

if self.protect_underscore:
# If '_' is in the namespace, python won't set it when executing
# code *in doctests*, and we have multiple doctests that use '_'.
# So we ensure that the namespace is always 'clean' of it before
# it's used for test code execution.
# This flag is only turned on by the doctest machinery, so that
# normal test code can assume the _ key is updated like any other
# key and can test for its presence after cell executions.
self.pop('_', None)

# The builtins namespace must *always* be the real __builtin__ module,
# else weird stuff happens. The main ipython code does have provisions
# to ensure this after %run, but since in this class we do some
# aggressive low-level cleaning of the execution namespace, we need to
# correct for that ourselves, to ensure consitency with the 'real'
# ipython.
self['__builtins__'] = builtin_mod

def __delitem__(self, key):
"""Part of the test suite checks that we can release all
references to an object. So we need to make sure that we're not
keeping a reference in _savedict."""
dict.__delitem__(self, key)
try:
del self._savedict[key]
except KeyError:
pass


def get_ipython():
# This will get replaced by the real thing once we start IPython below
return start_ipython()
Expand Down Expand Up @@ -189,7 +128,6 @@ def start_ipython():

# Create and initialize our test-friendly IPython instance.
shell = TerminalInteractiveShell.instance(config=config,
user_ns=ipnsdict(),
)

# A few more tweaks needed for playing nicely with doctests...
Expand Down
17 changes: 7 additions & 10 deletions IPython/testing/plugin/ipdoctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# Module imports

# From the standard library
import __builtin__
import __builtin__ as builtin_mod
import commands
import doctest
import inspect
Expand Down Expand Up @@ -267,32 +267,29 @@ def runTest(self):
def setUp(self):
"""Modified test setup that syncs with ipython namespace"""
#print "setUp test", self._dt_test.examples # dbg
if isinstance(self._dt_test.examples[0],IPExample):
if isinstance(self._dt_test.examples[0], IPExample):
# for IPython examples *only*, we swap the globals with the ipython
# namespace, after updating it with the globals (which doctest
# fills with the necessary info from the module being tested).
self.user_ns_orig = {}
self.user_ns_orig.update(_ip.user_ns)
_ip.user_ns.update(self._dt_test.globs)
# We must remove the _ key in the namespace, so that Python's
# doctest code sets it naturally
_ip.user_ns.pop('_', None)
_ip.user_ns['__builtins__'] = builtin_mod
self._dt_test.globs = _ip.user_ns
# IPython must protect the _ key in the namespace (it can't exist)
# so that Python's doctest code sets it naturally, so we enable
# this feature of our testing namespace.
_ip.user_ns.protect_underscore = True

super(DocTestCase, self).setUp()

def tearDown(self):

# Undo the test.globs reassignment we made, so that the parent class
# teardown doesn't destroy the ipython namespace
if isinstance(self._dt_test.examples[0],IPExample):
if isinstance(self._dt_test.examples[0], IPExample):
self._dt_test.globs = self._dt_test_globs_ori
_ip.user_ns.clear()
_ip.user_ns.update(self.user_ns_orig)
# Restore the behavior of the '_' key in the user namespace to
# normal after each doctest, so that unittests behave normally
_ip.user_ns.protect_underscore = False

# XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
# it does look like one to me: its tearDown method tries to run
Expand Down
4 changes: 2 additions & 2 deletions IPython/utils/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ def extract_vars(*names,**kw):

In [2]: def func(x):
...: y = 1
...: print extract_vars('x','y')
...: print sorted(extract_vars('x','y').items())
...:

In [3]: func('hello')
{'y': 1, 'x': 'hello'}
[('x', 'hello'), ('y', 1)]
"""

depth = kw.get('depth',0)
Expand Down
26 changes: 12 additions & 14 deletions IPython/utils/ipstruct.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ def __init__(self, *args, **kw):
>>> s.b
30
>>> s2 = Struct(s,c=30)
>>> s2.keys()
['a', 'c', 'b']
>>> sorted(s2.keys())
['a', 'b', 'c']
"""
object.__setattr__(self, '_allownew', True)
dict.__init__(self, *args, **kw)
Expand Down Expand Up @@ -161,8 +161,8 @@ def __iadd__(self, other):
>>> s = Struct(a=10,b=30)
>>> s2 = Struct(a=20,c=40)
>>> s += s2
>>> s
{'a': 10, 'c': 40, 'b': 30}
>>> sorted(s.keys())
['a', 'b', 'c']
"""
self.merge(other)
return self
Expand All @@ -176,8 +176,8 @@ def __add__(self,other):
>>> s1 = Struct(a=10,b=30)
>>> s2 = Struct(a=20,c=40)
>>> s = s1 + s2
>>> s
{'a': 10, 'c': 40, 'b': 30}
>>> sorted(s.keys())
['a', 'b', 'c']
"""
sout = self.copy()
sout.merge(other)
Expand Down Expand Up @@ -241,10 +241,8 @@ def copy(self):

>>> s = Struct(a=10,b=30)
>>> s2 = s.copy()
>>> s2
{'a': 10, 'b': 30}
>>> type(s2).__name__
'Struct'
>>> type(s2) is Struct
True
"""
return Struct(dict.copy(self))

Expand Down Expand Up @@ -348,17 +346,17 @@ def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
>>> s = Struct(a=10,b=30)
>>> s2 = Struct(a=20,c=40)
>>> s.merge(s2)
>>> s
{'a': 10, 'c': 40, 'b': 30}
>>> sorted(s.items())
[('a', 10), ('b', 30), ('c', 40)]

Now, show how to specify a conflict dict:

>>> s = Struct(a=10,b=30)
>>> s2 = Struct(a=20,b=40)
>>> conflict = {'update':'a','add':'b'}
>>> s.merge(s2,conflict)
>>> s
{'a': 20, 'b': 70}
>>> sorted(s.items())
[('a', 20), ('b', 70)]
"""

data_dict = dict(__loc_data__,**kw)
Expand Down
8 changes: 4 additions & 4 deletions IPython/utils/jsonutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ def json_clean(obj):
4
>>> json_clean(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> json_clean(dict(x=1, y=2))
{'y': 2, 'x': 1}
>>> json_clean(dict(x=1, y=2, z=[1,2,3]))
{'y': 2, 'x': 1, 'z': [1, 2, 3]}
>>> sorted(json_clean(dict(x=1, y=2)).items())
[('x', 1), ('y', 2)]
>>> sorted(json_clean(dict(x=1, y=2, z=[1,2,3])).items())
[('x', 1), ('y', 2), ('z', [1, 2, 3])]
>>> json_clean(True)
True
"""
Expand Down
3 changes: 2 additions & 1 deletion IPython/utils/tests/test_jsonutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ def test():

def test_lambda():
jc = json_clean(lambda : 1)
nt.assert_true(jc.startswith('<function <lambda> at '))
assert isinstance(jc, str)
assert '<lambda>' in jc
json.dumps(jc)


Expand Down
4 changes: 3 additions & 1 deletion IPython/utils/tests/test_module_paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
#

old_syspath = sys.path
sys.path = [TMP_TEST_DIR]

def make_empty_file(fname):
f = open(fname, 'w')
Expand All @@ -62,16 +61,19 @@ def setup():
make_empty_file(join(TMP_TEST_DIR, "xmod/sub.py"))
make_empty_file(join(TMP_TEST_DIR, "pack.py"))
make_empty_file(join(TMP_TEST_DIR, "packpyc.pyc"))
sys.path = [TMP_TEST_DIR]

def teardown():
"""Teardown testenvironment for the module:

- Remove tempdir
- restore sys.path
"""
# Note: we remove the parent test dir, which is the root of all test
# subdirs we may have created. Use shutil instead of os.removedirs, so
# that non-empty directories are all recursively removed.
shutil.rmtree(TMP_TEST_DIR)
sys.path = old_syspath


def test_get_init_1():
Expand Down
4 changes: 2 additions & 2 deletions IPython/utils/tests/test_traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,8 @@ class A(HasTraits):
i = Int
f = Float
a = A()
self.assertEquals(a.trait_names(),['i','f'])
self.assertEquals(A.class_trait_names(),['i','f'])
self.assertEquals(sorted(a.trait_names()),['f','i'])
self.assertEquals(sorted(A.class_trait_names()),['f','i'])

def test_trait_metadata(self):
class A(HasTraits):
Expand Down