1*7249d1a6SKrzysztof Kosiński# -*- coding: utf-8 -*- 2*7249d1a6SKrzysztof Kosiński# Copyright 2017 Google Inc. All Rights Reserved. 3*7249d1a6SKrzysztof Kosiński# 4*7249d1a6SKrzysztof Kosiński# Licensed under the Apache License, Version 2.0 (the "License"); 5*7249d1a6SKrzysztof Kosiński# you may not use this file except in compliance with the License. 6*7249d1a6SKrzysztof Kosiński# You may obtain a copy of the License at 7*7249d1a6SKrzysztof Kosiński# 8*7249d1a6SKrzysztof Kosiński# http://www.apache.org/licenses/LICENSE-2.0 9*7249d1a6SKrzysztof Kosiński# 10*7249d1a6SKrzysztof Kosiński# Unless required by applicable law or agreed to in writing, software 11*7249d1a6SKrzysztof Kosiński# distributed under the License is distributed on an "AS IS" BASIS, 12*7249d1a6SKrzysztof Kosiński# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*7249d1a6SKrzysztof Kosiński# See the License for the specific language governing permissions and 14*7249d1a6SKrzysztof Kosiński# limitations under the License. 15*7249d1a6SKrzysztof Kosiński"""Utilities for tests.""" 16*7249d1a6SKrzysztof Kosiński 17*7249d1a6SKrzysztof Kosińskiimport contextlib 18*7249d1a6SKrzysztof Kosińskiimport io 19*7249d1a6SKrzysztof Kosińskiimport os 20*7249d1a6SKrzysztof Kosińskiimport sys 21*7249d1a6SKrzysztof Kosińskiimport tempfile 22*7249d1a6SKrzysztof Kosiński 23*7249d1a6SKrzysztof Kosiński 24*7249d1a6SKrzysztof Kosiński@contextlib.contextmanager 25*7249d1a6SKrzysztof Kosińskidef stdout_redirector(stream): # pylint: disable=invalid-name 26*7249d1a6SKrzysztof Kosiński old_stdout = sys.stdout 27*7249d1a6SKrzysztof Kosiński sys.stdout = stream 28*7249d1a6SKrzysztof Kosiński try: 29*7249d1a6SKrzysztof Kosiński yield 30*7249d1a6SKrzysztof Kosiński finally: 31*7249d1a6SKrzysztof Kosiński sys.stdout = old_stdout 32*7249d1a6SKrzysztof Kosiński 33*7249d1a6SKrzysztof Kosiński 34*7249d1a6SKrzysztof Kosiński# NamedTemporaryFile is useless because on Windows the temporary file would be 35*7249d1a6SKrzysztof Kosiński# created with O_TEMPORARY, which would not allow the file to be opened a 36*7249d1a6SKrzysztof Kosiński# second time, even by the same process, unless the same flag is used. 37*7249d1a6SKrzysztof Kosiński# Thus we provide a simplified version ourselves. 38*7249d1a6SKrzysztof Kosiński# 39*7249d1a6SKrzysztof Kosiński# Note: returns a tuple of (io.file_obj, file_path), instead of a file_obj with 40*7249d1a6SKrzysztof Kosiński# a .name attribute 41*7249d1a6SKrzysztof Kosiński# 42*7249d1a6SKrzysztof Kosiński# Note: `buffering` is set to -1 despite documentation of NamedTemporaryFile 43*7249d1a6SKrzysztof Kosiński# says None. This is probably a problem with the python documentation. 44*7249d1a6SKrzysztof Kosiński@contextlib.contextmanager 45*7249d1a6SKrzysztof Kosińskidef NamedTempFile(mode='w+b', 46*7249d1a6SKrzysztof Kosiński buffering=-1, 47*7249d1a6SKrzysztof Kosiński encoding=None, 48*7249d1a6SKrzysztof Kosiński errors=None, 49*7249d1a6SKrzysztof Kosiński newline=None, 50*7249d1a6SKrzysztof Kosiński suffix=None, 51*7249d1a6SKrzysztof Kosiński prefix=None, 52*7249d1a6SKrzysztof Kosiński dirname=None, 53*7249d1a6SKrzysztof Kosiński text=False): 54*7249d1a6SKrzysztof Kosiński """Context manager creating a new temporary file in text mode.""" 55*7249d1a6SKrzysztof Kosiński if sys.version_info < (3, 5): # covers also python 2 56*7249d1a6SKrzysztof Kosiński if suffix is None: 57*7249d1a6SKrzysztof Kosiński suffix = '' 58*7249d1a6SKrzysztof Kosiński if prefix is None: 59*7249d1a6SKrzysztof Kosiński prefix = 'tmp' 60*7249d1a6SKrzysztof Kosiński (fd, fname) = tempfile.mkstemp( 61*7249d1a6SKrzysztof Kosiński suffix=suffix, prefix=prefix, dir=dirname, text=text) 62*7249d1a6SKrzysztof Kosiński f = io.open( 63*7249d1a6SKrzysztof Kosiński fd, 64*7249d1a6SKrzysztof Kosiński mode=mode, 65*7249d1a6SKrzysztof Kosiński buffering=buffering, 66*7249d1a6SKrzysztof Kosiński encoding=encoding, 67*7249d1a6SKrzysztof Kosiński errors=errors, 68*7249d1a6SKrzysztof Kosiński newline=newline) 69*7249d1a6SKrzysztof Kosiński yield f, fname 70*7249d1a6SKrzysztof Kosiński f.close() 71*7249d1a6SKrzysztof Kosiński os.remove(fname) 72*7249d1a6SKrzysztof Kosiński 73*7249d1a6SKrzysztof Kosiński 74*7249d1a6SKrzysztof Kosiński@contextlib.contextmanager 75*7249d1a6SKrzysztof Kosińskidef TempFileContents(dirname, 76*7249d1a6SKrzysztof Kosiński contents, 77*7249d1a6SKrzysztof Kosiński encoding='utf-8', 78*7249d1a6SKrzysztof Kosiński newline='', 79*7249d1a6SKrzysztof Kosiński suffix=None): 80*7249d1a6SKrzysztof Kosiński # Note: NamedTempFile properly handles unicode encoding when using mode='w' 81*7249d1a6SKrzysztof Kosiński with NamedTempFile( 82*7249d1a6SKrzysztof Kosiński dirname=dirname, 83*7249d1a6SKrzysztof Kosiński mode='w', 84*7249d1a6SKrzysztof Kosiński encoding=encoding, 85*7249d1a6SKrzysztof Kosiński newline=newline, 86*7249d1a6SKrzysztof Kosiński suffix=suffix) as (f, fname): 87*7249d1a6SKrzysztof Kosiński f.write(contents) 88*7249d1a6SKrzysztof Kosiński f.flush() 89*7249d1a6SKrzysztof Kosiński yield fname 90