def testRsopenBehaviour(self): # for ease of use, we just test binary unbuffered files... with rsfile.rsopen(TESTFN, "RAEB", buffering=0, locking=False) as f: self.assertEqual(f.readable(), True) self.assertEqual(f.writable(), True) self.assertEqual(f._append, True) self.assertEqual(f.size(), 0) f.write(b"abcde") with rsfile.rsopen(TESTFN, "RAEB", buffering=0) as f: self.assertEqual(f.size(), 0) f.write(b"abcdef") f.seek(0) f.write(b"abcdef") self.assertEqual(f.size(), 12) self.assertEqual(f.tell(), 12) self.assertRaises(IOError, rsfile.rsopen, TESTFN, "RB-", buffering=0) with rsfile.rsopen(TESTFN, "RAEB", buffering=0) as f: os.rename(TESTFN, TESTFN + ".temp") # for windows platforms... os.remove(TESTFN + ".temp") self.assertRaises(IOError, rsfile.rsopen, TESTFN, "WB+", buffering=0)
def reopener_via_fileno(name, mode): """Ensures that possible emulation of fileno doesn't break the access mode of the stream.""" f = rsfile.rsopen(name, mode=mode, locking=False, thread_safe=False) _disown_file_descriptor(f) fileno = f.fileno() assert fileno, fileno new_f = rsfile.rsopen(mode=mode, fileno=fileno, closefd=True) assert new_f.handle() == f.handle() assert new_f.fileno() == fileno return new_f
def reopener_via_fileno(name, mode): """Ensures that possible emulation of fileno doesn't break the access mode of the stream.""" f = rsfile.rsopen(name, mode=mode, locking=False, thread_safe=False) _disown_file_descriptor(f) fileno = f.fileno() assert fileno, fileno new_f = rsfile.rsopen(mode=mode, fileno=fileno, closefd=True) assert new_f.handle() == f.handle() assert new_f.fileno() == fileno return new_f
def __BROKEN__reopener_via_handle(name, mode): """Ensures that possible emulation of handle doesn't break the access mode of the stream.""" f = rsfile.rsopen(name, mode=mode, locking=False, thread_safe=False) _disown_file_descriptor(f) handle = f.handle() assert handle, handle new_f = rsfile.rsopen(mode=mode, handle=handle, closefd=True) assert new_f.handle() == handle if (defs.RSFILE_IMPLEMENTATION == "windows"): assert f._fileno is None, f._fileno # we take care of NOT exhausting these emulated resources here else: assert new_f.fileno() == f.fileno() return new_f
def __BROKEN__reopener_via_handle(name, mode): """Ensures that possible emulation of handle doesn't break the access mode of the stream.""" f = rsfile.rsopen(name, mode=mode, locking=False, thread_safe=False) _disown_file_descriptor(f) handle = f.handle() assert handle, handle new_f = rsfile.rsopen(mode=mode, handle=handle, closefd=True) assert new_f.handle() == handle if (defs.RSFILE_IMPLEMENTATION == "windows"): assert f._fileno is None, f._fileno # we take care of NOT exhausting these emulated resources here else: assert new_f.fileno() == f.fileno() return new_f
def testFileCreationPermissions(self): with rsfile.rsopen(TESTFN, "RWB-", buffering=0, locking=False, permissions=0o555) as f: # creating read-only file f.write(b"abc") # WORKS, because file permissions are only applied on subsequent open() f.flush() with rsfile.rsopen(TESTFN, "RB+", buffering=0, locking=False) as g: pass # no problem self.assertRaises(IOError, rsfile.rsopen, TESTFN, "WB+", buffering=0, locking=False) # now can't open for writing os.chmod(TESTFN, 0o777) os.remove(TESTFN)
def test_intraprocess_duplicated_handle_locking(self): TESTFN = "mytestfile" with rsfile.rsopen(TESTFN, "RWB", locking=False) as f: f.lock_file(length=100, offset=0) other_fileno = os.dup( f.fileno()) # using C compatibility layer on windows with rsfile.rsopen(mode="RWB", fileno=other_fileno, locking=False) as g: self.assertRaises(defs.LockingException, g.lock_file, timeout=0) # duplicate handle g.lock_file(length=100, offset=100, timeout=0) # chunk locking works os.remove(TESTFN)
def testFileDeletions(self): TESTFNBIS = TESTFN + "X" if os.path.exists(TESTFNBIS): os.remove(TESTFNBIS) with rsfile.rsopen(TESTFN, "RB", buffering=0, locking=True) as h: self.assertTrue(os.path.exists(TESTFN)) os.rename(TESTFN, TESTFNBIS) os.remove(TESTFNBIS) self.assertRaises(IOError, rsfile.rsopen, TESTFN, "R+", buffering=0) self.assertRaises(IOError, rsfile.rsopen, TESTFNBIS, "R+", buffering=0) if (defs.RSFILE_IMPLEMENTATION == "windows"): # on windows the file remains but in a weird state, awaiting deletion, so we can't reopen it... self.assertRaises(IOError, rsfile.rsopen, TESTFNBIS, "w", buffering=0) else: with rsfile.rsopen(TESTFN, "wb", buffering=0): pass """
def testReturnedStreamTypes(self): for forced_mutex in [None, threading.RLock(), multiprocessing.RLock()]: with rsfile.rsopen(TESTFN, "RWB", buffering=0, mutex=forced_mutex) as f: # by default, thread-safe self.assertTrue(isinstance(f, rsfile.RSThreadSafeWrapper)) self.assertEqual(f.mutex, forced_mutex if forced_mutex else f.mutex) f.write(b"abc") with rsfile.rsopen(TESTFN, "RWB", buffering=0, thread_safe=False) as f: self.assertTrue(isinstance(f, io.RawIOBase)) f.write(b"abc") with rsfile.rsopen(TESTFN, "RWB", mutex=forced_mutex) as f: self.assertTrue(isinstance(f, rsfile.RSThreadSafeWrapper)) self.assertEqual(f.mutex, forced_mutex if forced_mutex else f.mutex) f.write(b"abc") with rsfile.rsopen(TESTFN, "RWB", thread_safe=False) as f: self.assertTrue(isinstance(f, io.BufferedIOBase)) f.write(b"abc") with rsfile.rsopen(TESTFN, "RWT", mutex=forced_mutex) as f: self.assertTrue(isinstance(f, rsfile.RSThreadSafeWrapper)) self.assertEqual(f.mutex, forced_mutex if forced_mutex else f.mutex) f.write("abc") with rsfile.rsopen(TESTFN, "RWT", thread_safe=False) as f: self.assertTrue(isinstance(f, io.TextIOBase)) f.write("abc")
def __init__(self, buildout, name, options): variables = Variables() data = {} if options.get('index-file'): if os.path.exists(options['index-file']): with rsfile.rsopen(options['index-file']) as f: data = json.load(f) key = options.get('index-key') if key is not None: if key not in data: data[key] = len(data) index_start = int(options.get('index-start', 1)) variables.lookup['index'] = data[key] + index_start if options.get('index-file'): with rsfile.rsopen(options['index-file'], 'wb') as f: json.dump(data, f, indent=4) for k, v in options.items(): try: variables.add(k, v) except VariableError: continue variables.evaluate(buildout, name, options)
def testConflictsBetweenLockingAndOperations(self): f = rsfile.rsopen(TESTFN, "RWE", thread_safe=False, locking=False) f.lock_file(shared=False) f.write("héllo") f.flush() f.seek(0) data = f.read() self.assertEqual(data, "héllo") f.unlock_file() f.lock_file(shared=True) self.assertEqual(f.read(), "") if (defs.RSFILE_IMPLEMENTATION == "windows"): f.write("bye") self.assertRaises(IOError, f.flush) # data in buffers blocks implicit flush... self.assertRaises(IOError, f.unlock_file) assert f._buffer._write_buf, f._buffer._write_buf del f._buffer._write_buf[:] # else error on closing flush() f.flush() else: f.write("bye") f.flush() f.unlock_file() # no problem if we write OUTSIDE of the locked area though f.lock_file(length=1, offset=100, shared=True) f.seek(0) f.truncate() f.write("twist") f.flush() f.seek(0) data = f.read() self.assertEqual(data, "twist") f.unlock_file(length=1, offset=100) f.close()
def test_intra_process_locking(self): """ We check the behaviour of locks when opening several times the same file from within a process. """ # the locking type must be compatible with the opening mode (enforced by some OSes) with rsfile.rsopen(self.dummyFileName, "RB", buffering=0, locking=False) as f: self.assertRaises(IOError, f.lock_file, shared=False) with rsfile.rsopen(self.dummyFileName, "WB", buffering=0, locking=False) as f: self.assertRaises(IOError, f.lock_file, shared=True) # Locking from different open files with rsfile.rsopen(self.dummyFileName, "RB", buffering=0, timeout=0) as _: with rsfile.rsopen(self.dummyFileName, "RB", buffering=0, timeout=0) as _: pass # OK - shared locking # Exclusively locking the same disk file twice from different open file objects should fail (or block...) self.assertRaises(rsfile.LockingException, rsfile.rsopen, self.dummyFileName, "WB", buffering=0, timeout=0) with rsfile.rsopen(self.dummyFileName, "RWB", buffering=0, locking=False) as f: assert f.tell() == 0 f.lock_file(shared=True, timeout=0, length=1, offset=100, whence=os.SEEK_SET) f.lock_file(shared=False, timeout=0, length=1, offset=200, whence=os.SEEK_SET) assert f.tell() == 0 f.lock_file(shared=True, timeout=0, length=1, offset=0, whence=os.SEEK_SET) f.lock_file(shared=False, timeout=0, length=1, offset=1, whence=os.SEEK_SET) f.lock_file(shared=True, timeout=0, length=3, offset=2, whence=os.SEEK_SET) assert f.tell() == 0 f.seek(5) f.lock_file(shared=True, timeout=0, length=1, offset=0, whence=os.SEEK_CUR) # works f.seek(0) assert f.tell() == 0 # No double locking ! self.assertRaises(RuntimeError, f.lock_file, shared=True, timeout=None, length=1, offset=0, whence=os.SEEK_CUR) self.assertRaises(RuntimeError, f.lock_file, shared=False, timeout=None, length=1, offset=0, whence=os.SEEK_CUR) self.assertRaises(RuntimeError, f.lock_file, shared=True, timeout=0, length=1, offset=1, whence=os.SEEK_SET) self.assertRaises(RuntimeError, f.lock_file, shared=False, timeout=0, length=1, offset=1, whence=os.SEEK_CUR) self.assertRaises(RuntimeError, f.lock_file, length=2, offset=0, whence=os.SEEK_CUR) # no lock merging ! self.assertRaises(RuntimeError, f.lock_file, length=1, offset=3, whence=os.SEEK_CUR) # no lock splitting ! f.seek(5) self.assertRaises(RuntimeError, f.lock_file, shared=True, timeout=0, length=1, offset=0, whence=os.SEEK_CUR) f.seek(0) assert f.wrapped_stream.__class__._inner_file_lock f.wrapped_stream._inner_file_lock = "<nasty_string>" # this properly self.assertRaises(TypeError, f.lock_file, length=1, offset=355, whence=os.SEEK_SET) del f.wrapped_stream._inner_file_lock # IntraProcessLockRegistry was well cleaned up when treating this TypeError: f.lock_file(shared=True, timeout=0, length=1, offset=355, whence=os.SEEK_SET) # Todo - we test locking on duplicated handles, with os.dup() or DuplicateHandle()... but that's very # corner-case actually... """ if sys.platform == 'win32': self.fail("Exclusively locking the same disk file twice from different open file objects didn't fail on win32") if sys.platform != 'win32': self.fail("Exclusively locking the same disk file twice from different open file objects shouldn't fail on unix") """ # has the FCNTL gotcha disappeared ? with rsfile.rsopen(self.dummyFileName, "RWB", buffering=0, locking=True) as f: with rsfile.rsopen(self.dummyFileName, "RWB", buffering=0, locking=False) as g: pass # we close the file -> in normal conditions, we'd lose all fcntl() locks target = _worker_process.lock_tester lockingKwargs = {'timeout': 0} kwargs = { 'resultQueue': None, 'targetFileName': self.dummyFileName, 'multiprocessing_lock': None, 'lockingKwargs': lockingKwargs, 'pause': 0, 'multiprocess': True, 'res_by_exit_code': True } process = multiprocessing.Process(name="%s %s" % (target.__name__, "SEEK_SET"), target=target, kwargs=kwargs) process.daemon = True process.start() process.join() self.assertEqual( process.exitcode, 2, "Error, we lost all locks when closing a file descriptor - exitcode %s" % process.exitcode)
def testFileMethodForwarding(self): def test_new_methods(myfile, raw, char): myfile.sync() myfile.unique_id() times = myfile.times() assert times.access_time > 0 assert times.modification_time > 0 times_repr = repr(times) assert "FileTimes" in times_repr and "access" in times_repr and "modification" in times_repr myfile.size() myfile.mode myfile.name myfile.origin myfile.closefd myfile.write(char) self.assertEqual(raw.size(), 0) # not yet flushed myfile.lock_file() self.assertEqual(raw.size(), 1) # has been flushed myfile.write(char) self.assertEqual(raw.size(), 1) # not yet flushed myfile.unlock_file() self.assertEqual(raw.size(), 2) # has been flushed myfile.truncate(0) self.assertEqual(myfile.tell(), 2) # file pointer is unmoved myfile.write(char) self.assertEqual(raw.size(), 0) # not yet flushed myfile.lock_file() self.assertEqual(raw.size(), 3) # has been flushed, extending file as well myfile.write(char) self.assertEqual(raw.size(), 3) # not yet flushed myfile.unlock_file() self.assertEqual(raw.size(), 4) # has been flushed myfile.seek(0) myfile.write(char * 10) myfile.seek(0) self.assertEqual(myfile.read(1), char) self.assertTrue(raw.tell() > 1) # read ahead buffer full myfile.lock_file() self.assertEqual(raw.tell(), 1) # read ahead buffer reset self.assertEqual(myfile.read(1), char) self.assertTrue(raw.tell() > 2) # read ahead buffer full myfile.unlock_file() self.assertEqual(raw.tell(), 2) # read ahead buffer reset myfile.seek(0) self.assertEqual(myfile.read(1), char) self.assertTrue(raw.tell() > 1) # read ahead buffer full myfile.lock_file() self.assertEqual(raw.tell(), 1) # read ahead buffer reset self.assertEqual(myfile.read(1), char) self.assertTrue(raw.tell() > 2) # read ahead buffer full myfile.unlock_file() self.assertEqual(raw.tell(), 2) # read ahead buffer reset with rsfile.rsopen(TESTFN, "RWEB", buffering=100, locking=False, thread_safe=False) as myfile: # RW buffered binary stream test_new_methods(myfile, myfile.raw, b"x") with rsfile.rsopen(TESTFN, "RWET", buffering=100, locking=False, thread_safe=False) as myfile: # text stream test_new_methods(myfile, myfile.buffer.raw, "x")
def testFileSynchronization(self): # beware - randomization! buffering = random.choice([None, -1, 0, 100]) synchronized = random.choice((True, False)) combinations = [dict(metadata=True, full_flush=True), dict(metadata=False, full_flush=True), dict(metadata=True, full_flush=False), dict(metadata=False, full_flush=False)] kwargs = dict(name=TESTFN, mode="WB" + ("S" if synchronized else ""), buffering=buffering) string = b"abcdefghijklmnopqrstuvwxyz" * 1014 * 1024 # print("kwargs", kwargs) f = rsfile.rsopen(**kwargs) self.assertEqual(f._synchronized, synchronized) res = f.write(string) self.assertEqual(res, len(string)) for kwargs in combinations: f.sync(**kwargs) f.close() top_level_breakage = random.choice((True, False)) with rsfile.rsopen(TESTFN, "wt", thread_safe=False) as f: for kwargs in combinations: f.sync(**kwargs) def broken(*args, **kwargs): ABCD if top_level_breakage: f.flush = broken else: f.buffer.flush = broken try: # print("-------------->BEFORE", f.flush) for kwargs in combinations: self.assertRaises(NameError, f.sync, **kwargs) # sync implies flush! finally: if top_level_breakage: del f.flush else: del f.buffer.flush # print("-------------->AFTER", f.flush) pass if CHECK_SYNC_PERFS: # We have no easy way to check that the stream is REALLY in sync mode, except manually crashing the # computer... but we may check if perfs diff, at least with rsfile.rsopen(TESTFN, "wb", thread_safe=False) as f: N = 10 # NO SYNC a = time.time() for i in range(N): f.write(b"a") f.flush() b = time.time() res1 = b - a # LIGHTEST SYNC a = time.time() for i in range(N): f.write(b"b") f.sync(metadata=False, full_flush=False) b = time.time() res2 = b - a assert res2 > 1.05 * res1, (res1, res2) # it takes time to datasync() # HEAVIEST SYNC a = time.time() for i in range(N): f.write(b"c") # print("We issue full sync") f.sync(metadata=True, full_flush=True) # print("STOP") b = time.time() res3 = b - a if defs.RSFILE_IMPLEMENTATION == "windows": assert res3 > 1.05 * res1, (res1, res3) # same as datasync else: assert res3 > 1.05 * res2, (res2, res3) # full sync heavier than datasync, on linux/osx
def testModeEquivalences(self): std_parser = rsfile.parse_standard_args adv_parser = rsfile.parse_advanced_args file_modes = complete_and_normalize_possible_modes( FILE_MODES_CORRELATION) stdlib_file_modes = set(file_modes.values()) - set([None]) # pprint(stdlib_file_modes) # Combinations: 4 access modes, "+" or not, and ""/"b"/"t" assert len(stdlib_file_modes) == (4 if HAS_X_OPEN_FLAG else 3) * 2 * 3, len(stdlib_file_modes) def gen_all_combinations(values): for L in range(0, len(values) + 1): for subset in itertools.combinations(values, L): yield subset adv_flags = list("RAWCNEBT") # remove deprecated and isolated flags for idx, subset in enumerate(gen_all_combinations(adv_flags)): selected_adv_flags = "".join( subset) # the sames flags will come in various orders #print("-> Testing mode equivalences for", selected_adv_flags) _selected_adv_flags_normalized = "".join( sorted(selected_adv_flags)) is_abnormal_mode = _selected_adv_flags_normalized not in file_modes selected_stdlib_flags = file_modes.get( _selected_adv_flags_normalized, None) del _selected_adv_flags_normalized if False: # USEFUL LOGGING when debugging open modes print("==--> %r, %r" % (selected_adv_flags, selected_stdlib_flags)) if is_abnormal_mode: assert selected_stdlib_flags is None self.assertRaises(ValueError, rsfile.rsopen, TESTFN, selected_adv_flags) # NOT an OSError continue try: with rsfile.rsopen(TESTFN, selected_adv_flags): pass except EnvironmentError: # it's certainly due to file existence constraints if selected_stdlib_flags: # ALSO fails self.assertRaises(EnvironmentError, rsfile.rsopen, TESTFN, selected_stdlib_flags) else: if selected_stdlib_flags: # ALSO succeeds with rsfile.rsopen(TESTFN, selected_stdlib_flags): pass adv_res = adv_parser(TESTFN, selected_adv_flags, None, None, True) if selected_stdlib_flags: # we compare abilities on a THEORETICAL level between stdlib and advanced mode stdlib_res = std_parser(TESTFN, selected_stdlib_flags, None, None, True) msg = """ %s != %s : %s %s""" % (selected_stdlib_flags, selected_adv_flags, stdlib_res, adv_res) self.assertEqual(stdlib_res, adv_res, msg) chosen_flags = random.choice( (selected_stdlib_flags, selected_adv_flags)) else: chosen_flags = selected_adv_flags # we compare theoretical abilities with what the stream can ACTUALLY do theoretical_abilities = dict( read=adv_res[0]["read"], write=adv_res[0]["write"], append=adv_res[0]["append"], must_create=adv_res[0]["must_create"], must_not_create=adv_res[0]["must_not_create"], truncate=adv_res[1]["truncate"]) real_abilities = self.determine_stream_capabilities( rsfile.rsopen, chosen_flags) msg = """ THEORETICAL: %s REAL: %s""" % (theoretical_abilities, real_abilities) self.assertEqual(theoretical_abilities, real_abilities, msg) if selected_stdlib_flags: legacy_abilities = self.determine_stream_capabilities( io.open, selected_stdlib_flags) msg = """ THEORETICAL: %s LEGACY: %s""" % (theoretical_abilities, legacy_abilities) self.assertEqual(theoretical_abilities, legacy_abilities, msg) abilities_via_fileno = self.determine_stream_capabilities( reopener_via_fileno, chosen_flags) msg = """ THEORETICAL: %s REOPENED_VIA_FILENO: %s""" % (theoretical_abilities, abilities_via_fileno) self.assertEqual(theoretical_abilities, abilities_via_fileno, msg) ''' # no need to test "handle" passing because handles are below-or-equal filenos in our current implementations, # plus it leads to "too many open files" on windows because filenos can't be released without closing the handle too (and blcksize forces fileno creation..) abilities_via_handle = self.determine_stream_capabilities(reopener_via_handle, chosen_flags) msg = """ THEORETICAL : %s REOPENED_VIA_HANDLE: %s""" % (theoretical_abilities, abilities_via_handle) self.assertEqual(theoretical_abilities, abilities_via_handle, msg) ''' assert idx > 200, idx # we've well browsed lots of combinations
def test_global_locking_options(self): old_options = rsfile.get_rsfile_options() try: rsfile.set_rsfile_options(enforced_locking_timeout_value=2, default_spinlock_delay=1) with rsfile.rsopen(self.dummyFileName, "RWEB", buffering=100, locking=True) as myfile1: with rsfile.rsopen(self.dummyFileName, "RWEB", buffering=100, locking=False) as myfile2: self.assertEqual(myfile2.enforced_locking_timeout_value, 2) self.assertEqual(myfile2.default_spinlock_delay, 1) # this would deadlock the application, if no enforced timeout... self.assertRaises(rsfile.LockingException, myfile2.lock_file, timeout=1) self.assertRaises(rsfile.LockingException, myfile2.lock_file, timeout=3) self.assertRaises( RuntimeError, myfile2.lock_file, timeout=None) # blocking mode -> global option applies start = time.time() self.assertRaises(rsfile.LockingException, myfile2.lock_file, timeout=0.3) delay = time.time() - start self.assertTrue( 0.7 < delay < 1.3, "Delay is %d" % delay) # we check that the 1 s spinlock works target = _worker_process.lock_tester lockingKwargs = {'timeout': 0} kwargs = { 'resultQueue': None, 'targetFileName': self.dummyFileName, 'multiprocessing_lock': None, 'lockingKwargs': lockingKwargs, 'pause': 9, 'multiprocess': True } process = multiprocessing.Process(name="%s %s" % (target.__name__, "SEEK_SET"), target=target, kwargs=kwargs) process.daemon = True process.start() time.sleep(4) # let the child process start with rsfile.rsopen(self.dummyFileName, "RWEB", buffering=100, locking=False) as myfile: self.assertRaises(rsfile.LockingException, myfile.lock_file, timeout=1) self.assertRaises( RuntimeError, myfile.lock_file, timeout=None ) # global timeout due to interprocess locking conflict process.join() self.assertEqual( process.exitcode, 0, "Process '%s' encountered some trouble during execution" % process.name) finally: rsfile.set_rsfile_options(**old_options)
def testModeEquivalences(self): std_parser = rsfile.parse_standard_args adv_parser = rsfile.parse_advanced_args file_modes = complete_and_normalize_possible_modes(FILE_MODES_CORRELATION) stdlib_file_modes = set(file_modes.values()) - set([None]) # pprint(stdlib_file_modes) # Combinations: 4 access modes, "+" or not, and ""/"b"/"t" assert len(stdlib_file_modes) == (4 if HAS_X_OPEN_FLAG else 3) * 2 * 3, len(stdlib_file_modes) def gen_all_combinations(values): for L in range(0, len(values) + 1): for subset in itertools.combinations(values, L): yield subset adv_flags = list("RAWCNEBT") # remove deprecated and isolated flags for idx, subset in enumerate(gen_all_combinations(adv_flags)): selected_adv_flags = "".join(subset) # the sames flags will come in various orders #print("-> Testing mode equivalences for", selected_adv_flags) _selected_adv_flags_normalized = "".join(sorted(selected_adv_flags)) is_abnormal_mode = _selected_adv_flags_normalized not in file_modes selected_stdlib_flags = file_modes.get(_selected_adv_flags_normalized, None) del _selected_adv_flags_normalized if False: # USEFUL LOGGING when debugging open modes print("==--> %r, %r" % (selected_adv_flags, selected_stdlib_flags)) if is_abnormal_mode: assert selected_stdlib_flags is None self.assertRaises(ValueError, rsfile.rsopen, TESTFN, selected_adv_flags) # NOT an OSError continue try: with rsfile.rsopen(TESTFN, selected_adv_flags): pass except EnvironmentError: # it's certainly due to file existence constraints if selected_stdlib_flags: # ALSO fails self.assertRaises(EnvironmentError, rsfile.rsopen, TESTFN, selected_stdlib_flags) else: if selected_stdlib_flags: # ALSO succeeds with rsfile.rsopen(TESTFN, selected_stdlib_flags): pass adv_res = adv_parser(TESTFN, selected_adv_flags, None, None, True) if selected_stdlib_flags: # we compare abilities on a THEORETICAL level between stdlib and advanced mode stdlib_res = std_parser(TESTFN, selected_stdlib_flags, None, None, True) msg = """ %s != %s : %s %s""" % (selected_stdlib_flags, selected_adv_flags, stdlib_res, adv_res) self.assertEqual(stdlib_res, adv_res, msg) chosen_flags = random.choice((selected_stdlib_flags, selected_adv_flags)) else: chosen_flags = selected_adv_flags # we compare theoretical abilities with what the stream can ACTUALLY do theoretical_abilities = dict( read=adv_res[0]["read"], write=adv_res[0]["write"], append=adv_res[0]["append"], must_create=adv_res[0]["must_create"], must_not_create=adv_res[0]["must_not_create"], truncate=adv_res[1]["truncate"] ) real_abilities = self.determine_stream_capabilities(rsfile.rsopen, chosen_flags) msg = """ THEORETICAL: %s REAL: %s""" % (theoretical_abilities, real_abilities) self.assertEqual(theoretical_abilities, real_abilities, msg) if selected_stdlib_flags: legacy_abilities = self.determine_stream_capabilities(io.open, selected_stdlib_flags) msg = """ THEORETICAL: %s LEGACY: %s""" % (theoretical_abilities, legacy_abilities) self.assertEqual(theoretical_abilities, legacy_abilities, msg) abilities_via_fileno = self.determine_stream_capabilities(reopener_via_fileno, chosen_flags) msg = """ THEORETICAL: %s REOPENED_VIA_FILENO: %s""" % (theoretical_abilities, abilities_via_fileno) self.assertEqual(theoretical_abilities, abilities_via_fileno, msg) ''' # no need to test "handle" passing because handles are below-or-equal filenos in our current implementations, # plus it leads to "too many open files" on windows because filenos can't be released without closing the handle too (and blcksize forces fileno creation..) abilities_via_handle = self.determine_stream_capabilities(reopener_via_handle, chosen_flags) msg = """ THEORETICAL : %s REOPENED_VIA_HANDLE: %s""" % (theoretical_abilities, abilities_via_handle) self.assertEqual(theoretical_abilities, abilities_via_handle, msg) ''' assert idx > 200, idx # we've well browsed lots of combinations