Merge lp:~mterry/duplicity/drop-pexpect into lp:duplicity/0.6
- drop-pexpect
- Merge into 0.6-series
Proposed by
Michael Terry
Status: | Superseded |
---|---|
Proposed branch: | lp:~mterry/duplicity/drop-pexpect |
Merge into: | lp:duplicity/0.6 |
Diff against target: |
2162 lines (+52/-1903) 9 files modified
bin/duplicity.1 (+3/-0) duplicity/backend.py (+39/-49) duplicity/backends/_ssh_pexpect.py (+2/-1) duplicity/backends/~par2wrapperbackend.py (+5/-4) duplicity/pexpect.py (+0/-1845) po/POTFILES.in (+0/-2) setup.py (+1/-1) testing/helpers/helper.py (+1/-1) tox.ini (+1/-0) |
To merge this branch: | bzr merge lp:~mterry/duplicity/drop-pexpect |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
duplicity-team | Pending | ||
Review via email: mp+216388@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-04-17.
Commit message
Description of the change
Drop our local copy of pexpect in favor of a system version.
It's only used by the pexpect ssh backend (and if you're opting into that, you probably can expect that you will need pexpect) and the tests.
I've done a quick smoketest (backed up and restored using --ssh-backend=
To post a comment you must log in.
- 975. By Michael Terry
-
fix typo
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/duplicity.1' |
2 | --- bin/duplicity.1 2014-04-17 17:58:17 +0000 |
3 | +++ bin/duplicity.1 2014-04-17 19:52:16 +0000 |
4 | @@ -120,6 +120,9 @@ |
5 | .B ssh pexpect backend |
6 | .B sftp/scp client binaries |
7 | OpenSSH - http://www.openssh.com/ |
8 | +.br |
9 | +.B Python pexpect module |
10 | +- http://pexpect.sourceforge.net/pexpect.html |
11 | .TP |
12 | .BR "swift backend (OpenStack Object Storage)" |
13 | .B Python swiftclient module |
14 | |
15 | === modified file 'duplicity/backend.py' |
16 | --- duplicity/backend.py 2014-04-17 17:58:17 +0000 |
17 | +++ duplicity/backend.py 2014-04-17 19:52:16 +0000 |
18 | @@ -32,13 +32,12 @@ |
19 | import getpass |
20 | import gettext |
21 | import urllib |
22 | +import urlparse |
23 | |
24 | from duplicity import dup_temp |
25 | -from duplicity import dup_threading |
26 | from duplicity import file_naming |
27 | from duplicity import globals |
28 | from duplicity import log |
29 | -from duplicity import urlparse_2_5 as urlparser |
30 | from duplicity import progress |
31 | |
32 | from duplicity.util import exception_traceback |
33 | @@ -58,6 +57,27 @@ |
34 | _forced_backend = None |
35 | _backends = {} |
36 | |
37 | +# These URL schemes have a backend with a notion of an RFC "network location". |
38 | +# The 'file' and 's3+http' schemes should not be in this list. |
39 | +# 'http' and 'https' are not actually used for duplicity backend urls, but are needed |
40 | +# in order to properly support urls returned from some webdav servers. adding them here |
41 | +# is a hack. we should instead not stomp on the url parsing module to begin with. |
42 | +# |
43 | +# This looks similar to urlparse's 'uses_netloc' list, but urlparse doesn't use |
44 | +# that list for parsing, only creating urls. And doesn't include our custom |
45 | +# schemes anyway. So we keep our own here for our own use. |
46 | +uses_netloc = ['ftp', |
47 | + 'ftps', |
48 | + 'hsi', |
49 | + 'rsync', |
50 | + 's3', |
51 | + 'scp', 'ssh', 'sftp', |
52 | + 'webdav', 'webdavs', |
53 | + 'gdocs', |
54 | + 'http', 'https', |
55 | + 'imap', 'imaps', |
56 | + 'mega'] |
57 | + |
58 | |
59 | def import_backends(): |
60 | """ |
61 | @@ -165,46 +185,6 @@ |
62 | raise BackendException(_("Could not initialize backend: %s") % str(sys.exc_info()[1])) |
63 | |
64 | |
65 | -_urlparser_initialized = False |
66 | -_urlparser_initialized_lock = dup_threading.threading_module().Lock() |
67 | - |
68 | -def _ensure_urlparser_initialized(): |
69 | - """ |
70 | - Ensure that the appropriate clobbering of variables in the |
71 | - urlparser module has been done. In the future, the need for this |
72 | - clobbering to begin with should preferably be eliminated. |
73 | - """ |
74 | - def init(): |
75 | - global _urlparser_initialized |
76 | - |
77 | - if not _urlparser_initialized: |
78 | - # These URL schemes have a backend with a notion of an RFC "network location". |
79 | - # The 'file' and 's3+http' schemes should not be in this list. |
80 | - # 'http' and 'https' are not actually used for duplicity backend urls, but are needed |
81 | - # in order to properly support urls returned from some webdav servers. adding them here |
82 | - # is a hack. we should instead not stomp on the url parsing module to begin with. |
83 | - # |
84 | - # todo: eliminate the need for backend specific hacking here completely. |
85 | - urlparser.uses_netloc = ['ftp', |
86 | - 'ftps', |
87 | - 'hsi', |
88 | - 'rsync', |
89 | - 's3', |
90 | - 'scp', 'ssh', 'sftp', |
91 | - 'webdav', 'webdavs', |
92 | - 'gdocs', |
93 | - 'http', 'https', |
94 | - 'imap', 'imaps', |
95 | - 'mega'] |
96 | - |
97 | - # Do not transform or otherwise parse the URL path component. |
98 | - urlparser.uses_query = [] |
99 | - urlparser.uses_fragm = [] |
100 | - |
101 | - _urlparser_initialized = True |
102 | - |
103 | - dup_threading.with_lock(_urlparser_initialized_lock, init) |
104 | - |
105 | class ParsedUrl: |
106 | """ |
107 | Parse the given URL as a duplicity backend URL. |
108 | @@ -218,7 +198,6 @@ |
109 | """ |
110 | def __init__(self, url_string): |
111 | self.url_string = url_string |
112 | - _ensure_urlparser_initialized() |
113 | |
114 | # While useful in some cases, the fact is that the urlparser makes |
115 | # all the properties in the URL deferred or lazy. This means that |
116 | @@ -226,7 +205,7 @@ |
117 | # problems here, so they will be caught early. |
118 | |
119 | try: |
120 | - pu = urlparser.urlparse(url_string) |
121 | + pu = urlparse.urlparse(url_string) |
122 | except Exception: |
123 | raise InvalidBackendURL("Syntax error in: %s" % url_string) |
124 | |
125 | @@ -272,26 +251,37 @@ |
126 | self.port = None |
127 | try: |
128 | self.port = pu.port |
129 | - except Exception: |
130 | + except Exception: # not raised in python2.7+, just returns None |
131 | # old style rsync://host::[/]dest, are still valid, though they contain no port |
132 | if not ( self.scheme in ['rsync'] and re.search('::[^:]*$', self.url_string)): |
133 | raise InvalidBackendURL("Syntax error (port) in: %s A%s B%s C%s" % (url_string, (self.scheme in ['rsync']), re.search('::[^:]+$', self.netloc), self.netloc ) ) |
134 | |
135 | + # Our URL system uses two slashes more than urlparse's does when using |
136 | + # non-netloc URLs. And we want to make sure that if urlparse assuming |
137 | + # a netloc where we don't want one, that we correct it. |
138 | + if self.scheme not in uses_netloc: |
139 | + if self.netloc: |
140 | + self.path = '//' + self.netloc + self.path |
141 | + self.netloc = '' |
142 | + self.hostname = None |
143 | + elif self.path.startswith('/'): |
144 | + self.path = '//' + self.path |
145 | + |
146 | # This happens for implicit local paths. |
147 | - if not pu.scheme: |
148 | + if not self.scheme: |
149 | return |
150 | |
151 | # Our backends do not handle implicit hosts. |
152 | - if pu.scheme in urlparser.uses_netloc and not pu.hostname: |
153 | + if self.scheme in uses_netloc and not self.hostname: |
154 | raise InvalidBackendURL("Missing hostname in a backend URL which " |
155 | "requires an explicit hostname: %s" |
156 | "" % (url_string)) |
157 | |
158 | # Our backends do not handle implicit relative paths. |
159 | - if pu.scheme not in urlparser.uses_netloc and not pu.path.startswith('//'): |
160 | + if self.scheme not in uses_netloc and not self.path.startswith('//'): |
161 | raise InvalidBackendURL("missing // - relative paths not supported " |
162 | "for scheme %s: %s" |
163 | - "" % (pu.scheme, url_string)) |
164 | + "" % (self.scheme, url_string)) |
165 | |
166 | def geturl(self): |
167 | return self.url_string |
168 | |
169 | === modified file 'duplicity/backends/_ssh_pexpect.py' |
170 | --- duplicity/backends/_ssh_pexpect.py 2013-12-27 06:39:00 +0000 |
171 | +++ duplicity/backends/_ssh_pexpect.py 2014-04-17 19:52:16 +0000 |
172 | @@ -32,7 +32,6 @@ |
173 | import duplicity.backend |
174 | from duplicity import globals |
175 | from duplicity import log |
176 | -from duplicity import pexpect |
177 | from duplicity.errors import * #@UnusedWildImport |
178 | |
179 | class SSHPExpectBackend(duplicity.backend.Backend): |
180 | @@ -76,6 +75,7 @@ |
181 | |
182 | def run_scp_command(self, commandline): |
183 | """ Run an scp command, responding to password prompts """ |
184 | + import pexpect |
185 | for n in range(1, globals.num_retries+1): |
186 | if n > 1: |
187 | # sleep before retry |
188 | @@ -147,6 +147,7 @@ |
189 | |
190 | def run_sftp_command(self, commandline, commands): |
191 | """ Run an sftp command, responding to password prompts, passing commands from list """ |
192 | + import pexpect |
193 | maxread = 2000 # expected read buffer size |
194 | responses = [pexpect.EOF, |
195 | "(?i)timeout, server not responding", |
196 | |
197 | === modified file 'duplicity/backends/~par2wrapperbackend.py' |
198 | --- duplicity/backends/~par2wrapperbackend.py 2014-02-09 21:42:18 +0000 |
199 | +++ duplicity/backends/~par2wrapperbackend.py 2014-04-17 19:52:16 +0000 |
200 | @@ -20,7 +20,6 @@ |
201 | import re |
202 | from duplicity import backend |
203 | from duplicity.errors import UnsupportedBackendScheme, BackendException |
204 | -from duplicity.pexpect import run |
205 | from duplicity import log |
206 | from duplicity import globals |
207 | |
208 | @@ -52,6 +51,7 @@ |
209 | temp-filename later on. So first of all create a tempdir and symlink |
210 | the soure_path with remote_filename into this. |
211 | """ |
212 | + from pexpect |
213 | if remote_filename is None: |
214 | remote_filename = source_path.get_filename() |
215 | |
216 | @@ -63,7 +63,7 @@ |
217 | |
218 | log.Info("Create Par2 recovery files") |
219 | par2create = 'par2 c -r%d -n1 -q -q %s' % (self.redundancy, source_symlink.get_canonical()) |
220 | - out, returncode = run(par2create, -1, True) |
221 | + out, returncode = pexpect.run(par2create, -1, True) |
222 | source_symlink.delete() |
223 | files_to_transfer = [] |
224 | if not returncode: |
225 | @@ -89,6 +89,7 @@ |
226 | If "par2 verify" detect an error transfer the Par2-volumes into the |
227 | temp-dir and try to repair. |
228 | """ |
229 | + from pexpect |
230 | par2temp = local_path.get_temp_in_same_dir() |
231 | par2temp.mkdir() |
232 | local_path_temp = par2temp.append(remote_filename) |
233 | @@ -100,7 +101,7 @@ |
234 | self.wrapped_backend.get(par2file.get_filename(), par2file) |
235 | |
236 | par2verify = 'par2 v -q -q %s %s' % (par2file.get_canonical(), local_path_temp.get_canonical()) |
237 | - out, returncode = run(par2verify, -1, True) |
238 | + out, returncode = pexpect.run(par2verify, -1, True) |
239 | |
240 | if returncode: |
241 | log.Warn("File is corrupt. Try to repair %s" % remote_filename) |
242 | @@ -111,7 +112,7 @@ |
243 | self.wrapped_backend.get(filename, file) |
244 | |
245 | par2repair = 'par2 r -q -q %s %s' % (par2file.get_canonical(), local_path_temp.get_canonical()) |
246 | - out, returncode = run(par2repair, -1, True) |
247 | + out, returncode = pexpect.run(par2repair, -1, True) |
248 | |
249 | if returncode: |
250 | log.Error("Failed to repair %s" % remote_filename) |
251 | |
252 | === removed file 'duplicity/pexpect.py' |
253 | --- duplicity/pexpect.py 2012-03-13 20:54:44 +0000 |
254 | +++ duplicity/pexpect.py 1970-01-01 00:00:00 +0000 |
255 | @@ -1,1845 +0,0 @@ |
256 | -"""Pexpect is a Python module for spawning child applications and controlling |
257 | -them automatically. Pexpect can be used for automating interactive applications |
258 | -such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup |
259 | -scripts for duplicating software package installations on different servers. It |
260 | -can be used for automated software testing. Pexpect is in the spirit of Don |
261 | -Libes' Expect, but Pexpect is pure Python. Other Expect-like modules for Python |
262 | -require TCL and Expect or require C extensions to be compiled. Pexpect does not |
263 | -use C, Expect, or TCL extensions. It should work on any platform that supports |
264 | -the standard Python pty module. The Pexpect interface focuses on ease of use so |
265 | -that simple tasks are easy. |
266 | - |
267 | -There are two main interfaces to Pexpect -- the function, run() and the class, |
268 | -spawn. You can call the run() function to execute a command and return the |
269 | -output. This is a handy replacement for os.system(). |
270 | - |
271 | -For example:: |
272 | - |
273 | - pexpect.run('ls -la') |
274 | - |
275 | -The more powerful interface is the spawn class. You can use this to spawn an |
276 | -external child command and then interact with the child by sending lines and |
277 | -expecting responses. |
278 | - |
279 | -For example:: |
280 | - |
281 | - child = pexpect.spawn('scp foo myname@host.example.com:.') |
282 | - child.expect ('Password:') |
283 | - child.sendline (mypassword) |
284 | - |
285 | -This works even for commands that ask for passwords or other input outside of |
286 | -the normal stdio streams. |
287 | - |
288 | -Credits: Noah Spurrier, Richard Holden, Marco Molteni, Kimberley Burchett, |
289 | -Robert Stone, Hartmut Goebel, Chad Schroeder, Erick Tryzelaar, Dave Kirby, Ids |
290 | -vander Molen, George Todd, Noel Taylor, Nicolas D. Cesar, Alexander Gattin, |
291 | -Geoffrey Marshall, Francisco Lourenco, Glen Mabey, Karthik Gurusamy, Fernando |
292 | -Perez, Corey Minyard, Jon Cohen, Guillaume Chazarain, Andrew Ryan, Nick |
293 | -Craig-Wood, Andrew Stone, Jorgen Grahn (Let me know if I forgot anyone.) |
294 | - |
295 | -Free, open source, and all that good stuff. |
296 | - |
297 | -Permission is hereby granted, free of charge, to any person obtaining a copy of |
298 | -this software and associated documentation files (the "Software"), to deal in |
299 | -the Software without restriction, including without limitation the rights to |
300 | -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
301 | -of the Software, and to permit persons to whom the Software is furnished to do |
302 | -so, subject to the following conditions: |
303 | - |
304 | -The above copyright notice and this permission notice shall be included in all |
305 | -copies or substantial portions of the Software. |
306 | - |
307 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
308 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
309 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
310 | -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
311 | -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
312 | -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
313 | -SOFTWARE. |
314 | - |
315 | -Pexpect Copyright (c) 2008 Noah Spurrier |
316 | -http://pexpect.sourceforge.net/ |
317 | - |
318 | -$Id: pexpect.py,v 1.1 2009/01/06 22:11:37 loafman Exp $ |
319 | -""" |
320 | - |
321 | -try: |
322 | - import os, sys, time |
323 | - import select |
324 | - import string |
325 | - import re |
326 | - import struct |
327 | - import resource |
328 | - import types |
329 | - import pty |
330 | - import tty |
331 | - import termios |
332 | - import fcntl |
333 | - import errno |
334 | - import traceback |
335 | - import signal |
336 | -except ImportError, e: |
337 | - raise ImportError (str(e) + """ |
338 | - |
339 | -A critical module was not found. Probably this operating system does not |
340 | -support it. Pexpect is intended for UNIX-like operating systems.""") |
341 | - |
342 | -__version__ = '2.3' |
343 | -__revision__ = '$Revision: 1.1 $' |
344 | -__all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'run', 'which', |
345 | - 'split_command_line', '__version__', '__revision__'] |
346 | - |
347 | -# Exception classes used by this module. |
348 | -class ExceptionPexpect(Exception): |
349 | - |
350 | - """Base class for all exceptions raised by this module. |
351 | - """ |
352 | - |
353 | - def __init__(self, value): |
354 | - |
355 | - self.value = value |
356 | - |
357 | - def __str__(self): |
358 | - |
359 | - return str(self.value) |
360 | - |
361 | - def get_trace(self): |
362 | - |
363 | - """This returns an abbreviated stack trace with lines that only concern |
364 | - the caller. In other words, the stack trace inside the Pexpect module |
365 | - is not included. """ |
366 | - |
367 | - tblist = traceback.extract_tb(sys.exc_info()[2]) |
368 | - #tblist = filter(self.__filter_not_pexpect, tblist) |
369 | - tblist = [item for item in tblist if self.__filter_not_pexpect(item)] |
370 | - tblist = traceback.format_list(tblist) |
371 | - return ''.join(tblist) |
372 | - |
373 | - def __filter_not_pexpect(self, trace_list_item): |
374 | - |
375 | - """This returns True if list item 0 the string 'pexpect.py' in it. """ |
376 | - |
377 | - if trace_list_item[0].find('pexpect.py') == -1: |
378 | - return True |
379 | - else: |
380 | - return False |
381 | - |
382 | -class EOF(ExceptionPexpect): |
383 | - |
384 | - """Raised when EOF is read from a child. This usually means the child has exited.""" |
385 | - |
386 | -class TIMEOUT(ExceptionPexpect): |
387 | - |
388 | - """Raised when a read time exceeds the timeout. """ |
389 | - |
390 | -##class TIMEOUT_PATTERN(TIMEOUT): |
391 | -## """Raised when the pattern match time exceeds the timeout. |
392 | -## This is different than a read TIMEOUT because the child process may |
393 | -## give output, thus never give a TIMEOUT, but the output |
394 | -## may never match a pattern. |
395 | -## """ |
396 | -##class MAXBUFFER(ExceptionPexpect): |
397 | -## """Raised when a scan buffer fills before matching an expected pattern.""" |
398 | - |
399 | -def run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None, logfile=None, cwd=None, env=None): |
400 | - |
401 | - """ |
402 | - This function runs the given command; waits for it to finish; then |
403 | - returns all output as a string. STDERR is included in output. If the full |
404 | - path to the command is not given then the path is searched. |
405 | - |
406 | - Note that lines are terminated by CR/LF (\\r\\n) combination even on |
407 | - UNIX-like systems because this is the standard for pseudo ttys. If you set |
408 | - 'withexitstatus' to true, then run will return a tuple of (command_output, |
409 | - exitstatus). If 'withexitstatus' is false then this returns just |
410 | - command_output. |
411 | - |
412 | - The run() function can often be used instead of creating a spawn instance. |
413 | - For example, the following code uses spawn:: |
414 | - |
415 | - from pexpect import * #@UnusedWildImport |
416 | - child = spawn('scp foo myname@host.example.com:.') |
417 | - child.expect ('(?i)password') |
418 | - child.sendline (mypassword) |
419 | - |
420 | - The previous code can be replace with the following:: |
421 | - |
422 | - from pexpect import * #@UnusedWildImport |
423 | - run ('scp foo myname@host.example.com:.', events={'(?i)password': mypassword}) |
424 | - |
425 | - Examples |
426 | - ======== |
427 | - |
428 | - Start the apache daemon on the local machine:: |
429 | - |
430 | - from pexpect import * #@UnusedWildImport |
431 | - run ("/usr/local/apache/bin/apachectl start") |
432 | - |
433 | - Check in a file using SVN:: |
434 | - |
435 | - from pexpect import * #@UnusedWildImport |
436 | - run ("svn ci -m 'automatic commit' my_file.py") |
437 | - |
438 | - Run a command and capture exit status:: |
439 | - |
440 | - from pexpect import * #@UnusedWildImport |
441 | - (command_output, exitstatus) = run ('ls -l /bin', withexitstatus=1) |
442 | - |
443 | - Tricky Examples |
444 | - =============== |
445 | - |
446 | - The following will run SSH and execute 'ls -l' on the remote machine. The |
447 | - password 'secret' will be sent if the '(?i)password' pattern is ever seen:: |
448 | - |
449 | - run ("ssh username@machine.example.com 'ls -l'", events={'(?i)password':'secret\\n'}) |
450 | - |
451 | - This will start mencoder to rip a video from DVD. This will also display |
452 | - progress ticks every 5 seconds as it runs. For example:: |
453 | - |
454 | - from pexpect import * #@UnusedWildImport |
455 | - def print_ticks(d): |
456 | - print d['event_count'], |
457 | - run ("mencoder dvd://1 -o video.avi -oac copy -ovc copy", events={TIMEOUT:print_ticks}, timeout=5) |
458 | - |
459 | - The 'events' argument should be a dictionary of patterns and responses. |
460 | - Whenever one of the patterns is seen in the command out run() will send the |
461 | - associated response string. Note that you should put newlines in your |
462 | - string if Enter is necessary. The responses may also contain callback |
463 | - functions. Any callback is function that takes a dictionary as an argument. |
464 | - The dictionary contains all the locals from the run() function, so you can |
465 | - access the child spawn object or any other variable defined in run() |
466 | - (event_count, child, and extra_args are the most useful). A callback may |
467 | - return True to stop the current run process otherwise run() continues until |
468 | - the next event. A callback may also return a string which will be sent to |
469 | - the child. 'extra_args' is not used by directly run(). It provides a way to |
470 | - pass data to a callback function through run() through the locals |
471 | - dictionary passed to a callback. """ |
472 | - |
473 | - if timeout == -1: |
474 | - child = spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env) |
475 | - else: |
476 | - child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile, cwd=cwd, env=env) |
477 | - if events is not None: |
478 | - patterns = events.keys() |
479 | - responses = events.values() |
480 | - else: |
481 | - patterns=None # We assume that EOF or TIMEOUT will save us. |
482 | - responses=None |
483 | - child_result_list = [] |
484 | - event_count = 0 |
485 | - while 1: |
486 | - try: |
487 | - index = child.expect (patterns) |
488 | - if type(child.after) in types.StringTypes: |
489 | - child_result_list.append(child.before + child.after) |
490 | - else: # child.after may have been a TIMEOUT or EOF, so don't cat those. |
491 | - child_result_list.append(child.before) |
492 | - if type(responses[index]) in types.StringTypes: |
493 | - child.send(responses[index]) |
494 | - elif type(responses[index]) is types.FunctionType: |
495 | - callback_result = responses[index](locals()) |
496 | - sys.stdout.flush() |
497 | - if type(callback_result) in types.StringTypes: |
498 | - child.send(callback_result) |
499 | - elif callback_result: |
500 | - break |
501 | - else: |
502 | - raise TypeError ('The callback must be a string or function type.') |
503 | - event_count = event_count + 1 |
504 | - except TIMEOUT, e: |
505 | - child_result_list.append(child.before) |
506 | - break |
507 | - except EOF, e: |
508 | - child_result_list.append(child.before) |
509 | - break |
510 | - child_result = ''.join(child_result_list) |
511 | - if withexitstatus: |
512 | - child.close() |
513 | - return (child_result, child.exitstatus) |
514 | - else: |
515 | - return child_result |
516 | - |
517 | -class spawn (object): |
518 | - |
519 | - """This is the main class interface for Pexpect. Use this class to start |
520 | - and control child applications. """ |
521 | - |
522 | - def __init__(self, command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None): |
523 | - |
524 | - """This is the constructor. The command parameter may be a string that |
525 | - includes a command and any arguments to the command. For example:: |
526 | - |
527 | - child = pexpect.spawn ('/usr/bin/ftp') |
528 | - child = pexpect.spawn ('/usr/bin/ssh user@example.com') |
529 | - child = pexpect.spawn ('ls -latr /tmp') |
530 | - |
531 | - You may also construct it with a list of arguments like so:: |
532 | - |
533 | - child = pexpect.spawn ('/usr/bin/ftp', []) |
534 | - child = pexpect.spawn ('/usr/bin/ssh', ['user@example.com']) |
535 | - child = pexpect.spawn ('ls', ['-latr', '/tmp']) |
536 | - |
537 | - After this the child application will be created and will be ready to |
538 | - talk to. For normal use, see expect() and send() and sendline(). |
539 | - |
540 | - Remember that Pexpect does NOT interpret shell meta characters such as |
541 | - redirect, pipe, or wild cards (>, |, or *). This is a common mistake. |
542 | - If you want to run a command and pipe it through another command then |
543 | - you must also start a shell. For example:: |
544 | - |
545 | - child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > log_list.txt"') |
546 | - child.expect(pexpect.EOF) |
547 | - |
548 | - The second form of spawn (where you pass a list of arguments) is useful |
549 | - in situations where you wish to spawn a command and pass it its own |
550 | - argument list. This can make syntax more clear. For example, the |
551 | - following is equivalent to the previous example:: |
552 | - |
553 | - shell_cmd = 'ls -l | grep LOG > log_list.txt' |
554 | - child = pexpect.spawn('/bin/bash', ['-c', shell_cmd]) |
555 | - child.expect(pexpect.EOF) |
556 | - |
557 | - The maxread attribute sets the read buffer size. This is maximum number |
558 | - of bytes that Pexpect will try to read from a TTY at one time. Setting |
559 | - the maxread size to 1 will turn off buffering. Setting the maxread |
560 | - value higher may help performance in cases where large amounts of |
561 | - output are read back from the child. This feature is useful in |
562 | - conjunction with searchwindowsize. |
563 | - |
564 | - The searchwindowsize attribute sets the how far back in the incomming |
565 | - seach buffer Pexpect will search for pattern matches. Every time |
566 | - Pexpect reads some data from the child it will append the data to the |
567 | - incomming buffer. The default is to search from the beginning of the |
568 | - imcomming buffer each time new data is read from the child. But this is |
569 | - very inefficient if you are running a command that generates a large |
570 | - amount of data where you want to match The searchwindowsize does not |
571 | - effect the size of the incomming data buffer. You will still have |
572 | - access to the full buffer after expect() returns. |
573 | - |
574 | - The logfile member turns on or off logging. All input and output will |
575 | - be copied to the given file object. Set logfile to None to stop |
576 | - logging. This is the default. Set logfile to sys.stdout to echo |
577 | - everything to standard output. The logfile is flushed after each write. |
578 | - |
579 | - Example log input and output to a file:: |
580 | - |
581 | - child = pexpect.spawn('some_command') |
582 | - fout = file('mylog.txt','w') |
583 | - child.logfile = fout |
584 | - |
585 | - Example log to stdout:: |
586 | - |
587 | - child = pexpect.spawn('some_command') |
588 | - child.logfile = sys.stdout |
589 | - |
590 | - The logfile_read and logfile_send members can be used to separately log |
591 | - the input from the child and output sent to the child. Sometimes you |
592 | - don't want to see everything you write to the child. You only want to |
593 | - log what the child sends back. For example:: |
594 | - |
595 | - child = pexpect.spawn('some_command') |
596 | - child.logfile_read = sys.stdout |
597 | - |
598 | - To separately log output sent to the child use logfile_send:: |
599 | - |
600 | - self.logfile_send = fout |
601 | - |
602 | - The delaybeforesend helps overcome a weird behavior that many users |
603 | - were experiencing. The typical problem was that a user would expect() a |
604 | - "Password:" prompt and then immediately call sendline() to send the |
605 | - password. The user would then see that their password was echoed back |
606 | - to them. Passwords don't normally echo. The problem is caused by the |
607 | - fact that most applications print out the "Password" prompt and then |
608 | - turn off stdin echo, but if you send your password before the |
609 | - application turned off echo, then you get your password echoed. |
610 | - Normally this wouldn't be a problem when interacting with a human at a |
611 | - real keyboard. If you introduce a slight delay just before writing then |
612 | - this seems to clear up the problem. This was such a common problem for |
613 | - many users that I decided that the default pexpect behavior should be |
614 | - to sleep just before writing to the child application. 1/20th of a |
615 | - second (50 ms) seems to be enough to clear up the problem. You can set |
616 | - delaybeforesend to 0 to return to the old behavior. Most Linux machines |
617 | - don't like this to be below 0.03. I don't know why. |
618 | - |
619 | - Note that spawn is clever about finding commands on your path. |
620 | - It uses the same logic that "which" uses to find executables. |
621 | - |
622 | - If you wish to get the exit status of the child you must call the |
623 | - close() method. The exit or signal status of the child will be stored |
624 | - in self.exitstatus or self.signalstatus. If the child exited normally |
625 | - then exitstatus will store the exit return code and signalstatus will |
626 | - be None. If the child was terminated abnormally with a signal then |
627 | - signalstatus will store the signal value and exitstatus will be None. |
628 | - If you need more detail you can also read the self.status member which |
629 | - stores the status returned by os.waitpid. You can interpret this using |
630 | - os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG. """ |
631 | - |
632 | - self.STDIN_FILENO = pty.STDIN_FILENO |
633 | - self.STDOUT_FILENO = pty.STDOUT_FILENO |
634 | - self.STDERR_FILENO = pty.STDERR_FILENO |
635 | - self.stdin = sys.stdin |
636 | - self.stdout = sys.stdout |
637 | - self.stderr = sys.stderr |
638 | - |
639 | - self.searcher = None |
640 | - self.ignorecase = False |
641 | - self.before = None |
642 | - self.after = None |
643 | - self.match = None |
644 | - self.match_index = None |
645 | - self.terminated = True |
646 | - self.exitstatus = None |
647 | - self.signalstatus = None |
648 | - self.status = None # status returned by os.waitpid |
649 | - self.flag_eof = False |
650 | - self.pid = None |
651 | - self.child_fd = -1 # initially closed |
652 | - self.timeout = timeout |
653 | - self.delimiter = EOF |
654 | - self.logfile = logfile |
655 | - self.logfile_read = None # input from child (read_nonblocking) |
656 | - self.logfile_send = None # output to send (send, sendline) |
657 | - self.maxread = maxread # max bytes to read at one time into buffer |
658 | - self.buffer = '' # This is the read buffer. See maxread. |
659 | - self.searchwindowsize = searchwindowsize # Anything before searchwindowsize point is preserved, but not searched. |
660 | - # Most Linux machines don't like delaybeforesend to be below 0.03 (30 ms). |
661 | - self.delaybeforesend = 0.05 # Sets sleep time used just before sending data to child. Time in seconds. |
662 | - self.delayafterclose = 0.1 # Sets delay in close() method to allow kernel time to update process status. Time in seconds. |
663 | - self.delayafterterminate = 0.1 # Sets delay in terminate() method to allow kernel time to update process status. Time in seconds. |
664 | - self.softspace = False # File-like object. |
665 | - self.name = '<' + repr(self) + '>' # File-like object. |
666 | - self.encoding = None # File-like object. |
667 | - self.closed = True # File-like object. |
668 | - self.cwd = cwd |
669 | - self.env = env |
670 | - self.__irix_hack = (sys.platform.lower().find('irix')>=0) # This flags if we are running on irix |
671 | - # Solaris uses internal __fork_pty(). All others use pty.fork(). |
672 | - if (sys.platform.lower().find('solaris')>=0) or (sys.platform.lower().find('sunos5')>=0): |
673 | - self.use_native_pty_fork = False |
674 | - else: |
675 | - self.use_native_pty_fork = True |
676 | - |
677 | - |
678 | - # allow dummy instances for subclasses that may not use command or args. |
679 | - if command is None: |
680 | - self.command = None |
681 | - self.args = None |
682 | - self.name = '<pexpect factory incomplete>' |
683 | - else: |
684 | - self._spawn (command, args) |
685 | - |
686 | - def __del__(self): |
687 | - |
688 | - """This makes sure that no system resources are left open. Python only |
689 | - garbage collects Python objects. OS file descriptors are not Python |
690 | - objects, so they must be handled explicitly. If the child file |
691 | - descriptor was opened outside of this class (passed to the constructor) |
692 | - then this does not close it. """ |
693 | - |
694 | - if not self.closed: |
695 | - # It is possible for __del__ methods to execute during the |
696 | - # teardown of the Python VM itself. Thus self.close() may |
697 | - # trigger an exception because os.close may be None. |
698 | - # -- Fernando Perez |
699 | - try: |
700 | - self.close() |
701 | - except AttributeError: |
702 | - pass |
703 | - |
704 | - def __str__(self): |
705 | - |
706 | - """This returns a human-readable string that represents the state of |
707 | - the object. """ |
708 | - |
709 | - s = [] |
710 | - s.append(repr(self)) |
711 | - s.append('version: ' + __version__ + ' (' + __revision__ + ')') |
712 | - s.append('command: ' + str(self.command)) |
713 | - s.append('args: ' + str(self.args)) |
714 | - s.append('searcher: ' + str(self.searcher)) |
715 | - s.append('buffer (last 100 chars): ' + str(self.buffer)[-100:]) |
716 | - s.append('before (last 100 chars): ' + str(self.before)[-100:]) |
717 | - s.append('after: ' + str(self.after)) |
718 | - s.append('match: ' + str(self.match)) |
719 | - s.append('match_index: ' + str(self.match_index)) |
720 | - s.append('exitstatus: ' + str(self.exitstatus)) |
721 | - s.append('flag_eof: ' + str(self.flag_eof)) |
722 | - s.append('pid: ' + str(self.pid)) |
723 | - s.append('child_fd: ' + str(self.child_fd)) |
724 | - s.append('closed: ' + str(self.closed)) |
725 | - s.append('timeout: ' + str(self.timeout)) |
726 | - s.append('delimiter: ' + str(self.delimiter)) |
727 | - s.append('logfile: ' + str(self.logfile)) |
728 | - s.append('logfile_read: ' + str(self.logfile_read)) |
729 | - s.append('logfile_send: ' + str(self.logfile_send)) |
730 | - s.append('maxread: ' + str(self.maxread)) |
731 | - s.append('ignorecase: ' + str(self.ignorecase)) |
732 | - s.append('searchwindowsize: ' + str(self.searchwindowsize)) |
733 | - s.append('delaybeforesend: ' + str(self.delaybeforesend)) |
734 | - s.append('delayafterclose: ' + str(self.delayafterclose)) |
735 | - s.append('delayafterterminate: ' + str(self.delayafterterminate)) |
736 | - return '\n'.join(s) |
737 | - |
738 | - def _spawn(self,command,args=[]): |
739 | - |
740 | - """This starts the given command in a child process. This does all the |
741 | - fork/exec type of stuff for a pty. This is called by __init__. If args |
742 | - is empty then command will be parsed (split on spaces) and args will be |
743 | - set to parsed arguments. """ |
744 | - |
745 | - # The pid and child_fd of this object get set by this method. |
746 | - # Note that it is difficult for this method to fail. |
747 | - # You cannot detect if the child process cannot start. |
748 | - # So the only way you can tell if the child process started |
749 | - # or not is to try to read from the file descriptor. If you get |
750 | - # EOF immediately then it means that the child is already dead. |
751 | - # That may not necessarily be bad because you may haved spawned a child |
752 | - # that performs some task; creates no stdout output; and then dies. |
753 | - |
754 | - # If command is an int type then it may represent a file descriptor. |
755 | - if type(command) == type(0): |
756 | - raise ExceptionPexpect ('Command is an int type. If this is a file descriptor then maybe you want to use fdpexpect.fdspawn which takes an existing file descriptor instead of a command string.') |
757 | - |
758 | - if type (args) != type([]): |
759 | - raise TypeError ('The argument, args, must be a list.') |
760 | - |
761 | - if args == []: |
762 | - self.args = split_command_line(command) |
763 | - self.command = self.args[0] |
764 | - else: |
765 | - self.args = args[:] # work with a copy |
766 | - self.args.insert (0, command) |
767 | - self.command = command |
768 | - |
769 | - command_with_path = which(self.command) |
770 | - if command_with_path is None: |
771 | - raise ExceptionPexpect ('The command was not found or was not executable: %s.' % self.command) |
772 | - self.command = command_with_path |
773 | - self.args[0] = self.command |
774 | - |
775 | - self.name = '<' + ' '.join (self.args) + '>' |
776 | - |
777 | - assert self.pid is None, 'The pid member should be None.' |
778 | - assert self.command is not None, 'The command member should not be None.' |
779 | - |
780 | - if self.use_native_pty_fork: |
781 | - try: |
782 | - self.pid, self.child_fd = pty.fork() |
783 | - except OSError, e: |
784 | - raise ExceptionPexpect('Error! pty.fork() failed: ' + str(e)) |
785 | - else: # Use internal __fork_pty |
786 | - self.pid, self.child_fd = self.__fork_pty() |
787 | - |
788 | - if self.pid == 0: # Child |
789 | - try: |
790 | - self.child_fd = sys.stdout.fileno() # used by setwinsize() |
791 | - self.setwinsize(24, 80) |
792 | - except Exception: |
793 | - # Some platforms do not like setwinsize (Cygwin). |
794 | - # This will cause problem when running applications that |
795 | - # are very picky about window size. |
796 | - # This is a serious limitation, but not a show stopper. |
797 | - pass |
798 | - # Do not allow child to inherit open file descriptors from parent. |
799 | - max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0] |
800 | - for i in range (3, max_fd): |
801 | - try: |
802 | - os.close (i) |
803 | - except OSError: |
804 | - pass |
805 | - |
806 | - # I don't know why this works, but ignoring SIGHUP fixes a |
807 | - # problem when trying to start a Java daemon with sudo |
808 | - # (specifically, Tomcat). |
809 | - signal.signal(signal.SIGHUP, signal.SIG_IGN) |
810 | - |
811 | - if self.cwd is not None: |
812 | - os.chdir(self.cwd) |
813 | - if self.env is None: |
814 | - os.execv(self.command, self.args) |
815 | - else: |
816 | - os.execvpe(self.command, self.args, self.env) |
817 | - |
818 | - # Parent |
819 | - self.terminated = False |
820 | - self.closed = False |
821 | - |
822 | - def __fork_pty(self): |
823 | - |
824 | - """This implements a substitute for the forkpty system call. This |
825 | - should be more portable than the pty.fork() function. Specifically, |
826 | - this should work on Solaris. |
827 | - |
828 | - Modified 10.06.05 by Geoff Marshall: Implemented __fork_pty() method to |
829 | - resolve the issue with Python's pty.fork() not supporting Solaris, |
830 | - particularly ssh. Based on patch to posixmodule.c authored by Noah |
831 | - Spurrier:: |
832 | - |
833 | - http://mail.python.org/pipermail/python-dev/2003-May/035281.html |
834 | - |
835 | - """ |
836 | - |
837 | - parent_fd, child_fd = os.openpty() |
838 | - if parent_fd < 0 or child_fd < 0: |
839 | - raise ExceptionPexpect, "Error! Could not open pty with os.openpty()." |
840 | - |
841 | - pid = os.fork() |
842 | - if pid < 0: |
843 | - raise ExceptionPexpect, "Error! Failed os.fork()." |
844 | - elif pid == 0: |
845 | - # Child. |
846 | - os.close(parent_fd) |
847 | - self.__pty_make_controlling_tty(child_fd) |
848 | - |
849 | - os.dup2(child_fd, 0) |
850 | - os.dup2(child_fd, 1) |
851 | - os.dup2(child_fd, 2) |
852 | - |
853 | - if child_fd > 2: |
854 | - os.close(child_fd) |
855 | - else: |
856 | - # Parent. |
857 | - os.close(child_fd) |
858 | - |
859 | - return pid, parent_fd |
860 | - |
861 | - def __pty_make_controlling_tty(self, tty_fd): |
862 | - |
863 | - """This makes the pseudo-terminal the controlling tty. This should be |
864 | - more portable than the pty.fork() function. Specifically, this should |
865 | - work on Solaris. """ |
866 | - |
867 | - child_name = os.ttyname(tty_fd) |
868 | - |
869 | - # Disconnect from controlling tty if still connected. |
870 | - fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY); |
871 | - if fd >= 0: |
872 | - os.close(fd) |
873 | - |
874 | - os.setsid() |
875 | - |
876 | - # Verify we are disconnected from controlling tty |
877 | - try: |
878 | - fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY); |
879 | - if fd >= 0: |
880 | - os.close(fd) |
881 | - raise ExceptionPexpect, "Error! We are not disconnected from a controlling tty." |
882 | - except Exception: |
883 | - # Good! We are disconnected from a controlling tty. |
884 | - pass |
885 | - |
886 | - # Verify we can open child pty. |
887 | - fd = os.open(child_name, os.O_RDWR); |
888 | - if fd < 0: |
889 | - raise ExceptionPexpect, "Error! Could not open child pty, " + child_name |
890 | - else: |
891 | - os.close(fd) |
892 | - |
893 | - # Verify we now have a controlling tty. |
894 | - fd = os.open("/dev/tty", os.O_WRONLY) |
895 | - if fd < 0: |
896 | - raise ExceptionPexpect, "Error! Could not open controlling tty, /dev/tty" |
897 | - else: |
898 | - os.close(fd) |
899 | - |
900 | - def fileno (self): # File-like object. |
901 | - |
902 | - """This returns the file descriptor of the pty for the child. |
903 | - """ |
904 | - |
905 | - return self.child_fd |
906 | - |
907 | - def close (self, force=True): # File-like object. |
908 | - |
909 | - """This closes the connection with the child application. Note that |
910 | - calling close() more than once is valid. This emulates standard Python |
911 | - behavior with files. Set force to True if you want to make sure that |
912 | - the child is terminated (SIGKILL is sent if the child ignores SIGHUP |
913 | - and SIGINT). """ |
914 | - |
915 | - if not self.closed: |
916 | - self.flush() |
917 | - os.close (self.child_fd) |
918 | - time.sleep(self.delayafterclose) # Give kernel time to update process status. |
919 | - if self.isalive(): |
920 | - if not self.terminate(force): |
921 | - raise ExceptionPexpect ('close() could not terminate the child using terminate()') |
922 | - self.child_fd = -1 |
923 | - self.closed = True |
924 | - #self.pid = None |
925 | - |
926 | - def flush (self): # File-like object. |
927 | - |
928 | - """This does nothing. It is here to support the interface for a |
929 | - File-like object. """ |
930 | - |
931 | - pass |
932 | - |
933 | - def isatty (self): # File-like object. |
934 | - |
935 | - """This returns True if the file descriptor is open and connected to a |
936 | - tty(-like) device, else False. """ |
937 | - |
938 | - return os.isatty(self.child_fd) |
939 | - |
940 | - def waitnoecho (self, timeout=-1): |
941 | - |
942 | - """This waits until the terminal ECHO flag is set False. This returns |
943 | - True if the echo mode is off. This returns False if the ECHO flag was |
944 | - not set False before the timeout. This can be used to detect when the |
945 | - child is waiting for a password. Usually a child application will turn |
946 | - off echo mode when it is waiting for the user to enter a password. For |
947 | - example, instead of expecting the "password:" prompt you can wait for |
948 | - the child to set ECHO off:: |
949 | - |
950 | - p = pexpect.spawn ('ssh user@example.com') |
951 | - p.waitnoecho() |
952 | - p.sendline(mypassword) |
953 | - |
954 | - If timeout is None then this method to block forever until ECHO flag is |
955 | - False. |
956 | - |
957 | - """ |
958 | - |
959 | - if timeout == -1: |
960 | - timeout = self.timeout |
961 | - if timeout is not None: |
962 | - end_time = time.time() + timeout |
963 | - while True: |
964 | - if not self.getecho(): |
965 | - return True |
966 | - if timeout < 0 and timeout is not None: |
967 | - return False |
968 | - if timeout is not None: |
969 | - timeout = end_time - time.time() |
970 | - time.sleep(0.1) |
971 | - |
972 | - def getecho (self): |
973 | - |
974 | - """This returns the terminal echo mode. This returns True if echo is |
975 | - on or False if echo is off. Child applications that are expecting you |
976 | - to enter a password often set ECHO False. See waitnoecho(). """ |
977 | - |
978 | - attr = termios.tcgetattr(self.child_fd) |
979 | - if attr[3] & termios.ECHO: |
980 | - return True |
981 | - return False |
982 | - |
983 | - def setecho (self, state): |
984 | - |
985 | - """This sets the terminal echo mode on or off. Note that anything the |
986 | - child sent before the echo will be lost, so you should be sure that |
987 | - your input buffer is empty before you call setecho(). For example, the |
988 | - following will work as expected:: |
989 | - |
990 | - p = pexpect.spawn('cat') |
991 | - p.sendline ('1234') # We will see this twice (once from tty echo and again from cat). |
992 | - p.expect (['1234']) |
993 | - p.expect (['1234']) |
994 | - p.setecho(False) # Turn off tty echo |
995 | - p.sendline ('abcd') # We will set this only once (echoed by cat). |
996 | - p.sendline ('wxyz') # We will set this only once (echoed by cat) |
997 | - p.expect (['abcd']) |
998 | - p.expect (['wxyz']) |
999 | - |
1000 | - The following WILL NOT WORK because the lines sent before the setecho |
1001 | - will be lost:: |
1002 | - |
1003 | - p = pexpect.spawn('cat') |
1004 | - p.sendline ('1234') # We will see this twice (once from tty echo and again from cat). |
1005 | - p.setecho(False) # Turn off tty echo |
1006 | - p.sendline ('abcd') # We will set this only once (echoed by cat). |
1007 | - p.sendline ('wxyz') # We will set this only once (echoed by cat) |
1008 | - p.expect (['1234']) |
1009 | - p.expect (['1234']) |
1010 | - p.expect (['abcd']) |
1011 | - p.expect (['wxyz']) |
1012 | - """ |
1013 | - |
1014 | - self.child_fd |
1015 | - attr = termios.tcgetattr(self.child_fd) |
1016 | - if state: |
1017 | - attr[3] = attr[3] | termios.ECHO |
1018 | - else: |
1019 | - attr[3] = attr[3] & ~termios.ECHO |
1020 | - # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent |
1021 | - # and blocked on some platforms. TCSADRAIN is probably ideal if it worked. |
1022 | - termios.tcsetattr(self.child_fd, termios.TCSANOW, attr) |
1023 | - |
1024 | - def read_nonblocking (self, size = 1, timeout = -1): |
1025 | - |
1026 | - """This reads at most size characters from the child application. It |
1027 | - includes a timeout. If the read does not complete within the timeout |
1028 | - period then a TIMEOUT exception is raised. If the end of file is read |
1029 | - then an EOF exception will be raised. If a log file was set using |
1030 | - setlog() then all data will also be written to the log file. |
1031 | - |
1032 | - If timeout is None then the read may block indefinitely. If timeout is -1 |
1033 | - then the self.timeout value is used. If timeout is 0 then the child is |
1034 | - polled and if there was no data immediately ready then this will raise |
1035 | - a TIMEOUT exception. |
1036 | - |
1037 | - The timeout refers only to the amount of time to read at least one |
1038 | - character. This is not effected by the 'size' parameter, so if you call |
1039 | - read_nonblocking(size=100, timeout=30) and only one character is |
1040 | - available right away then one character will be returned immediately. |
1041 | - It will not wait for 30 seconds for another 99 characters to come in. |
1042 | - |
1043 | - This is a wrapper around os.read(). It uses select.select() to |
1044 | - implement the timeout. """ |
1045 | - |
1046 | - if self.closed: |
1047 | - raise ValueError ('I/O operation on closed file in read_nonblocking().') |
1048 | - |
1049 | - if timeout == -1: |
1050 | - timeout = self.timeout |
1051 | - |
1052 | - # Note that some systems such as Solaris do not give an EOF when |
1053 | - # the child dies. In fact, you can still try to read |
1054 | - # from the child_fd -- it will block forever or until TIMEOUT. |
1055 | - # For this case, I test isalive() before doing any reading. |
1056 | - # If isalive() is false, then I pretend that this is the same as EOF. |
1057 | - if not self.isalive(): |
1058 | - r,w,e = self.__select([self.child_fd], [], [], 0) # timeout of 0 means "poll" @UnusedVariable |
1059 | - if not r: |
1060 | - self.flag_eof = True |
1061 | - raise EOF ('End Of File (EOF) in read_nonblocking(). Braindead platform.') |
1062 | - elif self.__irix_hack: |
1063 | - # This is a hack for Irix. It seems that Irix requires a long delay before checking isalive. |
1064 | - # This adds a 2 second delay, but only when the child is terminated. |
1065 | - r, w, e = self.__select([self.child_fd], [], [], 2) #@UnusedVariable |
1066 | - if not r and not self.isalive(): |
1067 | - self.flag_eof = True |
1068 | - raise EOF ('End Of File (EOF) in read_nonblocking(). Pokey platform.') |
1069 | - |
1070 | - r,w,e = self.__select([self.child_fd], [], [], timeout) #@UnusedVariable |
1071 | - |
1072 | - if not r: |
1073 | - if not self.isalive(): |
1074 | - # Some platforms, such as Irix, will claim that their processes are alive; |
1075 | - # then timeout on the select; and then finally admit that they are not alive. |
1076 | - self.flag_eof = True |
1077 | - raise EOF ('End of File (EOF) in read_nonblocking(). Very pokey platform.') |
1078 | - else: |
1079 | - raise TIMEOUT ('Timeout exceeded in read_nonblocking().') |
1080 | - |
1081 | - if self.child_fd in r: |
1082 | - try: |
1083 | - s = os.read(self.child_fd, size) |
1084 | - except OSError, e: # Linux does this |
1085 | - self.flag_eof = True |
1086 | - raise EOF ('End Of File (EOF) in read_nonblocking(). Exception style platform.') |
1087 | - if s == '': # BSD style |
1088 | - self.flag_eof = True |
1089 | - raise EOF ('End Of File (EOF) in read_nonblocking(). Empty string style platform.') |
1090 | - |
1091 | - if self.logfile is not None: |
1092 | - self.logfile.write (s) |
1093 | - self.logfile.flush() |
1094 | - if self.logfile_read is not None: |
1095 | - self.logfile_read.write (s) |
1096 | - self.logfile_read.flush() |
1097 | - |
1098 | - return s |
1099 | - |
1100 | - raise ExceptionPexpect ('Reached an unexpected state in read_nonblocking().') |
1101 | - |
1102 | - def read (self, size = -1): # File-like object. |
1103 | - |
1104 | - """This reads at most "size" bytes from the file (less if the read hits |
1105 | - EOF before obtaining size bytes). If the size argument is negative or |
1106 | - omitted, read all data until EOF is reached. The bytes are returned as |
1107 | - a string object. An empty string is returned when EOF is encountered |
1108 | - immediately. """ |
1109 | - |
1110 | - if size == 0: |
1111 | - return '' |
1112 | - if size < 0: |
1113 | - self.expect (self.delimiter) # delimiter default is EOF |
1114 | - return self.before |
1115 | - |
1116 | - # I could have done this more directly by not using expect(), but |
1117 | - # I deliberately decided to couple read() to expect() so that |
1118 | - # I would catch any bugs early and ensure consistant behavior. |
1119 | - # It's a little less efficient, but there is less for me to |
1120 | - # worry about if I have to later modify read() or expect(). |
1121 | - # Note, it's OK if size==-1 in the regex. That just means it |
1122 | - # will never match anything in which case we stop only on EOF. |
1123 | - cre = re.compile('.{%d}' % size, re.DOTALL) |
1124 | - index = self.expect ([cre, self.delimiter]) # delimiter default is EOF |
1125 | - if index == 0: |
1126 | - return self.after ### self.before should be ''. Should I assert this? |
1127 | - return self.before |
1128 | - |
1129 | - def readline (self, size = -1): # File-like object. |
1130 | - |
1131 | - """This reads and returns one entire line. A trailing newline is kept |
1132 | - in the string, but may be absent when a file ends with an incomplete |
1133 | - line. Note: This readline() looks for a \\r\\n pair even on UNIX |
1134 | - because this is what the pseudo tty device returns. So contrary to what |
1135 | - you may expect you will receive the newline as \\r\\n. An empty string |
1136 | - is returned when EOF is hit immediately. Currently, the size argument is |
1137 | - mostly ignored, so this behavior is not standard for a file-like |
1138 | - object. If size is 0 then an empty string is returned. """ |
1139 | - |
1140 | - if size == 0: |
1141 | - return '' |
1142 | - index = self.expect (['\r\n', self.delimiter]) # delimiter default is EOF |
1143 | - if index == 0: |
1144 | - return self.before + '\r\n' |
1145 | - else: |
1146 | - return self.before |
1147 | - |
1148 | - def __iter__ (self): # File-like object. |
1149 | - |
1150 | - """This is to support iterators over a file-like object. |
1151 | - """ |
1152 | - |
1153 | - return self |
1154 | - |
1155 | - def next (self): # File-like object. |
1156 | - |
1157 | - """This is to support iterators over a file-like object. |
1158 | - """ |
1159 | - |
1160 | - result = self.readline() |
1161 | - if result == "": |
1162 | - raise StopIteration |
1163 | - return result |
1164 | - |
1165 | - def readlines (self, sizehint = -1): # File-like object. |
1166 | - |
1167 | - """This reads until EOF using readline() and returns a list containing |
1168 | - the lines thus read. The optional "sizehint" argument is ignored. """ |
1169 | - |
1170 | - lines = [] |
1171 | - while True: |
1172 | - line = self.readline() |
1173 | - if not line: |
1174 | - break |
1175 | - lines.append(line) |
1176 | - return lines |
1177 | - |
1178 | - def write(self, s): # File-like object. |
1179 | - |
1180 | - """This is similar to send() except that there is no return value. |
1181 | - """ |
1182 | - |
1183 | - self.send (s) |
1184 | - |
1185 | - def writelines (self, sequence): # File-like object. |
1186 | - |
1187 | - """This calls write() for each element in the sequence. The sequence |
1188 | - can be any iterable object producing strings, typically a list of |
1189 | - strings. This does not add line separators There is no return value. |
1190 | - """ |
1191 | - |
1192 | - for s in sequence: |
1193 | - self.write (s) |
1194 | - |
1195 | - def send(self, s): |
1196 | - |
1197 | - """This sends a string to the child process. This returns the number of |
1198 | - bytes written. If a log file was set then the data is also written to |
1199 | - the log. """ |
1200 | - |
1201 | - time.sleep(self.delaybeforesend) |
1202 | - if self.logfile is not None: |
1203 | - self.logfile.write (s) |
1204 | - self.logfile.flush() |
1205 | - if self.logfile_send is not None: |
1206 | - self.logfile_send.write (s) |
1207 | - self.logfile_send.flush() |
1208 | - c = os.write(self.child_fd, s) |
1209 | - return c |
1210 | - |
1211 | - def sendline(self, s=''): |
1212 | - |
1213 | - """This is like send(), but it adds a line feed (os.linesep). This |
1214 | - returns the number of bytes written. """ |
1215 | - |
1216 | - n = self.send(s) |
1217 | - n = n + self.send (os.linesep) |
1218 | - return n |
1219 | - |
1220 | - def sendcontrol(self, char): |
1221 | - |
1222 | - """This sends a control character to the child such as Ctrl-C or |
1223 | - Ctrl-D. For example, to send a Ctrl-G (ASCII 7):: |
1224 | - |
1225 | - child.sendcontrol('g') |
1226 | - |
1227 | - See also, sendintr() and sendeof(). |
1228 | - """ |
1229 | - |
1230 | - char = char.lower() |
1231 | - a = ord(char) |
1232 | - if a>=97 and a<=122: |
1233 | - a = a - ord('a') + 1 |
1234 | - return self.send (chr(a)) |
1235 | - d = {'@':0, '`':0, |
1236 | - '[':27, '{':27, |
1237 | - '\\':28, '|':28, |
1238 | - ']':29, '}': 29, |
1239 | - '^':30, '~':30, |
1240 | - '_':31, |
1241 | - '?':127} |
1242 | - if char not in d: |
1243 | - return 0 |
1244 | - return self.send (chr(d[char])) |
1245 | - |
1246 | - def sendeof(self): |
1247 | - |
1248 | - """This sends an EOF to the child. This sends a character which causes |
1249 | - the pending parent output buffer to be sent to the waiting child |
1250 | - program without waiting for end-of-line. If it is the first character |
1251 | - of the line, the read() in the user program returns 0, which signifies |
1252 | - end-of-file. This means to work as expected a sendeof() has to be |
1253 | - called at the beginning of a line. This method does not send a newline. |
1254 | - It is the responsibility of the caller to ensure the eof is sent at the |
1255 | - beginning of a line. """ |
1256 | - |
1257 | - ### Hmmm... how do I send an EOF? |
1258 | - ###C if ((m = write(pty, *buf, p - *buf)) < 0) |
1259 | - ###C return (errno == EWOULDBLOCK) ? n : -1; |
1260 | - #fd = sys.stdin.fileno() |
1261 | - #old = termios.tcgetattr(fd) # remember current state |
1262 | - #attr = termios.tcgetattr(fd) |
1263 | - #attr[3] = attr[3] | termios.ICANON # ICANON must be set to recognize EOF |
1264 | - #try: # use try/finally to ensure state gets restored |
1265 | - # termios.tcsetattr(fd, termios.TCSADRAIN, attr) |
1266 | - # if hasattr(termios, 'CEOF'): |
1267 | - # os.write (self.child_fd, '%c' % termios.CEOF) |
1268 | - # else: |
1269 | - # # Silly platform does not define CEOF so assume CTRL-D |
1270 | - # os.write (self.child_fd, '%c' % 4) |
1271 | - #finally: # restore state |
1272 | - # termios.tcsetattr(fd, termios.TCSADRAIN, old) |
1273 | - if hasattr(termios, 'VEOF'): |
1274 | - char = termios.tcgetattr(self.child_fd)[6][termios.VEOF] |
1275 | - else: |
1276 | - # platform does not define VEOF so assume CTRL-D |
1277 | - char = chr(4) |
1278 | - self.send(char) |
1279 | - |
1280 | - def sendintr(self): |
1281 | - |
1282 | - """This sends a SIGINT to the child. It does not require |
1283 | - the SIGINT to be the first character on a line. """ |
1284 | - |
1285 | - if hasattr(termios, 'VINTR'): |
1286 | - char = termios.tcgetattr(self.child_fd)[6][termios.VINTR] |
1287 | - else: |
1288 | - # platform does not define VINTR so assume CTRL-C |
1289 | - char = chr(3) |
1290 | - self.send (char) |
1291 | - |
1292 | - def eof (self): |
1293 | - |
1294 | - """This returns True if the EOF exception was ever raised. |
1295 | - """ |
1296 | - |
1297 | - return self.flag_eof |
1298 | - |
1299 | - def terminate(self, force=False): |
1300 | - |
1301 | - """This forces a child process to terminate. It starts nicely with |
1302 | - SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This |
1303 | - returns True if the child was terminated. This returns False if the |
1304 | - child could not be terminated. """ |
1305 | - |
1306 | - if not self.isalive(): |
1307 | - return True |
1308 | - try: |
1309 | - self.kill(signal.SIGHUP) |
1310 | - time.sleep(self.delayafterterminate) |
1311 | - if not self.isalive(): |
1312 | - return True |
1313 | - self.kill(signal.SIGCONT) |
1314 | - time.sleep(self.delayafterterminate) |
1315 | - if not self.isalive(): |
1316 | - return True |
1317 | - self.kill(signal.SIGINT) |
1318 | - time.sleep(self.delayafterterminate) |
1319 | - if not self.isalive(): |
1320 | - return True |
1321 | - if force: |
1322 | - self.kill(signal.SIGKILL) |
1323 | - time.sleep(self.delayafterterminate) |
1324 | - if not self.isalive(): |
1325 | - return True |
1326 | - else: |
1327 | - return False |
1328 | - return False |
1329 | - except OSError, e: |
1330 | - # I think there are kernel timing issues that sometimes cause |
1331 | - # this to happen. I think isalive() reports True, but the |
1332 | - # process is dead to the kernel. |
1333 | - # Make one last attempt to see if the kernel is up to date. |
1334 | - time.sleep(self.delayafterterminate) |
1335 | - if not self.isalive(): |
1336 | - return True |
1337 | - else: |
1338 | - return False |
1339 | - |
1340 | - def wait(self): |
1341 | - |
1342 | - """This waits until the child exits. This is a blocking call. This will |
1343 | - not read any data from the child, so this will block forever if the |
1344 | - child has unread output and has terminated. In other words, the child |
1345 | - may have printed output then called exit(); but, technically, the child |
1346 | - is still alive until its output is read. """ |
1347 | - |
1348 | - if self.isalive(): |
1349 | - pid, status = os.waitpid(self.pid, 0) #@UnusedVariable |
1350 | - else: |
1351 | - raise ExceptionPexpect ('Cannot wait for dead child process.') |
1352 | - self.exitstatus = os.WEXITSTATUS(status) |
1353 | - if os.WIFEXITED (status): |
1354 | - self.status = status |
1355 | - self.exitstatus = os.WEXITSTATUS(status) |
1356 | - self.signalstatus = None |
1357 | - self.terminated = True |
1358 | - elif os.WIFSIGNALED (status): |
1359 | - self.status = status |
1360 | - self.exitstatus = None |
1361 | - self.signalstatus = os.WTERMSIG(status) |
1362 | - self.terminated = True |
1363 | - elif os.WIFSTOPPED (status): |
1364 | - raise ExceptionPexpect ('Wait was called for a child process that is stopped. This is not supported. Is some other process attempting job control with our child pid?') |
1365 | - return self.exitstatus |
1366 | - |
1367 | - def isalive(self): |
1368 | - |
1369 | - """This tests if the child process is running or not. This is |
1370 | - non-blocking. If the child was terminated then this will read the |
1371 | - exitstatus or signalstatus of the child. This returns True if the child |
1372 | - process appears to be running or False if not. It can take literally |
1373 | - SECONDS for Solaris to return the right status. """ |
1374 | - |
1375 | - if self.terminated: |
1376 | - return False |
1377 | - |
1378 | - if self.flag_eof: |
1379 | - # This is for Linux, which requires the blocking form of waitpid to get |
1380 | - # status of a defunct process. This is super-lame. The flag_eof would have |
1381 | - # been set in read_nonblocking(), so this should be safe. |
1382 | - waitpid_options = 0 |
1383 | - else: |
1384 | - waitpid_options = os.WNOHANG |
1385 | - |
1386 | - try: |
1387 | - pid, status = os.waitpid(self.pid, waitpid_options) |
1388 | - except OSError, e: # No child processes |
1389 | - if e[0] == errno.ECHILD: |
1390 | - raise ExceptionPexpect ('isalive() encountered condition where "terminated" is 0, but there was no child process. Did someone else call waitpid() on our process?') |
1391 | - else: |
1392 | - raise e |
1393 | - |
1394 | - # I have to do this twice for Solaris. I can't even believe that I figured this out... |
1395 | - # If waitpid() returns 0 it means that no child process wishes to |
1396 | - # report, and the value of status is undefined. |
1397 | - if pid == 0: |
1398 | - try: |
1399 | - pid, status = os.waitpid(self.pid, waitpid_options) ### os.WNOHANG) # Solaris! |
1400 | - except OSError, e: # This should never happen... |
1401 | - if e[0] == errno.ECHILD: |
1402 | - raise ExceptionPexpect ('isalive() encountered condition that should never happen. There was no child process. Did someone else call waitpid() on our process?') |
1403 | - else: |
1404 | - raise e |
1405 | - |
1406 | - # If pid is still 0 after two calls to waitpid() then |
1407 | - # the process really is alive. This seems to work on all platforms, except |
1408 | - # for Irix which seems to require a blocking call on waitpid or select, so I let read_nonblocking |
1409 | - # take care of this situation (unfortunately, this requires waiting through the timeout). |
1410 | - if pid == 0: |
1411 | - return True |
1412 | - |
1413 | - if pid == 0: |
1414 | - return True |
1415 | - |
1416 | - if os.WIFEXITED (status): |
1417 | - self.status = status |
1418 | - self.exitstatus = os.WEXITSTATUS(status) |
1419 | - self.signalstatus = None |
1420 | - self.terminated = True |
1421 | - elif os.WIFSIGNALED (status): |
1422 | - self.status = status |
1423 | - self.exitstatus = None |
1424 | - self.signalstatus = os.WTERMSIG(status) |
1425 | - self.terminated = True |
1426 | - elif os.WIFSTOPPED (status): |
1427 | - raise ExceptionPexpect ('isalive() encountered condition where child process is stopped. This is not supported. Is some other process attempting job control with our child pid?') |
1428 | - return False |
1429 | - |
1430 | - def kill(self, sig): |
1431 | - |
1432 | - """This sends the given signal to the child application. In keeping |
1433 | - with UNIX tradition it has a misleading name. It does not necessarily |
1434 | - kill the child unless you send the right signal. """ |
1435 | - |
1436 | - # Same as os.kill, but the pid is given for you. |
1437 | - if self.isalive(): |
1438 | - os.kill(self.pid, sig) |
1439 | - |
1440 | - def compile_pattern_list(self, patterns): |
1441 | - |
1442 | - """This compiles a pattern-string or a list of pattern-strings. |
1443 | - Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of |
1444 | - those. Patterns may also be None which results in an empty list (you |
1445 | - might do this if waiting for an EOF or TIMEOUT condition without |
1446 | - expecting any pattern). |
1447 | - |
1448 | - This is used by expect() when calling expect_list(). Thus expect() is |
1449 | - nothing more than:: |
1450 | - |
1451 | - cpl = self.compile_pattern_list(pl) |
1452 | - return self.expect_list(cpl, timeout) |
1453 | - |
1454 | - If you are using expect() within a loop it may be more |
1455 | - efficient to compile the patterns first and then call expect_list(). |
1456 | - This avoid calls in a loop to compile_pattern_list():: |
1457 | - |
1458 | - cpl = self.compile_pattern_list(my_pattern) |
1459 | - while some_condition: |
1460 | - ... |
1461 | - i = self.expect_list(clp, timeout) |
1462 | - ... |
1463 | - """ |
1464 | - |
1465 | - if patterns is None: |
1466 | - return [] |
1467 | - if type(patterns) is not types.ListType: |
1468 | - patterns = [patterns] |
1469 | - |
1470 | - compile_flags = re.DOTALL # Allow dot to match \n |
1471 | - if self.ignorecase: |
1472 | - compile_flags = compile_flags | re.IGNORECASE |
1473 | - compiled_pattern_list = [] |
1474 | - for p in patterns: |
1475 | - if type(p) in types.StringTypes: |
1476 | - compiled_pattern_list.append(re.compile(p, compile_flags)) |
1477 | - elif p is EOF: |
1478 | - compiled_pattern_list.append(EOF) |
1479 | - elif p is TIMEOUT: |
1480 | - compiled_pattern_list.append(TIMEOUT) |
1481 | - elif type(p) is type(re.compile('')): |
1482 | - compiled_pattern_list.append(p) |
1483 | - else: |
1484 | - raise TypeError ('Argument must be one of StringTypes, EOF, TIMEOUT, SRE_Pattern, or a list of those type. %s' % str(type(p))) |
1485 | - |
1486 | - return compiled_pattern_list |
1487 | - |
1488 | - def expect(self, pattern, timeout = -1, searchwindowsize=None): |
1489 | - |
1490 | - """This seeks through the stream until a pattern is matched. The |
1491 | - pattern is overloaded and may take several types. The pattern can be a |
1492 | - StringType, EOF, a compiled re, or a list of any of those types. |
1493 | - Strings will be compiled to re types. This returns the index into the |
1494 | - pattern list. If the pattern was not a list this returns index 0 on a |
1495 | - successful match. This may raise exceptions for EOF or TIMEOUT. To |
1496 | - avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern |
1497 | - list. That will cause expect to match an EOF or TIMEOUT condition |
1498 | - instead of raising an exception. |
1499 | - |
1500 | - If you pass a list of patterns and more than one matches, the first match |
1501 | - in the stream is chosen. If more than one pattern matches at that point, |
1502 | - the leftmost in the pattern list is chosen. For example:: |
1503 | - |
1504 | - # the input is 'foobar' |
1505 | - index = p.expect (['bar', 'foo', 'foobar']) |
1506 | - # returns 1 ('foo') even though 'foobar' is a "better" match |
1507 | - |
1508 | - Please note, however, that buffering can affect this behavior, since |
1509 | - input arrives in unpredictable chunks. For example:: |
1510 | - |
1511 | - # the input is 'foobar' |
1512 | - index = p.expect (['foobar', 'foo']) |
1513 | - # returns 0 ('foobar') if all input is available at once, |
1514 | - # but returs 1 ('foo') if parts of the final 'bar' arrive late |
1515 | - |
1516 | - After a match is found the instance attributes 'before', 'after' and |
1517 | - 'match' will be set. You can see all the data read before the match in |
1518 | - 'before'. You can see the data that was matched in 'after'. The |
1519 | - re.MatchObject used in the re match will be in 'match'. If an error |
1520 | - occurred then 'before' will be set to all the data read so far and |
1521 | - 'after' and 'match' will be None. |
1522 | - |
1523 | - If timeout is -1 then timeout will be set to the self.timeout value. |
1524 | - |
1525 | - A list entry may be EOF or TIMEOUT instead of a string. This will |
1526 | - catch these exceptions and return the index of the list entry instead |
1527 | - of raising the exception. The attribute 'after' will be set to the |
1528 | - exception type. The attribute 'match' will be None. This allows you to |
1529 | - write code like this:: |
1530 | - |
1531 | - index = p.expect (['good', 'bad', pexpect.EOF, pexpect.TIMEOUT]) |
1532 | - if index == 0: |
1533 | - do_something() |
1534 | - elif index == 1: |
1535 | - do_something_else() |
1536 | - elif index == 2: |
1537 | - do_some_other_thing() |
1538 | - elif index == 3: |
1539 | - do_something_completely_different() |
1540 | - |
1541 | - instead of code like this:: |
1542 | - |
1543 | - try: |
1544 | - index = p.expect (['good', 'bad']) |
1545 | - if index == 0: |
1546 | - do_something() |
1547 | - elif index == 1: |
1548 | - do_something_else() |
1549 | - except EOF: |
1550 | - do_some_other_thing() |
1551 | - except TIMEOUT: |
1552 | - do_something_completely_different() |
1553 | - |
1554 | - These two forms are equivalent. It all depends on what you want. You |
1555 | - can also just expect the EOF if you are waiting for all output of a |
1556 | - child to finish. For example:: |
1557 | - |
1558 | - p = pexpect.spawn('/bin/ls') |
1559 | - p.expect (pexpect.EOF) |
1560 | - print p.before |
1561 | - |
1562 | - If you are trying to optimize for speed then see expect_list(). |
1563 | - """ |
1564 | - |
1565 | - compiled_pattern_list = self.compile_pattern_list(pattern) |
1566 | - return self.expect_list(compiled_pattern_list, timeout, searchwindowsize) |
1567 | - |
1568 | - def expect_list(self, pattern_list, timeout = -1, searchwindowsize = -1): |
1569 | - |
1570 | - """This takes a list of compiled regular expressions and returns the |
1571 | - index into the pattern_list that matched the child output. The list may |
1572 | - also contain EOF or TIMEOUT (which are not compiled regular |
1573 | - expressions). This method is similar to the expect() method except that |
1574 | - expect_list() does not recompile the pattern list on every call. This |
1575 | - may help if you are trying to optimize for speed, otherwise just use |
1576 | - the expect() method. This is called by expect(). If timeout==-1 then |
1577 | - the self.timeout value is used. If searchwindowsize==-1 then the |
1578 | - self.searchwindowsize value is used. """ |
1579 | - |
1580 | - return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize) |
1581 | - |
1582 | - def expect_exact(self, pattern_list, timeout = -1, searchwindowsize = -1): |
1583 | - |
1584 | - """This is similar to expect(), but uses plain string matching instead |
1585 | - of compiled regular expressions in 'pattern_list'. The 'pattern_list' |
1586 | - may be a string; a list or other sequence of strings; or TIMEOUT and |
1587 | - EOF. |
1588 | - |
1589 | - This call might be faster than expect() for two reasons: string |
1590 | - searching is faster than RE matching and it is possible to limit the |
1591 | - search to just the end of the input buffer. |
1592 | - |
1593 | - This method is also useful when you don't want to have to worry about |
1594 | - escaping regular expression characters that you want to match.""" |
1595 | - |
1596 | - if type(pattern_list) in types.StringTypes or pattern_list in (TIMEOUT, EOF): |
1597 | - pattern_list = [pattern_list] |
1598 | - return self.expect_loop(searcher_string(pattern_list), timeout, searchwindowsize) |
1599 | - |
1600 | - def expect_loop(self, searcher, timeout = -1, searchwindowsize = -1): |
1601 | - |
1602 | - """This is the common loop used inside expect. The 'searcher' should be |
1603 | - an instance of searcher_re or searcher_string, which describes how and what |
1604 | - to search for in the input. |
1605 | - |
1606 | - See expect() for other arguments, return value and exceptions. """ |
1607 | - |
1608 | - self.searcher = searcher |
1609 | - |
1610 | - if timeout == -1: |
1611 | - timeout = self.timeout |
1612 | - if timeout is not None: |
1613 | - end_time = time.time() + timeout |
1614 | - if searchwindowsize == -1: |
1615 | - searchwindowsize = self.searchwindowsize |
1616 | - |
1617 | - try: |
1618 | - incoming = self.buffer |
1619 | - freshlen = len(incoming) |
1620 | - while True: # Keep reading until exception or return. |
1621 | - index = searcher.search(incoming, freshlen, searchwindowsize) |
1622 | - if index >= 0: |
1623 | - self.buffer = incoming[searcher.end : ] |
1624 | - self.before = incoming[ : searcher.start] |
1625 | - self.after = incoming[searcher.start : searcher.end] |
1626 | - self.match = searcher.match |
1627 | - self.match_index = index |
1628 | - return self.match_index |
1629 | - # No match at this point |
1630 | - if timeout < 0 and timeout is not None: |
1631 | - raise TIMEOUT ('Timeout exceeded in expect_any().') |
1632 | - # Still have time left, so read more data |
1633 | - c = self.read_nonblocking (self.maxread, timeout) |
1634 | - freshlen = len(c) |
1635 | - time.sleep (0.0001) |
1636 | - incoming = incoming + c |
1637 | - if timeout is not None: |
1638 | - timeout = end_time - time.time() |
1639 | - except EOF, e: |
1640 | - self.buffer = '' |
1641 | - self.before = incoming |
1642 | - self.after = EOF |
1643 | - index = searcher.eof_index |
1644 | - if index >= 0: |
1645 | - self.match = EOF |
1646 | - self.match_index = index |
1647 | - return self.match_index |
1648 | - else: |
1649 | - self.match = None |
1650 | - self.match_index = None |
1651 | - raise EOF (str(e) + '\n' + str(self)) |
1652 | - except TIMEOUT, e: |
1653 | - self.buffer = incoming |
1654 | - self.before = incoming |
1655 | - self.after = TIMEOUT |
1656 | - index = searcher.timeout_index |
1657 | - if index >= 0: |
1658 | - self.match = TIMEOUT |
1659 | - self.match_index = index |
1660 | - return self.match_index |
1661 | - else: |
1662 | - self.match = None |
1663 | - self.match_index = None |
1664 | - raise TIMEOUT (str(e) + '\n' + str(self)) |
1665 | - except Exception: |
1666 | - self.before = incoming |
1667 | - self.after = None |
1668 | - self.match = None |
1669 | - self.match_index = None |
1670 | - raise |
1671 | - |
1672 | - def getwinsize(self): |
1673 | - |
1674 | - """This returns the terminal window size of the child tty. The return |
1675 | - value is a tuple of (rows, cols). """ |
1676 | - |
1677 | - TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912L) |
1678 | - s = struct.pack('HHHH', 0, 0, 0, 0) |
1679 | - x = fcntl.ioctl(self.fileno(), TIOCGWINSZ, s) |
1680 | - return struct.unpack('HHHH', x)[0:2] |
1681 | - |
1682 | - def setwinsize(self, r, c): |
1683 | - |
1684 | - """This sets the terminal window size of the child tty. This will cause |
1685 | - a SIGWINCH signal to be sent to the child. This does not change the |
1686 | - physical window size. It changes the size reported to TTY-aware |
1687 | - applications like vi or curses -- applications that respond to the |
1688 | - SIGWINCH signal. """ |
1689 | - |
1690 | - # Check for buggy platforms. Some Python versions on some platforms |
1691 | - # (notably OSF1 Alpha and RedHat 7.1) truncate the value for |
1692 | - # termios.TIOCSWINSZ. It is not clear why this happens. |
1693 | - # These platforms don't seem to handle the signed int very well; |
1694 | - # yet other platforms like OpenBSD have a large negative value for |
1695 | - # TIOCSWINSZ and they don't have a truncate problem. |
1696 | - # Newer versions of Linux have totally different values for TIOCSWINSZ. |
1697 | - # Note that this fix is a hack. |
1698 | - TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561) |
1699 | - if TIOCSWINSZ == 2148037735L: # L is not required in Python >= 2.2. |
1700 | - TIOCSWINSZ = -2146929561 # Same bits, but with sign. |
1701 | - # Note, assume ws_xpixel and ws_ypixel are zero. |
1702 | - s = struct.pack('HHHH', r, c, 0, 0) |
1703 | - fcntl.ioctl(self.fileno(), TIOCSWINSZ, s) |
1704 | - |
1705 | - def interact(self, escape_character = chr(29), input_filter = None, output_filter = None): |
1706 | - |
1707 | - """This gives control of the child process to the interactive user (the |
1708 | - human at the keyboard). Keystrokes are sent to the child process, and |
1709 | - the stdout and stderr output of the child process is printed. This |
1710 | - simply echos the child stdout and child stderr to the real stdout and |
1711 | - it echos the real stdin to the child stdin. When the user types the |
1712 | - escape_character this method will stop. The default for |
1713 | - escape_character is ^]. This should not be confused with ASCII 27 -- |
1714 | - the ESC character. ASCII 29 was chosen for historical merit because |
1715 | - this is the character used by 'telnet' as the escape character. The |
1716 | - escape_character will not be sent to the child process. |
1717 | - |
1718 | - You may pass in optional input and output filter functions. These |
1719 | - functions should take a string and return a string. The output_filter |
1720 | - will be passed all the output from the child process. The input_filter |
1721 | - will be passed all the keyboard input from the user. The input_filter |
1722 | - is run BEFORE the check for the escape_character. |
1723 | - |
1724 | - Note that if you change the window size of the parent the SIGWINCH |
1725 | - signal will not be passed through to the child. If you want the child |
1726 | - window size to change when the parent's window size changes then do |
1727 | - something like the following example:: |
1728 | - |
1729 | - import pexpect, struct, fcntl, termios, signal, sys |
1730 | - def sigwinch_passthrough (sig, data): |
1731 | - s = struct.pack("HHHH", 0, 0, 0, 0) |
1732 | - a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ , s)) |
1733 | - global p |
1734 | - p.setwinsize(a[0],a[1]) |
1735 | - p = pexpect.spawn('/bin/bash') # Note this is global and used in sigwinch_passthrough. |
1736 | - signal.signal(signal.SIGWINCH, sigwinch_passthrough) |
1737 | - p.interact() |
1738 | - """ |
1739 | - |
1740 | - # Flush the buffer. |
1741 | - self.stdout.write (self.buffer) |
1742 | - self.stdout.flush() |
1743 | - self.buffer = '' |
1744 | - mode = tty.tcgetattr(self.STDIN_FILENO) |
1745 | - tty.setraw(self.STDIN_FILENO) |
1746 | - try: |
1747 | - self.__interact_copy(escape_character, input_filter, output_filter) |
1748 | - finally: |
1749 | - tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode) |
1750 | - |
1751 | - def __interact_writen(self, fd, data): |
1752 | - |
1753 | - """This is used by the interact() method. |
1754 | - """ |
1755 | - |
1756 | - while data != '' and self.isalive(): |
1757 | - n = os.write(fd, data) |
1758 | - data = data[n:] |
1759 | - |
1760 | - def __interact_read(self, fd): |
1761 | - |
1762 | - """This is used by the interact() method. |
1763 | - """ |
1764 | - |
1765 | - return os.read(fd, 1000) |
1766 | - |
1767 | - def __interact_copy(self, escape_character = None, input_filter = None, output_filter = None): |
1768 | - |
1769 | - """This is used by the interact() method. |
1770 | - """ |
1771 | - |
1772 | - while self.isalive(): |
1773 | - r,w,e = self.__select([self.child_fd, self.STDIN_FILENO], [], []) #@UnusedVariable |
1774 | - if self.child_fd in r: |
1775 | - data = self.__interact_read(self.child_fd) |
1776 | - if output_filter: data = output_filter(data) |
1777 | - if self.logfile is not None: |
1778 | - self.logfile.write (data) |
1779 | - self.logfile.flush() |
1780 | - os.write(self.STDOUT_FILENO, data) |
1781 | - if self.STDIN_FILENO in r: |
1782 | - data = self.__interact_read(self.STDIN_FILENO) |
1783 | - if input_filter: data = input_filter(data) |
1784 | - i = data.rfind(escape_character) |
1785 | - if i != -1: |
1786 | - data = data[:i] |
1787 | - self.__interact_writen(self.child_fd, data) |
1788 | - break |
1789 | - self.__interact_writen(self.child_fd, data) |
1790 | - |
1791 | - def __select (self, iwtd, owtd, ewtd, timeout=None): |
1792 | - |
1793 | - """This is a wrapper around select.select() that ignores signals. If |
1794 | - select.select raises a select.error exception and errno is an EINTR |
1795 | - error then it is ignored. Mainly this is used to ignore sigwinch |
1796 | - (terminal resize). """ |
1797 | - |
1798 | - # if select() is interrupted by a signal (errno==EINTR) then |
1799 | - # we loop back and enter the select() again. |
1800 | - if timeout is not None: |
1801 | - end_time = time.time() + timeout |
1802 | - while True: |
1803 | - try: |
1804 | - return select.select (iwtd, owtd, ewtd, timeout) |
1805 | - except select.error, e: |
1806 | - if e[0] == errno.EINTR: |
1807 | - # if we loop back we have to subtract the amount of time we already waited. |
1808 | - if timeout is not None: |
1809 | - timeout = end_time - time.time() |
1810 | - if timeout < 0: |
1811 | - return ([],[],[]) |
1812 | - else: # something else caused the select.error, so this really is an exception |
1813 | - raise |
1814 | - |
1815 | -############################################################################## |
1816 | -# The following methods are no longer supported or allowed. |
1817 | - |
1818 | - def setmaxread (self, maxread): |
1819 | - |
1820 | - """This method is no longer supported or allowed. I don't like getters |
1821 | - and setters without a good reason. """ |
1822 | - |
1823 | - raise ExceptionPexpect ('This method is no longer supported or allowed. Just assign a value to the maxread member variable.') |
1824 | - |
1825 | - def setlog (self, fileobject): |
1826 | - |
1827 | - """This method is no longer supported or allowed. |
1828 | - """ |
1829 | - |
1830 | - raise ExceptionPexpect ('This method is no longer supported or allowed. Just assign a value to the logfile member variable.') |
1831 | - |
1832 | -############################################################################## |
1833 | -# End of spawn class |
1834 | -############################################################################## |
1835 | - |
1836 | -class searcher_string (object): |
1837 | - |
1838 | - """This is a plain string search helper for the spawn.expect_any() method. |
1839 | - |
1840 | - Attributes: |
1841 | - |
1842 | - eof_index - index of EOF, or -1 |
1843 | - timeout_index - index of TIMEOUT, or -1 |
1844 | - |
1845 | - After a successful match by the search() method the following attributes |
1846 | - are available: |
1847 | - |
1848 | - start - index into the buffer, first byte of match |
1849 | - end - index into the buffer, first byte after match |
1850 | - match - the matching string itself |
1851 | - """ |
1852 | - |
1853 | - def __init__(self, strings): |
1854 | - |
1855 | - """This creates an instance of searcher_string. This argument 'strings' |
1856 | - may be a list; a sequence of strings; or the EOF or TIMEOUT types. """ |
1857 | - |
1858 | - self.eof_index = -1 |
1859 | - self.timeout_index = -1 |
1860 | - self._strings = [] |
1861 | - for n, s in zip(range(len(strings)), strings): |
1862 | - if s is EOF: |
1863 | - self.eof_index = n |
1864 | - continue |
1865 | - if s is TIMEOUT: |
1866 | - self.timeout_index = n |
1867 | - continue |
1868 | - self._strings.append((n, s)) |
1869 | - |
1870 | - def __str__(self): |
1871 | - |
1872 | - """This returns a human-readable string that represents the state of |
1873 | - the object.""" |
1874 | - |
1875 | - ss = [ (ns[0],' %d: "%s"' % ns) for ns in self._strings ] |
1876 | - ss.append((-1,'searcher_string:')) |
1877 | - if self.eof_index >= 0: |
1878 | - ss.append ((self.eof_index,' %d: EOF' % self.eof_index)) |
1879 | - if self.timeout_index >= 0: |
1880 | - ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index)) |
1881 | - ss.sort() |
1882 | - ss = zip(*ss)[1] |
1883 | - return '\n'.join(ss) |
1884 | - |
1885 | - def search(self, buffer, freshlen, searchwindowsize=None): |
1886 | - |
1887 | - """This searches 'buffer' for the first occurence of one of the search |
1888 | - strings. 'freshlen' must indicate the number of bytes at the end of |
1889 | - 'buffer' which have not been searched before. It helps to avoid |
1890 | - searching the same, possibly big, buffer over and over again. |
1891 | - |
1892 | - See class spawn for the 'searchwindowsize' argument. |
1893 | - |
1894 | - If there is a match this returns the index of that string, and sets |
1895 | - 'start', 'end' and 'match'. Otherwise, this returns -1. """ |
1896 | - |
1897 | - absurd_match = len(buffer) |
1898 | - first_match = absurd_match |
1899 | - |
1900 | - # 'freshlen' helps a lot here. Further optimizations could |
1901 | - # possibly include: |
1902 | - # |
1903 | - # using something like the Boyer-Moore Fast String Searching |
1904 | - # Algorithm; pre-compiling the search through a list of |
1905 | - # strings into something that can scan the input once to |
1906 | - # search for all N strings; realize that if we search for |
1907 | - # ['bar', 'baz'] and the input is '...foo' we need not bother |
1908 | - # rescanning until we've read three more bytes. |
1909 | - # |
1910 | - # Sadly, I don't know enough about this interesting topic. /grahn |
1911 | - |
1912 | - for index, s in self._strings: |
1913 | - if searchwindowsize is None: |
1914 | - # the match, if any, can only be in the fresh data, |
1915 | - # or at the very end of the old data |
1916 | - offset = -(freshlen+len(s)) |
1917 | - else: |
1918 | - # better obey searchwindowsize |
1919 | - offset = -searchwindowsize |
1920 | - n = buffer.find(s, offset) |
1921 | - if n >= 0 and n < first_match: |
1922 | - first_match = n |
1923 | - best_index, best_match = index, s |
1924 | - if first_match == absurd_match: |
1925 | - return -1 |
1926 | - self.match = best_match |
1927 | - self.start = first_match |
1928 | - self.end = self.start + len(self.match) |
1929 | - return best_index |
1930 | - |
1931 | -class searcher_re (object): |
1932 | - |
1933 | - """This is regular expression string search helper for the |
1934 | - spawn.expect_any() method. |
1935 | - |
1936 | - Attributes: |
1937 | - |
1938 | - eof_index - index of EOF, or -1 |
1939 | - timeout_index - index of TIMEOUT, or -1 |
1940 | - |
1941 | - After a successful match by the search() method the following attributes |
1942 | - are available: |
1943 | - |
1944 | - start - index into the buffer, first byte of match |
1945 | - end - index into the buffer, first byte after match |
1946 | - match - the re.match object returned by a succesful re.search |
1947 | - |
1948 | - """ |
1949 | - |
1950 | - def __init__(self, patterns): |
1951 | - |
1952 | - """This creates an instance that searches for 'patterns' Where |
1953 | - 'patterns' may be a list or other sequence of compiled regular |
1954 | - expressions, or the EOF or TIMEOUT types.""" |
1955 | - |
1956 | - self.eof_index = -1 |
1957 | - self.timeout_index = -1 |
1958 | - self._searches = [] |
1959 | - for n, s in zip(range(len(patterns)), patterns): |
1960 | - if s is EOF: |
1961 | - self.eof_index = n |
1962 | - continue |
1963 | - if s is TIMEOUT: |
1964 | - self.timeout_index = n |
1965 | - continue |
1966 | - self._searches.append((n, s)) |
1967 | - |
1968 | - def __str__(self): |
1969 | - |
1970 | - """This returns a human-readable string that represents the state of |
1971 | - the object.""" |
1972 | - |
1973 | - ss = [ (n,' %d: re.compile("%s")' % (n,str(s.pattern))) for n,s in self._searches] |
1974 | - ss.append((-1,'searcher_re:')) |
1975 | - if self.eof_index >= 0: |
1976 | - ss.append ((self.eof_index,' %d: EOF' % self.eof_index)) |
1977 | - if self.timeout_index >= 0: |
1978 | - ss.append ((self.timeout_index,' %d: TIMEOUT' % self.timeout_index)) |
1979 | - ss.sort() |
1980 | - ss = zip(*ss)[1] |
1981 | - return '\n'.join(ss) |
1982 | - |
1983 | - def search(self, buffer, freshlen, searchwindowsize=None): |
1984 | - |
1985 | - """This searches 'buffer' for the first occurence of one of the regular |
1986 | - expressions. 'freshlen' must indicate the number of bytes at the end of |
1987 | - 'buffer' which have not been searched before. |
1988 | - |
1989 | - See class spawn for the 'searchwindowsize' argument. |
1990 | - |
1991 | - If there is a match this returns the index of that string, and sets |
1992 | - 'start', 'end' and 'match'. Otherwise, returns -1.""" |
1993 | - |
1994 | - absurd_match = len(buffer) |
1995 | - first_match = absurd_match |
1996 | - # 'freshlen' doesn't help here -- we cannot predict the |
1997 | - # length of a match, and the re module provides no help. |
1998 | - if searchwindowsize is None: |
1999 | - searchstart = 0 |
2000 | - else: |
2001 | - searchstart = max(0, len(buffer)-searchwindowsize) |
2002 | - for index, s in self._searches: |
2003 | - match = s.search(buffer, searchstart) |
2004 | - if match is None: |
2005 | - continue |
2006 | - n = match.start() |
2007 | - if n < first_match: |
2008 | - first_match = n |
2009 | - the_match = match |
2010 | - best_index = index |
2011 | - if first_match == absurd_match: |
2012 | - return -1 |
2013 | - self.start = first_match |
2014 | - self.match = the_match |
2015 | - self.end = self.match.end() |
2016 | - return best_index |
2017 | - |
2018 | -def which (filename): |
2019 | - |
2020 | - """This takes a given filename; tries to find it in the environment path; |
2021 | - then checks if it is executable. This returns the full path to the filename |
2022 | - if found and executable. Otherwise this returns None.""" |
2023 | - |
2024 | - # Special case where filename already contains a path. |
2025 | - if os.path.dirname(filename) != '': |
2026 | - if os.access (filename, os.X_OK): |
2027 | - return filename |
2028 | - |
2029 | - if not os.environ.has_key('PATH') or os.environ['PATH'] == '': |
2030 | - p = os.defpath |
2031 | - else: |
2032 | - p = os.environ['PATH'] |
2033 | - |
2034 | - # Oddly enough this was the one line that made Pexpect |
2035 | - # incompatible with Python 1.5.2. |
2036 | - #pathlist = p.split (os.pathsep) |
2037 | - pathlist = string.split (p, os.pathsep) |
2038 | - |
2039 | - for path in pathlist: |
2040 | - f = os.path.join(path, filename) |
2041 | - if os.access(f, os.X_OK): |
2042 | - return f |
2043 | - return None |
2044 | - |
2045 | -def split_command_line(command_line): |
2046 | - |
2047 | - """This splits a command line into a list of arguments. It splits arguments |
2048 | - on spaces, but handles embedded quotes, doublequotes, and escaped |
2049 | - characters. It's impossible to do this with a regular expression, so I |
2050 | - wrote a little state machine to parse the command line. """ |
2051 | - |
2052 | - arg_list = [] |
2053 | - arg = '' |
2054 | - |
2055 | - # Constants to name the states we can be in. |
2056 | - state_basic = 0 |
2057 | - state_esc = 1 |
2058 | - state_singlequote = 2 |
2059 | - state_doublequote = 3 |
2060 | - state_whitespace = 4 # The state of consuming whitespace between commands. |
2061 | - state = state_basic |
2062 | - |
2063 | - for c in command_line: |
2064 | - if state == state_basic or state == state_whitespace: |
2065 | - if c == '\\': # Escape the next character |
2066 | - state = state_esc |
2067 | - elif c == r"'": # Handle single quote |
2068 | - state = state_singlequote |
2069 | - elif c == r'"': # Handle double quote |
2070 | - state = state_doublequote |
2071 | - elif c.isspace(): |
2072 | - # Add arg to arg_list if we aren't in the middle of whitespace. |
2073 | - if state == state_whitespace: |
2074 | - None # Do nothing. |
2075 | - else: |
2076 | - arg_list.append(arg) |
2077 | - arg = '' |
2078 | - state = state_whitespace |
2079 | - else: |
2080 | - arg = arg + c |
2081 | - state = state_basic |
2082 | - elif state == state_esc: |
2083 | - arg = arg + c |
2084 | - state = state_basic |
2085 | - elif state == state_singlequote: |
2086 | - if c == r"'": |
2087 | - state = state_basic |
2088 | - else: |
2089 | - arg = arg + c |
2090 | - elif state == state_doublequote: |
2091 | - if c == r'"': |
2092 | - state = state_basic |
2093 | - else: |
2094 | - arg = arg + c |
2095 | - |
2096 | - if arg != '': |
2097 | - arg_list.append(arg) |
2098 | - return arg_list |
2099 | - |
2100 | -# vi:ts=4:sw=4:expandtab:ft=python: |
2101 | |
2102 | === modified file 'po/POTFILES.in' |
2103 | --- po/POTFILES.in 2014-04-16 20:45:09 +0000 |
2104 | +++ po/POTFILES.in 2014-04-17 19:52:16 +0000 |
2105 | @@ -29,7 +29,6 @@ |
2106 | duplicity/backends/_boto_single.py |
2107 | duplicity/backends/_boto_multi.py |
2108 | duplicity/backends/__init__.py |
2109 | -duplicity/backends/u1backend.py |
2110 | duplicity/backends/dpbxbackend.py |
2111 | duplicity/backends/ftpsbackend.py |
2112 | duplicity/backends/hsibackend.py |
2113 | @@ -52,7 +51,6 @@ |
2114 | duplicity/filechunkio.py |
2115 | duplicity/dup_threading.py |
2116 | duplicity/path.py |
2117 | -duplicity/pexpect.py |
2118 | duplicity/gpginterface.py |
2119 | duplicity/dup_time.py |
2120 | duplicity/gpg.py |
2121 | |
2122 | === modified file 'setup.py' |
2123 | --- setup.py 2014-04-16 20:45:09 +0000 |
2124 | +++ setup.py 2014-04-17 19:52:16 +0000 |
2125 | @@ -144,7 +144,7 @@ |
2126 | libraries=["rsync"])], |
2127 | scripts = ['bin/rdiffdir', 'bin/duplicity'], |
2128 | data_files = data_files, |
2129 | - tests_require = ['lockfile', 'mock', 'nose'], |
2130 | + tests_require = ['lockfile', 'mock', 'nose', 'pexpect'], |
2131 | test_suite = 'nose.collector', |
2132 | cmdclass={'test': TestCommand, |
2133 | 'install': InstallCommand, |
2134 | |
2135 | === modified file 'testing/helpers/helper.py' |
2136 | --- testing/helpers/helper.py 2014-04-16 02:43:43 +0000 |
2137 | +++ testing/helpers/helper.py 2014-04-17 19:52:16 +0000 |
2138 | @@ -20,13 +20,13 @@ |
2139 | # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
2140 | |
2141 | import os |
2142 | +import pexpect |
2143 | import time |
2144 | import unittest |
2145 | |
2146 | from duplicity import backend |
2147 | from duplicity import globals |
2148 | from duplicity import log |
2149 | -from duplicity import pexpect |
2150 | |
2151 | sign_key = '56538CCF' |
2152 | sign_passphrase = 'test' |
2153 | |
2154 | === modified file 'tox.ini' |
2155 | --- tox.ini 2014-04-16 18:37:39 +0000 |
2156 | +++ tox.ini 2014-04-17 19:52:16 +0000 |
2157 | @@ -5,4 +5,5 @@ |
2158 | deps=lockfile |
2159 | mock |
2160 | nose |
2161 | + pexpect |
2162 | commands=nosetests |