Package: pymg
Table of Contents:IntroductionInstallationHow to use pymg?Using the --help optionInterpret the file without optionsSyntax validation using the --syntax optionCombination of optionsCombination of --trace and --inner options with --localsUsing the --recent optionSearch for a solution with the --search optionWrite the output to the file with the --output optionHow does pymg work?How does pymg check syntax?Prioritizing optionsRecipe fileSource information fileMirror fileInterpret the mirror fileCustomized excepthookBugs/RequestsLicenseIntroductionpymgis aCLItool that caninterpretPython files by thePython interpreterand display the error message in amore readableway if anexceptionoccurs.InstallationYou can usepipto install:python3 -m pip install pymgAnd also to upgrade:python3 -m pip install --upgrade pymgUsing the --help optionWith the help of the (-h, --help) option, you can easily see how to use pymg and the explanations of the options.Usage: pymg [OPTIONS] [PYTHON_FILE]...

  pymg is a CLI tool that can interpret Python files by the Python interpreter
  and display the error message in a more readable way if an exception occurs.

Options:
  -x, --syntax       It checks the syntax of the selected Python file. If
                     there is a syntax problem, an error message will be
                     displayed, otherwise 'INTACT' will be displayed.
  -t, --type         The type of exception that occurred will be displayed.
  -m, --message      The message of exception that occurred will be displayed.
  -f, --file         The full path of the Python file where the exception
                     occurred will be displayed.
  -s, --scope        The scope where the exception occurred will be displayed.
  -l, --line         The line number that caused the exception will be
                     displayed.
  -c, --code         The code that caused the exception will be displayed.
  -T, --trace        All paths that contributed to the creation of the
                     exception will be tracked, and then, with separation,
                     each created stack will be displayed.
  -i, --inner        Just like the --trace option, The exception that occurred
                     will be tracked and the result will be limited and
                     displayed to the internal content of the selected Python
                     file.
  -L, --locals       The last value of each scope's local variables before the
                     exception occurs will be displayed. This option can be
                     combined with --trace and --inner.
  -S, --search       With the help of stackoverflow api, the links of answered
                     posts related to the exception that occurred will be
                     displayed.
  -o, --output PATH  Writes the output to a text file. It has an argument that
                     contains the path of the text file.
  -r, --recent       Redisplays the last operation performed.
  -v, --version      Displays the current version of pymg installed on the
                     system.
  -h, --help         Show this message and exit.Interpret the file without optionsBy default, (-i, --inner) and (-L, --locals) will happen if you don't select any options. Combining these two options will make an effective form of error message.Let's check the test.py file as an example:importsysdefdiv(a,b):returna/bprint(div(int(sys.argv[1]),int(sys.argv[2])))The task of this program is very simple. It passes the two values it receives from the command line arguments to the div function, and the div function divides them.Now let us interpret the test.py file with pymg so that the ZeroDivisionError exception occurs.pymg test.py 4 0Output:Syntax validation using the --syntax optionLet's create an intentional syntax problem in the test.py file:importsysdefdiv(a,b):return(a/bprint(div(int(sys.argv[1]),int(sys.argv[2])))Now we will use the (-x, --syntax) option:pymg test.py 4 0 -xOutput:SyntaxError always precedes exceptions, and even if you don't use the (-x, --syntax) option, it will be checked at interpret time.Pay attention to the following command, which displays a similar output:pymg test.py 4 0Output:IndentationErrorandTabErrorwill also be checked in the syntax checking stage:importsysdefdiv(a,b):returna/bprint(div(int(sys.argv[1]),int(sys.argv[2])))Output:Combination of optionspymg allows you to combine options to access all the features of the exception separately and get different outputs:pymg test.py 4 0 -f -s -l -c -mOutput:But some options are ahead of others, you can see the prioritization of optionshere.For example, using the (-T, --trace) option, other options will not work (Because all the options are included in this option):pymg test.py 4 0 -f -s -l -c -m -TOutput:Combination of --trace and --inner options with --localsThe (-T, --trace) and (-i, --inner) options can be combined with (-L, --locals) option:pymg test.py -i -LOutput:Using the --recent optionBy using the --recent option, you can re-execute the last operation you have done. pymg saves your last move.Search for a solution with the --search optionYou can search for solutions to your problems in stackoverflow by using the (-S, --search) option. pymg searches stackoverflow for the exception and shows you the title and link of the posts that got the answer:pymg test.py 4 0 -SOutput:Write the output to the file with the --output optionYou can use the (-o, --output) option to write the generated output in a text file:pymg test.py -T -L -o output.txtoutput.txt╭─────────────────────────────────────────── Exception ───────────────────────────────────────────╮
│ Exception Type ❱ JSONDecodeError                                                                │
│ Exception Message ❱ Expecting value: line 1 column 1 (char 0)                                   │
│                                                                                                 │
│ ╭─ Trace[1] - <module> ───────────────────────────────────────────────────────────────────────╮ │
│ │                                                                                             │ │
│ │ File: /Users/mimseyedi/Desktop/test.py                                                      │ │
│ │                                                                                             │ │
│ │ ❱ 8 print(read_json_file(json_file_path))                                                   │ │
│ │           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                    │ │
│ │                                                                                             │ │
│ │ ╭───────────────────────── locals ──────────────────────────╮                               │ │
│ │ │ read_json_file = <function read_json_file at 0x1012705e0> │                               │ │
│ │ │ json_file_path = json_file.json                           │                               │ │
│ │ ╰───────────────────────────────────────────────────────────╯                               │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                 │
│ ╭─ Trace[2] - read_json_file ─────────────────────────────────────────────────────────────────╮ │
│ │                                                                                             │ │
│ │ File: /Users/mimseyedi/Desktop/test.py                                                      │ │
│ │                                                                                             │ │
│ │ ❱ 5 return json.load(jsonf)                                                                 │ │
│ │            ^^^^^^^^^^^^^^^^                                                                 │ │
│ │                                                                                             │ │
│ │ ╭────────────────────────────────── locals ───────────────────────────────────╮             │ │
│ │ │ json_file = json_file.json                                                  │             │ │
│ │ │ jsonf = <_io.TextIOWrapper name='json_file.json' mode='r' encoding='UTF-8'> │             │ │
│ │ ╰─────────────────────────────────────────────────────────────────────────────╯             │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                 │
│ ╭─ Trace[3] - load ───────────────────────────────────────────────────────────────────────────╮ │
│ │                                                                                             │ │
│ │ File: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/__init__.py    │ │
│ │                                                                                             │ │
│ │ ❱ 293 return loads(fp.read(),                                                               │ │
│ │       ^^^^^^^^^^^^^^^^^^^^^^^                                                               │ │
│ │                                                                                             │ │
│ │ NO LOCALS WERE FOUND IN THIS TRACE                                                          │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                 │
│ ╭─ Trace[4] - loads ──────────────────────────────────────────────────────────────────────────╮ │
│ │                                                                                             │ │
│ │ File: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/__init__.py    │ │
│ │                                                                                             │ │
│ │ ❱ 346 return _default_decoder.decode(s)                                                     │ │
│ │       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                     │ │
│ │                                                                                             │ │
│ │ NO LOCALS WERE FOUND IN THIS TRACE                                                          │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                 │
│ ╭─ Trace[5] - decode ─────────────────────────────────────────────────────────────────────────╮ │
│ │                                                                                             │ │
│ │ File: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/decoder.py     │ │
│ │                                                                                             │ │
│ │ ❱ 337 obj, end = self.raw_decode(s, idx=_w(s, 0).end())                                     │ │
│ │       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                     │ │
│ │                                                                                             │ │
│ │ NO LOCALS WERE FOUND IN THIS TRACE                                                          │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                 │
│ ╭─ Trace[6] - raw_decode ─────────────────────────────────────────────────────────────────────╮ │
│ │                                                                                             │ │
│ │ File: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/json/decoder.py     │ │
│ │                                                                                             │ │
│ │ ❱ 355 raise JSONDecodeError("Expecting value", s, err.value) from None                      │ │
│ │       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                      │ │
│ │                                                                                             │ │
│ │ NO LOCALS WERE FOUND IN THIS TRACE                                                          │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯How does pymg work?How does pymg check syntax?pymguses thepy_compilemodule and thePython interpreterto make sure that thesyntaxof the Python file is correct.This will be done with the help of thesubprocessmodule and theoutputwill becaptured:syntax_err:str=subprocess.run([python_interpreter,'-m','py_compile',source_file],capture_output=True).stderr.decode()Prioritizing optionsDue to the better display of the output, the options selected by the user areprioritized, which you will see in thetablebelow.OPTIONPRIORITYDESCRIPTION-x, --syntaxgroup 1It checks the syntax of the selected Python file. If there is a syntax problem, an error message will be displayed, otherwise 'INTACT' will be displayed.-T, --tracegroup 2All paths that contributed to the creation of the exception will be tracked, and then, with separation, each created stack will be displayed.-i, --innergroup 2Just like the --trace option, The exception that occurred will be tracked and the result will be limited and displayed to the internal content of the selected Python file.-t, --typegroup 3The type of exception that occurred will be displayed.-m, --messagegroup 3The message of exception that occurred will be displayed.-f, --filegroup 3The full path of the Python file where the exception occurred will be displayed.-s, --scopegroup 3The scope where the exception occurred will be displayed.-l, --linegroup 3The line number that caused the exception will be displayed.-c, --codegroup 3The code that caused the exception will be displayed.-L, --localsgroup 3The last value of each scope's local variables before the exception occurs will be displayed. This option can be combined with --trace and --inner.-S, --searchgroup 4With the help of stackoverflow api, the links of answered posts related to the exception that occurred will be displayed.Recipe fileAfterprioritizationand modification, the options arestoredas pointers to atemplate(the function that creates the specified template) in a file calledrecipe.Therecipelater helps the called function to create thetemplatesaccording to therecipewhen anexceptionoccurs.Source information fileIn order toaccesstheinformationof themain file (source), such as thefile nameand command linearguments, a file containing the source information is created toreplacethe information related to themirrorfile.Mirror fileAmirrorfile is a file thatimitatesthesource.In order tocapturethe data of theexceptionthat occurred, a piece of code must beaddedto the source:importsysfrompymgimportdisplay_error_messagesys.excepthook=display_error_messageThe task of this piece of code is toreplacetheexcepthookfunction from thesysmodule with acustomizedfunction.Note: When an exception occurs, the excepthook function of the sys module will be executed.Since you should nottouchthemain file (source)and makechangesin it, a file namedmirrorfile will becreated, which contains aheader(the piece of code you saw above) and thesource content. This file is interpretedinsteadof thesourcefile so that the source remainsisolatedandnot damaged.Interpret the mirror fileThemirrorfile will beinterpreted(executed) by thePython interpreter, and if anexceptionoccurs, thedisplay_error_messagefunction will be calledinsteadofexcepthook. Next, by reading therecipe, this function will find out what functions to call togeneratethetemplate, and at the end, it will display thetemplatethat contains the informationrequestedby the user.Customized excepthookThe task of this function is to read therecipeandlinkthecommandsto thefunctionswhose job is to produce a specifictemplate. This functionsendsthedatarelated to theexceptionthat occurred to the functions that mustgeneratethetemplatesso that they can easily access this data andcreatethetemplates.
At the end, thetemplateswill becombinedand the output will be displayed.Bugs/RequestsPlease send bug reports and feature requests throughgithub issue tracker.Licensepymg is a free and open source project under theGPL-3 LICENSE. Any contribution is welcome. You can do this by registering a pull request.