def test_no_false_positive(): # The following tests use valid syntax. # They should never have raised a Syntax error, and thus # we should not be able to find a likely cause of a problem. set_lang("en") no_cause = "I cannot guess the likely cause of this error" assert no_cause in find(["def test(arg1, arg2):"]) assert no_cause in find(["def test(arg1, arg2=None):"]) assert no_cause in find(["def test(arg1=(None, 1)):"]) assert no_cause in find(["def test(arg1=(1, None)):"]) assert no_cause in find(["def test(arg1=[1, None]):"]) assert no_cause in find(["def test(arg1={1, None}):"]) # assert no_cause in find(multiline_def.split("\n")) assert no_cause in find(["for i in range(3):"]) assert no_cause in find(["while True:"]) assert no_cause in find(["pass"]) assert no_cause in find(["else:"]) walrus_test = ["a := 1"] if sys.version_info >= (3, 8): assert no_cause in find(walrus_test, offset=3) else: assert "walrus operator" in find(walrus_test, offset=3)
def test_run_error_fr(): friendly_traceback.run( "tests/name_error.py", lang="fr", include="why", # more restricted than the English test console=False, redirect="capture", ) result = friendly_traceback.get_output() friendly_traceback.set_lang('en') friendly_traceback.uninstall() assert "Le nom semblable `pi` a été trouvé dans la portée locale." in result
def what(exception=None, lang="en", pre=False): """If known, shows the generic explanation about a given exception.""" if exception is not None: if hasattr(exception, "__name__"): exception = exception.__name__ if lang is not None: old_lang = friendly_traceback.get_lang() friendly_traceback.set_lang(lang) result = info_generic.get_generic_explanation(exception) if lang is not None: friendly_traceback.set_lang(old_lang) if pre: # for documentation lines = result.split("\n") for line in lines: session.write_err(" " + line + "\n") session.write_err("\n") else: session.write_err(result) return explain("what")
def set_lang(self, lang): """Sets the current language. Raises an exception if the language is unknown. If current dialect is set to None, an attempt will be made to set dialect to the value corresponding to language. """ if not self.is_lang(lang): raise exceptions.UnknownLanguageError( "Unknown language %s" % lang, (lang, self.languages) ) else: self.current_lang = lang self.install_gettext(lang) if self.current_dialect is None: try: self.set_dialect("py" + lang) except exceptions.UnknownDialectError: pass elif self.console_active: self.print_lang_info() friendly_traceback.set_lang(lang)
def test_check_syntax(): # set-up bad_code_syntax = "True = 1" bad_code_exec = "a = b" # Not a syntax error, but a NameError good_code = "c = 1" friendly.set_stream("capture") original_verbosity = friendly.get_verbosity() installed = friendly.is_installed() # ----- end of set-up # When a SyntaxError is raised, check_syntax returns False assert not friendly.advanced_check_syntax(source=bad_code_syntax) result = friendly.get_output() # content is flushed assert "Python exception" in result assert "SyntaxError" in result assert not friendly.get_output() # confirm that content was flushed # When no SyntaxError is raised, check_syntax returns a tuple # containing a code object and a file name assert friendly.advanced_check_syntax(source=bad_code_exec) assert friendly.advanced_check_syntax(source=good_code) assert not friendly.get_output() # no new exceptions recorded try: exec(bad_code_syntax, {}) except Exception: assert not friendly.get_output() # When friendly-traceback is not installed, a call to check_syntax # will end with verbosity set to 0, which corresponds to normal Python # tracebacks friendly.uninstall() friendly.advanced_check_syntax(source=bad_code_syntax) assert friendly.get_verbosity() == 0 friendly.advanced_check_syntax(source=bad_code_syntax, verbosity=4) assert friendly.get_verbosity() == 0 # When friendly-traceback is "installed", a call to check_syntax # leaves its verbosity unchanged. friendly.install(redirect="capture") friendly.set_verbosity(3) friendly.advanced_check_syntax(source=bad_code_syntax) assert friendly.get_verbosity() == 3 friendly.advanced_check_syntax(source=bad_code_syntax, verbosity=4) assert friendly.get_verbosity() == 3 # A call to advanced_code_syntax, with a language specified as an argument # should leave the previous language unchanged. friendly.set_lang("en") assert not friendly.advanced_check_syntax(source=bad_code_syntax, lang="fr") result = friendly.get_output() assert "Exception Python" in result # French heading assert friendly.get_lang() == "en" # Clean up and restore for other tests friendly.get_output() friendly.set_stream(None) if installed: friendly.uninstall() friendly.set_verbosity(original_verbosity)
by Python and its corresponding linenumber. [The offset is ignored.] 2. Next, it will try to look at the content of the line flagged by Python as the last line it could analyze, going through a series of individual tests. Here, only the last line of code is passed, which is broken down into a series of tokens prior to be sent to individual analyzers. [The message, linenumber and offset arguments are not used.] 3. Finally, it will look at the entire content, mostly focusing on checking if (), [], and {}, are properly matched and closed. In doing so, it might identify other errors along the way. """ import sys from friendly_traceback import analyze_syntax, set_lang set_lang("en") def find(lines=[" "], linenumber=1, message="invalid syntax", offset=1): return analyze_syntax._find_likely_cause( source_lines=lines, linenumber=linenumber, message=message, offset=offset ) def test_no_false_positive(): # The following tests use valid syntax. # They should never have raised a Syntax error, and thus # we should not be able to find a likely cause of a problem. no_cause = "I cannot guess the likely cause of this error" assert no_cause in find(["def test(arg1, arg2):"])
import sys import platform import friendly_traceback # Make it possible to find docs and tests source this_dir = os.path.dirname(__file__) docs_root_dir = os.path.abspath( os.path.join(this_dir, "..", "..", "friendly-traceback-docs") ) assert os.path.isdir(docs_root_dir), "Separate docs repo need to exist" # sys.path.insert(0, root_dir) LANG = "en" friendly_traceback.install() friendly_traceback.set_lang(LANG) sys.path.insert(0, this_dir) py_version = f"{sys.version_info.major}.{sys.version_info.minor}" import trb_syntax_common target = os.path.normpath( os.path.join(docs_root_dir, f"docs/source/syntax_tracebacks_{LANG}_{py_version}.rst") ) intro_text = """ Friendly SyntaxError tracebacks - in English ============================================= Friendly-traceback aims to provide friendlier feedback when an exception
def change_lang(self, event=None): """Keeping all the translations in sync""" lang = self.lang.get() friendly_traceback.set_lang(lang) demo_lang.install(lang) self.set_ui_lang()
def test_exec_code(): # set-up bad_code_syntax = "True = 1" bad_code_exec = "a = b" # Not a syntax error, but a NameError good_code = "c = 1" friendly.set_stream("capture") original_include = friendly.get_include() installed = friendly.is_installed() # ----- end of set-up # When a SyntaxError is raised, exec_code returns False assert not friendly.editors_helper.exec_code(source=bad_code_syntax) result = friendly.get_output() # content is flushed assert "SyntaxError" in result assert not friendly.get_output() # confirm that content was flushed friendly.editors_helper.exec_code(source=bad_code_exec) result = friendly.get_output() assert "NameError" in result assert friendly.editors_helper.exec_code(source=good_code) assert not friendly.get_output() # no new exceptions recorded try: exec(bad_code_syntax, {}) except Exception: assert not friendly.get_output() # Ensure that a call to exec_code only install() temporarily # if it was not installed before. friendly.uninstall() friendly.editors_helper.exec_code(source=bad_code_syntax) assert not friendly.is_installed() friendly.editors_helper.exec_code(source=bad_code_syntax, include="no_tb") assert not friendly.is_installed() # When friendly-traceback is "installed", a call to exec_code # leaves its include unchanged. friendly.install(redirect="capture") friendly.set_include("friendly_tb") friendly.editors_helper.exec_code(source=bad_code_syntax) assert friendly.get_include() == "friendly_tb" friendly.editors_helper.exec_code(source=bad_code_syntax, include="no_tb") assert friendly.get_include() == "friendly_tb" # A call to exec_code, with a language specified as an argument # should leave the previous language unchanged. friendly.set_lang("en") friendly.editors_helper.exec_code(source=bad_code_exec, lang="fr", include="explain") result = friendly.get_output() assert "Une exception `NameError` indique" in result assert friendly.get_lang() == "en" # Clean up and restore for other tests friendly.get_output() friendly.set_stream(None) if installed: friendly.uninstall() friendly.set_include(original_include)
import sys import pytest import friendly_traceback friendly_traceback.set_lang("en") # Format of the dict below # filename : "partial content of the Friendly traceback information" causes = { "raise_indentation_error1": "expected to begin a new indented block", "raise_indentation_error2": "does not match the indentation of the previous line", "raise_indentation_error3": "not aligned vertically with another block of code", "raise_tab_error": "A `TabError` indicates that you have used", "raise_syntax_error1": "assign a value to the Python keyword `def`", "raise_syntax_error2": "`if` but forgot to add a colon `:`", "raise_syntax_error3": "wrote a `while` loop but", "raise_syntax_error4": "wrote `else if` instead", "raise_syntax_error5": "wrote `elseif` instead", "raise_syntax_error6":
import sys import traceback from core import translation as t for attr in "type value traceback".split(): sys.__dict__.pop("last_" + attr, None) from friendly_traceback.core import FriendlyTraceback import friendly_traceback friendly_traceback.set_lang(t.current_language or "en") def friendly_syntax_error(e, filename): lines = iter(traceback.format_exception(type(e), e, e.__traceback__)) for line in lines: if line.strip().startswith(f'File "{filename}"'): break return f"""\ {''.join(lines).rstrip()} {t.Terms.syntax_error_at_line} {e.lineno} {friendly_message(e, double_newline=False)} """ def friendly_message(e, double_newline: bool): try: fr = FriendlyTraceback(type(e), e, e.__traceback__)