diff --git a/src/calibre/utils/rapydscript.py b/src/calibre/utils/rapydscript.py index e90fb20673..4976dec174 100644 --- a/src/calibre/utils/rapydscript.py +++ b/src/calibre/utils/rapydscript.py @@ -227,7 +227,16 @@ def forked_compile(): stdout.close() -def compile_pyj(data, filename='', beautify=True, private_scope=True, libdir=None, omit_baselib=False, js_version=5): +def compile_pyj( + data, + filename='', + beautify=True, + private_scope=True, + libdir=None, + omit_baselib=False, + js_version=5, + add_call_site_to_functions='' +): if isinstance(data, bytes): data = data.decode('utf-8') options = { @@ -236,6 +245,7 @@ def compile_pyj(data, filename='', beautify=True, private_scope=True, lib 'keep_baselib': not omit_baselib, 'filename': filename, 'js_version': js_version, + 'add_call_site_to_functions': '', } if not ok_to_import_webengine(): from calibre.debug import run_calibre_debug @@ -273,12 +283,21 @@ def detect_external_compiler(): return False -def compile_fast(data, filename=None, beautify=True, private_scope=True, libdir=None, omit_baselib=False, js_version=None): +def compile_fast( + data, + filename=None, + beautify=True, + private_scope=True, + libdir=None, + omit_baselib=False, + js_version=None, + add_call_site_to_functions='assert_' +): global has_external_compiler if has_external_compiler is None: has_external_compiler = detect_external_compiler() if not has_external_compiler: - return compile_pyj(data, filename or '', beautify, private_scope, libdir, omit_baselib, js_version or 6) + return compile_pyj(data, filename or '', beautify, private_scope, libdir, omit_baselib, js_version or 6, add_call_site_to_functions) args = ['--cache-dir', module_cache_dir()] if libdir: args += ['--import-path', libdir] @@ -290,6 +309,8 @@ def compile_fast(data, filename=None, beautify=True, private_scope=True, libdir= args.append('--omit-baselib') if js_version: args.append('--js-version={}'.format(js_version or 6)) + if add_call_site_to_functions: + args.append('--add-call-site-to-functions=' + add_call_site_to_functions) if not isinstance(data, bytes): data = data.encode('utf-8') if filename: diff --git a/src/pyj/date.pyj b/src/pyj/date.pyj index eef6fb26a4..e7257d5977 100644 --- a/src/pyj/date.pyj +++ b/src/pyj/date.pyj @@ -99,11 +99,6 @@ fd_function_index = { 'A': fd_format_ampm, } -def test_fd(date, fmt, ans): - q = format_date(date, fmt, as_utc=True) - if q is not ans: - raise Exception(str.format('Failed to format {} with {}: {} is not {}', date, fmt, q, ans)) - def format_date(date=None, fmt='dd MMM yyyy', as_utc=False): fmt = fmt or 'dd MMM yyyy' ampm = 'ap' in fmt.toLowerCase() @@ -122,9 +117,3 @@ def format_date(date=None, fmt='dd MMM yyyy', as_utc=False): return '' ) # }}} - -if __name__ is '__main__': - test_fd('1101-01-01T09:00:00+00:00', 'hh h', '09 9') - test_fd('1101-01-01T09:05:01+00:00', 'hh h mm m ss s ap AP yy yyyy', '09 9 05 5 01 1 am AM 01 1101') - test_fd('2001-01-02T09:00:00+00:00', 'M MM MMM MMMM', '1 01 Jan January') - test_fd('2001-01-01T12:00:00+00:00', 'd dd ddd dddd', '1 01 Mon Monday') diff --git a/src/pyj/read_book/cfi.pyj b/src/pyj/read_book/cfi.pyj index b50946d03e..9f98d092fc 100644 --- a/src/pyj/read_book/cfi.pyj +++ b/src/pyj/read_book/cfi.pyj @@ -688,8 +688,3 @@ def cfi_for_selection(r): # {{{ } # }}} - -if __name__ is '__main__': - t = 'a^!,1' - if unescape_from_cfi(escape_for_cfi(t)) is not t: - raise Exception('Failed to properly roundtrip cfi') diff --git a/src/pyj/read_book/test_cfi.pyj b/src/pyj/read_book/test_cfi.pyj new file mode 100644 index 0000000000..0565c014af --- /dev/null +++ b/src/pyj/read_book/test_cfi.pyj @@ -0,0 +1,12 @@ +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2020, Kovid Goyal +from __python__ import bound_methods, hash_literals + +from read_book.cfi import escape_for_cfi, unescape_from_cfi +from testing import test, assert_equal + + +@test +def cfi_escaping(): + t = 'a^!,1' + assert_equal(t, unescape_from_cfi(escape_for_cfi(t))) diff --git a/src/pyj/test.pyj b/src/pyj/test.pyj index aea7d9f841..2bbcacb3a0 100644 --- a/src/pyj/test.pyj +++ b/src/pyj/test.pyj @@ -4,6 +4,11 @@ from __python__ import bound_methods, hash_literals import traceback +import initialize # noqa: unused-import +import test_date # noqa: unused-import +import test_utils # noqa: unused-import +import read_book.test_cfi # noqa: unused-import + from testing import registered_tests, reset_dom @@ -16,6 +21,19 @@ def get_matching_tests_for_name(name): return ans +def get_traceback(lines): + lines = traceback.format_exception() + last_line = lines[-1] + final_lines = v'[]' + pat = /at assert_\w+ \(/ + for line in lines: + if pat.test(line): + break + final_lines.push(line) + final_lines.push(last_line) + return final_lines.join('') + + def run_tests(tests): failed_tests = [] count = 0 @@ -26,8 +44,9 @@ def run_tests(tests): f() count += 1 except: - traceback.print_stack() - failed_tests.append((f.test_name, traceback.format_stack())) + tb = get_traceback() + console.error(tb) + failed_tests.append((f.test_name, tb)) return failed_tests, count diff --git a/src/pyj/test_date.pyj b/src/pyj/test_date.pyj new file mode 100644 index 0000000000..6a76ea77be --- /dev/null +++ b/src/pyj/test_date.pyj @@ -0,0 +1,18 @@ +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2020, Kovid Goyal +from __python__ import bound_methods, hash_literals + +from date import format_date +from testing import test, assert_equal + + +def test_fd(date, fmt, ans): + q = format_date(date, fmt, as_utc=True) + assert_equal(ans, q) + +@test +def date_formatting(): + test_fd('1101-01-01T09:00:00+00:00', 'hh h', '09 9') + test_fd('1101-01-01T09:05:01+00:00', 'hh h mm m ss s ap AP yy yyyy', '09 9 05 5 01 1 am AM 01 1101') + test_fd('2001-01-02T09:00:00+00:00', 'M MM MMM MMMM', '1 01 Jan January') + test_fd('2001-01-01T12:00:00+00:00', 'd dd ddd dddd', '1 01 Mon Monday') diff --git a/src/pyj/test_utils.pyj b/src/pyj/test_utils.pyj new file mode 100644 index 0000000000..f424e1b06d --- /dev/null +++ b/src/pyj/test_utils.pyj @@ -0,0 +1,14 @@ +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2020, Kovid Goyal +from __python__ import bound_methods, hash_literals + +from testing import assert_equal, test +from utils import fmt_sidx, human_readable, rating_to_stars + + +@test +def misc_utils(): + assert_equal(rating_to_stars(3, True), '★½') + assert_equal(fmt_sidx(10), 'X') + assert_equal(fmt_sidx(1.2), '1.20') + assert_equal(list(map(human_readable, [1, 1024.0, 1025, 1024*1024*2.3])), ["1 B", "1 KB", "1 KB", "2.3 MB"]) diff --git a/src/pyj/testing.pyj b/src/pyj/testing.pyj index ffdc037158..4fe561fc7d 100644 --- a/src/pyj/testing.pyj +++ b/src/pyj/testing.pyj @@ -4,23 +4,26 @@ from __python__ import bound_methods, hash_literals from dom import clear -def raise_fail(preamble, msg): +def raise_fail(preamble, msg, call_site): if msg: msg = '. ' + msg else: msg = '' + if call_site?.module_name: + msg += f' [in module {call_site.module_name}:{call_site.line}:{call_site.col}]' raise AssertionError(preamble + msg) -def assert_equal(a, b, msg): +def assert_equal(a, b, msg, call_site=None): def fail(): - raise_fail(f'{a} != {b}', msg) + p = f'{a} != {b}' + raise_fail(p, msg, call_site) atype = jstype(a) btype = jstype(b) base_types = {'number': True, 'boolean': True, 'string': True, 'undefined': True} - if base_types[a] or base_types[b] or a is None or b is None: + if base_types[atype] or base_types[btype] or a is None or b is None: if a is not b: fail() return @@ -49,14 +52,14 @@ def assert_equal(a, b, msg): fail() -def assert_true(x, msg): +def assert_true(x, msg, call_site=None): if not x: - raise_fail(f'{x} is not truthy', msg) + raise_fail(f'{x} is not truthy', msg, call_site) -def assert_fale(x, msg): +def assert_fale(x, msg, call_site=None): if x: - raise_fail(f'{x} is truthy', msg) + raise_fail(f'{x} is truthy', msg, call_site) def reset_dom(): diff --git a/src/pyj/utils.pyj b/src/pyj/utils.pyj index 93e1747e10..a431d94905 100644 --- a/src/pyj/utils.pyj +++ b/src/pyj/utils.pyj @@ -250,11 +250,3 @@ def sandboxed_html(html, style, sandbox): # Microsoft Edge does not support srcdoc not does it work using a data URI. ans.srcdoc = final_html return ans - - -if __name__ is '__main__': - from pythonize import strings - strings() - print(rating_to_stars(3, True)) - print(fmt_sidx(10), fmt_sidx(1.2)) - print(list(map(human_readable, [1, 1024.0, 1025, 1024*1024*2.3])))