def tearDown(self): restore() try: # logging for record in self.log.records: if self.is_endpoints and len(record.args) >= 3: exception = record.args[2] if isinstance(exception, endpoints.ServiceException): try: str(exception) except TypeError: record.args[2].args = [str(arg) for arg in exception.args] except UnicodeEncodeError: record.args[2].args = [unicode(arg) for arg in exception.args] pathname = get_tail(record.pathname).group("tail") curdir_abspath = os.path.abspath(os.curdir) if is_mac: if curdir_abspath.startswith(mac_volumes_prefix): curdir_abspath = curdir_abspath[mac_volumes_prefix_length:] if pathname.startswith(mac_volumes_prefix): pathname = pathname[mac_volumes_prefix_length:] else: curdir_abspath = curdir_abspath.lstrip('/') pathname = pathname.lstrip('/') log = (record.levelname, pathname.replace(curdir_abspath, "").lstrip("/"), record.funcName, record.getMessage()) if getattr(self, "expected_logs", None): if log in self.expected_logs: continue matched = None for expected_log in self.expected_logs: if "..." in expected_log[3]: if log[:2] == expected_log[:2]: if doctest._ellipsis_match(expected_log[3], log[3]): matched = True continue if matched: continue elif self.is_endpoints: expected_log = ( 'WARNING', 'google/appengine/ext/ndb/tasklets.py', '_help_tasklet_along', '... generator ...(....py:...) raised ...Exception(...)') if log[:2] == expected_log[:2]: if doctest._ellipsis_match(expected_log[3], log[3]): matched = True continue print(record.levelname, pathname, record.lineno, record.funcName, record.getMessage()) assert not log finally: self.log.clear() self.log.uninstall() # testbed self.testbed.deactivate() # os.environ for key, value in self.origin_environ.iteritems(): if value is not None: os.environ[key] = value
def test_dt_file(self, test_id, sagews, src_file): print(("src_file=", src_file)) import sys from sage.doctest.sources import FileDocTestSource from sage.doctest.control import DocTestDefaults FDS = FileDocTestSource(src_file, DocTestDefaults()) doctests, extras = FDS.create_doctests(globals()) id = test_id excount = 0 dtn = 0 print(("{} doctests".format(len(doctests)))) for dt in doctests: print(("doctest number", dtn)) dtn += 1 exs = dt.examples excount += len(exs) for ex in exs: c = ex.sage_source print(("code", c)) w = ex.want print(("want", w)) use_pattern = False # handle ellipsis in wanted output if '...' in w: use_pattern = True # special case for bad "want" value at end of banner() wf = w.find('"help()" for help') if wf > 0: w = w[:wf] + '...' m = conftest.message.execute_code(code=c, id=id) sagews.send_json(m) if len(w) > 0: typ, mesg = sagews.recv() assert typ == 'json' assert mesg['id'] == id if 'stdout' in mesg: #assert 'stdout' in mesg output = mesg['stdout'] print(("outp", output)) elif 'stderr' in mesg: output = mesg['stderr'] # bypass err line number reporting in CoCalc if w.startswith('Traceback'): otf = output.find('Traceback') if otf > 0: output = output[otf:] print(("outp", output)) else: assert 0 if use_pattern: assert doctest._ellipsis_match(w, output) else: assert output.strip() == w.strip() conftest.recv_til_done(sagews, id) id += 1 print(("{} examples".format(excount))) conftest.test_id.id = id
def tearDown(self): try: # logging for record in self.log.records: pathname = get_tail(record.pathname).group("tail") log = (record.levelname, pathname.replace(os.path.abspath(os.curdir), "").lstrip("/"), record.funcName, record.getMessage()) if getattr(self, "expected_logs", None): if log in self.expected_logs: continue matched = None for expected_log in self.expected_logs: if "..." in expected_log[3]: if log[:2] == expected_log[:2]: if doctest._ellipsis_match(expected_log[3], log[3]): matched = True continue if matched: continue print(record.levelname, pathname, record.lineno, record.funcName, record.getMessage()) assert not log finally: self.log.clear() self.log.uninstall() # testbed self.testbed.deactivate() # os.environ for key, value in self.origin_environ.iteritems(): if value is not None: os.environ[key] = value
def tearDown(self): try: # logging for record in self.log.records: pathname = get_tail(record.pathname).group("tail") log = (record.levelname, pathname.replace(os.path.abspath(os.curdir), "").lstrip("/"), record.funcName, record.getMessage()) if getattr(self, "expected_logs", None): if log in self.expected_logs: continue matched = None for expected_log in self.expected_logs: if "..." in expected_log[3]: if log[:2] == expected_log[:2]: if doctest._ellipsis_match( expected_log[3], log[3]): matched = True continue if matched: continue print(record.levelname, pathname, record.lineno, record.funcName, record.getMessage()) assert not log finally: self.log.clear() self.log.uninstall() # testbed self.testbed.deactivate() # os.environ for key, value in self.origin_environ.iteritems(): if value is not None: os.environ[key] = value
def test_dt_file(self, test_id, sagews, src_file): print("src_file=",src_file) import sys from sage.doctest.sources import FileDocTestSource from sage.doctest.control import DocTestDefaults FDS = FileDocTestSource(src_file,DocTestDefaults()) doctests, extras = FDS.create_doctests(globals()) id = test_id excount = 0 dtn = 0 print "{} doctests".format(len(doctests)) for dt in doctests: print "doctest number", dtn dtn += 1 exs = dt.examples excount += len(exs) for ex in exs: c = ex.sage_source print("code",c) w = ex.want print("want",w) use_pattern = False # handle ellipsis in wanted output if '...' in w: use_pattern = True # special case for bad "want" value at end of banner() wf = w.find('"help()" for help') if wf > 0: w = w[:wf]+'...' m = conftest.message.execute_code(code = c, id = id) sagews.send_json(m) if len(w) > 0: typ, mesg = sagews.recv() assert typ == 'json' assert mesg['id'] == id if 'stdout' in mesg: #assert 'stdout' in mesg output = mesg['stdout'] print("outp",output) elif 'stderr' in mesg: output = mesg['stderr'] # bypass err line number reporting in CoCalc if w.startswith('Traceback'): otf = output.find('Traceback') if otf > 0: output = output[otf:] print("outp",output) else: assert 0 if use_pattern: assert doctest._ellipsis_match(w ,output) else: assert output.strip() == w.strip() conftest.recv_til_done(sagews, id) id += 1 print "{} examples".format(excount) conftest.test_id.id = id
def assert_ellipsis_match(want): """Match like doctest +ELLIPSIS, tolerating "...".""" got = sio.getvalue().strip() if not _ellipsis_match(want, got): msg = "Logging output differs from the expected.\n" msg += "Wanted:\n{}\n\nGot:\n{}".format(want, got) raise AssertionError(msg)
def ellipsis_match(expected, actual): """Check whether there is an ellipsis match.""" expected = text(expected) actual = text(actual) # normalize whitespace norm_expected = ' '.join(expected.split()) norm_actual = ' '.join(actual.split()) return doctest._ellipsis_match(norm_expected, norm_actual)
def test_repr(): """Test string representation of Cvodeint object.""" got = repr(Cvodeint(example_ode.exp_growth, t=[0, 2], y=[0.1])) wants = ["Cvodeint(f_ode=exp_growth, t=array([0, 2]), y=[0.1...], " + "abstol=c_double(1e-08))", "<class 'cvodeint.Cvodeint'> <function ode at 0x..." + "getargspec(__init__) is not available when running under Cython"] if not any([_ellipsis_match(want, got) for want in wants]): print "Wanted:", wants, "\\n", "Got:", got
def _assertTransformsTo(self, input, expected): # compare two chunks of HTML ignoring whitespace differences, # and with a useful diff on failure out = self.parser(input) normalized_out = normalize_html(out) normalized_expected = normalize_html(expected) try: self.assertTrue(_ellipsis_match(normalized_expected, normalized_out)) except AssertionError: class wrapper(object): want = expected raise AssertionError(self.outputchecker.output_difference( wrapper, out, REPORT_NDIFF))
def normalize_floats(self, want, got, flags): """ Alternative to the built-in check_output that also handles parsing float values and comparing their numeric values rather than their string representations. This requires rewriting enough of the basic check_output that, when FLOAT_CMP is enabled, it totally takes over for check_output. """ # Handle the common case first, for efficiency: # if they're string-identical, always return true. if got == want: return True # TODO parse integers as well ? # Parse floats and compare them. If some of the parsed floats contain # ellipses, skip the comparison. matches = self.num_got_rgx.finditer(got) numbers_got = [match.group(1) for match in matches] # list of strs matches = self.num_want_rgx.finditer(want) numbers_want = [match.group(1) for match in matches] # list of strs if len(numbers_got) != len(numbers_want): return False if len(numbers_got) > 0: nw_ = [] for ng, nw in zip(numbers_got, numbers_want): if '...' in nw: nw_.append(ng) continue else: nw_.append(nw) if not np.allclose(float(ng), float(nw)): return False got = self.num_got_rgx.sub(r'{}', got) got = got.format(*tuple(nw_)) # <BLANKLINE> can be used as a special sequence to signify a # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. if not (flags & doctest.DONT_ACCEPT_BLANKLINE): # Replace <BLANKLINE> in want with a blank line. want = re.sub( r'(?m)^{}\s*?$'.format(re.escape(doctest.BLANKLINE_MARKER)), '', want) # If a line in got contains only spaces, then remove the # spaces. got = re.sub(r'(?m)^\s*?$', '', got) if got == want: return True # This flag causes doctest to ignore any differences in the # contents of whitespace strings. Note that this can be used # in conjunction with the ELLIPSIS flag. if flags & doctest.NORMALIZE_WHITESPACE: got = ' '.join(got.split()) want = ' '.join(want.split()) if got == want: return True # The ELLIPSIS flag says to let the sequence "..." in `want` # match any substring in `got`. if flags & doctest.ELLIPSIS: if doctest._ellipsis_match(want, got): return True # We didn't find any match; return false. return False
def normalize_floats(self, want, got, flags): """ Alternative to the built-in check_output that also handles parsing float values and comparing their numeric values rather than their string representations. This requires rewriting enough of the basic check_output that, when FLOAT_CMP is enabled, it totally takes over for check_output. """ # Handle the common case first, for efficiency: # if they're string-identical, always return true. if got == want: return True # TODO parse integers as well ? # Parse floats and compare them. If some of the parsed floats contain # ellipses, skip the comparison. matches = self.num_got_rgx.finditer(got) numbers_got = [match.group(1) for match in matches] # list of strs matches = self.num_want_rgx.finditer(want) numbers_want = [match.group(1) for match in matches] # list of strs if len(numbers_got) != len(numbers_want): return False if len(numbers_got) > 0: nw_ = [] for ng, nw in zip(numbers_got, numbers_want): if '...' in nw: nw_.append(ng) continue else: nw_.append(nw) if not np.allclose(float(ng), float(nw)): return False got = self.num_got_rgx.sub(r'{}', got) got = got.format(*tuple(nw_)) # <BLANKLINE> can be used as a special sequence to signify a # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. if not (flags & doctest.DONT_ACCEPT_BLANKLINE): # Replace <BLANKLINE> in want with a blank line. want = re.sub(r'(?m)^{}\s*?$'.format(re.escape(doctest.BLANKLINE_MARKER)), '', want) # If a line in got contains only spaces, then remove the # spaces. got = re.sub(r'(?m)^\s*?$', '', got) if got == want: return True # This flag causes doctest to ignore any differences in the # contents of whitespace strings. Note that this can be used # in conjunction with the ELLIPSIS flag. if flags & doctest.NORMALIZE_WHITESPACE: got = ' '.join(got.split()) want = ' '.join(want.split()) if got == want: return True # The ELLIPSIS flag says to let the sequence "..." in `want` # match any substring in `got`. if flags & doctest.ELLIPSIS: if doctest._ellipsis_match(want, got): return True # We didn't find any match; return false. return False
def normalize_floats(self, want, got, flags): """ Alternative to the built-in check_output that also handles parsing float values and comparing their numeric values rather than their string representations. This requires rewriting enough of the basic check_output that, when FLOAT_CMP is enabled, it totally takes over for check_output. """ # <BLANKLINE> can be used as a special sequence to signify a # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. if not (flags & doctest.DONT_ACCEPT_BLANKLINE): # Replace <BLANKLINE> in want with a blank line. want = re.sub(r'(?m)^{}\s*?$'.format(re.escape(doctest.BLANKLINE_MARKER)), '', want) # If a line in got contains only spaces, then remove the # spaces. got = re.sub(r'(?m)^\s*?$', '', got) # This flag causes doctest to ignore any differences in the # contents of whitespace strings. Note that this can be used # in conjunction with the ELLIPSIS flag. if flags & doctest.NORMALIZE_WHITESPACE: got = ' '.join(got.split()) want = ' '.join(want.split()) # Handle the common case first, for efficiency: # if they're string-identical, always return true. if got == want: return True got_ = self.num_got_rgx.sub('0.0', got) want_ = self.num_got_rgx.sub('0.0', want) # fail if strings with ellipsis and normalize floats are not equal if flags & doctest.ELLIPSIS: if not doctest._ellipsis_match(want_, got_): return False else: if not got_ == want_: return False # at this point we made sure that non-float parts of strings are equivalent # so now we need to compare each number numbers_got = self.find_numbers(got) numbers_want_chunks = [ self.find_numbers(chunk) for chunk in want.split(doctest.ELLIPSIS_MARKER) ] if flags & doctest.ELLIPSIS and len(numbers_want_chunks) >= 2: return self.partial_match(numbers_got, numbers_want_chunks) # TODO parse integers as well ? # Parse floats and compare them. numbers_want = [f for chunk in numbers_want_chunks for f in chunk] # flatten array if len(numbers_got) != len(numbers_want): return False for ng, nw in zip(numbers_got, numbers_want): if not self.equal_floats(ng, nw): return False return True
def normalize_floats(self, want, got, flags): """ Alternative to the built-in check_output that also handles parsing float values and comparing their numeric values rather than their string representations. This requires rewriting enough of the basic check_output that, when FLOAT_CMP is enabled, it totally takes over for check_output. """ # Handle the common case first, for efficiency: # if they're string-identical, always return true. if got == want: return True # TODO parse integers as well ? # Parse floats and compare them. If some of the parsed floats contain # ellipses, skip the comparison. matches = self.num_got_rgx.finditer(got) numbers_got = [match.group(1) for match in matches] # list of strs matches = self.num_want_rgx.finditer(want) numbers_want = [match.group(1) for match in matches] # list of strs if len(numbers_got) != len(numbers_want): return False if len(numbers_got) > 0: nw_ = [] for ng, nw in zip(numbers_got, numbers_want): if '...' in nw: nw_.append(ng) continue else: nw_.append(nw) ngf = float(ng) nwf = float(nw) # This is a workaround for the backported version of this # plugin since we need to support older versions of numpy that # do not provide the 'equal_nan' argument, which was added in # numpy-1.10. if NUMPY_LT_1_10 and np.isnan(ngf) and np.isnan(nwf): continue if not np.allclose(ngf, nwf, rtol=self.rtol, atol=self.atol, **_ALLCLOSE_KWARGS): return False # replace all floats in the "got" string by those from "wanted". # TODO: can this be done more elegantly? Used to replace all with # '{}' and then format, but this is problematic if the string # contains other curly braces (e.g., from a dict). got = self.num_got_rgx.sub(lambda x: nw_.pop(0), got) # <BLANKLINE> can be used as a special sequence to signify a # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. if not (flags & doctest.DONT_ACCEPT_BLANKLINE): # Replace <BLANKLINE> in want with a blank line. want = re.sub( r'(?m)^{}\s*?$'.format(re.escape(doctest.BLANKLINE_MARKER)), '', want) # If a line in got contains only spaces, then remove the # spaces. got = re.sub(r'(?m)^\s*?$', '', got) if got == want: return True # This flag causes doctest to ignore any differences in the # contents of whitespace strings. Note that this can be used # in conjunction with the ELLIPSIS flag. if flags & doctest.NORMALIZE_WHITESPACE: got = ' '.join(got.split()) want = ' '.join(want.split()) if got == want: return True # The ELLIPSIS flag says to let the sequence "..." in `want` # match any substring in `got`. if flags & doctest.ELLIPSIS: if doctest._ellipsis_match(want, got): return True # We didn't find any match; return false. return False
def update_event(self, inp=-1): self.set_output_val(0, doctest._ellipsis_match(self.input(0), self.input(1)))