##// END OF EJS Templates
Allow IPython to run without sqlite3...
MinRK -
Show More
@@ -17,12 +17,15 b' import atexit'
17 import datetime
17 import datetime
18 import os
18 import os
19 import re
19 import re
20 import sqlite3
20 try:
21 import sqlite3
22 except ImportError:
23 sqlite3 = None
21 import threading
24 import threading
22
25
23 # Our own packages
26 # Our own packages
24 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
25
28 from IPython.external.decorator import decorator
26 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.utils import io
30 from IPython.utils import io
28 from IPython.utils.path import locate_profile
31 from IPython.utils.path import locate_profile
@@ -33,6 +36,30 b' from IPython.utils.warn import warn'
33 # Classes and functions
36 # Classes and functions
34 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
35
38
39 class DummyDB(object):
40 """Dummy DB that will act as a black hole for history.
41
42 Only used in the absence of sqlite"""
43 def execute(*args, **kwargs):
44 return []
45
46 def commit(self, *args, **kwargs):
47 pass
48
49 def __enter__(self, *args, **kwargs):
50 pass
51
52 def __exit__(self, *args, **kwargs):
53 pass
54
55 @decorator
56 def needs_sqlite(f,*a,**kw):
57 """return an empty list in the absence of sqlite"""
58 if sqlite3 is None:
59 return []
60 else:
61 return f(*a,**kw)
62
36 class HistoryAccessor(Configurable):
63 class HistoryAccessor(Configurable):
37 """Access the history database without adding to it.
64 """Access the history database without adding to it.
38
65
@@ -42,7 +69,10 b' class HistoryAccessor(Configurable):'
42 hist_file = Unicode(config=True)
69 hist_file = Unicode(config=True)
43
70
44 # The SQLite database
71 # The SQLite database
45 db = Instance(sqlite3.Connection)
72 if sqlite3:
73 db = Instance(sqlite3.Connection)
74 else:
75 db = Instance(DummyDB)
46
76
47 def __init__(self, profile='default', hist_file=u'', shell=None, config=None, **traits):
77 def __init__(self, profile='default', hist_file=u'', shell=None, config=None, **traits):
48 """Create a new history accessor.
78 """Create a new history accessor.
@@ -67,6 +97,11 b' class HistoryAccessor(Configurable):'
67 # No one has set the hist_file, yet.
97 # No one has set the hist_file, yet.
68 self.hist_file = self._get_hist_file_name(profile)
98 self.hist_file = self._get_hist_file_name(profile)
69
99
100 if sqlite3 is None:
101 warn("IPython History requires SQLite, your history will not be saved\n")
102 self.db = DummyDB()
103 return
104
70 try:
105 try:
71 self.init_db()
106 self.init_db()
72 except sqlite3.DatabaseError:
107 except sqlite3.DatabaseError:
@@ -146,6 +181,7 b' class HistoryAccessor(Configurable):'
146 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
181 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
147 return cur
182 return cur
148
183
184 @needs_sqlite
149 def get_session_info(self, session=0):
185 def get_session_info(self, session=0):
150 """get info about a session
186 """get info about a session
151
187
@@ -351,7 +387,7 b' class HistoryManager(HistoryAccessor):'
351 self.save_thread.start()
387 self.save_thread.start()
352
388
353 self.new_session()
389 self.new_session()
354
390
355 def _get_hist_file_name(self, profile=None):
391 def _get_hist_file_name(self, profile=None):
356 """Get default history file name based on the Shell's profile.
392 """Get default history file name based on the Shell's profile.
357
393
@@ -360,6 +396,7 b' class HistoryManager(HistoryAccessor):'
360 profile_dir = self.shell.profile_dir.location
396 profile_dir = self.shell.profile_dir.location
361 return os.path.join(profile_dir, 'history.sqlite')
397 return os.path.join(profile_dir, 'history.sqlite')
362
398
399 @needs_sqlite
363 def new_session(self, conn=None):
400 def new_session(self, conn=None):
364 """Get a new session number."""
401 """Get a new session number."""
365 if conn is None:
402 if conn is None:
@@ -537,6 +574,7 b' class HistoryManager(HistoryAccessor):'
537 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
574 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
538 (self.session_number,)+line)
575 (self.session_number,)+line)
539
576
577 @needs_sqlite
540 def writeout_cache(self, conn=None):
578 def writeout_cache(self, conn=None):
541 """Write any entries in the cache to the database."""
579 """Write any entries in the cache to the database."""
542 if conn is None:
580 if conn is None:
@@ -581,6 +619,7 b' class HistorySavingThread(threading.Thread):'
581 self.history_manager = history_manager
619 self.history_manager = history_manager
582 atexit.register(self.stop)
620 atexit.register(self.stop)
583
621
622 @needs_sqlite
584 def run(self):
623 def run(self):
585 # We need a separate db connection per thread:
624 # We need a separate db connection per thread:
586 try:
625 try:
@@ -55,7 +55,8 b' def test_magic_parse_options():'
55 expected = path
55 expected = path
56 nt.assert_equals(opts['f'], expected)
56 nt.assert_equals(opts['f'], expected)
57
57
58
58
59 @dec.skip_without('sqlite3')
59 def doctest_hist_f():
60 def doctest_hist_f():
60 """Test %hist -f with temporary filename.
61 """Test %hist -f with temporary filename.
61
62
@@ -69,6 +70,7 b' def doctest_hist_f():'
69 """
70 """
70
71
71
72
73 @dec.skip_without('sqlite3')
72 def doctest_hist_r():
74 def doctest_hist_r():
73 """Test %hist -r
75 """Test %hist -r
74
76
@@ -86,6 +88,8 b' def doctest_hist_r():'
86 %hist -r 2
88 %hist -r 2
87 """
89 """
88
90
91
92 @dec.skip_without('sqlite3')
89 def doctest_hist_op():
93 def doctest_hist_op():
90 """Test %hist -op
94 """Test %hist -op
91
95
@@ -151,7 +155,9 b' def doctest_hist_op():'
151 's'
155 's'
152 >>>
156 >>>
153 """
157 """
154
158
159
160 @dec.skip_without('sqlite3')
155 def test_macro():
161 def test_macro():
156 ip = get_ipython()
162 ip = get_ipython()
157 ip.history_manager.reset() # Clear any existing history.
163 ip.history_manager.reset() # Clear any existing history.
@@ -164,6 +170,8 b' def test_macro():'
164 # List macros.
170 # List macros.
165 assert "test" in ip.magic("macro")
171 assert "test" in ip.magic("macro")
166
172
173
174 @dec.skip_without('sqlite3')
167 def test_macro_run():
175 def test_macro_run():
168 """Test that we can run a multi-line macro successfully."""
176 """Test that we can run a multi-line macro successfully."""
169 ip = get_ipython()
177 ip = get_ipython()
@@ -169,9 +169,13 b' class TestMagicRunSimple(tt.TempFileMixin):'
169 " print 'object A deleted'\n"
169 " print 'object A deleted'\n"
170 "a = A()\n")
170 "a = A()\n")
171 self.mktmp(py3compat.doctest_refactor_print(src))
171 self.mktmp(py3compat.doctest_refactor_print(src))
172 tt.ipexec_validate(self.fname, 'object A deleted')
172 if dec.module_not_available('sqlite3'):
173
173 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
174 @dec.skip_known_failure
174 else:
175 err = None
176 tt.ipexec_validate(self.fname, 'object A deleted', err)
177
178 @dec.skip_known_failure
175 def test_aggressive_namespace_cleanup(self):
179 def test_aggressive_namespace_cleanup(self):
176 """Test that namespace cleanup is not too aggressive GH-238
180 """Test that namespace cleanup is not too aggressive GH-238
177
181
@@ -207,4 +211,8 b" ARGV 1-: ['C-third']"
207 tclass.py: deleting object: C-second
211 tclass.py: deleting object: C-second
208 tclass.py: deleting object: C-third
212 tclass.py: deleting object: C-third
209 """
213 """
210 tt.ipexec_validate(self.fname, out)
214 if dec.module_not_available('sqlite3'):
215 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
216 else:
217 err = None
218 tt.ipexec_validate(self.fname, out, err)
@@ -16,7 +16,10 b' import os'
16 import cPickle as pickle
16 import cPickle as pickle
17 from datetime import datetime
17 from datetime import datetime
18
18
19 import sqlite3
19 try:
20 import sqlite3
21 except ImportError:
22 sqlite3 = None
20
23
21 from zmq.eventloop import ioloop
24 from zmq.eventloop import ioloop
22
25
@@ -99,7 +102,10 b' class SQLiteDB(BaseDB):'
99 in tasks from previous sessions being available via Clients' db_query and
102 in tasks from previous sessions being available via Clients' db_query and
100 get_result methods.""")
103 get_result methods.""")
101
104
102 _db = Instance('sqlite3.Connection')
105 if sqlite3 is not None:
106 _db = Instance('sqlite3.Connection')
107 else:
108 _db = None
103 # the ordered list of column names
109 # the ordered list of column names
104 _keys = List(['msg_id' ,
110 _keys = List(['msg_id' ,
105 'header' ,
111 'header' ,
@@ -145,6 +151,8 b' class SQLiteDB(BaseDB):'
145
151
146 def __init__(self, **kwargs):
152 def __init__(self, **kwargs):
147 super(SQLiteDB, self).__init__(**kwargs)
153 super(SQLiteDB, self).__init__(**kwargs)
154 if sqlite3 is None:
155 raise ImportError("SQLiteDB requires sqlite3")
148 if not self.table:
156 if not self.table:
149 # use session, and prefix _, since starting with # is illegal
157 # use session, and prefix _, since starting with # is illegal
150 self.table = '_'+self.session.replace('-','_')
158 self.table = '_'+self.session.replace('-','_')
@@ -24,13 +24,12 b' import time'
24 from datetime import datetime, timedelta
24 from datetime import datetime, timedelta
25 from unittest import TestCase
25 from unittest import TestCase
26
26
27 from nose import SkipTest
28
29 from IPython.parallel import error
27 from IPython.parallel import error
30 from IPython.parallel.controller.dictdb import DictDB
28 from IPython.parallel.controller.dictdb import DictDB
31 from IPython.parallel.controller.sqlitedb import SQLiteDB
29 from IPython.parallel.controller.sqlitedb import SQLiteDB
32 from IPython.parallel.controller.hub import init_record, empty_record
30 from IPython.parallel.controller.hub import init_record, empty_record
33
31
32 from IPython.testing import decorators as dec
34 from IPython.zmq.session import Session
33 from IPython.zmq.session import Session
35
34
36
35
@@ -171,8 +170,11 b' class TestDictBackend(TestCase):'
171 self.db.drop_matching_records(query)
170 self.db.drop_matching_records(query)
172 recs = self.db.find_records(query)
171 recs = self.db.find_records(query)
173 self.assertEquals(len(recs), 0)
172 self.assertEquals(len(recs), 0)
174
173
174
175 class TestSQLiteBackend(TestDictBackend):
175 class TestSQLiteBackend(TestDictBackend):
176
177 @dec.skip_without('sqlite3')
176 def create_db(self):
178 def create_db(self):
177 return SQLiteDB(location=tempfile.gettempdir())
179 return SQLiteDB(location=tempfile.gettempdir())
178
180
@@ -128,6 +128,7 b" have['pymongo'] = test_for('pymongo')"
128 have['wx'] = test_for('wx')
128 have['wx'] = test_for('wx')
129 have['wx.aui'] = test_for('wx.aui')
129 have['wx.aui'] = test_for('wx.aui')
130 have['qt'] = test_for('IPython.external.qt')
130 have['qt'] = test_for('IPython.external.qt')
131 have['sqlite3'] = test_for('sqlite3')
131
132
132 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
133 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
133
134
@@ -204,7 +205,9 b' def make_exclude():'
204 ipjoin('config', 'default'),
205 ipjoin('config', 'default'),
205 ipjoin('config', 'profile'),
206 ipjoin('config', 'profile'),
206 ]
207 ]
207
208 if not have['sqlite3']:
209 exclusions.append(ipjoin('core', 'tests', 'test_history'))
210 exclusions.append(ipjoin('core', 'history'))
208 if not have['wx']:
211 if not have['wx']:
209 exclusions.append(ipjoin('lib', 'inputhookwx'))
212 exclusions.append(ipjoin('lib', 'inputhookwx'))
210
213
General Comments 0
You need to be logged in to leave comments. Login now