Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sublimerepl getenv failing

I'd like to use the SiblimeREPL package with Sublime Text. When I try to start a REPL, I get

SublimeREPL: obtaining sane environment failed in getenv()
Check console and 'getenv_command' setting
WARN: Falling back to SublimeText environment

This happens regardless of which REPL I try to start. (I tried Ruby, Python, and Clojure.) I tried Sublime Text 2 and Sublime Text 3 with the same results. This is on Mac OS X, if that matters.

I looked in the package settings, where I see

"getenv_command": ["/bin/bash", "--login", "-c", "env"],

If I run "/bin/bash --login -c env" at a Terminal prompt, I get my environment listed.

What do I need to change in order to get a successful getenv_command?

like image 721
Kevin Kleinfelter Avatar asked Nov 11 '15 02:11

Kevin Kleinfelter


6 Answers

I had the same problem as ssgam. The problem line for me is in the getenv method. It calls subprocess.check_output(getenv_command), which doesn't exist in python 2.6, which ST2 seems to use.

The trick is, it only calls subprocess.check_output() if getenv_command is truthy, and defaults to os.environ.copy() otherwise. So to get ssgam's fix without modifying the SublimeREPL package, in Preferences > Package Settings > SublimeREPL > Settings - User, do something like this:

{
  "getenv_command": false
}
like image 178
Vectorjohn Avatar answered Nov 18 '22 16:11

Vectorjohn


I investigated this issue a little bit deeper and it seems SublimeText 3 is also affected. In my case the problem is related to bash-completion feature, in particular COMP_WORDBREAKS environment variable.

Use the following command to show the contents of COMP_WORDBREAKS:

$ echo "$COMP_WORDBREAKS"

will output

"'><=;|&(:

You can also use:

$ echo $COMP_WORDBREAKS

but note that with the second command (without quotes), you'll not see that the variable also contains a line feed character.

The problem here is the line feed character which breaks output parsing in getenv_command feature. If you extract part of the source code for SublimeREPL you can get real error message from python interpreter.

Traceback (most recent call last):
  File "main.py", line 71, in getenv
    env = dict(line.split('=', 1)  for line in lines)
ValueError: dictionary update sequence element #6 has length 1; 2 is required

You can match element #6 with the position of COMP_WORDBREAKS in env listing.

Solution (first that came to my mind)

I can't tell at the moment what is real impact on bash-completion feature after following solution is applied and of course SublimeREPL hopefully should be fixed accordingly. Please comment my answer to fill in missing knowledge.

We may want to remove disturbing characters to get rid of the error. First let's identify those characters

$ echo -n "${COMP_WORDBREAKS}" | od -t x1c

will output

0000000  20  09  0a  22  27  3e  3c  3b  7c  26  28  3a
             \t  \n   "   '   >   <   ;   |   &   (   :
0000014

so we have three to remove. The simplest way is to add to your .bashrc following line:

COMP_WORDBREAKS="${COMP_WORDBREAKS#???}"

Voila! No more error message.

My final thought is about removed characters. I'm not fully in how bash-completion works and I'm aware of that modifying COMP_WORDBREAKS can affect other scripts using it. For now you can always change it ad-hoc.

I hope this helped.

Cheers

like image 23
develucas Avatar answered Nov 18 '22 18:11

develucas


Found it. Fixed it. SublimeREPL assumes that running getenv_command will produce SOLELY the output from running env, and every line will contain an equals sign. But my .bash_profile echos some stuff to stdout.

The solution was to wrap my .bash_profile output in a

if [[ $- == *i* ]] 

to not produce extra output besides the executed command.

like image 23
Kevin Kleinfelter Avatar answered Nov 18 '22 16:11

Kevin Kleinfelter


TLDR;

Replace:

env = dict(line.split('=', 1)  for line in lines)

in ~/.config/sublime-text-3/Packages/SublimeREPL/repls/subprocess_repl.py with

env = dict(line.split('=', 1)  for line in lines if '=' in line)

(Thanks @MichaelOhlrogge for the shorter syntax)


Why this works

@develucas's solution helped me solve my issue. I didn't have the problem he was describing, but his investigation helped.

In my case, the login shell had a greeting. So, bash --login -c env (the command specified in SublimeREPL.sublime-settings file under the getenv_command option) was printing something like this:

Hello, parth!
USER=parth
SHELL=/bin/bash
.
.
.

It turns out that SublimeREPL uses the output of this command to load the environment variables - as mentioned in the comment above the getenv_command setting:

// On POSIX system SublimeText launched from GUI does not inherit
// a proper environment. Often leading to problems with finding interpreters
// or not using the ones affected by changes in ~/.profile / *rc files
// This command is used as a workaround, it's launched before any subprocess
// repl starts and it's output is parsed as an environment
"getenv_command": ["/bin/bash", "--login", "-c", "env"],

The code that parses this output is like this (in the ~/.config/sublime-text-3/Packages/SublimeREPL/repls/subprocess_repl.py file for ST3):

def getenv(self, settings):
    """Tries to get most appropriate environent, on windows
       it's os.environ.copy, but on other system's we'll
       try get values from login shell"""

    getenv_command = settings.get("getenv_command")
    if getenv_command and POSIX:
        try:
            output = subprocess.check_output(getenv_command)
            lines = output.decode("utf-8", errors="replace").splitlines()
            env = dict(line.split('=', 1)  for line in lines)
            return env
        except:
            import traceback
            traceback.print_exc()
            error_message(
                "SublimeREPL: obtaining sane environment failed in getenv()\n"
                "Check console and 'getenv_command' setting \n"
                "WARN: Falling back to SublimeText environment")

    # Fallback to environ.copy() if not on POSIX or sane getenv failed
    return os.environ.copy()

The env = dict(line.split('=', 1) for line in lines) line causes an issue, because the first line in the bash --login -c env output has no =. So I modified this line to ignore the lines that don't have an = sign:

env = dict(line.split('=', 1) for line in lines if '=' in line)

And this solved the issue for me. Don't forget the restart Sublime Text after modifying this file.

like image 21
Parth Thakkar Avatar answered Nov 18 '22 16:11

Parth Thakkar


changing COMP_WORDBREAKS does not work for me ... i'm using ST2, and the exception was thrown at check_output().

also, name completions at the command line fails, after changing COMP_WORDBREAKS.

in my case, i changed subprocess_repl.py's env() method:

[wind]$ diff subprocess_repl.py.20151117.173317 subprocess_repl.py
160c160,161
<         updated_env = env if env else self.getenv(settings)
---
>         # updated_env = env if env else self.getenv(settings)
>         updated_env = env if env else os.environ.copy()
[wind]$

would be interesting to find out why the problem started appearing suddenly ...

hth,cheers,

sam

like image 1
ssgam Avatar answered Nov 18 '22 16:11

ssgam


The answer from @develucas mostly works for me with ST3 with OSX El Capitan except I had to put

export COMP_WORDBREAKS="${COMP_WORDBREAKS#???}"

Note the export. However, if I do this, tab completion no longer works.

like image 1
gniquil Avatar answered Nov 18 '22 17:11

gniquil