Найти - Пользователи
Полная версия: Проверить, есть ли программа в PATH
Начало » Python для новичков » Проверить, есть ли программа в PATH
1 2
_alexs_
Для обработки данных вызываю консольное приложение. Но перед вызовом хотелось бы убедиться, что это приложение присутствует в PATH. Пришел к такому решению
def appInstalled():
  myPath = utils.getPath()
  res = 1
  fnull = open( os.devnull, "w" )
  try:
    res = subprocess.call( myPath, stdout = fnull, stderr = fnull )
  except:
    pass
  finally:
    fnull.close()
  if res == 0:
    return True
  else:
    return False
В Linux такая функция работает отлично, а вот в Windows всегда возвращается False. При этом если в except добавить вывод исключений, то видно, что возникает вот такая ошибка
res = subprocess.call( myPath, stdout = fnull, stderr = fnull )
File “C:\Python27\lib\subprocess.py”, line 493, in call
return Popen(*popenargs, **kwargs).wait()
File “C:\Python27\lib\subprocess.py”, line 672, in __init__
errread, errwrite) = self._get_handles(stdin, stdout, stderr)
File “C:\Python27\lib\subprocess.py”, line 784, in _get_handles
p2cread = self._make_inheritable(p2cread)
File “C:\Python27\lib\subprocess.py”, line 823, in _make_inheritable
_subprocess.DUPLICATE_SAME_ACCESS)
WindowsError:
Что делаю не так, в чем ошибка? Может, есть другие кроссплатформенные способы проверить наличие исполнимого файла в PATH?
fata1ex
https://www.google.ru/?q=DUPLICATE_SAME_ACCESS
odnochlen
Как говорит гугл, попробуй shell=True

Вместо
  if res == 0:
    return True
  else:
    return False

можно написать
return res==0
EBFE
_alexs_
Для обработки данных вызываю консольное приложение. Но перед вызовом хотелось бы убедиться, что это приложение присутствует в PATH
А не проще сразу ловить исключения при вызове?
что нибудь вроде
def call_app(path):
    try:
        subprocess.call(path)
    except Exception, ex:
        logging.error("Exception: {0}, Path: {1}".format(ex, path))
        print_to_user "Application '{app}' does not exists!".format(app = path)   

Ну или действительно проверить:
http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python
_alexs_
odnochlen
Как говорит гугл, попробуй shell=True
Результат тот же. Кроме того, использование shell=True потенциально небезопасно.

Попробовал вместо devnull перенаправлять стандартные потоки в subprocess.PIPE, тоже без особого успеха: после вызова call() все подвисает, запущенная программа висит в памяти.
_alexs_
EBFE
А не проще сразу ловить исключения при вызове?
Было бы проще, если бы не одно но. Предложенный вами код
def call_app(path):
    try:
        subprocess.call(path)
    except Exception, ex:
        logging.error("Exception: {0}, Path: {1}".format(ex, path))
        print_to_user "Application '{app}' does not exists!".format(app = path)   
вызовет консольное окно с обширной встроенной справкой злополучного приложения. И пока пользователь это окно не закроет, кина не будет. Вот чтобы этого окна не было (и ничего не надо было закрывать) и нужны перенаправления потоков ввода-вывода.

Да, тот топик на SE уже читал. Мне кажется, предложенный там вариант с самописным which не самый удобный
reclosedev
Не понял, если нужно просто проверить установлено ли приложение, чем не устраивает проверка на присутствие файла или более продвинутый вариант самодельного which из SO?

Если нужно запустить, перенаправить вывод, и не дожидаясь закрыть процесс, можно попробовать так:
import subprocess
 
def can_execute(*args):
    try:
        process = subprocess.Popen(args, stdout=subprocess.PIPE, 
                                         stderr=subprocess.PIPE)
        process.terminate()
        return True
    except OSError:
        return False
 
print can_execute('ping', '127.0.0.1', '-n', '10')
print can_execute('ping_pong', '127.0.0.1', '-n', '10')

True
False
[Finished in 0.1s]
_alexs_
reclosedev
Не понял, если нужно просто проверить установлено ли приложение, чем не устраивает проверка на присутствие файла
Тем, что для проверки на присутствие файла надо знать полный путь к этому файлу. А так, если программа может с равной вероятностью лежать в /usr/bin, /usr/local/bin/, /opt/sometool/, /opt/sometool/bin, ~/bin или еще где-нибудь, аналогично и на Win (Program Files, C:\tool или что-то еще)
reclosedev
или более продвинутый вариант самодельного which из SO?
Да вобщем-то устраивает. Просто, как мне кажется, вариант с попыткой вызова приложения немного проще и эффективнее

reclosedev
Если нужно запустить, перенаправить вывод, и не дожидаясь закрыть процесс, можно попробовать так:
Увы не работает. Точнее, из консоли Python работает, как и мой вариант из первого поста. А вот когда вызывают в GUI получаю DUPLICATE_SAME_ACCESS

Наверное, все же перепишу с использованием самодельного which
EBFE
_alexs_
А вот когда вызывают в GUI
добавте stdin = fnull
Просто по умолчанию subprocess.call(stdin=None) => stdin вызывающего процесса (“child’s file handles will be inherited from the parent”). А в pythonw stdin,stdout,stderr не привязанны:
from sys import stdin, stdout, stderr
with open('stds.txt','a') as f:
f.write("in %d, out %d, err: %d\n" % (stdin.fileno(),
stdout.fileno(), stderr.fileno()))
-----
python: in 0, out 1, err: 2
pythonw: in -2, out -2, err: -2[code]
py.user.next
>>> import os.path
>>> 
>>> def f(progname):
...     path = os.getenv('PATH')
...     for p in path.split(':'):
...         if os.path.exists(os.path.join(p, progname)):
...             return True
...     return False
... 
>>> f('grep')
True
>>> f('grepa')
False
>>> f('python2.7')
True
>>> f('python2.6')
True
>>> f('python2.5')
False
>>>
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB