Merge lp:~chromakode/boots/localization into lp:~ken-brotherton/boots/local2

Proposed by Max Goodhart
Status: Merged
Merge reported by: Max Goodhart
Merged at revision: not available
Proposed branch: lp:~chromakode/boots/localization
Merge into: lp:~ken-brotherton/boots/local2
Diff against target: 2946 lines (+1110/-813)
32 files modified
boots/api/__init__.py (+1/-0)
boots/api/api.py (+131/-29)
boots/api/constructors.py (+106/-15)
boots/api/errors.py (+34/-10)
boots/api/nodes/node.py (+146/-64)
boots/app/__init__.py (+1/-1)
boots/app/client_config.py (+44/-6)
boots/lib/__init__.py (+4/-0)
boots/lib/console.py (+93/-44)
boots/lib/lingos/bash_external.py (+2/-2)
boots/lib/lingos/external.py (+2/-2)
boots/lib/lingos/lingo.py (+6/-6)
boots/lib/lingos/lisp/builtins.py (+3/-3)
boots/lib/lingos/lisp/lexer.py (+2/-1)
boots/lib/lingos/lisp/lisp.py (+9/-9)
boots/lib/lingos/lisp/objects.py (+5/-5)
boots/lib/lingos/lisp/parser.py (+4/-3)
boots/lib/lingos/piped_sql.py (+17/-8)
boots/lib/lingos/python.py (+9/-3)
boots/lib/lingos/sql.py (+2/-1)
boots/lib/ui/components/help.py (+3/-3)
boots/lib/ui/components/metacommands.py (+39/-8)
boots/lib/ui/generic.py (+6/-0)
boots/lib/ui/plain.py (+99/-42)
boots/util.py (+0/-27)
localizations/potfiles.txt (+0/-12)
po/README.txt (+12/-18)
po/boots.pot (+316/-221)
po/createpots.sh (+1/-1)
tests/boots/api/api_tests.py (+10/-10)
tests/boots/lib/lingos/cand_correct.txt (+0/-256)
tests/boots/lib/lingos/lingo_tests.py (+3/-3)
To merge this branch: bzr merge lp:~chromakode/boots/localization
Reviewer Review Type Date Requested Status
Boots Developers Pending
Review via email: mp+20843@code.launchpad.net

Description of the change

Merged with the latest boots trunk. Localization install code forthcoming.

To post a comment you must log in.
lp:~chromakode/boots/localization updated
117. By Max Goodhart

Fix a couple translatable strings in client_config.py.

118. By Max Goodhart

Fix translatable strings again.

119. By Max Goodhart

Localize boots.api.

120. By Max Goodhart

Merge and localize latest updates to trunk.

121. By Max Goodhart

Update potfile.

122. By Max Goodhart

Update localization README.

123. By Max Goodhart

Fix another translatable string that slipped through.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'boots/api/__init__.py'
2--- boots/api/__init__.py 2009-12-22 00:12:18 +0000
3+++ boots/api/__init__.py 2010-03-07 09:23:23 +0000
4@@ -0,0 +1,1 @@
5+from boots.lib import _, n_
6\ No newline at end of file
7
8=== modified file 'boots/api/api.py'
9--- boots/api/api.py 2010-02-27 05:40:10 +0000
10+++ boots/api/api.py 2010-03-07 09:23:23 +0000
11@@ -30,37 +30,63 @@
12
13 import time
14 from boots.api import errors
15-from drizzle import db
16+from boots.api.nodes.node import Status
17+from boots.api import _, n_
18+
19+_server_classes = []
20+
21+def extract_field_indexes(cursor_description):
22+ """Returns a dictionary which maps field names to their indexes."""
23+ return dict(zip((field[0] for field in cursor_description), range(0, len(cursor_description))))
24+
25+class Rows(list):
26+ """Represents a chunk of rows."""
27+ def __init__(self, sequence, field_indexes):
28+ super(Rows, self).__init__(sequence)
29+ self.field_indexes = field_indexes
30+
31+class ResultInfo(Status):
32+ pass
33
34 class Server(object):
35 """Represents a connection to a database server.
36
37 This object is used to execute commands on a remote server."""
38
39- def __init__(self, hostname, port, auth):
40+ def __init__(self, dbapi_module, hostname, port, auth):
41 """Initialize a Server object.
42
43 hostname should be a string.
44 port should be a positive integer value.
45 auth should be a dictionary possibly containing keys:
46 'username', 'password', and 'database' mapping to their
47- appropriate string values."""
48+ appropriate string values."""
49+ self.db = dbapi_module
50 self.hostname = hostname
51 self.port = port
52 self.auth = auth
53 self._connection = None
54
55+ def __str__(self):
56+ return "{0}:{1}".format(self.hostname, self.port)
57+
58+ def _connect(self):
59+ return self.db.connect(
60+ host = self.hostname,
61+ port = self.port,
62+ username = self.auth.get("username", ""),
63+ password = self.auth.get("password", ""),
64+ database = self.auth.get("database", ""))
65+
66 def connect(self):
67 """Establishes database connection.
68
69 Connect to the database server whose details were provided through
70 the __init__ method."""
71- self._connection = db.connect(
72- host = self.hostname,
73- port = self.port,
74- username = self.auth.get('username', ""),
75- password = self.auth.get('password', ""),
76- database = self.auth.get('database', ""))
77+ try:
78+ self._connection = self._connect()
79+ except self.db.Error:
80+ raise errors.ConnectionError(_("Could not connect to {0}").format(self))
81
82 @property
83 def is_connected(self):
84@@ -72,38 +98,60 @@
85 def _check_connected(self):
86 """Raise a ProgrammingError if the Connection has been closed."""
87 if not self.is_connected:
88- raise errors.ConnectionError("Connection closed")
89+ raise errors.ConnectionError(_("Connection closed"))
90
91 def disconnect(self):
92 self._check_connected()
93 """Disconnect from the connected database server."""
94 self._connection.close()
95 self._connection = None
96+
97+ def _execute(self, query):
98+ cursor = self._connection.cursor()
99+ cursor.execute(query)
100+ return cursor
101
102 def execute(self, query):
103- #FIXME: I don't like how this is phrased, but cannot right now think of a better way to do it.
104- #FIXME: Gotta come back to that, I think.
105- """Executes a query, returning an iterator of resulting rows.
106-
107- The resulting rows are packaged in a 'packet' which is a dict:
108- {"__server_execute_sql_query": query,
109- "info": meta data,
110- "result": chunk of rows (list of tuples)}"""
111-
112+ """Executes a query, returning an iterator of resulting rows."""
113 self._check_connected()
114- cursor = self._connection.cursor(convert=False)
115 begin_time = time.time()
116- cursor.execute(query)
117+
118+ try:
119+ cursor = self._execute(query)
120+ except errors.LostConnectionError as lost_e:
121+ # FIXME: this is NOT thread safe
122+ # Attempt to reconnect and retry
123+ yield Status(_("Lost connection to {0}. Reconnecting...").format(self))
124+
125+ if self.is_connected:
126+ self.disconnect()
127+
128+ try:
129+ self.connect()
130+ cursor = self._execute(query)
131+ except Exception as e:
132+ lost_e.reconnect_exception = e
133+ raise lost_e
134+ else:
135+ yield Status(_("Reconnected."))
136+
137 if cursor.description:
138+ field_indexes = extract_field_indexes(cursor.description)
139+
140 while True:
141 chunk = cursor.fetchmany(256)
142- packet = {"__server_execute_sql_query": query,
143- "info": cursor.description,
144+ # FIXME: Eventually it would be good to implement chunk packeting
145+ # as a generic nodes feature.
146+ if chunk:
147+ yield Rows(chunk, field_indexes)
148+ else:
149+ break
150+
151+ yield ResultInfo({"description": cursor.description,
152+ "row_count": cursor.rowcount,
153 "begin_time": begin_time,
154- "result": chunk}
155- yield packet
156- if not chunk:
157- return
158+ "end_time": time.time()})
159+ return
160
161 @property
162 def server_version(self):
163@@ -115,7 +163,61 @@
164 self._check_connected()
165 return self._connection.protocol_version
166
167+try:
168+ import drizzle.db
169+ class DrizzleServer(Server):
170+ def __init__(self, hostname, port, auth):
171+ Server.__init__(self, drizzle.db, hostname, port, auth)
172+
173+ def _execute(self, query):
174+ try:
175+ cursor = self._connection.cursor(convert=False)
176+ cursor.execute(query)
177+ except drizzle.errors.LostConnectionError:
178+ raise errors.LostConnectionError(server=self)
179+ else:
180+ return cursor
181+
182+except ImportError:
183+ pass
184+else:
185+ _server_classes.append(DrizzleServer)
186+
187+try:
188+ import MySQLdb
189+ import MySQLdb.converters
190+ class MySQLServer(Server):
191+ def __init__(self, hostname, port, auth):
192+ Server.__init__(self, MySQLdb, hostname, port, auth)
193+
194+ def _connect(self):
195+ """Establishes database connection.
196+
197+ Connect to the database server whose details were provided through
198+ the __init__ method."""
199+
200+ converter = self.db.converters.conversions.copy()
201+ for x in range(0,256):
202+ converter.pop(x, None)
203+ if self.auth["database"] == None:
204+ self.auth["database"] = ""
205+ return self.db.connect(
206+ host = self.hostname,
207+ port = self.port,
208+ user = self.auth.get("username", ""),
209+ passwd = self.auth.get("password", ""),
210+ db = self.auth.get("database", ""),
211+ conv = converter)
212+
213+ @property
214+ def server_version(self):
215+ self._check_connected()
216+ return self._connection.get_server_info()
217+except ImportError:
218+ pass
219+else:
220+ _server_classes.append(MySQLServer)
221+
222 class Query(str):
223 def substitute(self, rows): pass
224-
225-class Row(dict): pass
226+
227
228=== modified file 'boots/api/constructors.py'
229--- boots/api/constructors.py 2010-02-27 05:40:10 +0000
230+++ boots/api/constructors.py 2010-03-07 09:23:23 +0000
231@@ -21,7 +21,11 @@
232 #
233 # ##### END LICENSE BLOCK #####
234
235+import re
236+
237+from boots.api.api import Rows, ResultInfo
238 from boots.api.nodes.node import NodeGraph, SyncNode, IteratorNode
239+from boots.api import _, n_
240
241 _constructors = {}
242
243@@ -29,7 +33,7 @@
244 """Allow the function constructor to be used from PipedSQL under name. constructor is a
245 function that takes any number of strings as arguments and returns a node."""
246 if name in _constructors:
247- raise KeyError('A constructor with name ' + name + ' already exists')
248+ raise KeyError(_('A constructor with name {0} already exists').format(name))
249
250 _constructors[name] = constructor
251
252@@ -40,7 +44,7 @@
253 def construct(name, *arguments):
254 """Contructs a node using the given name and arguments."""
255 if name not in _constructors:
256- raise KeyError('There is no constructor with the name' + ' {0}.'.format(name))
257+ raise KeyError(_('There is no constructor with the name {0}.').format(name))
258
259 return _constructors[name](*arguments)
260
261@@ -52,18 +56,105 @@
262
263 return register_constructor_with_name
264
265+@register('csv_in')
266+def csv_input_file_node(path):
267+ """Constructs a node that reads from a csv file and then sends the word to its outputs."""
268+ input_file = open(path)
269+
270+ def read_iterator():
271+ for line in input_file:
272+ for word in line.split(','):
273+ yield word
274+
275+ return IteratorNode(read_iterator())
276+
277 @register('csv_out')
278 def csv_output_file_node(path):
279- """Constructs a node that writes each object it is passed to a
280- file and then sends the object to its outputs."""
281- output_file = open(path, 'w')
282-
283- def write(result):
284- if type(result) is dict and "__server_execute_sql_query" in result:
285- output_file.write('\n'.join(','.join(row) for row in result['result']))
286- else:
287- output_file.write(str(result) + '\n')
288-
289- return StopIteration
290-
291- return SyncNode(write)
292+ """Constructs a node that writes each object it is passed to a file and then sends the object to
293+ its outputs."""
294+ class CSVOutput(object):
295+ def __init__(self):
296+ self.write_comma = False
297+ self.output_file = open(path, 'w')
298+
299+ def write(self, result):
300+ if type(result) is Rows:
301+ self.output_file.write('\n'.join(','.join(row) for row in result))
302+ else:
303+ if self.write_comma:
304+ self.output_file.write(',')
305+
306+ self.output_file.write(str(result))
307+
308+ if not isinstance(result, str) or not result.endswith('\n'):
309+ self.write_comma = True
310+ else:
311+ self.write_comma = False
312+
313+ self.output_file.flush()
314+
315+ csv_output = CSVOutput()
316+ return SyncNode(csv_output.write)
317+
318+@register('sink')
319+def sink_node():
320+ """Constructs a node that ignores all input."""
321+ return SyncNode(lambda x: None)
322+
323+@register('sub')
324+def substitute_node(pattern, replacement, field = None):
325+ """Constructs a node that replaces any text matching pattern with replacement as if by re.sub.
326+ field can be used to specify the name of the field to perform substitution against. The default
327+ is to substitute against all fields."""
328+
329+ regexp = re.compile(pattern)
330+
331+ def sub(result):
332+ if type(result) is Rows:
333+ field_indexes = result.field_indexes
334+
335+ if field:
336+ index = field_indexes[field]
337+
338+ def sub_field(row, replacement):
339+ row = list(row)
340+ row[index] = replacement
341+ return tuple(row)
342+
343+ return Rows((sub_field(row, regexp.sub(replacement, row[index])) for row in result), field_indexes)
344+ else:
345+ return Rows((tuple(regexp.sub(replacement, field) for field in row) for row in result), field_indexes)
346+
347+ elif isinstance(result, str):
348+ return regexp.sub(replacement, result)
349+ else:
350+ return result
351+
352+ return SyncNode(sub)
353+
354+@register('filter')
355+def filter_node(pattern, field = None):
356+ """Constructs a node that allows text to pass through only if it matches pattern. A row is
357+ allowed to pass through if at least one of its fields matches pattern. field can be used to
358+ specify the name of the field to perform substitution against. The default is to substitute
359+ against all fields."""
360+
361+ regexp = re.compile(pattern)
362+
363+ def filter(result):
364+ if type(result) is Rows:
365+ field_indexes = result.field_indexes
366+
367+ if field:
368+ index = field_indexes[field]
369+ return Rows((row for row in result if regexp.match(row[index])), field_indexes)
370+ else:
371+ return Rows((row for row in result if any(map(regexp.match, row))), field_indexes)
372+
373+ elif isinstance(result, str):
374+ if regexp.match(result):
375+ return result
376+ else:
377+ return result
378+
379+ return SyncNode(filter)
380
381=== modified file 'boots/api/errors.py'
382--- boots/api/errors.py 2010-02-27 05:40:10 +0000
383+++ boots/api/errors.py 2010-03-07 09:23:23 +0000
384@@ -22,15 +22,39 @@
385 # ##### END LICENSE BLOCK #####
386
387 import exceptions
388+import traceback
389+
390+from boots.api import _, n_
391
392 class BootsError(exceptions.StandardError):
393- """Base class of boots error exceptions"""
394- pass
395-
396-class ConsoleError(BootsError):
397- """Errors to be displayed to be displayed on the console"""
398- pass
399-
400-class ConnectionError(ConsoleError):
401- """Errors related to server connections"""
402- pass
403+ """Base class of boots error exceptions."""
404+ pass
405+
406+class BootsWarning(exceptions.Warning):
407+ """Base class of boots warnings."""
408+ pass
409+
410+class ConnectionError(BootsError):
411+ """Errors related to server connections."""
412+ pass
413+
414+class LostConnectionError(ConnectionError):
415+ """Raised when a connection is lost."""
416+ def __init__(self, msg=None, server=None, reconnect_exception=None):
417+ self.msg = msg
418+ self.server = server
419+ self.reconnect_exception = reconnect_exception
420+
421+ def __str__(self):
422+ msg = []
423+ if self.msg:
424+ msg.append(self.msg)
425+ else:
426+ msg.append(_("Lost connection to {0}").format(self.server))
427+
428+ if self.reconnect_exception:
429+ exc_lines = traceback.format_exception_only(type(self.reconnect_exception), self.reconnect_exception)
430+ exc_text = ". ".join(line.strip() for line in exc_lines)
431+ msg.append(_("(Exception upon reconnect: {0})").format(exc_text))
432+
433+ return " ".join(msg)
434
435=== modified file 'boots/api/nodes/node.py'
436--- boots/api/nodes/node.py 2010-03-02 00:45:59 +0000
437+++ boots/api/nodes/node.py 2010-03-07 09:23:23 +0000
438@@ -21,12 +21,13 @@
439 #
440 # ##### END LICENSE BLOCK #####
441
442+from __future__ import print_function
443+
444+import sys
445 from Queue import Queue
446-from itertools import chain, tee, repeat
447+from itertools import chain, tee, repeat, ifilter
448 from threading import Thread, Event, Lock
449 from types import GeneratorType
450-import gettext
451-gettext.install("boots",localedir=None,unicode=1)
452
453 def catch_exceptions(iterable):
454 try:
455@@ -34,6 +35,11 @@
456 yield x
457 except Exception as e:
458 yield e
459+
460+def trace(msg, iterable):
461+ for x in iterable:
462+ print(msg, repr(x), file=sys.stderr)
463+ yield x
464
465 def alternate_iterators(*iterables):
466 """Iterate over the given iterables, taking turns.
467@@ -62,7 +68,7 @@
468 yield x
469
470 def imap_flatten(func, iterable):
471- """Map a function over the iterables, flattening the result."""
472+ """Map a function over the iterable, flattening the result."""
473 for x in iterable:
474 result = func(x)
475 for item in flatten(result):
476@@ -70,27 +76,27 @@
477
478 # FIXME: need a thread safe tee here, perhapse "safetee"?
479
480-class BaseNode(object):
481- """Base class for the node system."""
482-
483- def __init__(self, name=None, inputs=None, outputs=None):
484+class Status(object):
485+ def __init__(self, value):
486+ self.value = value
487+
488+ def __str__(self):
489+ return str(self.value)
490+
491+def filter_default(value):
492+ return not isinstance(value, Status) and not isinstance(value, Exception)
493+
494+def filter_none(value):
495+ return True
496+
497+class PrimitiveNode(object):
498+ def __init__(self, name=None):
499 """Constructor of the base node object.
500
501 Initializes the node object.
502 Takes the node name, inputs and outputs as parameters.
503 """
504 self.name = name
505- self._finalized = False
506-
507- if inputs:
508- self.inputs = set(inputs)
509- else:
510- self.inputs = set()
511-
512- if outputs:
513- self.outputs = set(outputs)
514- else:
515- self.outputs = set()
516
517 @property
518 def name(self):
519@@ -117,6 +123,28 @@
520 For the base node object, returns NONE."""
521 return None
522
523+class BaseNode(PrimitiveNode):
524+ """Base class for the node system."""
525+
526+ def __init__(self, name=None, inputs=None, outputs=None):
527+ """Constructor of the base node object.
528+
529+ Initializes the node object.
530+ Takes the node name, inputs and outputs as parameters.
531+ """
532+ PrimitiveNode.__init__(self, name)
533+ self._finalized = False
534+
535+ if inputs:
536+ self.inputs = set(inputs)
537+ else:
538+ self.inputs = set()
539+
540+ if outputs:
541+ self.outputs = set(outputs)
542+ else:
543+ self.outputs = set()
544+
545 def finalize(self):
546 """Finalizes node setup.
547
548@@ -240,33 +268,40 @@
549 assert input_edges == output_edges, "Graph integrity check failed."
550 return output_edges
551
552- def add(self, *nodes):
553+ def add(self, *nodes, **flags):
554 """Add individual nodes to the collection.
555
556 Accepts a list of nodes to be added to the collection."""
557- return self._add(False, nodes)
558+ self._add(False, nodes)
559+ if flags.get("input", False):
560+ for node in nodes:
561+ self.input_link.connect_output(node)
562+ elif flags.get("output", False):
563+ for node in nodes:
564+ node.connect_output(self.output_link)
565+
566+ return self
567
568 def add_input(self, *nodes):
569 """Adds nodes to the input link.
570
571 Accepts a list of nodes and adds them to the input_link of this
572 graph."""
573- self.add(*nodes)
574- for node in nodes:
575- self.input_link.connect_output(node)
576+ self.add(*nodes, input=True)
577+ return self
578
579 def add_output(self, *nodes):
580 """Adds nodes to the output link.
581
582 Accepts a list of nodes and adds them to the output_link of this
583 graph."""
584- self.add(*nodes)
585- for node in nodes:
586- node.connect_output(self.output_link)
587+ self.add(*nodes, output=True)
588+ return self
589
590 def add_connected(self, *nodes):
591 """Add all connected nodes to the collection."""
592- return self._add(True, nodes)
593+ self._add(True, nodes)
594+ return self
595
596 def _add(self, traverse, nodes):
597 if traverse:
598@@ -278,8 +313,6 @@
599 self.nodes.add(node)
600 if node.name:
601 self.names[node.name] = node
602-
603- return nodes
604
605 def link_output(self, output_graph):
606 """Link output link of this node graph to input of another."""
607@@ -346,6 +379,9 @@
608 # Notify all nodes that their connections are final.
609 for node in self.nodes:
610 node.finalize()
611+
612+ self.input_link.finalize()
613+ self.output_link.finalize()
614
615 self._finalized = True
616
617@@ -370,14 +406,21 @@
618 self.output_link.put(data)
619
620 class ActionNode(BaseNode):
621- def __init__(self, action, name=None, inputs=None, outputs=None, include_stop=False):
622+ def __init__(self, action, name=None, inputs=None, outputs=None, filter=None):
623 BaseNode.__init__(self, name, inputs, outputs)
624+ self.filter = filter or filter_default
625 self.action = action
626-
627+
628+ def _do_action(self, data):
629+ if self.filter(data):
630+ return self.action(data)
631+ else:
632+ return data
633+
634 def _run(self):
635 for data in self._iter_inputs():
636 try:
637- for result in flatten(self.action(data)):
638+ for result in flatten(self._do_action(data)):
639 self._put_outputs(result)
640 except Exception as e:
641 self.put_outputs(e)
642@@ -392,7 +435,7 @@
643 class QueueNode(BaseNode):
644 """Thread-safe queue that buffers pushed data for pull access."""
645
646- def __init__(self, name=None, inputs=None, outputs=None, include_stop=False):
647+ def __init__(self, name=None, inputs=None, outputs=None):
648 BaseNode.__init__(self, name, inputs, outputs)
649 self._queue = Queue()
650 self._unfinished_inputs = None
651@@ -413,31 +456,39 @@
652 else:
653 yield data
654
655-class LinkNode(BaseNode):
656- """Link node to connect to nodes in a dynamic, thread-safe manner."""
657-
658- def __init__(self, name=None, inputs=None, outputs=None, mortal=False):
659+class BaseLinkNode(object):
660+ def __init__(self):
661 """Initializes link node."""
662- BaseNode.__init__(self, name, inputs, outputs)
663 self.input_links = set()
664+ self.output_links = set()
665 self.input_lock = Lock()
666- self.output_links = set()
667 self.output_lock = Lock()
668- self.mortal = mortal
669-
670+
671 def link_output(self, output_link):
672 """Links own output to another unit's input link."""
673- with self.input_lock:
674- with output_link.output_lock:
675+ with self.output_lock:
676+ with output_link.input_lock:
677 self.output_links.add(output_link)
678 output_link.input_links.add(self)
679
680 def unlink_output(self, output_link):
681 """Unlinks own output from another unit's input link."""
682- with self.input_lock:
683- with output_link.output_lock:
684+ with self.output_lock:
685+ with output_link.input_lock:
686 self.output_links.remove(output_link)
687 output_link.input_links.remove(self)
688+
689+class LinkNode(BaseNode, BaseLinkNode):
690+ """Link node to connect to nodes in a dynamic, thread-safe manner."""
691+
692+ def __init__(self, name=None, inputs=None, outputs=None, mortal=False):
693+ """Initializes link node."""
694+ BaseNode.__init__(self, name, inputs, outputs)
695+ BaseLinkNode.__init__(self)
696+ self.mortal = mortal
697+
698+ def _finalize(self):
699+ self._input_iter = self._iter_inputs()
700
701 def put(self, data):
702 """Push data through the link."""
703@@ -471,23 +522,57 @@
704 yield
705
706 def __iter__(self):
707- return alternate_iterators(self._iter_inputs(), self._iter_links())
708-
709+ return alternate_iterators(self._input_iter, self._iter_links())
710+
711+class LinkStackNode(PrimitiveNode, BaseLinkNode):
712+ """Link node to read input from a stack of nodes, popping off the stack
713+ when a node finishes."""
714+
715+ def __init__(self, name=None):
716+ """Initializes link node."""
717+ PrimitiveNode.__init__(self, name)
718+ BaseLinkNode.__init__(self)
719+ self.input_stack = list()
720+
721+ def push_input(self, input_link):
722+ with self.input_lock:
723+ with input_link.output_lock:
724+ self.input_stack.append(input_link)
725+ input_link.output_links.add(self)
726+
727+ def pop_input(self):
728+ with self.input_lock:
729+ input_link = self.input_stack.pop()
730+ with input_link.output_lock:
731+ input_link.output_links.remove(self)
732+
733+ def __iter__(self):
734+ while True:
735+ with self.input_lock:
736+ top_input = self.input_stack[-1] if self.input_stack else None
737+
738+ if top_input:
739+ try:
740+ yield iter(top_input).next()
741+ except StopIteration:
742+ self.pop_input()
743+ else:
744+ return
745+
746 class SyncNode(ActionNode):
747 """Synchronous lazy pull-based node."""
748 def _finalize(self):
749 if self.inputs:
750- self._input_iter = self._iter_inputs()
751+ self._result_iter = imap_flatten(self._do_action, self._iter_inputs())
752 else:
753- self._input_iter = repeat(None)
754- self._result_iter = catch_exceptions(imap_flatten(self.action, self._input_iter))
755- self._tees = list(tee(self._result_iter, len(self.outputs)))
756+ self._result_iter = self.action
757+ self._tees = list(tee(catch_exceptions(self._result_iter), len(self.outputs)))
758
759 def put(self, data):
760 if data is StopIteration:
761 result = StopIteration
762 else:
763- result = self.action(data)
764+ result = self._do_action(data)
765
766 self._put_outputs(result)
767
768@@ -501,19 +586,16 @@
769 self._run()
770
771 class IteratorNode(SyncNode):
772- def __init__(self, value, name=None, inputs=None, outputs=None, include_stop=False):
773+ def __init__(self, value, name=None, inputs=None, outputs=None, filter=None):
774 self.iterator = iter(value)
775- SyncNode.__init__(self, self.advance, name, inputs, outputs, include_stop)
776-
777- def advance(self, data):
778- return self.iterator.next()
779+ SyncNode.__init__(self, self.iterator, name, inputs, outputs, filter)
780
781 class AsyncNode(ActionNode, Thread):
782 """Asynchronous push-based node. Runs in a thread."""
783
784- def __init__(self, action=None, name=None, inputs=None, outputs=None, include_stop=False, profile=False):
785+ def __init__(self, action=None, name=None, inputs=None, outputs=None, filter=None, profile=False):
786 Thread.__init__(self)
787- ActionNode.__init__(self, action, name, inputs, outputs, include_stop)
788+ ActionNode.__init__(self, action, name, inputs, outputs, filter)
789 if action:
790 self.action = action
791 else:
792@@ -544,12 +626,12 @@
793 def test():
794 def wait(x):
795 import time
796- print "waiting: {0}".format(x)
797+ print("waiting: {0}".format(x))
798 time.sleep(1)
799 return x
800
801 def print_it(foo):
802- print "printing: {0}".format(foo)
803+ print("printing: {0}".format(foo))
804 return foo
805
806 nodes = NodeGraph.from_sequence([SyncNode(lambda x:xrange(10), name="count"),
807@@ -557,9 +639,9 @@
808 SyncNode(print_it, name="print"),
809 QueueNode(name="out")])
810 nodes.start()
811- print nodes.edges()
812+ print(nodes.edges())
813 for result in nodes["out"]:
814- print result
815+ print(result)
816
817 if __name__ == "__main__":
818 test()
819
820=== modified file 'boots/app/__init__.py'
821--- boots/app/__init__.py 2009-12-23 20:58:28 +0000
822+++ boots/app/__init__.py 2010-03-07 09:23:23 +0000
823@@ -1,1 +1,1 @@
824-__all__ = ["boots", "config", "info"]
825+from boots.lib import _, n_
826\ No newline at end of file
827
828=== modified file 'boots/app/client_config.py'
829--- boots/app/client_config.py 2010-03-02 00:45:59 +0000
830+++ boots/app/client_config.py 2010-03-07 09:23:23 +0000
831@@ -26,9 +26,32 @@
832 options/arguments."""
833
834 import optparse
835-import os
836+import os, os.path
837 import info
838-from boots.util import set_gettext
839+
840+from boots.app import _, n_
841+
842+def find_executable(name):
843+ # Search algorithm adapted from os._execvpe
844+ head, tail = os.path.split(name)
845+ if head and os.path.exists(name):
846+ return name
847+ else:
848+ if 'PATH' in os.environ:
849+ envpath = os.environ['PATH']
850+ else:
851+ envpath = os.defpath
852+ PATH = envpath.split(os.pathsep)
853+ for dir in PATH:
854+ fullname = os.path.join(dir, name)
855+ if os.path.exists(fullname):
856+ return fullname
857+
858+def get_auto_pager():
859+ if find_executable("less"):
860+ return "less -XF"
861+ elif find_executable("more"):
862+ return "more"
863
864 class ClientConfig(object):
865 """Class used to read client configuration from files and the cli."""
866@@ -42,7 +65,7 @@
867 self._defaults = {"command": None,
868 "database": None,
869 "script": None,
870- 'lingo': 'sql',
871+ "lingo": "sql",
872 "rcfile": info.RCFILE,
873 "host": "localhost",
874 "port": 9306,
875@@ -50,6 +73,8 @@
876 "password": False,
877 "prompt1": "> ",
878 "prompt2": "+ ",
879+ "pager": None,
880+ "pager_command": None,
881 "terminating_char": ";",
882 "history_length": 100,
883 "history_file": os.path.expanduser("~/.boots_history")}
884@@ -110,6 +135,11 @@
885 type = "string",
886 dest = "password",
887 help = _("Connect using password. If none is given, query for password"))
888+ self._cli_parser.add_option("--pager",
889+ action = "store",
890+ type = "string",
891+ dest = "pager",
892+ help = _("Pipe query results to the specified pager."))
893 self._cli_parser.add_option("-t", "--terminatingchar",
894 action = "store",
895 type = "string",
896@@ -155,6 +185,14 @@
897
898 self._dict.update(from_file)
899 self._dict.update(from_cli)
900+ self._interpret_options()
901+
902+ def _interpret_options(self):
903+ # Interpret options
904+ if self["pager"] == "auto":
905+ self["pager_command"] = get_auto_pager()
906+ elif self["pager"]:
907+ self["pager_command"] = self["pager"]
908
909 def get_file_conf(self, filepath):
910 """Read a configuration from the specified file. Return a dict."""
911@@ -164,11 +202,11 @@
912 except IOError:
913 if filepath != info.RCFILE:
914 # Only print an error if a non-default rc file was specified.
915- print("rcfile {0} "+_("not found").format(filepath))
916+ print(_("rcfile {0} not found").format(filepath))
917 except SyntaxError:
918- print("rcfile {0} "+_("contains a syntax error").format(filepath))
919+ print(_("rcfile {0} contains a syntax error").format(filepath))
920 except Exception as e:
921- print("rcfile {0} "+_("contains an error:")+" {1}".format(filepath, e))
922+ print(_("rcfile {0} contains an error: {1}").format(filepath, e))
923 return file_dict
924
925 def get_cli_conf(self):
926
927=== modified file 'boots/lib/__init__.py'
928--- boots/lib/__init__.py 2009-12-22 00:12:18 +0000
929+++ boots/lib/__init__.py 2010-03-07 09:23:23 +0000
930@@ -0,0 +1,4 @@
931+import gettext
932+translation = gettext.translation("boots", fallback=True)
933+_ = translation.lgettext
934+n_ = translation.lngettext
935\ No newline at end of file
936
937=== modified file 'boots/lib/console.py'
938--- boots/lib/console.py 2010-03-02 00:45:59 +0000
939+++ boots/lib/console.py 2010-03-07 09:23:23 +0000
940@@ -24,9 +24,11 @@
941 """This module provides the boots Console class. This class is the core
942 driver of any boots client."""
943
944+import sys
945+
946 from boots.api import api
947-from boots.api.errors import ConsoleError
948-from boots.api.nodes import node
949+from boots.api.errors import BootsError, BootsWarning, ConnectionError
950+from boots.api.nodes.node import NodeGraph, IteratorNode, LinkStackNode
951 from boots.lib.ui.plain import PlainUI
952 from boots.lib.ui.generic import ScriptDriver, StringDriver, StdoutPresenter
953 from boots.lib.ui.components.help import HelpTopic, QueryIndexTopic
954@@ -34,14 +36,17 @@
955 from boots.lib.hook import Hooks
956 from boots.lib.lingos.lingo import lingo_registry
957 from boots.lib.lingos import bash_external
958-from boots.lib.lingos.lisp import lisp
959 from boots.lib.lingos import python
960 from boots.lib.lingos import piped_sql
961 from boots.lib.lingos import sql
962-from boots.util import set_gettext
963+from boots.lib import _, n_
964+try:
965+ from boots.lib.lingos.lisp import lisp
966+except ImportError:
967+ # Allow the lisp lingo import to fail if Ply is not installed.
968+ pass
969 import sys
970
971-
972 # Utility function.
973 def iterable(obj):
974 """Returns True if obj is iterable; otherwise, False is returned."""
975@@ -50,6 +55,18 @@
976 return True
977 except TypeError:
978 return False
979+
980+class ConsoleError(BootsError):
981+ """Errors to be displayed on the console."""
982+ pass
983+
984+class InternalError(BootsError):
985+ """Errors to be displayed on the console."""
986+ def __init__(self, exception):
987+ self.exception = exception
988+
989+ def __str__(self):
990+ return _("Boots encountered an internal error: {0}").format(self.exception)
991
992 class Console(object):
993 def __init__(self, config, welcome_msg=None):
994@@ -67,7 +84,9 @@
995 '\quit': self.quit,
996 '\help': self.show_help,
997 '\h': self.show_help,
998- 'help': self.show_help})
999+ 'help': self.show_help,
1000+ 'source': self.meta_source,
1001+ '\.': self.meta_source,})
1002 self.metacommandmanager.add(self.metacommands)
1003
1004 self.servers = []
1005@@ -86,27 +105,31 @@
1006 self.driver = self.ui
1007
1008 if hasattr(self.ui, "metacommands"):
1009- self.metacommandmanager.add(self.ui.metacommands)
1010+ result = self.metacommandmanager.add(self.ui.metacommands)
1011+ if isinstance(result, BootsWarning):
1012+ self._display_error(result)
1013 if hasattr(self.ui, "help"):
1014 self.help["ui"] = self.ui.help
1015+
1016+ self.driver_stack = LinkStackNode()
1017
1018 self.hooks["load"].call()
1019
1020 def _init_help(self):
1021- self.help = HelpTopic("boots", "Boots Help", "Help", _("""
1022- Boots is a flexible, extensible, and multilingual shell for working with databases. To read more about a subtopic, use `help <topic>`."""))
1023+ self.help = HelpTopic("boots", _("Boots Help"), _("Help"),
1024+ description = _("Boots is a flexible, extensible, and multilingual shell for working with databases. To read more about a subtopic, use `help <topic>`."))
1025
1026 self.help["commands"] = QueryIndexTopic("commands", None,
1027 _("List of Boots commands."),
1028 query=("commands",))
1029
1030- self.help["commands"].add("\quit", "quit", _("Quit boots."))
1031- self.help["commands"].add("\help", "help", _("Show help for a topic."), _("""
1032- help <topic>
1033- Show help for \"topic\"."""))
1034+ self.help["commands"].add("\quit", _("quit"), _("Quit boots."))
1035+ self.help["commands"].add("\help", _("help"), _("Show help for a topic."),
1036+ description = _("help <topic>\n"
1037+ "Show help for \"topic\"."))
1038
1039- self.help.add("lingos", "Lingos", _("Documentation for loaded lingos."), _("""
1040- A lingo is a command language usable within Boots."""))
1041+ self.help.add("lingos", _("Lingos"), _("Documentation for loaded lingos."),
1042+ description = _("A lingo is a command language usable within Boots."))
1043
1044 def input_complete(self, command, lingo):
1045 if self.metacommands.get_metacommand(command) is not None:
1046@@ -117,24 +140,37 @@
1047 return command
1048
1049 def run(self, command, lingo="sql"):
1050- if lingo in self.lingos:
1051- return self.lingos[lingo].execute(command)
1052+ if not lingo in self.lingos:
1053+ self._display_error(ConsoleError(_("Invalid lingo \"{0}\" specified.").format(lingo)))
1054+ return
1055+
1056+ result_data = self.lingos[lingo].execute(command)
1057+ result = self.lingos[lingo].present(result_data)
1058+ if isinstance(result, NodeGraph):
1059+ result_graph = result
1060 else:
1061- return ConsoleError(_("Invalid lingo")+" \"{0}\" "+_("specified.").format(lingo))
1062+ result_graph = NodeGraph()
1063+ if isinstance(result, (str, Exception)) or not iterable(result):
1064+ result = iter([result])
1065+ result_graph.add_output(IteratorNode(result))
1066+
1067+ result_graph.link_output(self.presenter.presenter_graph)
1068+ result_graph.start()
1069+ result_graph.run()
1070+ return result_data
1071
1072 def connect(self, host, port, database):
1073 try:
1074- server = api.Server(host, port, {"database": database})
1075+ server = api.DrizzleServer(host, port, {"database": database})
1076 server.connect()
1077- except:
1078+ except ConnectionError:
1079 server = None
1080
1081 if server and server.is_connected:
1082 self.servers.append(server)
1083 return True
1084 else:
1085- error = ConsoleError(_("Could not connect to")+" {0}:{1}".format(host, port))
1086- self.presenter.presenter_graph.put(error)
1087+ self._display_error(ConsoleError(_("Could not connect to {0}:{1}").format(host, port)))
1088 return False
1089
1090 def disconnect(self, host, port):
1091@@ -153,38 +189,40 @@
1092 if self.welcome_msg and self.driver.is_interactive:
1093 server_lines = []
1094 for server in self.servers:
1095- line_format = "{0.hostname}:{0.port} ("+_("server")+" v{0.server_version})"
1096+ line_format = _("{0.hostname}:{0.port} (server v{0.server_version})")
1097 server_lines.append(line_format.format(server))
1098 server_status = "\n".join(server_lines)
1099
1100 welcome = self.welcome_msg.format(server_status=server_status)
1101 self.presenter.presenter_graph.put(welcome)
1102
1103+ def _display_error(self, error):
1104+ if not isinstance(error, (BootsError, BootsWarning)):
1105+ error = InternalError(error)
1106+ self.presenter.presenter_graph.put(error)
1107+
1108 def main(self):
1109 self.presenter.presenter_graph.start()
1110+ self.driver_stack.push_input(self.driver.driver_graph.output_link)
1111+ self.driver.driver_graph.start()
1112+
1113 self._load_servers()
1114 self._welcome_message()
1115-
1116- for command, lingo in self.driver.get_input():
1117- if not self.metacommands.execute(command):
1118- result = self.run(command, lingo)
1119-
1120- if isinstance(result, node.NodeGraph):
1121- result_graph = result
1122-
1123- else:
1124- result_graph = node.NodeGraph()
1125- if isinstance(result, (str, Exception)) or not iterable(result):
1126- result = iter([result])
1127- result_graph.add_output(node.IteratorNode(result))
1128-
1129- result_graph.link_output(self.presenter.presenter_graph)
1130- result_graph.start()
1131- result_graph.run()
1132-
1133+
1134+ for data in self.driver_stack:
1135+ if isinstance(data, Exception):
1136+ self._display_error(data)
1137+ else:
1138+ command, lingo = data
1139+ try:
1140+ if not self.metacommands.execute(command):
1141+ self.run(command, lingo)
1142+ except Exception as e:
1143+ self._display_error(e)
1144+
1145 self.quit()
1146
1147- def quit(self, exitcode = 0):
1148+ def quit(self, exitcode=0):
1149 if self.driver.is_interactive:
1150 self.presenter.presenter_graph.put(_("Boots quit."))
1151
1152@@ -204,9 +242,9 @@
1153 self.presenter.present(topic.format(include_index=True))
1154 else:
1155 paths = ", ".join("\"{0}\"".format(" ".join(path)) for path in results)
1156- self.presenter.present(_("Did you mean:")+" {0}?".format(paths))
1157+ self.presenter.present(_("Did you mean: {0}?").format(paths))
1158 else:
1159- self.presenter.present(_("No help found for")+" \"{0}\".".format(" ".join(query)))
1160+ self.presenter.present(_("No help found for \"{0}\".").format(" ".join(query)))
1161
1162 def meta_connect(self, host=None, port=None, database=None):
1163 if host is None:
1164@@ -229,3 +267,14 @@
1165 port = int(port)
1166
1167 self.disconnect(host, port)
1168+
1169+ def meta_source(self, *file_list):
1170+ for filepath in file_list:
1171+ try:
1172+ script_driver = ScriptDriver(self, filepath, self.config["lingo"])
1173+ except IOError as e:
1174+ self._display_error(ConsoleError(_("Could not open file {0}").format(filepath)))
1175+ return
1176+
1177+ self.driver_stack.push_input(script_driver.driver_graph.output_link)
1178+ script_driver.driver_graph.start()
1179
1180=== modified file 'boots/lib/lingos/bash_external.py'
1181--- boots/lib/lingos/bash_external.py 2010-02-27 05:54:13 +0000
1182+++ boots/lib/lingos/bash_external.py 2010-03-07 09:23:23 +0000
1183@@ -25,12 +25,12 @@
1184 from boots.lib.lingos import external
1185 from boots.lib.lingos import lingo
1186 from boots.lib.ui.components.help import HelpTopic
1187-
1188+from boots.lib import _, n_
1189
1190 class ExternalBashInterpreter(external.ExternalInterpreter):
1191 """Provides an interface to an external bash shell."""
1192
1193- help = HelpTopic("bash", "Bash Lingo", "External bash shell.")
1194+ help = HelpTopic("bash", _("Bash Lingo"), _("External bash shell."))
1195
1196 def __init__(self, *args, **kwargs):
1197 super(ExternalBashInterpreter, self).__init__('bash', [], *args, **kwargs)
1198
1199=== modified file 'boots/lib/lingos/external.py'
1200--- boots/lib/lingos/external.py 2010-02-27 05:40:10 +0000
1201+++ boots/lib/lingos/external.py 2010-03-07 09:23:23 +0000
1202@@ -47,12 +47,12 @@
1203 """Evaluate code using the external interpreter. All return values are strings."""
1204 if self.interpreter == None:
1205 self.interpreter = subprocess.Popen(self.executable, *self.executable_args, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
1206+ self.output_lines = []
1207+ self.lock = threading.RLock()
1208 # Since self.interpreter.stdout.readline could block, a thread is used to read the output.
1209 self.read_thread = threading.Thread(target = self._readlines)
1210 self.read_thread.daemon = True
1211 self.read_thread.start()
1212- self.output_lines = []
1213- self.lock = threading.RLock()
1214 # The maximum amount of time to wait for output.
1215 # FIXME: This is a kludge and should be fixed if possible.
1216
1217
1218=== modified file 'boots/lib/lingos/lingo.py'
1219--- boots/lib/lingos/lingo.py 2010-03-02 00:45:59 +0000
1220+++ boots/lib/lingos/lingo.py 2010-03-07 09:23:23 +0000
1221@@ -23,7 +23,7 @@
1222
1223 import sys
1224
1225-from boots.util import set_gettext
1226+from boots.lib import _, n_
1227
1228 class LingoRegistry(object):
1229 def __init__(self):
1230@@ -33,7 +33,7 @@
1231 """Registers a lingo with the given name and interpreter. Raises a KeyError if a lingo with
1232 name is already registered."""
1233 if name in self._lingos:
1234- raise KeyError(_('A lingo with name')+' {0} '+_('already exists').format(name))
1235+ raise KeyError(_('A lingo with name {0} already exists').format(name))
1236
1237 self._lingos[name] = interpreter
1238
1239@@ -92,10 +92,10 @@
1240 code should be an object returned by read."""
1241 pass
1242
1243- def string(self, obj):
1244- """Convert obj to a string. obj is an object in the object system for this lingo."""
1245- return str(obj)
1246-
1247+ def present(self, obj):
1248+ """Convert obj to a presentable object. obj is an object in the object system for this lingo."""
1249+ return obj
1250+
1251 def python(self, obj):
1252 """Convert obj to the appropriate python type. obj is an object in the object system for
1253 this lingo."""
1254
1255=== modified file 'boots/lib/lingos/lisp/builtins.py'
1256--- boots/lib/lingos/lisp/builtins.py 2010-03-02 00:45:59 +0000
1257+++ boots/lib/lingos/lisp/builtins.py 2010-03-07 09:23:23 +0000
1258@@ -21,10 +21,10 @@
1259 #
1260 # ##### END LICENSE BLOCK #####
1261
1262+import sys
1263+
1264 from boots.lib.lingos.lisp import objects
1265-from boots.util import set_gettext
1266-import sys
1267-
1268+from boots.lib import _, n_
1269
1270 nil = objects.Null()
1271 t = objects.T()
1272
1273=== modified file 'boots/lib/lingos/lisp/lexer.py'
1274--- boots/lib/lingos/lisp/lexer.py 2010-03-02 00:45:59 +0000
1275+++ boots/lib/lingos/lisp/lexer.py 2010-03-07 09:23:23 +0000
1276@@ -22,7 +22,8 @@
1277 # ##### END LICENSE BLOCK #####
1278
1279 import ply.lex as lex
1280-from boots.util import set_gettext
1281+
1282+from boots.lib import _, n_
1283
1284 tokens = ('INTEGER', 'STRING', 'SYMBOL', 'QUOTE', 'LEFT_PAREN', 'RIGHT_PAREN')
1285
1286
1287=== modified file 'boots/lib/lingos/lisp/lisp.py'
1288--- boots/lib/lingos/lisp/lisp.py 2010-03-02 00:45:59 +0000
1289+++ boots/lib/lingos/lisp/lisp.py 2010-03-07 09:23:23 +0000
1290@@ -30,23 +30,20 @@
1291 # let
1292 # do
1293
1294-# Optimize the code:
1295-# The current implementation is simple but very inefficient (especially environements, this can be fixed by using a
1296-# dictionary of lists instead of a list of dictionaries).
1297-
1298 import sys
1299
1300 if __name__ == '__main__':
1301 sys.path.append('../../../../')
1302
1303+import re
1304+import readline
1305+
1306 from boots.lib.lingos import lingo
1307 from boots.lib.lingos.lisp import builtins
1308 from boots.lib.lingos.lisp import lexer
1309 from boots.lib.lingos.lisp import objects
1310 from boots.lib.lingos.lisp import parser
1311-from boots.util import set_gettext
1312-import re
1313-import readline
1314+from boots.lib import _, n_
1315
1316
1317 def input_complete(string):
1318@@ -77,7 +74,7 @@
1319 if isinstance(stream, file):
1320 stream = stream.readline
1321 elif not callable(stream):
1322- raise TypeError('{0} '+_('is not a stream or a callable').format(stream))
1323+ raise TypeError(_('{0} is not a stream or a callable').format(stream))
1324 # Read lines until all open lisp expressions have been closed.
1325 while True:
1326 line = stream()
1327@@ -118,7 +115,10 @@
1328 builtins.initialize(global_environment)
1329
1330 while True:
1331- print(evaluate(read(lambda: raw_input('> ')), global_environment))
1332+ try:
1333+ print(evaluate(read(lambda: raw_input('> ')), global_environment))
1334+ except SyntaxError as e:
1335+ print(e)
1336
1337 except EOFError:
1338 pass
1339
1340=== modified file 'boots/lib/lingos/lisp/objects.py'
1341--- boots/lib/lingos/lisp/objects.py 2010-03-02 00:45:59 +0000
1342+++ boots/lib/lingos/lisp/objects.py 2010-03-07 09:23:23 +0000
1343@@ -25,7 +25,7 @@
1344 import copy
1345 import sys
1346
1347-from boots.util import set_gettext
1348+from boots.lib import _, n_
1349
1350 _gensym_count = 1
1351 _symbols = {}
1352@@ -98,7 +98,7 @@
1353 else_expression = car(cdr(cdr(cdr(self))))
1354
1355 if then_expression is Null() or cdr(cdr(cdr(cdr(self)))) is not Null():
1356- raise SyntaxError(_('wrong number of arguments for if special form')+' {0}'.format(self))
1357+ raise SyntaxError(_('Wrong number of arguments for if special form {0}').format(self))
1358
1359 if condition_expression.evaluate(environment) != Null():
1360 return then_expression.evaluate(environment)
1361@@ -172,10 +172,10 @@
1362 try:
1363 return self._environment[symbol][-1]
1364 except KeyError:
1365- raise KeyError(_('No binding for')+' {0} '+_('exists in the current environment').format(symbol))
1366+ raise KeyError(_('No binding for {0} exists in the current environment').format(symbol))
1367
1368 def __setitem__(self, symbol, value):
1369- """Sets symbol to value in the environment. If no binding for symbol exists, a binding is created at the innermost
1370+ """Sets symbol to value in the environment. If no binding for symbol exists, a binding is created at the innermost
1371 scope."""
1372 if not isinstance(symbol, Symbol):
1373 raise TypeError(_('Expected a symbol'))
1374@@ -204,7 +204,7 @@
1375 # return False
1376
1377 def push(self, symbol_values):
1378- """Adds a new innermost lexical scope as determined by symbol_values. symbol_values is a dictionary mapping Symbols
1379+ """Adds a new innermost lexical scope as determined by symbol_values. symbol_values is a dictionary mapping Symbols
1380 to Objects and describes bindings in the current scope."""
1381 self._scopes.append(set(symbol_values.keys()))
1382
1383
1384=== modified file 'boots/lib/lingos/lisp/parser.py'
1385--- boots/lib/lingos/lisp/parser.py 2010-03-02 00:45:59 +0000
1386+++ boots/lib/lingos/lisp/parser.py 2010-03-07 09:23:23 +0000
1387@@ -22,10 +22,11 @@
1388 # ##### END LICENSE BLOCK #####
1389
1390 from lexer import tokens
1391+import ply.yacc as yacc
1392+
1393 from boots.lib.lingos.lisp import builtins
1394 from boots.lib.lingos.lisp import objects
1395-from boots.util import set_gettext
1396-import ply.yacc as yacc
1397+from boots.lib import _, n_
1398
1399
1400 def p_expression_integer(p):
1401@@ -61,7 +62,7 @@
1402 p[0] = objects.Cons(p[1], p[2])
1403
1404 def p_error(p):
1405- print(_('syntax error'))
1406+ raise SyntaxError(_('syntax error'))
1407
1408 # Disable debugging output and caching of parse tables.
1409 parser = yacc.yacc(debug = 0, write_tables = 0)
1410
1411=== modified file 'boots/lib/lingos/piped_sql.py'
1412--- boots/lib/lingos/piped_sql.py 2010-03-02 00:45:59 +0000
1413+++ boots/lib/lingos/piped_sql.py 2010-03-07 09:23:23 +0000
1414@@ -21,14 +21,14 @@
1415 #
1416 # ##### END LICENSE BLOCK #####
1417
1418+import re
1419+
1420 from boots.api.nodes.node import NodeGraph, SyncNode, IteratorNode
1421-from boots.api.constructors import construct, csv_output_file_node
1422+from boots.api.constructors import construct, csv_output_file_node, sink_node
1423 from boots.lib.ui.components.help import HelpTopic
1424 from boots.lib.lingos import lingo
1425 from boots.lib.lingos import sql
1426-from boots.util import set_gettext
1427-import re
1428-
1429+from boots.lib import _, n_
1430
1431 # Set this to another node constructor to change the default constructor used for output files.
1432 output_file_node = csv_output_file_node
1433@@ -40,9 +40,11 @@
1434 # This regexp matches a function call syntax. Use the name group to access the name of the function
1435 # and the arguments group to access the list of arguments (as a string).
1436 constructor_call_re = re.compile('^(?P<name>[a-zA-Z_]+)\((?P<arguments>([^,\(\)]+,)*[^,\(\)]+)?\)$')
1437+# Matches a string of the form 'abc' or "abc".
1438+string_re = re.compile('^(?P<text>(\'[^\']*\')|("[^"]*"))')
1439
1440 class PipedSQLInterpreter(sql.SQLInterpreter):
1441- help = HelpTopic("pipedsql", "Piped SQL Lingo", _("Enhanced SQL query language supporting pipes."))
1442+ help = HelpTopic("pipedsql", _("Piped SQL Lingo"), _("Enhanced SQL query language supporting pipes."))
1443
1444 def __init__(self, *args, **kwargs):
1445 super(PipedSQLInterpreter, self).__init__(*args, **kwargs)
1446@@ -54,7 +56,7 @@
1447 match = clause_re.match(clause_string)
1448
1449 if not match:
1450- raise SyntaxError('{0} '+_('is not in the correct function call syntax').format(clause_string))
1451+ raise SyntaxError(_('{0} is not in the correct function call syntax').format(clause_string))
1452
1453 constructor_call = match.group('constructor_call').strip()
1454 output_file = match.group('output_file')
1455@@ -65,13 +67,13 @@
1456 match = constructor_call_re.match(constructor_string)
1457
1458 if not match:
1459- raise SyntaxError('{0} '+_('is not in the correct function call syntax').format(constructor_string))
1460+ raise SyntaxError(_('{0} is not in the correct function call syntax').format(constructor_string))
1461
1462 name = match.group('name')
1463 arguments = match.group('arguments')
1464
1465 if arguments:
1466- arguments = [argument.strip('\'"') for argument in arguments.split(',')]
1467+ arguments = [string_re.match(argument.strip()).group('text')[1:-1] for argument in arguments.split(',')]
1468 else:
1469 arguments = []
1470
1471@@ -137,6 +139,13 @@
1472 last_node = node
1473 first_node = False
1474
1475+ # Suppress output from the pipeline if the last clause redirected output.
1476+ if output_file:
1477+ sink = sink_node()
1478+ nodes.add(sink)
1479+ node.connect_output(sink)
1480+ node = sink
1481+
1482 nodes.add_output(node)
1483 return nodes
1484
1485
1486=== modified file 'boots/lib/lingos/python.py'
1487--- boots/lib/lingos/python.py 2010-02-27 05:54:13 +0000
1488+++ boots/lib/lingos/python.py 2010-03-07 09:23:23 +0000
1489@@ -27,12 +27,13 @@
1490 from boots.api import errors
1491 from boots.lib.lingos import lingo
1492 from boots.lib.ui.components.help import HelpTopic
1493+from boots.lib import _, n_
1494
1495 class PythonInterpreter(lingo.Interpreter):
1496 """Implements a python interpreter that will send commands to the python interpreter that runs
1497 boots."""
1498
1499- help = HelpTopic("python", "Python Lingo", "Integrated Python interpreter using the Boots API.")
1500+ help = HelpTopic("python", _("Python Lingo"), _("Integrated Python interpreter using the Boots API."))
1501
1502 def __init__(self, *args, **kwargs):
1503 super(PythonInterpreter, self).__init__(*args, **kwargs)
1504@@ -56,13 +57,18 @@
1505 def evaluate(self, code):
1506 if code.strip():
1507 try:
1508- # Wrap each python object in a list so that the Console will not iterate over it if it is an iterable.
1509 return eval(code, self._globals, self._locals)
1510 # If eval results in an error, it might be because code is a statement rather than an expression.
1511 except:
1512 try:
1513 exec code in self._globals, self._locals
1514 except Exception:
1515- return errors.ConsoleError(traceback.format_exc())
1516+ return errors.BootsError(traceback.format_exc())
1517+
1518+ def present(self, obj):
1519+ if not isinstance(obj, Exception) and obj is not None:
1520+ return repr(obj)
1521+ else:
1522+ return obj
1523
1524 lingo.register('python', PythonInterpreter)
1525
1526=== modified file 'boots/lib/lingos/sql.py'
1527--- boots/lib/lingos/sql.py 2010-02-27 05:54:13 +0000
1528+++ boots/lib/lingos/sql.py 2010-03-07 09:23:23 +0000
1529@@ -24,9 +24,10 @@
1530 from boots.api.nodes.node import NodeGraph, SyncNode, IteratorNode
1531 from boots.lib.ui.components.help import HelpTopic
1532 from boots.lib.lingos import lingo
1533+from boots.lib import _, n_
1534
1535 class SQLInterpreter(lingo.Interpreter):
1536- help = HelpTopic("sql", "SQL Lingo", "Raw SQL commands sent to a server.")
1537+ help = HelpTopic("sql", _("SQL Lingo"), _("Raw SQL commands sent to a server."))
1538
1539 def __init__(self, *args, **kwargs):
1540 super(SQLInterpreter, self).__init__(*args, **kwargs)
1541
1542=== modified file 'boots/lib/ui/components/help.py'
1543--- boots/lib/ui/components/help.py 2010-03-02 00:45:59 +0000
1544+++ boots/lib/ui/components/help.py 2010-03-07 09:23:23 +0000
1545@@ -21,7 +21,7 @@
1546 #
1547 # ##### END LICENSE BLOCK #####
1548
1549-from boots.util import set_gettext
1550+from boots.lib import _, n_
1551
1552 def issubseq(subseq, seq):
1553 """Determines if the elements the sequence subseq form a subsequence of the sequence seq."""
1554@@ -65,7 +65,7 @@
1555 template += "{0.description}"
1556
1557 if self.see_also:
1558- template += "\n\n"+_("See also:")+" {0.see_also}"
1559+ template += "\n\n"+_("See also: {0.see_also}")
1560
1561 output = template.format(self)
1562 if include_index and self._subtopics:
1563@@ -103,7 +103,7 @@
1564 assert isinstance(item, str)
1565 return query
1566 else:
1567- raise TypeError(_('query object')+' {0} '+_('is not a string or tuple of strings').format(query))
1568+ raise TypeError(_('query object {0} is not a string or tuple of strings').format(query))
1569
1570 def _ensure_key(self, key):
1571 """Creates a new subtopic that key maps to if none exists."""
1572
1573=== modified file 'boots/lib/ui/components/metacommands.py'
1574--- boots/lib/ui/components/metacommands.py 2010-03-02 00:45:59 +0000
1575+++ boots/lib/ui/components/metacommands.py 2010-03-07 09:23:23 +0000
1576@@ -22,7 +22,32 @@
1577 # ##### END LICENSE BLOCK #####
1578
1579 import warnings
1580-from boots.util import set_gettext
1581+import inspect
1582+import types
1583+
1584+from boots.api.errors import BootsError, BootsWarning
1585+from boots.lib import _, n_
1586+
1587+class MetaCommandError(BootsError):
1588+ """Errors related to metacommands."""
1589+
1590+class MetaCommandConflictWarning(BootsWarning):
1591+ """Raised when conflicting metacommand definitions are encountered."""
1592+ pass
1593+
1594+class InvalidArgumentError(MetaCommandError):
1595+ """Raised when a metacommand has an invalid argument."""
1596+
1597+def argument_count(func):
1598+ # Note: this can be fooled by things like *args
1599+ argspec = inspect.getargspec(func)
1600+ if argspec.varargs is not None:
1601+ return None
1602+ else:
1603+ argcount = len(argspec.args)
1604+ if type(func) is types.MethodType and func.im_self is not None:
1605+ argcount -= 1
1606+ return argcount
1607
1608 def parse_metacommand(commandstring):
1609 """This function wraps str.split() for metacommands
1610@@ -31,8 +56,8 @@
1611 to return a list of substrings, using whitespace as separator. The metacommand
1612 object uses this list to call a metacommand function and pass parameters.
1613
1614- """
1615- return commandstring.split()
1616+ """
1617+ return commandstring.rstrip(";\n").split()
1618
1619 class MetaCommandManager(object):
1620 def __init__(self):
1621@@ -44,7 +69,7 @@
1622 # FIXME: Issue warning through the UI using ui.print
1623 # FIXME: Determine the offending command(s) (set.intersect?)
1624 # FIXME: Print offending commands
1625- warnings.warn(_("Conflicts between metacommands detected."))
1626+ return MetaCommandConflictWarning(_("Conflicts between metacommands detected."))
1627 self.names |= newnames
1628
1629 class MetaCommands(object):
1630@@ -66,7 +91,7 @@
1631 def get_metacommand(self, command):
1632 commandlist = parse_metacommand(command)
1633 if len(commandlist) != 0 and commandlist[0] in self.commands:
1634- return self.commands[commandlist[0]], commandlist[1:]
1635+ return commandlist[0], self.commands[commandlist[0]], commandlist[1:]
1636
1637 def execute(self, command):
1638 """Parse and execute a metacommand string.
1639@@ -78,8 +103,14 @@
1640 """
1641 metacommand = self.get_metacommand(command)
1642 if metacommand:
1643- metacommand[0](*metacommand[1])
1644- # FIXME: Do we need to pass metacommand return values back?
1645- return True
1646+ name, func, args = metacommand
1647+ expected_arg_count = argument_count(func)
1648+ if expected_arg_count is not None and len(args) != expected_arg_count:
1649+ raise InvalidArgumentError(_("{0} takes {1} arguments ({2} given)").format(
1650+ name, expected_arg_count, len(args)))
1651+ else:
1652+ func(*args)
1653+ # FIXME: Do we need to pass metacommand return values back?
1654+ return True
1655 else:
1656 return False
1657
1658=== modified file 'boots/lib/ui/generic.py'
1659--- boots/lib/ui/generic.py 2010-02-27 05:40:10 +0000
1660+++ boots/lib/ui/generic.py 2010-03-07 09:23:23 +0000
1661@@ -28,6 +28,8 @@
1662 import os
1663 import StringIO
1664
1665+from boots.api.nodes.node import NodeGraph, SyncNode
1666+
1667 class StreamDriver(object):
1668 """StreamDrivers receive stream inputs to boots, stdin for example."""
1669 def __init__(self, console, stream, lingo):
1670@@ -36,6 +38,8 @@
1671 self.console = console
1672 self.stream = stream
1673 self.lingo = lingo
1674+ self.driver_graph = NodeGraph("streamdriver")
1675+ self.driver_graph.add(SyncNode(self.get_input()), output=True)
1676
1677 def get_input(self):
1678 """Gets user input from a stream."""
1679@@ -64,6 +68,8 @@
1680 def __init__(self, stream):
1681 """Initialize a StreamPresenter giving it the stream to write to."""
1682 self.stream = stream
1683+ self.presenter_graph = NodeGraph("streampresenter")
1684+ self.presenter_graph.add(SyncNode(self.present), input=True, output=True)
1685
1686 def present(self, row):
1687 """Prints row information in a "raw" format"""
1688
1689=== modified file 'boots/lib/ui/plain.py'
1690--- boots/lib/ui/plain.py 2010-03-02 00:45:59 +0000
1691+++ boots/lib/ui/plain.py 2010-03-07 09:23:23 +0000
1692@@ -28,13 +28,15 @@
1693 import os
1694 import time
1695 import readline
1696+import subprocess
1697+import threading
1698
1699-
1700-from boots.api.nodes.node import NodeGraph, SyncNode
1701+from boots.api.api import Rows, ResultInfo
1702+from boots.api.nodes.node import Status, NodeGraph, SyncNode, filter_none
1703 from boots.lib.ui.components.help import HelpTopic
1704-from boots.lib.ui.components.metacommands import MetaCommands, parse_metacommand
1705+from boots.lib.ui.components.metacommands import MetaCommandError, MetaCommands, parse_metacommand
1706 from boots.lib.ui.generic import StdinDriver, StdoutPresenter
1707-from boots.util import set_gettext
1708+from boots.lib import _, n_
1709
1710 class PlainUI(StdinDriver, StdoutPresenter):
1711 """Class that provides a 'plain' UI for boots. Input is taken on stdin,
1712@@ -42,11 +44,11 @@
1713 results are printed to stdout. These results are printed as tables when
1714 they are Server packets and as string interpretations otherwise."""
1715
1716- help = HelpTopic("plain", "Plain UI", _("Plain UI documentation."), _("""
1717- A simple, minimal user interface for Boots."""))
1718+ help = HelpTopic("plain", _("Plain UI"), _("Plain UI documentation."),
1719+ _("A simple, minimal user interface for Boots."))
1720
1721 help.add("commands", None, _("List of Plain UI commands."))
1722- help["commands"].add("\use", "use", _("Switch to a different lingo."))
1723+ help["commands"].add("\use", _("use"), _("Switch to a different lingo."))
1724
1725 def __init__(self, console):
1726 """Initialize a UI giving it its parent console, primary prompt,
1727@@ -61,16 +63,15 @@
1728 self.prompt2 = console.config["prompt2"]
1729 self.hist_file = console.config["history_file"]
1730 self.lingo = console.config["lingo"]
1731+ self.pager_command = console.config["pager_command"]
1732 self.last_desc = None
1733 self.buffer = []
1734
1735 self.driver_graph = NodeGraph("plaindriver")
1736- self.driver_graph.add_output(SyncNode(self.get_input))
1737+ self.driver_graph.add(SyncNode(self.get_input()), output=True)
1738
1739 self.presenter_graph = NodeGraph("plainpresenter")
1740- present_node = SyncNode(self.present)
1741- self.presenter_graph.add_input(present_node)
1742- self.presenter_graph.add_output(present_node)
1743+ self.presenter_graph.add(SyncNode(self.present, filter=filter_none), input=True, output=True)
1744
1745 readline.set_history_length(console.config["history_length"])
1746 self.read_history()
1747@@ -112,6 +113,8 @@
1748
1749 except EOFError:
1750 return
1751+ except MetaCommandError as e:
1752+ yield e
1753
1754 def set_prompt(self, prompt1 = None, prompt2 = None):
1755 """Change the prompts during execution of a PlainUI."""
1756@@ -125,6 +128,25 @@
1757 self.prompt1 = prompt1
1758 self.prompt2 = prompt2
1759
1760+ def print_with_pager(self, text):
1761+ try:
1762+ pager = subprocess.Popen(self.pager_command.split(),
1763+ shell=False,
1764+ stdin=subprocess.PIPE)
1765+ except:
1766+ sys.stdout.write(_("Unable to run pager command \"{0}\". Pager disabled.\n")
1767+ .format(self.pager_command))
1768+ self.pager_command = None
1769+ return False
1770+
1771+ try:
1772+ pager.communicate(text)
1773+ except IOError:
1774+ # IOError is raised sometimes with large outputs
1775+ pass
1776+
1777+ return True
1778+
1779 def present(self, result):
1780 """Print the result provided as an argument.
1781
1782@@ -135,42 +157,77 @@
1783 def padded(fields, widths):
1784 """Utility function used to convert rows from tuples to table rows.
1785 Results are returned as strings."""
1786- return "| {0} |\n".format(" | ".join(map(str.ljust, fields, widths)))
1787+ return "| {0} |".format(" | ".join(map(str.ljust, fields, widths)))
1788
1789 def show_NULL(value):
1790 """There is a 'bug' in the dbapi that does not convert NULL objects
1791 to the string 'NULL'. This utility function performs that
1792 conversion."""
1793 return value if value is not None else "NULL"
1794-
1795- if type(result) is dict and "__server_execute_sql_query" in result:
1796- self.last_desc = result["info"]
1797- if result["result"]:
1798- self.buffer.extend(result["result"])
1799- else:
1800- if self.buffer:
1801- max_widths = map(max, [(len(column[0]), column[2]) for column in self.last_desc])
1802- dashes = map(lambda x: "-"*(x+2), max_widths)
1803- sep_line = "+" + "+".join(dashes) + "+\n"
1804- current_time = time.time()
1805- info_line = "{0} "+_("rows in set")+" ({1:.2f} "+_("seconds")+").\n".format(len(self.buffer),
1806- current_time - result["begin_time"])
1807- names = (column[0] for column in self.last_desc)
1808- sys.stdout.write(sep_line)
1809- sys.stdout.write(padded(names, max_widths))
1810- sys.stdout.write(sep_line)
1811- for row in self.buffer:
1812- sys.stdout.write(padded(map(show_NULL, row), max_widths))
1813- sys.stdout.write(sep_line)
1814- sys.stdout.write(info_line)
1815- # Reset values for next result set.
1816- self.buffer = []
1817- else:
1818- if isinstance(result, Exception):
1819- sys.stdout.write(_("ERROR "))
1820- sys.stdout.write(" :: ".join(map(str, result.args)))
1821- else:
1822- sys.stdout.write(str(result))
1823+
1824+ def _gen_table(info):
1825+ if self.buffer:
1826+ max_widths = map(max, [(len(column[0]), column[2]) for column in info["description"]])
1827+ dashes = map(lambda x: "-"*(x+2), max_widths)
1828+ sep_line = "+" + "+".join(dashes) + "+"
1829+ names = (column[0] for column in info["description"])
1830+ yield sep_line
1831+ yield padded(names, max_widths)
1832+ yield sep_line
1833+ for row in self.buffer:
1834+ yield padded(map(show_NULL, row), max_widths)
1835+
1836+ yield sep_line
1837+
1838+ if self.console.driver.is_interactive:
1839+ elapsed = info["end_time"] - info["begin_time"]
1840+ noun = "row" if info["row_count"] == 1 else "rows"
1841+ if info["description"] is not None:
1842+ info_line = n_("{count} row in set ({elapsed:.2f} seconds)",
1843+ "{count} rows in set ({elapsed:.2f} seconds)",
1844+ info["row_count"])
1845+ else:
1846+ info_line = n_("{count} row affected ({elapsed:.2f} seconds)",
1847+ "{count} rows affected ({elapsed:.2f} seconds)",
1848+ info["row_count"])
1849+
1850+ yield info_line.format(count=info["row_count"],
1851+ noun=noun,
1852+ elapsed=elapsed)
1853+
1854+ if type(result) is Rows:
1855+ self.buffer.extend(result)
1856+ elif isinstance(result, ResultInfo):
1857+ printed = False
1858+ output = _gen_table(result.value)
1859+ if self.pager_command and self.console.driver.is_interactive:
1860+ printed = self.print_with_pager("\n".join(output))
1861+
1862+ # Fallback if no pager set, or paging fails.
1863+ if not printed:
1864+ for line in output:
1865+ sys.stdout.write(line)
1866+ sys.stdout.write("\n")
1867+
1868+ # Reset values for next result set.
1869+ self.buffer = []
1870+ elif isinstance(result, Status):
1871+ sys.stdout.write(_("Status"))
1872+ sys.stdout.write(" :: ")
1873+ sys.stdout.write(str(result))
1874+ sys.stdout.write("\n")
1875+ elif isinstance(result, Warning):
1876+ sys.stderr.write(_("WARNING"))
1877+ sys.stderr.write(" :: ")
1878+ sys.stderr.write(str(result))
1879+ sys.stderr.write("\n")
1880+ elif isinstance(result, Exception):
1881+ sys.stderr.write(_("ERROR"))
1882+ sys.stderr.write(" :: ")
1883+ sys.stderr.write(str(result))
1884+ sys.stderr.write("\n")
1885+ elif result is not None:
1886+ sys.stdout.write(str(result))
1887 sys.stdout.write("\n")
1888
1889 @property
1890@@ -186,4 +243,4 @@
1891 if lingo in self.console.lingos:
1892 self.lingo = lingo
1893 else:
1894- self.present(_("The specified lingo")+" \"{0}\" "+_("does not exist.").format(lingo))
1895+ self.present(_("The specified lingo \"{0}\" does not exist.").format(lingo))
1896
1897=== removed file 'boots/util.py'
1898--- boots/util.py 2010-03-02 01:04:23 +0000
1899+++ boots/util.py 1970-01-01 00:00:00 +0000
1900@@ -1,27 +0,0 @@
1901-# Boots Client Project
1902-# www.launchpad.net/boots
1903-#
1904-# ##### BEGIN LICENSE BLOCK #####
1905-#
1906-# Copyright (C) 2009-2010 Clark Boylan, Ken Brotherton, Max Goodman,
1907-# Victoria Lewis, David Rosenbaum, and Andreas Turriff
1908-#
1909-# This program is free software: you can redistribute it and/or modify
1910-# it under the terms of the GNU General Public License as published by
1911-# the Free Software Foundation, either version 3 of the License, or
1912-# (at your option) any later version.
1913-#
1914-# This program is distributed in the hope that it will be useful,
1915-# but WITHOUT ANY WARRANTY; without even the implied warranty of
1916-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1917-# GNU General Public License for more details.
1918-#
1919-# You should have received a copy of the GNU General Public License
1920-# along with this program. If not, see <http://www.gnu.org/licenses/>.
1921-#
1922-# ##### END LICENSE BLOCK #####
1923-
1924-import locale, gettext
1925-def set_gettext(mo_location='/usr/share/locale'):
1926- locale.setlocale(locale.LC_ALL)
1927- gettext.install('boots', mo_location)
1928
1929=== removed file 'localizations/potfiles.txt'
1930--- localizations/potfiles.txt 2010-03-02 01:04:23 +0000
1931+++ localizations/potfiles.txt 1970-01-01 00:00:00 +0000
1932@@ -1,12 +0,0 @@
1933-../boots/lib/console.py
1934-../boots/lib/ui/plain.py
1935-../boots/lib/ui/components/metacommands.py
1936-../boots/lib/ui/components/help.py
1937-../boots/lib/lingos/lingo.py
1938-../boots/lib/lingos/piped_sql.py
1939-../boots/lib/lingos/lisp/builtins.py
1940-../boots/lib/lingos/lisp/lexer.py
1941-../boots/lib/lingos/lisp/lisp.py
1942-../boots/lib/lingos/lisp/objects.py
1943-../boots/lib/lingos/lisp/parser.py
1944-../boots/app/client_config.py
1945
1946=== renamed directory 'localizations' => 'po'
1947=== modified file 'po/README.txt'
1948--- localizations/README.txt 2010-03-02 01:04:23 +0000
1949+++ po/README.txt 2010-03-07 09:23:23 +0000
1950@@ -1,22 +1,16 @@
1951-========When adding code that outputs a string========
1952-1) Add (if not present already) to the import section of the .py file
1953-#=========
1954-import gettext
1955-gettext.bindtextdomain("fslint", "/usr/share/locale") #sys default used if localedir=None
1956-gettext.textdomain("fslint")
1957-_ = gettext.gettext
1958-#=========
1959-And then wrap all output strings with _("...").
1960-You should do this so that if you are using dynamicly created content, that created content is not part of the wrapped string.
1961-Ex:
1962+====== When adding code that outputs a string ======
1963+1) Add (if not present already) to the import section of the .py file:
1964+
1965+Depending on the package the file is in:
1966+from boots.app import _, n_
1967+from boots.api import _, n_
1968+from boots.lib import _, n_
1969+
1970+Then, wrap all output strings with _("...").
1971+
1972+Example:
1973 help = "Execute commands from file and exit")
1974 should be wrapped as such:
1975 help = _("Execute commands from file and exit"))
1976-Ex:
1977-print("rcfile {0} contains a syntax error".format(filepath))
1978-should be wrapped as such:
1979-print(_("rcfile ")+"{0} "+_("contains a syntax error").format(filepath))
1980
1981-2) Add your file path to the /boots/localizations/potfiles.txt file.
1982-3) Generate the updated .pot file by running the /boots/localization/createpots.sh script. This will overwrite the existing pot.cms file. Any prevously generated .po .mo files can then be updated from this new file.
1983-4) Upload new pot file to the launchpad localization section for creation or updating of .po files. (more on this later --ken)
1984+2) Generate the updated .pot file by running the /boots/po/createpots.sh script. This will overwrite the existing pot.cms file. Any prevously generated .po .mo files can then be updated from this new file.
1985\ No newline at end of file
1986
1987=== modified file 'po/boots.pot'
1988--- localizations/boots.pot 2010-03-02 01:04:23 +0000
1989+++ po/boots.pot 2010-03-07 09:23:23 +0000
1990@@ -6,160 +6,115 @@
1991 #, fuzzy
1992 msgid ""
1993 msgstr ""
1994-"Project-Id-Version: PACKAGE VERSION\n"
1995-"Report-Msgid-Bugs-To: \n"
1996-"POT-Creation-Date: 2010-03-01 16:40-0800\n"
1997+"Project-Id-Version: boots\n"
1998+"Report-Msgid-Bugs-To: http://translations.launchpad.net/boots\n"
1999+"POT-Creation-Date: 2010-03-07 01:23-0800\n"
2000 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
2001 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
2002 "Language-Team: LANGUAGE <LL@li.org>\n"
2003 "MIME-Version: 1.0\n"
2004 "Content-Type: text/plain; charset=CHARSET\n"
2005 "Content-Transfer-Encoding: 8bit\n"
2006-
2007-#: ../boots/lib/console.py:96
2008-msgid ""
2009-"\n"
2010-" Boots is a flexible, extensible, and multilingual shell for "
2011-"working with databases. To read more about a subtopic, use `help <topic>`."
2012-msgstr ""
2013-
2014-#: ../boots/lib/console.py:100
2015-msgid "List of Boots commands."
2016-msgstr ""
2017-
2018-#: ../boots/lib/console.py:103
2019-msgid "Quit boots."
2020-msgstr ""
2021-
2022-#: ../boots/lib/console.py:104
2023-msgid "Show help for a topic."
2024-msgstr ""
2025-
2026-#: ../boots/lib/console.py:104
2027-msgid ""
2028-"\n"
2029-" help <topic>\n"
2030-" Show help for \"topic\"."
2031-msgstr ""
2032-
2033-#: ../boots/lib/console.py:108
2034-msgid "Documentation for loaded lingos."
2035-msgstr ""
2036-
2037-#: ../boots/lib/console.py:108
2038-msgid ""
2039-"\n"
2040-" A lingo is a command language usable within Boots."
2041-msgstr ""
2042-
2043-#: ../boots/lib/console.py:123
2044-msgid "Invalid lingo"
2045-msgstr ""
2046-
2047-#: ../boots/lib/console.py:123
2048-msgid "specified."
2049-msgstr ""
2050-
2051-#: ../boots/lib/console.py:136
2052-msgid "Could not connect to"
2053-msgstr ""
2054-
2055-#: ../boots/lib/console.py:156
2056-msgid "server"
2057-msgstr ""
2058-
2059-#: ../boots/lib/console.py:189
2060-msgid "Boots quit."
2061-msgstr ""
2062-
2063-#: ../boots/lib/console.py:207
2064-msgid "Did you mean:"
2065-msgstr ""
2066-
2067-#: ../boots/lib/console.py:209
2068-msgid "No help found for"
2069-msgstr ""
2070-
2071-#: ../boots/lib/ui/plain.py:45
2072-msgid "Plain UI documentation."
2073-msgstr ""
2074-
2075-#: ../boots/lib/ui/plain.py:45
2076-msgid ""
2077-"\n"
2078-" A simple, minimal user interface for Boots."
2079-msgstr ""
2080-
2081-#: ../boots/lib/ui/plain.py:48
2082-msgid "List of Plain UI commands."
2083-msgstr ""
2084-
2085-#: ../boots/lib/ui/plain.py:49
2086-msgid "Switch to a different lingo."
2087-msgstr ""
2088-
2089-#: ../boots/lib/ui/plain.py:156
2090-msgid "rows in set"
2091-msgstr ""
2092-
2093-#: ../boots/lib/ui/plain.py:156
2094-msgid "seconds"
2095-msgstr ""
2096-
2097-#: ../boots/lib/ui/plain.py:170
2098-msgid "ERROR "
2099-msgstr ""
2100-
2101-#: ../boots/lib/ui/plain.py:189
2102-msgid "The specified lingo"
2103-msgstr ""
2104-
2105-#: ../boots/lib/ui/plain.py:189
2106-msgid "does not exist."
2107-msgstr ""
2108-
2109-#: ../boots/lib/ui/components/metacommands.py:47
2110-msgid "Conflicts between metacommands detected."
2111-msgstr ""
2112-
2113-#: ../boots/lib/ui/components/help.py:68
2114-msgid "See also:"
2115-msgstr ""
2116-
2117-#: ../boots/lib/ui/components/help.py:72
2118-msgid "Subtopics"
2119-msgstr ""
2120-
2121-#: ../boots/lib/ui/components/help.py:106
2122-msgid "query object"
2123-msgstr ""
2124-
2125-#: ../boots/lib/ui/components/help.py:106
2126-msgid "is not a string or tuple of strings"
2127-msgstr ""
2128-
2129-#: ../boots/lib/lingos/lingo.py:36
2130-msgid "A lingo with name"
2131-msgstr ""
2132-
2133-#: ../boots/lib/lingos/lingo.py:36
2134-msgid "already exists"
2135-msgstr ""
2136-
2137-#: ../boots/lib/lingos/piped_sql.py:45
2138-msgid "Enhanced SQL query language supporting pipes."
2139-msgstr ""
2140-
2141-#: ../boots/lib/lingos/piped_sql.py:57 ../boots/lib/lingos/piped_sql.py:68
2142-msgid "is not in the correct function call syntax"
2143-msgstr ""
2144-
2145-#: ../boots/lib/lingos/piped_sql.py:95
2146-msgid "error1"
2147-msgstr ""
2148-
2149-#: ../boots/lib/lingos/piped_sql.py:107
2150-msgid "SQL is only permitted for the first clause"
2151+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
2152+
2153+#: ../boots/api/api.py:89
2154+msgid "Could not connect to {0}"
2155+msgstr ""
2156+
2157+#: ../boots/api/api.py:101
2158+msgid "Connection closed"
2159+msgstr ""
2160+
2161+#: ../boots/api/api.py:124
2162+msgid "Lost connection to {0}. Reconnecting..."
2163+msgstr ""
2164+
2165+#: ../boots/api/api.py:136
2166+msgid "Reconnected."
2167+msgstr ""
2168+
2169+#: ../boots/api/constructors.py:36
2170+msgid "A constructor with name {0} already exists"
2171+msgstr ""
2172+
2173+#: ../boots/api/constructors.py:47
2174+msgid "There is no constructor with the name {0}."
2175+msgstr ""
2176+
2177+#: ../boots/api/errors.py:53
2178+msgid "Lost connection to {0}"
2179+msgstr ""
2180+
2181+#: ../boots/api/errors.py:58
2182+msgid "(Exception upon reconnect: {0})"
2183+msgstr ""
2184+
2185+#: ../boots/app/client_config.py:93
2186+msgid "Execute command and exit"
2187+msgstr ""
2188+
2189+#: ../boots/app/client_config.py:98
2190+msgid "Use database"
2191+msgstr ""
2192+
2193+#: ../boots/app/client_config.py:103
2194+msgid "Execute commands from file and exit"
2195+msgstr ""
2196+
2197+#: ../boots/app/client_config.py:108
2198+msgid "Set the lingo to use"
2199+msgstr ""
2200+
2201+#: ../boots/app/client_config.py:112
2202+msgid "Do not read user configuration file"
2203+msgstr ""
2204+
2205+#: ../boots/app/client_config.py:117
2206+msgid "Filename of user configuration file"
2207+msgstr ""
2208+
2209+#: ../boots/app/client_config.py:122
2210+msgid "Connect to host"
2211+msgstr ""
2212+
2213+#: ../boots/app/client_config.py:127
2214+msgid "Use port number"
2215+msgstr ""
2216+
2217+#: ../boots/app/client_config.py:132
2218+msgid "Login with username"
2219+msgstr ""
2220+
2221+#: ../boots/app/client_config.py:137
2222+msgid "Connect using password. If none is given, query for password"
2223+msgstr ""
2224+
2225+#: ../boots/app/client_config.py:142
2226+msgid "Pipe query results to the specified pager."
2227+msgstr ""
2228+
2229+#: ../boots/app/client_config.py:147
2230+msgid "Specify the SQL statement terminating character. Default is ';'."
2231+msgstr ""
2232+
2233+#: ../boots/app/client_config.py:152
2234+msgid "Specify file to save history to"
2235+msgstr ""
2236+
2237+#: ../boots/app/client_config.py:157
2238+msgid "Specify max history file length"
2239+msgstr ""
2240+
2241+#: ../boots/app/client_config.py:205
2242+msgid "rcfile {0} not found"
2243+msgstr ""
2244+
2245+#: ../boots/app/client_config.py:207
2246+msgid "rcfile {0} contains a syntax error"
2247+msgstr ""
2248+
2249+#: ../boots/app/client_config.py:209
2250+msgid "rcfile {0} contains an error: {1}"
2251 msgstr ""
2252
2253 #: ../boots/lib/lingos/lisp/builtins.py:62
2254@@ -170,20 +125,20 @@
2255 msgid "Expected a cons or string"
2256 msgstr ""
2257
2258-#: ../boots/lib/lingos/lisp/lexer.py:38
2259+#: ../boots/lib/lingos/lisp/lexer.py:39
2260 msgid "illegal character {0} found"
2261 msgstr ""
2262
2263-#: ../boots/lib/lingos/lisp/lisp.py:61
2264+#: ../boots/lib/lingos/lisp/lisp.py:58
2265 msgid "unmatched closing \")\""
2266 msgstr ""
2267
2268-#: ../boots/lib/lingos/lisp/lisp.py:80
2269-msgid "is not a stream or a callable"
2270+#: ../boots/lib/lingos/lisp/lisp.py:77
2271+msgid "{0} is not a stream or a callable"
2272 msgstr ""
2273
2274 #: ../boots/lib/lingos/lisp/objects.py:101
2275-msgid "wrong number of arguments for if special form"
2276+msgid "Wrong number of arguments for if special form {0}"
2277 msgstr ""
2278
2279 #: ../boots/lib/lingos/lisp/objects.py:120
2280@@ -201,81 +156,221 @@
2281 msgstr ""
2282
2283 #: ../boots/lib/lingos/lisp/objects.py:175
2284-msgid "No binding for"
2285-msgstr ""
2286-
2287-#: ../boots/lib/lingos/lisp/objects.py:175
2288-msgid "exists in the current environment"
2289+msgid "No binding for {0} exists in the current environment"
2290 msgstr ""
2291
2292 #: ../boots/lib/lingos/lisp/objects.py:220
2293 msgid "Cannot pop the innermost scope because then no scopes would remain"
2294 msgstr ""
2295
2296-#: ../boots/lib/lingos/lisp/parser.py:64
2297+#: ../boots/lib/lingos/lisp/parser.py:65
2298 msgid "syntax error"
2299 msgstr ""
2300
2301-#: ../boots/app/client_config.py:68
2302-msgid "Execute command and exit"
2303-msgstr ""
2304-
2305-#: ../boots/app/client_config.py:73
2306-msgid "Use database"
2307-msgstr ""
2308-
2309-#: ../boots/app/client_config.py:78
2310-msgid "Execute commands from file and exit"
2311-msgstr ""
2312-
2313-#: ../boots/app/client_config.py:83
2314-msgid "Set the lingo to use"
2315-msgstr ""
2316-
2317-#: ../boots/app/client_config.py:87
2318-msgid "Do not read user configuration file"
2319-msgstr ""
2320-
2321-#: ../boots/app/client_config.py:92
2322-msgid "Filename of user configuration file"
2323-msgstr ""
2324-
2325-#: ../boots/app/client_config.py:97
2326-msgid "Connect to host"
2327-msgstr ""
2328-
2329-#: ../boots/app/client_config.py:102
2330-msgid "Use port number"
2331-msgstr ""
2332-
2333-#: ../boots/app/client_config.py:107
2334-msgid "Login with username"
2335-msgstr ""
2336-
2337-#: ../boots/app/client_config.py:112
2338-msgid "Connect using password. If none is given, query for password"
2339-msgstr ""
2340-
2341-#: ../boots/app/client_config.py:117
2342-msgid "Specify the SQL statement terminating character. Default is ';'."
2343-msgstr ""
2344-
2345-#: ../boots/app/client_config.py:122
2346-msgid "Specify file to save history to"
2347-msgstr ""
2348-
2349-#: ../boots/app/client_config.py:127
2350-msgid "Specify max history file length"
2351-msgstr ""
2352-
2353-#: ../boots/app/client_config.py:167
2354-msgid "not found"
2355-msgstr ""
2356-
2357-#: ../boots/app/client_config.py:169
2358-msgid "contains a syntax error"
2359-msgstr ""
2360-
2361-#: ../boots/app/client_config.py:171
2362-msgid "contains an error:"
2363+#: ../boots/lib/lingos/bash_external.py:33
2364+msgid "Bash Lingo"
2365+msgstr ""
2366+
2367+#: ../boots/lib/lingos/bash_external.py:33
2368+msgid "External bash shell."
2369+msgstr ""
2370+
2371+#: ../boots/lib/lingos/lingo.py:36
2372+msgid "A lingo with name {0} already exists"
2373+msgstr ""
2374+
2375+#: ../boots/lib/lingos/sql.py:30
2376+msgid "SQL Lingo"
2377+msgstr ""
2378+
2379+#: ../boots/lib/lingos/sql.py:30
2380+msgid "Raw SQL commands sent to a server."
2381+msgstr ""
2382+
2383+#: ../boots/lib/lingos/python.py:36
2384+msgid "Python Lingo"
2385+msgstr ""
2386+
2387+#: ../boots/lib/lingos/python.py:36
2388+msgid "Integrated Python interpreter using the Boots API."
2389+msgstr ""
2390+
2391+#: ../boots/lib/lingos/piped_sql.py:47
2392+msgid "Piped SQL Lingo"
2393+msgstr ""
2394+
2395+#: ../boots/lib/lingos/piped_sql.py:47
2396+msgid "Enhanced SQL query language supporting pipes."
2397+msgstr ""
2398+
2399+#: ../boots/lib/lingos/piped_sql.py:59 ../boots/lib/lingos/piped_sql.py:70
2400+msgid "{0} is not in the correct function call syntax"
2401+msgstr ""
2402+
2403+#: ../boots/lib/lingos/piped_sql.py:97
2404+msgid "error1"
2405+msgstr ""
2406+
2407+#: ../boots/lib/lingos/piped_sql.py:109
2408+msgid "SQL is only permitted for the first clause"
2409+msgstr ""
2410+
2411+#: ../boots/lib/ui/components/help.py:68
2412+msgid "See also: {0.see_also}"
2413+msgstr ""
2414+
2415+#: ../boots/lib/ui/components/help.py:72
2416+msgid "Subtopics"
2417+msgstr ""
2418+
2419+#: ../boots/lib/ui/components/help.py:106
2420+msgid "query object {0} is not a string or tuple of strings"
2421+msgstr ""
2422+
2423+#: ../boots/lib/ui/components/metacommands.py:72
2424+msgid "Conflicts between metacommands detected."
2425+msgstr ""
2426+
2427+#: ../boots/lib/ui/components/metacommands.py:109
2428+msgid "{0} takes {1} arguments ({2} given)"
2429+msgstr ""
2430+
2431+#: ../boots/lib/ui/plain.py:47
2432+msgid "Plain UI"
2433+msgstr ""
2434+
2435+#: ../boots/lib/ui/plain.py:47
2436+msgid "Plain UI documentation."
2437+msgstr ""
2438+
2439+#: ../boots/lib/ui/plain.py:48
2440+msgid "A simple, minimal user interface for Boots."
2441+msgstr ""
2442+
2443+#: ../boots/lib/ui/plain.py:50
2444+msgid "List of Plain UI commands."
2445+msgstr ""
2446+
2447+#: ../boots/lib/ui/plain.py:51
2448+msgid "use"
2449+msgstr ""
2450+
2451+#: ../boots/lib/ui/plain.py:51
2452+msgid "Switch to a different lingo."
2453+msgstr ""
2454+
2455+#: ../boots/lib/ui/plain.py:137
2456+msgid "Unable to run pager command \"{0}\". Pager disabled.\n"
2457+msgstr ""
2458+
2459+#: ../boots/lib/ui/plain.py:186
2460+msgid "{count} row in set ({elapsed:.2f} seconds)"
2461+msgid_plural "{count} rows in set ({elapsed:.2f} seconds)"
2462+msgstr[0] ""
2463+msgstr[1] ""
2464+
2465+#: ../boots/lib/ui/plain.py:190
2466+msgid "{count} row affected ({elapsed:.2f} seconds)"
2467+msgid_plural "{count} rows affected ({elapsed:.2f} seconds)"
2468+msgstr[0] ""
2469+msgstr[1] ""
2470+
2471+#: ../boots/lib/ui/plain.py:215
2472+msgid "Status"
2473+msgstr ""
2474+
2475+#: ../boots/lib/ui/plain.py:220
2476+msgid "WARNING"
2477+msgstr ""
2478+
2479+#: ../boots/lib/ui/plain.py:225
2480+msgid "ERROR"
2481+msgstr ""
2482+
2483+#: ../boots/lib/ui/plain.py:246
2484+msgid "The specified lingo \"{0}\" does not exist."
2485+msgstr ""
2486+
2487+#: ../boots/lib/console.py:69
2488+msgid "Boots encountered an internal error: {0}"
2489+msgstr ""
2490+
2491+#: ../boots/lib/console.py:119
2492+msgid "Boots Help"
2493+msgstr ""
2494+
2495+#: ../boots/lib/console.py:119
2496+msgid "Help"
2497+msgstr ""
2498+
2499+#: ../boots/lib/console.py:120
2500+msgid ""
2501+"Boots is a flexible, extensible, and multilingual shell for working with "
2502+"databases. To read more about a subtopic, use `help <topic>`."
2503+msgstr ""
2504+
2505+#: ../boots/lib/console.py:123
2506+msgid "List of Boots commands."
2507+msgstr ""
2508+
2509+#: ../boots/lib/console.py:126
2510+msgid "quit"
2511+msgstr ""
2512+
2513+#: ../boots/lib/console.py:126
2514+msgid "Quit boots."
2515+msgstr ""
2516+
2517+#: ../boots/lib/console.py:127
2518+msgid "help"
2519+msgstr ""
2520+
2521+#: ../boots/lib/console.py:127
2522+msgid "Show help for a topic."
2523+msgstr ""
2524+
2525+#: ../boots/lib/console.py:128
2526+msgid ""
2527+"help <topic>\n"
2528+"Show help for \"topic\"."
2529+msgstr ""
2530+
2531+#: ../boots/lib/console.py:131
2532+msgid "Lingos"
2533+msgstr ""
2534+
2535+#: ../boots/lib/console.py:131
2536+msgid "Documentation for loaded lingos."
2537+msgstr ""
2538+
2539+#: ../boots/lib/console.py:132
2540+msgid "A lingo is a command language usable within Boots."
2541+msgstr ""
2542+
2543+#: ../boots/lib/console.py:144
2544+msgid "Invalid lingo \"{0}\" specified."
2545+msgstr ""
2546+
2547+#: ../boots/lib/console.py:173
2548+msgid "Could not connect to {0}:{1}"
2549+msgstr ""
2550+
2551+#: ../boots/lib/console.py:192
2552+msgid "{0.hostname}:{0.port} (server v{0.server_version})"
2553+msgstr ""
2554+
2555+#: ../boots/lib/console.py:227
2556+msgid "Boots quit."
2557+msgstr ""
2558+
2559+#: ../boots/lib/console.py:245
2560+msgid "Did you mean: {0}?"
2561+msgstr ""
2562+
2563+#: ../boots/lib/console.py:247
2564+msgid "No help found for \"{0}\"."
2565+msgstr ""
2566+
2567+#: ../boots/lib/console.py:276
2568+msgid "Could not open file {0}"
2569 msgstr ""
2570
2571=== modified file 'po/createpots.sh'
2572--- localizations/createpots.sh 2010-03-02 01:04:23 +0000
2573+++ po/createpots.sh 2010-03-07 09:23:23 +0000
2574@@ -1,3 +1,3 @@
2575 #!/bin/bash
2576-xgettext --from-code=utf-8 --keyword=tr --default-domain=cms --output=boots.pot --files-from=potfiles.txt
2577+find ../boots/ -name *.py | xargs xgettext --language=Python --keyword="n_:1,2" --output=boots.pot --package-name="boots" --msgid-bugs-address="http://translations.launchpad.net/boots"
2578
2579
2580=== modified file 'tests/boots/api/api_tests.py'
2581--- tests/boots/api/api_tests.py 2010-02-27 05:40:10 +0000
2582+++ tests/boots/api/api_tests.py 2010-03-07 09:23:23 +0000
2583@@ -28,7 +28,7 @@
2584 import boots_unit_test
2585
2586 class TestServerConnections(boots_unit_test.BootsQueryTester):
2587- """Class that provides unit tests that test the api.Server class' ability
2588+ """Class that provides unit tests that test the api.DrizzleServer class' ability
2589 to connect to servers as well as provide proper errors when connections
2590 should fail."""
2591 #FIXME should use the configuration provided.
2592@@ -38,54 +38,54 @@
2593 pass
2594
2595 def test_valid_connect_fqdn(self):
2596- server = api.Server("capstonedd.cs.pdx.edu", 9306, {})
2597+ server = api.DrizzleServer("capstonedd.cs.pdx.edu", 9306, {})
2598 server.connect()
2599 self.assert_(server.is_connected)
2600 server.disconnect()
2601
2602 def test_valid_connect_partial(self):
2603- server = api.Server("capstonedd", 9306, {})
2604+ server = api.DrizzleServer("capstonedd", 9306, {})
2605 server.connect()
2606 self.assert_(server.is_connected)
2607 server.disconnect()
2608
2609 def test_valid_connect_ip(self):
2610- server = api.Server("131.252.214.178", 9306, {})
2611+ server = api.DrizzleServer("131.252.214.178", 9306, {})
2612 server.connect()
2613 self.assert_(server.is_connected)
2614 server.disconnect()
2615
2616 def test_valid_connect_fqdn_with_db(self):
2617 boots_unit_test.BootsQueryTester.setUp(self)
2618- server = api.Server("capstonedd.cs.pdx.edu", 9306, {"database": "fec"})
2619+ server = api.DrizzleServer("capstonedd.cs.pdx.edu", 9306, {"database": "fec"})
2620 server.connect()
2621 self.assert_(server.is_connected)
2622 server.disconnect()
2623
2624 def test_invalid_connect(self):
2625- server = api.Server("kororaa.cs.pdx.edu", 9306, {})
2626+ server = api.DrizzleServer("kororaa.cs.pdx.edu", 9306, {})
2627 self.assertRaises(errors.InterfaceError, server.connect)
2628 self.assert_(not server.is_connected)
2629
2630 def test_valid_disconnect(self):
2631- server = api.Server("capstonedd.cs.pdx.edu", 9306, {})
2632+ server = api.DrizzleServer("capstonedd.cs.pdx.edu", 9306, {})
2633 server.connect()
2634 server.disconnect()
2635 self.assert_(not server.is_connected)
2636
2637 def test_invalid_disconnect(self):
2638- server = api.Server("kororaa.cs.pdx.edu", 9306, {})
2639+ server = api.DrizzleServer("kororaa.cs.pdx.edu", 9306, {})
2640 self.assertRaises(errors.InterfaceError, server.connect)
2641 self.assertRaises(AttributeError, server.disconnect)
2642 self.assert_(not server.is_connected)
2643
2644 class TestServerExecute(boots_unit_test.BootsQueryTester):
2645- """Class that provides unit tests that tests api.Server class' ability
2646+ """Class that provides unit tests that tests api.DrizzleServer class' ability
2647 to execute SQL statements on a server."""
2648 #FIXME needs to test more than just SELECT statements.
2649 def setUp(self):
2650 boots_unit_test.BootsQueryTester.setUp(self)
2651- self.server = api.Server(self.config["host"], self.config["port"], {"database": self.config["database"]})
2652+ self.server = api.DrizzleServer(self.config["host"], self.config["port"], {"database": self.config["database"]})
2653 self.server.connect()
2654
2655 def tearDown(self):
2656
2657=== removed file 'tests/boots/lib/lingos/cand_correct.txt'
2658--- tests/boots/lib/lingos/cand_correct.txt 2010-02-21 21:24:59 +0000
2659+++ tests/boots/lib/lingos/cand_correct.txt 1970-01-01 00:00:00 +0000
2660@@ -1,256 +0,0 @@
2661-H0AK00089,CRAWFORD, HARRY T JR,H,AK,DEM,4350 BUTTE CIR,ANCHORAGE,AK,99504
2662-H0AL00016,BOZEMAN, MARTHA RENEE,H,AL,UNK,PO BOX 2512,BIRMINGHAM,AL,35201
2663-H0AL01030,GOUNARES, PETER HUNTER,H,AL,REP,4881 CYPRESS VILLAGE BLVD UNIT E,ORANGE BEACH,AL,36561
2664-H0AL02095,JOHN, ROBERT E JR,H,AL,IND,1465 W OVERBROOK ROAD,MILLBROOK,AL,36054
2665-H0AL02103,BARBER, RICK JOE,H,AL,REP,211 ARROWHEAD DRIVE,MONTGOMERY,AL,36117
2666-H0AL05163,BROOKS, MO,H,AL,REP,7610 FOXFIRE DRIVE,HUNTSVILLE,AL,35802
2667-H0AL06088,COOKE, STANLEY KYLE,H,AL,REP,723 CHERRY BROOK ROAD,KIMBERLY,AL,35091
2668-H0AL06096,LAMBERT, PAUL ANTHONY,H,AL,REP,POST OFFICE BOX 244,MAYLENE,AL,35114
2669-H0AL07086,SEWELL, TERRYCINA ANDREA,H,AL,DEM,PO BOX 1964,BIRMINGHAM,AL,35201
2670-H0AL07094,HILLIARD, EARL FREDERICK JR,H,AL,DEM,PO BOX 12804,BIRMINGHAM,AL,35202
2671-H0AL07102,SMOOT, SHEILA,H,AL,DEM,PO BOX 1354,BIRMINGHAM,AL,35201
2672-H0AL07128,MOKOLO, PATRICIA EVANS,H,AL,DEM,15 EL DORADO EAST,TUSCALOOSA,AL,35405
2673-H0AL07136,LANKSTER, FRANK,H,AL,DEM,1000 COATS AVE EAST,LINDEN,AL,367481608
2674-H0AL07144,WALLER, MICHELE,H,AL,REP,PO BOX 10711,BIRMINGHAM,AL,35202
2675-H0AR01083,CRAWFORD, ERIC ALAN RICK,H,AR,REP,34 CR 455,JONESBORO,AR,72404
2676-H0AR01091,GREGORY, JAMES CHRISTOPHER,H,AR,DEM,510 S LILLY ST,BLYTHEVILLE,AR,72315
2677-H0AR02099,MEEKS, DAVID MARK EMERSON,H,AR,REP,3130 DAVE WARD DR,CONWAY,AR,72034
2678-H0AR02107,GRIFFIN, JOHN TIMOTHY,H,AR,REP,1819 NORTH TYLER STREET,LITTLE ROCK,AR,72217
2679-H0AR02115,WALLACE, SCOTT,H,AR,REP,PO BOX 242600,LITTLE ROCK,AR,72223
2680-H0AR03022,SKOCH, BERNARD KURT BERNIE'',H,AR,REP,21142 KIRKSEY ROAD,ELKINS,AR,72727
2681-H0AR03030,WHITAKER, DAVID JEFFREY,H,AR,DEM,PO BOX 957,FAYETTEVILLE,AR,727020957
2682-H0AR04038,ROSS, MICHAEL AVERY,H,AR,DEM,PO BOX 360,PRESCOTT,AR,71857
2683-H0AS00018,FALEOMAVAEGA, ENI,H,AS,DEM,PO BOX 44669,WASHINGTON,DC,20026
2684-H0AZ01184,FLAKE, JEFF MR.,H,AZ,REP,4222 E. MCLELLAN, NO. 19,MESA,AZ,85205
2685-H0AZ01259,GOSAR, PAUL ANTHONY,H,AZ,REP,7485 RAIN VALLEY RD,FLAGSTAFF,AZ,86004
2686-H0AZ01267,BEAUCHAMP, BRADLEY DON,H,AZ,REP,PO BOX 222,GLOBE ,AZ,85502
2687-H0AZ01275,BOWERS, RUSSELL WESLEY,H,AZ,REP,PO BOX 336,SUPERIOR,AZ,85173
2688-H0AZ03305,HULBURD, JON,H,AZ,DEM,4340 E INDIAN SCHOOL RD #21-467,PHOENIX,AZ,85018
2689-H0AZ04485,HILL, BRIAN,H,AZ,IND,PO BOX 6013,PHOENIX,AZ,85005
2690-H0AZ05078,WARD, JIM,H,AZ,REP,9342 EAST SANDS DRIVE,SCOTTSDALE,AZ,85255
2691-H0AZ05086,WNUCK, ERIC,H,AZ,REP,8630 E WINDROSE,SCOTTSDALE,AZ,85260
2692-H0AZ05094,SMITH, JEFFREY W,H,AZ,REP,3713 E ENCINAS AVE,GILBERT,AZ,85234
2693-H0AZ05102,SALVINO, CHRIS,H,AZ,REP,7694 E ROSE GARDEN LANE,SCOTTSDALE,AZ,85255
2694-H0AZ06043,KELSEY, EASTON CLINT,H,AZ,REP,3927 S RIM RD,GILBERT,AZ,85297
2695-H0AZ07017,MCCLUNG, RUTH CRAWFORD,H,AZ,REP,3963 W PROSPERITY MINE PL,TUCSON,AZ,85745
2696-H0AZ08015,KELLY, JESSE,H,AZ,REP,7481 W PHOBOS DR,TUCSON,AZ,85743
2697-H0AZ08023,GOSS, VINCENT ANDREW (ANDY),H,AZ,REP,4617 TERRITORIAL LP,SIERRA VISTA,AZ,85635
2698-H0AZ08031,MILLER, BRIAN ALLAN,H,AZ,REP,PO BOX 15023,TUCSON,AZ,857085023
2699-H0AZ08049,CARLSON, THOMAS A JR,H,AZ,REP,9598 N ELAN LANE,TUCSON,AZ,85742
2700-H0CA00066,FINK, MARI HAMLIN,H,CA,REP,3410 BANGOR PLACE,SAN DIEGO,CA,92106
2701-H0CA02120,STIGLICH, PETER VINCENT,H,CA,REP,14684 SINGING TREES LANE,COTTONWOOD,CA,96022
2702-H0CA03078,BERA, AMERIASH,H,CA,DEM,61707 PIRATE POINT CT,ELK GROVE,CA,95758
2703-H0CA03086,DAVIS, GARY,H,CA,DEM,510 BERCUT DRIVE SUITE S,SACRAMENTO,CA,95811
2704-H0CA03094,SLATON, BILL,H,CA,DEM,555 CAPITOL MALL SUITE 1425,SACRAMENTO,CA,95814
2705-H0CA06089,ROMANOWSKY, PETER CHRISTIAN,H,CA,REP,300 NAPA ST #40,SAUSACITO,CA,94965
2706-H0CA08069,DENNIS, JOHN,H,CA,REP,1592 UNION STREET,SAN FRANCISCO,CA,941234531
2707-H0CA08077,SHIELDS, SUMMER J,H,CA,DEM,PO BOX 882472,SAN FRANCISCO,CA,94188
2708-H0CA10073,DESAULNIER, MARK,H,CA,DEM,POST OFFICE BOX 6066,CONCORD,CA,94524
2709-H0CA10081,HAMPTON, ADRIEL,H,CA,DEM,5425 DE MARCUS BLVD., APT 104,DUBLIN,CA,94568
2710-H0CA10099,BUCHANAN, JOAN,H,CA,DEM,555 CAPITOL MALL, SUITE 1425,SACRAMENTO,CA,95814
2711-H0CA10107,WOODS, ANTHONY MR,H,CA,DEM,PO BOX 28,FAIRFIELD,CA,94533
2712-H0CA10115,VANGUNDY, GINO W,H,CA,IND,1500 OLIVER ROAD #K259,FAIRFIELD,CA,94533
2713-H0CA10123,HARMER, DAVID JEFFREY,H,CA,REP,9321 SILVERBEND LANE,ELK GROVE,CA,95624
2714-H0CA10131,ATTWOOD, TIFFANY,H,CA,DEM,939 RICHARD LANE,DANVILLE,CA,94526
2715-H0CA10149,GARAMENDI, JOHN,H,CA,DEM,C/O CALIFORNIA POLITICAL LAW, INC.,LONG BEACH,CA,90807
2716-H0CA10156,BUNCH, CHRISTOPHER N,H,CA,REP,1652 W TEXAS ST SUITE 258,FAIRFIELD,CA,94533
2717-H0CA10164,CLOWARD, JEREMY,H,CA,GRE,1713 MARY DRIVE,PLEASANT HILL,CA,94523
2718-H0CA10180,CLIFT, GARY WILLIAM,H,CA,REP,PO BOX 841,DIXON,CA,95620
2719-H0CA10198,LOOS, MARK ALAN,H,CA,REP,5631 CARNEGIE WAY,LIVERMORE,CA,94550
2720-H0CA10206,TOTH, JOHN RICHARD,H,CA,REP,2270 BACON STREET,CONCORD,CA,94520
2721-H0CA11295,DEL ARROZ, JONATHAN MR.,H,CA,REP,656 TUNBRIDGE ROAD,DANVILLE,CA,945263651
2722-H0CA11303,GOEHRING, BRAD,H,CA,REP,21500 CLEMENTS ROAD,ACAMPO,CA,95220
2723-H0CA11329,BEADLES, ROBERT,H,CA,REP,1040 W KETTLEMAN LANE #388,LODI,CA,95240
2724-H0CA11337,AMADOR, ANTONIO C,H,CA,REP,30151 TOMAS,RCHO STA MARGARITA,CA,92688
2725-H0CA11345,TAKADA, JEFFREY DAVID,H,CA,REP,1081 BRENDA LEE DRIVE,MANTECA,CA,95337
2726-H0CA11352,EMKEN, ELIZABETH,H,CA,REP,243 MORRIS RANCH COURT,DANVILLE,CA,94526
2727-H0CA15148,HONDA, MIKE,H,CA,DEM,P.O. BOX 8180,SAN JOSE,CA,95155
2728-H0CA15171,SIMITIAN, S. JOSEPH,H,CA,DEM,2059 CAMDEN AVENUE #281,SAN JOSE,CA,95124
2729-H0CA15189,BARICH, DON,H,CA,REP,1071 WILMINGTON AVE,SAN JOSE,CA,95129
2730-H0CA16088,HOWELL, ROBERT PAUL,H,CA,REP,1145 ARDSLEY CT,SAN JOSE,CA,951201783
2731-H0CA18050,BERRYHILL, MICHAEL CLARE SR,H,CA,REP,1842 EAST TAYLOR ROAD,CERES,CA,95307
2732-H0CA19124,MARSDEN, LES,H,CA,DEM,7145 SNYDER CREEK ROAD,MARIPOSA,CA,953389641
2733-H0CA19132,GOODWIN, LORAINE,H,CA,DEM,1009 W FOURTH STREET,MADERA,CA,93637
2734-H0CA19173,DENHAM, JEFF,H,CA,REP,941 E MONTE VISTA,TURLOCK,CA,95381
2735-H0CA20080,MILLER, JOSHUA THOMAS COULSTON,H,CA,REP,PO BOX 711,HANFORD,CA,93277
2736-H0CA20098,VIDAK, JAMES ANDREW,H,CA,REP,13775 LACY BLVD,VISALIA,CA,93230
2737-H0CA20114,LAKE, RICHARD DAVID GEORGE,H,CA,REP,7005 N MAPLE AVE SUITE 101,FRESNO,CA,93720
2738-H0CA23043,KALEMKARIAN, TIMOTHY CHARLES,H,CA,REP,PO BOX 3272,WESTLAKE VILLAGE,CA,91359
2739-H0CA23092,STOCKDALE, DAVID R,H,CA,REP,2151 S COLLEGE DR SUITE 101,SANTA MARIA,CA,93455
2740-H0CA23100,DAVIDSON, JOHN,H,CA,REP,1710 N MOORPARK ROAD SUITE 18,THOUSAND OAKS,CA,91360
2741-H0CA24108,STERN, SHAWN,H,CA,DEM,1212 S VICTORY BLVD,BURBANK,CA,91502
2742-H0CA24116,ALLISON, TIMOTHY JAMES,H,CA,DEM,PO BOX 4304,SANTA BARBARA,CA,93140
2743-H0CA27085,SCHIFF, ADAM,H,CA,DEM,777 S. FIGUEROA ST., STE. 4050,LOS ANGELES,CA,90017
2744-H0CA28091,FROYD, ERIK MERLIN,H,CA,REP,PO BOX 6455,BURBANK,CA,91510
2745-H0CA29081,LARGE, MORTON R,H,CA,REP,PO BOX 5003,BURBANK,CA,91504
2746-H0CA30063,DAVID, ARI,H,CA,REP,PO BOX 163,MALIBU,CA,90265
2747-H0CA30071,FLUTIE, ROBERT A,H,CA,REP,888 S FIGUEROA #860,LOS ANGELES,CA,90017
2748-H0CA30089,BENNING, DAVID,H,CA,REP,5931 WOODLAND VIEW DRIVE,WOODLAND HILLS,CA,913671075
2749-H0CA32101,CHU, JUDY,H,CA,DEM,777 S. FIGUEROA ST., STE.4050,LOS ANGELES,CA,90017
2750-H0CA32119,ROMERO, GLORIA,H,CA,,PO BOX 32398,LOS ANGELES,CA,90032
2751-H0CA32127,CEDILLO, GILBERT,H,CA,DEM,1212 S VICTORY BLVD,BURBANK,CA,91502
2752-H0CA32135,HERNANDEZ, TERESA,H,CA,REP,2001 SANTA ANITA AVENUE, #103,SOUTH EL MONTE,CA,91733
2753-H0CA32176,ALONSO, FRANCISCO,H,CA,DEM,415-A N SIERR VISTA ST,MONTEREY PARK,CA,91755
2754-H0CA32192,ARIF, MOHAMMAD,H,CA,PAF,11520 JEFFERSON BOULEVARD, #201,CULVER CITY,CA,90230
2755-H0CA32200,BLAKE, M. WAYNE,H,CA,REP,506 EAST 9THSTREET, #2,AZUSA,CA,91702
2756-H0CA32218,CHU, BETTY,H,CA,REP,645 BARNUM WAY,MONTEREY PARK,CA,91754
2757-H0CA32226,DURAN, BENITA,H,CA,DEM,313 NORTH RECORD AVENUE,EAST LOS ANGELES,CA,90063
2758-H0CA32234,ESTRADA, ANDRES,H,CA,DEM,3700 EAGLE STREET,LOS ANGELES,CA,90063
2759-H0CA32242,LYSENKO, STEFAN (CONTRERAS),H,CA,DEM,P.O. BOX 58024,VAN NUYS,CA,91413
2760-H0CA32259,MORRISON, WILLIAM (RODRIGUEZ),H,CA,REP,2728 CINCINNATI STREET,LOS ANGELES,CA,90033
2761-H0CA32267,MOSTERT, NICK JUAN,H,CA,DEM,P.O. BOX 428,MONTEREY PARK,CA,91754
2762-H0CA32291,SANTANA, SALVADOR,H,CA,REP,1928 WEST KENOAK DRIVE,WEST COVINA,CA,91790
2763-H0CA32309,WONG, MARGARITA MARIE,H,CA,DEM,P.O. BOX 416,SAN GABRIEL,CA,91778
2764-H0CA32317,SCARBOROUGH, LARRY DEAN,H,CA,REP,POST OFFICE BOX 341174,LOS ANGELES,CA,900349174
2765-H0CA36128,KESTERSON, PETE,H,CA,REP,800 S PACIFIC COAST HWY #8-305,REDONDO BEACH,CA,90277
2766-H0CA36136,FEIN, MATTIE,H,CA,REP,PO BOX 2006,REDONDO BEACH,CA,90278
2767-H0CA39080,ANDRE, LARRY STEVEN,H,CA,REP,7033 MCMANUS STREET,LAKEWOOD,CA,90713
2768-H0CA42167,MCGROARTY, LEE,H,CA,REP,15338 CENTRAL AVENUE,CHINO,CA,947107658
2769-H0CA42175,LIBERATORE, PHILIP LAURENCE,H,CA,REP,14702 ROMERO DRIVE,WHITTIER,CA,90605
2770-H0CA45061,THIBODEAU, CLAYTON DEL,H,CA,REP,3800 W DEVONSHIRE AVE #D-128,HEMET,CA,92545
2771-H0CA47067,TRAN, VAN,H,CA,REP,8856 CITRUS AVE,WESTMINSTER,CA,92683
2772-H0CA47083,IGLESIAS, CECILIA PATRICIA,H,CA,IND,1322 S ARAPAHO DR,SANTA ANA,CA,92704
2773-H0CA48024,ISSA, DARRELL,H,CA,REP,PO BOX 760,VISTA,CA,92085
2774-H0CA48131,KROM, BETH,H,CA,DEM,1212 S VICTORY BLVD,BURBANK,CA,91502
2775-H0CA49055,DAVIS, SUSAN A,H,CA,DEM,5241 CANTERBURY DR.,SAN DIEGO,CA,92116
2776-H0CA49089,KATZ, HOWARD LOUIS,H,CA,DEM,35125 CALLE NOPAL,TEMECULA,CA,92592
2777-H0CA50061,EMBLEM, TRACY,H,CA,DEM,205 W. 5TH AVENUE SUITE 105,ESCONDIDO,CA,92025
2778-H0CA51028,MCLEROY, WILLIAM DAVID,H,CA,REP,3862 GATTY ST,SAN DIEGO,CA,92154
2779-H0CA53016,FRIEDMAN, MATT,H,CA,REP,302 WASHINGTON #942,SAN DIEGO,CA,92103
2780-H0CA53024,ARRINGTON, RANDALL STEVEN PHD,H,CA,REP,5206 MERRICK DRIVE,PEACHTREE CITY,GA,30269
2781-H0CA53032,WEAVER, CLARENCE MASON,H,CA,REP,PO BOX 33451,SAN DIEGO,CA,92163
2782-H0CA53040,MERRIMAN, CHARLES MILLER II,H,CA,REP,1740 ROOSEVELT AVE #M,SAN DIEGO,CA,92109
2783-H0CO00013,BROWN, DIGGS,H,CO,UNK,125 S HOWES STREET,FORT COLLINS,CO,80521
2784-H0CO02134,BAILEY, STEPHEN,H,CO,REP,6664 CHEROKEE COURT,HIWOT,CO,80503
2785-H0CO02142,BRANCATO, BOB,H,CO,REP,534 HART SSTREET,FIRESTONE,CO,80520
2786-H0CO03074,BEESON, MARTIN C,H,CO,REP,1533 DOGWOOD DRIVE,RIFLE,CO,81650
2787-H0CO03082,THOMPSON, DOUGLAS BOMAR,H,CO,REP,2694 DEL MAR DRIVE,GRAND JUNCTION,CO,81506
2788-H0CO03090,MCCONNELL, ROBERT M,H,CO,REP,PO 883133,STEAMBOAT SPRINGS,CO,80488
2789-H0CO04114,LUCERO, THOMAS JOSEPH,H,CO,REP,PO BOX 921,JOHNSTOWN,CO,80534
2790-H0CO04122,GARDNER, CORY,H,CO,REP,PO BOX 2408,LOVELAND,CO,80539
2791-H0CO04130,MADERE, DEAN MATTHEW,H,CO,REP,4092 GOLF VISTA DR,LOVELAND,CO,80537
2792-H0CO06069,CANTER, DAVID,H,CO,DEM,303 WEST WINTERTHUR WAY,HIGHLANDS RANCH,CO,80139
2793-H0CO06077,FLERLAGE, JOHN,H,CO,DEM,PO BOX 1279,LITTLETON,CO,80160
2794-H0CO07018,CAMPBELL, BRIAN T SR,H,CO,REP,6164 CARR STREET,ARVADA,CO,80004
2795-H0CO07026,FRAZIER, RYAN L,H,CO,REP,PO BOX 140182,EDGEWATER,CO,802140182
2796-H0CO07034,DEMING, MICHAEL,H,CO,REP,1171 S SABLE BLVD UNIT F,AURORA,CO,800124900
2797-H0CO07042,SHEELY, MICHEL L,H,CO,REP,48065 EAST 38TH AVENUE,BENNETT,CO,80102
2798-H0CO07059,LAKEY, JIMMY,H,CO,REP,PO BOX 402,ARVADA,CO,800010402
2799-H0CO07067,SIAS, LANGHORNE C,H,CO,REP,15400 WEST 64TH AVENUE SUITE 9F,ARVADA,CO,80007
2800-H0CT02132,DALY, MATTHEW MOULTON,H,CT,REP,14 PASTURE LANE,SOUTH GLASTONBURY,CT,06073
2801-H0CT03072,DELAURO, ROSA,H,CT,DEM,49 HUNTINGTON STREET,NEW HAVEN,CT,06511
2802-H0CT03106,LABRIOLA, JERRY JR,H,CT,REP,8 AUTUM LEAVES ROAD,WALLINGFORD,CT,06492
2803-H0CT04120,GREGORY, WILL,H,CT,REP,PO BOX 972,STAMFORD,CT,06904
2804-H0CT04138,MERKLE, ROBERT,H,CT,REP,PO BOX 155,WILTON,CT,06897
2805-H0CT04146,DEBICELLA, DAN,H,CT,REP,1 LAZYBROOK ROAD,SHELTON,CT,06484
2806-H0CT04153,RUSSO, ROBERT,H,CT,REP,PO BOX 3493,BRIDGEPORT,CT,06055
2807-H0CT04161,TORRES, ENRIQUE RAUL,H,CT,REP,108 MIDLAND STREET,BRIDGEPORT,CT,06605
2808-H0CT05119,BERNIER, JUSTIN,H,CT,REP,PO BOX 207,PLAINVILLE,CT,06062
2809-H0CT05135,CARTER, DANIEL E,H,CT,REP,PO BOX 11331,WATERBURY,CT,06703
2810-H0CT05143,WESTBY, KIE,H,CT,REP,45 HOMESTEAD ROAD,SOUTHBURY,CT,06488
2811-H0CT05150,GREENBERG, MARK DANIEL,H,CT,REP,184 FERN AVENUE,LITCHFIELD,CT,06759
2812-H0CT05168,EVANS, WILLIAM J JR,H,CT,REP,325 CELIA DRIVE,WOLCOTT,CT,06705
2813-H0CT05176,CALIGIURI, SAM,H,CT,REP,PO BOX 11252,WATERBURY,CT,06703
2814-H0DE00084,SPENCER, SCOTT RICHARD,H,DE,DEM,PO BOX 484,WILMINGTON,DE,19899
2815-H0DE00092,CULLIS, FREDERICK R,H,DE,REP,601 ORIOLE PLACE,HOCKESSIN,DE,19707
2816-H0DE00100,LAFLANC, EARL R,H,DE,CON,,WYOMING,DE,19934
2817-H0DE00118,CAMPBELL, DOUGLAS ALLEN JR,H,DE,CON,5979 SUMMIT BRIDGE RD,TOWNSEND,DE,19734
2818-H0DE01017,CARNEY, JOHN CHARLES JR,H,DE,DEM,506 WEST 19TH STREET,WILMINGTON,DE,19802
2819-H0DE01025,IZZO, ROSE,H,DE,REP,2115 COVENTRY DRIVE,WILMINGTON,DE,198102851
2820-H0FL00023,KRAUSE, JOHN E,H,FL,REP,2350 TEATE AVE,PENSACOLA,FL,32504
2821-H0FL01096,KELLEY, HENRY ARTHUR JR,H,FL,UNK,548 MARY ESTHER CUTOFF UNIT 18-133,FORT WALTON BEACH,FL,32548
2822-H0FL02086,LAWSON, ALFRED AL' JR',H,FL,DEM,400 NORTH ADAMS ST,TALLAHASSEE,FL,32301
2823-H0FL02094,MCKAIN, PAUL CRANDALL,H,FL,OTH,PO BOX 71,LLOYD,FL,32337
2824-H0FL02102,MEECE, CARL EDWARD JR,H,FL,REP,20253 153RD PL,O'BRIEN,FL,32071
2825-H0FL02110,SOUTHERLAND, WILLIAM STEVE II,H,FL,REP,PO BOX 1692,LYNN HAVEN,FL,32444
2826-H0FL03068,GILMAN, JAMES NICHOLAS,H,FL,REP,550 WATER ST STE 1325,JACKSONVILLE,FL,32202
2827-H0FL03076,MARTIN-BACK, TERRY L,H,FL,NPA,10930 NW 9TH PL,GAINESVILLE,FL,32606
2828-H0FL03084,ANNARUMMA, JOHN CARL,H,FL,OTH,PO BOX 971,ALACHUA,FL,32616
2829-H0FL03092,MACNAUGHTON, GEORGE SCOTT,H,FL,LIB,10336 DEPAUL DR,JACKSONVILLE,FL,32218
2830-H0FL04066,CRENSHAW, ANDER HON,H,FL,REP,2358 RIVERSIDE AVENUE,JACKSONVILLE,FL,322044641
2831-H0FL04108,STANLEY, TROY DWAYNE,H,FL,REP,12436 HICKORY FOREST RD,JACKSONVILLE,FL,32226
2832-H0FL05105,DOOLAN, THOMAS JOSEPH,H,FL,DEM,2114 MEDINA HILLS LN,MASCOTTE,FL,34753
2833-H0FL05121,SAGER, JASON PATRICK,H,FL,REP,915 HAMMOCK RD,BROOKSVILLE,FL,34601
2834-H0FL06061,YOST, MICHAEL F 'MIKE',H,FL,REP,902 HALSEMA RD S,JACKSONVILLE,FL,321101020
2835-H0FL07051,BACON, STEPHEN,H,FL,NNE,257 BAYOU CIRCLE,DEBARY,FL,32713
2836-H0FL07069,SILVA, PETER,H,FL,DEM,891 E RED HOUSE BRANCH RD,ST AUGUSTINE,FL,32084
2837-H0FL07077,BEAVEN, HEATHER MAURINE,H,FL,DEM,203 LONDON DRIVE,PALM COAST,FL,321379709
2838-H0FL07085,MORRIS, RALPH LEROY,H,FL,UNK,8300 MORRISON ROAD,HASTINGS,FL,321453907
2839-H0FL08091,FANELLI, DANIEL ROY,H,FL,REP,2958 MARQUESAS CT,WINDERMERE,FL,347867825
2840-H0FL08109,SULLIVAN, PATRICIA ANNE,H,FL,REP,901 HASELTON ST,EUSTIS,FL,32726
2841-H0FL08117,DUNMIRE, PEG,H,FL,REP,13352 PALOMA DR,ORLANDO,FL,32837
2842-H0FL08125,GUTIERREZ, ARMANDO JR,H,FL,REP,2640A MITCHAM DRIVE,TALLAHASSEE,FL,32308
2843-H0FL08133,BUTLER, KEVIN MICHAEL,H,FL,REP,4453 WINDERWOOD CIRCLE,ORLANDO,FL,32835
2844-H0FL08141,BROWN, PRINCE,H,FL,REP,PO BOX 607812,ORLANDO,FL,32860
2845-H0FL08158,KELLY, KURT,H,FL,REP,PO BOX 533021,ORLANDO,FL,328533021
2846-H0FL10055,JUSTICE, CHARLIE,H,FL,DEM,3101 60TH STREET NORTH,ST PETERSBURG,FL,33170
2847-H0FL10063,FORCADE, ERIC LEE,H,FL,REP,PO BOX 128,PALM HARBOR,FL,346820128
2848-H0FL11137,KELLER, SCOTT THOMAS,H,FL,REP,8754 HANDEL LOOP,LAND O LAKES,FL,34637
2849-H0FL11145,STANFORD, STEVEN CRAIG,H,FL,REP,3106 W FAIR OAKS AVE,TAMPA,FL,33611
2850-H0FL11152,BUNTYN, TONY,H,FL,REP,4934 W SAN RAFAEL ST,TAMPA,FL,33629
2851-H0FL12101,ROSS, DENNIS ALAN,H,FL,REP,607 LAKE MIRIAM DRIVE,LAKELAND,FL,33813
2852-H0FL12119,EDWARDS, LORI,H,FL,DEM,4066 LAKE MARIANNA DRIVE,WINTER HAVEN,FL,33881
2853-H0FL12127,SNIDER, THOMAS K,H,FL,LIB,810 WALSINGHAM WAY,VALRICO,FL,33594
2854-H0FL12135,WILKINSON, RANDY,H,FL,REP,100 E HOOKER STREET,BARTOW,FL,33830
2855-H0FL12143,EDWARDS, RANDOLPH,H,FL,DEM,1609 GRAND HERITAGE BLVD,VALRICO,FL,33594
2856-H0FL12150,LINDSEY, JOHN W JR,H,FL,REP,385 STERLING DRIVE,WINTER HAVEN,FL,33884
2857-H0FL13109,GOLDEN, JAMES THEOPOLIS,H,FL,DEM,4815 11TH AVE CIR E,BRADENTON,FL,34208
2858-H0FL16045,CRAFT, CHRISTOPHER LEE,H,FL,DEM,PO BOX 1328,FT PIERCE,FL,34954
2859-H0FL17035,WILLIAMS, ANDRE LEWIS,H,FL,DEM,1850 NW 170TH STREET,MIAMI GARDENS,FL,33056
2860-H0FL17050,BASTIEN, MARLEINE M,H,FL,DEM,PO BOX 381255,MIAMI,FL,33238
2861-H0FL17068,WILSON, FREDERICA S,H,FL,DEM,19821 NW 2ND AVENUE,MIAMI GARDENS,FL,33169
2862-H0FL17076,BRUTUS, PHILLIP J,H,FL,DEM,16801 NE 6 AVENUE,N MIAMI BEACH,FL,33162
2863-H0FL17084,GIBSON, SHIRLEY,H,FL,DEM,PO BOX 694313,MIAMI GARDENS,FL,33269
2864-H0FL17092,VEREEN, RODERICK D,H,FL,DEM,14630 S RIVER DRIVE,MIAMI,FL,33167
2865-H0FL17100,ADAM, LEROY,H,FL,DEM,888 NE 89 ST APT D,MIAMI,FL,33138
2866-H0FL17118,MOISE, RUDOLPH,H,FL,DEM,PO BOX 680417,NORTH MIA,FL,331689998
2867-H0FL18025,ROS-LEHTINEN, ILEANA,H,FL,REP,POST OFFICE BOX 52-2784,MIAMI,FL,33152
2868-H0FL19049,RUIZ, JOSE M,H,FL,DEM,6875 HOULTON CIR,LAKE WORTH,FL,334678742
2869-H0FL19056,LAROSE, JOSUE,H,FL,DEM,929 SW 15TH STREET,DEERFIELD BEACH,FL,33441
2870-H0FL19072,BUDD, JOSEPH E,H,FL,UNK,10396 SUNSTREAM LANE,BOCA RATON,FL,33428
2871-H0FL19080,DEUTCH, THEODORE ELIOT,H,FL,DEM,12373 CASCADES POINTE DRIVE,BOCA RATON,FL,33428
2872-H0FL19098,MCCORMICK, JIM,H,FL,NPA,22465 TIKI DR,BOCA RATON,FL,33428
2873-H0FL20039,LOWRY, ROBERT PAUL,H,FL,REP,940 N NORTHLAKE DR,HOLLYWOOD,FL,33020
2874-H0FL20054,SCHOCK, CLAYTON JAMES,H,FL,OTH,641 WOODGATE LN,SUNRISE,FL,33326
2875-H0FL21029,SANCHEZ, WILLAIM,H,FL,DEM,9725 SW 140TH ST,MIAMI,FL,33176
2876-H0FL24015,MILLER, KENNETH JOHN,H,FL,REP,4098 SCARLET IRIS PL,WINTER PARK,FL,32792
2877-H0FL24023,DIEBEL, KAREN,H,FL,REP,941 GEORGIA AVE,WINTER PARK,FL,32789
2878-H0FL24031,HUKILL, DOROTHY L,H,FL,REP,5832 WALES AVENUE,PORT ORANGE,FL,32127
2879-H0FL24049,ADAMS, SANDY,H,FL,REP,PO BOX 1566,ORLANDO,FL,32802
2880-H0FL24056,CAMPBELL, SEAN FIELD,H,FL,REP,PO BOX 542846,MERRITT ISLAND,FL,32954
2881-H0FL24064,LONG, OMETRIAS DEON,H,FL,REP,POST OFFICE BOX 3119,WINTER PARK,FL,327903119
2882-H0FL24072,HEINZELMAN, JAMES P SR,H,FL,REP,2957 W ST RD 434 STE 200,LONGWOOD,FL,32779
2883-H0FL24080,MACINNES, CHAD,H,FL,REP,13638 CRYSTAL RIVER DRIVE,ORLANDO,FL,32828
2884-H0FL24098,SINCLAIR, LARRY,H,FL,UNK,9 SPRING DRIVE,PORT ORANGE,FL,32129
2885-H0FL24122,FOSTER, JAMES NORMAN,H,FL,REP,2116 ELMCREST PL,OVIEDO,FL,32765
2886-H0FL24130,GARCIA, GEORGE THOMAS,H,FL,REP,PO BOX 5037,TITUSVILLE,FL,32783
2887-H0GA02217,KEOWN, MICHAEL HUEL (MIKE),H,GA,REP,1086 W VIOLET AVE,COOLIDGE,GA,31738
2888-H0GA04023,LINDER, JOHN,H,GA,REP,PO BOX 4026,DULUTH,GA,30096
2889-H0GA04064,GAUSE, LAWRENCE FRANKLIN,H,GA,REP,PO BOX 225,TUCKER,GA,300850225
2890-H0GA04072,CARTER, LISBETH LIZ'',H,GA,REP,2639 BRIARLAKE RD NE,ATLANTA,GA,30345
2891-H0GA04080,JONES, VERNON A,H,GA,DEM,PO BOX 190496,ATLANTA,GA,31119
2892-H0GA08032,MARSHALL, JIM,H,GA,DEM,586 ORANGE STREET,MACON,GA,31201
2893-H0GA08040,DELOACH, KENNETH RAY JR,H,GA,REP,314 CHEYENNE DRIVE,WARNER ROBINS,GA,31093
2894-H0GA08065,HICKS, ANGELA,H,GA,REP,5962 ZEBULON ROAD BOX 306,MACON,GA,31210
2895-H0GA09022,EVANS, MIKE ALLEN,H,GA,REP,212 DAHLONEGA STREET,CUMMING,GA,30040
2896-H0GA09030,GRAVES, JOHN THOMAS JR,H,GA,REP,475 CRAIG ROAD,RANGER,GA,30734
2897-H0GA09055,STEPHENS, WILLIAM V,H,GA,REP,2300 BETHELVIEW ROAD,CUMMINGS,GA,30040
2898-H0GA09063,JONES, JEREMY EDWARD,H,GA,REP,190 PLAYHOUSE DRIVE,RINGGOLD,GA,30736
2899-H0GA09071,MOON, EDWARD 'EUGENE',H,GA,IND,3407 LAKE RIDGE PLACE,GAINESVILLE,GA,30506
2900-H0GA09089,HAWKINS, B LEE,H,GA,REP,4710 JIM HOOD ROAD,GAINESVILLE,GA,30506
2901-H0GA09097,TARVIN, THOMAS STEPHEN,H,GA,REP,PO BOX 365,CHICKAMAUGA,GA,307070365
2902-H0GA09105,FREEMAN, MIKE,H,GA,DEM,5194 GLENSTONE CT,GAINSVILLE,GA,30504
2903-H0GA09113,BENTON, CLYDE DANIEL,H,GA,REP,114 WASHINGTON ST,GAINESVILLE,GA,30501
2904-H0GA09121,LOFTMAN, BERTIL ARMIN,H,GA,REP,11342 BIG CANOE,JASPER,GA,30143
2905-H0GA09139,DOOLEY, THOMAS EUGENE,H,GA,REP,129 MORRIS DRIVE,RINGGOLD,GA,30736
2906-H0GA10228,CATES, CHRISTOPHER U MD,H,GA,REP,11 TIMBER GRACE COURT,BLAIRSVILLE,GA,30512
2907-H0GA12018,MOSLEY, EMMETT WAYNE JR,H,GA,REP,2107 ADAMS STREET,VIDALIA,GA,30474
2908-H0GA12026,SMITH, LAWTON CARLOS JR,H,GA,REP,3210 GILREATH DR,THUNDERBOLT,GA,31404
2909-H0GA12034,SEAVER, JEAN MARIE,H,GA,REP,63 RIVER BLUFF DRIVE,SAVANNAH,GA,31406
2910-H0GA13016,SLEEPER, SONJA,H,GA,REP,201 PORTER LN,JONESBORO,GA,30236
2911-H0GA13024,FRISBEE, MICHAEL,H,GA,IND,PO BOX 5,WINSTON,GA,30187
2912-H0HI01157,DJOU, CHARLES KONG,H,HI,REP,P O BOX 23580,HONOLULU,HI,96813
2913-H0HI01165,HANABUSA, COLLEEN WAKAKO,H,HI,DEM,92-1019 J KOIO DRIVE,KAPOLEI,HI,96707
2914-H0HI02106,WILLOUGHBY, JOHN WILLIAM,H,HI,REP,3054 ALA POHA PLACE APT 1811,HONOLULU,HI,968181678
2915-H0IA01109,BUDDE, JAMES R,H,IA,REP,23741 415TH AVE,BELLEVUE,IA,52031
2916-H0IA02107,SICARD, GARY JOSEPH,H,IA,LIB,585 BROUGHAM RD,ROBINS,IA,52328
2917\ No newline at end of file
2918
2919=== modified file 'tests/boots/lib/lingos/lingo_tests.py'
2920--- tests/boots/lib/lingos/lingo_tests.py 2010-02-27 05:40:10 +0000
2921+++ tests/boots/lib/lingos/lingo_tests.py 2010-03-07 09:23:23 +0000
2922@@ -27,7 +27,7 @@
2923 from boots.app import client_config
2924 from boots.lib import console
2925 from boots.lib.lingos import lingo, bash_external, lisp, piped_sql, python, sql
2926-import filecmp
2927+import os
2928 import tempfile
2929
2930 def node_graph_values(graph):
2931@@ -105,13 +105,13 @@
2932 super(TestPipedSQLInterpreter, self).setUp()
2933 self.sql = piped_sql.PipedSQLInterpreter(self.console)
2934
2935- def test_input_redirect(self):
2936+ def test_redirect(self):
2937 temp = tempfile.mkstemp(prefix = 'boots-test-file')[1]
2938 piped_sql_query = 'select * from cand; > {0}'.format(temp)
2939 graph = self.sql.execute(piped_sql_query)
2940 graph.start()
2941 graph.run()
2942- self.assertTrue(filecmp.cmp(temp, 'lib/lingos/cand_correct.txt', False))
2943+ self.assertEqual(len(open(temp).readlines()), 1458)
2944
2945 class TestPythonInterpreter(LingoBaseTester):
2946 def setUp(self):

Subscribers

People subscribed via source and target branches

to all changes: