Python Forum
shutils.get_terminal_size()
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
shutils.get_terminal_size()
#1
a while back someone suggested using shutil.get_terminal_size() instead of doing syscalls to get the terminal size info. my objection at the time was that it didn't work on all versions. what i ended up coding was using it under try: and doing the syscalls under except:.

but i just recently saw that shutil.get_terminal_size() uses environment variables. this is wrong since the terminal size can change. despite it actually getting the correct answer when the size changes, because it is documented to get the size from environment variables, i do not want the risk that some day in the future it might be made to conform to documentation. and i just can't trust os.get_terminal_size(), either. so i'm switching back to the syscall way. if they fix the documentation, then i can use those modules to get the terminal size.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#2
I have an oooold python 2 function in my own recipes. I don't know if it still works
def get_terminal_size(subprocess=False):
    import os
    if os.name == "posix": # linux
        if subprocess:
            # other possible commands: tput cols 
            rows, cols = [ int(x) for x in
                        os.popen("stty size").readline().strip().split()]
        else:
        # http://bytes.com/topic/python/answers/607757-getting-terminal-display-size
        # You may also want to handle the WINCH signal so that you know
        # when the window size has been changed.
            import termios, fcntl, struct, sys
            s = struct.pack("HHHH", 0, 0, 0, 0)
            x = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s)
            rows, cols, x_pixels, y_pixels = struct.unpack("HHHH", x)
        return cols, rows
    else: # windows
        # from http://rosettacode.org/wiki/Terminal_control/Dimensions#Python
        from ctypes import windll, create_string_buffer
        h = windll.kernel32.GetStdHandle(-12)
        csbi = create_string_buffer(22)
        res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
        #return default size if actual size can't be determined
        if not res:
            return 80, 25 
        import struct
        (bufx, bufy, curx, cury, wattr, left, top, right, bottom,
                            maxx, maxy)= struct.unpack("hhhhHhhhhhh", csbi.raw)
        width = right - left + 1
        height = bottom - top + 1
        return width, height
Reply
#3
"COLUMNS" and "LINES" are available as environment variables, but they aren't environment variables. They're just available through that interface, and different shells handle them differently. But because they aren't really environment variables, they are actually accurate (or should be). There's pretty good discussion of this on Stack Overflow: https://unix.stackexchange.com/questions...inal-width

If you want to take some sort of action on resize, you could watch for the SIGWINCH signal (...though Windows doesn't use it) which is sent whenever a terminal resizes.

I just tried shutil's method, on Windows, and it seems to work fine.
>>> import shutil
>>> shutil.get_terminal_size()
os.terminal_size(columns=120, lines=30)
>>> shutil.get_terminal_size()
os.terminal_size(columns=174, lines=30)
If there's some reason that it isn't giving accurate numbers when you resize, I'd suggest bringing it up on the issue tracker of github so the bug can be fixed.

For reference, here's shutil's method: https://github.com/python/cpython/blob/m...l.py#L1233
Reply
#4
Instead of reading documentation or something else, try it. I just did it and here is what I got:

>>> import shutil
>>> shutil.get_terminal_size() # not resized terminal window
os.terminal_size(columns=80, lines=24)
>>> shutil.get_terminal_size() # using the mouse  
os.terminal_size(columns=129, lines=39)
>>> shutil.get_terminal_size() # maximized window
os.terminal_size(columns=211, lines=59)
>>> shutil.get_terminal_size() # F11 - full screen
os.terminal_size(columns=211, lines=62)
>>> 
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#5
i wasn't testing what i get from os.environ['COLUMNS'] because i didn't know they were specially modified. thanks for insight. i will recode it and test the variables within oython.

trying things to see how they behave is not a good way to depend on it being right. it might be wrong yet you want that wrong behavior. your test looked good. later it all breaks when they fix it (making it match documentation).
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#6
Well, writing a software is not "write it once an forget" process. Especially when you depend on 3rd party library.
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#7
(Nov-29-2018, 01:32 AM)Skaperen Wrote: later it all breaks when they fix it (making it match documentation).
I don't understand. The documentation currently says that it checks environment variables. So the current behavior does, already, 100% match the documentation.
https://docs.python.org/3/library/shutil...minal_size Wrote:shutil.get_terminal_size(fallback=(columns, lines))

Get the size of the terminal window.

For each of the two dimensions, the environment variable, COLUMNS and LINES respectively, is checked. If the variable is defined and the value is a positive integer, it is used.
Reply
#8
maintenance is a cost factor just as the original coding is. ultimately the best software used in a business finds the right balance to minimize the total cost. just ignoring the cost factor of maintenance lets it easily run up the cost. even as an individual who maintains his own software letting maintenance go as it will, ends up taking away more of my time that i'd rather spend being creative. this means using best practices in the design like adherence to standards. understanding how the system around your program works is all part of making it work well. just accepting more maintenance because you know there will be some is a terrible idea.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#9
Just google for it how many terminal emulators does exits. Count how many shells (sh, bash, csh, zsh, ...) we do have. And count all distributions.

Then you can calculate the possible combinations of everything:
terminals * shells * distros = many different standards

I guess it's nearly impossible to do it right, because there is no clear strict definition of only one standard.
We have many standards and the libraries have to handle this correct.

So every time, when your problem was solved by another programmer, you should give him a hug.
Ok, you can stop :-D
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#10
(Dec-04-2018, 12:33 PM)DeaD_EyE Wrote: Just google for it how many terminal emulators does exits. Count how many shells (sh, bash, csh, zsh, ...) we do have. And count all distributions.

Then you can calculate the possible combinations of everything:
terminals * shells * distros = many different standards

I guess it's nearly impossible to do it right, because there is no clear strict definition of only one standard.
We have many standards and the libraries have to handle this correct.

So every time, when your problem was solved by another programmer, you should give him a hug.
Ok, you can stop :-D

then no code should depend on anything besides the controlling tty attributes. so i guess i need to revise my code, yet, again, to do this based only on the controlling tty attributes, which is how i did it when i first coded it.

the screen command has a means to start a detached screen session. but you have very little control over the screen size of that session. i have implemented, in Python, a means to create a detached screen session of the specific size you want (up to the implementation maximum, which appears to be 1023x1023 in amd64 Linux). it is likely doable in almost any language that can call the system exec* syscalls. i used the stty command to perform the actual setting and a bit of juggling with screen and bash to be sure it recognized that size. setting the terminal size did not set any environment variables. bash does set some as it initializes an interactive shell. my own .bashrc code than sets the other common ones. but i must not assume everyone uses bash, my .bashrc code, or even amd64 Linux. that means using the controlling tty attributes, if there is a controlling tty.

i use detached screen sessions to run long running work in the background. for that i implemented commands to ...

1. create a detached screen session with whatever virtual terminal size is desired (defaulting to what is set, currently).

2. stuff input, with conversion from many escape sequences, into the detached screen session.

3. obtain the current output screen contents and output it to stdout.

4. attach to an existing detached screen session.

that is the current reason i have been examining this issue. but i tend to make functions to do many of the various things i do. i have a collection of over 100 Python functions.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020