how to detect if input is stdin or not using python click?

82 Views Asked by At

Consider the following code:

import click

@click.command()
@click.argument("file", type=click.File())
def cli(file):
   print(file)

if __name__ == "__main__":
    cli()

Executing as:

$ python ./cmd.py -
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='utf-8'>
$ touch '<stdin>'
$ python ./cmd.py '<stdin>'
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>

There is suprising difference in encoding.

How can I detect if the input was actual - and not anything else in python click?

1

There are 1 best solutions below

4
On BEST ANSWER

'<stdin>' doesn't means filename but special object sys.stdin

And you can compare file == sys.stdin


Every opened file has number which system uses to work with this opened file and sys.stdin also has this number.

Normally

  • sys.stdin.fileno() is 0,
  • sys.stdout.fileno() is 1,
  • sys.sterr.fileno() is 2

So you can compare file.fileno() == 0


sys.stdin is usually also assigned to console/terminal but normal file is not assigned - and you can check it with .isatty()

So you can compare file.isatty() is False

But this is not good method because sometimes sys.stdin is not assigned - ie.

  • when it runs in script without access to terminal - like in cron
  • when it works in pipe like echo "text" | script.py (but it will be it can be assigned when it is first in pipe like script.py | sort

But this method can be useful when you want to draw colored text on screen and send not colored text to file. But this may need to check also sys.stdout.


import click
import sys

@click.command()
@click.argument("file", type=click.File())
def cli(file):
   print('file  :', file)
   print('number:', file.fileno())
   print('  ==  :', file == sys.stdin)
   print('isatty:', file.isatty())
   print('stdin :', sys.stdin.isatty())
   print('stdout:', sys.stdout.isatty())   

if __name__ == "__main__":
    cli()
$ python3 ./cmd.py -

<_io.TextIOWrapper name='<stdin>' mode='r' encoding='utf-8'>
number: 0
 ==   : True
isatty: True
$ python3 ./cmd.py cmd.py

<_io.TextIOWrapper name='cmd.py' mode='r' encoding='UTF-8'>
number: 3
 ==   : False
isatty: False