Is eval $(opam env --switch={switch} --set-switch) equivalent to opam switch set switch?

I need to change opam envs within python due to my applicaiton (no way around this 100%).

Usually I do:

eval $(opam env --switch={switch} --set-switch)

but this gives an issue (see end).

Thus, going to try:

opam switch set {switch}

are these truly equivalent?


For context error:

Traceback (most recent call last):
  File "/lfs/ampere4/0/brando9/iit-term-synthesis/iit-term-synthesis-src/data_pkg/data_gen.py", line 510, in <module>
    main()
  File "/lfs/ampere4/0/brando9/iit-term-synthesis/iit-term-synthesis-src/data_pkg/data_gen.py", line 497, in main
    asyncio.run(create_dataset(path_2_save_new_dataset_all_splits=args.path_to_save_new_dataset,
  File "/dfs/scratch0/brando9/anaconda/envs/iit_synthesis/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/dfs/scratch0/brando9/anaconda/envs/iit_synthesis/lib/python3.9/asyncio/base_events.py", line 647, in run_until_complete
    return future.result()
  File "/lfs/ampere4/0/brando9/iit-term-synthesis/iit-term-synthesis-src/data_pkg/data_gen.py", line 437, in create_dataset
    coq_proj_data: DataCoqProj = await get_coq_proj_data(coq_proj, split)
  File "/lfs/ampere4/0/brando9/iit-term-synthesis/iit-term-synthesis-src/data_pkg/data_gen.py", line 194, in get_coq_proj_data
    path2filenames_raw: list[str] = strace_build_coq_project_and_get_filenames(coq_proj)
  File "/afs/cs.stanford.edu/u/brando9/pycoq/pycoq/opam.py", line 706, in strace_build_coq_project_and_get_filenames
    activate_opam_switch(switch)
  File "/afs/cs.stanford.edu/u/brando9/pycoq/pycoq/opam.py", line 892, in activate_opam_switch
    raise e
  File "/afs/cs.stanford.edu/u/brando9/pycoq/pycoq/opam.py", line 886, in activate_opam_switch
    res = subprocess.run(command.split(), check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  File "/dfs/scratch0/brando9/anaconda/envs/iit_synthesis/lib/python3.9/subprocess.py", line 505, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/dfs/scratch0/brando9/anaconda/envs/iit_synthesis/lib/python3.9/subprocess.py", line 951, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/dfs/scratch0/brando9/anaconda/envs/iit_synthesis/lib/python3.9/subprocess.py", line 1821, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'eval'

I think it has something to do with calling subprocesses from within python don’t fully understand, refs:


I think an alternative would be to get the output of $(…) then run that with subprocess (without bash’s eval I think).

You could easily make an experiment for two approaches:

  1. Change the switch in one tab
  2. Check the switch there (it should be changed)
  3. Open a new terminal tab. Check switch again

One of the commands changes switch globally, another one only for the current environment.

To execute a command in a switch from a python program, prefer opam exec --switch {switch} -- command args - it will exec command args without you having to mess with shell eval etc.

1 Like

I still want to know why opam switch set SWITCH and the eval $(opam env --switch={switch} --set-switch) methods exist and the difference. :slight_smile:

so what do I put as args in my context? @emillon

would args be args := opam env --switch={switch} --set-switch?

this doesn’t work:

def run_eval_opam_env(switch: str,
                      ):
    """
Tries to run through opam exec command arg https://opam.ocaml.org/doc/man/opam-exec.html.
eval $(opam env --switch=switch --set-switch)

    note:
        - command substituion: replace the command ran here $(cmd) with its output (string).
        It turns out, $() is called a command substitution. The command in between $() or backticks (“) is run and the
        output replaces $().
    ref:
        - command sub: https://blog.wplauncher.com/what-is-in-linux/#:~:text=Example%20of%20command%20substitution%20using%20%24()%20in%20Linux%3A&text=Again%2C%20%24()%20is%20a%20command,another%20context%E2%80%9D%20(Source).
        - eval $(opam env): https://stackoverflow.com/questions/30155960/what-is-the-use-of-eval-opam-config-env-or-eval-opam-env-and-their-differen?noredirect=1&lq=1
        - there is a way with opam exec: https://discuss.ocaml.org/t/is-eval-opam-env-switch-switch-set-switch-equivalent-to-opam-switch-set-switch/10957/4
    """
    logging.info(f'{run_eval_opam_env=}')
    # - get cmd sub output
    try:
        cmd_sub_output: str = subprocess.check_output(f'opam env --switch={switch} --set-switch'.split())
    except Exception as e:
        logging.critical(f'Error: {e=}')
        raise e
    # - run command to eval
    # command: str = f'eval {cmd_sub_output}'  # doesn't seem possible https://stackoverflow.com/questions/53950225/python-check-output-call-to-eval-with-arguments-fails
    command: list[str] = f'opam exec --switch {switch}'.split()
    # command: list[str] = command + cmd_sub_output.split()
    command: list[str] = command + [cmd_sub_output]
    logging.info(f"-> {command=}")
    try:
        # res = subprocess.run(command.split(), check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        res = subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        logging.info(f'{res.stdout.decode()=}')
        logging.info(f'{res.stderr.decode()=}')
    except Exception as e:
        logging.critical(f'Error: {e=}')
        raise e

current attempts linux - How does one run `eval $(opam env)` when the command substitution is changes to the environment - all ran from within **python**? - Stack Overflow

These are the arguments you want to pass to your command. Say, if you want to run dune build under a switch named 4.14.0, you’d call opam exec -- --switch 4.14.0 dune build.

In a nutshell: running a command under an opam switch means running a command with certain environment variables set. There are 2 techniques to do that:

  • for non-interactive use (in scripts, etc), wrap the commands you want to run under opam exec --switch switch_name, which will set the environment variables for the underlying command
  • for interactive use (development shells), there’s the opam env command that outputs a bit of shell that needs to be evaluated. That’s why the full command to run in the shell is eval $(opam env). But it that case, which switch should be used? Opam maintains that as a piece of global data that you can change using opam switch set. So opam switch set changes what the following opam env command will return.

For completeness, be aware that there’s a notion of local switches in opam that are stored in specific directories and get priority when computing the “active switch” (either in the shell or in opam exec when --switch is not passed) but it does not seem that you’re using these in your setup.