Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Unable to see os.environ['COLUMNS']

220 views
Skip to first unread message

Tim Chase

unread,
Sep 13, 2008, 1:09:56 PM9/13/08
to pytho...@python.org
Not sure what's going on here and hoping for some insight:

tim@rubbish:~$ echo $COLUMNS
129
tim@rubbish:~$ python2.5
Python 2.5.2 (r252:60911, May 28 2008, 08:35:32)
[GCC 4.2.4 (Debian 4.2.4-1)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> import os
>>> os.environ.get('COLUMNS')
>>> 'COLUMNS' in os.environ
False

I can coerce it by using

tim@rubbish:~$ COLUMNS=$COLUMNS python2.5
Python 2.5.2 (r252:60911, May 28 2008, 08:35:32)
[GCC 4.2.4 (Debian 4.2.4-1)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> import os
>>> 'COLUMNS' in os.environ
True

However, this seems hokey to me.

FWIW, this is in Bash on Debian.

What's the best way to read what seems to be a pseudo-environment
variable?

-tkc


Grant Edwards

unread,
Sep 15, 2008, 1:02:35 AM9/15/08
to
On 2008-09-13, Tim Chase <pytho...@tim.thechases.com> wrote:
> Not sure what's going on here and hoping for some insight:
>
> tim@rubbish:~$ echo $COLUMNS
> 129
> tim@rubbish:~$ python2.5
> Python 2.5.2 (r252:60911, May 28 2008, 08:35:32)
> [GCC 4.2.4 (Debian 4.2.4-1)] on linux2
> Type "help", "copyright", "credits" or "license" for more
> information.
> >>> import os
> >>> os.environ.get('COLUMNS')
> >>> 'COLUMNS' in os.environ
> False
>
> I can coerce it by using
>
> tim@rubbish:~$ COLUMNS=$COLUMNS python2.5
> Python 2.5.2 (r252:60911, May 28 2008, 08:35:32)
> [GCC 4.2.4 (Debian 4.2.4-1)] on linux2
> Type "help", "copyright", "credits" or "license" for more
> information.
> >>> import os
> >>> 'COLUMNS' in os.environ
> True
>
> However, this seems hokey to me.
>
> FWIW, this is in Bash on Debian.

In bash (and other descendants of the Bourne shell), there are
two types of environment variables: 1) local variables that are
not passed on to child processes and 2) exported variables that
_are_ passed on to children.

By default, when a variable is created it is local and will not
be inherited by sub-processes.

> What's the best way to read what seems to be a
> pseudo-environment variable?

You can't. You need to export the variable in the parent shell
before it exec's the child:

$ echo $COLUMNS
80

$ python -c "import os; print os.environ['COLUMNS']"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python2.5/UserDict.py", line 22, in __getitem__
raise KeyError(key)
KeyError: 'COLUMNS'

$ export COLUMNS

$ python -c "import os; print os.environ['COLUMNS']"
80


Now, on to the question you're about to ask:

Q: How do I find out how big my terminal is from a Python
program?

A: You use the TIOCGWINSZ ioctl call on the terminal's file
descriptor:

>>> import sys,fcntl,termios,struct
>>> data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
>>> struct.unpack('hh',data)
(24, 80)

There's a more detailed explanation here (including an
explanation of what the third parameter to ioctl() does, and
how you detect changes in the window size):

http://mail.python.org/pipermail/python-list/2006-February/365710.html

There's also chance that you'd be better off just using ncurses or
newt for screen management, but that's another post.

--
Grant


Tim Chase

unread,
Sep 15, 2008, 6:52:16 AM9/15/08
to Grant Edwards, pytho...@python.org
>> What's the best way to read what seems to be a
>> pseudo-environment variable?
>
> You can't. You need to export the variable in the parent shell
> before it exec's the child:
>
> $ export COLUMNS
>
> $ python -c "import os; print os.environ['COLUMNS']"
> 80

This works well, and also manages to keep up to date across runs
as window-size changes. More importantly, it makes sense (minus
the "why doesn't bash automatically export COLUMNS to subshells"
question, but a little investigation shows I can use "set -a" or
"export COLUMNS" in my .bashrc and everything works).

> Now, on to the question you're about to ask:
>
> Q: How do I find out how big my terminal is from a Python
> program?

You must be one of the folks working with the Python
time-machine. :) (okay, so the intent of my question was pretty
obvious)

> A: You use the TIOCGWINSZ ioctl call on the terminal's file
> descriptor:
>
>>>> import sys,fcntl,termios,struct
>>>> data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
>>>> struct.unpack('hh',data)
> (24, 80)
>
> There's a more detailed explanation here (including an
> explanation of what the third parameter to ioctl() does, and
> how you detect changes in the window size):
>
> http://mail.python.org/pipermail/python-list/2006-February/365710.html

Thanks, I'll read up on that, as well as investigate ncurses options.

> There's also chance that you'd be better off just using ncurses or
> newt for screen management, but that's another post.

The screen-width is merely for a little output formatting to
determine how many items can fit across. However, given the
opacity of the ioctl() call, it might not hurt to look into using
curses.

Thanks for the pointers,

-tkc

Thomas Bellman

unread,
Sep 15, 2008, 10:28:34 AM9/15/08
to
Tim Chase <pytho...@tim.thechases.com> writes:

>> $ export COLUMNS
>>
>> $ python -c "import os; print os.environ['COLUMNS']"
>> 80

> This works well, and also manages to keep up to date across runs
> as window-size changes.

Now try this:

$ export COLUMNS
$ python -c "import time, os; time.sleep(60); print os.environ['COLUMNS']"

and change the window width during that sleep.


--
Thomas Bellman, Lysator Computer Club, Linköping University, Sweden
"Don't tell me I'm burning the candle at both ! bellman @ lysator.liu.se
ends -- tell me where to get more wax!!" ! Make Love -- Nicht Wahr!

Tim Chase

unread,
Sep 15, 2008, 2:26:06 PM9/15/08
to Thomas Bellman, pytho...@python.org
Thomas Bellman wrote:
> Tim Chase <pytho...@tim.thechases.com> writes:
>
>>> $ export COLUMNS
>>>
>>> $ python -c "import os; print os.environ['COLUMNS']"
>>> 80
>
>> This works well, and also manages to keep up to date across runs
>> as window-size changes.
>
> Now try this:
>
> $ export COLUMNS
> $ python -c "import time, os; time.sleep(60); print os.environ['COLUMNS']"
>
> and change the window width during that sleep.

Yes, I did try something similar in my experimenting:

$ export COLUMNS
$ python

>>> import os
>>> print os.environ['COLUMNS']
80

>>> # resize to some other width
>>> print os.environ['COLUMNS']
80

However, for my particular use-case, it's merely for output
formatting of a short-running process (akin to "svn status"
output). If you resize it in the middle of the sub-second
operation, you deserve what you get :)

It is disappointing that something so cross-platform as "what's
my output width" isn't built-in, requiring jumping through hoops,
in ways that aren't cross-platform. The ioctl() method worked on
my *nix-like boxes, as did the ncurses versions. However on
Win32, neither worked:

C:\Temp>python
Python 2.4.3 (#69, Mar 29 2006, 17:35:34)
[MSC v.1310 32 bit (Intel)] on win32


Type "help", "copyright", "credits" or "license"
for more information.

>>> # try the Curses version:
...
>>> import curses


Traceback (most recent call last):

File "<stdin>", line 1, in ?
File "c:\Program Files\Python24\lib\curses\__init__.py",
line 15, in ?
from _curses import *
ImportError: No module named _curses
>>> # try the ioctl version:
...
>>> import fcntl


Traceback (most recent call last):

File "<stdin>", line 1, in ?
ImportError: No module named fcntl
>>> import termios


Traceback (most recent call last):

File "<stdin>", line 1, in ?
ImportError: No module named termios
>>>

So for cross-platform'ness on Win32, you wander over here:

http://code.activestate.com/recipes/440694/

Abstracting all this mess in a cross-platform sort of way would
be a nice "batteries included" tool to have. Based on the other
thread that Grant directed me to and the comments in the Win32
page, I'm not the first to have hoped for such an built-in.

Fortunately, for now I'm mostly focused on the *nix side of
things and have enough to get it working for now. Thanks to
those who gave their input.

-tkc

0 new messages