I am building an Electron
app (running an Angular application) which acts as the User Interface for a python
program underneath.
The python
program uses anaconda
for package management (I am using miniconda
for development).
When the app boots up, it checks whether the required conda
environment exists, and if not, creates it.
The following code is part of a Service
which is responsible for managing the python
program.
public doEnvironmentSetup() {
let stdOutSub = new Subject<string>();
let stdErrSub = new Subject<string>();
let completeSubject = new Subject<string>();
this.runningSetup = true;
const TEMP_ENV_FILE = join(tmpdir(), "env.yml");
return Promise.resolve()
.then(() => {
// Copy packaged environment.yml to TEMP_ENV_FILE
})
.then(() => this.electron.getApplicationStoragePath())
.then((stor) => {
setTimeout(() => {
let runProcess = this.electron.childProcess.spawn("conda", ["env", "create", "--file", TEMP_ENV_FILE, "--name", CONDA_ENV_NAME], {
cwd: stor
});
const stdOutReaderInterface = createInterface(runProcess.stdout);
const stdErrReaderInterface = createInterface(runProcess.stderr);
stdOutReaderInterface.on('line', (line) => {
stdOutSub.next(line);
});
stdErrReaderInterface.on('line', (line) => {
stdErrSub.next(line);
});
runProcess.on('close', (code: number) => {
this.electron.fs.unlinkSync(TEMP_ENV_FILE);
this.runningSetup = false;
completeSubject.next("");
});
}, 2000);
return {
stdOut: stdOutSub,
stdErr: stdErrSub,
onComplete: completeSubject
};
});
}
Now, when I need to run the actual python
code, the piece of code which runs is (not giving the whole thing, since it is too long for our purpose here) :
execCmd.push(
`conda init ${this.electron.os.platform() === "win32" ? "powershell" : "bash"}`,
`conda activate ${CONDA_ENV_NAME}`,
// long python spawn command
`conda deactivate`,
)
setTimeout(() => {
logLineSubject.next({ out: "--- Setting up Execution Environment ---", err: "" });
logLineSubject.next({ out: `Running in ${dir}`, err: "" });
const cmd = execCmd.join(" && ");
let runProcess = this.electron.childProcess.spawn(cmd, {
detached: false,
windowsHide: true,
cwd: cwd,
shell: this.getShell()
});
const stdOutInterface = createInterface(runProcess.stdout);
const stdErrInterface = createInterface(runProcess.stderr);
stdOutInterface.on('line', (line) => {
// get this line back to the component
});
stdErrInterface.on('line', (line) => {
// get this line back to the component
});
runProcess.on("error", (err) => {
// get this back to the component
});
runProcess.on('close', (code: number) => {
// get this line back to the component
});
}, 1000);
where getShell
is defined as:
private getShell() {
return process.env[this.electron.os.platform() === "win32" ? "COMSPEC" : "SHELL"];
}
However, whenever I try to run this, it comes back with:
CommandNotFoundError: Your shell has not been properly configured to use 'conda activate'.
To initialize your shell, run
$ conda init <SHELL_NAME>
blah blah blah ...
When I try with source activate ${CONDA_ENV_NAME}
, it comes back with:
/bin/bash: activate: No such file or directory
Not really sure what I am doing wrong here. Can somebody please point me in the right direction?
PS: It works with source $(conda info --root)/etc/profile.d/conda.sh
, but I can't really use it since I need to support Windows as well!
Disclaimer: I am new to python
/anaconda
.