##// END OF EJS Templates
HistoryAccessor can automatically find a history file for a standard profile.
Thomas Kluyver -
Show More
@@ -1,885 +1,909 b''
1 """ History related magics and functionality """
1 """ History related magics and functionality """
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (C) 2010 The IPython Development Team.
3 # Copyright (C) 2010 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the BSD License.
5 # Distributed under the terms of the BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import atexit
17 import datetime
17 import datetime
18 import os
18 import os
19 import re
19 import re
20 import sqlite3
20 import sqlite3
21 import threading
21 import threading
22
22
23 # Our own packages
23 # Our own packages
24 from IPython.config.configurable import Configurable
24 from IPython.config.configurable import Configurable
25
25
26 from IPython.testing.skipdoctest import skip_doctest
26 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.utils import io
27 from IPython.utils import io
28 from IPython.utils.path import locate_profile
28 from IPython.utils.traitlets import Bool, Dict, Instance, Int, CInt, List, Unicode
29 from IPython.utils.traitlets import Bool, Dict, Instance, Int, CInt, List, Unicode
29 from IPython.utils.warn import warn
30 from IPython.utils.warn import warn
30
31
31 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
32 # Classes and functions
33 # Classes and functions
33 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
34
35
35 class HistoryAccessor(Configurable):
36 class HistoryAccessor(Configurable):
36 """Access the history database without adding to it.
37 """Access the history database without adding to it.
37
38
38 This is intended for use by standalone history tools. IPython shells use
39 This is intended for use by standalone history tools. IPython shells use
39 HistoryManager, below, which is a subclass of this."""
40 HistoryManager, below, which is a subclass of this."""
40 # String holding the path to the history file
41 # String holding the path to the history file
41 hist_file = Unicode(config=True)
42 hist_file = Unicode(config=True)
42
43
43 # The SQLite database
44 # The SQLite database
44 db = Instance(sqlite3.Connection)
45 db = Instance(sqlite3.Connection)
45
46
46 def __init__(self, hist_file=u'', shell=None, config=None, **traits):
47 def __init__(self, profile='default', hist_file=u'', shell=None, config=None, **traits):
47 """Create a new history accessor.
48 """Create a new history accessor.
48
49
49 hist_file must be given, either as an argument or through config.
50 Parameters
51 ----------
52 profile : str
53 The name of the profile from which to open history.
54 hist_file : str
55 Path to an SQLite history database stored by IPython. If specified,
56 hist_file overrides profile.
57 shell :
58 InteractiveShell object, for use by HistoryManager subclass
59 config :
60 Config object. hist_file can also be set through this.
50 """
61 """
51 # We need a pointer back to the shell for various tasks.
62 # We need a pointer back to the shell for various tasks.
52 super(HistoryAccessor, self).__init__(shell=shell, config=config,
63 super(HistoryAccessor, self).__init__(shell=shell, config=config,
53 hist_file=hist_file, **traits)
64 hist_file=hist_file, **traits)
54
65
55 if self.hist_file == u'':
66 if self.hist_file == u'':
56 # No one has set the hist_file, yet.
67 # No one has set the hist_file, yet.
57 self.hist_file = self._get_hist_file_name(hist_file)
68 self.hist_file = self._get_hist_file_name(profile)
58
69
59 try:
70 try:
60 self.init_db()
71 self.init_db()
61 except sqlite3.DatabaseError:
72 except sqlite3.DatabaseError:
62 if os.path.isfile(self.hist_file):
73 if os.path.isfile(self.hist_file):
63 # Try to move the file out of the way.
74 # Try to move the file out of the way.
64 newpath = os.path.join(self.shell.profile_dir.location, "hist-corrupt.sqlite")
75 newpath = os.path.join(self.shell.profile_dir.location, "hist-corrupt.sqlite")
65 os.rename(self.hist_file, newpath)
76 os.rename(self.hist_file, newpath)
66 print("ERROR! History file wasn't a valid SQLite database.",
77 print("ERROR! History file wasn't a valid SQLite database.",
67 "It was moved to %s" % newpath, "and a new file created.")
78 "It was moved to %s" % newpath, "and a new file created.")
68 self.init_db()
79 self.init_db()
69 else:
80 else:
70 # The hist_file is probably :memory: or something else.
81 # The hist_file is probably :memory: or something else.
71 raise
82 raise
72
83
73 def _get_hist_file_name(self, hist_file=None):
84 def _get_hist_file_name(self, profile='default'):
74 "Override to produce a default history file name."
85 """Find the history file for the given profile name.
75 raise NotImplementedError("No default history file")
86
87 This is overridden by the HistoryManager subclass, to use the shell's
88 active profile.
89
90 Parameters
91 ----------
92 profile : str
93 The name of a profile which has a history file.
94 """
95 return os.path.join(locate_profile(profile), 'history.sqlite')
76
96
77 def init_db(self):
97 def init_db(self):
78 """Connect to the database, and create tables if necessary."""
98 """Connect to the database, and create tables if necessary."""
79 # use detect_types so that timestamps return datetime objects
99 # use detect_types so that timestamps return datetime objects
80 self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
100 self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
81 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
101 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
82 primary key autoincrement, start timestamp,
102 primary key autoincrement, start timestamp,
83 end timestamp, num_cmds integer, remark text)""")
103 end timestamp, num_cmds integer, remark text)""")
84 self.db.execute("""CREATE TABLE IF NOT EXISTS history
104 self.db.execute("""CREATE TABLE IF NOT EXISTS history
85 (session integer, line integer, source text, source_raw text,
105 (session integer, line integer, source text, source_raw text,
86 PRIMARY KEY (session, line))""")
106 PRIMARY KEY (session, line))""")
87 # Output history is optional, but ensure the table's there so it can be
107 # Output history is optional, but ensure the table's there so it can be
88 # enabled later.
108 # enabled later.
89 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
109 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
90 (session integer, line integer, output text,
110 (session integer, line integer, output text,
91 PRIMARY KEY (session, line))""")
111 PRIMARY KEY (session, line))""")
92 self.db.commit()
112 self.db.commit()
93
113
94 def writeout_cache(self):
114 def writeout_cache(self):
95 """Overridden by HistoryManager to dump the cache before certain
115 """Overridden by HistoryManager to dump the cache before certain
96 database lookups."""
116 database lookups."""
97 pass
117 pass
98
118
99 ## -------------------------------
119 ## -------------------------------
100 ## Methods for retrieving history:
120 ## Methods for retrieving history:
101 ## -------------------------------
121 ## -------------------------------
102 def _run_sql(self, sql, params, raw=True, output=False):
122 def _run_sql(self, sql, params, raw=True, output=False):
103 """Prepares and runs an SQL query for the history database.
123 """Prepares and runs an SQL query for the history database.
104
124
105 Parameters
125 Parameters
106 ----------
126 ----------
107 sql : str
127 sql : str
108 Any filtering expressions to go after SELECT ... FROM ...
128 Any filtering expressions to go after SELECT ... FROM ...
109 params : tuple
129 params : tuple
110 Parameters passed to the SQL query (to replace "?")
130 Parameters passed to the SQL query (to replace "?")
111 raw, output : bool
131 raw, output : bool
112 See :meth:`get_range`
132 See :meth:`get_range`
113
133
114 Returns
134 Returns
115 -------
135 -------
116 Tuples as :meth:`get_range`
136 Tuples as :meth:`get_range`
117 """
137 """
118 toget = 'source_raw' if raw else 'source'
138 toget = 'source_raw' if raw else 'source'
119 sqlfrom = "history"
139 sqlfrom = "history"
120 if output:
140 if output:
121 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
141 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
122 toget = "history.%s, output_history.output" % toget
142 toget = "history.%s, output_history.output" % toget
123 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
143 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
124 (toget, sqlfrom) + sql, params)
144 (toget, sqlfrom) + sql, params)
125 if output: # Regroup into 3-tuples, and parse JSON
145 if output: # Regroup into 3-tuples, and parse JSON
126 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
146 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
127 return cur
147 return cur
128
148
129 def get_session_info(self, session=0):
149 def get_session_info(self, session=0):
130 """get info about a session
150 """get info about a session
131
151
132 Parameters
152 Parameters
133 ----------
153 ----------
134
154
135 session : int
155 session : int
136 Session number to retrieve. The current session is 0, and negative
156 Session number to retrieve. The current session is 0, and negative
137 numbers count back from current session, so -1 is previous session.
157 numbers count back from current session, so -1 is previous session.
138
158
139 Returns
159 Returns
140 -------
160 -------
141
161
142 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
162 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
143
163
144 Sessions that are running or did not exit cleanly will have `end=None`
164 Sessions that are running or did not exit cleanly will have `end=None`
145 and `num_cmds=None`.
165 and `num_cmds=None`.
146
166
147 """
167 """
148
168
149 if session <= 0:
169 if session <= 0:
150 session += self.session_number
170 session += self.session_number
151
171
152 query = "SELECT * from sessions where session == ?"
172 query = "SELECT * from sessions where session == ?"
153 return self.db.execute(query, (session,)).fetchone()
173 return self.db.execute(query, (session,)).fetchone()
154
174
155 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
175 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
156 """Get the last n lines from the history database.
176 """Get the last n lines from the history database.
157
177
158 Parameters
178 Parameters
159 ----------
179 ----------
160 n : int
180 n : int
161 The number of lines to get
181 The number of lines to get
162 raw, output : bool
182 raw, output : bool
163 See :meth:`get_range`
183 See :meth:`get_range`
164 include_latest : bool
184 include_latest : bool
165 If False (default), n+1 lines are fetched, and the latest one
185 If False (default), n+1 lines are fetched, and the latest one
166 is discarded. This is intended to be used where the function
186 is discarded. This is intended to be used where the function
167 is called by a user command, which it should not return.
187 is called by a user command, which it should not return.
168
188
169 Returns
189 Returns
170 -------
190 -------
171 Tuples as :meth:`get_range`
191 Tuples as :meth:`get_range`
172 """
192 """
173 self.writeout_cache()
193 self.writeout_cache()
174 if not include_latest:
194 if not include_latest:
175 n += 1
195 n += 1
176 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
196 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
177 (n,), raw=raw, output=output)
197 (n,), raw=raw, output=output)
178 if not include_latest:
198 if not include_latest:
179 return reversed(list(cur)[1:])
199 return reversed(list(cur)[1:])
180 return reversed(list(cur))
200 return reversed(list(cur))
181
201
182 def search(self, pattern="*", raw=True, search_raw=True,
202 def search(self, pattern="*", raw=True, search_raw=True,
183 output=False):
203 output=False):
184 """Search the database using unix glob-style matching (wildcards
204 """Search the database using unix glob-style matching (wildcards
185 * and ?).
205 * and ?).
186
206
187 Parameters
207 Parameters
188 ----------
208 ----------
189 pattern : str
209 pattern : str
190 The wildcarded pattern to match when searching
210 The wildcarded pattern to match when searching
191 search_raw : bool
211 search_raw : bool
192 If True, search the raw input, otherwise, the parsed input
212 If True, search the raw input, otherwise, the parsed input
193 raw, output : bool
213 raw, output : bool
194 See :meth:`get_range`
214 See :meth:`get_range`
195
215
196 Returns
216 Returns
197 -------
217 -------
198 Tuples as :meth:`get_range`
218 Tuples as :meth:`get_range`
199 """
219 """
200 tosearch = "source_raw" if search_raw else "source"
220 tosearch = "source_raw" if search_raw else "source"
201 if output:
221 if output:
202 tosearch = "history." + tosearch
222 tosearch = "history." + tosearch
203 self.writeout_cache()
223 self.writeout_cache()
204 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
224 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
205 raw=raw, output=output)
225 raw=raw, output=output)
206
226
207 def get_range(self, session, start=1, stop=None, raw=True,output=False):
227 def get_range(self, session, start=1, stop=None, raw=True,output=False):
208 """Retrieve input by session.
228 """Retrieve input by session.
209
229
210 Parameters
230 Parameters
211 ----------
231 ----------
212 session : int
232 session : int
213 Session number to retrieve.
233 Session number to retrieve.
214 start : int
234 start : int
215 First line to retrieve.
235 First line to retrieve.
216 stop : int
236 stop : int
217 End of line range (excluded from output itself). If None, retrieve
237 End of line range (excluded from output itself). If None, retrieve
218 to the end of the session.
238 to the end of the session.
219 raw : bool
239 raw : bool
220 If True, return untranslated input
240 If True, return untranslated input
221 output : bool
241 output : bool
222 If True, attempt to include output. This will be 'real' Python
242 If True, attempt to include output. This will be 'real' Python
223 objects for the current session, or text reprs from previous
243 objects for the current session, or text reprs from previous
224 sessions if db_log_output was enabled at the time. Where no output
244 sessions if db_log_output was enabled at the time. Where no output
225 is found, None is used.
245 is found, None is used.
226
246
227 Returns
247 Returns
228 -------
248 -------
229 An iterator over the desired lines. Each line is a 3-tuple, either
249 An iterator over the desired lines. Each line is a 3-tuple, either
230 (session, line, input) if output is False, or
250 (session, line, input) if output is False, or
231 (session, line, (input, output)) if output is True.
251 (session, line, (input, output)) if output is True.
232 """
252 """
233 if stop:
253 if stop:
234 lineclause = "line >= ? AND line < ?"
254 lineclause = "line >= ? AND line < ?"
235 params = (session, start, stop)
255 params = (session, start, stop)
236 else:
256 else:
237 lineclause = "line>=?"
257 lineclause = "line>=?"
238 params = (session, start)
258 params = (session, start)
239
259
240 return self._run_sql("WHERE session==? AND %s""" % lineclause,
260 return self._run_sql("WHERE session==? AND %s""" % lineclause,
241 params, raw=raw, output=output)
261 params, raw=raw, output=output)
242
262
243 def get_range_by_str(self, rangestr, raw=True, output=False):
263 def get_range_by_str(self, rangestr, raw=True, output=False):
244 """Get lines of history from a string of ranges, as used by magic
264 """Get lines of history from a string of ranges, as used by magic
245 commands %hist, %save, %macro, etc.
265 commands %hist, %save, %macro, etc.
246
266
247 Parameters
267 Parameters
248 ----------
268 ----------
249 rangestr : str
269 rangestr : str
250 A string specifying ranges, e.g. "5 ~2/1-4". See
270 A string specifying ranges, e.g. "5 ~2/1-4". See
251 :func:`magic_history` for full details.
271 :func:`magic_history` for full details.
252 raw, output : bool
272 raw, output : bool
253 As :meth:`get_range`
273 As :meth:`get_range`
254
274
255 Returns
275 Returns
256 -------
276 -------
257 Tuples as :meth:`get_range`
277 Tuples as :meth:`get_range`
258 """
278 """
259 for sess, s, e in extract_hist_ranges(rangestr):
279 for sess, s, e in extract_hist_ranges(rangestr):
260 for line in self.get_range(sess, s, e, raw=raw, output=output):
280 for line in self.get_range(sess, s, e, raw=raw, output=output):
261 yield line
281 yield line
262
282
263
283
264 class HistoryManager(HistoryAccessor):
284 class HistoryManager(HistoryAccessor):
265 """A class to organize all history-related functionality in one place.
285 """A class to organize all history-related functionality in one place.
266 """
286 """
267 # Public interface
287 # Public interface
268
288
269 # An instance of the IPython shell we are attached to
289 # An instance of the IPython shell we are attached to
270 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
290 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
271 # Lists to hold processed and raw history. These start with a blank entry
291 # Lists to hold processed and raw history. These start with a blank entry
272 # so that we can index them starting from 1
292 # so that we can index them starting from 1
273 input_hist_parsed = List([""])
293 input_hist_parsed = List([""])
274 input_hist_raw = List([""])
294 input_hist_raw = List([""])
275 # A list of directories visited during session
295 # A list of directories visited during session
276 dir_hist = List()
296 dir_hist = List()
277 def _dir_hist_default(self):
297 def _dir_hist_default(self):
278 try:
298 try:
279 return [os.getcwdu()]
299 return [os.getcwdu()]
280 except OSError:
300 except OSError:
281 return []
301 return []
282
302
283 # A dict of output history, keyed with ints from the shell's
303 # A dict of output history, keyed with ints from the shell's
284 # execution count.
304 # execution count.
285 output_hist = Dict()
305 output_hist = Dict()
286 # The text/plain repr of outputs.
306 # The text/plain repr of outputs.
287 output_hist_reprs = Dict()
307 output_hist_reprs = Dict()
288
308
289 # The number of the current session in the history database
309 # The number of the current session in the history database
290 session_number = CInt()
310 session_number = CInt()
291 # Should we log output to the database? (default no)
311 # Should we log output to the database? (default no)
292 db_log_output = Bool(False, config=True)
312 db_log_output = Bool(False, config=True)
293 # Write to database every x commands (higher values save disk access & power)
313 # Write to database every x commands (higher values save disk access & power)
294 # Values of 1 or less effectively disable caching.
314 # Values of 1 or less effectively disable caching.
295 db_cache_size = Int(0, config=True)
315 db_cache_size = Int(0, config=True)
296 # The input and output caches
316 # The input and output caches
297 db_input_cache = List()
317 db_input_cache = List()
298 db_output_cache = List()
318 db_output_cache = List()
299
319
300 # History saving in separate thread
320 # History saving in separate thread
301 save_thread = Instance('IPython.core.history.HistorySavingThread')
321 save_thread = Instance('IPython.core.history.HistorySavingThread')
302 try: # Event is a function returning an instance of _Event...
322 try: # Event is a function returning an instance of _Event...
303 save_flag = Instance(threading._Event)
323 save_flag = Instance(threading._Event)
304 except AttributeError: # ...until Python 3.3, when it's a class.
324 except AttributeError: # ...until Python 3.3, when it's a class.
305 save_flag = Instance(threading.Event)
325 save_flag = Instance(threading.Event)
306
326
307 # Private interface
327 # Private interface
308 # Variables used to store the three last inputs from the user. On each new
328 # Variables used to store the three last inputs from the user. On each new
309 # history update, we populate the user's namespace with these, shifted as
329 # history update, we populate the user's namespace with these, shifted as
310 # necessary.
330 # necessary.
311 _i00 = Unicode(u'')
331 _i00 = Unicode(u'')
312 _i = Unicode(u'')
332 _i = Unicode(u'')
313 _ii = Unicode(u'')
333 _ii = Unicode(u'')
314 _iii = Unicode(u'')
334 _iii = Unicode(u'')
315
335
316 # A regex matching all forms of the exit command, so that we don't store
336 # A regex matching all forms of the exit command, so that we don't store
317 # them in the history (it's annoying to rewind the first entry and land on
337 # them in the history (it's annoying to rewind the first entry and land on
318 # an exit call).
338 # an exit call).
319 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
339 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
320
340
321 def __init__(self, shell=None, config=None, **traits):
341 def __init__(self, shell=None, config=None, **traits):
322 """Create a new history manager associated with a shell instance.
342 """Create a new history manager associated with a shell instance.
323 """
343 """
324 # We need a pointer back to the shell for various tasks.
344 # We need a pointer back to the shell for various tasks.
325 super(HistoryManager, self).__init__(shell=shell, config=config,
345 super(HistoryManager, self).__init__(shell=shell, config=config,
326 **traits)
346 **traits)
327 self.save_flag = threading.Event()
347 self.save_flag = threading.Event()
328 self.db_input_cache_lock = threading.Lock()
348 self.db_input_cache_lock = threading.Lock()
329 self.db_output_cache_lock = threading.Lock()
349 self.db_output_cache_lock = threading.Lock()
330 self.save_thread = HistorySavingThread(self)
350 self.save_thread = HistorySavingThread(self)
331 self.save_thread.start()
351 self.save_thread.start()
332
352
333 self.new_session()
353 self.new_session()
334
354
335 def _get_hist_file_name(self, hist_file=None):
355 def _get_hist_file_name(self, profile=None):
356 """Get default history file name based on the Shell's profile.
357
358 The profile parameter is ignored, but must exist for compatibility with
359 the parent class."""
336 profile_dir = self.shell.profile_dir.location
360 profile_dir = self.shell.profile_dir.location
337 return os.path.join(profile_dir, 'history.sqlite')
361 return os.path.join(profile_dir, 'history.sqlite')
338
362
339 def new_session(self, conn=None):
363 def new_session(self, conn=None):
340 """Get a new session number."""
364 """Get a new session number."""
341 if conn is None:
365 if conn is None:
342 conn = self.db
366 conn = self.db
343
367
344 with conn:
368 with conn:
345 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
369 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
346 NULL, "") """, (datetime.datetime.now(),))
370 NULL, "") """, (datetime.datetime.now(),))
347 self.session_number = cur.lastrowid
371 self.session_number = cur.lastrowid
348
372
349 def end_session(self):
373 def end_session(self):
350 """Close the database session, filling in the end time and line count."""
374 """Close the database session, filling in the end time and line count."""
351 self.writeout_cache()
375 self.writeout_cache()
352 with self.db:
376 with self.db:
353 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
377 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
354 session==?""", (datetime.datetime.now(),
378 session==?""", (datetime.datetime.now(),
355 len(self.input_hist_parsed)-1, self.session_number))
379 len(self.input_hist_parsed)-1, self.session_number))
356 self.session_number = 0
380 self.session_number = 0
357
381
358 def name_session(self, name):
382 def name_session(self, name):
359 """Give the current session a name in the history database."""
383 """Give the current session a name in the history database."""
360 with self.db:
384 with self.db:
361 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
385 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
362 (name, self.session_number))
386 (name, self.session_number))
363
387
364 def reset(self, new_session=True):
388 def reset(self, new_session=True):
365 """Clear the session history, releasing all object references, and
389 """Clear the session history, releasing all object references, and
366 optionally open a new session."""
390 optionally open a new session."""
367 self.output_hist.clear()
391 self.output_hist.clear()
368 # The directory history can't be completely empty
392 # The directory history can't be completely empty
369 self.dir_hist[:] = [os.getcwdu()]
393 self.dir_hist[:] = [os.getcwdu()]
370
394
371 if new_session:
395 if new_session:
372 if self.session_number:
396 if self.session_number:
373 self.end_session()
397 self.end_session()
374 self.input_hist_parsed[:] = [""]
398 self.input_hist_parsed[:] = [""]
375 self.input_hist_raw[:] = [""]
399 self.input_hist_raw[:] = [""]
376 self.new_session()
400 self.new_session()
377
401
378 # ------------------------------
402 # ------------------------------
379 # Methods for retrieving history
403 # Methods for retrieving history
380 # ------------------------------
404 # ------------------------------
381 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
405 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
382 """Get input and output history from the current session. Called by
406 """Get input and output history from the current session. Called by
383 get_range, and takes similar parameters."""
407 get_range, and takes similar parameters."""
384 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
408 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
385
409
386 n = len(input_hist)
410 n = len(input_hist)
387 if start < 0:
411 if start < 0:
388 start += n
412 start += n
389 if not stop or (stop > n):
413 if not stop or (stop > n):
390 stop = n
414 stop = n
391 elif stop < 0:
415 elif stop < 0:
392 stop += n
416 stop += n
393
417
394 for i in range(start, stop):
418 for i in range(start, stop):
395 if output:
419 if output:
396 line = (input_hist[i], self.output_hist_reprs.get(i))
420 line = (input_hist[i], self.output_hist_reprs.get(i))
397 else:
421 else:
398 line = input_hist[i]
422 line = input_hist[i]
399 yield (0, i, line)
423 yield (0, i, line)
400
424
401 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
425 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
402 """Retrieve input by session.
426 """Retrieve input by session.
403
427
404 Parameters
428 Parameters
405 ----------
429 ----------
406 session : int
430 session : int
407 Session number to retrieve. The current session is 0, and negative
431 Session number to retrieve. The current session is 0, and negative
408 numbers count back from current session, so -1 is previous session.
432 numbers count back from current session, so -1 is previous session.
409 start : int
433 start : int
410 First line to retrieve.
434 First line to retrieve.
411 stop : int
435 stop : int
412 End of line range (excluded from output itself). If None, retrieve
436 End of line range (excluded from output itself). If None, retrieve
413 to the end of the session.
437 to the end of the session.
414 raw : bool
438 raw : bool
415 If True, return untranslated input
439 If True, return untranslated input
416 output : bool
440 output : bool
417 If True, attempt to include output. This will be 'real' Python
441 If True, attempt to include output. This will be 'real' Python
418 objects for the current session, or text reprs from previous
442 objects for the current session, or text reprs from previous
419 sessions if db_log_output was enabled at the time. Where no output
443 sessions if db_log_output was enabled at the time. Where no output
420 is found, None is used.
444 is found, None is used.
421
445
422 Returns
446 Returns
423 -------
447 -------
424 An iterator over the desired lines. Each line is a 3-tuple, either
448 An iterator over the desired lines. Each line is a 3-tuple, either
425 (session, line, input) if output is False, or
449 (session, line, input) if output is False, or
426 (session, line, (input, output)) if output is True.
450 (session, line, (input, output)) if output is True.
427 """
451 """
428 if session <= 0:
452 if session <= 0:
429 session += self.session_number
453 session += self.session_number
430 if session==self.session_number: # Current session
454 if session==self.session_number: # Current session
431 return self._get_range_session(start, stop, raw, output)
455 return self._get_range_session(start, stop, raw, output)
432 return super(HistoryManager, self).get_range(session, start, stop, raw, output)
456 return super(HistoryManager, self).get_range(session, start, stop, raw, output)
433
457
434 ## ----------------------------
458 ## ----------------------------
435 ## Methods for storing history:
459 ## Methods for storing history:
436 ## ----------------------------
460 ## ----------------------------
437 def store_inputs(self, line_num, source, source_raw=None):
461 def store_inputs(self, line_num, source, source_raw=None):
438 """Store source and raw input in history and create input cache
462 """Store source and raw input in history and create input cache
439 variables _i*.
463 variables _i*.
440
464
441 Parameters
465 Parameters
442 ----------
466 ----------
443 line_num : int
467 line_num : int
444 The prompt number of this input.
468 The prompt number of this input.
445
469
446 source : str
470 source : str
447 Python input.
471 Python input.
448
472
449 source_raw : str, optional
473 source_raw : str, optional
450 If given, this is the raw input without any IPython transformations
474 If given, this is the raw input without any IPython transformations
451 applied to it. If not given, ``source`` is used.
475 applied to it. If not given, ``source`` is used.
452 """
476 """
453 if source_raw is None:
477 if source_raw is None:
454 source_raw = source
478 source_raw = source
455 source = source.rstrip('\n')
479 source = source.rstrip('\n')
456 source_raw = source_raw.rstrip('\n')
480 source_raw = source_raw.rstrip('\n')
457
481
458 # do not store exit/quit commands
482 # do not store exit/quit commands
459 if self._exit_re.match(source_raw.strip()):
483 if self._exit_re.match(source_raw.strip()):
460 return
484 return
461
485
462 self.input_hist_parsed.append(source)
486 self.input_hist_parsed.append(source)
463 self.input_hist_raw.append(source_raw)
487 self.input_hist_raw.append(source_raw)
464
488
465 with self.db_input_cache_lock:
489 with self.db_input_cache_lock:
466 self.db_input_cache.append((line_num, source, source_raw))
490 self.db_input_cache.append((line_num, source, source_raw))
467 # Trigger to flush cache and write to DB.
491 # Trigger to flush cache and write to DB.
468 if len(self.db_input_cache) >= self.db_cache_size:
492 if len(self.db_input_cache) >= self.db_cache_size:
469 self.save_flag.set()
493 self.save_flag.set()
470
494
471 # update the auto _i variables
495 # update the auto _i variables
472 self._iii = self._ii
496 self._iii = self._ii
473 self._ii = self._i
497 self._ii = self._i
474 self._i = self._i00
498 self._i = self._i00
475 self._i00 = source_raw
499 self._i00 = source_raw
476
500
477 # hackish access to user namespace to create _i1,_i2... dynamically
501 # hackish access to user namespace to create _i1,_i2... dynamically
478 new_i = '_i%s' % line_num
502 new_i = '_i%s' % line_num
479 to_main = {'_i': self._i,
503 to_main = {'_i': self._i,
480 '_ii': self._ii,
504 '_ii': self._ii,
481 '_iii': self._iii,
505 '_iii': self._iii,
482 new_i : self._i00 }
506 new_i : self._i00 }
483 self.shell.user_ns.update(to_main)
507 self.shell.user_ns.update(to_main)
484
508
485 def store_output(self, line_num):
509 def store_output(self, line_num):
486 """If database output logging is enabled, this saves all the
510 """If database output logging is enabled, this saves all the
487 outputs from the indicated prompt number to the database. It's
511 outputs from the indicated prompt number to the database. It's
488 called by run_cell after code has been executed.
512 called by run_cell after code has been executed.
489
513
490 Parameters
514 Parameters
491 ----------
515 ----------
492 line_num : int
516 line_num : int
493 The line number from which to save outputs
517 The line number from which to save outputs
494 """
518 """
495 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
519 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
496 return
520 return
497 output = self.output_hist_reprs[line_num]
521 output = self.output_hist_reprs[line_num]
498
522
499 with self.db_output_cache_lock:
523 with self.db_output_cache_lock:
500 self.db_output_cache.append((line_num, output))
524 self.db_output_cache.append((line_num, output))
501 if self.db_cache_size <= 1:
525 if self.db_cache_size <= 1:
502 self.save_flag.set()
526 self.save_flag.set()
503
527
504 def _writeout_input_cache(self, conn):
528 def _writeout_input_cache(self, conn):
505 with conn:
529 with conn:
506 for line in self.db_input_cache:
530 for line in self.db_input_cache:
507 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
531 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
508 (self.session_number,)+line)
532 (self.session_number,)+line)
509
533
510 def _writeout_output_cache(self, conn):
534 def _writeout_output_cache(self, conn):
511 with conn:
535 with conn:
512 for line in self.db_output_cache:
536 for line in self.db_output_cache:
513 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
537 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
514 (self.session_number,)+line)
538 (self.session_number,)+line)
515
539
516 def writeout_cache(self, conn=None):
540 def writeout_cache(self, conn=None):
517 """Write any entries in the cache to the database."""
541 """Write any entries in the cache to the database."""
518 if conn is None:
542 if conn is None:
519 conn = self.db
543 conn = self.db
520
544
521 with self.db_input_cache_lock:
545 with self.db_input_cache_lock:
522 try:
546 try:
523 self._writeout_input_cache(conn)
547 self._writeout_input_cache(conn)
524 except sqlite3.IntegrityError:
548 except sqlite3.IntegrityError:
525 self.new_session(conn)
549 self.new_session(conn)
526 print("ERROR! Session/line number was not unique in",
550 print("ERROR! Session/line number was not unique in",
527 "database. History logging moved to new session",
551 "database. History logging moved to new session",
528 self.session_number)
552 self.session_number)
529 try: # Try writing to the new session. If this fails, don't recurse
553 try: # Try writing to the new session. If this fails, don't recurse
530 self._writeout_input_cache(conn)
554 self._writeout_input_cache(conn)
531 except sqlite3.IntegrityError:
555 except sqlite3.IntegrityError:
532 pass
556 pass
533 finally:
557 finally:
534 self.db_input_cache = []
558 self.db_input_cache = []
535
559
536 with self.db_output_cache_lock:
560 with self.db_output_cache_lock:
537 try:
561 try:
538 self._writeout_output_cache(conn)
562 self._writeout_output_cache(conn)
539 except sqlite3.IntegrityError:
563 except sqlite3.IntegrityError:
540 print("!! Session/line number for output was not unique",
564 print("!! Session/line number for output was not unique",
541 "in database. Output will not be stored.")
565 "in database. Output will not be stored.")
542 finally:
566 finally:
543 self.db_output_cache = []
567 self.db_output_cache = []
544
568
545
569
546 class HistorySavingThread(threading.Thread):
570 class HistorySavingThread(threading.Thread):
547 """This thread takes care of writing history to the database, so that
571 """This thread takes care of writing history to the database, so that
548 the UI isn't held up while that happens.
572 the UI isn't held up while that happens.
549
573
550 It waits for the HistoryManager's save_flag to be set, then writes out
574 It waits for the HistoryManager's save_flag to be set, then writes out
551 the history cache. The main thread is responsible for setting the flag when
575 the history cache. The main thread is responsible for setting the flag when
552 the cache size reaches a defined threshold."""
576 the cache size reaches a defined threshold."""
553 daemon = True
577 daemon = True
554 stop_now = False
578 stop_now = False
555 def __init__(self, history_manager):
579 def __init__(self, history_manager):
556 super(HistorySavingThread, self).__init__()
580 super(HistorySavingThread, self).__init__()
557 self.history_manager = history_manager
581 self.history_manager = history_manager
558 atexit.register(self.stop)
582 atexit.register(self.stop)
559
583
560 def run(self):
584 def run(self):
561 # We need a separate db connection per thread:
585 # We need a separate db connection per thread:
562 try:
586 try:
563 self.db = sqlite3.connect(self.history_manager.hist_file)
587 self.db = sqlite3.connect(self.history_manager.hist_file)
564 while True:
588 while True:
565 self.history_manager.save_flag.wait()
589 self.history_manager.save_flag.wait()
566 if self.stop_now:
590 if self.stop_now:
567 return
591 return
568 self.history_manager.save_flag.clear()
592 self.history_manager.save_flag.clear()
569 self.history_manager.writeout_cache(self.db)
593 self.history_manager.writeout_cache(self.db)
570 except Exception as e:
594 except Exception as e:
571 print(("The history saving thread hit an unexpected error (%s)."
595 print(("The history saving thread hit an unexpected error (%s)."
572 "History will not be written to the database.") % repr(e))
596 "History will not be written to the database.") % repr(e))
573
597
574 def stop(self):
598 def stop(self):
575 """This can be called from the main thread to safely stop this thread.
599 """This can be called from the main thread to safely stop this thread.
576
600
577 Note that it does not attempt to write out remaining history before
601 Note that it does not attempt to write out remaining history before
578 exiting. That should be done by calling the HistoryManager's
602 exiting. That should be done by calling the HistoryManager's
579 end_session method."""
603 end_session method."""
580 self.stop_now = True
604 self.stop_now = True
581 self.history_manager.save_flag.set()
605 self.history_manager.save_flag.set()
582 self.join()
606 self.join()
583
607
584
608
585 # To match, e.g. ~5/8-~2/3
609 # To match, e.g. ~5/8-~2/3
586 range_re = re.compile(r"""
610 range_re = re.compile(r"""
587 ((?P<startsess>~?\d+)/)?
611 ((?P<startsess>~?\d+)/)?
588 (?P<start>\d+) # Only the start line num is compulsory
612 (?P<start>\d+) # Only the start line num is compulsory
589 ((?P<sep>[\-:])
613 ((?P<sep>[\-:])
590 ((?P<endsess>~?\d+)/)?
614 ((?P<endsess>~?\d+)/)?
591 (?P<end>\d+))?
615 (?P<end>\d+))?
592 $""", re.VERBOSE)
616 $""", re.VERBOSE)
593
617
594 def extract_hist_ranges(ranges_str):
618 def extract_hist_ranges(ranges_str):
595 """Turn a string of history ranges into 3-tuples of (session, start, stop).
619 """Turn a string of history ranges into 3-tuples of (session, start, stop).
596
620
597 Examples
621 Examples
598 --------
622 --------
599 list(extract_input_ranges("~8/5-~7/4 2"))
623 list(extract_input_ranges("~8/5-~7/4 2"))
600 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
624 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
601 """
625 """
602 for range_str in ranges_str.split():
626 for range_str in ranges_str.split():
603 rmatch = range_re.match(range_str)
627 rmatch = range_re.match(range_str)
604 if not rmatch:
628 if not rmatch:
605 continue
629 continue
606 start = int(rmatch.group("start"))
630 start = int(rmatch.group("start"))
607 end = rmatch.group("end")
631 end = rmatch.group("end")
608 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
632 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
609 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
633 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
610 end += 1
634 end += 1
611 startsess = rmatch.group("startsess") or "0"
635 startsess = rmatch.group("startsess") or "0"
612 endsess = rmatch.group("endsess") or startsess
636 endsess = rmatch.group("endsess") or startsess
613 startsess = int(startsess.replace("~","-"))
637 startsess = int(startsess.replace("~","-"))
614 endsess = int(endsess.replace("~","-"))
638 endsess = int(endsess.replace("~","-"))
615 assert endsess >= startsess
639 assert endsess >= startsess
616
640
617 if endsess == startsess:
641 if endsess == startsess:
618 yield (startsess, start, end)
642 yield (startsess, start, end)
619 continue
643 continue
620 # Multiple sessions in one range:
644 # Multiple sessions in one range:
621 yield (startsess, start, None)
645 yield (startsess, start, None)
622 for sess in range(startsess+1, endsess):
646 for sess in range(startsess+1, endsess):
623 yield (sess, 1, None)
647 yield (sess, 1, None)
624 yield (endsess, 1, end)
648 yield (endsess, 1, end)
625
649
626 def _format_lineno(session, line):
650 def _format_lineno(session, line):
627 """Helper function to format line numbers properly."""
651 """Helper function to format line numbers properly."""
628 if session == 0:
652 if session == 0:
629 return str(line)
653 return str(line)
630 return "%s#%s" % (session, line)
654 return "%s#%s" % (session, line)
631
655
632 @skip_doctest
656 @skip_doctest
633 def magic_history(self, parameter_s = ''):
657 def magic_history(self, parameter_s = ''):
634 """Print input history (_i<n> variables), with most recent last.
658 """Print input history (_i<n> variables), with most recent last.
635
659
636 %history -> print at most 40 inputs (some may be multi-line)\\
660 %history -> print at most 40 inputs (some may be multi-line)\\
637 %history n -> print at most n inputs\\
661 %history n -> print at most n inputs\\
638 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
662 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
639
663
640 By default, input history is printed without line numbers so it can be
664 By default, input history is printed without line numbers so it can be
641 directly pasted into an editor. Use -n to show them.
665 directly pasted into an editor. Use -n to show them.
642
666
643 Ranges of history can be indicated using the syntax:
667 Ranges of history can be indicated using the syntax:
644 4 : Line 4, current session
668 4 : Line 4, current session
645 4-6 : Lines 4-6, current session
669 4-6 : Lines 4-6, current session
646 243/1-5: Lines 1-5, session 243
670 243/1-5: Lines 1-5, session 243
647 ~2/7 : Line 7, session 2 before current
671 ~2/7 : Line 7, session 2 before current
648 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
672 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
649 of 6 sessions ago.
673 of 6 sessions ago.
650 Multiple ranges can be entered, separated by spaces
674 Multiple ranges can be entered, separated by spaces
651
675
652 The same syntax is used by %macro, %save, %edit, %rerun
676 The same syntax is used by %macro, %save, %edit, %rerun
653
677
654 Options:
678 Options:
655
679
656 -n: print line numbers for each input.
680 -n: print line numbers for each input.
657 This feature is only available if numbered prompts are in use.
681 This feature is only available if numbered prompts are in use.
658
682
659 -o: also print outputs for each input.
683 -o: also print outputs for each input.
660
684
661 -p: print classic '>>>' python prompts before each input. This is useful
685 -p: print classic '>>>' python prompts before each input. This is useful
662 for making documentation, and in conjunction with -o, for producing
686 for making documentation, and in conjunction with -o, for producing
663 doctest-ready output.
687 doctest-ready output.
664
688
665 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
689 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
666
690
667 -t: print the 'translated' history, as IPython understands it. IPython
691 -t: print the 'translated' history, as IPython understands it. IPython
668 filters your input and converts it all into valid Python source before
692 filters your input and converts it all into valid Python source before
669 executing it (things like magics or aliases are turned into function
693 executing it (things like magics or aliases are turned into function
670 calls, for example). With this option, you'll see the native history
694 calls, for example). With this option, you'll see the native history
671 instead of the user-entered version: '%cd /' will be seen as
695 instead of the user-entered version: '%cd /' will be seen as
672 'get_ipython().magic("%cd /")' instead of '%cd /'.
696 'get_ipython().magic("%cd /")' instead of '%cd /'.
673
697
674 -g: treat the arg as a pattern to grep for in (full) history.
698 -g: treat the arg as a pattern to grep for in (full) history.
675 This includes the saved history (almost all commands ever written).
699 This includes the saved history (almost all commands ever written).
676 Use '%hist -g' to show full saved history (may be very long).
700 Use '%hist -g' to show full saved history (may be very long).
677
701
678 -l: get the last n lines from all sessions. Specify n as a single arg, or
702 -l: get the last n lines from all sessions. Specify n as a single arg, or
679 the default is the last 10 lines.
703 the default is the last 10 lines.
680
704
681 -f FILENAME: instead of printing the output to the screen, redirect it to
705 -f FILENAME: instead of printing the output to the screen, redirect it to
682 the given file. The file is always overwritten, though IPython asks for
706 the given file. The file is always overwritten, though IPython asks for
683 confirmation first if it already exists.
707 confirmation first if it already exists.
684
708
685 Examples
709 Examples
686 --------
710 --------
687 ::
711 ::
688
712
689 In [6]: %hist -n 4 6
713 In [6]: %hist -n 4 6
690 4:a = 12
714 4:a = 12
691 5:print a**2
715 5:print a**2
692
716
693 """
717 """
694
718
695 if not self.shell.displayhook.do_full_cache:
719 if not self.shell.displayhook.do_full_cache:
696 print('This feature is only available if numbered prompts are in use.')
720 print('This feature is only available if numbered prompts are in use.')
697 return
721 return
698 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
722 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
699
723
700 # For brevity
724 # For brevity
701 history_manager = self.shell.history_manager
725 history_manager = self.shell.history_manager
702
726
703 def _format_lineno(session, line):
727 def _format_lineno(session, line):
704 """Helper function to format line numbers properly."""
728 """Helper function to format line numbers properly."""
705 if session in (0, history_manager.session_number):
729 if session in (0, history_manager.session_number):
706 return str(line)
730 return str(line)
707 return "%s/%s" % (session, line)
731 return "%s/%s" % (session, line)
708
732
709 # Check if output to specific file was requested.
733 # Check if output to specific file was requested.
710 try:
734 try:
711 outfname = opts['f']
735 outfname = opts['f']
712 except KeyError:
736 except KeyError:
713 outfile = io.stdout # default
737 outfile = io.stdout # default
714 # We don't want to close stdout at the end!
738 # We don't want to close stdout at the end!
715 close_at_end = False
739 close_at_end = False
716 else:
740 else:
717 if os.path.exists(outfname):
741 if os.path.exists(outfname):
718 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
742 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
719 print('Aborting.')
743 print('Aborting.')
720 return
744 return
721
745
722 outfile = open(outfname,'w')
746 outfile = open(outfname,'w')
723 close_at_end = True
747 close_at_end = True
724
748
725 print_nums = 'n' in opts
749 print_nums = 'n' in opts
726 get_output = 'o' in opts
750 get_output = 'o' in opts
727 pyprompts = 'p' in opts
751 pyprompts = 'p' in opts
728 # Raw history is the default
752 # Raw history is the default
729 raw = not('t' in opts)
753 raw = not('t' in opts)
730
754
731 default_length = 40
755 default_length = 40
732 pattern = None
756 pattern = None
733
757
734 if 'g' in opts: # Glob search
758 if 'g' in opts: # Glob search
735 pattern = "*" + args + "*" if args else "*"
759 pattern = "*" + args + "*" if args else "*"
736 hist = history_manager.search(pattern, raw=raw, output=get_output)
760 hist = history_manager.search(pattern, raw=raw, output=get_output)
737 print_nums = True
761 print_nums = True
738 elif 'l' in opts: # Get 'tail'
762 elif 'l' in opts: # Get 'tail'
739 try:
763 try:
740 n = int(args)
764 n = int(args)
741 except ValueError, IndexError:
765 except ValueError, IndexError:
742 n = 10
766 n = 10
743 hist = history_manager.get_tail(n, raw=raw, output=get_output)
767 hist = history_manager.get_tail(n, raw=raw, output=get_output)
744 else:
768 else:
745 if args: # Get history by ranges
769 if args: # Get history by ranges
746 hist = history_manager.get_range_by_str(args, raw, get_output)
770 hist = history_manager.get_range_by_str(args, raw, get_output)
747 else: # Just get history for the current session
771 else: # Just get history for the current session
748 hist = history_manager.get_range(raw=raw, output=get_output)
772 hist = history_manager.get_range(raw=raw, output=get_output)
749
773
750 # We could be displaying the entire history, so let's not try to pull it
774 # We could be displaying the entire history, so let's not try to pull it
751 # into a list in memory. Anything that needs more space will just misalign.
775 # into a list in memory. Anything that needs more space will just misalign.
752 width = 4
776 width = 4
753
777
754 for session, lineno, inline in hist:
778 for session, lineno, inline in hist:
755 # Print user history with tabs expanded to 4 spaces. The GUI clients
779 # Print user history with tabs expanded to 4 spaces. The GUI clients
756 # use hard tabs for easier usability in auto-indented code, but we want
780 # use hard tabs for easier usability in auto-indented code, but we want
757 # to produce PEP-8 compliant history for safe pasting into an editor.
781 # to produce PEP-8 compliant history for safe pasting into an editor.
758 if get_output:
782 if get_output:
759 inline, output = inline
783 inline, output = inline
760 inline = inline.expandtabs(4).rstrip()
784 inline = inline.expandtabs(4).rstrip()
761
785
762 multiline = "\n" in inline
786 multiline = "\n" in inline
763 line_sep = '\n' if multiline else ' '
787 line_sep = '\n' if multiline else ' '
764 if print_nums:
788 if print_nums:
765 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
789 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
766 line_sep), file=outfile, end='')
790 line_sep), file=outfile, end='')
767 if pyprompts:
791 if pyprompts:
768 print(">>> ", end="", file=outfile)
792 print(">>> ", end="", file=outfile)
769 if multiline:
793 if multiline:
770 inline = "\n... ".join(inline.splitlines()) + "\n..."
794 inline = "\n... ".join(inline.splitlines()) + "\n..."
771 print(inline, file=outfile)
795 print(inline, file=outfile)
772 if get_output and output:
796 if get_output and output:
773 print(output, file=outfile)
797 print(output, file=outfile)
774
798
775 if close_at_end:
799 if close_at_end:
776 outfile.close()
800 outfile.close()
777
801
778
802
779 def magic_rep(self, arg):
803 def magic_rep(self, arg):
780 r"""Repeat a command, or get command to input line for editing. %recall and
804 r"""Repeat a command, or get command to input line for editing. %recall and
781 %rep are equivalent.
805 %rep are equivalent.
782
806
783 - %recall (no arguments):
807 - %recall (no arguments):
784
808
785 Place a string version of last computation result (stored in the special '_'
809 Place a string version of last computation result (stored in the special '_'
786 variable) to the next input prompt. Allows you to create elaborate command
810 variable) to the next input prompt. Allows you to create elaborate command
787 lines without using copy-paste::
811 lines without using copy-paste::
788
812
789 In[1]: l = ["hei", "vaan"]
813 In[1]: l = ["hei", "vaan"]
790 In[2]: "".join(l)
814 In[2]: "".join(l)
791 Out[2]: heivaan
815 Out[2]: heivaan
792 In[3]: %rep
816 In[3]: %rep
793 In[4]: heivaan_ <== cursor blinking
817 In[4]: heivaan_ <== cursor blinking
794
818
795 %recall 45
819 %recall 45
796
820
797 Place history line 45 on the next input prompt. Use %hist to find
821 Place history line 45 on the next input prompt. Use %hist to find
798 out the number.
822 out the number.
799
823
800 %recall 1-4
824 %recall 1-4
801
825
802 Combine the specified lines into one cell, and place it on the next
826 Combine the specified lines into one cell, and place it on the next
803 input prompt. See %history for the slice syntax.
827 input prompt. See %history for the slice syntax.
804
828
805 %recall foo+bar
829 %recall foo+bar
806
830
807 If foo+bar can be evaluated in the user namespace, the result is
831 If foo+bar can be evaluated in the user namespace, the result is
808 placed at the next input prompt. Otherwise, the history is searched
832 placed at the next input prompt. Otherwise, the history is searched
809 for lines which contain that substring, and the most recent one is
833 for lines which contain that substring, and the most recent one is
810 placed at the next input prompt.
834 placed at the next input prompt.
811 """
835 """
812 if not arg: # Last output
836 if not arg: # Last output
813 self.set_next_input(str(self.shell.user_ns["_"]))
837 self.set_next_input(str(self.shell.user_ns["_"]))
814 return
838 return
815 # Get history range
839 # Get history range
816 histlines = self.history_manager.get_range_by_str(arg)
840 histlines = self.history_manager.get_range_by_str(arg)
817 cmd = "\n".join(x[2] for x in histlines)
841 cmd = "\n".join(x[2] for x in histlines)
818 if cmd:
842 if cmd:
819 self.set_next_input(cmd.rstrip())
843 self.set_next_input(cmd.rstrip())
820 return
844 return
821
845
822 try: # Variable in user namespace
846 try: # Variable in user namespace
823 cmd = str(eval(arg, self.shell.user_ns))
847 cmd = str(eval(arg, self.shell.user_ns))
824 except Exception: # Search for term in history
848 except Exception: # Search for term in history
825 histlines = self.history_manager.search("*"+arg+"*")
849 histlines = self.history_manager.search("*"+arg+"*")
826 for h in reversed([x[2] for x in histlines]):
850 for h in reversed([x[2] for x in histlines]):
827 if 'rep' in h:
851 if 'rep' in h:
828 continue
852 continue
829 self.set_next_input(h.rstrip())
853 self.set_next_input(h.rstrip())
830 return
854 return
831 else:
855 else:
832 self.set_next_input(cmd.rstrip())
856 self.set_next_input(cmd.rstrip())
833 print("Couldn't evaluate or find in history:", arg)
857 print("Couldn't evaluate or find in history:", arg)
834
858
835 def magic_rerun(self, parameter_s=''):
859 def magic_rerun(self, parameter_s=''):
836 """Re-run previous input
860 """Re-run previous input
837
861
838 By default, you can specify ranges of input history to be repeated
862 By default, you can specify ranges of input history to be repeated
839 (as with %history). With no arguments, it will repeat the last line.
863 (as with %history). With no arguments, it will repeat the last line.
840
864
841 Options:
865 Options:
842
866
843 -l <n> : Repeat the last n lines of input, not including the
867 -l <n> : Repeat the last n lines of input, not including the
844 current command.
868 current command.
845
869
846 -g foo : Repeat the most recent line which contains foo
870 -g foo : Repeat the most recent line which contains foo
847 """
871 """
848 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
872 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
849 if "l" in opts: # Last n lines
873 if "l" in opts: # Last n lines
850 n = int(opts['l'])
874 n = int(opts['l'])
851 hist = self.history_manager.get_tail(n)
875 hist = self.history_manager.get_tail(n)
852 elif "g" in opts: # Search
876 elif "g" in opts: # Search
853 p = "*"+opts['g']+"*"
877 p = "*"+opts['g']+"*"
854 hist = list(self.history_manager.search(p))
878 hist = list(self.history_manager.search(p))
855 for l in reversed(hist):
879 for l in reversed(hist):
856 if "rerun" not in l[2]:
880 if "rerun" not in l[2]:
857 hist = [l] # The last match which isn't a %rerun
881 hist = [l] # The last match which isn't a %rerun
858 break
882 break
859 else:
883 else:
860 hist = [] # No matches except %rerun
884 hist = [] # No matches except %rerun
861 elif args: # Specify history ranges
885 elif args: # Specify history ranges
862 hist = self.history_manager.get_range_by_str(args)
886 hist = self.history_manager.get_range_by_str(args)
863 else: # Last line
887 else: # Last line
864 hist = self.history_manager.get_tail(1)
888 hist = self.history_manager.get_tail(1)
865 hist = [x[2] for x in hist]
889 hist = [x[2] for x in hist]
866 if not hist:
890 if not hist:
867 print("No lines in history match specification")
891 print("No lines in history match specification")
868 return
892 return
869 histlines = "\n".join(hist)
893 histlines = "\n".join(hist)
870 print("=== Executing: ===")
894 print("=== Executing: ===")
871 print(histlines)
895 print(histlines)
872 print("=== Output: ===")
896 print("=== Output: ===")
873 self.run_cell("\n".join(hist), store_history=False)
897 self.run_cell("\n".join(hist), store_history=False)
874
898
875
899
876 def init_ipython(ip):
900 def init_ipython(ip):
877 ip.define_magic("rep", magic_rep)
901 ip.define_magic("rep", magic_rep)
878 ip.define_magic("recall", magic_rep)
902 ip.define_magic("recall", magic_rep)
879 ip.define_magic("rerun", magic_rerun)
903 ip.define_magic("rerun", magic_rerun)
880 ip.define_magic("hist",magic_history) # Alternative name
904 ip.define_magic("hist",magic_history) # Alternative name
881 ip.define_magic("history",magic_history)
905 ip.define_magic("history",magic_history)
882
906
883 # XXX - ipy_completers are in quarantine, need to be updated to new apis
907 # XXX - ipy_completers are in quarantine, need to be updated to new apis
884 #import ipy_completers
908 #import ipy_completers
885 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
909 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
@@ -1,478 +1,490 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for path handling.
3 Utilities for path handling.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 from hashlib import md5
20 from hashlib import md5
21
21
22 import IPython
22 import IPython
23 from IPython.utils import warn
23 from IPython.utils import warn
24 from IPython.utils.process import system
24 from IPython.utils.process import system
25 from IPython.utils.importstring import import_item
25 from IPython.utils.importstring import import_item
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Code
29 # Code
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 fs_encoding = sys.getfilesystemencoding()
32 fs_encoding = sys.getfilesystemencoding()
33
33
34 def _get_long_path_name(path):
34 def _get_long_path_name(path):
35 """Dummy no-op."""
35 """Dummy no-op."""
36 return path
36 return path
37
37
38 def _writable_dir(path):
38 def _writable_dir(path):
39 """Whether `path` is a directory, to which the user has write access."""
39 """Whether `path` is a directory, to which the user has write access."""
40 return os.path.isdir(path) and os.access(path, os.W_OK)
40 return os.path.isdir(path) and os.access(path, os.W_OK)
41
41
42 if sys.platform == 'win32':
42 if sys.platform == 'win32':
43 def _get_long_path_name(path):
43 def _get_long_path_name(path):
44 """Get a long path name (expand ~) on Windows using ctypes.
44 """Get a long path name (expand ~) on Windows using ctypes.
45
45
46 Examples
46 Examples
47 --------
47 --------
48
48
49 >>> get_long_path_name('c:\\docume~1')
49 >>> get_long_path_name('c:\\docume~1')
50 u'c:\\\\Documents and Settings'
50 u'c:\\\\Documents and Settings'
51
51
52 """
52 """
53 try:
53 try:
54 import ctypes
54 import ctypes
55 except ImportError:
55 except ImportError:
56 raise ImportError('you need to have ctypes installed for this to work')
56 raise ImportError('you need to have ctypes installed for this to work')
57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
59 ctypes.c_uint ]
59 ctypes.c_uint ]
60
60
61 buf = ctypes.create_unicode_buffer(260)
61 buf = ctypes.create_unicode_buffer(260)
62 rv = _GetLongPathName(path, buf, 260)
62 rv = _GetLongPathName(path, buf, 260)
63 if rv == 0 or rv > 260:
63 if rv == 0 or rv > 260:
64 return path
64 return path
65 else:
65 else:
66 return buf.value
66 return buf.value
67
67
68
68
69 def get_long_path_name(path):
69 def get_long_path_name(path):
70 """Expand a path into its long form.
70 """Expand a path into its long form.
71
71
72 On Windows this expands any ~ in the paths. On other platforms, it is
72 On Windows this expands any ~ in the paths. On other platforms, it is
73 a null operation.
73 a null operation.
74 """
74 """
75 return _get_long_path_name(path)
75 return _get_long_path_name(path)
76
76
77
77
78 def unquote_filename(name, win32=(sys.platform=='win32')):
78 def unquote_filename(name, win32=(sys.platform=='win32')):
79 """ On Windows, remove leading and trailing quotes from filenames.
79 """ On Windows, remove leading and trailing quotes from filenames.
80 """
80 """
81 if win32:
81 if win32:
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
83 name = name[1:-1]
83 name = name[1:-1]
84 return name
84 return name
85
85
86
86
87 def get_py_filename(name, force_win32=None):
87 def get_py_filename(name, force_win32=None):
88 """Return a valid python filename in the current directory.
88 """Return a valid python filename in the current directory.
89
89
90 If the given name is not a file, it adds '.py' and searches again.
90 If the given name is not a file, it adds '.py' and searches again.
91 Raises IOError with an informative message if the file isn't found.
91 Raises IOError with an informative message if the file isn't found.
92
92
93 On Windows, apply Windows semantics to the filename. In particular, remove
93 On Windows, apply Windows semantics to the filename. In particular, remove
94 any quoting that has been applied to it. This option can be forced for
94 any quoting that has been applied to it. This option can be forced for
95 testing purposes.
95 testing purposes.
96 """
96 """
97
97
98 name = os.path.expanduser(name)
98 name = os.path.expanduser(name)
99 if force_win32 is None:
99 if force_win32 is None:
100 win32 = (sys.platform == 'win32')
100 win32 = (sys.platform == 'win32')
101 else:
101 else:
102 win32 = force_win32
102 win32 = force_win32
103 name = unquote_filename(name, win32=win32)
103 name = unquote_filename(name, win32=win32)
104 if not os.path.isfile(name) and not name.endswith('.py'):
104 if not os.path.isfile(name) and not name.endswith('.py'):
105 name += '.py'
105 name += '.py'
106 if os.path.isfile(name):
106 if os.path.isfile(name):
107 return name
107 return name
108 else:
108 else:
109 raise IOError,'File `%s` not found.' % name
109 raise IOError,'File `%s` not found.' % name
110
110
111
111
112 def filefind(filename, path_dirs=None):
112 def filefind(filename, path_dirs=None):
113 """Find a file by looking through a sequence of paths.
113 """Find a file by looking through a sequence of paths.
114
114
115 This iterates through a sequence of paths looking for a file and returns
115 This iterates through a sequence of paths looking for a file and returns
116 the full, absolute path of the first occurence of the file. If no set of
116 the full, absolute path of the first occurence of the file. If no set of
117 path dirs is given, the filename is tested as is, after running through
117 path dirs is given, the filename is tested as is, after running through
118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
119
119
120 filefind('myfile.txt')
120 filefind('myfile.txt')
121
121
122 will find the file in the current working dir, but::
122 will find the file in the current working dir, but::
123
123
124 filefind('~/myfile.txt')
124 filefind('~/myfile.txt')
125
125
126 Will find the file in the users home directory. This function does not
126 Will find the file in the users home directory. This function does not
127 automatically try any paths, such as the cwd or the user's home directory.
127 automatically try any paths, such as the cwd or the user's home directory.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 filename : str
131 filename : str
132 The filename to look for.
132 The filename to look for.
133 path_dirs : str, None or sequence of str
133 path_dirs : str, None or sequence of str
134 The sequence of paths to look for the file in. If None, the filename
134 The sequence of paths to look for the file in. If None, the filename
135 need to be absolute or be in the cwd. If a string, the string is
135 need to be absolute or be in the cwd. If a string, the string is
136 put into a sequence and the searched. If a sequence, walk through
136 put into a sequence and the searched. If a sequence, walk through
137 each element and join with ``filename``, calling :func:`expandvars`
137 each element and join with ``filename``, calling :func:`expandvars`
138 and :func:`expanduser` before testing for existence.
138 and :func:`expanduser` before testing for existence.
139
139
140 Returns
140 Returns
141 -------
141 -------
142 Raises :exc:`IOError` or returns absolute path to file.
142 Raises :exc:`IOError` or returns absolute path to file.
143 """
143 """
144
144
145 # If paths are quoted, abspath gets confused, strip them...
145 # If paths are quoted, abspath gets confused, strip them...
146 filename = filename.strip('"').strip("'")
146 filename = filename.strip('"').strip("'")
147 # If the input is an absolute path, just check it exists
147 # If the input is an absolute path, just check it exists
148 if os.path.isabs(filename) and os.path.isfile(filename):
148 if os.path.isabs(filename) and os.path.isfile(filename):
149 return filename
149 return filename
150
150
151 if path_dirs is None:
151 if path_dirs is None:
152 path_dirs = ("",)
152 path_dirs = ("",)
153 elif isinstance(path_dirs, basestring):
153 elif isinstance(path_dirs, basestring):
154 path_dirs = (path_dirs,)
154 path_dirs = (path_dirs,)
155
155
156 for path in path_dirs:
156 for path in path_dirs:
157 if path == '.': path = os.getcwdu()
157 if path == '.': path = os.getcwdu()
158 testname = expand_path(os.path.join(path, filename))
158 testname = expand_path(os.path.join(path, filename))
159 if os.path.isfile(testname):
159 if os.path.isfile(testname):
160 return os.path.abspath(testname)
160 return os.path.abspath(testname)
161
161
162 raise IOError("File %r does not exist in any of the search paths: %r" %
162 raise IOError("File %r does not exist in any of the search paths: %r" %
163 (filename, path_dirs) )
163 (filename, path_dirs) )
164
164
165
165
166 class HomeDirError(Exception):
166 class HomeDirError(Exception):
167 pass
167 pass
168
168
169
169
170 def get_home_dir():
170 def get_home_dir():
171 """Return the closest possible equivalent to a 'home' directory.
171 """Return the closest possible equivalent to a 'home' directory.
172
172
173 * On POSIX, we try $HOME.
173 * On POSIX, we try $HOME.
174 * On Windows we try:
174 * On Windows we try:
175 - %HOMESHARE%
175 - %HOMESHARE%
176 - %HOMEDRIVE\%HOMEPATH%
176 - %HOMEDRIVE\%HOMEPATH%
177 - %USERPROFILE%
177 - %USERPROFILE%
178 - Registry hack for My Documents
178 - Registry hack for My Documents
179 - %HOME%: rare, but some people with unix-like setups may have defined it
179 - %HOME%: rare, but some people with unix-like setups may have defined it
180 * On Dos C:\
180 * On Dos C:\
181
181
182 Currently only Posix and NT are implemented, a HomeDirError exception is
182 Currently only Posix and NT are implemented, a HomeDirError exception is
183 raised for all other OSes.
183 raised for all other OSes.
184 """
184 """
185
185
186 env = os.environ
186 env = os.environ
187
187
188 # first, check py2exe distribution root directory for _ipython.
188 # first, check py2exe distribution root directory for _ipython.
189 # This overrides all. Normally does not exist.
189 # This overrides all. Normally does not exist.
190
190
191 if hasattr(sys, "frozen"): #Is frozen by py2exe
191 if hasattr(sys, "frozen"): #Is frozen by py2exe
192 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
192 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
193 root, rest = IPython.__file__.lower().split('library.zip')
193 root, rest = IPython.__file__.lower().split('library.zip')
194 else:
194 else:
195 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
195 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
196 root=os.path.abspath(root).rstrip('\\')
196 root=os.path.abspath(root).rstrip('\\')
197 if _writable_dir(os.path.join(root, '_ipython')):
197 if _writable_dir(os.path.join(root, '_ipython')):
198 os.environ["IPYKITROOT"] = root
198 os.environ["IPYKITROOT"] = root
199 return py3compat.cast_unicode(root, fs_encoding)
199 return py3compat.cast_unicode(root, fs_encoding)
200
200
201 if os.name == 'posix':
201 if os.name == 'posix':
202 # Linux, Unix, AIX, OS X
202 # Linux, Unix, AIX, OS X
203 try:
203 try:
204 homedir = env['HOME']
204 homedir = env['HOME']
205 except KeyError:
205 except KeyError:
206 # Last-ditch attempt at finding a suitable $HOME, on systems where
206 # Last-ditch attempt at finding a suitable $HOME, on systems where
207 # it may not be defined in the environment but the system shell
207 # it may not be defined in the environment but the system shell
208 # still knows it - reported once as:
208 # still knows it - reported once as:
209 # https://github.com/ipython/ipython/issues/154
209 # https://github.com/ipython/ipython/issues/154
210 from subprocess import Popen, PIPE
210 from subprocess import Popen, PIPE
211 homedir = Popen('echo $HOME', shell=True,
211 homedir = Popen('echo $HOME', shell=True,
212 stdout=PIPE).communicate()[0].strip()
212 stdout=PIPE).communicate()[0].strip()
213 if homedir:
213 if homedir:
214 return py3compat.cast_unicode(homedir, fs_encoding)
214 return py3compat.cast_unicode(homedir, fs_encoding)
215 else:
215 else:
216 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
216 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
217 else:
217 else:
218 return py3compat.cast_unicode(homedir, fs_encoding)
218 return py3compat.cast_unicode(homedir, fs_encoding)
219 elif os.name == 'nt':
219 elif os.name == 'nt':
220 # Now for win9x, XP, Vista, 7?
220 # Now for win9x, XP, Vista, 7?
221 # For some strange reason all of these return 'nt' for os.name.
221 # For some strange reason all of these return 'nt' for os.name.
222 # First look for a network home directory. This will return the UNC
222 # First look for a network home directory. This will return the UNC
223 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
223 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
224 # is needed when running IPython on cluster where all paths have to
224 # is needed when running IPython on cluster where all paths have to
225 # be UNC.
225 # be UNC.
226 try:
226 try:
227 homedir = env['HOMESHARE']
227 homedir = env['HOMESHARE']
228 except KeyError:
228 except KeyError:
229 pass
229 pass
230 else:
230 else:
231 if _writable_dir(homedir):
231 if _writable_dir(homedir):
232 return py3compat.cast_unicode(homedir, fs_encoding)
232 return py3compat.cast_unicode(homedir, fs_encoding)
233
233
234 # Now look for a local home directory
234 # Now look for a local home directory
235 try:
235 try:
236 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
236 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
237 except KeyError:
237 except KeyError:
238 pass
238 pass
239 else:
239 else:
240 if _writable_dir(homedir):
240 if _writable_dir(homedir):
241 return py3compat.cast_unicode(homedir, fs_encoding)
241 return py3compat.cast_unicode(homedir, fs_encoding)
242
242
243 # Now the users profile directory
243 # Now the users profile directory
244 try:
244 try:
245 homedir = os.path.join(env['USERPROFILE'])
245 homedir = os.path.join(env['USERPROFILE'])
246 except KeyError:
246 except KeyError:
247 pass
247 pass
248 else:
248 else:
249 if _writable_dir(homedir):
249 if _writable_dir(homedir):
250 return py3compat.cast_unicode(homedir, fs_encoding)
250 return py3compat.cast_unicode(homedir, fs_encoding)
251
251
252 # Use the registry to get the 'My Documents' folder.
252 # Use the registry to get the 'My Documents' folder.
253 try:
253 try:
254 import _winreg as wreg
254 import _winreg as wreg
255 key = wreg.OpenKey(
255 key = wreg.OpenKey(
256 wreg.HKEY_CURRENT_USER,
256 wreg.HKEY_CURRENT_USER,
257 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
257 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
258 )
258 )
259 homedir = wreg.QueryValueEx(key,'Personal')[0]
259 homedir = wreg.QueryValueEx(key,'Personal')[0]
260 key.Close()
260 key.Close()
261 except:
261 except:
262 pass
262 pass
263 else:
263 else:
264 if _writable_dir(homedir):
264 if _writable_dir(homedir):
265 return py3compat.cast_unicode(homedir, fs_encoding)
265 return py3compat.cast_unicode(homedir, fs_encoding)
266
266
267 # A user with a lot of unix tools in win32 may have defined $HOME.
267 # A user with a lot of unix tools in win32 may have defined $HOME.
268 # Try this as a last ditch option.
268 # Try this as a last ditch option.
269 try:
269 try:
270 homedir = env['HOME']
270 homedir = env['HOME']
271 except KeyError:
271 except KeyError:
272 pass
272 pass
273 else:
273 else:
274 if _writable_dir(homedir):
274 if _writable_dir(homedir):
275 return py3compat.cast_unicode(homedir, fs_encoding)
275 return py3compat.cast_unicode(homedir, fs_encoding)
276
276
277 # If all else fails, raise HomeDirError
277 # If all else fails, raise HomeDirError
278 raise HomeDirError('No valid home directory could be found')
278 raise HomeDirError('No valid home directory could be found')
279 elif os.name == 'dos':
279 elif os.name == 'dos':
280 # Desperate, may do absurd things in classic MacOS. May work under DOS.
280 # Desperate, may do absurd things in classic MacOS. May work under DOS.
281 return u'C:\\'
281 return u'C:\\'
282 else:
282 else:
283 raise HomeDirError('No valid home directory could be found for your OS')
283 raise HomeDirError('No valid home directory could be found for your OS')
284
284
285 def get_xdg_dir():
285 def get_xdg_dir():
286 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
286 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
287
287
288 This is only for posix (Linux,Unix,OS X, etc) systems.
288 This is only for posix (Linux,Unix,OS X, etc) systems.
289 """
289 """
290
290
291 env = os.environ
291 env = os.environ
292
292
293 if os.name == 'posix':
293 if os.name == 'posix':
294 # Linux, Unix, AIX, OS X
294 # Linux, Unix, AIX, OS X
295 # use ~/.config if not set OR empty
295 # use ~/.config if not set OR empty
296 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
296 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
297 if xdg and _writable_dir(xdg):
297 if xdg and _writable_dir(xdg):
298 return py3compat.cast_unicode(xdg, fs_encoding)
298 return py3compat.cast_unicode(xdg, fs_encoding)
299
299
300 return None
300 return None
301
301
302
302
303 def get_ipython_dir():
303 def get_ipython_dir():
304 """Get the IPython directory for this platform and user.
304 """Get the IPython directory for this platform and user.
305
305
306 This uses the logic in `get_home_dir` to find the home directory
306 This uses the logic in `get_home_dir` to find the home directory
307 and then adds .ipython to the end of the path.
307 and then adds .ipython to the end of the path.
308 """
308 """
309
309
310 env = os.environ
310 env = os.environ
311 pjoin = os.path.join
311 pjoin = os.path.join
312
312
313
313
314 ipdir_def = '.ipython'
314 ipdir_def = '.ipython'
315 xdg_def = 'ipython'
315 xdg_def = 'ipython'
316
316
317 home_dir = get_home_dir()
317 home_dir = get_home_dir()
318 xdg_dir = get_xdg_dir()
318 xdg_dir = get_xdg_dir()
319 # import pdb; pdb.set_trace() # dbg
319 # import pdb; pdb.set_trace() # dbg
320 ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
320 ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
321 if ipdir is None:
321 if ipdir is None:
322 # not set explicitly, use XDG_CONFIG_HOME or HOME
322 # not set explicitly, use XDG_CONFIG_HOME or HOME
323 home_ipdir = pjoin(home_dir, ipdir_def)
323 home_ipdir = pjoin(home_dir, ipdir_def)
324 if xdg_dir:
324 if xdg_dir:
325 # use XDG, as long as the user isn't already
325 # use XDG, as long as the user isn't already
326 # using $HOME/.ipython and *not* XDG/ipython
326 # using $HOME/.ipython and *not* XDG/ipython
327
327
328 xdg_ipdir = pjoin(xdg_dir, xdg_def)
328 xdg_ipdir = pjoin(xdg_dir, xdg_def)
329
329
330 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
330 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
331 ipdir = xdg_ipdir
331 ipdir = xdg_ipdir
332
332
333 if ipdir is None:
333 if ipdir is None:
334 # not using XDG
334 # not using XDG
335 ipdir = home_ipdir
335 ipdir = home_ipdir
336
336
337 ipdir = os.path.normpath(os.path.expanduser(ipdir))
337 ipdir = os.path.normpath(os.path.expanduser(ipdir))
338
338
339 if os.path.exists(ipdir) and not _writable_dir(ipdir):
339 if os.path.exists(ipdir) and not _writable_dir(ipdir):
340 # ipdir exists, but is not writable
340 # ipdir exists, but is not writable
341 warn.warn("IPython dir '%s' is not a writable location,"
341 warn.warn("IPython dir '%s' is not a writable location,"
342 " using a temp directory."%ipdir)
342 " using a temp directory."%ipdir)
343 ipdir = tempfile.mkdtemp()
343 ipdir = tempfile.mkdtemp()
344 elif not os.path.exists(ipdir):
344 elif not os.path.exists(ipdir):
345 parent = ipdir.rsplit(os.path.sep, 1)[0]
345 parent = ipdir.rsplit(os.path.sep, 1)[0]
346 if not _writable_dir(parent):
346 if not _writable_dir(parent):
347 # ipdir does not exist and parent isn't writable
347 # ipdir does not exist and parent isn't writable
348 warn.warn("IPython parent '%s' is not a writable location,"
348 warn.warn("IPython parent '%s' is not a writable location,"
349 " using a temp directory."%parent)
349 " using a temp directory."%parent)
350 ipdir = tempfile.mkdtemp()
350 ipdir = tempfile.mkdtemp()
351
351
352 return py3compat.cast_unicode(ipdir, fs_encoding)
352 return py3compat.cast_unicode(ipdir, fs_encoding)
353
353
354
354
355 def get_ipython_package_dir():
355 def get_ipython_package_dir():
356 """Get the base directory where IPython itself is installed."""
356 """Get the base directory where IPython itself is installed."""
357 ipdir = os.path.dirname(IPython.__file__)
357 ipdir = os.path.dirname(IPython.__file__)
358 return py3compat.cast_unicode(ipdir, fs_encoding)
358 return py3compat.cast_unicode(ipdir, fs_encoding)
359
359
360
360
361 def get_ipython_module_path(module_str):
361 def get_ipython_module_path(module_str):
362 """Find the path to an IPython module in this version of IPython.
362 """Find the path to an IPython module in this version of IPython.
363
363
364 This will always find the version of the module that is in this importable
364 This will always find the version of the module that is in this importable
365 IPython package. This will always return the path to the ``.py``
365 IPython package. This will always return the path to the ``.py``
366 version of the module.
366 version of the module.
367 """
367 """
368 if module_str == 'IPython':
368 if module_str == 'IPython':
369 return os.path.join(get_ipython_package_dir(), '__init__.py')
369 return os.path.join(get_ipython_package_dir(), '__init__.py')
370 mod = import_item(module_str)
370 mod = import_item(module_str)
371 the_path = mod.__file__.replace('.pyc', '.py')
371 the_path = mod.__file__.replace('.pyc', '.py')
372 the_path = the_path.replace('.pyo', '.py')
372 the_path = the_path.replace('.pyo', '.py')
373 return py3compat.cast_unicode(the_path, fs_encoding)
373 return py3compat.cast_unicode(the_path, fs_encoding)
374
374
375 def locate_profile(profile='default'):
376 """Find the path to the folder associated with a given profile.
377
378 I.e. find $IPYTHON_DIR/profile_whatever.
379 """
380 from IPython.core.profiledir import ProfileDir, ProfileDirError
381 try:
382 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
383 except ProfileDirError:
384 # IOError makes more sense when people are expecting a path
385 raise IOError("Couldn't find profile %r" % profile)
386 return pd.location
375
387
376 def expand_path(s):
388 def expand_path(s):
377 """Expand $VARS and ~names in a string, like a shell
389 """Expand $VARS and ~names in a string, like a shell
378
390
379 :Examples:
391 :Examples:
380
392
381 In [2]: os.environ['FOO']='test'
393 In [2]: os.environ['FOO']='test'
382
394
383 In [3]: expand_path('variable FOO is $FOO')
395 In [3]: expand_path('variable FOO is $FOO')
384 Out[3]: 'variable FOO is test'
396 Out[3]: 'variable FOO is test'
385 """
397 """
386 # This is a pretty subtle hack. When expand user is given a UNC path
398 # This is a pretty subtle hack. When expand user is given a UNC path
387 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
399 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
388 # the $ to get (\\server\share\%username%). I think it considered $
400 # the $ to get (\\server\share\%username%). I think it considered $
389 # alone an empty var. But, we need the $ to remains there (it indicates
401 # alone an empty var. But, we need the $ to remains there (it indicates
390 # a hidden share).
402 # a hidden share).
391 if os.name=='nt':
403 if os.name=='nt':
392 s = s.replace('$\\', 'IPYTHON_TEMP')
404 s = s.replace('$\\', 'IPYTHON_TEMP')
393 s = os.path.expandvars(os.path.expanduser(s))
405 s = os.path.expandvars(os.path.expanduser(s))
394 if os.name=='nt':
406 if os.name=='nt':
395 s = s.replace('IPYTHON_TEMP', '$\\')
407 s = s.replace('IPYTHON_TEMP', '$\\')
396 return s
408 return s
397
409
398
410
399 def target_outdated(target,deps):
411 def target_outdated(target,deps):
400 """Determine whether a target is out of date.
412 """Determine whether a target is out of date.
401
413
402 target_outdated(target,deps) -> 1/0
414 target_outdated(target,deps) -> 1/0
403
415
404 deps: list of filenames which MUST exist.
416 deps: list of filenames which MUST exist.
405 target: single filename which may or may not exist.
417 target: single filename which may or may not exist.
406
418
407 If target doesn't exist or is older than any file listed in deps, return
419 If target doesn't exist or is older than any file listed in deps, return
408 true, otherwise return false.
420 true, otherwise return false.
409 """
421 """
410 try:
422 try:
411 target_time = os.path.getmtime(target)
423 target_time = os.path.getmtime(target)
412 except os.error:
424 except os.error:
413 return 1
425 return 1
414 for dep in deps:
426 for dep in deps:
415 dep_time = os.path.getmtime(dep)
427 dep_time = os.path.getmtime(dep)
416 if dep_time > target_time:
428 if dep_time > target_time:
417 #print "For target",target,"Dep failed:",dep # dbg
429 #print "For target",target,"Dep failed:",dep # dbg
418 #print "times (dep,tar):",dep_time,target_time # dbg
430 #print "times (dep,tar):",dep_time,target_time # dbg
419 return 1
431 return 1
420 return 0
432 return 0
421
433
422
434
423 def target_update(target,deps,cmd):
435 def target_update(target,deps,cmd):
424 """Update a target with a given command given a list of dependencies.
436 """Update a target with a given command given a list of dependencies.
425
437
426 target_update(target,deps,cmd) -> runs cmd if target is outdated.
438 target_update(target,deps,cmd) -> runs cmd if target is outdated.
427
439
428 This is just a wrapper around target_outdated() which calls the given
440 This is just a wrapper around target_outdated() which calls the given
429 command if target is outdated."""
441 command if target is outdated."""
430
442
431 if target_outdated(target,deps):
443 if target_outdated(target,deps):
432 system(cmd)
444 system(cmd)
433
445
434 def filehash(path):
446 def filehash(path):
435 """Make an MD5 hash of a file, ignoring any differences in line
447 """Make an MD5 hash of a file, ignoring any differences in line
436 ending characters."""
448 ending characters."""
437 with open(path, "rU") as f:
449 with open(path, "rU") as f:
438 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
450 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
439
451
440 # If the config is unmodified from the default, we'll just delete it.
452 # If the config is unmodified from the default, we'll just delete it.
441 # These are consistent for 0.10.x, thankfully. We're not going to worry about
453 # These are consistent for 0.10.x, thankfully. We're not going to worry about
442 # older versions.
454 # older versions.
443 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
455 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
444 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
456 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
445
457
446 def check_for_old_config(ipython_dir=None):
458 def check_for_old_config(ipython_dir=None):
447 """Check for old config files, and present a warning if they exist.
459 """Check for old config files, and present a warning if they exist.
448
460
449 A link to the docs of the new config is included in the message.
461 A link to the docs of the new config is included in the message.
450
462
451 This should mitigate confusion with the transition to the new
463 This should mitigate confusion with the transition to the new
452 config system in 0.11.
464 config system in 0.11.
453 """
465 """
454 if ipython_dir is None:
466 if ipython_dir is None:
455 ipython_dir = get_ipython_dir()
467 ipython_dir = get_ipython_dir()
456
468
457 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
469 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
458 warned = False
470 warned = False
459 for cfg in old_configs:
471 for cfg in old_configs:
460 f = os.path.join(ipython_dir, cfg)
472 f = os.path.join(ipython_dir, cfg)
461 if os.path.exists(f):
473 if os.path.exists(f):
462 if filehash(f) == old_config_md5.get(cfg, ''):
474 if filehash(f) == old_config_md5.get(cfg, ''):
463 os.unlink(f)
475 os.unlink(f)
464 else:
476 else:
465 warn.warn("Found old IPython config file %r (modified by user)"%f)
477 warn.warn("Found old IPython config file %r (modified by user)"%f)
466 warned = True
478 warned = True
467
479
468 if warned:
480 if warned:
469 warn.info("""
481 warn.info("""
470 The IPython configuration system has changed as of 0.11, and these files will
482 The IPython configuration system has changed as of 0.11, and these files will
471 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
483 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
472 of the new config system.
484 of the new config system.
473 To start configuring IPython, do `ipython profile create`, and edit
485 To start configuring IPython, do `ipython profile create`, and edit
474 `ipython_config.py` in <ipython_dir>/profile_default.
486 `ipython_config.py` in <ipython_dir>/profile_default.
475 If you need to leave the old config files in place for an older version of
487 If you need to leave the old config files in place for an older version of
476 IPython and want to suppress this warning message, set
488 IPython and want to suppress this warning message, set
477 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
489 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
478
490
General Comments 0
You need to be logged in to leave comments. Login now