Package: runmany
RunManyIntro|Installation|Usage|Syntax|Settings|AboutA tool to run many programs written in many languages from one file.Normally to practice multiple programming languages at once you need multiple files or multiple projects,
perhaps multiple IDE's. RunMany is a tool that lets you write multiple programs inthe samefile using
any programming languages you want, and then run them all at once.RunMany uses ".many" as its file extension, so for example, if a file calledsimple.manyhas the following contents:Python:
    print("Hi")

JavaScript:
    console.log("Hi")

C:
    #include <stdio.h>
    int main() {
        printf("Hi\n");
        return 0;
    }Then doingrunmany simple.manyin terminal will produce this organized output
of running the Python, JavaScript, and C programs within:************************************************************
1. Python
-------------------- output from line 1 --------------------
Hi


************************************************************
2. JavaScript
-------------------- output from line 4 --------------------
Hi


************************************************************
3. C
-------------------- output from line 7 --------------------
Hi


************************************************************
3/3 programs successfully run!
3/3 had the exact same stdout!
************************************************************Argv and stdin can also be specified in the .many file on a per-language basis, and there are manysettingsthat can customize how languages are run and displayed in the output.In general, RunMany can be used for:Chrestomathy - Writing equivalent programs in many languages, like onRosetta Code.
(example/output)Performance Testing - Timing different implementations of a program, even across languages.
(example/output)Input Testing - Easily giving many combinations of argv or stdin to programs.
(example/output)Polyglots - Making esoteric code that can be executed in multiple languages at once.
(example/output)Overall RunMany is a useful tool for anyone who wants to play with multiple programming languages at a time.InstallationMake sure you havePythonversion 3.6 or above installed, then runpip install runmanyin terminal to install the latestRunMany Python package from PyPI.
Thenrunmany <filename>should work to run .many files. See more ways to run inUsage.RunMany works best inVSCodewith the companionRunMany VSCode extensionwhich provides
syntax highlighting for .many files and quick ways to run them.
Install the extension for freefrom the marketplaceor by running:code --install-extension discretegames.runmanyYou also need the programming languages you want RunMany to run installed on your computer
because RunMany uses their interpreters/compilers behind the scenes to actually run programs.RunMany has built-in support for the following languages:Ada, Bash, Batch, C, C#, C++, Dart, Fortran, Go, Groovy, Haskell, Java, JavaScript,
Julia, Kotlin, Lisp, Lua, MIPS, Pascal, Perl, PHP, PowerShell, Print, Python, Python 2,
R, Racket, Ruby, Rust, Scala, TypeScript, VBScript, and Visual BasicMeaning, if you already have one of these languages installed,
there's a good chance it will work in RunMany automatically.TheRunMany VSCode extensionprovides syntax highlighting for all of these languages plus a few more.There are ways to add custom languages and change the behavior of built-in languages, and even make them different on
different operating systems. For more info seeCustomizing Languages.Note thatPrintis a utility language that simply prints the code content to stdout, andMIPSexpectsmars.jarto be in the current working directory.TroubleshootingIfpip install runmanydidn't work trypip3 install runmanyorpython -m pip install runmanyorpython3 -m pip install runmany.On Windows, if nothing works, you may need tomake sure the Python installation and Scripts directories are in your
Path environment variable,
then restart your terminal and try again.RunMany was made in Python 3.9 on Windows and has beenthoroughly testedon Python versions 3.6, 3.7, 3.8, 3.9, and 3.10 on Windows.
It should also work fine on Linux and macOS but has been less extensively tested on those operating systems,
especially when it comes tothe commandsthat run the interpreters/compilers of other programming languages.RunMany is now in version 2 with improved .many file syntax and more settings.The old 1.0.3 version is still available on PyPI.UsageRunning RunMany From Command LineTo run a RunMany file namedmyfile.manyuse the terminal command:runmany myfile.manyThere are also optional arguments to get help and specify the settings and output files:runmany [-h --help] [-s --settings <settings-file>] [-o --outfile <output-file>] <input-file><input-file>is the required .many file to run.<settings-file>is the optional .json file that defines how languages are run and how the output is formatted.<output-file>is the optional file to send the output to. When omitted, output goes to stdout.For example, the command to runmyfile.manywith settingsmysettings.jsonand send output tomyoutput.txtwould be:runmany -s mysettings.json -o myoutput.txt myfile.manyWhen a settings file is provided on command line, anysettings sectionsembedded in the input file are ignored.
If neither are present, or for any missing settings,default_settings.jsonis used as a fallback. See more info inSettings.For some examples of .many files and their output checkthe examples folder on GitHuborthe manychallenges repowhere various code challenges for sites likeProject Eulerare solved in many languages at once.The .many extension for RunMany files is not required but recommended for clarity.Running RunMany From PythonRunMany can be imported and used from Python as follows:fromrunmanyimportrunmany,runmanys# Run to stdoutrunmany('path/to/myfile.many','path/to/mysettings.json')# settings JSON is always optional# Run to output filerunmany('path/to/myfile.many','path/to/mysettings.json','path/to/myoutput.txt')# Run to file objectwithopen('path/to/myoutput.txt','w')asoutput_file:runmany('path/to/myfile.many','path/to/mysettings.json',output_file)# Run to stringoutput_string=runmanys('path/to/myfile.many','path/to/mysettings.json')print(output_string)In bothrunmany.runmanyandrunmany.runmanysfunctions,from_string=Truewill make the .many file argument be
interpreted as a string instead of a file path, and the settings JSON argument may be given as a path to the
.json file or a JSON-like Python dictionary, orNoneto provide no settings. As with running from the command line,
providing settings here means all settings embedded in the .many file are ignored.The functionrunmany.cmdline, which takes a list of command line arguments,
is also present as an alternative to using the command line directly..many SyntaxThe .many file format is what RunMany expects when given a file to run.Principally, a .many file consists of sections that each contain one or more snippets. A section starts with an
unindented header line such asPython:orStdin for Python:,
then the content of the first snippet is what appears after the colon and on indented lines below.
Additional snippets may be added to the section with an unindentedAlso:header, and a section ends when a new one starts or an unindentedEnd.or the end of the file is reached.A .many file runs from top to bottom, executing sections and snippets in the order they are encountered. Notably,
a .many file will run regardless of if it has syntax errors or not. Any invalid syntax will be ignored and mentioned
in an error message.In the example .many file below, theStdin for Python:section has two snippets,barandbaz, and they become the
standard input for the Python program in thePython:section, which has one snippetprint('foo' + input()).
Running this file runs the Python program twice, once forbarand once forbaz, giving the respective outputsfoobarandfoobaz.Stdin for Python:
    bar
Also:
    baz
End.

Python:
    print('foo' + input())
End.Read on for specifics about all .many file syntax, or check outsyntax.manywhich has examples of all syntax as well.Syntax SpecificsComments%%as the first non-whitespace characters in a line makes a comment until the end of that line.%% this is a comment
Python: %% this is not a comment
    %% this is a comment
    print(1) %% this is not a commentThere are no block comments, thoughStart & Stopare close in functionality.Sections & SnippetsAs mentioned, a .many file consists of sections that start with a header and contain snippets.
There are four types of sections:Code sectionswith the header<language>:or<language1>, <language2>, ...:Argv sectionswith the headerArgv:orArgv for <language1>, <language2>, ...:Stdin sectionswith the headerStdin:orStdin for <language1>, <language2>, ...:Settings sectionswith the headerSettings:All but the settings section can have a comma separated list of the languages it applies to in the header.
These languages, once stripped of whitespace, must match the"name"keys of the languages in thesettingsJSON,
but are not case sensitive. (Keywords like "Argv" and "Stdin"arecase sensitive. Custom languages should not use
RunMany keywords as names nor contain the characters,:%!@.)The headerAlso:is used to add snippets to a section andEnd.can optionally be used to end a section.The content of a snippet is the text after any whitespace after the colon (:) in the snippet header,
plus all the lines below that are indented with a single tab or 4 spaces (with these indents removed),
until the next header orEnd.or end of file.So this code sectionPython: import math
    print(math.pi)
Also: print('pie')
    print('cake')has two snippets whose contents are:importmathprint(math.pi)print('pie')print('cake')Blank lines above or below sections are only for readability and not required.
Uncommented code outside of sections is invalid.Code SectionA code section starts right out with a comma separated list of languages
and its snippet contents are the programs to run in those languages.One language in the comma separated list is almost always sufficient unless you are writingpolyglots,JavaScript:
    console.log('Some code that will be run in JavaScript.')

Python, Python 2:
    print('Some code that will be run in Python 3 then Python 2.')
Also:
    print('Some more code that will be run in Python 3 then Python 2.')Also:snippet headers in code sections are shorthand for repeating the section header.Argv SectionArgv is the argument vector, aka the command line arguments sent to programs.An argv section can either startArgv:to apply to all languages, orArgv for <language1>, <language2>, ...:to
apply to the languages in the comma separated list. Either way overwrites any previous argv set for those languages.Each snippet in an argv section is a separate argv that will be sent in turn to the programs of the languages
the section applies to. This makes it easy to test many argvs at once.Argv: argv sent to all languages

Argv for Python: 1
Also: 2
Also: 3

Python:
    import sys
    print(sys.argv[1])This .many code will run the Python program three times with argv1then2then3.For argv to work the$argvplaceholdermust be placed properly into the command of the language.Stdin SectionAlmost exactly like an argv section but for the standard input stream users normally type text into.An stdin section can either startStdin:to apply to all languages, orStdin for <language1>, <language2>, ...:to
apply to the languages in the comma separated list. Either way overwrites any previous stdin set for those languages.Each snippet in a stdin section is a separate stdin that will be sent in turn to the programs of the languages
the section applies to. This makes it easy to test many stdins at once.Stdin: stdin sent to all languages

Stdin for Python: A
Also: B
Also: C

Python:
    print(input())This .many code will run the Python program three times with stdinAthenBthenC.When multiple argvs and stdins apply to one language, all possible combinations of every argv and every stdin
are sent to programs of that language.Settings SectionA settings section starts withSettings:and allows embedding asettingsJSON in a .many file, which is used until another settings section is encountered.These embedded settings are only used when settings were not specifically provided when runmany was called.
Any missing settings default to their values indefault_settings.json.Settings:
    { "show_code": true }
Python:
    print('this Python code will now be shown as part of the output')A JSON string of the path to a settings file can also be used, likeSettings: "path/to/mysettings.json".Also:snippet headers in settings sections are shorthand for repeating the section header.
So they don't serve much purpose since they immediately overwrite the previous settings.Disabled Sections & SnippetsPutting!!at the start of a section header disables the entire section and all its snippets.Putting!at the start of a snippet header disables that snippet.!!Python:
    print('this is disabled')
Also:
    print('this is also disabled')

!Python:
    print('this is disabled')
Also:
    print('this is not disabled')
!Also:
    print('this is disabled')Solo Sections & SnippetsIf any section headers start with@@then only those sections are run, similar to a "solo" checkbox in
audio/video editing software.If any snippet headers within a section start with@then only those snippets are run when the section runs.@@@Python:
    print('this is run')
Also:
    print('this is not run')
@Also:
    print('this is run')

Python:
    print('this is not run')
@Also:
    print('this is also not run')Note how the first line has three@@@, two to solo the section and another to solo its first snippet.Start & StopEverything before the lastSTART:at the start of a line by itself in a .many file is ignored.Everything after the firstSTOP.at the start of a line by itself in a .many file is ignored.So only the JavaScript section of this .many file is run:Python: print('unseen')
START:
JavaScript: console.log('seen')
STOP.
Python: print('unseen')There should only be up to oneSTART:and oneSTOP.in a .many file.SettingsRunMany's setting are defined by aJSONfile that can beprovided when runmany is calledordirectly embedded in a .many file.The settings JSON defines what languages RunMany can run and how it will run them.
It also defines how the RunMany output will be formatted.The filedefault_settings.jsonholds the default values for all settings.
These defaults are automatically used if not present in a provided or embedded settings JSON.Customizing LanguagesMost settings are simple flags or values that can be set in the base settings JSON object to apply them globally
(seeList of Settings)
but four special keys in the JSON are used to customize the languages RunMany can run or to add more languages.
These are"languages","languages_windows","languages_linux"and"languages_mac"("languages_<os>"will be used to refer to the last three).
They are arrays of single-level JSON objects that specify the settings for the language that
matches the"name"key of the object.The"languages_<os>"array that matches the system OS has highest priority when determining a language's settings,
followed by the"languages"array, followed by the built-in"supplied_languages_<os>"and"supplied_languages"arrays. (These"supplied_languages..."arrays should never be set in your settings JSON.) Languages use the settings
in the base JSON object as a final fallback.For example, the following settings JSON sets the"show_code"setting (which is false by default)
to true for all languages except for Python and Python 2. It also creates a new language
"Python 3.10" that can be used in a .many file section header on Windows.{"show_code":true,"languages":[{"name":"Python","show_code":false},{"name":"Python 2","show_code":false}],"languages_windows":[{"name":"Python 3.10","extension":".py","command":"py -3.10"}]}The"name"key is required for every object in a languages array, and the"command"and"extension"keys
should always be provided for new custom languages. Not every setting makes sense to apply on a per-language basis
though. For example,"show_equal"applies to the run of the .many file as a whole, so it only makes sense in the
base JSON object.List of SettingsAll settings described and whether or not they can be overridden on a per-language basis in the"languages"and"languages_<os>"array objects:JSON KeyTypeDefaultOverridableDescription"command"string"echo NOCOMMAND"yesThe console command to run a language, following thecommand format."extension"string""yesThe file extension of a language, including the dot."timeout"float10.0yesThe time limit of each program in seconds, ornullfor no time limit."runs"int1yesThe number of times each program is run. Only the output of the last run is shown."stderr"string"smart"yes"yes"/trueto combine program stderr with stdout."no"/falseto hide program stderr."smart"/nullto only show stderr when programs have non-zero exit codes."spacing"int1yesThe number of blank lines to add after each run."newline"string"\n"yesWhat newlines are replaced with in code, argv, and stdin snippet content. Ornullfor the OS default."tab"string"\t"yesWhat the tab character is replaced with in code, argv, and stdin snippet content."cwd"stringnullyesThe current working directory to run programs from. May be a relative path. Usenullor"."for no change to the current working directory."minimalist"boolfalsenoWhether to display all output in a minimal format where the dividers, code, argv, and stdin are not shown."run_blanks"boolfalsenoWhether blank snippets that consist purely of whitespace are run or ignored."show_time"boolfalseyesWhether the execution time is shown. Useful for performance testing when combined with"runs"."show_command"boolfalseyesWhether the command used to run each program is shown. Useful for debugging commands for new languages."show_code"boolfalseyesWhether the source code of the program is shown."show_argv"booltrueyesWhether the argv for the program is shown (when present)."show_stdin"booltrueyesWhether the stdin for the program is shown (when present)."show_output"booltrueyesWhether the output for the program is shown. This includes the stdout, and, depending on"stderr", the stderr."show_runs"booltruenoWhether the list of runs is shown. This is usually the bulk of the output."show_stats"booltruenoWhether the success and failure counts are shown after everything has run."show_equal"booltruenoWhether the matching stdouts are compared and grouped after everything has run."show_errors"booltruenoWhether RunMany errors like `"strip_argv"string"smart"no"yes"/trueto strip the snippet content of leading and trailing whitespace."no"/falseto keep the snippet content as is."smart"/nullto join all the lines in the snippet together with spaces as if they were on one line."strip_stdin"string"smart"no"yes"/trueto strip the start and end of the snippet of whitespace-only lines."no"/falseto keep the snippet content as is."smart"/nullto do the same as"yes"/truebut also append a single newline."strip_code"string"smart"yes"yes"/trueto strip the start and end of the snippet of whitespace-only lines."no"/falseto keep the snippet content as is."smart"/nullto treat the top of the .many file as the start of the code snippet with all irrelevant parts blanked out so errors in programs report correct line numbers."strip_output"string"no"yes"yes"/trueto strip program output of leading and trailing whitespace."no"/falseto leave program output as is."smart"/nullto strip program output of empty leading and trailing lines.It should be mentioned that the code, argv, and stdin portions of the .many file output are stripped of empty lines
to keep things visually clean regardless of the values of"strip_code","strip_argv", and"strip_stdin".Command FormatThe"command"key of an object in the"languages"or"languages_<os>"array defines the terminal command that is run to execute that language.Placeholders like$fileand$dircan be used in a command to refer to the temporary file RunMany creates
for the code of each program it runs and the directory that file is stored in:PlaceholderPortion of.../dir/file.ext$rawdir.../dir$dir".../dir"$rawfile.../dir/file.ext$file".../dir/file.ext"$rawbranch.../dir/file$branch".../dir/file"$namefile.ext$stemfile$ext.ext$sep/(OS specific)$argvn/a - the argv is inserted here$coden/a - the raw snippet contentNote that some placeholders are "quoted" and some are not.
Some operating systems like Windows may have spaces in the path to temporary files so correct quoting is important.If$is not present anywhere in the command string,$file $argvis appended to it.
For example, the commandpythonis implicitlypython $file $argv.Check the"supplied_languages"array indefault_settings.jsonfor more examples of commands.AboutI was driven to make RunMany by my desire to learn more programming languages,combined with my annoyance that whenever
I tried I would invariably have to make a whole new project for that language, or even switch IDEs.I plan to use it to practice solving code challenges in multiple languages from sites likeProject Euler.Check out some of my other Python packages.