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
1=== modified file 'src/boots/app/client_config.py'
2--- src/boots/app/client_config.py 2010-01-22 05:58:25 +0000
3+++ src/boots/app/client_config.py 2010-02-04 01:10:27 +0000
4@@ -51,7 +51,9 @@
5 "port" : 9306,
6 "username" : os.getenv("USER"),
7 "password" : False,
8- "prompt" : "> "}
9+ "prompt" : "> ",
10+ "history_length": 0,
11+ "history_file": None}
12 self._dict = self._defaults.copy()
13
14 # Use default rc location in info if no argument is passed in.
15@@ -111,7 +113,17 @@
16 type = "string",
17 dest = "password",
18 help = "Connect using password. If none is given, query for password")
19-
20+ self._cli_parser.add_option("-F", "--historyfile",
21+ action = "store",
22+ type = "string",
23+ dest = "history_file",
24+ help = "Specify file to save history to")
25+ self._cli_parser.add_option("-L", "--historylength",
26+ action = "store",
27+ type = "int",
28+ dest = "history_length",
29+ help = "Specify max history file length")
30+
31 def __getitem__(self, key):
32 return self._dict[key]
33
34
35=== modified file 'src/boots/lib/console.py'
36--- src/boots/lib/console.py 2010-02-01 20:46:55 +0000
37+++ src/boots/lib/console.py 2010-02-04 01:10:27 +0000
38@@ -30,6 +30,7 @@
39
40 from boots.api import api
41 from boots.lib.ui.plain import PlainUI
42+<<<<<<< TREE
43 from boots.lib.metacommands import metacommands
44 from boots.lib.lingos import lingo
45 from boots.lib.lingos.lisp import lisp
46@@ -44,10 +45,15 @@
47 return True
48 except TypeError:
49 return False
50+=======
51+import os
52+import atexit
53+>>>>>>> MERGE-SOURCE
54
55 class Console(object):
56 def __init__(self, config):
57 self.config = config
58+<<<<<<< TREE
59 # FIXME: Once metacommands are supported it should be possible to change the lingo at runtime using a metacommand.
60 self.lingo = self.config['lingo']
61 self.servers = [api.Server(self.config["host"], self.config["port"],
62@@ -102,7 +108,15 @@
63 lingo.register('lisp', lisp.LispInterpreter(self))
64 lingo.register('python', python.PythonInterpreter(self))
65 lingo.register('sql', sql.SQLInterpreter(self))
66+=======
67+ self.server = api.Server(self.config["host"], self.config["port"],
68+ {"database": self.config["database"]})
69+ self.ui = PlainUI(self.config["prompt"], self.config["history_length"],
70+ self.config["history_file"])
71+ atexit.register(self.ui.save_history)
72+>>>>>>> MERGE-SOURCE
73
74+<<<<<<< TREE
75 for command in self.ui.get_input(input_complete = lingo.get(self.lingo).input_complete):
76 if not self.metacommands.execute(metacommands.parse(command)):
77 result = self.run(command, self.lingo)
78@@ -114,7 +128,23 @@
79 # Don't print None; a return value of None means there was no result.
80 elif result != None:
81 self.ui.present(result)
82-
83+=======
84+
85+ def run(self, command, language):
86+ result = self.server.execute(command)
87+ return result
88+>>>>>>> MERGE-SOURCE
89+
90+<<<<<<< TREE
91 # Print a trailing newline.
92 self.ui.present('')
93 self.disconnect()
94+=======
95+ def main(self):
96+ self.ui.read_history()
97+ self.server.connect()
98+ for command in self.ui.get_input():
99+ for row in self.run(command, "sql"):
100+ self.ui.present(row)
101+ self.server.disconnect()
102+>>>>>>> MERGE-SOURCE
103
104=== removed file 'src/boots/lib/ui/components/help.py'
105=== added file 'src/boots/lib/ui/components/helptopics.py'
106--- src/boots/lib/ui/components/helptopics.py 1970-01-01 00:00:00 +0000
107+++ src/boots/lib/ui/components/helptopics.py 2010-02-04 01:10:27 +0000
108@@ -0,0 +1,137 @@
109+# Utility function
110+def issubseq(seq, seq2):
111+ """Determines if the elements the sequence seq form a subsequence of the sequence seq2."""
112+ if len(seq) == 0:
113+ return True
114+ else:
115+ i = 0
116+
117+ while i < len(seq2) and seq[0] != seq2[i]:
118+ i += 1
119+
120+ if i == len(seq2):
121+ return False
122+
123+ return list(seq[1:]) == list(seq2[:i + 1:len(seq)])
124+
125+
126+class Topic(object):
127+ """A topic in the help system which may contain other topics."""
128+ def __init__(self, name, title = None, description = None, short_description = None, see_also = None):
129+ """Creates a new a help topic. The fields are as described above."""
130+ self.subtopics = dict()
131+ self.title = title
132+ self.name = name
133+ self.description = description
134+ self.short_description = short_description
135+ self.see_also = see_also
136+
137+ def format(self):
138+ """Returns a string that represents this topic in human readable form as
139+ described in detail above."""
140+ text = "{0.title}\n\n{0.description}\n\nSee also: {0.see_also}".format(self)
141+ return text
142+
143+ def format_index(self):
144+ """Returns a string that lists the subtopics of this topic in human
145+ readable form as described above."""
146+ lines = list()
147+
148+ for name, topic in self.subtopics.iteritems():
149+ max_name_len = max(len(subtopic.name) for subtopic in self.subtopics.itervalues())
150+ subtext = "{0:{2}}--{1:30}".format(topic.name, topic.short_description, max_name_len +3)
151+ lines.append(subtext)
152+ lines.sort()
153+ return "\n".join(lines)
154+
155+ # Queries:
156+ #
157+ # A query is used to refer to a topic in the help system. A query is either
158+ # a string or a non-empty tuple of strings. Using a string is equivalent to
159+ # using a tuple of length one containing that string. As an example, the
160+ # tuple ('python', 'syntax', 'csv') refers to the csv subtopic in the syntax
161+ # topic which is itself a subtopic of the python topic.
162+
163+ def _translate_query(self, query):
164+ """Converts a query into a tuple. If query is not a valid query an
165+ exception is raised."""
166+ if isinstance(query, str):
167+ return (query,)
168+ elif isinstance(query, (tuple, list)):
169+ assert len(query) != 0
170+ for item in query:
171+ assert isinstance(item, str)
172+ return query
173+ else:
174+ raise TypeError('query object {0} is not a string or tuple of strings'.format(query))
175+
176+ def _ensure_key(self, key):
177+ """Creates a new subtopic that key maps to if none exists."""
178+ if key not in self.subtopics:
179+ self.subtopics[key] = Topic(key)
180+
181+ def _walk(self, path = ()):
182+ """Returns an iterable of all absolute paths."""
183+ if len(self.subtopics) == 0:
184+ yield path
185+ else:
186+ for subtopic in self.subtopics:
187+ for path2 in subtopic._walk(path + self.name):
188+ yield path2
189+
190+ # The intention is for these methods to be implemented recursively
191+ # by calling these methods on topics contained in the current
192+ # topic (ie. this Help object). Queries are represented as a
193+ # tuple denoting the topics. For example, "python syntax csv"
194+ # would be represented as ('python', 'syntax', 'csv').
195+
196+ def __contains__(self, query):
197+ """Return True if query refers to a help topic. OTherwise,
198+ False is returned."""
199+ t = self._translate_query(query)
200+
201+ if len(t) == 1:
202+ return t[0] in self.subtopics
203+ else:
204+ return t[0] in self.subtopics and t[1:] in self.subtopics[t[0]]
205+
206+ def __getitem__(self, query):
207+ """Returns the help topic denoted by query; topics in query
208+ that do not exist should be created automatically. query may
209+ refer to topic with subtopics."""
210+ t = self._translate_query(query)
211+ self._ensure_key(t[0])
212+
213+ if len(t) == 1:
214+ return self.subtopics[t[0]]
215+ else:
216+ return self.subtopics[t[0]][t[1:]]
217+
218+ def __setitem__(self, query, value):
219+ """Sets the help topic denoted by query to value. topics in
220+ query that do not exist should be created automatically.
221+ query may refer to topic with subtopics."""
222+ t = self._translate_query(query)
223+
224+ if len(t) == 1:
225+ self.subtopics[t[0]] = value
226+ else:
227+ self._ensure_key(t[0])
228+ self.subtopics[t[0]][t[1:]] = value
229+
230+ def __delitem__(self, query):
231+ """Deletes the reference to help topic denoted by query.
232+ query may refer to topic with subtopics."""
233+ t = self._translate_query(query)
234+ if len(t) == 1:
235+ del self.subtopics[t[0]]
236+ else:
237+ del self.subtopics[t[0]][t[1:]]
238+
239+ def search(self, query):
240+ """Returns an iterable of the absolute paths to topics that
241+ partially match query."""
242+ t = self._translate_query(query)
243+ return (path for path in self._walk() if issubseq(t, path))
244+
245+
246
247=== modified file 'src/boots/lib/ui/generic.py'
248--- src/boots/lib/ui/generic.py 2010-01-31 00:00:49 +0000
249+++ src/boots/lib/ui/generic.py 2010-02-04 01:10:27 +0000
250@@ -51,3 +51,5 @@
251 """Prints row information in a "raw" format"""
252 def present(self, row):
253 print(row)
254+
255+
256
257=== modified file 'src/boots/lib/ui/plain.py'
258--- src/boots/lib/ui/plain.py 2010-02-02 02:48:04 +0000
259+++ src/boots/lib/ui/plain.py 2010-02-04 01:10:27 +0000
260@@ -34,17 +34,44 @@
261 from boots.lib.ui.generic import StdinDriver, StdoutPresenter
262
263 class PlainUI(StdinDriver, StdoutPresenter):
264+<<<<<<< TREE
265 def __init__(self, prompt):
266 self.metacommands = metacommands.MetaCommands({}, self)
267+=======
268+ def __init__(self, prompt, hist_length, hist_file):
269+ readline.set_history_length(hist_length)
270+ self.hist_file = hist_file
271+>>>>>>> MERGE-SOURCE
272 self.prompt = prompt
273+<<<<<<< TREE
274 self.current_widths = None
275 self.buffer = []
276
277 def get_input(self, input_complete = lambda command: True):
278 return super(PlainUI, self).get_input(self.prompt, input_complete)
279+=======
280+
281+ def read_history(self):
282+ try:
283+ readline.read_history_file(self.hist_file)
284+ except IOError:
285+ pass
286+
287+ def save_history(self):
288+ readline.write_history_file(self.hist_file)
289+
290+ def get_input(self):
291+ while True:
292+ var = raw_input(self.prompt)
293+ yield var
294+
295+ def present(self, row):
296+ print(row)
297+>>>>>>> MERGE-SOURCE
298
299 def set_prompt(self, prompt):
300 self.prompt = prompt
301+<<<<<<< TREE
302
303 def present(self, result):
304 def get_dashes(x):
305@@ -79,3 +106,6 @@
306 except:
307 # Reset values for next result set.
308 self.current_widths = None
309+=======
310+
311+>>>>>>> MERGE-SOURCE

Subscribers

People subscribed via source and target branches

to status/vote changes: