Show More
@@ -1,91 +1,92 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """This file contains unittests for the |
|
2 | """This file contains unittests for the | |
3 | IPython.frontend.cocoa.cocoa_frontend module. |
|
3 | IPython.frontend.cocoa.cocoa_frontend module. | |
4 | """ |
|
4 | """ | |
5 | __docformat__ = "restructuredtext en" |
|
5 | __docformat__ = "restructuredtext en" | |
6 |
|
6 | |||
7 | #--------------------------------------------------------------------------- |
|
7 | #--------------------------------------------------------------------------- | |
8 | # Copyright (C) 2005 The IPython Development Team |
|
8 | # Copyright (C) 2005 The IPython Development Team | |
9 | # |
|
9 | # | |
10 | # Distributed under the terms of the BSD License. The full license is in |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
11 | # the file COPYING, distributed as part of this software. |
|
11 | # the file COPYING, distributed as part of this software. | |
12 | #--------------------------------------------------------------------------- |
|
12 | #--------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 | #--------------------------------------------------------------------------- |
|
14 | #--------------------------------------------------------------------------- | |
15 | # Imports |
|
15 | # Imports | |
16 | #--------------------------------------------------------------------------- |
|
16 | #--------------------------------------------------------------------------- | |
17 | from IPython.kernel.core.interpreter import Interpreter |
|
17 | from IPython.kernel.core.interpreter import Interpreter | |
18 | import IPython.kernel.engineservice as es |
|
18 | import IPython.kernel.engineservice as es | |
19 | from IPython.testing.util import DeferredTestCase |
|
19 | from IPython.testing.util import DeferredTestCase | |
20 | from twisted.internet.defer import succeed |
|
20 | from twisted.internet.defer import succeed | |
21 | from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController |
|
|||
22 |
|
||||
23 | from Foundation import NSMakeRect |
|
|||
24 | from AppKit import NSTextView, NSScrollView |
|
|||
25 |
|
21 | |||
26 | class TestIPythonCocoaControler(DeferredTestCase): |
|
22 | try: | |
27 | """Tests for IPythonCocoaController""" |
|
23 | from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController | |
|
24 | from Foundation import NSMakeRect | |||
|
25 | from AppKit import NSTextView, NSScrollView | |||
|
26 | except ImportError: | |||
|
27 | class TestIPythonCocoaControler(DeferredTestCase): | |||
|
28 | """Tests for IPythonCocoaController""" | |||
28 |
|
29 | |||
29 | def setUp(self): |
|
30 | def setUp(self): | |
30 | self.controller = IPythonCocoaController.alloc().init() |
|
31 | self.controller = IPythonCocoaController.alloc().init() | |
31 | self.engine = es.EngineService() |
|
32 | self.engine = es.EngineService() | |
32 | self.engine.startService() |
|
33 | self.engine.startService() | |
33 |
|
34 | |||
34 |
|
35 | |||
35 | def tearDown(self): |
|
36 | def tearDown(self): | |
36 | self.controller = None |
|
37 | self.controller = None | |
37 | self.engine.stopService() |
|
38 | self.engine.stopService() | |
38 |
|
39 | |||
39 | def testControllerExecutesCode(self): |
|
40 | def testControllerExecutesCode(self): | |
40 | code ="""5+5""" |
|
41 | code ="""5+5""" | |
41 | expected = Interpreter().execute(code) |
|
42 | expected = Interpreter().execute(code) | |
42 | del expected['number'] |
|
43 | del expected['number'] | |
43 | def removeNumberAndID(result): |
|
44 | def removeNumberAndID(result): | |
44 | del result['number'] |
|
45 | del result['number'] | |
45 | del result['id'] |
|
46 | del result['id'] | |
46 | return result |
|
47 | return result | |
47 | self.assertDeferredEquals( |
|
48 | self.assertDeferredEquals( | |
48 | self.controller.execute(code).addCallback(removeNumberAndID), |
|
49 | self.controller.execute(code).addCallback(removeNumberAndID), | |
49 | expected) |
|
50 | expected) | |
50 |
|
51 | |||
51 | def testControllerMirrorsUserNSWithValuesAsStrings(self): |
|
52 | def testControllerMirrorsUserNSWithValuesAsStrings(self): | |
52 | code = """userns1=1;userns2=2""" |
|
53 | code = """userns1=1;userns2=2""" | |
53 | def testControllerUserNS(result): |
|
54 | def testControllerUserNS(result): | |
54 | self.assertEquals(self.controller.userNS['userns1'], 1) |
|
55 | self.assertEquals(self.controller.userNS['userns1'], 1) | |
55 | self.assertEquals(self.controller.userNS['userns2'], 2) |
|
56 | self.assertEquals(self.controller.userNS['userns2'], 2) | |
56 |
|
57 | |||
57 | self.controller.execute(code).addCallback(testControllerUserNS) |
|
58 | self.controller.execute(code).addCallback(testControllerUserNS) | |
58 |
|
59 | |||
59 |
|
60 | |||
60 | def testControllerInstantiatesIEngine(self): |
|
61 | def testControllerInstantiatesIEngine(self): | |
61 | self.assert_(es.IEngineBase.providedBy(self.controller.engine)) |
|
62 | self.assert_(es.IEngineBase.providedBy(self.controller.engine)) | |
62 |
|
63 | |||
63 | def testControllerCompletesToken(self): |
|
64 | def testControllerCompletesToken(self): | |
64 | code = """longNameVariable=10""" |
|
65 | code = """longNameVariable=10""" | |
65 | def testCompletes(result): |
|
66 | def testCompletes(result): | |
66 | self.assert_("longNameVariable" in result) |
|
67 | self.assert_("longNameVariable" in result) | |
67 |
|
68 | |||
68 | def testCompleteToken(result): |
|
69 | def testCompleteToken(result): | |
69 | self.controller.complete("longNa").addCallback(testCompletes) |
|
70 | self.controller.complete("longNa").addCallback(testCompletes) | |
70 |
|
71 | |||
71 | self.controller.execute(code).addCallback(testCompletes) |
|
72 | self.controller.execute(code).addCallback(testCompletes) | |
72 |
|
73 | |||
73 |
|
74 | |||
74 | def testCurrentIndent(self): |
|
75 | def testCurrentIndent(self): | |
75 | """test that current_indent_string returns current indent or None. |
|
76 | """test that current_indent_string returns current indent or None. | |
76 | Uses _indent_for_block for direct unit testing. |
|
77 | Uses _indent_for_block for direct unit testing. | |
77 | """ |
|
78 | """ | |
78 |
|
79 | |||
79 | self.controller.tabUsesSpaces = True |
|
80 | self.controller.tabUsesSpaces = True | |
80 | self.assert_(self.controller._indent_for_block("""a=3""") == None) |
|
81 | self.assert_(self.controller._indent_for_block("""a=3""") == None) | |
81 | self.assert_(self.controller._indent_for_block("") == None) |
|
82 | self.assert_(self.controller._indent_for_block("") == None) | |
82 | block = """def test():\n a=3""" |
|
83 | block = """def test():\n a=3""" | |
83 | self.assert_(self.controller._indent_for_block(block) == \ |
|
84 | self.assert_(self.controller._indent_for_block(block) == \ | |
84 | ' ' * self.controller.tabSpaces) |
|
85 | ' ' * self.controller.tabSpaces) | |
85 |
|
86 | |||
86 | block = """if(True):\n%sif(False):\n%spass""" % \ |
|
87 | block = """if(True):\n%sif(False):\n%spass""" % \ | |
87 | (' '*self.controller.tabSpaces, |
|
88 | (' '*self.controller.tabSpaces, | |
88 | 2*' '*self.controller.tabSpaces) |
|
89 | 2*' '*self.controller.tabSpaces) | |
89 | self.assert_(self.controller._indent_for_block(block) == \ |
|
90 | self.assert_(self.controller._indent_for_block(block) == \ | |
90 | 2*(' '*self.controller.tabSpaces)) |
|
91 | 2*(' '*self.controller.tabSpaces)) | |
91 |
|
92 |
@@ -1,828 +1,827 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 |
|
2 | |||
3 | """""" |
|
3 | """""" | |
4 |
|
4 | |||
5 | __docformat__ = "restructuredtext en" |
|
5 | __docformat__ = "restructuredtext en" | |
6 |
|
6 | |||
7 | #------------------------------------------------------------------------------- |
|
7 | #------------------------------------------------------------------------------- | |
8 | # Copyright (C) 2008 The IPython Development Team |
|
8 | # Copyright (C) 2008 The IPython Development Team | |
9 | # |
|
9 | # | |
10 | # Distributed under the terms of the BSD License. The full license is in |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
11 | # the file COPYING, distributed as part of this software. |
|
11 | # the file COPYING, distributed as part of this software. | |
12 | #------------------------------------------------------------------------------- |
|
12 | #------------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 | #------------------------------------------------------------------------------- |
|
14 | #------------------------------------------------------------------------------- | |
15 | # Imports |
|
15 | # Imports | |
16 | #------------------------------------------------------------------------------- |
|
16 | #------------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | from twisted.internet import defer |
|
18 | from twisted.internet import defer | |
19 |
|
19 | |||
20 | from IPython.kernel import engineservice as es |
|
20 | from IPython.kernel import engineservice as es | |
21 | from IPython.kernel import multiengine as me |
|
21 | from IPython.kernel import multiengine as me | |
22 | from IPython.kernel import newserialized |
|
22 | from IPython.kernel import newserialized | |
23 | from IPython.kernel.error import NotDefined |
|
|||
24 | from IPython.testing import util |
|
23 | from IPython.testing import util | |
25 | from IPython.testing.parametric import parametric, Parametric |
|
24 | from IPython.testing.parametric import parametric, Parametric | |
26 | from IPython.kernel import newserialized |
|
25 | from IPython.kernel import newserialized | |
27 | from IPython.kernel.util import printer |
|
26 | from IPython.kernel.util import printer | |
28 | from IPython.kernel.error import (InvalidEngineID, |
|
27 | from IPython.kernel.error import (InvalidEngineID, | |
29 | NoEnginesRegistered, |
|
28 | NoEnginesRegistered, | |
30 | CompositeError, |
|
29 | CompositeError, | |
31 | InvalidDeferredID) |
|
30 | InvalidDeferredID) | |
32 | from IPython.kernel.tests.engineservicetest import validCommands, invalidCommands |
|
31 | from IPython.kernel.tests.engineservicetest import validCommands, invalidCommands | |
33 | from IPython.kernel.core.interpreter import Interpreter |
|
32 | from IPython.kernel.core.interpreter import Interpreter | |
34 |
|
33 | |||
35 |
|
34 | |||
36 | #------------------------------------------------------------------------------- |
|
35 | #------------------------------------------------------------------------------- | |
37 | # Base classes and utilities |
|
36 | # Base classes and utilities | |
38 | #------------------------------------------------------------------------------- |
|
37 | #------------------------------------------------------------------------------- | |
39 |
|
38 | |||
40 | class IMultiEngineBaseTestCase(object): |
|
39 | class IMultiEngineBaseTestCase(object): | |
41 | """Basic utilities for working with multiengine tests. |
|
40 | """Basic utilities for working with multiengine tests. | |
42 |
|
41 | |||
43 | Some subclass should define: |
|
42 | Some subclass should define: | |
44 |
|
43 | |||
45 | * self.multiengine |
|
44 | * self.multiengine | |
46 | * self.engines to keep track of engines for clean up""" |
|
45 | * self.engines to keep track of engines for clean up""" | |
47 |
|
46 | |||
48 | def createShell(self): |
|
47 | def createShell(self): | |
49 | return Interpreter() |
|
48 | return Interpreter() | |
50 |
|
49 | |||
51 | def addEngine(self, n=1): |
|
50 | def addEngine(self, n=1): | |
52 | for i in range(n): |
|
51 | for i in range(n): | |
53 | e = es.EngineService() |
|
52 | e = es.EngineService() | |
54 | e.startService() |
|
53 | e.startService() | |
55 | regDict = self.controller.register_engine(es.QueuedEngine(e), None) |
|
54 | regDict = self.controller.register_engine(es.QueuedEngine(e), None) | |
56 | e.id = regDict['id'] |
|
55 | e.id = regDict['id'] | |
57 | self.engines.append(e) |
|
56 | self.engines.append(e) | |
58 |
|
57 | |||
59 |
|
58 | |||
60 | def testf(x): |
|
59 | def testf(x): | |
61 | return 2.0*x |
|
60 | return 2.0*x | |
62 |
|
61 | |||
63 |
|
62 | |||
64 | globala = 99 |
|
63 | globala = 99 | |
65 |
|
64 | |||
66 |
|
65 | |||
67 | def testg(x): |
|
66 | def testg(x): | |
68 | return globala*x |
|
67 | return globala*x | |
69 |
|
68 | |||
70 |
|
69 | |||
71 | def isdid(did): |
|
70 | def isdid(did): | |
72 | if not isinstance(did, str): |
|
71 | if not isinstance(did, str): | |
73 | return False |
|
72 | return False | |
74 | if not len(did)==40: |
|
73 | if not len(did)==40: | |
75 | return False |
|
74 | return False | |
76 | return True |
|
75 | return True | |
77 |
|
76 | |||
78 |
|
77 | |||
79 | def _raise_it(f): |
|
78 | def _raise_it(f): | |
80 | try: |
|
79 | try: | |
81 | f.raiseException() |
|
80 | f.raiseException() | |
82 | except CompositeError, e: |
|
81 | except CompositeError, e: | |
83 | e.raise_exception() |
|
82 | e.raise_exception() | |
84 |
|
83 | |||
85 | #------------------------------------------------------------------------------- |
|
84 | #------------------------------------------------------------------------------- | |
86 | # IMultiEngineTestCase |
|
85 | # IMultiEngineTestCase | |
87 | #------------------------------------------------------------------------------- |
|
86 | #------------------------------------------------------------------------------- | |
88 |
|
87 | |||
89 | class IMultiEngineTestCase(IMultiEngineBaseTestCase): |
|
88 | class IMultiEngineTestCase(IMultiEngineBaseTestCase): | |
90 | """A test for any object that implements IEngineMultiplexer. |
|
89 | """A test for any object that implements IEngineMultiplexer. | |
91 |
|
90 | |||
92 | self.multiengine must be defined and implement IEngineMultiplexer. |
|
91 | self.multiengine must be defined and implement IEngineMultiplexer. | |
93 | """ |
|
92 | """ | |
94 |
|
93 | |||
95 | def testIMultiEngineInterface(self): |
|
94 | def testIMultiEngineInterface(self): | |
96 | """Does self.engine claim to implement IEngineCore?""" |
|
95 | """Does self.engine claim to implement IEngineCore?""" | |
97 | self.assert_(me.IEngineMultiplexer.providedBy(self.multiengine)) |
|
96 | self.assert_(me.IEngineMultiplexer.providedBy(self.multiengine)) | |
98 | self.assert_(me.IMultiEngine.providedBy(self.multiengine)) |
|
97 | self.assert_(me.IMultiEngine.providedBy(self.multiengine)) | |
99 |
|
98 | |||
100 | def testIEngineMultiplexerInterfaceMethods(self): |
|
99 | def testIEngineMultiplexerInterfaceMethods(self): | |
101 | """Does self.engine have the methods and attributes in IEngineCore.""" |
|
100 | """Does self.engine have the methods and attributes in IEngineCore.""" | |
102 | for m in list(me.IEngineMultiplexer): |
|
101 | for m in list(me.IEngineMultiplexer): | |
103 | self.assert_(hasattr(self.multiengine, m)) |
|
102 | self.assert_(hasattr(self.multiengine, m)) | |
104 |
|
103 | |||
105 | def testIEngineMultiplexerDeferreds(self): |
|
104 | def testIEngineMultiplexerDeferreds(self): | |
106 | self.addEngine(1) |
|
105 | self.addEngine(1) | |
107 | d= self.multiengine.execute('a=5', targets=0) |
|
106 | d= self.multiengine.execute('a=5', targets=0) | |
108 | d.addCallback(lambda _: self.multiengine.push(dict(a=5),targets=0)) |
|
107 | d.addCallback(lambda _: self.multiengine.push(dict(a=5),targets=0)) | |
109 | d.addCallback(lambda _: self.multiengine.push(dict(a=5, b='asdf', c=[1,2,3]),targets=0)) |
|
108 | d.addCallback(lambda _: self.multiengine.push(dict(a=5, b='asdf', c=[1,2,3]),targets=0)) | |
110 | d.addCallback(lambda _: self.multiengine.pull(('a','b','c'),targets=0)) |
|
109 | d.addCallback(lambda _: self.multiengine.pull(('a','b','c'),targets=0)) | |
111 | d.addCallback(lambda _: self.multiengine.get_result(targets=0)) |
|
110 | d.addCallback(lambda _: self.multiengine.get_result(targets=0)) | |
112 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) |
|
111 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) | |
113 | d.addCallback(lambda _: self.multiengine.keys(targets=0)) |
|
112 | d.addCallback(lambda _: self.multiengine.keys(targets=0)) | |
114 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)),targets=0)) |
|
113 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)),targets=0)) | |
115 | d.addCallback(lambda _: self.multiengine.pull_serialized('a',targets=0)) |
|
114 | d.addCallback(lambda _: self.multiengine.pull_serialized('a',targets=0)) | |
116 | d.addCallback(lambda _: self.multiengine.clear_queue(targets=0)) |
|
115 | d.addCallback(lambda _: self.multiengine.clear_queue(targets=0)) | |
117 | d.addCallback(lambda _: self.multiengine.queue_status(targets=0)) |
|
116 | d.addCallback(lambda _: self.multiengine.queue_status(targets=0)) | |
118 | return d |
|
117 | return d | |
119 |
|
118 | |||
120 | def testInvalidEngineID(self): |
|
119 | def testInvalidEngineID(self): | |
121 | self.addEngine(1) |
|
120 | self.addEngine(1) | |
122 | badID = 100 |
|
121 | badID = 100 | |
123 | d = self.multiengine.execute('a=5', targets=badID) |
|
122 | d = self.multiengine.execute('a=5', targets=badID) | |
124 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) |
|
123 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) | |
125 | d.addCallback(lambda _: self.multiengine.push(dict(a=5), targets=badID)) |
|
124 | d.addCallback(lambda _: self.multiengine.push(dict(a=5), targets=badID)) | |
126 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) |
|
125 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) | |
127 | d.addCallback(lambda _: self.multiengine.pull('a', targets=badID)) |
|
126 | d.addCallback(lambda _: self.multiengine.pull('a', targets=badID)) | |
128 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) |
|
127 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) | |
129 | d.addCallback(lambda _: self.multiengine.reset(targets=badID)) |
|
128 | d.addCallback(lambda _: self.multiengine.reset(targets=badID)) | |
130 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) |
|
129 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) | |
131 | d.addCallback(lambda _: self.multiengine.keys(targets=badID)) |
|
130 | d.addCallback(lambda _: self.multiengine.keys(targets=badID)) | |
132 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) |
|
131 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) | |
133 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)), targets=badID)) |
|
132 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)), targets=badID)) | |
134 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) |
|
133 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) | |
135 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=badID)) |
|
134 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=badID)) | |
136 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) |
|
135 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) | |
137 | d.addCallback(lambda _: self.multiengine.queue_status(targets=badID)) |
|
136 | d.addCallback(lambda _: self.multiengine.queue_status(targets=badID)) | |
138 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) |
|
137 | d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException)) | |
139 | return d |
|
138 | return d | |
140 |
|
139 | |||
141 | def testNoEnginesRegistered(self): |
|
140 | def testNoEnginesRegistered(self): | |
142 | badID = 'all' |
|
141 | badID = 'all' | |
143 | d= self.multiengine.execute('a=5', targets=badID) |
|
142 | d= self.multiengine.execute('a=5', targets=badID) | |
144 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
143 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
145 | d.addCallback(lambda _: self.multiengine.push(dict(a=5), targets=badID)) |
|
144 | d.addCallback(lambda _: self.multiengine.push(dict(a=5), targets=badID)) | |
146 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
145 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
147 | d.addCallback(lambda _: self.multiengine.pull('a', targets=badID)) |
|
146 | d.addCallback(lambda _: self.multiengine.pull('a', targets=badID)) | |
148 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
147 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
149 | d.addCallback(lambda _: self.multiengine.get_result(targets=badID)) |
|
148 | d.addCallback(lambda _: self.multiengine.get_result(targets=badID)) | |
150 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
149 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
151 | d.addCallback(lambda _: self.multiengine.reset(targets=badID)) |
|
150 | d.addCallback(lambda _: self.multiengine.reset(targets=badID)) | |
152 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
151 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
153 | d.addCallback(lambda _: self.multiengine.keys(targets=badID)) |
|
152 | d.addCallback(lambda _: self.multiengine.keys(targets=badID)) | |
154 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
153 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
155 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)), targets=badID)) |
|
154 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)), targets=badID)) | |
156 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
155 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
157 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=badID)) |
|
156 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=badID)) | |
158 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
157 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
159 | d.addCallback(lambda _: self.multiengine.queue_status(targets=badID)) |
|
158 | d.addCallback(lambda _: self.multiengine.queue_status(targets=badID)) | |
160 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) |
|
159 | d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException)) | |
161 | return d |
|
160 | return d | |
162 |
|
161 | |||
163 | def runExecuteAll(self, d, cmd, shell): |
|
162 | def runExecuteAll(self, d, cmd, shell): | |
164 | actual = shell.execute(cmd) |
|
163 | actual = shell.execute(cmd) | |
165 | d.addCallback(lambda _: self.multiengine.execute(cmd)) |
|
164 | d.addCallback(lambda _: self.multiengine.execute(cmd)) | |
166 | def compare(result): |
|
165 | def compare(result): | |
167 | for r in result: |
|
166 | for r in result: | |
168 | actual['id'] = r['id'] |
|
167 | actual['id'] = r['id'] | |
169 | self.assertEquals(r, actual) |
|
168 | self.assertEquals(r, actual) | |
170 | d.addCallback(compare) |
|
169 | d.addCallback(compare) | |
171 |
|
170 | |||
172 | def testExecuteAll(self): |
|
171 | def testExecuteAll(self): | |
173 | self.addEngine(4) |
|
172 | self.addEngine(4) | |
174 | d= defer.Deferred() |
|
173 | d= defer.Deferred() | |
175 | shell = Interpreter() |
|
174 | shell = Interpreter() | |
176 | for cmd in validCommands: |
|
175 | for cmd in validCommands: | |
177 | self.runExecuteAll(d, cmd, shell) |
|
176 | self.runExecuteAll(d, cmd, shell) | |
178 | d.callback(None) |
|
177 | d.callback(None) | |
179 | return d |
|
178 | return d | |
180 |
|
179 | |||
181 | # The following two methods show how to do parametrized |
|
180 | # The following two methods show how to do parametrized | |
182 | # tests. This is really slick! Same is used above. |
|
181 | # tests. This is really slick! Same is used above. | |
183 | def runExecuteFailures(self, cmd, exc): |
|
182 | def runExecuteFailures(self, cmd, exc): | |
184 | self.addEngine(4) |
|
183 | self.addEngine(4) | |
185 | d= self.multiengine.execute(cmd) |
|
184 | d= self.multiengine.execute(cmd) | |
186 | d.addErrback(lambda f: self.assertRaises(exc, _raise_it, f)) |
|
185 | d.addErrback(lambda f: self.assertRaises(exc, _raise_it, f)) | |
187 | return d |
|
186 | return d | |
188 |
|
187 | |||
189 | @parametric |
|
188 | @parametric | |
190 | def testExecuteFailuresMultiEng(cls): |
|
189 | def testExecuteFailuresMultiEng(cls): | |
191 | return [(cls.runExecuteFailures,cmd,exc) for |
|
190 | return [(cls.runExecuteFailures,cmd,exc) for | |
192 | cmd,exc in invalidCommands] |
|
191 | cmd,exc in invalidCommands] | |
193 |
|
192 | |||
194 | def testPushPull(self): |
|
193 | def testPushPull(self): | |
195 | self.addEngine(1) |
|
194 | self.addEngine(1) | |
196 | objs = [10,"hi there",1.2342354,{"p":(1,2)}] |
|
195 | objs = [10,"hi there",1.2342354,{"p":(1,2)}] | |
197 | d= self.multiengine.push(dict(key=objs[0]), targets=0) |
|
196 | d= self.multiengine.push(dict(key=objs[0]), targets=0) | |
198 | d.addCallback(lambda _: self.multiengine.pull('key', targets=0)) |
|
197 | d.addCallback(lambda _: self.multiengine.pull('key', targets=0)) | |
199 | d.addCallback(lambda r: self.assertEquals(r, [objs[0]])) |
|
198 | d.addCallback(lambda r: self.assertEquals(r, [objs[0]])) | |
200 | d.addCallback(lambda _: self.multiengine.push(dict(key=objs[1]), targets=0)) |
|
199 | d.addCallback(lambda _: self.multiengine.push(dict(key=objs[1]), targets=0)) | |
201 | d.addCallback(lambda _: self.multiengine.pull('key', targets=0)) |
|
200 | d.addCallback(lambda _: self.multiengine.pull('key', targets=0)) | |
202 | d.addCallback(lambda r: self.assertEquals(r, [objs[1]])) |
|
201 | d.addCallback(lambda r: self.assertEquals(r, [objs[1]])) | |
203 | d.addCallback(lambda _: self.multiengine.push(dict(key=objs[2]), targets=0)) |
|
202 | d.addCallback(lambda _: self.multiengine.push(dict(key=objs[2]), targets=0)) | |
204 | d.addCallback(lambda _: self.multiengine.pull('key', targets=0)) |
|
203 | d.addCallback(lambda _: self.multiengine.pull('key', targets=0)) | |
205 | d.addCallback(lambda r: self.assertEquals(r, [objs[2]])) |
|
204 | d.addCallback(lambda r: self.assertEquals(r, [objs[2]])) | |
206 | d.addCallback(lambda _: self.multiengine.push(dict(key=objs[3]), targets=0)) |
|
205 | d.addCallback(lambda _: self.multiengine.push(dict(key=objs[3]), targets=0)) | |
207 | d.addCallback(lambda _: self.multiengine.pull('key', targets=0)) |
|
206 | d.addCallback(lambda _: self.multiengine.pull('key', targets=0)) | |
208 | d.addCallback(lambda r: self.assertEquals(r, [objs[3]])) |
|
207 | d.addCallback(lambda r: self.assertEquals(r, [objs[3]])) | |
209 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) |
|
208 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) | |
210 | d.addCallback(lambda _: self.multiengine.pull('a', targets=0)) |
|
209 | d.addCallback(lambda _: self.multiengine.pull('a', targets=0)) | |
211 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) |
|
210 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) | |
212 | d.addCallback(lambda _: self.multiengine.push(dict(a=10,b=20))) |
|
211 | d.addCallback(lambda _: self.multiengine.push(dict(a=10,b=20))) | |
213 | d.addCallback(lambda _: self.multiengine.pull(('a','b'))) |
|
212 | d.addCallback(lambda _: self.multiengine.pull(('a','b'))) | |
214 | d.addCallback(lambda r: self.assertEquals(r, [[10,20]])) |
|
213 | d.addCallback(lambda r: self.assertEquals(r, [[10,20]])) | |
215 | return d |
|
214 | return d | |
216 |
|
215 | |||
217 | def testPushPullAll(self): |
|
216 | def testPushPullAll(self): | |
218 | self.addEngine(4) |
|
217 | self.addEngine(4) | |
219 | d= self.multiengine.push(dict(a=10)) |
|
218 | d= self.multiengine.push(dict(a=10)) | |
220 | d.addCallback(lambda _: self.multiengine.pull('a')) |
|
219 | d.addCallback(lambda _: self.multiengine.pull('a')) | |
221 | d.addCallback(lambda r: self.assert_(r==[10,10,10,10])) |
|
220 | d.addCallback(lambda r: self.assert_(r==[10,10,10,10])) | |
222 | d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20))) |
|
221 | d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20))) | |
223 | d.addCallback(lambda _: self.multiengine.pull(('a','b'))) |
|
222 | d.addCallback(lambda _: self.multiengine.pull(('a','b'))) | |
224 | d.addCallback(lambda r: self.assert_(r==4*[[10,20]])) |
|
223 | d.addCallback(lambda r: self.assert_(r==4*[[10,20]])) | |
225 | d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20), targets=0)) |
|
224 | d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20), targets=0)) | |
226 | d.addCallback(lambda _: self.multiengine.pull(('a','b'), targets=0)) |
|
225 | d.addCallback(lambda _: self.multiengine.pull(('a','b'), targets=0)) | |
227 | d.addCallback(lambda r: self.assert_(r==[[10,20]])) |
|
226 | d.addCallback(lambda r: self.assert_(r==[[10,20]])) | |
228 | d.addCallback(lambda _: self.multiengine.push(dict(a=None, b=None), targets=0)) |
|
227 | d.addCallback(lambda _: self.multiengine.push(dict(a=None, b=None), targets=0)) | |
229 | d.addCallback(lambda _: self.multiengine.pull(('a','b'), targets=0)) |
|
228 | d.addCallback(lambda _: self.multiengine.pull(('a','b'), targets=0)) | |
230 | d.addCallback(lambda r: self.assert_(r==[[None,None]])) |
|
229 | d.addCallback(lambda r: self.assert_(r==[[None,None]])) | |
231 | return d |
|
230 | return d | |
232 |
|
231 | |||
233 | def testPushPullSerialized(self): |
|
232 | def testPushPullSerialized(self): | |
234 | self.addEngine(1) |
|
233 | self.addEngine(1) | |
235 | objs = [10,"hi there",1.2342354,{"p":(1,2)}] |
|
234 | objs = [10,"hi there",1.2342354,{"p":(1,2)}] | |
236 | d= self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[0])), targets=0) |
|
235 | d= self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[0])), targets=0) | |
237 | d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0)) |
|
236 | d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0)) | |
238 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) |
|
237 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) | |
239 | d.addCallback(lambda r: self.assertEquals(r, objs[0])) |
|
238 | d.addCallback(lambda r: self.assertEquals(r, objs[0])) | |
240 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[1])), targets=0)) |
|
239 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[1])), targets=0)) | |
241 | d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0)) |
|
240 | d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0)) | |
242 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) |
|
241 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) | |
243 | d.addCallback(lambda r: self.assertEquals(r, objs[1])) |
|
242 | d.addCallback(lambda r: self.assertEquals(r, objs[1])) | |
244 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[2])), targets=0)) |
|
243 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[2])), targets=0)) | |
245 | d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0)) |
|
244 | d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0)) | |
246 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) |
|
245 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) | |
247 | d.addCallback(lambda r: self.assertEquals(r, objs[2])) |
|
246 | d.addCallback(lambda r: self.assertEquals(r, objs[2])) | |
248 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[3])), targets=0)) |
|
247 | d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[3])), targets=0)) | |
249 | d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0)) |
|
248 | d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0)) | |
250 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) |
|
249 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) | |
251 | d.addCallback(lambda r: self.assertEquals(r, objs[3])) |
|
250 | d.addCallback(lambda r: self.assertEquals(r, objs[3])) | |
252 | d.addCallback(lambda _: self.multiengine.push(dict(a=10,b=range(5)), targets=0)) |
|
251 | d.addCallback(lambda _: self.multiengine.push(dict(a=10,b=range(5)), targets=0)) | |
253 | d.addCallback(lambda _: self.multiengine.pull_serialized(('a','b'), targets=0)) |
|
252 | d.addCallback(lambda _: self.multiengine.pull_serialized(('a','b'), targets=0)) | |
254 | d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]]) |
|
253 | d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]]) | |
255 | d.addCallback(lambda r: self.assertEquals(r, [10, range(5)])) |
|
254 | d.addCallback(lambda r: self.assertEquals(r, [10, range(5)])) | |
256 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) |
|
255 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) | |
257 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0)) |
|
256 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0)) | |
258 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) |
|
257 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) | |
259 | return d |
|
258 | return d | |
260 |
|
259 | |||
261 | objs = [10,"hi there",1.2342354,{"p":(1,2)}] |
|
260 | objs = [10,"hi there",1.2342354,{"p":(1,2)}] | |
262 | d= defer.succeed(None) |
|
261 | d= defer.succeed(None) | |
263 | for o in objs: |
|
262 | for o in objs: | |
264 | self.multiengine.push_serialized(0, key=newserialized.serialize(o)) |
|
263 | self.multiengine.push_serialized(0, key=newserialized.serialize(o)) | |
265 | value = self.multiengine.pull_serialized(0, 'key') |
|
264 | value = self.multiengine.pull_serialized(0, 'key') | |
266 | value.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) |
|
265 | value.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) | |
267 | d = self.assertDeferredEquals(value,o,d) |
|
266 | d = self.assertDeferredEquals(value,o,d) | |
268 | return d |
|
267 | return d | |
269 |
|
268 | |||
270 | def runGetResultAll(self, d, cmd, shell): |
|
269 | def runGetResultAll(self, d, cmd, shell): | |
271 | actual = shell.execute(cmd) |
|
270 | actual = shell.execute(cmd) | |
272 | d.addCallback(lambda _: self.multiengine.execute(cmd)) |
|
271 | d.addCallback(lambda _: self.multiengine.execute(cmd)) | |
273 | d.addCallback(lambda _: self.multiengine.get_result()) |
|
272 | d.addCallback(lambda _: self.multiengine.get_result()) | |
274 | def compare(result): |
|
273 | def compare(result): | |
275 | for r in result: |
|
274 | for r in result: | |
276 | actual['id'] = r['id'] |
|
275 | actual['id'] = r['id'] | |
277 | self.assertEquals(r, actual) |
|
276 | self.assertEquals(r, actual) | |
278 | d.addCallback(compare) |
|
277 | d.addCallback(compare) | |
279 |
|
278 | |||
280 | def testGetResultAll(self): |
|
279 | def testGetResultAll(self): | |
281 | self.addEngine(4) |
|
280 | self.addEngine(4) | |
282 | d= defer.Deferred() |
|
281 | d= defer.Deferred() | |
283 | shell = Interpreter() |
|
282 | shell = Interpreter() | |
284 | for cmd in validCommands: |
|
283 | for cmd in validCommands: | |
285 | self.runGetResultAll(d, cmd, shell) |
|
284 | self.runGetResultAll(d, cmd, shell) | |
286 | d.callback(None) |
|
285 | d.callback(None) | |
287 | return d |
|
286 | return d | |
288 |
|
287 | |||
289 | def testGetResultDefault(self): |
|
288 | def testGetResultDefault(self): | |
290 | self.addEngine(1) |
|
289 | self.addEngine(1) | |
291 | target = 0 |
|
290 | target = 0 | |
292 | cmd = 'a=5' |
|
291 | cmd = 'a=5' | |
293 | shell = self.createShell() |
|
292 | shell = self.createShell() | |
294 | shellResult = shell.execute(cmd) |
|
293 | shellResult = shell.execute(cmd) | |
295 | def popit(dikt, key): |
|
294 | def popit(dikt, key): | |
296 | dikt.pop(key) |
|
295 | dikt.pop(key) | |
297 | return dikt |
|
296 | return dikt | |
298 | d= self.multiengine.execute(cmd, targets=target) |
|
297 | d= self.multiengine.execute(cmd, targets=target) | |
299 | d.addCallback(lambda _: self.multiengine.get_result(targets=target)) |
|
298 | d.addCallback(lambda _: self.multiengine.get_result(targets=target)) | |
300 | d.addCallback(lambda r: self.assertEquals(shellResult, popit(r[0],'id'))) |
|
299 | d.addCallback(lambda r: self.assertEquals(shellResult, popit(r[0],'id'))) | |
301 | return d |
|
300 | return d | |
302 |
|
301 | |||
303 | def testGetResultFailure(self): |
|
302 | def testGetResultFailure(self): | |
304 | self.addEngine(1) |
|
303 | self.addEngine(1) | |
305 | d= self.multiengine.get_result(None, targets=0) |
|
304 | d= self.multiengine.get_result(None, targets=0) | |
306 | d.addErrback(lambda f: self.assertRaises(IndexError, _raise_it, f)) |
|
305 | d.addErrback(lambda f: self.assertRaises(IndexError, _raise_it, f)) | |
307 | d.addCallback(lambda _: self.multiengine.get_result(10, targets=0)) |
|
306 | d.addCallback(lambda _: self.multiengine.get_result(10, targets=0)) | |
308 | d.addErrback(lambda f: self.assertRaises(IndexError, _raise_it, f)) |
|
307 | d.addErrback(lambda f: self.assertRaises(IndexError, _raise_it, f)) | |
309 | return d |
|
308 | return d | |
310 |
|
309 | |||
311 | def testPushFunction(self): |
|
310 | def testPushFunction(self): | |
312 | self.addEngine(1) |
|
311 | self.addEngine(1) | |
313 | d= self.multiengine.push_function(dict(f=testf), targets=0) |
|
312 | d= self.multiengine.push_function(dict(f=testf), targets=0) | |
314 | d.addCallback(lambda _: self.multiengine.execute('result = f(10)', targets=0)) |
|
313 | d.addCallback(lambda _: self.multiengine.execute('result = f(10)', targets=0)) | |
315 | d.addCallback(lambda _: self.multiengine.pull('result', targets=0)) |
|
314 | d.addCallback(lambda _: self.multiengine.pull('result', targets=0)) | |
316 | d.addCallback(lambda r: self.assertEquals(r[0], testf(10))) |
|
315 | d.addCallback(lambda r: self.assertEquals(r[0], testf(10))) | |
317 | d.addCallback(lambda _: self.multiengine.push(dict(globala=globala), targets=0)) |
|
316 | d.addCallback(lambda _: self.multiengine.push(dict(globala=globala), targets=0)) | |
318 | d.addCallback(lambda _: self.multiengine.push_function(dict(g=testg), targets=0)) |
|
317 | d.addCallback(lambda _: self.multiengine.push_function(dict(g=testg), targets=0)) | |
319 | d.addCallback(lambda _: self.multiengine.execute('result = g(10)', targets=0)) |
|
318 | d.addCallback(lambda _: self.multiengine.execute('result = g(10)', targets=0)) | |
320 | d.addCallback(lambda _: self.multiengine.pull('result', targets=0)) |
|
319 | d.addCallback(lambda _: self.multiengine.pull('result', targets=0)) | |
321 | d.addCallback(lambda r: self.assertEquals(r[0], testg(10))) |
|
320 | d.addCallback(lambda r: self.assertEquals(r[0], testg(10))) | |
322 | return d |
|
321 | return d | |
323 |
|
322 | |||
324 | def testPullFunction(self): |
|
323 | def testPullFunction(self): | |
325 | self.addEngine(1) |
|
324 | self.addEngine(1) | |
326 | d= self.multiengine.push(dict(a=globala), targets=0) |
|
325 | d= self.multiengine.push(dict(a=globala), targets=0) | |
327 | d.addCallback(lambda _: self.multiengine.push_function(dict(f=testf), targets=0)) |
|
326 | d.addCallback(lambda _: self.multiengine.push_function(dict(f=testf), targets=0)) | |
328 | d.addCallback(lambda _: self.multiengine.pull_function('f', targets=0)) |
|
327 | d.addCallback(lambda _: self.multiengine.pull_function('f', targets=0)) | |
329 | d.addCallback(lambda r: self.assertEquals(r[0](10), testf(10))) |
|
328 | d.addCallback(lambda r: self.assertEquals(r[0](10), testf(10))) | |
330 | d.addCallback(lambda _: self.multiengine.execute("def g(x): return x*x", targets=0)) |
|
329 | d.addCallback(lambda _: self.multiengine.execute("def g(x): return x*x", targets=0)) | |
331 | d.addCallback(lambda _: self.multiengine.pull_function(('f','g'),targets=0)) |
|
330 | d.addCallback(lambda _: self.multiengine.pull_function(('f','g'),targets=0)) | |
332 | d.addCallback(lambda r: self.assertEquals((r[0][0](10),r[0][1](10)), (testf(10), 100))) |
|
331 | d.addCallback(lambda r: self.assertEquals((r[0][0](10),r[0][1](10)), (testf(10), 100))) | |
333 | return d |
|
332 | return d | |
334 |
|
333 | |||
335 | def testPushFunctionAll(self): |
|
334 | def testPushFunctionAll(self): | |
336 | self.addEngine(4) |
|
335 | self.addEngine(4) | |
337 | d= self.multiengine.push_function(dict(f=testf)) |
|
336 | d= self.multiengine.push_function(dict(f=testf)) | |
338 | d.addCallback(lambda _: self.multiengine.execute('result = f(10)')) |
|
337 | d.addCallback(lambda _: self.multiengine.execute('result = f(10)')) | |
339 | d.addCallback(lambda _: self.multiengine.pull('result')) |
|
338 | d.addCallback(lambda _: self.multiengine.pull('result')) | |
340 | d.addCallback(lambda r: self.assertEquals(r, 4*[testf(10)])) |
|
339 | d.addCallback(lambda r: self.assertEquals(r, 4*[testf(10)])) | |
341 | d.addCallback(lambda _: self.multiengine.push(dict(globala=globala))) |
|
340 | d.addCallback(lambda _: self.multiengine.push(dict(globala=globala))) | |
342 | d.addCallback(lambda _: self.multiengine.push_function(dict(testg=testg))) |
|
341 | d.addCallback(lambda _: self.multiengine.push_function(dict(testg=testg))) | |
343 | d.addCallback(lambda _: self.multiengine.execute('result = testg(10)')) |
|
342 | d.addCallback(lambda _: self.multiengine.execute('result = testg(10)')) | |
344 | d.addCallback(lambda _: self.multiengine.pull('result')) |
|
343 | d.addCallback(lambda _: self.multiengine.pull('result')) | |
345 | d.addCallback(lambda r: self.assertEquals(r, 4*[testg(10)])) |
|
344 | d.addCallback(lambda r: self.assertEquals(r, 4*[testg(10)])) | |
346 | return d |
|
345 | return d | |
347 |
|
346 | |||
348 | def testPullFunctionAll(self): |
|
347 | def testPullFunctionAll(self): | |
349 | self.addEngine(4) |
|
348 | self.addEngine(4) | |
350 | d= self.multiengine.push_function(dict(f=testf)) |
|
349 | d= self.multiengine.push_function(dict(f=testf)) | |
351 | d.addCallback(lambda _: self.multiengine.pull_function('f')) |
|
350 | d.addCallback(lambda _: self.multiengine.pull_function('f')) | |
352 | d.addCallback(lambda r: self.assertEquals([func(10) for func in r], 4*[testf(10)])) |
|
351 | d.addCallback(lambda r: self.assertEquals([func(10) for func in r], 4*[testf(10)])) | |
353 | return d |
|
352 | return d | |
354 |
|
353 | |||
355 | def testGetIDs(self): |
|
354 | def testGetIDs(self): | |
356 | self.addEngine(1) |
|
355 | self.addEngine(1) | |
357 | d= self.multiengine.get_ids() |
|
356 | d= self.multiengine.get_ids() | |
358 | d.addCallback(lambda r: self.assertEquals(r, [0])) |
|
357 | d.addCallback(lambda r: self.assertEquals(r, [0])) | |
359 | d.addCallback(lambda _: self.addEngine(3)) |
|
358 | d.addCallback(lambda _: self.addEngine(3)) | |
360 | d.addCallback(lambda _: self.multiengine.get_ids()) |
|
359 | d.addCallback(lambda _: self.multiengine.get_ids()) | |
361 | d.addCallback(lambda r: self.assertEquals(r, [0,1,2,3])) |
|
360 | d.addCallback(lambda r: self.assertEquals(r, [0,1,2,3])) | |
362 | return d |
|
361 | return d | |
363 |
|
362 | |||
364 | def testClearQueue(self): |
|
363 | def testClearQueue(self): | |
365 | self.addEngine(4) |
|
364 | self.addEngine(4) | |
366 | d= self.multiengine.clear_queue() |
|
365 | d= self.multiengine.clear_queue() | |
367 | d.addCallback(lambda r: self.assertEquals(r,4*[None])) |
|
366 | d.addCallback(lambda r: self.assertEquals(r,4*[None])) | |
368 | return d |
|
367 | return d | |
369 |
|
368 | |||
370 | def testQueueStatus(self): |
|
369 | def testQueueStatus(self): | |
371 | self.addEngine(4) |
|
370 | self.addEngine(4) | |
372 | d= self.multiengine.queue_status(targets=0) |
|
371 | d= self.multiengine.queue_status(targets=0) | |
373 | d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple))) |
|
372 | d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple))) | |
374 | return d |
|
373 | return d | |
375 |
|
374 | |||
376 | def testGetSetProperties(self): |
|
375 | def testGetSetProperties(self): | |
377 | self.addEngine(4) |
|
376 | self.addEngine(4) | |
378 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) |
|
377 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) | |
379 | d= self.multiengine.set_properties(dikt) |
|
378 | d= self.multiengine.set_properties(dikt) | |
380 | d.addCallback(lambda r: self.multiengine.get_properties()) |
|
379 | d.addCallback(lambda r: self.multiengine.get_properties()) | |
381 | d.addCallback(lambda r: self.assertEquals(r, 4*[dikt])) |
|
380 | d.addCallback(lambda r: self.assertEquals(r, 4*[dikt])) | |
382 | d.addCallback(lambda r: self.multiengine.get_properties(('c',))) |
|
381 | d.addCallback(lambda r: self.multiengine.get_properties(('c',))) | |
383 | d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}])) |
|
382 | d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}])) | |
384 | d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False))) |
|
383 | d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False))) | |
385 | d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd'))) |
|
384 | d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd'))) | |
386 | d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)])) |
|
385 | d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)])) | |
387 | return d |
|
386 | return d | |
388 |
|
387 | |||
389 | def testClearProperties(self): |
|
388 | def testClearProperties(self): | |
390 | self.addEngine(4) |
|
389 | self.addEngine(4) | |
391 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) |
|
390 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) | |
392 | d= self.multiengine.set_properties(dikt) |
|
391 | d= self.multiengine.set_properties(dikt) | |
393 | d.addCallback(lambda r: self.multiengine.clear_properties()) |
|
392 | d.addCallback(lambda r: self.multiengine.clear_properties()) | |
394 | d.addCallback(lambda r: self.multiengine.get_properties()) |
|
393 | d.addCallback(lambda r: self.multiengine.get_properties()) | |
395 | d.addCallback(lambda r: self.assertEquals(r, 4*[{}])) |
|
394 | d.addCallback(lambda r: self.assertEquals(r, 4*[{}])) | |
396 | return d |
|
395 | return d | |
397 |
|
396 | |||
398 | def testDelHasProperties(self): |
|
397 | def testDelHasProperties(self): | |
399 | self.addEngine(4) |
|
398 | self.addEngine(4) | |
400 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) |
|
399 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) | |
401 | d= self.multiengine.set_properties(dikt) |
|
400 | d= self.multiengine.set_properties(dikt) | |
402 | d.addCallback(lambda r: self.multiengine.del_properties(('b','e'))) |
|
401 | d.addCallback(lambda r: self.multiengine.del_properties(('b','e'))) | |
403 | d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e'))) |
|
402 | d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e'))) | |
404 | d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]])) |
|
403 | d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]])) | |
405 | return d |
|
404 | return d | |
406 |
|
405 | |||
407 | Parametric(IMultiEngineTestCase) |
|
406 | Parametric(IMultiEngineTestCase) | |
408 |
|
407 | |||
409 | #------------------------------------------------------------------------------- |
|
408 | #------------------------------------------------------------------------------- | |
410 | # ISynchronousMultiEngineTestCase |
|
409 | # ISynchronousMultiEngineTestCase | |
411 | #------------------------------------------------------------------------------- |
|
410 | #------------------------------------------------------------------------------- | |
412 |
|
411 | |||
413 | class ISynchronousMultiEngineTestCase(IMultiEngineBaseTestCase): |
|
412 | class ISynchronousMultiEngineTestCase(IMultiEngineBaseTestCase): | |
414 |
|
413 | |||
415 | def testISynchronousMultiEngineInterface(self): |
|
414 | def testISynchronousMultiEngineInterface(self): | |
416 | """Does self.engine claim to implement IEngineCore?""" |
|
415 | """Does self.engine claim to implement IEngineCore?""" | |
417 | self.assert_(me.ISynchronousEngineMultiplexer.providedBy(self.multiengine)) |
|
416 | self.assert_(me.ISynchronousEngineMultiplexer.providedBy(self.multiengine)) | |
418 | self.assert_(me.ISynchronousMultiEngine.providedBy(self.multiengine)) |
|
417 | self.assert_(me.ISynchronousMultiEngine.providedBy(self.multiengine)) | |
419 |
|
418 | |||
420 | def testExecute(self): |
|
419 | def testExecute(self): | |
421 | self.addEngine(4) |
|
420 | self.addEngine(4) | |
422 | execute = self.multiengine.execute |
|
421 | execute = self.multiengine.execute | |
423 | d= execute('a=5', targets=0, block=True) |
|
422 | d= execute('a=5', targets=0, block=True) | |
424 | d.addCallback(lambda r: self.assert_(len(r)==1)) |
|
423 | d.addCallback(lambda r: self.assert_(len(r)==1)) | |
425 | d.addCallback(lambda _: execute('b=10')) |
|
424 | d.addCallback(lambda _: execute('b=10')) | |
426 | d.addCallback(lambda r: self.assert_(len(r)==4)) |
|
425 | d.addCallback(lambda r: self.assert_(len(r)==4)) | |
427 | d.addCallback(lambda _: execute('c=30', block=False)) |
|
426 | d.addCallback(lambda _: execute('c=30', block=False)) | |
428 | d.addCallback(lambda did: self.assert_(isdid(did))) |
|
427 | d.addCallback(lambda did: self.assert_(isdid(did))) | |
429 | d.addCallback(lambda _: execute('d=[0,1,2]', block=False)) |
|
428 | d.addCallback(lambda _: execute('d=[0,1,2]', block=False)) | |
430 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
429 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
431 | d.addCallback(lambda r: self.assert_(len(r)==4)) |
|
430 | d.addCallback(lambda r: self.assert_(len(r)==4)) | |
432 | return d |
|
431 | return d | |
433 |
|
432 | |||
434 | def testPushPull(self): |
|
433 | def testPushPull(self): | |
435 | data = dict(a=10, b=1.05, c=range(10), d={'e':(1,2),'f':'hi'}) |
|
434 | data = dict(a=10, b=1.05, c=range(10), d={'e':(1,2),'f':'hi'}) | |
436 | self.addEngine(4) |
|
435 | self.addEngine(4) | |
437 | push = self.multiengine.push |
|
436 | push = self.multiengine.push | |
438 | pull = self.multiengine.pull |
|
437 | pull = self.multiengine.pull | |
439 | d= push({'data':data}, targets=0) |
|
438 | d= push({'data':data}, targets=0) | |
440 | d.addCallback(lambda r: pull('data', targets=0)) |
|
439 | d.addCallback(lambda r: pull('data', targets=0)) | |
441 | d.addCallback(lambda r: self.assertEqual(r,[data])) |
|
440 | d.addCallback(lambda r: self.assertEqual(r,[data])) | |
442 | d.addCallback(lambda _: push({'data':data})) |
|
441 | d.addCallback(lambda _: push({'data':data})) | |
443 | d.addCallback(lambda r: pull('data')) |
|
442 | d.addCallback(lambda r: pull('data')) | |
444 | d.addCallback(lambda r: self.assertEqual(r,4*[data])) |
|
443 | d.addCallback(lambda r: self.assertEqual(r,4*[data])) | |
445 | d.addCallback(lambda _: push({'data':data}, block=False)) |
|
444 | d.addCallback(lambda _: push({'data':data}, block=False)) | |
446 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
445 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
447 | d.addCallback(lambda _: pull('data', block=False)) |
|
446 | d.addCallback(lambda _: pull('data', block=False)) | |
448 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
447 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
449 | d.addCallback(lambda r: self.assertEqual(r,4*[data])) |
|
448 | d.addCallback(lambda r: self.assertEqual(r,4*[data])) | |
450 | d.addCallback(lambda _: push(dict(a=10,b=20))) |
|
449 | d.addCallback(lambda _: push(dict(a=10,b=20))) | |
451 | d.addCallback(lambda _: pull(('a','b'))) |
|
450 | d.addCallback(lambda _: pull(('a','b'))) | |
452 | d.addCallback(lambda r: self.assertEquals(r, 4*[[10,20]])) |
|
451 | d.addCallback(lambda r: self.assertEquals(r, 4*[[10,20]])) | |
453 | return d |
|
452 | return d | |
454 |
|
453 | |||
455 | def testPushPullFunction(self): |
|
454 | def testPushPullFunction(self): | |
456 | self.addEngine(4) |
|
455 | self.addEngine(4) | |
457 | pushf = self.multiengine.push_function |
|
456 | pushf = self.multiengine.push_function | |
458 | pullf = self.multiengine.pull_function |
|
457 | pullf = self.multiengine.pull_function | |
459 | push = self.multiengine.push |
|
458 | push = self.multiengine.push | |
460 | pull = self.multiengine.pull |
|
459 | pull = self.multiengine.pull | |
461 | execute = self.multiengine.execute |
|
460 | execute = self.multiengine.execute | |
462 | d= pushf({'testf':testf}, targets=0) |
|
461 | d= pushf({'testf':testf}, targets=0) | |
463 | d.addCallback(lambda r: pullf('testf', targets=0)) |
|
462 | d.addCallback(lambda r: pullf('testf', targets=0)) | |
464 | d.addCallback(lambda r: self.assertEqual(r[0](1.0), testf(1.0))) |
|
463 | d.addCallback(lambda r: self.assertEqual(r[0](1.0), testf(1.0))) | |
465 | d.addCallback(lambda _: execute('r = testf(10)', targets=0)) |
|
464 | d.addCallback(lambda _: execute('r = testf(10)', targets=0)) | |
466 | d.addCallback(lambda _: pull('r', targets=0)) |
|
465 | d.addCallback(lambda _: pull('r', targets=0)) | |
467 | d.addCallback(lambda r: self.assertEquals(r[0], testf(10))) |
|
466 | d.addCallback(lambda r: self.assertEquals(r[0], testf(10))) | |
468 | d.addCallback(lambda _: pushf({'testf':testf}, block=False)) |
|
467 | d.addCallback(lambda _: pushf({'testf':testf}, block=False)) | |
469 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
468 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
470 | d.addCallback(lambda _: pullf('testf', block=False)) |
|
469 | d.addCallback(lambda _: pullf('testf', block=False)) | |
471 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
470 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
472 | d.addCallback(lambda r: self.assertEqual(r[0](1.0), testf(1.0))) |
|
471 | d.addCallback(lambda r: self.assertEqual(r[0](1.0), testf(1.0))) | |
473 | d.addCallback(lambda _: execute("def g(x): return x*x", targets=0)) |
|
472 | d.addCallback(lambda _: execute("def g(x): return x*x", targets=0)) | |
474 | d.addCallback(lambda _: pullf(('testf','g'),targets=0)) |
|
473 | d.addCallback(lambda _: pullf(('testf','g'),targets=0)) | |
475 | d.addCallback(lambda r: self.assertEquals((r[0][0](10),r[0][1](10)), (testf(10), 100))) |
|
474 | d.addCallback(lambda r: self.assertEquals((r[0][0](10),r[0][1](10)), (testf(10), 100))) | |
476 | return d |
|
475 | return d | |
477 |
|
476 | |||
478 | def testGetResult(self): |
|
477 | def testGetResult(self): | |
479 | shell = Interpreter() |
|
478 | shell = Interpreter() | |
480 | result1 = shell.execute('a=10') |
|
479 | result1 = shell.execute('a=10') | |
481 | result1['id'] = 0 |
|
480 | result1['id'] = 0 | |
482 | result2 = shell.execute('b=20') |
|
481 | result2 = shell.execute('b=20') | |
483 | result2['id'] = 0 |
|
482 | result2['id'] = 0 | |
484 | execute= self.multiengine.execute |
|
483 | execute= self.multiengine.execute | |
485 | get_result = self.multiengine.get_result |
|
484 | get_result = self.multiengine.get_result | |
486 | self.addEngine(1) |
|
485 | self.addEngine(1) | |
487 | d= execute('a=10') |
|
486 | d= execute('a=10') | |
488 | d.addCallback(lambda _: get_result()) |
|
487 | d.addCallback(lambda _: get_result()) | |
489 | d.addCallback(lambda r: self.assertEquals(r[0], result1)) |
|
488 | d.addCallback(lambda r: self.assertEquals(r[0], result1)) | |
490 | d.addCallback(lambda _: execute('b=20')) |
|
489 | d.addCallback(lambda _: execute('b=20')) | |
491 | d.addCallback(lambda _: get_result(1)) |
|
490 | d.addCallback(lambda _: get_result(1)) | |
492 | d.addCallback(lambda r: self.assertEquals(r[0], result1)) |
|
491 | d.addCallback(lambda r: self.assertEquals(r[0], result1)) | |
493 | d.addCallback(lambda _: get_result(2, block=False)) |
|
492 | d.addCallback(lambda _: get_result(2, block=False)) | |
494 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
493 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
495 | d.addCallback(lambda r: self.assertEquals(r[0], result2)) |
|
494 | d.addCallback(lambda r: self.assertEquals(r[0], result2)) | |
496 | return d |
|
495 | return d | |
497 |
|
496 | |||
498 | def testResetAndKeys(self): |
|
497 | def testResetAndKeys(self): | |
499 | self.addEngine(1) |
|
498 | self.addEngine(1) | |
500 |
|
499 | |||
501 | #Blocking mode |
|
500 | #Blocking mode | |
502 | d= self.multiengine.push(dict(a=10, b=20, c=range(10)), targets=0) |
|
501 | d= self.multiengine.push(dict(a=10, b=20, c=range(10)), targets=0) | |
503 | d.addCallback(lambda _: self.multiengine.keys(targets=0)) |
|
502 | d.addCallback(lambda _: self.multiengine.keys(targets=0)) | |
504 | def keys_found(keys): |
|
503 | def keys_found(keys): | |
505 | self.assert_('a' in keys[0]) |
|
504 | self.assert_('a' in keys[0]) | |
506 | self.assert_('b' in keys[0]) |
|
505 | self.assert_('b' in keys[0]) | |
507 | self.assert_('b' in keys[0]) |
|
506 | self.assert_('b' in keys[0]) | |
508 | d.addCallback(keys_found) |
|
507 | d.addCallback(keys_found) | |
509 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) |
|
508 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) | |
510 | d.addCallback(lambda _: self.multiengine.keys(targets=0)) |
|
509 | d.addCallback(lambda _: self.multiengine.keys(targets=0)) | |
511 | def keys_not_found(keys): |
|
510 | def keys_not_found(keys): | |
512 | self.assert_('a' not in keys[0]) |
|
511 | self.assert_('a' not in keys[0]) | |
513 | self.assert_('b' not in keys[0]) |
|
512 | self.assert_('b' not in keys[0]) | |
514 | self.assert_('b' not in keys[0]) |
|
513 | self.assert_('b' not in keys[0]) | |
515 | d.addCallback(keys_not_found) |
|
514 | d.addCallback(keys_not_found) | |
516 |
|
515 | |||
517 | #Non-blocking mode |
|
516 | #Non-blocking mode | |
518 | d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20, c=range(10)), targets=0)) |
|
517 | d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20, c=range(10)), targets=0)) | |
519 | d.addCallback(lambda _: self.multiengine.keys(targets=0, block=False)) |
|
518 | d.addCallback(lambda _: self.multiengine.keys(targets=0, block=False)) | |
520 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
519 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
521 | def keys_found(keys): |
|
520 | def keys_found(keys): | |
522 | self.assert_('a' in keys[0]) |
|
521 | self.assert_('a' in keys[0]) | |
523 | self.assert_('b' in keys[0]) |
|
522 | self.assert_('b' in keys[0]) | |
524 | self.assert_('b' in keys[0]) |
|
523 | self.assert_('b' in keys[0]) | |
525 | d.addCallback(keys_found) |
|
524 | d.addCallback(keys_found) | |
526 | d.addCallback(lambda _: self.multiengine.reset(targets=0, block=False)) |
|
525 | d.addCallback(lambda _: self.multiengine.reset(targets=0, block=False)) | |
527 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
526 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
528 | d.addCallback(lambda _: self.multiengine.keys(targets=0, block=False)) |
|
527 | d.addCallback(lambda _: self.multiengine.keys(targets=0, block=False)) | |
529 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
528 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
530 | def keys_not_found(keys): |
|
529 | def keys_not_found(keys): | |
531 | self.assert_('a' not in keys[0]) |
|
530 | self.assert_('a' not in keys[0]) | |
532 | self.assert_('b' not in keys[0]) |
|
531 | self.assert_('b' not in keys[0]) | |
533 | self.assert_('b' not in keys[0]) |
|
532 | self.assert_('b' not in keys[0]) | |
534 | d.addCallback(keys_not_found) |
|
533 | d.addCallback(keys_not_found) | |
535 |
|
534 | |||
536 | return d |
|
535 | return d | |
537 |
|
536 | |||
538 | def testPushPullSerialized(self): |
|
537 | def testPushPullSerialized(self): | |
539 | self.addEngine(1) |
|
538 | self.addEngine(1) | |
540 | dikt = dict(a=10,b='hi there',c=1.2345,d={'p':(1,2)}) |
|
539 | dikt = dict(a=10,b='hi there',c=1.2345,d={'p':(1,2)}) | |
541 | sdikt = {} |
|
540 | sdikt = {} | |
542 | for k,v in dikt.iteritems(): |
|
541 | for k,v in dikt.iteritems(): | |
543 | sdikt[k] = newserialized.serialize(v) |
|
542 | sdikt[k] = newserialized.serialize(v) | |
544 | d= self.multiengine.push_serialized(dict(a=sdikt['a']), targets=0) |
|
543 | d= self.multiengine.push_serialized(dict(a=sdikt['a']), targets=0) | |
545 | d.addCallback(lambda _: self.multiengine.pull('a',targets=0)) |
|
544 | d.addCallback(lambda _: self.multiengine.pull('a',targets=0)) | |
546 | d.addCallback(lambda r: self.assertEquals(r[0], dikt['a'])) |
|
545 | d.addCallback(lambda r: self.assertEquals(r[0], dikt['a'])) | |
547 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0)) |
|
546 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0)) | |
548 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) |
|
547 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) | |
549 | d.addCallback(lambda r: self.assertEquals(r, dikt['a'])) |
|
548 | d.addCallback(lambda r: self.assertEquals(r, dikt['a'])) | |
550 | d.addCallback(lambda _: self.multiengine.push_serialized(sdikt, targets=0)) |
|
549 | d.addCallback(lambda _: self.multiengine.push_serialized(sdikt, targets=0)) | |
551 | d.addCallback(lambda _: self.multiengine.pull_serialized(sdikt.keys(), targets=0)) |
|
550 | d.addCallback(lambda _: self.multiengine.pull_serialized(sdikt.keys(), targets=0)) | |
552 | d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]]) |
|
551 | d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]]) | |
553 | d.addCallback(lambda r: self.assertEquals(r, dikt.values())) |
|
552 | d.addCallback(lambda r: self.assertEquals(r, dikt.values())) | |
554 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) |
|
553 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) | |
555 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0)) |
|
554 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0)) | |
556 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) |
|
555 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) | |
557 |
|
556 | |||
558 | #Non-blocking mode |
|
557 | #Non-blocking mode | |
559 | d.addCallback(lambda r: self.multiengine.push_serialized(dict(a=sdikt['a']), targets=0, block=False)) |
|
558 | d.addCallback(lambda r: self.multiengine.push_serialized(dict(a=sdikt['a']), targets=0, block=False)) | |
560 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
559 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
561 | d.addCallback(lambda _: self.multiengine.pull('a',targets=0)) |
|
560 | d.addCallback(lambda _: self.multiengine.pull('a',targets=0)) | |
562 | d.addCallback(lambda r: self.assertEquals(r[0], dikt['a'])) |
|
561 | d.addCallback(lambda r: self.assertEquals(r[0], dikt['a'])) | |
563 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0, block=False)) |
|
562 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0, block=False)) | |
564 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
563 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
565 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) |
|
564 | d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject()) | |
566 | d.addCallback(lambda r: self.assertEquals(r, dikt['a'])) |
|
565 | d.addCallback(lambda r: self.assertEquals(r, dikt['a'])) | |
567 | d.addCallback(lambda _: self.multiengine.push_serialized(sdikt, targets=0, block=False)) |
|
566 | d.addCallback(lambda _: self.multiengine.push_serialized(sdikt, targets=0, block=False)) | |
568 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
567 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
569 | d.addCallback(lambda _: self.multiengine.pull_serialized(sdikt.keys(), targets=0, block=False)) |
|
568 | d.addCallback(lambda _: self.multiengine.pull_serialized(sdikt.keys(), targets=0, block=False)) | |
570 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
569 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
571 | d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]]) |
|
570 | d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]]) | |
572 | d.addCallback(lambda r: self.assertEquals(r, dikt.values())) |
|
571 | d.addCallback(lambda r: self.assertEquals(r, dikt.values())) | |
573 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) |
|
572 | d.addCallback(lambda _: self.multiengine.reset(targets=0)) | |
574 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0, block=False)) |
|
573 | d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0, block=False)) | |
575 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
574 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
576 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) |
|
575 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) | |
577 | return d |
|
576 | return d | |
578 |
|
577 | |||
579 | def testClearQueue(self): |
|
578 | def testClearQueue(self): | |
580 | self.addEngine(4) |
|
579 | self.addEngine(4) | |
581 | d= self.multiengine.clear_queue() |
|
580 | d= self.multiengine.clear_queue() | |
582 | d.addCallback(lambda r: self.multiengine.clear_queue(block=False)) |
|
581 | d.addCallback(lambda r: self.multiengine.clear_queue(block=False)) | |
583 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
582 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
584 | d.addCallback(lambda r: self.assertEquals(r,4*[None])) |
|
583 | d.addCallback(lambda r: self.assertEquals(r,4*[None])) | |
585 | return d |
|
584 | return d | |
586 |
|
585 | |||
587 | def testQueueStatus(self): |
|
586 | def testQueueStatus(self): | |
588 | self.addEngine(4) |
|
587 | self.addEngine(4) | |
589 | d= self.multiengine.queue_status(targets=0) |
|
588 | d= self.multiengine.queue_status(targets=0) | |
590 | d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple))) |
|
589 | d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple))) | |
591 | d.addCallback(lambda r: self.multiengine.queue_status(targets=0, block=False)) |
|
590 | d.addCallback(lambda r: self.multiengine.queue_status(targets=0, block=False)) | |
592 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
591 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
593 | d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple))) |
|
592 | d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple))) | |
594 | return d |
|
593 | return d | |
595 |
|
594 | |||
596 | def testGetIDs(self): |
|
595 | def testGetIDs(self): | |
597 | self.addEngine(1) |
|
596 | self.addEngine(1) | |
598 | d= self.multiengine.get_ids() |
|
597 | d= self.multiengine.get_ids() | |
599 | d.addCallback(lambda r: self.assertEquals(r, [0])) |
|
598 | d.addCallback(lambda r: self.assertEquals(r, [0])) | |
600 | d.addCallback(lambda _: self.addEngine(3)) |
|
599 | d.addCallback(lambda _: self.addEngine(3)) | |
601 | d.addCallback(lambda _: self.multiengine.get_ids()) |
|
600 | d.addCallback(lambda _: self.multiengine.get_ids()) | |
602 | d.addCallback(lambda r: self.assertEquals(r, [0,1,2,3])) |
|
601 | d.addCallback(lambda r: self.assertEquals(r, [0,1,2,3])) | |
603 | return d |
|
602 | return d | |
604 |
|
603 | |||
605 | def testGetSetProperties(self): |
|
604 | def testGetSetProperties(self): | |
606 | self.addEngine(4) |
|
605 | self.addEngine(4) | |
607 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) |
|
606 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) | |
608 | d= self.multiengine.set_properties(dikt) |
|
607 | d= self.multiengine.set_properties(dikt) | |
609 | d.addCallback(lambda r: self.multiengine.get_properties()) |
|
608 | d.addCallback(lambda r: self.multiengine.get_properties()) | |
610 | d.addCallback(lambda r: self.assertEquals(r, 4*[dikt])) |
|
609 | d.addCallback(lambda r: self.assertEquals(r, 4*[dikt])) | |
611 | d.addCallback(lambda r: self.multiengine.get_properties(('c',))) |
|
610 | d.addCallback(lambda r: self.multiengine.get_properties(('c',))) | |
612 | d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}])) |
|
611 | d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}])) | |
613 | d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False))) |
|
612 | d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False))) | |
614 | d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd'))) |
|
613 | d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd'))) | |
615 | d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)])) |
|
614 | d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)])) | |
616 |
|
615 | |||
617 | #Non-blocking |
|
616 | #Non-blocking | |
618 | d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False)) |
|
617 | d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False)) | |
619 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
618 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
620 | d.addCallback(lambda r: self.multiengine.get_properties(block=False)) |
|
619 | d.addCallback(lambda r: self.multiengine.get_properties(block=False)) | |
621 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
620 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
622 | d.addCallback(lambda r: self.assertEquals(r, 4*[dikt])) |
|
621 | d.addCallback(lambda r: self.assertEquals(r, 4*[dikt])) | |
623 | d.addCallback(lambda r: self.multiengine.get_properties(('c',), block=False)) |
|
622 | d.addCallback(lambda r: self.multiengine.get_properties(('c',), block=False)) | |
624 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
623 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
625 | d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}])) |
|
624 | d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}])) | |
626 | d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False), block=False)) |
|
625 | d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False), block=False)) | |
627 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
626 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
628 | d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd'), block=False)) |
|
627 | d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd'), block=False)) | |
629 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
628 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
630 | d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)])) |
|
629 | d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)])) | |
631 | return d |
|
630 | return d | |
632 |
|
631 | |||
633 | def testClearProperties(self): |
|
632 | def testClearProperties(self): | |
634 | self.addEngine(4) |
|
633 | self.addEngine(4) | |
635 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) |
|
634 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) | |
636 | d= self.multiengine.set_properties(dikt) |
|
635 | d= self.multiengine.set_properties(dikt) | |
637 | d.addCallback(lambda r: self.multiengine.clear_properties()) |
|
636 | d.addCallback(lambda r: self.multiengine.clear_properties()) | |
638 | d.addCallback(lambda r: self.multiengine.get_properties()) |
|
637 | d.addCallback(lambda r: self.multiengine.get_properties()) | |
639 | d.addCallback(lambda r: self.assertEquals(r, 4*[{}])) |
|
638 | d.addCallback(lambda r: self.assertEquals(r, 4*[{}])) | |
640 |
|
639 | |||
641 | #Non-blocking |
|
640 | #Non-blocking | |
642 | d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False)) |
|
641 | d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False)) | |
643 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
642 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
644 | d.addCallback(lambda r: self.multiengine.clear_properties(block=False)) |
|
643 | d.addCallback(lambda r: self.multiengine.clear_properties(block=False)) | |
645 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
644 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
646 | d.addCallback(lambda r: self.multiengine.get_properties(block=False)) |
|
645 | d.addCallback(lambda r: self.multiengine.get_properties(block=False)) | |
647 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
646 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
648 | d.addCallback(lambda r: self.assertEquals(r, 4*[{}])) |
|
647 | d.addCallback(lambda r: self.assertEquals(r, 4*[{}])) | |
649 | return d |
|
648 | return d | |
650 |
|
649 | |||
651 | def testDelHasProperties(self): |
|
650 | def testDelHasProperties(self): | |
652 | self.addEngine(4) |
|
651 | self.addEngine(4) | |
653 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) |
|
652 | dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5)) | |
654 | d= self.multiengine.set_properties(dikt) |
|
653 | d= self.multiengine.set_properties(dikt) | |
655 | d.addCallback(lambda r: self.multiengine.del_properties(('b','e'))) |
|
654 | d.addCallback(lambda r: self.multiengine.del_properties(('b','e'))) | |
656 | d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e'))) |
|
655 | d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e'))) | |
657 | d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]])) |
|
656 | d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]])) | |
658 |
|
657 | |||
659 | #Non-blocking |
|
658 | #Non-blocking | |
660 | d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False)) |
|
659 | d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False)) | |
661 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
660 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
662 | d.addCallback(lambda r: self.multiengine.del_properties(('b','e'), block=False)) |
|
661 | d.addCallback(lambda r: self.multiengine.del_properties(('b','e'), block=False)) | |
663 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
662 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
664 | d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e'), block=False)) |
|
663 | d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e'), block=False)) | |
665 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
664 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
666 | d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]])) |
|
665 | d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]])) | |
667 | return d |
|
666 | return d | |
668 |
|
667 | |||
669 | def test_clear_pending_deferreds(self): |
|
668 | def test_clear_pending_deferreds(self): | |
670 | self.addEngine(4) |
|
669 | self.addEngine(4) | |
671 | did_list = [] |
|
670 | did_list = [] | |
672 | d= self.multiengine.execute('a=10',block=False) |
|
671 | d= self.multiengine.execute('a=10',block=False) | |
673 | d.addCallback(lambda did: did_list.append(did)) |
|
672 | d.addCallback(lambda did: did_list.append(did)) | |
674 | d.addCallback(lambda _: self.multiengine.push(dict(b=10),block=False)) |
|
673 | d.addCallback(lambda _: self.multiengine.push(dict(b=10),block=False)) | |
675 | d.addCallback(lambda did: did_list.append(did)) |
|
674 | d.addCallback(lambda did: did_list.append(did)) | |
676 | d.addCallback(lambda _: self.multiengine.pull(('a','b'),block=False)) |
|
675 | d.addCallback(lambda _: self.multiengine.pull(('a','b'),block=False)) | |
677 | d.addCallback(lambda did: did_list.append(did)) |
|
676 | d.addCallback(lambda did: did_list.append(did)) | |
678 | d.addCallback(lambda _: self.multiengine.clear_pending_deferreds()) |
|
677 | d.addCallback(lambda _: self.multiengine.clear_pending_deferreds()) | |
679 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[0],True)) |
|
678 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[0],True)) | |
680 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) |
|
679 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) | |
681 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[1],True)) |
|
680 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[1],True)) | |
682 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) |
|
681 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) | |
683 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[2],True)) |
|
682 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[2],True)) | |
684 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) |
|
683 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) | |
685 | return d |
|
684 | return d | |
686 |
|
685 | |||
687 | #------------------------------------------------------------------------------- |
|
686 | #------------------------------------------------------------------------------- | |
688 | # Coordinator test cases |
|
687 | # Coordinator test cases | |
689 | #------------------------------------------------------------------------------- |
|
688 | #------------------------------------------------------------------------------- | |
690 |
|
689 | |||
691 | class IMultiEngineCoordinatorTestCase(object): |
|
690 | class IMultiEngineCoordinatorTestCase(object): | |
692 |
|
691 | |||
693 | def testScatterGather(self): |
|
692 | def testScatterGather(self): | |
694 | self.addEngine(4) |
|
693 | self.addEngine(4) | |
695 | d= self.multiengine.scatter('a', range(16)) |
|
694 | d= self.multiengine.scatter('a', range(16)) | |
696 | d.addCallback(lambda r: self.multiengine.gather('a')) |
|
695 | d.addCallback(lambda r: self.multiengine.gather('a')) | |
697 | d.addCallback(lambda r: self.assertEquals(r, range(16))) |
|
696 | d.addCallback(lambda r: self.assertEquals(r, range(16))) | |
698 | d.addCallback(lambda _: self.multiengine.gather('asdf')) |
|
697 | d.addCallback(lambda _: self.multiengine.gather('asdf')) | |
699 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) |
|
698 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) | |
700 | return d |
|
699 | return d | |
701 |
|
700 | |||
702 | def testScatterGatherNumpy(self): |
|
701 | def testScatterGatherNumpy(self): | |
703 | try: |
|
702 | try: | |
704 | import numpy |
|
703 | import numpy | |
705 | from numpy.testing.utils import assert_array_equal, assert_array_almost_equal |
|
704 | from numpy.testing.utils import assert_array_equal, assert_array_almost_equal | |
706 | except: |
|
705 | except: | |
707 | return |
|
706 | return | |
708 | else: |
|
707 | else: | |
709 | self.addEngine(4) |
|
708 | self.addEngine(4) | |
710 | a = numpy.arange(16) |
|
709 | a = numpy.arange(16) | |
711 | d = self.multiengine.scatter('a', a) |
|
710 | d = self.multiengine.scatter('a', a) | |
712 | d.addCallback(lambda r: self.multiengine.gather('a')) |
|
711 | d.addCallback(lambda r: self.multiengine.gather('a')) | |
713 | d.addCallback(lambda r: assert_array_equal(r, a)) |
|
712 | d.addCallback(lambda r: assert_array_equal(r, a)) | |
714 | return d |
|
713 | return d | |
715 |
|
714 | |||
716 | def testMap(self): |
|
715 | def testMap(self): | |
717 | self.addEngine(4) |
|
716 | self.addEngine(4) | |
718 | def f(x): |
|
717 | def f(x): | |
719 | return x**2 |
|
718 | return x**2 | |
720 | data = range(16) |
|
719 | data = range(16) | |
721 | d= self.multiengine.map(f, data) |
|
720 | d= self.multiengine.map(f, data) | |
722 | d.addCallback(lambda r: self.assertEquals(r,[f(x) for x in data])) |
|
721 | d.addCallback(lambda r: self.assertEquals(r,[f(x) for x in data])) | |
723 | return d |
|
722 | return d | |
724 |
|
723 | |||
725 |
|
724 | |||
726 | class ISynchronousMultiEngineCoordinatorTestCase(IMultiEngineCoordinatorTestCase): |
|
725 | class ISynchronousMultiEngineCoordinatorTestCase(IMultiEngineCoordinatorTestCase): | |
727 |
|
726 | |||
728 | def testScatterGatherNonblocking(self): |
|
727 | def testScatterGatherNonblocking(self): | |
729 | self.addEngine(4) |
|
728 | self.addEngine(4) | |
730 | d= self.multiengine.scatter('a', range(16), block=False) |
|
729 | d= self.multiengine.scatter('a', range(16), block=False) | |
731 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
730 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
732 | d.addCallback(lambda r: self.multiengine.gather('a', block=False)) |
|
731 | d.addCallback(lambda r: self.multiengine.gather('a', block=False)) | |
733 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
732 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
734 | d.addCallback(lambda r: self.assertEquals(r, range(16))) |
|
733 | d.addCallback(lambda r: self.assertEquals(r, range(16))) | |
735 | return d |
|
734 | return d | |
736 |
|
735 | |||
737 | def testScatterGatherNumpyNonblocking(self): |
|
736 | def testScatterGatherNumpyNonblocking(self): | |
738 | try: |
|
737 | try: | |
739 | import numpy |
|
738 | import numpy | |
740 | from numpy.testing.utils import assert_array_equal, assert_array_almost_equal |
|
739 | from numpy.testing.utils import assert_array_equal, assert_array_almost_equal | |
741 | except: |
|
740 | except: | |
742 | return |
|
741 | return | |
743 | else: |
|
742 | else: | |
744 | self.addEngine(4) |
|
743 | self.addEngine(4) | |
745 | a = numpy.arange(16) |
|
744 | a = numpy.arange(16) | |
746 | d = self.multiengine.scatter('a', a, block=False) |
|
745 | d = self.multiengine.scatter('a', a, block=False) | |
747 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
746 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
748 | d.addCallback(lambda r: self.multiengine.gather('a', block=False)) |
|
747 | d.addCallback(lambda r: self.multiengine.gather('a', block=False)) | |
749 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
748 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
750 | d.addCallback(lambda r: assert_array_equal(r, a)) |
|
749 | d.addCallback(lambda r: assert_array_equal(r, a)) | |
751 | return d |
|
750 | return d | |
752 |
|
751 | |||
753 | def test_clear_pending_deferreds(self): |
|
752 | def test_clear_pending_deferreds(self): | |
754 | self.addEngine(4) |
|
753 | self.addEngine(4) | |
755 | did_list = [] |
|
754 | did_list = [] | |
756 | d= self.multiengine.scatter('a',range(16),block=False) |
|
755 | d= self.multiengine.scatter('a',range(16),block=False) | |
757 | d.addCallback(lambda did: did_list.append(did)) |
|
756 | d.addCallback(lambda did: did_list.append(did)) | |
758 | d.addCallback(lambda _: self.multiengine.gather('a',block=False)) |
|
757 | d.addCallback(lambda _: self.multiengine.gather('a',block=False)) | |
759 | d.addCallback(lambda did: did_list.append(did)) |
|
758 | d.addCallback(lambda did: did_list.append(did)) | |
760 | d.addCallback(lambda _: self.multiengine.map(lambda x: x, range(16),block=False)) |
|
759 | d.addCallback(lambda _: self.multiengine.map(lambda x: x, range(16),block=False)) | |
761 | d.addCallback(lambda did: did_list.append(did)) |
|
760 | d.addCallback(lambda did: did_list.append(did)) | |
762 | d.addCallback(lambda _: self.multiengine.clear_pending_deferreds()) |
|
761 | d.addCallback(lambda _: self.multiengine.clear_pending_deferreds()) | |
763 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[0],True)) |
|
762 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[0],True)) | |
764 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) |
|
763 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) | |
765 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[1],True)) |
|
764 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[1],True)) | |
766 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) |
|
765 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) | |
767 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[2],True)) |
|
766 | d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[2],True)) | |
768 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) |
|
767 | d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException)) | |
769 | return d |
|
768 | return d | |
770 |
|
769 | |||
771 | #------------------------------------------------------------------------------- |
|
770 | #------------------------------------------------------------------------------- | |
772 | # Extras test cases |
|
771 | # Extras test cases | |
773 | #------------------------------------------------------------------------------- |
|
772 | #------------------------------------------------------------------------------- | |
774 |
|
773 | |||
775 | class IMultiEngineExtrasTestCase(object): |
|
774 | class IMultiEngineExtrasTestCase(object): | |
776 |
|
775 | |||
777 | def testZipPull(self): |
|
776 | def testZipPull(self): | |
778 | self.addEngine(4) |
|
777 | self.addEngine(4) | |
779 | d= self.multiengine.push(dict(a=10,b=20)) |
|
778 | d= self.multiengine.push(dict(a=10,b=20)) | |
780 | d.addCallback(lambda r: self.multiengine.zip_pull(('a','b'))) |
|
779 | d.addCallback(lambda r: self.multiengine.zip_pull(('a','b'))) | |
781 | d.addCallback(lambda r: self.assert_(r, [4*[10],4*[20]])) |
|
780 | d.addCallback(lambda r: self.assert_(r, [4*[10],4*[20]])) | |
782 | return d |
|
781 | return d | |
783 |
|
782 | |||
784 | def testRun(self): |
|
783 | def testRun(self): | |
785 | self.addEngine(4) |
|
784 | self.addEngine(4) | |
786 | import tempfile |
|
785 | import tempfile | |
787 | fname = tempfile.mktemp('foo.py') |
|
786 | fname = tempfile.mktemp('foo.py') | |
788 | f= open(fname, 'w') |
|
787 | f= open(fname, 'w') | |
789 | f.write('a = 10\nb=30') |
|
788 | f.write('a = 10\nb=30') | |
790 | f.close() |
|
789 | f.close() | |
791 | d= self.multiengine.run(fname) |
|
790 | d= self.multiengine.run(fname) | |
792 | d.addCallback(lambda r: self.multiengine.pull(('a','b'))) |
|
791 | d.addCallback(lambda r: self.multiengine.pull(('a','b'))) | |
793 | d.addCallback(lambda r: self.assertEquals(r, 4*[[10,30]])) |
|
792 | d.addCallback(lambda r: self.assertEquals(r, 4*[[10,30]])) | |
794 | return d |
|
793 | return d | |
795 |
|
794 | |||
796 |
|
795 | |||
797 | class ISynchronousMultiEngineExtrasTestCase(IMultiEngineExtrasTestCase): |
|
796 | class ISynchronousMultiEngineExtrasTestCase(IMultiEngineExtrasTestCase): | |
798 |
|
797 | |||
799 | def testZipPullNonblocking(self): |
|
798 | def testZipPullNonblocking(self): | |
800 | self.addEngine(4) |
|
799 | self.addEngine(4) | |
801 | d= self.multiengine.push(dict(a=10,b=20)) |
|
800 | d= self.multiengine.push(dict(a=10,b=20)) | |
802 | d.addCallback(lambda r: self.multiengine.zip_pull(('a','b'), block=False)) |
|
801 | d.addCallback(lambda r: self.multiengine.zip_pull(('a','b'), block=False)) | |
803 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
802 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
804 | d.addCallback(lambda r: self.assert_(r, [4*[10],4*[20]])) |
|
803 | d.addCallback(lambda r: self.assert_(r, [4*[10],4*[20]])) | |
805 | return d |
|
804 | return d | |
806 |
|
805 | |||
807 | def testRunNonblocking(self): |
|
806 | def testRunNonblocking(self): | |
808 | self.addEngine(4) |
|
807 | self.addEngine(4) | |
809 | import tempfile |
|
808 | import tempfile | |
810 | fname = tempfile.mktemp('foo.py') |
|
809 | fname = tempfile.mktemp('foo.py') | |
811 | f= open(fname, 'w') |
|
810 | f= open(fname, 'w') | |
812 | f.write('a = 10\nb=30') |
|
811 | f.write('a = 10\nb=30') | |
813 | f.close() |
|
812 | f.close() | |
814 | d= self.multiengine.run(fname, block=False) |
|
813 | d= self.multiengine.run(fname, block=False) | |
815 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) |
|
814 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
816 | d.addCallback(lambda r: self.multiengine.pull(('a','b'))) |
|
815 | d.addCallback(lambda r: self.multiengine.pull(('a','b'))) | |
817 | d.addCallback(lambda r: self.assertEquals(r, 4*[[10,30]])) |
|
816 | d.addCallback(lambda r: self.assertEquals(r, 4*[[10,30]])) | |
818 | return d |
|
817 | return d | |
819 |
|
818 | |||
820 |
|
819 | |||
821 | #------------------------------------------------------------------------------- |
|
820 | #------------------------------------------------------------------------------- | |
822 | # IFullSynchronousMultiEngineTestCase |
|
821 | # IFullSynchronousMultiEngineTestCase | |
823 | #------------------------------------------------------------------------------- |
|
822 | #------------------------------------------------------------------------------- | |
824 |
|
823 | |||
825 | class IFullSynchronousMultiEngineTestCase(ISynchronousMultiEngineTestCase, |
|
824 | class IFullSynchronousMultiEngineTestCase(ISynchronousMultiEngineTestCase, | |
826 | ISynchronousMultiEngineCoordinatorTestCase, |
|
825 | ISynchronousMultiEngineCoordinatorTestCase, | |
827 | ISynchronousMultiEngineExtrasTestCase): |
|
826 | ISynchronousMultiEngineExtrasTestCase): | |
828 | pass |
|
827 | pass |
@@ -1,360 +1,393 b'' | |||||
1 | .. _development: |
|
1 | .. _development: | |
2 |
|
2 | |||
3 | ================================== |
|
3 | ================================== | |
4 | IPython development guidelines |
|
4 | IPython development guidelines | |
5 | ================================== |
|
5 | ================================== | |
6 |
|
6 | |||
7 | .. contents:: |
|
7 | .. contents:: | |
8 |
|
8 | |||
9 |
|
9 | |||
10 | Overview |
|
10 | Overview | |
11 | ======== |
|
11 | ======== | |
12 |
|
12 | |||
13 | IPython is the next generation of IPython. It is named such for two reasons: |
|
13 | IPython is the next generation of IPython. It is named such for two reasons: | |
14 |
|
14 | |||
15 | - Eventually, IPython will become IPython version 1.0. |
|
15 | - Eventually, IPython will become IPython version 1.0. | |
16 | - This new code base needs to be able to co-exist with the existing IPython until |
|
16 | - This new code base needs to be able to co-exist with the existing IPython until | |
17 | it is a full replacement for it. Thus we needed a different name. We couldn't |
|
17 | it is a full replacement for it. Thus we needed a different name. We couldn't | |
18 | use ``ipython`` (lowercase) as some files systems are case insensitive. |
|
18 | use ``ipython`` (lowercase) as some files systems are case insensitive. | |
19 |
|
19 | |||
20 | There are two, no three, main goals of the IPython effort: |
|
20 | There are two, no three, main goals of the IPython effort: | |
21 |
|
21 | |||
22 | 1. Clean up the existing codebase and write lots of tests. |
|
22 | 1. Clean up the existing codebase and write lots of tests. | |
23 | 2. Separate the core functionality of IPython from the terminal to enable IPython |
|
23 | 2. Separate the core functionality of IPython from the terminal to enable IPython | |
24 | to be used from within a variety of GUI applications. |
|
24 | to be used from within a variety of GUI applications. | |
25 | 3. Implement a system for interactive parallel computing. |
|
25 | 3. Implement a system for interactive parallel computing. | |
26 |
|
26 | |||
27 | While the third goal may seem a bit unrelated to the main focus of IPython, it turns |
|
27 | While the third goal may seem a bit unrelated to the main focus of IPython, it turns | |
28 | out that the technologies required for this goal are nearly identical with those |
|
28 | out that the technologies required for this goal are nearly identical with those | |
29 | required for goal two. This is the main reason the interactive parallel computing |
|
29 | required for goal two. This is the main reason the interactive parallel computing | |
30 | capabilities are being put into IPython proper. Currently the third of these goals is |
|
30 | capabilities are being put into IPython proper. Currently the third of these goals is | |
31 | furthest along. |
|
31 | furthest along. | |
32 |
|
32 | |||
33 | This document describes IPython from the perspective of developers. |
|
33 | This document describes IPython from the perspective of developers. | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | Project organization |
|
36 | Project organization | |
37 | ==================== |
|
37 | ==================== | |
38 |
|
38 | |||
39 | Subpackages |
|
39 | Subpackages | |
40 | ----------- |
|
40 | ----------- | |
41 |
|
41 | |||
42 | IPython is organized into semi self-contained subpackages. Each of the subpackages will have its own: |
|
42 | IPython is organized into semi self-contained subpackages. Each of the subpackages will have its own: | |
43 |
|
43 | |||
44 | - **Dependencies**. One of the most important things to keep in mind in |
|
44 | - **Dependencies**. One of the most important things to keep in mind in | |
45 | partitioning code amongst subpackages, is that they should be used to cleanly |
|
45 | partitioning code amongst subpackages, is that they should be used to cleanly | |
46 | encapsulate dependencies. |
|
46 | encapsulate dependencies. | |
47 | - **Tests**. Each subpackage shoud have its own ``tests`` subdirectory that |
|
47 | - **Tests**. Each subpackage shoud have its own ``tests`` subdirectory that | |
48 | contains all of the tests for that package. For information about writing tests |
|
48 | contains all of the tests for that package. For information about writing tests | |
49 | for IPython, see the `Testing System`_ section of this document. |
|
49 | for IPython, see the `Testing System`_ section of this document. | |
50 | - **Configuration**. Each subpackage should have its own ``config`` subdirectory |
|
50 | - **Configuration**. Each subpackage should have its own ``config`` subdirectory | |
51 | that contains the configuration information for the components of the |
|
51 | that contains the configuration information for the components of the | |
52 | subpackage. For information about how the IPython configuration system |
|
52 | subpackage. For information about how the IPython configuration system | |
53 | works, see the `Configuration System`_ section of this document. |
|
53 | works, see the `Configuration System`_ section of this document. | |
54 | - **Scripts**. Each subpackage should have its own ``scripts`` subdirectory that |
|
54 | - **Scripts**. Each subpackage should have its own ``scripts`` subdirectory that | |
55 | contains all of the command line scripts associated with the subpackage. |
|
55 | contains all of the command line scripts associated with the subpackage. | |
56 |
|
56 | |||
57 | Installation and dependencies |
|
57 | Installation and dependencies | |
58 | ----------------------------- |
|
58 | ----------------------------- | |
59 |
|
59 | |||
60 | IPython will not use `setuptools`_ for installation. Instead, we will use standard |
|
60 | IPython will not use `setuptools`_ for installation. Instead, we will use standard | |
61 | ``setup.py`` scripts that use `distutils`_. While there are a number a extremely nice |
|
61 | ``setup.py`` scripts that use `distutils`_. While there are a number a extremely nice | |
62 | features that `setuptools`_ has (like namespace packages), the current implementation |
|
62 | features that `setuptools`_ has (like namespace packages), the current implementation | |
63 | of `setuptools`_ has performance problems, particularly on shared file systems. In |
|
63 | of `setuptools`_ has performance problems, particularly on shared file systems. In | |
64 | particular, when Python packages are installed on NSF file systems, import times |
|
64 | particular, when Python packages are installed on NSF file systems, import times | |
65 | become much too long (up towards 10 seconds). |
|
65 | become much too long (up towards 10 seconds). | |
66 |
|
66 | |||
67 | Because IPython is being used extensively in the context of high performance |
|
67 | Because IPython is being used extensively in the context of high performance | |
68 | computing, where performance is critical but shared file systems are common, we feel |
|
68 | computing, where performance is critical but shared file systems are common, we feel | |
69 | these performance hits are not acceptable. Thus, until the performance problems |
|
69 | these performance hits are not acceptable. Thus, until the performance problems | |
70 | associated with `setuptools`_ are addressed, we will stick with plain `distutils`_. We |
|
70 | associated with `setuptools`_ are addressed, we will stick with plain `distutils`_. We | |
71 | are hopeful that these problems will be addressed and that we will eventually begin |
|
71 | are hopeful that these problems will be addressed and that we will eventually begin | |
72 | using `setuptools`_. Because of this, we are trying to organize IPython in a way that |
|
72 | using `setuptools`_. Because of this, we are trying to organize IPython in a way that | |
73 | will make the eventual transition to `setuptools`_ as painless as possible. |
|
73 | will make the eventual transition to `setuptools`_ as painless as possible. | |
74 |
|
74 | |||
75 | Because we will be using `distutils`_, there will be no method for automatically installing dependencies. Instead, we are following the approach of `Matplotlib`_ which can be summarized as follows: |
|
75 | Because we will be using `distutils`_, there will be no method for automatically installing dependencies. Instead, we are following the approach of `Matplotlib`_ which can be summarized as follows: | |
76 |
|
76 | |||
77 | - Distinguish between required and optional dependencies. However, the required |
|
77 | - Distinguish between required and optional dependencies. However, the required | |
78 | dependencies for IPython should be only the Python standard library. |
|
78 | dependencies for IPython should be only the Python standard library. | |
79 | - Upon installation check to see which optional dependencies are present and tell |
|
79 | - Upon installation check to see which optional dependencies are present and tell | |
80 | the user which parts of IPython need which optional dependencies. |
|
80 | the user which parts of IPython need which optional dependencies. | |
81 |
|
81 | |||
82 | It is absolutely critical that each subpackage of IPython has a clearly specified set |
|
82 | It is absolutely critical that each subpackage of IPython has a clearly specified set | |
83 | of dependencies and that dependencies are not carelessly inherited from other IPython |
|
83 | of dependencies and that dependencies are not carelessly inherited from other IPython | |
84 | subpackages. Furthermore, tests that have certain dependencies should not fail if |
|
84 | subpackages. Furthermore, tests that have certain dependencies should not fail if | |
85 | those dependencies are not present. Instead they should be skipped and print a |
|
85 | those dependencies are not present. Instead they should be skipped and print a | |
86 | message. |
|
86 | message. | |
87 |
|
87 | |||
88 | .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools |
|
88 | .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools | |
89 | .. _distutils: http://docs.python.org/lib/module-distutils.html |
|
89 | .. _distutils: http://docs.python.org/lib/module-distutils.html | |
90 | .. _Matplotlib: http://matplotlib.sourceforge.net/ |
|
90 | .. _Matplotlib: http://matplotlib.sourceforge.net/ | |
91 |
|
91 | |||
92 | Specific subpackages |
|
92 | Specific subpackages | |
93 | -------------------- |
|
93 | -------------------- | |
94 |
|
94 | |||
95 | ``core`` |
|
95 | ``core`` | |
96 | This is the core functionality of IPython that is independent of the |
|
96 | This is the core functionality of IPython that is independent of the | |
97 | terminal, network and GUIs. Most of the code that is in the current |
|
97 | terminal, network and GUIs. Most of the code that is in the current | |
98 | IPython trunk will be refactored, cleaned up and moved here. |
|
98 | IPython trunk will be refactored, cleaned up and moved here. | |
99 |
|
99 | |||
100 | ``kernel`` |
|
100 | ``kernel`` | |
101 | The enables the IPython core to be expose to a the network. This is |
|
101 | The enables the IPython core to be expose to a the network. This is | |
102 | also where all of the parallel computing capabilities are to be found. |
|
102 | also where all of the parallel computing capabilities are to be found. | |
103 |
|
103 | |||
104 | ``config`` |
|
104 | ``config`` | |
105 | The configuration package used by IPython. |
|
105 | The configuration package used by IPython. | |
106 |
|
106 | |||
107 | ``frontends`` |
|
107 | ``frontends`` | |
108 | The various frontends for IPython. A frontend is the end-user application |
|
108 | The various frontends for IPython. A frontend is the end-user application | |
109 | that exposes the capabilities of IPython to the user. The most basic frontend |
|
109 | that exposes the capabilities of IPython to the user. The most basic frontend | |
110 | will simply be a terminal based application that looks just like today 's |
|
110 | will simply be a terminal based application that looks just like today 's | |
111 | IPython. Other frontends will likely be more powerful and based on GUI toolkits. |
|
111 | IPython. Other frontends will likely be more powerful and based on GUI toolkits. | |
112 |
|
112 | |||
113 | ``notebook`` |
|
113 | ``notebook`` | |
114 | An application that allows users to work with IPython notebooks. |
|
114 | An application that allows users to work with IPython notebooks. | |
115 |
|
115 | |||
116 | ``tools`` |
|
116 | ``tools`` | |
117 | This is where general utilities go. |
|
117 | This is where general utilities go. | |
118 |
|
118 | |||
119 |
|
119 | |||
120 | Version control |
|
120 | Version control | |
121 | =============== |
|
121 | =============== | |
122 |
|
122 | |||
123 | In the past, IPython development has been done using `Subversion`__. Recently, we made the transition to using `Bazaar`__ and `Launchpad`__. This makes it much easier for people |
|
123 | In the past, IPython development has been done using `Subversion`__. Recently, we made the transition to using `Bazaar`__ and `Launchpad`__. This makes it much easier for people | |
124 | to contribute code to IPython. Here is a sketch of how to use Bazaar for IPython |
|
124 | to contribute code to IPython. Here is a sketch of how to use Bazaar for IPython | |
125 | development. First, you should install Bazaar. After you have done that, make |
|
125 | development. First, you should install Bazaar. After you have done that, make | |
126 | sure that it is working by getting the latest main branch of IPython:: |
|
126 | sure that it is working by getting the latest main branch of IPython:: | |
127 |
|
127 | |||
128 | $ bzr branch lp:ipython |
|
128 | $ bzr branch lp:ipython | |
129 |
|
129 | |||
130 | Now you can create a new branch for you to do your work in:: |
|
130 | Now you can create a new branch for you to do your work in:: | |
131 |
|
131 | |||
132 | $ bzr branch ipython ipython-mybranch |
|
132 | $ bzr branch ipython ipython-mybranch | |
133 |
|
133 | |||
134 | The typical work cycle in this branch will be to make changes in `ipython-mybranch` |
|
134 | The typical work cycle in this branch will be to make changes in `ipython-mybranch` | |
135 | and then commit those changes using the commit command:: |
|
135 | and then commit those changes using the commit command:: | |
136 |
|
136 | |||
137 | $ ...do work in ipython-mybranch... |
|
137 | $ ...do work in ipython-mybranch... | |
138 | $ bzr ci -m "the commit message goes here" |
|
138 | $ bzr ci -m "the commit message goes here" | |
139 |
|
139 | |||
140 | Please note that since we now don't use an old-style linear ChangeLog |
|
140 | Please note that since we now don't use an old-style linear ChangeLog | |
141 | (that tends to cause problems with distributed version control |
|
141 | (that tends to cause problems with distributed version control | |
142 | systems), you should ensure that your log messages are reasonably |
|
142 | systems), you should ensure that your log messages are reasonably | |
143 | detailed. Use a docstring-like approach in the commit messages |
|
143 | detailed. Use a docstring-like approach in the commit messages | |
144 | (including the second line being left *blank*):: |
|
144 | (including the second line being left *blank*):: | |
145 |
|
145 | |||
146 | Single line summary of changes being committed. |
|
146 | Single line summary of changes being committed. | |
147 |
|
147 | |||
148 | - more details when warranted ... |
|
148 | - more details when warranted ... | |
149 | - including crediting outside contributors if they sent the |
|
149 | - including crediting outside contributors if they sent the | |
150 | code/bug/idea! |
|
150 | code/bug/idea! | |
151 |
|
151 | |||
152 | If we couple this with a policy of making single commits for each |
|
152 | If we couple this with a policy of making single commits for each | |
153 | reasonably atomic change, the bzr log should give an excellent view of |
|
153 | reasonably atomic change, the bzr log should give an excellent view of | |
154 | the project, and the `--short` log option becomes a nice summary. |
|
154 | the project, and the `--short` log option becomes a nice summary. | |
155 |
|
155 | |||
156 | While working with this branch, it is a good idea to merge in changes that have been |
|
156 | While working with this branch, it is a good idea to merge in changes that have been | |
157 | made upstream in the parent branch. This can be done by doing:: |
|
157 | made upstream in the parent branch. This can be done by doing:: | |
158 |
|
158 | |||
159 | $ bzr pull |
|
159 | $ bzr pull | |
160 |
|
160 | |||
161 | If this command shows that the branches have diverged, then you should do a merge |
|
161 | If this command shows that the branches have diverged, then you should do a merge | |
162 | instead:: |
|
162 | instead:: | |
163 |
|
163 | |||
164 | $ bzr merge lp:ipython |
|
164 | $ bzr merge lp:ipython | |
165 |
|
165 | |||
166 | If you want others to be able to see your branch, you can create an account with |
|
166 | If you want others to be able to see your branch, you can create an account with | |
167 | launchpad and push the branch to your own workspace:: |
|
167 | launchpad and push the branch to your own workspace:: | |
168 |
|
168 | |||
169 | $ bzr push bzr+ssh://<me>@bazaar.launchpad.net/~<me>/+junk/ipython-mybranch |
|
169 | $ bzr push bzr+ssh://<me>@bazaar.launchpad.net/~<me>/+junk/ipython-mybranch | |
170 |
|
170 | |||
171 | Finally, once the work in your branch is done, you can merge your changes back into |
|
171 | Finally, once the work in your branch is done, you can merge your changes back into | |
172 | the `ipython` branch by using merge:: |
|
172 | the `ipython` branch by using merge:: | |
173 |
|
173 | |||
174 | $ cd ipython |
|
174 | $ cd ipython | |
175 | $ merge ../ipython-mybranch |
|
175 | $ merge ../ipython-mybranch | |
176 | [resolve any conflicts] |
|
176 | [resolve any conflicts] | |
177 | $ bzr ci -m "Fixing that bug" |
|
177 | $ bzr ci -m "Fixing that bug" | |
178 | $ bzr push |
|
178 | $ bzr push | |
179 |
|
179 | |||
180 | But this will require you to have write permissions to the `ipython` branch. It you don't |
|
180 | But this will require you to have write permissions to the `ipython` branch. It you don't | |
181 | you can tell one of the IPython devs about your branch and they can do the merge for you. |
|
181 | you can tell one of the IPython devs about your branch and they can do the merge for you. | |
182 |
|
182 | |||
183 | More information about Bazaar workflows can be found `here`__. |
|
183 | More information about Bazaar workflows can be found `here`__. | |
184 |
|
184 | |||
185 | .. __: http://subversion.tigris.org/ |
|
185 | .. __: http://subversion.tigris.org/ | |
186 | .. __: http://bazaar-vcs.org/ |
|
186 | .. __: http://bazaar-vcs.org/ | |
187 | .. __: http://www.launchpad.net/ipython |
|
187 | .. __: http://www.launchpad.net/ipython | |
188 | .. __: http://doc.bazaar-vcs.org/bzr.dev/en/user-guide/index.html |
|
188 | .. __: http://doc.bazaar-vcs.org/bzr.dev/en/user-guide/index.html | |
189 |
|
189 | |||
190 | Documentation |
|
190 | Documentation | |
191 | ============= |
|
191 | ============= | |
192 |
|
192 | |||
193 | Standalone documentation |
|
193 | Standalone documentation | |
194 | ------------------------ |
|
194 | ------------------------ | |
195 |
|
195 | |||
196 | All standalone documentation should be written in plain text (``.txt``) files using |
|
196 | All standalone documentation should be written in plain text (``.txt``) files using | |
197 | `reStructuredText`_ for markup and formatting. All such documentation should be placed |
|
197 | `reStructuredText`_ for markup and formatting. All such documentation should be placed | |
198 | in the top level directory ``docs`` of the IPython source tree. Or, when appropriate, |
|
198 | in the top level directory ``docs`` of the IPython source tree. Or, when appropriate, | |
199 | a suitably named subdirectory should be used. The documentation in this location will |
|
199 | a suitably named subdirectory should be used. The documentation in this location will | |
200 | serve as the main source for IPython documentation and all existing documentation |
|
200 | serve as the main source for IPython documentation and all existing documentation | |
201 | should be converted to this format. |
|
201 | should be converted to this format. | |
202 |
|
202 | |||
203 | In the future, the text files in the ``docs`` directory will be used to generate all |
|
203 | In the future, the text files in the ``docs`` directory will be used to generate all | |
204 | forms of documentation for IPython. This include documentation on the IPython website |
|
204 | forms of documentation for IPython. This include documentation on the IPython website | |
205 | as well as *pdf* documentation. |
|
205 | as well as *pdf* documentation. | |
206 |
|
206 | |||
207 | .. _reStructuredText: http://docutils.sourceforge.net/rst.html |
|
207 | .. _reStructuredText: http://docutils.sourceforge.net/rst.html | |
208 |
|
208 | |||
209 | Docstring format |
|
209 | Docstring format | |
210 | ---------------- |
|
210 | ---------------- | |
211 |
|
211 | |||
212 | Good docstrings are very important. All new code will use `Epydoc`_ for generating API |
|
212 | Good docstrings are very important. All new code will use `Epydoc`_ for generating API | |
213 | docs, so we will follow the `Epydoc`_ conventions. More specifically, we will use |
|
213 | docs, so we will follow the `Epydoc`_ conventions. More specifically, we will use | |
214 | `reStructuredText`_ for markup and formatting, since it is understood by a wide |
|
214 | `reStructuredText`_ for markup and formatting, since it is understood by a wide | |
215 | variety of tools. This means that if in the future we have any reason to change from |
|
215 | variety of tools. This means that if in the future we have any reason to change from | |
216 | `Epydoc`_ to something else, we'll have fewer transition pains. |
|
216 | `Epydoc`_ to something else, we'll have fewer transition pains. | |
217 |
|
217 | |||
218 | Details about using `reStructuredText`_ for docstrings can be found `here |
|
218 | Details about using `reStructuredText`_ for docstrings can be found `here | |
219 | <http://epydoc.sourceforge.net/manual-othermarkup.html>`_. |
|
219 | <http://epydoc.sourceforge.net/manual-othermarkup.html>`_. | |
220 |
|
220 | |||
221 | .. _Epydoc: http://epydoc.sourceforge.net/ |
|
221 | .. _Epydoc: http://epydoc.sourceforge.net/ | |
222 |
|
222 | |||
223 | Additional PEPs of interest regarding documentation of code: |
|
223 | Additional PEPs of interest regarding documentation of code: | |
224 |
|
224 | |||
225 | - `Docstring Conventions <http://www.python.org/peps/pep-0257.html>`_ |
|
225 | - `Docstring Conventions <http://www.python.org/peps/pep-0257.html>`_ | |
226 | - `Docstring Processing System Framework <http://www.python.org/peps/pep-0256.html>`_ |
|
226 | - `Docstring Processing System Framework <http://www.python.org/peps/pep-0256.html>`_ | |
227 | - `Docutils Design Specification <http://www.python.org/peps/pep-0258.html>`_ |
|
227 | - `Docutils Design Specification <http://www.python.org/peps/pep-0258.html>`_ | |
228 |
|
228 | |||
229 |
|
229 | |||
230 | Coding conventions |
|
230 | Coding conventions | |
231 | ================== |
|
231 | ================== | |
232 |
|
232 | |||
233 | General |
|
233 | General | |
234 | ------- |
|
234 | ------- | |
235 |
|
235 | |||
236 | In general, we'll try to follow the standard Python style conventions as described here: |
|
236 | In general, we'll try to follow the standard Python style conventions as described here: | |
237 |
|
237 | |||
238 | - `Style Guide for Python Code <http://www.python.org/peps/pep-0008.html>`_ |
|
238 | - `Style Guide for Python Code <http://www.python.org/peps/pep-0008.html>`_ | |
239 |
|
239 | |||
240 |
|
240 | |||
241 | Other comments: |
|
241 | Other comments: | |
242 |
|
242 | |||
243 | - In a large file, top level classes and functions should be |
|
243 | - In a large file, top level classes and functions should be | |
244 | separated by 2-3 lines to make it easier to separate them visually. |
|
244 | separated by 2-3 lines to make it easier to separate them visually. | |
245 | - Use 4 spaces for indentation. |
|
245 | - Use 4 spaces for indentation. | |
246 | - Keep the ordering of methods the same in classes that have the same |
|
246 | - Keep the ordering of methods the same in classes that have the same | |
247 | methods. This is particularly true for classes that implement |
|
247 | methods. This is particularly true for classes that implement | |
248 | similar interfaces and for interfaces that are similar. |
|
248 | similar interfaces and for interfaces that are similar. | |
249 |
|
249 | |||
250 | Naming conventions |
|
250 | Naming conventions | |
251 | ------------------ |
|
251 | ------------------ | |
252 |
|
252 | |||
253 | In terms of naming conventions, we'll follow the guidelines from the `Style Guide for |
|
253 | In terms of naming conventions, we'll follow the guidelines from the `Style Guide for | |
254 | Python Code`_. |
|
254 | Python Code`_. | |
255 |
|
255 | |||
256 | For all new IPython code (and much existing code is being refactored), we'll use: |
|
256 | For all new IPython code (and much existing code is being refactored), we'll use: | |
257 |
|
257 | |||
258 | - All ``lowercase`` module names. |
|
258 | - All ``lowercase`` module names. | |
259 |
|
259 | |||
260 | - ``CamelCase`` for class names. |
|
260 | - ``CamelCase`` for class names. | |
261 |
|
261 | |||
262 | - ``lowercase_with_underscores`` for methods, functions, variables and attributes. |
|
262 | - ``lowercase_with_underscores`` for methods, functions, variables and attributes. | |
263 |
|
263 | |||
264 | This may be confusing as most of the existing IPython codebase uses a different convention (``lowerCamelCase`` for methods and attributes). Slowly, we will move IPython over to the new |
|
264 | This may be confusing as most of the existing IPython codebase uses a different convention (``lowerCamelCase`` for methods and attributes). Slowly, we will move IPython over to the new | |
265 | convention, providing shadow names for backward compatibility in public interfaces. |
|
265 | convention, providing shadow names for backward compatibility in public interfaces. | |
266 |
|
266 | |||
267 | There are, however, some important exceptions to these rules. In some cases, IPython |
|
267 | There are, however, some important exceptions to these rules. In some cases, IPython | |
268 | code will interface with packages (Twisted, Wx, Qt) that use other conventions. At some level this makes it impossible to adhere to our own standards at all times. In particular, when subclassing classes that use other naming conventions, you must follow their naming conventions. To deal with cases like this, we propose the following policy: |
|
268 | code will interface with packages (Twisted, Wx, Qt) that use other conventions. At some level this makes it impossible to adhere to our own standards at all times. In particular, when subclassing classes that use other naming conventions, you must follow their naming conventions. To deal with cases like this, we propose the following policy: | |
269 |
|
269 | |||
270 | - If you are subclassing a class that uses different conventions, use its |
|
270 | - If you are subclassing a class that uses different conventions, use its | |
271 | naming conventions throughout your subclass. Thus, if you are creating a |
|
271 | naming conventions throughout your subclass. Thus, if you are creating a | |
272 | Twisted Protocol class, used Twisted's ``namingSchemeForMethodsAndAttributes.`` |
|
272 | Twisted Protocol class, used Twisted's ``namingSchemeForMethodsAndAttributes.`` | |
273 |
|
273 | |||
274 | - All IPython's official interfaces should use our conventions. In some cases |
|
274 | - All IPython's official interfaces should use our conventions. In some cases | |
275 | this will mean that you need to provide shadow names (first implement ``fooBar`` |
|
275 | this will mean that you need to provide shadow names (first implement ``fooBar`` | |
276 | and then ``foo_bar = fooBar``). We want to avoid this at all costs, but it |
|
276 | and then ``foo_bar = fooBar``). We want to avoid this at all costs, but it | |
277 | will probably be necessary at times. But, please use this sparingly! |
|
277 | will probably be necessary at times. But, please use this sparingly! | |
278 |
|
278 | |||
279 | Implementation-specific *private* methods will use ``_single_underscore_prefix``. |
|
279 | Implementation-specific *private* methods will use ``_single_underscore_prefix``. | |
280 | Names with a leading double underscore will *only* be used in special cases, as they |
|
280 | Names with a leading double underscore will *only* be used in special cases, as they | |
281 | makes subclassing difficult (such names are not easily seen by child classes). |
|
281 | makes subclassing difficult (such names are not easily seen by child classes). | |
282 |
|
282 | |||
283 | Occasionally some run-in lowercase names are used, but mostly for very short names or |
|
283 | Occasionally some run-in lowercase names are used, but mostly for very short names or | |
284 | where we are implementing methods very similar to existing ones in a base class (like |
|
284 | where we are implementing methods very similar to existing ones in a base class (like | |
285 | ``runlines()`` where ``runsource()`` and ``runcode()`` had established precedent). |
|
285 | ``runlines()`` where ``runsource()`` and ``runcode()`` had established precedent). | |
286 |
|
286 | |||
287 | The old IPython codebase has a big mix of classes and modules prefixed with an |
|
287 | The old IPython codebase has a big mix of classes and modules prefixed with an | |
288 | explicit ``IP``. In Python this is mostly unnecessary, redundant and frowned upon, as |
|
288 | explicit ``IP``. In Python this is mostly unnecessary, redundant and frowned upon, as | |
289 | namespaces offer cleaner prefixing. The only case where this approach is justified is |
|
289 | namespaces offer cleaner prefixing. The only case where this approach is justified is | |
290 | for classes which are expected to be imported into external namespaces and a very |
|
290 | for classes which are expected to be imported into external namespaces and a very | |
291 | generic name (like Shell) is too likely to clash with something else. We'll need to |
|
291 | generic name (like Shell) is too likely to clash with something else. We'll need to | |
292 | revisit this issue as we clean up and refactor the code, but in general we should |
|
292 | revisit this issue as we clean up and refactor the code, but in general we should | |
293 | remove as many unnecessary ``IP``/``ip`` prefixes as possible. However, if a prefix |
|
293 | remove as many unnecessary ``IP``/``ip`` prefixes as possible. However, if a prefix | |
294 | seems absolutely necessary the more specific ``IPY`` or ``ipy`` are preferred. |
|
294 | seems absolutely necessary the more specific ``IPY`` or ``ipy`` are preferred. | |
295 |
|
295 | |||
296 | .. _devel_testing: |
|
296 | .. _devel_testing: | |
297 |
|
297 | |||
298 | Testing system |
|
298 | Testing system | |
299 | ============== |
|
299 | ============== | |
300 |
|
300 | |||
301 | It is extremely important that all code contributed to IPython has tests. Tests should |
|
301 | It is extremely important that all code contributed to IPython has tests. Tests should | |
302 | be written as unittests, doctests or as entities that the `Nose`_ testing package will |
|
302 | be written as unittests, doctests or as entities that the `Nose`_ testing package will | |
303 | find. Regardless of how the tests are written, we will use `Nose`_ for discovering and |
|
303 | find. Regardless of how the tests are written, we will use `Nose`_ for discovering and | |
304 | running the tests. `Nose`_ will be required to run the IPython test suite, but will |
|
304 | running the tests. `Nose`_ will be required to run the IPython test suite, but will | |
305 | not be required to simply use IPython. |
|
305 | not be required to simply use IPython. | |
306 |
|
306 | |||
307 | .. _Nose: http://code.google.com/p/python-nose/ |
|
307 | .. _Nose: http://code.google.com/p/python-nose/ | |
308 |
|
308 | |||
309 | Tests of `Twisted`__ using code should be written by subclassing the ``TestCase`` class |
|
309 | Tests of `Twisted`__ using code should be written by subclassing the ``TestCase`` class | |
310 | that comes with ``twisted.trial.unittest``. When this is done, `Nose`_ will be able to |
|
310 | that comes with ``twisted.trial.unittest``. When this is done, `Nose`_ will be able to | |
311 | run the tests and the twisted reactor will be handled correctly. |
|
311 | run the tests and the twisted reactor will be handled correctly. | |
312 |
|
312 | |||
313 | .. __: http://www.twistedmatrix.com |
|
313 | .. __: http://www.twistedmatrix.com | |
314 |
|
314 | |||
315 | Each subpackage in IPython should have its own ``tests`` directory that contains all |
|
315 | Each subpackage in IPython should have its own ``tests`` directory that contains all | |
316 | of the tests for that subpackage. This allows each subpackage to be self-contained. If |
|
316 | of the tests for that subpackage. This allows each subpackage to be self-contained. If | |
317 | a subpackage has any dependencies beyond the Python standard library, the tests for |
|
317 | a subpackage has any dependencies beyond the Python standard library, the tests for | |
318 | that subpackage should be skipped if the dependencies are not found. This is very |
|
318 | that subpackage should be skipped if the dependencies are not found. This is very | |
319 | important so users don't get tests failing simply because they don't have dependencies. |
|
319 | important so users don't get tests failing simply because they don't have dependencies. | |
320 |
|
320 | |||
321 | We also need to look into use Noses ability to tag tests to allow a more modular |
|
321 | We also need to look into use Noses ability to tag tests to allow a more modular | |
322 | approach of running tests. |
|
322 | approach of running tests. | |
323 |
|
323 | |||
324 | .. _devel_config: |
|
324 | .. _devel_config: | |
325 |
|
325 | |||
326 | Configuration system |
|
326 | Configuration system | |
327 | ==================== |
|
327 | ==================== | |
328 |
|
328 | |||
329 | IPython uses `.ini`_ files for configuration purposes. This represents a huge |
|
329 | IPython uses `.ini`_ files for configuration purposes. This represents a huge | |
330 | improvement over the configuration system used in IPython. IPython works with these |
|
330 | improvement over the configuration system used in IPython. IPython works with these | |
331 | files using the `ConfigObj`_ package, which IPython includes as |
|
331 | files using the `ConfigObj`_ package, which IPython includes as | |
332 | ``ipython1/external/configobj.py``. |
|
332 | ``ipython1/external/configobj.py``. | |
333 |
|
333 | |||
334 | Currently, we are using raw `ConfigObj`_ objects themselves. Each subpackage of IPython |
|
334 | Currently, we are using raw `ConfigObj`_ objects themselves. Each subpackage of IPython | |
335 | should contain a ``config`` subdirectory that contains all of the configuration |
|
335 | should contain a ``config`` subdirectory that contains all of the configuration | |
336 | information for the subpackage. To see how configuration information is defined (along |
|
336 | information for the subpackage. To see how configuration information is defined (along | |
337 | with defaults) see at the examples in ``ipython1/kernel/config`` and |
|
337 | with defaults) see at the examples in ``ipython1/kernel/config`` and | |
338 | ``ipython1/core/config``. Likewise, to see how the configuration information is used, |
|
338 | ``ipython1/core/config``. Likewise, to see how the configuration information is used, | |
339 | see examples in ``ipython1/kernel/scripts/ipengine.py``. |
|
339 | see examples in ``ipython1/kernel/scripts/ipengine.py``. | |
340 |
|
340 | |||
341 | Eventually, we will add a new layer on top of the raw `ConfigObj`_ objects. We are |
|
341 | Eventually, we will add a new layer on top of the raw `ConfigObj`_ objects. We are | |
342 | calling this new layer, ``tconfig``, as it will use a `Traits`_-like validation model. |
|
342 | calling this new layer, ``tconfig``, as it will use a `Traits`_-like validation model. | |
343 | We won't actually use `Traits`_, but will implement something similar in pure Python. |
|
343 | We won't actually use `Traits`_, but will implement something similar in pure Python. | |
344 | But, even in this new system, we will still use `ConfigObj`_ and `.ini`_ files |
|
344 | But, even in this new system, we will still use `ConfigObj`_ and `.ini`_ files | |
345 | underneath the hood. Talk to Fernando if you are interested in working on this part of |
|
345 | underneath the hood. Talk to Fernando if you are interested in working on this part of | |
346 | IPython. The current prototype of ``tconfig`` is located in the IPython sandbox. |
|
346 | IPython. The current prototype of ``tconfig`` is located in the IPython sandbox. | |
347 |
|
347 | |||
348 | .. _.ini: http://docs.python.org/lib/module-ConfigParser.html |
|
348 | .. _.ini: http://docs.python.org/lib/module-ConfigParser.html | |
349 | .. _ConfigObj: http://www.voidspace.org.uk/python/configobj.html |
|
349 | .. _ConfigObj: http://www.voidspace.org.uk/python/configobj.html | |
350 | .. _Traits: http://code.enthought.com/traits/ |
|
350 | .. _Traits: http://code.enthought.com/traits/ | |
351 |
|
351 | |||
|
352 | Installation and testing scenarios | |||
|
353 | ================================== | |||
|
354 | ||||
|
355 | This section outlines the various scenarios that we need to test before we release an IPython version. These scenarios represent different ways of installing IPython and its dependencies. | |||
|
356 | ||||
|
357 | Installation scenarios | |||
|
358 | ---------------------- | |||
|
359 | ||||
|
360 | 1. Install from tarball using `python setup.py install`. | |||
|
361 | a. With only readline+nose dependencies installed (test1) | |||
|
362 | b. With all dependencies installed (readline, zope.interface, | |||
|
363 | Twisted, foolscap, Sphinx, nose, pyOpenSSL) (test2) | |||
|
364 | 2. Install using easy_install. | |||
|
365 | a. With only readline+nose dependencies installed (test3) | |||
|
366 | i. Default dependencies. | |||
|
367 | ii. Optional dependency sets (kernel, doc, test, security) | |||
|
368 | easy_install -f ipython-0.9.beta3-py2.5.egg IPython[kernel,doc,test,security] | |||
|
369 | ||||
|
370 | b. With all dependencies already installed (test2) | |||
|
371 | ||||
|
372 | ||||
|
373 | Tests to run for these scenarios | |||
|
374 | -------------------------------- | |||
|
375 | ||||
|
376 | 1. Run the full test suite. | |||
|
377 | 2. Start a controller and engines and try a few things by hand. | |||
|
378 | a. Using ipcluster. | |||
|
379 | b. Using ipcontroller/ipengine by hand. | |||
|
380 | 3. Run a few of the parallel examples. | |||
|
381 | 4. Try the kernel with and without security with and without PyOpenSSL | |||
|
382 | installed. | |||
|
383 | 5. Beat on the IPython terminal a bunch. | |||
|
384 | 6. Make sure that furl files are being put in proper locations. | |||
352 |
|
385 | |||
353 |
|
386 | |||
354 |
|
387 | |||
355 |
|
388 | |||
356 |
|
389 | |||
357 |
|
390 | |||
358 |
|
391 | |||
359 |
|
392 | |||
360 |
|
393 |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now