annotate rhodecode/lib/vcs/subprocessio.py @ 4116:ffd45b185016 rhodecode-2.2.5-gpl

Imported some of the GPLv3'd changes from RhodeCode v2.2.5. This imports changes between changesets 21af6c4eab3d and 6177597791c2 in RhodeCode's original repository, including only changes to Python files and HTML. RhodeCode clearly licensed its changes to these files under GPLv3 in their /LICENSE file, which states the following: The Python code and integrated HTML are licensed under the GPLv3 license. (See: https://code.rhodecode.com/rhodecode/files/v2.2.5/LICENSE or http://web.archive.org/web/20140512193334/https://code.rhodecode.com/rhodecode/files/f3b123159901f15426d18e3dc395e8369f70ebe0/LICENSE for an online copy of that LICENSE file) Conservancy reviewed these changes and confirmed that they can be licensed as a whole to the Kallithea project under GPLv3-only. While some of the contents committed herein are clearly licensed GPLv3-or-later, on the whole we must assume the are GPLv3-only, since the statement above from RhodeCode indicates that they intend GPLv3-only as their license, per GPLv3ยง14 and other relevant sections of GPLv3.
author Bradley M. Kuhn <bkuhn@sfconservancy.org>
date Wed, 02 Jul 2014 19:03:13 -0400
parents e39fb661998b
children 7e5f8c12a3fc
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
1 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
2 Module provides a class allowing to wrap communication over subprocess.Popen
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
3 input, output, error streams into a meaningfull, non-blocking, concurrent
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
4 stream processor exposing the output data as an iterator fitting to be a
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
5 return value passed by a WSGI applicaiton to a WSGI server per PEP 3333.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
6
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
7 Copyright (c) 2011 Daniel Dotsenko <dotsa[at]hotmail.com>
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
8
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
9 This file is part of git_http_backend.py Project.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
10
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
11 git_http_backend.py Project is free software: you can redistribute it and/or
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
12 modify it under the terms of the GNU Lesser General Public License as
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
13 published by the Free Software Foundation, either version 2.1 of the License,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
14 or (at your option) any later version.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
15
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
16 git_http_backend.py Project is distributed in the hope that it will be useful,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
19 GNU Lesser General Public License for more details.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
20
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
21 You should have received a copy of the GNU Lesser General Public License
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
22 along with git_http_backend.py Project.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
23 If not, see <http://www.gnu.org/licenses/>.
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
24 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
25 import os
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
26 import subprocess
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
27 from rhodecode.lib.vcs.utils.compat import deque, Event, Thread, _bytes, _bytearray
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
28
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
29
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
30 class StreamFeeder(Thread):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
31 """
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
32 Normal writing into pipe-like is blocking once the buffer is filled.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
33 This thread allows a thread to seep data from a file-like into a pipe
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
34 without blocking the main thread.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
35 We close inpipe once the end of the source stream is reached.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
36 """
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
37
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
38 def __init__(self, source):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
39 super(StreamFeeder, self).__init__()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
40 self.daemon = True
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
41 filelike = False
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
42 self.bytes = _bytes()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
43 if type(source) in (type(''), _bytes, _bytearray): # string-like
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
44 self.bytes = _bytes(source)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
45 else: # can be either file pointer or file-like
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
46 if type(source) in (int, long): # file pointer it is
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
47 ## converting file descriptor (int) stdin into file-like
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
48 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
49 source = os.fdopen(source, 'rb', 16384)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
50 except Exception:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
51 pass
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
52 # let's see if source is file-like by now
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
53 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
54 filelike = source.read
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
55 except Exception:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
56 pass
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
57 if not filelike and not self.bytes:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
58 raise TypeError("StreamFeeder's source object must be a readable "
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
59 "file-like, a file descriptor, or a string-like.")
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
60 self.source = source
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
61 self.readiface, self.writeiface = os.pipe()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
62
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
63 def run(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
64 t = self.writeiface
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
65 if self.bytes:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
66 os.write(t, self.bytes)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
67 else:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
68 s = self.source
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
69 b = s.read(4096)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
70 while b:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
71 os.write(t, b)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
72 b = s.read(4096)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
73 os.close(t)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
74
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
75 @property
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
76 def output(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
77 return self.readiface
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
78
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
79
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
80 class InputStreamChunker(Thread):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
81 def __init__(self, source, target, buffer_size, chunk_size):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
82
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
83 super(InputStreamChunker, self).__init__()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
84
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
85 self.daemon = True # die die die.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
86
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
87 self.source = source
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
88 self.target = target
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
89 self.chunk_count_max = int(buffer_size / chunk_size) + 1
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
90 self.chunk_size = chunk_size
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
91
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
92 self.data_added = Event()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
93 self.data_added.clear()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
94
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
95 self.keep_reading = Event()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
96 self.keep_reading.set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
97
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
98 self.EOF = Event()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
99 self.EOF.clear()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
100
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
101 self.go = Event()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
102 self.go.set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
103
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
104 def stop(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
105 self.go.clear()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
106 self.EOF.set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
107 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
108 # this is not proper, but is done to force the reader thread let
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
109 # go of the input because, if successful, .close() will send EOF
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
110 # down the pipe.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
111 self.source.close()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
112 except:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
113 pass
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
114
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
115 def run(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
116 s = self.source
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
117 t = self.target
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
118 cs = self.chunk_size
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
119 ccm = self.chunk_count_max
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
120 kr = self.keep_reading
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
121 da = self.data_added
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
122 go = self.go
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
123
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
124 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
125 b = s.read(cs)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
126 except ValueError:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
127 b = ''
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
128
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
129 while b and go.is_set():
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
130 if len(t) > ccm:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
131 kr.clear()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
132 kr.wait(2)
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
133 # # this only works on 2.7.x and up
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
134 # if not kr.wait(10):
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
135 # raise Exception("Timed out while waiting for input to be read.")
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
136 # instead we'll use this
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
137 if len(t) > ccm + 3:
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
138 raise IOError(
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
139 "Timed out while waiting for input from subprocess.")
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
140 t.append(b)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
141 da.set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
142 b = s.read(cs)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
143 self.EOF.set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
144 da.set() # for cases when done but there was no input.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
145
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
146
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
147 class BufferedGenerator(object):
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
148 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
149 Class behaves as a non-blocking, buffered pipe reader.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
150 Reads chunks of data (through a thread)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
151 from a blocking pipe, and attaches these to an array (Deque) of chunks.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
152 Reading is halted in the thread when max chunks is internally buffered.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
153 The .next() may operate in blocking or non-blocking fashion by yielding
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
154 '' if no data is ready
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
155 to be sent or by not returning until there is some data to send
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
156 When we get EOF from underlying source pipe we raise the marker to raise
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
157 StopIteration after the last chunk of data is yielded.
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
158 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
159
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
160 def __init__(self, source, buffer_size=65536, chunk_size=4096,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
161 starting_values=[], bottomless=False):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
162
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
163 if bottomless:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
164 maxlen = int(buffer_size / chunk_size)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
165 else:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
166 maxlen = None
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
167
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
168 self.data = deque(starting_values, maxlen)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
169 self.worker = InputStreamChunker(source, self.data, buffer_size,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
170 chunk_size)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
171 if starting_values:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
172 self.worker.data_added.set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
173 self.worker.start()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
174
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
175 ####################
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
176 # Generator's methods
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
177 ####################
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
178
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
179 def __iter__(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
180 return self
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
181
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
182 def next(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
183 while not len(self.data) and not self.worker.EOF.is_set():
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
184 self.worker.data_added.clear()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
185 self.worker.data_added.wait(0.2)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
186 if len(self.data):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
187 self.worker.keep_reading.set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
188 return _bytes(self.data.popleft())
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
189 elif self.worker.EOF.is_set():
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
190 raise StopIteration
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
191
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
192 def throw(self, type, value=None, traceback=None):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
193 if not self.worker.EOF.is_set():
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
194 raise type(value)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
195
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
196 def start(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
197 self.worker.start()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
198
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
199 def stop(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
200 self.worker.stop()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
201
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
202 def close(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
203 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
204 self.worker.stop()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
205 self.throw(GeneratorExit)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
206 except (GeneratorExit, StopIteration):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
207 pass
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
208
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
209 def __del__(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
210 self.close()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
211
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
212 ####################
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
213 # Threaded reader's infrastructure.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
214 ####################
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
215 @property
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
216 def input(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
217 return self.worker.w
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
218
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
219 @property
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
220 def data_added_event(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
221 return self.worker.data_added
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
222
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
223 @property
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
224 def data_added(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
225 return self.worker.data_added.is_set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
226
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
227 @property
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
228 def reading_paused(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
229 return not self.worker.keep_reading.is_set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
230
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
231 @property
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
232 def done_reading_event(self):
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
233 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
234 Done_reding does not mean that the iterator's buffer is empty.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
235 Iterator might have done reading from underlying source, but the read
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
236 chunks might still be available for serving through .next() method.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
237
3895
e39fb661998b small docstring fixes
Marcin Kuzminski <marcin@python-works.com>
parents: 3889
diff changeset
238 :returns: An Event class instance.
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
239 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
240 return self.worker.EOF
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
241
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
242 @property
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
243 def done_reading(self):
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
244 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
245 Done_reding does not mean that the iterator's buffer is empty.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
246 Iterator might have done reading from underlying source, but the read
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
247 chunks might still be available for serving through .next() method.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
248
3895
e39fb661998b small docstring fixes
Marcin Kuzminski <marcin@python-works.com>
parents: 3889
diff changeset
249 :returns: An Bool value.
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
250 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
251 return self.worker.EOF.is_set()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
252
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
253 @property
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
254 def length(self):
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
255 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
256 returns int.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
257
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
258 This is the lenght of the que of chunks, not the length of
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
259 the combined contents in those chunks.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
260
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
261 __len__() cannot be meaningfully implemented because this
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
262 reader is just flying throuh a bottomless pit content and
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
263 can only know the lenght of what it already saw.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
264
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
265 If __len__() on WSGI server per PEP 3333 returns a value,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
266 the responce's length will be set to that. In order not to
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
267 confuse WSGI PEP3333 servers, we will not implement __len__
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
268 at all.
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
269 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
270 return len(self.data)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
271
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
272 def prepend(self, x):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
273 self.data.appendleft(x)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
274
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
275 def append(self, x):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
276 self.data.append(x)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
277
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
278 def extend(self, o):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
279 self.data.extend(o)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
280
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
281 def __getitem__(self, i):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
282 return self.data[i]
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
283
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
284
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
285 class SubprocessIOChunker(object):
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
286 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
287 Processor class wrapping handling of subprocess IO.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
288
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
289 In a way, this is a "communicate()" replacement with a twist.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
290
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
291 - We are multithreaded. Writing in and reading out, err are all sep threads.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
292 - We support concurrent (in and out) stream processing.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
293 - The output is not a stream. It's a queue of read string (bytes, not unicode)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
294 chunks. The object behaves as an iterable. You can "for chunk in obj:" us.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
295 - We are non-blocking in more respects than communicate()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
296 (reading from subprocess out pauses when internal buffer is full, but
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
297 does not block the parent calling code. On the flip side, reading from
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
298 slow-yielding subprocess may block the iteration until data shows up. This
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
299 does not block the parallel inpipe reading occurring parallel thread.)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
300
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
301 The purpose of the object is to allow us to wrap subprocess interactions into
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
302 and interable that can be passed to a WSGI server as the application's return
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
303 value. Because of stream-processing-ability, WSGI does not have to read ALL
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
304 of the subprocess's output and buffer it, before handing it to WSGI server for
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
305 HTTP response. Instead, the class initializer reads just a bit of the stream
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
306 to figure out if error ocurred or likely to occur and if not, just hands the
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
307 further iteration over subprocess output to the server for completion of HTTP
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
308 response.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
309
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
310 The real or perceived subprocess error is trapped and raised as one of
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
311 EnvironmentError family of exceptions
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
312
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
313 Example usage:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
314 # try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
315 # answer = SubprocessIOChunker(
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
316 # cmd,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
317 # input,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
318 # buffer_size = 65536,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
319 # chunk_size = 4096
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
320 # )
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
321 # except (EnvironmentError) as e:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
322 # print str(e)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
323 # raise e
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
324 #
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
325 # return answer
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
326
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
327
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
328 """
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
329
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
330 def __init__(self, cmd, inputstream=None, buffer_size=65536,
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
331 chunk_size=4096, starting_values=[], **kwargs):
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
332 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
333 Initializes SubprocessIOChunker
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
334
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
335 :param cmd: A Subprocess.Popen style "cmd". Can be string or array of strings
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
336 :param inputstream: (Default: None) A file-like, string, or file pointer.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
337 :param buffer_size: (Default: 65536) A size of total buffer per stream in bytes.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
338 :param chunk_size: (Default: 4096) A max size of a chunk. Actual chunk may be smaller.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
339 :param starting_values: (Default: []) An array of strings to put in front of output que.
3886
a1696507b3ad use consisten double quote docstring formatting
Marcin Kuzminski <marcin@python-works.com>
parents: 3830
diff changeset
340 """
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
341
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
342 if inputstream:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
343 input_streamer = StreamFeeder(inputstream)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
344 input_streamer.start()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
345 inputstream = input_streamer.output
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
346
3830
08d439bfbd8c fixed handling shell argument in subprocess calls, it always was hardcoded even when passed properly in arguments
Marcin Kuzminski <marcin@python-works.com>
parents: 3797
diff changeset
347 _shell = kwargs.get('shell', True)
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
348 if isinstance(cmd, (list, tuple)):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
349 cmd = ' '.join(cmd)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
350
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
351 kwargs['shell'] = _shell
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
352 _p = subprocess.Popen(cmd, bufsize=-1,
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
353 stdin=inputstream,
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
354 stdout=subprocess.PIPE,
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
355 stderr=subprocess.PIPE,
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
356 **kwargs)
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
357
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
358 bg_out = BufferedGenerator(_p.stdout, buffer_size, chunk_size,
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
359 starting_values)
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
360 bg_err = BufferedGenerator(_p.stderr, 16000, 1, bottomless=True)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
361
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
362 while not bg_out.done_reading and not bg_out.reading_paused and not bg_err.length:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
363 # doing this until we reach either end of file, or end of buffer.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
364 bg_out.data_added_event.wait(1)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
365 bg_out.data_added_event.clear()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
366
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
367 # at this point it's still ambiguous if we are done reading or just full buffer.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
368 # Either way, if error (returned by ended process, or implied based on
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
369 # presence of stuff in stderr output) we error out.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
370 # Else, we are happy.
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
371 _returncode = _p.poll()
3889
b84c83b651de replace equality comparision to None
Marcin Kuzminski <marcin@python-works.com>
parents: 3886
diff changeset
372 if _returncode or (_returncode is None and bg_err.length):
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
373 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
374 _p.terminate()
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
375 except Exception:
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
376 pass
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
377 bg_out.stop()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
378 bg_err.stop()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
379 err = '%s' % ''.join(bg_err)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
380 if err:
4116
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
381 raise EnvironmentError(
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
382 "Subprocess exited due to an error:\n" + err)
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
383 raise EnvironmentError(
ffd45b185016 Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
Bradley M. Kuhn <bkuhn@sfconservancy.org>
parents: 3895
diff changeset
384 "Subprocess exited with non 0 ret code:%s" % _returncode)
3797
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
385
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
386 self.process = _p
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
387 self.output = bg_out
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
388 self.error = bg_err
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
389
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
390 def __iter__(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
391 return self
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
392
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
393 def next(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
394 if self.process.poll():
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
395 err = '%s' % ''.join(self.error)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
396 raise EnvironmentError("Subprocess exited due to an error:\n" + err)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
397 return self.output.next()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
398
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
399 def throw(self, type, value=None, traceback=None):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
400 if self.output.length or not self.output.done_reading:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
401 raise type(value)
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
402
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
403 def close(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
404 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
405 self.process.terminate()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
406 except:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
407 pass
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
408 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
409 self.output.close()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
410 except:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
411 pass
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
412 try:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
413 self.error.close()
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
414 except:
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
415 pass
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
416
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
417 def __del__(self):
d7488551578e synced vcs with upstream
Marcin Kuzminski <marcin@python-works.com>
parents:
diff changeset
418 self.close()