Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(735)

Side by Side Diff: recipe_modules/raw_io/api.py

Issue 2672593002: raw_io module: Add text_input and text_output (Closed)
Patch Set: Change approach Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | recipe_modules/raw_io/example.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # -*- encoding: utf-8 -*-
1 # Copyright 2014 The LUCI Authors. All rights reserved. 2 # Copyright 2014 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 3 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 4 # that can be found in the LICENSE file.
4 5
5 from recipe_engine import recipe_api 6 from recipe_engine import recipe_api
6 from recipe_engine import util as recipe_util 7 from recipe_engine import util as recipe_util
7 8
8 import os 9 import os
9 import shutil 10 import shutil
10 import tempfile 11 import tempfile
(...skipping 12 matching lines...) Expand all
23 return self._backing_file 24 return self._backing_file
24 25
25 def render(self, test): 26 def render(self, test):
26 assert not self._backing_file, 'Placeholder can be used only once' 27 assert not self._backing_file, 'Placeholder can be used only once'
27 if test.enabled: 28 if test.enabled:
28 # cheat and pretend like we're going to pass the data on the 29 # cheat and pretend like we're going to pass the data on the
29 # cmdline for test expectation purposes. 30 # cmdline for test expectation purposes.
30 self._backing_file = self.data 31 self._backing_file = self.data
31 else: # pragma: no cover 32 else: # pragma: no cover
32 input_fd, self._backing_file = tempfile.mkstemp(suffix=self.suffix) 33 input_fd, self._backing_file = tempfile.mkstemp(suffix=self.suffix)
33 os.write(input_fd, self.data.encode('utf-8')) 34
35 os.write(input_fd, self.encode_data(self.data))
34 os.close(input_fd) 36 os.close(input_fd)
35 return [self._backing_file] 37 return [self._backing_file]
36 38
37 def cleanup(self, test_enabled): 39 def cleanup(self, test_enabled):
38 assert self._backing_file is not None 40 assert self._backing_file is not None
39 if not test_enabled: # pragma: no cover 41 if not test_enabled: # pragma: no cover
40 try: 42 try:
41 os.unlink(self._backing_file) 43 os.unlink(self._backing_file)
42 except OSError: 44 except OSError:
43 pass 45 pass
44 self._backing_file = None 46 self._backing_file = None
45 47
48 def encode_data(self, data):
49 return data
50
51 class InputTextPlaceholder(InputDataPlaceholder):
52 def encode_data(self, data):
53 # Sometimes users give us invalid utf-8 data. They shouldn't, but it does
54 # happen every once and a while. Just ignore it, and replace with �.
55 # We're assuming users only want to write text data out.
56 decoded = self.data.decode('utf-8', 'replace')
57 return decoded.encode('utf-8')
58
59
46 60
47 class OutputDataPlaceholder(recipe_util.OutputPlaceholder): 61 class OutputDataPlaceholder(recipe_util.OutputPlaceholder):
48 def __init__(self, suffix, leak_to, name=None): 62 def __init__(self, suffix, leak_to, name=None):
49 self.suffix = suffix 63 self.suffix = suffix
50 self.leak_to = leak_to 64 self.leak_to = leak_to
51 self._backing_file = None 65 self._backing_file = None
52 super(OutputDataPlaceholder, self).__init__(name=name) 66 super(OutputDataPlaceholder, self).__init__(name=name)
53 67
54 @property 68 @property
55 def backing_file(self): 69 def backing_file(self):
(...skipping 18 matching lines...) Expand all
74 return test.data 88 return test.data
75 else: # pragma: no cover 89 else: # pragma: no cover
76 try: 90 try:
77 with open(self._backing_file, 'rb') as f: 91 with open(self._backing_file, 'rb') as f:
78 return f.read() 92 return f.read()
79 finally: 93 finally:
80 if not self.leak_to: 94 if not self.leak_to:
81 os.unlink(self._backing_file) 95 os.unlink(self._backing_file)
82 self._backing_file = None 96 self._backing_file = None
83 97
98 def decode(self, result):
99 return result
100
101 class OutputTextPlaceholder(OutputDataPlaceholder):
102 def decode(self, result):
103 return result.decode('utf-8', 'replace')
84 104
85 class OutputDataDirPlaceholder(recipe_util.OutputPlaceholder): 105 class OutputDataDirPlaceholder(recipe_util.OutputPlaceholder):
86 def __init__(self, suffix, leak_to, name=None): 106 def __init__(self, suffix, leak_to, name=None):
87 self.suffix = suffix 107 self.suffix = suffix
88 self.leak_to = leak_to 108 self.leak_to = leak_to
89 self._backing_dir = None 109 self._backing_dir = None
90 super(OutputDataDirPlaceholder, self).__init__(name=name) 110 super(OutputDataDirPlaceholder, self).__init__(name=name)
91 111
92 @property 112 @property
93 def backing_file(self): # pragma: no cover 113 def backing_file(self): # pragma: no cover
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 151
132 152
133 class RawIOApi(recipe_api.RecipeApi): 153 class RawIOApi(recipe_api.RecipeApi):
134 @recipe_util.returns_placeholder 154 @recipe_util.returns_placeholder
135 @staticmethod 155 @staticmethod
136 def input(data, suffix=''): 156 def input(data, suffix=''):
137 return InputDataPlaceholder(data, suffix) 157 return InputDataPlaceholder(data, suffix)
138 158
139 @recipe_util.returns_placeholder 159 @recipe_util.returns_placeholder
140 @staticmethod 160 @staticmethod
161 def input_text(data, suffix=''):
iannucci 2017/02/02 02:23:30 docstring (and for input above)
162 return InputTextPlaceholder(data, suffix)
163
164 # TODO(martiniss): Remove this once downstream callers are using text_input
165 # input = text_input
166
167 @recipe_util.returns_placeholder
168 @staticmethod
141 def output(suffix='', leak_to=None, name=None): 169 def output(suffix='', leak_to=None, name=None):
142 """Returns a Placeholder for use as a step argument, or for std{out,err}. 170 """Returns a Placeholder for use as a step argument, or for std{out,err}.
143 171
144 If 'leak_to' is None, the placeholder is backed by a temporary file with 172 If 'leak_to' is None, the placeholder is backed by a temporary file with
145 a suffix 'suffix'. The file is deleted when the step finishes. 173 a suffix 'suffix'. The file is deleted when the step finishes.
146 174
147 If 'leak_to' is not None, then it should be a Path and placeholder 175 If 'leak_to' is not None, then it should be a Path and placeholder
148 redirects IO to a file at that path. Once step finishes, the file is 176 redirects IO to a file at that path. Once step finishes, the file is
149 NOT deleted (i.e. it's 'leaking'). 'suffix' is ignored in that case. 177 NOT deleted (i.e. it's 'leaking'). 'suffix' is ignored in that case.
150 """ 178 """
151 return OutputDataPlaceholder(suffix, leak_to, name=name) 179 return OutputDataPlaceholder(suffix, leak_to, name=name)
152 180
153 @recipe_util.returns_placeholder 181 @recipe_util.returns_placeholder
154 @staticmethod 182 @staticmethod
183 def output_text(suffix='', leak_to=None, name=None):
184 """Returns a Placeholder for use as a step argument, or for std{out,err}.
iannucci 2017/02/02 02:23:30 document encoding difference here and text_input.
185
186 If 'leak_to' is None, the placeholder is backed by a temporary file with
187 a suffix 'suffix'. The file is deleted when the step finishes.
188
189 If 'leak_to' is not None, then it should be a Path and placeholder
190 redirects IO to a file at that path. Once step finishes, the file is
191 NOT deleted (i.e. it's 'leaking'). 'suffix' is ignored in that case.
192 """
193 return OutputTextPlaceholder(suffix, leak_to, name=name)
194
195 #output = output_text
196
197 @recipe_util.returns_placeholder
198 @staticmethod
155 def output_dir(suffix='', leak_to=None, name=None): 199 def output_dir(suffix='', leak_to=None, name=None):
156 """Returns a directory Placeholder for use as a step argument. 200 """Returns a directory Placeholder for use as a step argument.
157 201
158 If 'leak_to' is None, the placeholder is backed by a temporary dir with 202 If 'leak_to' is None, the placeholder is backed by a temporary dir with
159 a suffix 'suffix'. The dir is deleted when the step finishes. 203 a suffix 'suffix'. The dir is deleted when the step finishes.
160 204
161 If 'leak_to' is not None, then it should be a Path and placeholder 205 If 'leak_to' is not None, then it should be a Path and placeholder
162 redirects IO to a dir at that path. Once step finishes, the dir is 206 redirects IO to a dir at that path. Once step finishes, the dir is
163 NOT deleted (i.e. it's 'leaking'). 'suffix' is ignored in that case. 207 NOT deleted (i.e. it's 'leaking'). 'suffix' is ignored in that case.
164 """ 208 """
165 return OutputDataDirPlaceholder(suffix, leak_to, name=name) 209 return OutputDataDirPlaceholder(suffix, leak_to, name=name)
OLDNEW
« no previous file with comments | « no previous file | recipe_modules/raw_io/example.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698