Suggestion for a new package: MinimalWorkingExamples.jl

I have an idea for a package and am wondering if anyone feels like implementing it.

MinimalWorkingExamples.jl

A package for Minimal Working Examples (MWE), where by using MinimalWorkingExamples the current REPL session

  1. activates a temporary environment
  2. catches all the using SomePackage
  3. adds them to the environment
  4. and finally runs the example

The idea isn’t to cover all edge cases but to be pretty simple as MWEs are expected to be. This will simply save the extra steps of activating a temporary environment and adding all the dependencies before trying out people’s MWEs. This tool should make it a lot easier for people to try out other people’s MWEs: just copy-paste into the REPL.

Of course, this would mean that people would need to have MinimalWorkingExamples.jl as a dependency in their main environment, and that all MWE code should begin with using MinimalWorkingExamples.

What do you think? Wanna build the next big thing in Julia? :wink:

4 Likes

So this would be used as a boilerplate for a MWE?

The "catches all the using SomePackage" part I don’t get.
Would MinimalWorkingExamples load a jl source file and generate a REPL + environment out of this?

Would this be an user story you think of?
1.) Person A: write your normal MWE
2.) Person A: send jl file to person B
3.) Person B: open repl
4.) Person B: load MinimalWorkingExamples
5.) Person B: load jl file using MinimalWorkingExamples
6.) MinimalWorkingExamples: generate environment
7.) MinimalWorkingExamples: parse jl file for using or import or include
8.) MinimalWorkingExamples: add packages to enivronment
9.) MinimalWorkingExamples: run jl file (+ benchmark, export package versions; julia version, etc)
10.) Person B: modify jl file
11.) Person B: goto 5 if not happy
12.) Person B: Send new jl file and generated statistics / meta info to person A
13.) Person A is now person B
14.) Goto 3

Yes.

No. The main use case would be code you want people to copy (from Discourse, Slack, Zulip, Discord, or anywhere really) and paste in the (existing or fresh) REPL. No files involved, just simple code. For more complicated (and thus perhaps not so minimal MWE) examples, ideally a Project and Manifest files will be involved, but that’s not the intended use of MinimalWorkingExamples.jl.

And to clarify the "catches all the using SomePackage ", I was hoping that some meta-programming magic could do that…

To start julia with a temp env you can run

julia --project=$(mktemp -d) # does not work on windows
julia --eval "using Pkg;Pkg.activate(mktempdir())" # does not enter the REPL

Basically the new package would need to introduce a new REPL mode where packages are auto-installed on entering a using/import command.
1.) Open REPL
2.) Switch to “experiment” mode
2.1) New environment is generated and activated
3.) Enter code
3.1) Code is scanned for using and intercepted to install the packages

Not that it matters too much how that specific step is achieved, but

julia> import Pkg

julia> Pkg.activate(temp = true)
  Activating new environment at `/tmp/jl_Rqkofw/Project.toml`

Or

]
(@v1.6) pkg> activate --temp
  Activating new environment at `/tmp/jl_Z2tBdP/Project.toml`

(jl_Z2tBdP) pkg> 

Well, if that’s the only way. But in the interest of keeping things as simple as possible for the user, it would be great if there was no need to switch to a new REPL mode. To have that work, we would not only need people to have a MinimalWorkingExamples dependency in their main environment, but also import it in every Julia session (in case they want to use the new REPL mode), which seems a bit too much to hope for.

2 Likes

I did not know about the temp switch. :+1:

The problem I see with this is that it would be an extra step in the REPL.
To my knowledge there is no temp switch for the julia binary.

The REPL mode is a bit much maybe, but I don’t see a good way to scanning the code without manually adding macros in the REPL. Maybe a lower level intercept would work, but I don’t have experience with Cassette.jl or similar packages.

I love that switch, it’s so useful.

I stand corrected though: Couldn’t the activation of the REPL mode be elicited by the user using MinimalWorkingExamples? So that would work really well.

Or even something as simple as this:

module MinimalWorkingExamples

import Pkg
Pkg.activate(temp = true)

for command in readlines()
    if startswith(command, ["using", "import"])
        pkgs = split(command)[2:end]
        Pkg.add(pkgs)
    end
    @eval command # I suspect this is wrong, my meta-foo is worthless
end

end
1 Like

One way would be to read in the whole example code at once. I just don’t know how to terminate readlines. Maybe an end of file command, but this seems to require additional knowledge of the user.

The other option would be to check if an input is a valid command. For this parsing the input and checking for errors might work. And if it is OK run it.

Still the problem remains on how to exit the input loop automatically.
If we don’t exit the loop it is almost like a REPL mode :wink:

Maybe print a message like: Please press “CTRL+D” if you finished the example code input.

There are hooks in Julia 1.5+ to transform code run in the repl: document REPL `ast_transforms` · Issue #37047 · JuliaLang/julia · GitHub. So I don’t think you need a separate repl mode.

1 Like

As it is not documented I guess it is not for public use yet.

julia --project=$(mktemp -d)

This does not work on windows.

> julia --project=$(mktemp -d)
mktemp : The term 'mktemp' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:19
+ julia --project=$(mktemp -d)
+                   ~~~~~~
    + CategoryInfo          : ObjectNotFound: (mktemp:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

I mean, there is no real reason to exit that loop, it will just wait for more lines to “eat”. It’s not like the user is going to want to maintain that session open/functional beyond testing that MWE.

How do you end a MWE session? CTRL+C ?

Regarding the possible methods I like the REPL hooks introduces by @ericphanson , but without documentation it seems quite troublesome to get it working.

Oh, I was just assuming the user would close the terminal. Like I said, it’s not like they need to use that specific session for anything. So once they’re done playing around they can just close the terminal. But yea, this is just an implementation detail relevant to the readlines loop, which might not be ideal.

If you want a complete sandbox you should start a new julia process with a new depot (JULIA_DEPOT_PATH), something like:

julia> withenv("JULIA_DEPOT_PATH" => mktempdir()) do
           run(`$(joinpath(Sys.BINDIR, Base.julia_exename())) -q --startup-file=no`)
       end;

or at least a new load path (JULIA_LOAD_PATH ) (and maybe a new project as well, JULIA_PROJECT):

julia> withenv("JULIA_LOAD_PATH" => mktempdir(), "JULIA_PROJECT" => mktempdir()) do
           run(`$(joinpath(Sys.BINDIR, Base.julia_exename())) -q --startup-file=no`)
       end;
2 Likes

Once Pluto’s package management PR lands it might be the easiest way to get a self-contained reproducible environment, although a reactive one which might be a bit different than what some users are accustomed to. I think I saw also some code somewhere for storing Project/Manifests in regular Julia scripts too, but I can’t find it now.

Wow, yea, that would work very well, minus the reactivity. I didn’t check out that PR in detail, but if using Package would add it automatically (ha, I had a similar idea a year ago Add a addusing convenience function · Issue #1812 · JuliaLang/Pkg.jl · GitHub) then that would make this a lot easier.

Yeah, as I understand it you just type using PkgX and it installs it into a local environment that gets copied into the Pluto notebook file itself (and it doesn’t use packages from the global environment), so then the notebook file itself holds all the information about packages and versions etc. (It literally stores the Project.toml and Manifest.toml as a string inside the notebook! But it handles making use of those automatically, so it looks pretty smooth). My info is based on the cool PlutoCon talk on it, Built-In Package Management | Fons van der Plas | PlutoCon 2021 - YouTube.

Ah nice.
TBH, I imagined something a lot simpler (and perhaps less robust) that just alleviates the need to

  1. activate a temp env
  2. add the mentioned packages

The whole point of MWE is that they are as minimal as they can be while still showcasing some point/issue/behavior. So there shouldn’t need to be any compt issues or needs.