kislyuk / argcomplete

Python and tab completion, better together.
https://kislyuk.github.io/argcomplete/
Apache License 2.0
1.39k stars 129 forks source link

Problem with os.get_terminal_size() and argcomplete #476

Closed rabuchaim closed 3 months ago

rabuchaim commented 3 months ago

Hi there!

I rewrote my code twice... the third time (this weekend) I decided to add class by class, and I found the problem. A pretty stupid problem.

If you add the class below in your code with argcomplete, the argcomplete will stop working. This class just draw a line in your terminal. You don't even need to call the class, the code will stop working.

class line:
    middot = "\xb7" * (os.get_terminal_size().columns - 1)
    single = "─" * (os.get_terminal_size().columns - 1)
    double = "═" * (os.get_terminal_size().columns - 1)

If you want to call to see the result:

print(line.middot)

This is the expected result: ····················································································································

The problem is the function os.get_terminal_size().columns. If you change this text by a number like '120', the argcomplete will work without problem. But the terminal size can change, the user can change the window size, this is why to get the current columns size every time I call the class "line".

So my code is like this:

class terminal:
    def __init__(self):
        self.width = os.get_terminal_size().columns - 1
class line:
    middot = "\xb7" * terminal().width
    single = "─" * terminal().width
    double = "═" * terminal().width

If you put a __init__(self) function in this class "line", the argcomplete works with no problems, but I don´t want to call the function line with parentheses (kkkk).

class line:
    def __init__(self):
        self.middot = "\xb7" * os.get_terminal_size().columns
        self.single = "─" * os.get_terminal_size().columns
        self.double = "═" * os.get_terminal_size().columns

print(line().middot)

If you set the environment variable _ARC_DEBUG=1 you will see an error exception <class 'SystemExit'> 2 while parsing args without any useful information. BUT AT THE END YOU WILL SEE THE COMPLETION WORKING!!

word ./argc.py split, lexer state: ' '
In trailing whitespace
LINE: './argc.py '
POINT: 10
PREQUOTE: ''
PREFIX: ''
SUFFIX: ''
WORDS: ['./argc.py']
Active parsers: [MonkeyPatchedIntrospectiveArgumentParser(prog='argc.py', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=False)]
Visited positionals: [MonkeyPatchedIntrospectiveArgumentParser(prog='argc.py', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=False)]
invoking parser with []

exception <class 'SystemExit'> 2 while parsing args
all active parsers: [MonkeyPatchedIntrospectiveArgumentParser(prog='argc.py', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=False)]
active_parser: MonkeyPatchedIntrospectiveArgumentParser(prog='argc.py', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=False)
optional options: ['-c', '-r', '--raw', '-nc', '--no-color']
(.....)
display completions: {'-c': 'Supply a configuration file. (Default: /opt/relogwatch/argc.conf).', '-r': 'Displays output to stdout without colors and with linear summary sections', '--raw': 'Displays output to stdout without colors and with linear summary sections', '-nc': 'Displays output to stdout without colors. Note: the output for syslog is already without colors.', '--no-color': 'Displays output to stdout without colors. Note: the output for syslog is already without colors.', 'block': 'Manage the IP/CIDR list currently blocked.'}

Returning completions: ['--raw', '--no-color', 'block']

If you remove the environment variable, It will stop working.

Why does it happen? I didn't understand... (I gave up and my code is calling the line() function with parentheses)

I appreciate your time reading this, I spent a lot of time to discover this, I think the debug function could show more specific errors.

Thanks

Ricardo Abuchaim - ricardoabuchaim@gmail.com

kislyuk commented 3 months ago

Hello,

When argcomplete runs your program to collect completions, there is no terminal that the program is connected to. So if you run os.get_terminal_size() (which raises OSError in this situation) at startup time, you will have to catch and deal with the error.

You can reproduce this issue more easily by redirecting the output of your program to a file or device: ./argc.py > /dev/null

rabuchaim commented 3 months ago

Thanks!!

I just changed the code and put a try: except and argcomplete is working as I expected!

##──── GET THE TERMINAL WIDTH 
class terminal:
    def __init__(self):
        try:
            self.width = os.get_terminal_size().columns - 1
        except:
            self.width = 120
##──── RETURNS A LINE FILLED WITH A CHAR 
class line:
    middot = "\xb7" * terminal().width
    single = "─" * terminal().width
    double = "═" * terminal().width