Skip to content
This repository

History access #824

Merged
merged 7 commits into from over 2 years ago

3 participants

Thomas Kluyver Fernando Perez Min RK
Thomas Kluyver
Collaborator

This separates out an HistoryAccessor class, which can be used to read the history db without initialising an IPython shell. HistoryManager becomes a subclass of that, adding in the methods to write to the database.

Fernando Perez
Owner

Hey Thomas, it looks like conflicts slipped in from recent merges. Could you rebase before we can have a look? Thx!

Thomas Kluyver
Collaborator

Done, it was only one small conflict.

IPython/core/history.py
((15 lines not shown))
46  
-    # A list of directories visited during session
47  
-    dir_hist = List()
48  
-    def _dir_hist_default(self):
49  
-        try:
50  
-            return [os.getcwdu()]
51  
-        except OSError:
52  
-            return []
53  
-
54  
-    # A dict of output history, keyed with ints from the shell's
55  
-    # execution count.
56  
-    output_hist = Dict()
57  
-    # The text/plain repr of outputs.
58  
-    output_hist_reprs = Dict()
59  
-
  35
+class HistoryAccessor(Configurable):
  36
+    """Access the history database without adding to it. For use by standalone
1
Fernando Perez Owner
fperez added a note September 30, 2011

Let's try to keep, here and elsewhere, to the format for docstrings (just like git commit messages) of 'one line summary, blank line, more verbose description). Tooltips that use the one line summary look bad if it's broken up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Fernando Perez
Owner

Otherwise looks good. It seems to be mostly refactoring, which means it should be pretty safe. But since I see there's a new method (for range), I'd like to see at least a test or two for that guy in isolation. The better we can make our test coverage...

Thomas Kluyver
Collaborator

OK, I've tweaked that docstring. I don't think I've added any really new methods - HistoryAccessor has a get_range method which requires a positive session number specified. HistoryManager overrides that with a version which has a default value for session (i.e. the current one), and allows negative numbers to count back from that.

Fernando Perez
Owner

No, what I meant is that now there's a bit of logic that's nicely isolated in the private _get_range_session. I saw that method as a good candidate to add a small test or two that would improve our coverage.

I hope soon we'll start turning on test coverage reports in the test suite, so we can begin tracking our progress on that front. In the meantime, every little bit we can do will help. What do you think?

Thomas Kluyver
Collaborator

Most of it should be indirectly covered by this call and this call, but I'll add some more specific tests for it.

Thomas Kluyver
Collaborator

Added some tests.

Min RK
Owner

Is this ready for merge? It sounds like review has been covered, assuming tests pass.

Thomas Kluyver
Collaborator

As far as I know, it's ready to go.

Min RK
Owner

Okay, then I say go for it. I think writing some good examples for turning sessions into scripts etc. with the new Accessor would be great, since it's fairly easy, but not immediately obvious.

Thomas Kluyver
Collaborator

Actually, just thinking about it, I'd like to add a slightly nicer interface to load history for a particular profile. Do we have a function that will get the folder (as in, $IPYTHONDIR/profile_whatever) for a given profile name?

Min RK
Owner

We have ProfileDir objects for managing/creating/locating profile directories, so you can do:

from IPython.core.profiledir import ProfileDir
pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), 'foo')
path = pd.location

Perhaps adding this to utils.path would be useful:

def locate_profile(profile='default'):
    from IPython.core.profiledir import ProfileDir, ProfileDirError
    try:
        pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
    except ProfileDirError:
        # IOError makes more sense when people are expecting a path
        raise IOError("Couldn't find profile %r" % profile)
    return pd.location
Thomas Kluyver
Collaborator

Thanks Min, that's just the ticket.

Thomas Kluyver takluyver merged commit a355a9f into from October 14, 2011
Thomas Kluyver takluyver closed this October 14, 2011
Thomas Kluyver
Collaborator

OK, I've made the API improvement I wanted, added an example script (docs/examples/core/ipython-extract-history.py), merged and checked the tests. Hopefully post-0.12 someone will be inspired to build a nice history viewer/dumper.

Min RK
Owner

Thanks!

Yes, that would be great. All of the %log, etc. tools should probably use this as well.

Thomas Kluyver
Collaborator

Magics like %hist, %macro, %save and so on already do. The %log* machinery writes cells directly to a text file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
366  IPython/core/history.py
@@ -25,6 +25,7 @@
25 25
 
26 26
 from IPython.testing.skipdoctest import skip_doctest
27 27
 from IPython.utils import io
  28
+from IPython.utils.path import locate_profile
28 29
 from IPython.utils.traitlets import Bool, Dict, Instance, Int, CInt, List, Unicode
29 30
 from IPython.utils.warn import warn
30 31
 
@@ -32,79 +33,39 @@
32 33
 # Classes and functions
33 34
 #-----------------------------------------------------------------------------
34 35
 
35  
-class HistoryManager(Configurable):
36  
-    """A class to organize all history-related functionality in one place.
37  
-    """
38  
-    # Public interface
39  
-
40  
-    # An instance of the IPython shell we are attached to
41  
-    shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
42  
-    # Lists to hold processed and raw history. These start with a blank entry
43  
-    # so that we can index them starting from 1
44  
-    input_hist_parsed = List([""])
45  
-    input_hist_raw = List([""])
46  
-    # A list of directories visited during session
47  
-    dir_hist = List()
48  
-    def _dir_hist_default(self):
49  
-        try:
50  
-            return [os.getcwdu()]
51  
-        except OSError:
52  
-            return []
53  
-
54  
-    # A dict of output history, keyed with ints from the shell's
55  
-    # execution count.
56  
-    output_hist = Dict()
57  
-    # The text/plain repr of outputs.
58  
-    output_hist_reprs = Dict()
59  
-
  36
+class HistoryAccessor(Configurable):
  37
+    """Access the history database without adding to it.
  38
+    
  39
+    This is intended for use by standalone history tools. IPython shells use
  40
+    HistoryManager, below, which is a subclass of this."""
60 41
     # String holding the path to the history file
61 42
     hist_file = Unicode(config=True)
62 43
 
63 44
     # The SQLite database
64 45
     db = Instance(sqlite3.Connection)
65  
-    # The number of the current session in the history database
66  
-    session_number = CInt()
67  
-    # Should we log output to the database? (default no)
68  
-    db_log_output = Bool(False, config=True)
69  
-    # Write to database every x commands (higher values save disk access & power)
70  
-    #  Values of 1 or less effectively disable caching.
71  
-    db_cache_size = Int(0, config=True)
72  
-    # The input and output caches
73  
-    db_input_cache = List()
74  
-    db_output_cache = List()
75  
-
76  
-    # History saving in separate thread
77  
-    save_thread = Instance('IPython.core.history.HistorySavingThread')
78  
-    try:               # Event is a function returning an instance of _Event...
79  
-        save_flag = Instance(threading._Event)
80  
-    except AttributeError:         # ...until Python 3.3, when it's a class.
81  
-        save_flag = Instance(threading.Event)
82  
-
83  
-    # Private interface
84  
-    # Variables used to store the three last inputs from the user.  On each new
85  
-    # history update, we populate the user's namespace with these, shifted as
86  
-    # necessary.
87  
-    _i00 = Unicode(u'')
88  
-    _i = Unicode(u'')
89  
-    _ii = Unicode(u'')
90  
-    _iii = Unicode(u'')
91  
-
92  
-    # A regex matching all forms of the exit command, so that we don't store
93  
-    # them in the history (it's annoying to rewind the first entry and land on
94  
-    # an exit call).
95  
-    _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
96  
-
97  
-    def __init__(self, shell, config=None, **traits):
98  
-        """Create a new history manager associated with a shell instance.
  46
+    
  47
+    def __init__(self, profile='default', hist_file=u'', shell=None, config=None, **traits):
  48
+        """Create a new history accessor.
  49
+        
  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.
99 61
         """
100 62
         # We need a pointer back to the shell for various tasks.
101  
-        super(HistoryManager, self).__init__(shell=shell, config=config,
102  
-            **traits)
  63
+        super(HistoryAccessor, self).__init__(shell=shell, config=config,
  64
+                                              hist_file=hist_file, **traits)
103 65
 
104 66
         if self.hist_file == u'':
105 67
             # No one has set the hist_file, yet.
106  
-            histfname = 'history'
107  
-            self.hist_file = os.path.join(shell.profile_dir.location, histfname + '.sqlite')
  68
+            self.hist_file = self._get_hist_file_name(profile)
108 69
 
109 70
         try:
110 71
             self.init_db()
@@ -119,16 +80,20 @@ def __init__(self, shell, config=None, **traits):
119 80
             else:
120 81
                 # The hist_file is probably :memory: or something else.
121 82
                 raise
122  
-
123  
-        self.save_flag = threading.Event()
124  
-        self.db_input_cache_lock = threading.Lock()
125  
-        self.db_output_cache_lock = threading.Lock()
126  
-        self.save_thread = HistorySavingThread(self)
127  
-        self.save_thread.start()
128  
-
129  
-        self.new_session()
130  
-
131  
-
  83
+    
  84
+    def _get_hist_file_name(self, profile='default'):
  85
+        """Find the history file for the given profile name.
  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')
  96
+    
132 97
     def init_db(self):
133 98
         """Connect to the database, and create tables if necessary."""
134 99
         # use detect_types so that timestamps return datetime objects
@@ -146,48 +111,10 @@ def init_db(self):
146 111
                         PRIMARY KEY (session, line))""")
147 112
         self.db.commit()
148 113
 
149  
-    def new_session(self, conn=None):
150  
-        """Get a new session number."""
151  
-        if conn is None:
152  
-            conn = self.db
153  
-
154  
-        with conn:
155  
-            # N.B. 'insert into' here is lower case because of a bug in the
156  
-            # sqlite3 module that affects the Turkish locale. This should be
157  
-            # fixed for Python 2.7.3 and 3.2.3, as well as 3.3 onwards.
158  
-            # http://bugs.python.org/issue13099
159  
-            cur = conn.execute("""insert into sessions VALUES (NULL, ?, NULL,
160  
-                            NULL, "") """, (datetime.datetime.now(),))
161  
-            self.session_number = cur.lastrowid
162  
-
163  
-    def end_session(self):
164  
-        """Close the database session, filling in the end time and line count."""
165  
-        self.writeout_cache()
166  
-        with self.db:
167  
-            self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
168  
-                            session==?""", (datetime.datetime.now(),
169  
-                            len(self.input_hist_parsed)-1, self.session_number))
170  
-        self.session_number = 0
171  
-
172  
-    def name_session(self, name):
173  
-        """Give the current session a name in the history database."""
174  
-        with self.db:
175  
-            self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
176  
-                            (name, self.session_number))
177  
-
178  
-    def reset(self, new_session=True):
179  
-        """Clear the session history, releasing all object references, and
180  
-        optionally open a new session."""
181  
-        self.output_hist.clear()
182  
-        # The directory history can't be completely empty
183  
-        self.dir_hist[:] = [os.getcwdu()]
184  
-
185  
-        if new_session:
186  
-            if self.session_number:
187  
-                self.end_session()
188  
-            self.input_hist_parsed[:] = [""]
189  
-            self.input_hist_raw[:] = [""]
190  
-            self.new_session()
  114
+    def writeout_cache(self):
  115
+        """Overridden by HistoryManager to dump the cache before certain
  116
+        database lookups."""
  117
+        pass
191 118
 
192 119
     ## -------------------------------
193 120
     ## Methods for retrieving history:
@@ -219,7 +146,6 @@ def _run_sql(self, sql, params, raw=True, output=False):
219 146
             return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
220 147
         return cur
221 148
 
222  
-
223 149
     def get_session_info(self, session=0):
224 150
         """get info about a session
225 151
 
@@ -246,7 +172,6 @@ def get_session_info(self, session=0):
246 172
         query = "SELECT * from sessions where session == ?"
247 173
         return self.db.execute(query, (session,)).fetchone()
248 174
 
249  
-
250 175
     def get_tail(self, n=10, raw=True, output=False, include_latest=False):
251 176
         """Get the last n lines from the history database.
252 177
 
@@ -298,35 +223,14 @@ def search(self, pattern="*", raw=True, search_raw=True,
298 223
         self.writeout_cache()
299 224
         return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
300 225
                                     raw=raw, output=output)
301  
-
302  
-    def _get_range_session(self, start=1, stop=None, raw=True, output=False):
303  
-        """Get input and output history from the current session. Called by
304  
-        get_range, and takes similar parameters."""
305  
-        input_hist = self.input_hist_raw if raw else self.input_hist_parsed
306  
-
307  
-        n = len(input_hist)
308  
-        if start < 0:
309  
-            start += n
310  
-        if not stop or (stop > n):
311  
-            stop = n
312  
-        elif stop < 0:
313  
-            stop += n
314  
-
315  
-        for i in range(start, stop):
316  
-            if output:
317  
-                line = (input_hist[i], self.output_hist_reprs.get(i))
318  
-            else:
319  
-                line = input_hist[i]
320  
-            yield (0, i, line)
321  
-
322  
-    def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
  226
+    
  227
+    def get_range(self, session, start=1, stop=None, raw=True,output=False):
323 228
         """Retrieve input by session.
324 229
 
325 230
         Parameters
326 231
         ----------
327 232
         session : int
328  
-            Session number to retrieve. The current session is 0, and negative
329  
-            numbers count back from current session, so -1 is previous session.
  233
+            Session number to retrieve.
330 234
         start : int
331 235
             First line to retrieve.
332 236
         stop : int
@@ -346,11 +250,6 @@ def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
346 250
         (session, line, input) if output is False, or
347 251
         (session, line, (input, output)) if output is True.
348 252
         """
349  
-        if session == 0 or session==self.session_number:   # Current session
350  
-            return self._get_range_session(start, stop, raw, output)
351  
-        if session < 0:
352  
-            session += self.session_number
353  
-
354 253
         if stop:
355 254
             lineclause = "line >= ? AND line < ?"
356 255
             params = (session, start, stop)
@@ -381,6 +280,181 @@ def get_range_by_str(self, rangestr, raw=True, output=False):
381 280
             for line in self.get_range(sess, s, e, raw=raw, output=output):
382 281
                 yield line
383 282
 
  283
+
  284
+class HistoryManager(HistoryAccessor):
  285
+    """A class to organize all history-related functionality in one place.
  286
+    """
  287
+    # Public interface
  288
+
  289
+    # An instance of the IPython shell we are attached to
  290
+    shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
  291
+    # Lists to hold processed and raw history. These start with a blank entry
  292
+    # so that we can index them starting from 1
  293
+    input_hist_parsed = List([""])
  294
+    input_hist_raw = List([""])
  295
+    # A list of directories visited during session
  296
+    dir_hist = List()
  297
+    def _dir_hist_default(self):
  298
+        try:
  299
+            return [os.getcwdu()]
  300
+        except OSError:
  301
+            return []
  302
+
  303
+    # A dict of output history, keyed with ints from the shell's
  304
+    # execution count.
  305
+    output_hist = Dict()
  306
+    # The text/plain repr of outputs.
  307
+    output_hist_reprs = Dict()
  308
+
  309
+    # The number of the current session in the history database
  310
+    session_number = CInt()
  311
+    # Should we log output to the database? (default no)
  312
+    db_log_output = Bool(False, config=True)
  313
+    # Write to database every x commands (higher values save disk access & power)
  314
+    #  Values of 1 or less effectively disable caching. 
  315
+    db_cache_size = Int(0, config=True)
  316
+    # The input and output caches
  317
+    db_input_cache = List()
  318
+    db_output_cache = List()
  319
+    
  320
+    # History saving in separate thread
  321
+    save_thread = Instance('IPython.core.history.HistorySavingThread')
  322
+    try:               # Event is a function returning an instance of _Event...
  323
+        save_flag = Instance(threading._Event)
  324
+    except AttributeError:         # ...until Python 3.3, when it's a class.
  325
+        save_flag = Instance(threading.Event)
  326
+    
  327
+    # Private interface
  328
+    # Variables used to store the three last inputs from the user.  On each new
  329
+    # history update, we populate the user's namespace with these, shifted as
  330
+    # necessary.
  331
+    _i00 = Unicode(u'')
  332
+    _i = Unicode(u'')
  333
+    _ii = Unicode(u'')
  334
+    _iii = Unicode(u'')
  335
+
  336
+    # A regex matching all forms of the exit command, so that we don't store
  337
+    # them in the history (it's annoying to rewind the first entry and land on
  338
+    # an exit call).
  339
+    _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
  340
+
  341
+    def __init__(self, shell=None, config=None, **traits):
  342
+        """Create a new history manager associated with a shell instance.
  343
+        """
  344
+        # We need a pointer back to the shell for various tasks.
  345
+        super(HistoryManager, self).__init__(shell=shell, config=config,
  346
+            **traits)
  347
+        self.save_flag = threading.Event()
  348
+        self.db_input_cache_lock = threading.Lock()
  349
+        self.db_output_cache_lock = threading.Lock()
  350
+        self.save_thread = HistorySavingThread(self)
  351
+        self.save_thread.start()
  352
+
  353
+        self.new_session()
  354
+    
  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."""
  360
+        profile_dir = self.shell.profile_dir.location
  361
+        return os.path.join(profile_dir, 'history.sqlite')
  362
+    
  363
+    def new_session(self, conn=None):
  364
+        """Get a new session number."""
  365
+        if conn is None:
  366
+            conn = self.db
  367
+        
  368
+        with conn:
  369
+            cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
  370
+                            NULL, "") """, (datetime.datetime.now(),))
  371
+            self.session_number = cur.lastrowid
  372
+            
  373
+    def end_session(self):
  374
+        """Close the database session, filling in the end time and line count."""
  375
+        self.writeout_cache()
  376
+        with self.db:
  377
+            self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
  378
+                            session==?""", (datetime.datetime.now(),
  379
+                            len(self.input_hist_parsed)-1, self.session_number))
  380
+        self.session_number = 0
  381
+                            
  382
+    def name_session(self, name):
  383
+        """Give the current session a name in the history database."""
  384
+        with self.db:
  385
+            self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
  386
+                            (name, self.session_number))
  387
+                            
  388
+    def reset(self, new_session=True):
  389
+        """Clear the session history, releasing all object references, and
  390
+        optionally open a new session."""
  391
+        self.output_hist.clear()
  392
+        # The directory history can't be completely empty
  393
+        self.dir_hist[:] = [os.getcwdu()]
  394
+        
  395
+        if new_session:
  396
+            if self.session_number:
  397
+                self.end_session()
  398
+            self.input_hist_parsed[:] = [""]
  399
+            self.input_hist_raw[:] = [""]
  400
+            self.new_session()
  401
+    
  402
+    # ------------------------------
  403
+    # Methods for retrieving history
  404
+    # ------------------------------
  405
+    def _get_range_session(self, start=1, stop=None, raw=True, output=False):
  406
+        """Get input and output history from the current session. Called by
  407
+        get_range, and takes similar parameters."""
  408
+        input_hist = self.input_hist_raw if raw else self.input_hist_parsed
  409
+            
  410
+        n = len(input_hist)
  411
+        if start < 0:
  412
+            start += n
  413
+        if not stop or (stop > n):
  414
+            stop = n
  415
+        elif stop < 0:
  416
+            stop += n
  417
+        
  418
+        for i in range(start, stop):
  419
+            if output:
  420
+                line = (input_hist[i], self.output_hist_reprs.get(i))
  421
+            else:
  422
+                line = input_hist[i]
  423
+            yield (0, i, line)
  424
+    
  425
+    def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
  426
+        """Retrieve input by session.
  427
+        
  428
+        Parameters
  429
+        ----------
  430
+        session : int
  431
+            Session number to retrieve. The current session is 0, and negative
  432
+            numbers count back from current session, so -1 is previous session.
  433
+        start : int
  434
+            First line to retrieve.
  435
+        stop : int
  436
+            End of line range (excluded from output itself). If None, retrieve
  437
+            to the end of the session.
  438
+        raw : bool
  439
+            If True, return untranslated input
  440
+        output : bool
  441
+            If True, attempt to include output. This will be 'real' Python
  442
+            objects for the current session, or text reprs from previous
  443
+            sessions if db_log_output was enabled at the time. Where no output
  444
+            is found, None is used.
  445
+            
  446
+        Returns
  447
+        -------
  448
+        An iterator over the desired lines. Each line is a 3-tuple, either
  449
+        (session, line, input) if output is False, or
  450
+        (session, line, (input, output)) if output is True.
  451
+        """
  452
+        if session <= 0:
  453
+            session += self.session_number
  454
+        if session==self.session_number:          # Current session
  455
+            return self._get_range_session(start, stop, raw, output)
  456
+        return super(HistoryManager, self).get_range(session, start, stop, raw, output)
  457
+
384 458
     ## ----------------------------
385 459
     ## Methods for storing history:
386 460
     ## ----------------------------
6  IPython/core/tests/test_history.py
@@ -38,6 +38,12 @@ def test_history():
38 38
             ip.history_manager.store_output(3)
39 39
 
40 40
             nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
  41
+            
  42
+            # Detailed tests for _get_range_session
  43
+            grs = ip.history_manager._get_range_session
  44
+            nt.assert_equal(list(grs(start=2,stop=-1)), zip([0], [2], hist[1:-1]))
  45
+            nt.assert_equal(list(grs(start=-2)), zip([0,0], [2,3], hist[-2:]))
  46
+            nt.assert_equal(list(grs(output=True)), zip([0,0,0], [1,2,3], zip(hist, [None,None,'spam'])))
41 47
 
42 48
             # Check whether specifying a range beyond the end of the current
43 49
             # session results in an error (gh-804)
12  IPython/utils/path.py
@@ -372,6 +372,18 @@ def get_ipython_module_path(module_str):
372 372
     the_path = the_path.replace('.pyo', '.py')
373 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 388
 def expand_path(s):
377 389
     """Expand $VARS and ~names in a string, like a shell
38  docs/examples/core/ipython-get-history.py
... ...
@@ -0,0 +1,38 @@
  1
+#!/usr/bin/env python
  2
+"""Extract a session from the IPython input history.
  3
+
  4
+Usage:
  5
+  ipython-get-history.py sessionnumber [outputfile]
  6
+
  7
+If outputfile is not given, the relevant history is written to stdout. If
  8
+outputfile has a .py extension, the translated history (without IPython's
  9
+special syntax) will be extracted.
  10
+
  11
+Example:
  12
+  ./ipython-get-history.py 57 record.ipy
  13
+
  14
+
  15
+This script is a simple demonstration of HistoryAccessor. It should be possible
  16
+to build much more flexible and powerful tools to browse and pull from the
  17
+history database.
  18
+"""
  19
+import sys
  20
+import codecs
  21
+
  22
+from IPython.core.history import HistoryAccessor
  23
+
  24
+session_number = int(sys.argv[1])
  25
+if len(sys.argv) > 2:
  26
+    dest = open(sys.argv[2], "w")
  27
+    raw = not sys.argv[2].endswith('.py')
  28
+else:
  29
+    dest = sys.stdout
  30
+    raw = True
  31
+dest.write("# coding: utf-8\n")
  32
+
  33
+# Profiles other than 'default' can be specified here with a profile= argument:
  34
+hist = HistoryAccessor()
  35
+
  36
+for session, lineno, cell in hist.get_range(session=session_number, raw=raw):
  37
+    # To use this in Python 3, remove the .encode() here:
  38
+    dest.write(cell.encode('utf-8') + '\n')
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.