Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can expectrl spawn with modified environment variables? #69

Open
Centauria opened this issue Jul 17, 2024 · 4 comments
Open

Can expectrl spawn with modified environment variables? #69

Centauria opened this issue Jul 17, 2024 · 4 comments
Labels
question Further information is requested

Comments

@Centauria
Copy link

Let's say this code

let mut session = expectrl::repl::spawn_python();

I need it find python in somewhere else beyond system PATH,
so I add something like

if let Some(path) = env::var_os("PATH") {
        let mut paths = env::split_paths(&path).collect::<Vec<_>>();
        paths.push(PathBuf::from(r"D:\PF\anaconda3\envs\forecast"));
        paths.push(PathBuf::from(r"C:\Users\centa\.julia\juliaup\julia-1.10.2+0.x64.w64.mingw32\bin"));
        let new_path = env::join_paths(paths).unwrap();
        env::set_var("PATH", &new_path);
    }

before that.

But this won't work.

So is there an approach for doing this?

@zhiburt zhiburt added the question Further information is requested label Jul 17, 2024
@zhiburt
Copy link
Owner

zhiburt commented Jul 17, 2024

Hi @Centauria

Something like this?

use expectrl::{Expect, Regex};

fn main() {
    let path_to_python_bin = "/usr/bin/python";

    let mut p = expectrl::spawn(path_to_python_bin).unwrap();
    p.expect(Regex("\n")).unwrap(); // skip python prompt

    p.send_line("print('Does it work?')").unwrap();

    let mut buf = String::new();
    p.read_line(&mut buf).unwrap();

    assert_eq!(buf, ">>> Does it work?\r\n");
}

Or like this

fn main() {
    let path_to_python_bin = "/usr/bin/python";

    let p = expectrl::spawn(path_to_python_bin).unwrap();
    let mut p = expectrl::repl::ReplSession::new(p, ">>> ");
    p.set_quit_command("quit()");
    p.expect_prompt().unwrap();

    p.send_line("print('Does it work?')").unwrap();

    let mut buf = String::new();
    p.read_line(&mut buf).unwrap();

    assert_eq!(buf, "Does it work?\r\n");
}

@Centauria
Copy link
Author

Thank you for the fast reply.
I tried your approach and it worked.
That's to say, I can only specify path to python executable, then spawn it.

But what should I do if I need the spawned python recognize some specific environment variables, such as "PYTHONPATH", for further usage?

@zhiburt
Copy link
Owner

zhiburt commented Jul 18, 2024

Well the example you've provided
Must work, doesn't it?

use std::env;
use std::path::PathBuf;

fn main() {
    set_env("SOMEWHERE_NEW");

    let p = expectrl::spawn("python").unwrap();
    let mut p = expectrl::repl::ReplSession::new(p, ">>> ");
    p.set_quit_command("quit()");
    p.expect_prompt().unwrap();

    let output = p.execute("import os; print(os.environ.get('PATH'))").unwrap();

    println!("{}", String::from_utf8_lossy(&output));
}

fn set_env(p: &str) {
    if let Some(path) = env::var_os("PATH") {
        let mut paths = env::split_paths(&path).collect::<Vec<_>>();
        paths.push(PathBuf::from(p));
        let new_path = env::join_paths(paths).unwrap();
        env::set_var("PATH", new_path);
    }
}

You could also use std::process::Command for it.

use std::process::Command;

use expectrl::Session;

fn main() {
    let mut cmd = Command::new("python");
    cmd.env("SOME_NEW_ENV", "NEW VALUE");

    let p = Session::spawn(cmd).unwrap();
    let mut p = expectrl::repl::ReplSession::new(p, ">>> ");
    p.set_quit_command("quit()");
    p.expect_prompt().unwrap();

    let output = p
        .execute("import os; print(os.environ.get('SOME_NEW_ENV'))")
        .unwrap();

    println!("{}", String::from_utf8_lossy(&output));
}

@Centauria
Copy link
Author

The first code snippet do not work.
Even though it changes the "PATH" variable in the code, e.g. env::var_os("PATH") changes, expectrl::spawn("python") still cannot find python in the "PATH".

The second code snippet do not work.

I changed it like below:

use std::process::Command;

use expectrl::repl::ReplSession;
use expectrl::Session;

fn main() {
    let mut cmd = Command::new(r"D:\path\to\anaconda3\python.exe");
    cmd.env("SOME_NEW_ENV", "NEW VALUE");

    let p = Session::spawn(cmd).unwrap();
    let mut p = ReplSession::new(
        p,
        ">>> ".to_owned(),
        Some("import sys; sys.exit()".to_owned()),
        false,
    );
    p.expect_prompt().unwrap();

    let output = p
        .execute("import os; print(os.environ.get('SOME_NEW_ENV'))")
        .unwrap();

    println!("{}", String::from_utf8_lossy(&output));
}

this code do not work on Windows.

thread 'main' panicked at src/main.rs:17:23:
called `Result::unwrap()` on an `Err` value: ExpectTimeout
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\exptest.exe` (exit code: 101)

I changed ">>> " to ">>>", then it can run on Windows. But the result is different between different Windows version.

On Windows 10, 19045.4651, it prints a blank line


on Windows 11, 22631.3880, it prints

 import os; print(os.environ.get('SOME_NEW_ENV'))
NEW VALUE

rustup show result

Default host: x86_64-pc-windows-msvc
rustup home:  D:\PF\Rust\Rustup

stable-x86_64-pc-windows-msvc (default)
rustc 1.79.0 (129f3b996 2024-06-10)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants