0

I am trying to display the final results.txt file via default program. I've tried with bare Popen() without run() and got the same effect. The target file is opening (for me it's the see mode) but after exiting it I receive:

Warning: program returned non-zero exit code #256

Is there any way to ignore it and prevent my program from displaying such warning? I don't care about it because it's the last thing the program does, so I don't want people to waste their time clicking Enter each time...

Code's below:

from subprocess import run, Popen

if filepath[len(filepath)-1] != '/':
   try:
       results = run(Popen(['start', 'results.txt'], shell=True), stdout=None, shell=True, check=False)
   except TypeError:
        pass
else:
   try:
       results = run(Popen(['open', 'results.txt']), stdout=None, check=False)
   except TypeError:
       pass
   except FileNotFoundError:
       try:
           results = run(Popen(['see', 'results.txt']), stdout=None, check=False)
       except TypeError:
           pass
       except FileNotFoundError:
           pass
skelly37
  • 1
  • 3
  • what the - you're passing a `Popen` object to `run`? That's not how you use either of those things. – user2357112 Apr 06 '21 at 07:56
  • I've tried using bare `Popen`, as I've already mentioned in the post. It's the way that someone proposed to me with no success and it doesn't matter since both ways doesn't work. I'd appreciate a solution with either `run` or `Popen`, I'm not picky – skelly37 Apr 06 '21 at 08:01
  • 1
    first of there is `os.system()`, which allows to run cmd commands like so: `os.system('open results.txt')` for example. also You can open files using python, for example: `with open('results.txt') as file:` or if You want to open visually: `os.startfile(r'path\to\file.extension')` and probably other built in methods to do what You want simpler – Matiiss Apr 06 '21 at 08:02
  • `run` takes a command to run, not a `Popen` object (which represents an already-launched process). – user2357112 Apr 06 '21 at 08:04
  • @Matiiss I want to open them visually and your solution does not work smh. os.startfile(filepath + 'results.txt') AttributeError: module 'os' has no attribute 'startfile' – skelly37 Apr 06 '21 at 08:07
  • @skelly37 but if You use os.system You can open them visually, just type in the command You'd type in cmd `os.system('open results.txt')`, also os certainly has startfile since I just ran it, You have to import os first tho – Matiiss Apr 06 '21 at 08:09
  • also do You use windows? because on linux: does this hlep: https://stackoverflow.com/questions/29823028/attributeerror-module-object-has-no-attribute-startfile – Matiiss Apr 06 '21 at 08:14
  • @Matiiss The way with `os.system` helped me and almost solved my problem. But as you can see, I want it to work on Windows, Mac and Linux. How do I handle such output? *sh: 1: open: not found* Basic try/except doesn't work and I have no other ideas... Also I'm on Linux but this should work on all from the "big 3" – skelly37 Apr 06 '21 at 08:20
  • I have no idea how to handle os not depending on machine, since os is machined dependent so the same cmd comand for windows may not work for mac (or linux), also I am pretty sure that try except should work, You just try one os command and then if an error happens, catch it an run the other os command in another try except which executes under the first except and try running there, if it fails again run the other command, also there probably is a library in python that can open files visually like so machine independent but I don't know any – Matiiss Apr 06 '21 at 08:26
  • @Matiiss Okay, I can handle it with os.uname(), problem solved. Thanks – skelly37 Apr 06 '21 at 08:32
  • @skelly37 great! – Matiiss Apr 06 '21 at 08:33
  • @skelly37 by the way I couldn't import uname, although IDE did not suggest any errors, running the code caused an import error so that also may be os limited – Matiiss Apr 06 '21 at 08:45
  • @Matiiss are you on Windows or Mac? If so, please, check whether the `platform.system()` function works. If you're on Linux, tho, I'm really surprised – skelly37 Apr 06 '21 at 08:52
  • @skelly37 I am on Windows, it works, if I print it `print(platform.system())` it outputs ''Windows', – Matiiss Apr 06 '21 at 08:54
  • @Matiiss then I'll use this method. Thanks again! – skelly37 Apr 06 '21 at 08:54
  • @skelly37 also You can probably take a look at os source code since they probably too handle different systems and just try understand how they do it, but if `platform` works then I guess use that – Matiiss Apr 06 '21 at 08:55

2 Answers2

1

Your immediate error is that you are mixing subprocess.run with subprocess.Popen. The correct syntax is

y = subprocess.Popen(['command', 'argument'])

or

x = subprocess.run(['command', 'argument'])

but you are incorrectly combining them into, effectively

x = subprocess.run(subprocess.Popen(['command', 'argument']), shell=True)

where the shell=True is a separate bug in its own right (though it will weirdly work on Windows).

What happens is that Popen runs successfully, but then you try to run run on the result, which of course is not a valid command at all.

You want to prefer subprocess.run() over subprocess.Popen in this scenario; the latter is for hand-wiring your own low-level functionality in scenarios where run doesn't offer enough flexibility (such as when you require the subprocess to run in parallel with your Python program as an independent process).

Your approach seems vaguely flawed for Unix-like systems; you probably want to run xdg-open if it's available, otherwise the value of os.environ["PAGER"] if it's defined, else fall back to less, else try more. Some ancient systems also have a default pager called pg.

You will definitely want to add check=True to actually make sure your command fails properly if the command cannot be found, which is the diametrical opposite of what you appear to be asking. With this keyword parameter, Python checks whether the command worked, and will raise an exception if not. (In its absence, failures will be silently ignored, in general.) You should never catch every possible exception; instead, trap just the one you really know how to handle.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Okay, I'm grateful for the answer but since I've managed with the program without `subprocess` module (as you can see in my own answer) I have one question for you about the paragraph about Unix-like OS. Does that mean that `os.system(see filename)` for Linux and `os.system(open filename)` for MacOS won't suffice or are fine? – skelly37 Apr 06 '21 at 09:06
  • 1
    You're probably fine using [`os.system()`](https://docs.python.org/3/library/os.html#os.system) wherever it seems to work (and could try this on import if you're feeling especially pernicious), but practically, your program will be worse for it and you will likely find you have a better interface with `subprocess`. You'll still need to make changes for other operating systems (`program` vs `program.exe` vs a general non-availability of useful software under Windows). Anecdotally, I would recommend `subprocess.Popen()` with PIPE args and some form of `.communicate(my_input)` over other uses. – ti7 Apr 06 '21 at 09:16
0

Okay, I've achieved my goal with a different approach. I didn't need to handle such exception, I did it without the subprocess module.

Question closed, here's the final code (it looks even better):

from os import system
from platform import system as sysname

if sysname() == 'Windows':
    system('start results.txt')
elif sysname() == 'Linux':
    system('see results.txt')
elif sysname() == 'Darwin':
    system('open results.txt')
else:
    pass
skelly37
  • 1
  • 3