Merge lp:~vlewis/boots/vdev into lp:boots

Proposed by Victoria Lewis
Status: Merged
Merged at revision: not available
Proposed branch: lp:~vlewis/boots/vdev
Merge into: lp:boots
Diff against target: 311 lines (+214/-3) (has conflicts)
5 files modified
src/boots/app/client_config.py (+14/-2)
src/boots/lib/console.py (+31/-1)
src/boots/lib/ui/components/helptopics.py (+137/-0)
src/boots/lib/ui/generic.py (+2/-0)
src/boots/lib/ui/plain.py (+30/-0)
Text conflict in src/boots/lib/console.py
Text conflict in src/boots/lib/ui/plain.py
To merge this branch: bzr merge lp:~vlewis/boots/vdev
Reviewer Review Type Date Requested Status
Max Goodhart Approve
David Rosenbaum Needs Fixing
Review via email: mp+18176@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Victoria Lewis (vlewis) wrote :

Here is my code. I need to add a sort.

lp:~vlewis/boots/vdev updated
23. By Victoria Lewis <email address hidden>

Add sort to helptopics.py

Revision history for this message
Max Goodhart (chromakode) wrote :

> Here is my code. I need to add a sort.

The code sorted(lines) does not sort the lines list in place. Instead, it will return an iterator that traverses the sorted list. Instead, use lines.sort().

The files help.py and helpinfo.py are no longer needed in this merge. Use "bzr rm --keep <file>" to remove them.

Finally, instead of:

leng = len(max(str.split(topic.see_also))) + 2

You can find the topic with the longest name using:

max_name_len = max((subtopic for subtopic in self.subtopics.itervalues), key=len)

-M

review: Needs Fixing
Revision history for this message
Victoria Lewis (vlewis) wrote :

Thanks.
Don't I still need to add some space to the end of the longest name?
Victoria

>>> Chromakode 01/28/10 8:10 PM >>>
Review: Needs Fixing
> Here is my code. I need to add a sort.

The code sorted(lines) does not sort the lines list in place. Instead, it will return an iterator that traverses the sorted list. Instead, use lines.sort().

The files help.py and helpinfo.py are no longer needed in this merge. Use "bzr rm --keep " to remove them.

Finally, instead of:

leng = len(max(str.split(topic.see_also))) + 2

You can find the topic with the longest name using:

max_name_len = max((subtopic for subtopic in self.subtopics.itervalues), key=len)

-M
--
https://code.launchpad.net/~vlewis/boots/vdev/+merge/18176
You are the owner of lp:~vlewis/boots/vdev.

Revision history for this message
David Rosenbaum (davidjrosenbaum) wrote :

In addition to the above comments (which I agree with) there are a couple of other issues:
First, the local function maxword that you added in the issubseq function I wrote is dead code and should be removed. Another problem is that the code does not use proper indentation which will cause the interpreter to crash. Lines 51-53 mix tabs and spaces and use indentation of width 8. This is incorrect in Python and the indentation width must be 4. Please use only spaces for indentation.

review: Needs Fixing
lp:~vlewis/boots/vdev updated
24. By Victoria Lewis <email address hidden>

I corrected errors in format_index.

25. By Victoria Lewis <email address hidden>

Implemented readline history

Revision history for this message
Max Goodhart (chromakode) wrote :

Merged.

A couple comments:

* The default config options disabled this feature! I've modified them so the user gets 100 lines of persistent history by default, saved at ~/.boots_history.

* Whenever possible, try to keep UI-specific code out of the Console. I moved the save/load calls to inside the Plain UI class, and created a general "unload" method which, when called by the quitting Console, calls save_history.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/boots/app/client_config.py'
--- src/boots/app/client_config.py 2010-01-22 05:58:25 +0000
+++ src/boots/app/client_config.py 2010-02-04 01:10:27 +0000
@@ -51,7 +51,9 @@
51 "port" : 9306,51 "port" : 9306,
52 "username" : os.getenv("USER"),52 "username" : os.getenv("USER"),
53 "password" : False,53 "password" : False,
54 "prompt" : "> "}54 "prompt" : "> ",
55 "history_length": 0,
56 "history_file": None}
55 self._dict = self._defaults.copy()57 self._dict = self._defaults.copy()
5658
57 # Use default rc location in info if no argument is passed in.59 # Use default rc location in info if no argument is passed in.
@@ -111,7 +113,17 @@
111 type = "string",113 type = "string",
112 dest = "password",114 dest = "password",
113 help = "Connect using password. If none is given, query for password")115 help = "Connect using password. If none is given, query for password")
114116 self._cli_parser.add_option("-F", "--historyfile",
117 action = "store",
118 type = "string",
119 dest = "history_file",
120 help = "Specify file to save history to")
121 self._cli_parser.add_option("-L", "--historylength",
122 action = "store",
123 type = "int",
124 dest = "history_length",
125 help = "Specify max history file length")
126
115 def __getitem__(self, key):127 def __getitem__(self, key):
116 return self._dict[key]128 return self._dict[key]
117129
118130
=== modified file 'src/boots/lib/console.py'
--- src/boots/lib/console.py 2010-02-01 20:46:55 +0000
+++ src/boots/lib/console.py 2010-02-04 01:10:27 +0000
@@ -30,6 +30,7 @@
3030
31from boots.api import api31from boots.api import api
32from boots.lib.ui.plain import PlainUI32from boots.lib.ui.plain import PlainUI
33<<<<<<< TREE
33from boots.lib.metacommands import metacommands34from boots.lib.metacommands import metacommands
34from boots.lib.lingos import lingo35from boots.lib.lingos import lingo
35from boots.lib.lingos.lisp import lisp36from boots.lib.lingos.lisp import lisp
@@ -44,10 +45,15 @@
44 return True45 return True
45 except TypeError:46 except TypeError:
46 return False47 return False
48=======
49import os
50import atexit
51>>>>>>> MERGE-SOURCE
4752
48class Console(object):53class Console(object):
49 def __init__(self, config):54 def __init__(self, config):
50 self.config = config55 self.config = config
56<<<<<<< TREE
51 # FIXME: Once metacommands are supported it should be possible to change the lingo at runtime using a metacommand.57 # FIXME: Once metacommands are supported it should be possible to change the lingo at runtime using a metacommand.
52 self.lingo = self.config['lingo']58 self.lingo = self.config['lingo']
53 self.servers = [api.Server(self.config["host"], self.config["port"],59 self.servers = [api.Server(self.config["host"], self.config["port"],
@@ -102,7 +108,15 @@
102 lingo.register('lisp', lisp.LispInterpreter(self))108 lingo.register('lisp', lisp.LispInterpreter(self))
103 lingo.register('python', python.PythonInterpreter(self))109 lingo.register('python', python.PythonInterpreter(self))
104 lingo.register('sql', sql.SQLInterpreter(self))110 lingo.register('sql', sql.SQLInterpreter(self))
111=======
112 self.server = api.Server(self.config["host"], self.config["port"],
113 {"database": self.config["database"]})
114 self.ui = PlainUI(self.config["prompt"], self.config["history_length"],
115 self.config["history_file"])
116 atexit.register(self.ui.save_history)
117>>>>>>> MERGE-SOURCE
105 118
119<<<<<<< TREE
106 for command in self.ui.get_input(input_complete = lingo.get(self.lingo).input_complete):120 for command in self.ui.get_input(input_complete = lingo.get(self.lingo).input_complete):
107 if not self.metacommands.execute(metacommands.parse(command)):121 if not self.metacommands.execute(metacommands.parse(command)):
108 result = self.run(command, self.lingo)122 result = self.run(command, self.lingo)
@@ -114,7 +128,23 @@
114 # Don't print None; a return value of None means there was no result.128 # Don't print None; a return value of None means there was no result.
115 elif result != None:129 elif result != None:
116 self.ui.present(result)130 self.ui.present(result)
117131=======
132
133 def run(self, command, language):
134 result = self.server.execute(command)
135 return result
136>>>>>>> MERGE-SOURCE
137
138<<<<<<< TREE
118 # Print a trailing newline.139 # Print a trailing newline.
119 self.ui.present('')140 self.ui.present('')
120 self.disconnect()141 self.disconnect()
142=======
143 def main(self):
144 self.ui.read_history()
145 self.server.connect()
146 for command in self.ui.get_input():
147 for row in self.run(command, "sql"):
148 self.ui.present(row)
149 self.server.disconnect()
150>>>>>>> MERGE-SOURCE
121151
=== removed file 'src/boots/lib/ui/components/help.py'
=== added file 'src/boots/lib/ui/components/helptopics.py'
--- src/boots/lib/ui/components/helptopics.py 1970-01-01 00:00:00 +0000
+++ src/boots/lib/ui/components/helptopics.py 2010-02-04 01:10:27 +0000
@@ -0,0 +1,137 @@
1# Utility function
2def issubseq(seq, seq2):
3 """Determines if the elements the sequence seq form a subsequence of the sequence seq2."""
4 if len(seq) == 0:
5 return True
6 else:
7 i = 0
8
9 while i < len(seq2) and seq[0] != seq2[i]:
10 i += 1
11
12 if i == len(seq2):
13 return False
14
15 return list(seq[1:]) == list(seq2[:i + 1:len(seq)])
16
17
18class Topic(object):
19 """A topic in the help system which may contain other topics."""
20 def __init__(self, name, title = None, description = None, short_description = None, see_also = None):
21 """Creates a new a help topic. The fields are as described above."""
22 self.subtopics = dict()
23 self.title = title
24 self.name = name
25 self.description = description
26 self.short_description = short_description
27 self.see_also = see_also
28
29 def format(self):
30 """Returns a string that represents this topic in human readable form as
31 described in detail above."""
32 text = "{0.title}\n\n{0.description}\n\nSee also: {0.see_also}".format(self)
33 return text
34
35 def format_index(self):
36 """Returns a string that lists the subtopics of this topic in human
37 readable form as described above."""
38 lines = list()
39
40 for name, topic in self.subtopics.iteritems():
41 max_name_len = max(len(subtopic.name) for subtopic in self.subtopics.itervalues())
42 subtext = "{0:{2}}--{1:30}".format(topic.name, topic.short_description, max_name_len +3)
43 lines.append(subtext)
44 lines.sort()
45 return "\n".join(lines)
46
47 # Queries:
48 #
49 # A query is used to refer to a topic in the help system. A query is either
50 # a string or a non-empty tuple of strings. Using a string is equivalent to
51 # using a tuple of length one containing that string. As an example, the
52 # tuple ('python', 'syntax', 'csv') refers to the csv subtopic in the syntax
53 # topic which is itself a subtopic of the python topic.
54
55 def _translate_query(self, query):
56 """Converts a query into a tuple. If query is not a valid query an
57 exception is raised."""
58 if isinstance(query, str):
59 return (query,)
60 elif isinstance(query, (tuple, list)):
61 assert len(query) != 0
62 for item in query:
63 assert isinstance(item, str)
64 return query
65 else:
66 raise TypeError('query object {0} is not a string or tuple of strings'.format(query))
67
68 def _ensure_key(self, key):
69 """Creates a new subtopic that key maps to if none exists."""
70 if key not in self.subtopics:
71 self.subtopics[key] = Topic(key)
72
73 def _walk(self, path = ()):
74 """Returns an iterable of all absolute paths."""
75 if len(self.subtopics) == 0:
76 yield path
77 else:
78 for subtopic in self.subtopics:
79 for path2 in subtopic._walk(path + self.name):
80 yield path2
81
82 # The intention is for these methods to be implemented recursively
83 # by calling these methods on topics contained in the current
84 # topic (ie. this Help object). Queries are represented as a
85 # tuple denoting the topics. For example, "python syntax csv"
86 # would be represented as ('python', 'syntax', 'csv').
87
88 def __contains__(self, query):
89 """Return True if query refers to a help topic. OTherwise,
90 False is returned."""
91 t = self._translate_query(query)
92
93 if len(t) == 1:
94 return t[0] in self.subtopics
95 else:
96 return t[0] in self.subtopics and t[1:] in self.subtopics[t[0]]
97
98 def __getitem__(self, query):
99 """Returns the help topic denoted by query; topics in query
100 that do not exist should be created automatically. query may
101 refer to topic with subtopics."""
102 t = self._translate_query(query)
103 self._ensure_key(t[0])
104
105 if len(t) == 1:
106 return self.subtopics[t[0]]
107 else:
108 return self.subtopics[t[0]][t[1:]]
109
110 def __setitem__(self, query, value):
111 """Sets the help topic denoted by query to value. topics in
112 query that do not exist should be created automatically.
113 query may refer to topic with subtopics."""
114 t = self._translate_query(query)
115
116 if len(t) == 1:
117 self.subtopics[t[0]] = value
118 else:
119 self._ensure_key(t[0])
120 self.subtopics[t[0]][t[1:]] = value
121
122 def __delitem__(self, query):
123 """Deletes the reference to help topic denoted by query.
124 query may refer to topic with subtopics."""
125 t = self._translate_query(query)
126 if len(t) == 1:
127 del self.subtopics[t[0]]
128 else:
129 del self.subtopics[t[0]][t[1:]]
130
131 def search(self, query):
132 """Returns an iterable of the absolute paths to topics that
133 partially match query."""
134 t = self._translate_query(query)
135 return (path for path in self._walk() if issubseq(t, path))
136
137
0138
=== modified file 'src/boots/lib/ui/generic.py'
--- src/boots/lib/ui/generic.py 2010-01-31 00:00:49 +0000
+++ src/boots/lib/ui/generic.py 2010-02-04 01:10:27 +0000
@@ -51,3 +51,5 @@
51 """Prints row information in a "raw" format"""51 """Prints row information in a "raw" format"""
52 def present(self, row):52 def present(self, row):
53 print(row)53 print(row)
54
55
5456
=== modified file 'src/boots/lib/ui/plain.py'
--- src/boots/lib/ui/plain.py 2010-02-02 02:48:04 +0000
+++ src/boots/lib/ui/plain.py 2010-02-04 01:10:27 +0000
@@ -34,17 +34,44 @@
34from boots.lib.ui.generic import StdinDriver, StdoutPresenter34from boots.lib.ui.generic import StdinDriver, StdoutPresenter
3535
36class PlainUI(StdinDriver, StdoutPresenter):36class PlainUI(StdinDriver, StdoutPresenter):
37<<<<<<< TREE
37 def __init__(self, prompt):38 def __init__(self, prompt):
38 self.metacommands = metacommands.MetaCommands({}, self)39 self.metacommands = metacommands.MetaCommands({}, self)
40=======
41 def __init__(self, prompt, hist_length, hist_file):
42 readline.set_history_length(hist_length)
43 self.hist_file = hist_file
44>>>>>>> MERGE-SOURCE
39 self.prompt = prompt45 self.prompt = prompt
46<<<<<<< TREE
40 self.current_widths = None47 self.current_widths = None
41 self.buffer = []48 self.buffer = []
4249
43 def get_input(self, input_complete = lambda command: True):50 def get_input(self, input_complete = lambda command: True):
44 return super(PlainUI, self).get_input(self.prompt, input_complete)51 return super(PlainUI, self).get_input(self.prompt, input_complete)
52=======
53
54 def read_history(self):
55 try:
56 readline.read_history_file(self.hist_file)
57 except IOError:
58 pass
59
60 def save_history(self):
61 readline.write_history_file(self.hist_file)
62
63 def get_input(self):
64 while True:
65 var = raw_input(self.prompt)
66 yield var
67
68 def present(self, row):
69 print(row)
70>>>>>>> MERGE-SOURCE
4571
46 def set_prompt(self, prompt):72 def set_prompt(self, prompt):
47 self.prompt = prompt73 self.prompt = prompt
74<<<<<<< TREE
4875
49 def present(self, result):76 def present(self, result):
50 def get_dashes(x):77 def get_dashes(x):
@@ -79,3 +106,6 @@
79 except:106 except:
80 # Reset values for next result set.107 # Reset values for next result set.
81 self.current_widths = None108 self.current_widths = None
109=======
110
111>>>>>>> MERGE-SOURCE

Subscribers

People subscribed via source and target branches

to status/vote changes: