programing

Python 하위 프로세스에서 예외 출력을 가져오는 방법.check_output()?

testmans 2023. 5. 15. 21:23
반응형

Python 하위 프로세스에서 예외 출력을 가져오는 방법.check_output()?

저는 파이썬 내에서 비트코인 결제를 하려고 합니다.bash에서 저는 보통 다음과 같이 합니다.

bitcoin sendtoaddress <bitcoin address> <amount>

예를 들어 다음과 같습니다.

bitcoin sendtoaddress 1HoCUcbK9RbVnuaGQwiyaJGGAG6xrTPC9y 1.4214

성공하면 트랜잭션 ID가 출력으로 표시되지만 비트코인 잔액보다 큰 금액을 전송하려고 하면 다음과 같은 출력이 표시됩니다.

error: {"code":-4,"message":"Insufficient funds"}

제 파이썬 프로그램에서 저는 이제 다음과 같이 결제를 시도합니다.

import subprocess

try:
    output = subprocess.check_output(['bitcoin', 'sendtoaddress', address, str(amount)])
except:
    print "Unexpected error:", sys.exc_info()

잘 균형이 잘 합니다.sys.exc_info()다음을 출력:

(<class 'subprocess.CalledProcessError'>, CalledProcessError(), <traceback object at 0x7f339599ac68>)

명령줄에서 발생하는 오류는 포함되어 있지 않습니다.의 질문은 를 얻을 수 하는 것입니다.{"code":-4,"message":"Insufficient funds"}파이썬 내서에?

문서에 따르면 오류 시 발생한 예외에는 오류 세부 정보에 액세스하는 데 사용할 수 있는 속성이 있습니다.

try:
    subprocess.check_output(...)
except subprocess.CalledProcessError as e:
    print(e.output)

다음 이을 분석하고 을 "" "" "" "" "" "" ""로 구문 할 수 .json모듈:

if e.output.startswith('error: {'):
    error = json.loads(e.output[7:]) # Skip "error: "
    print(error['code'])
    print(error['message'])

stderr에 오류 텍스트가 보고되는 경우는 승인된 솔루션이 처리하지 않는 것 같습니다.테스트 결과 예외의 출력 특성에 stderr의 결과가 포함되지 않았으며 stderr= 사용에 대한 문서 경고가 표시되었습니다.pipe in check_output().대신, 저는 J에게 한 가지 작은 개선점을 제안하고 싶습니다.Stderr 지원을 추가한 F Sebastian의 솔루션.우리는 결국 오류를 처리하려고 노력하고 있으며 오류가 자주 보고되는 곳이 stderr입니다.

from subprocess import Popen, PIPE

p = Popen(['bitcoin', 'sendtoaddress', ..], stdout=PIPE, stderr=PIPE)
output, error = p.communicate()
if p.returncode != 0: 
   print("bitcoin failed %d %s %s" % (p.returncode, output, error))

@Sebastian이 언급했듯이 기본 솔루션은 다음을 목표로 해야 합니다.run(): https://docs.python.org/3/library/subprocess.html#subprocess.run

다음은 편리한 구현입니다(인쇄문 또는 사용 중인 다른 로깅 기능을 사용하여 로그 클래스를 자유롭게 변경할 수 있습니다).

import subprocess

def _run_command(command):
    log.debug("Command: {}".format(command))
    result = subprocess.run(command, shell=True, capture_output=True)
    if result.stderr:
        raise subprocess.CalledProcessError(
                returncode = result.returncode,
                cmd = result.args,
                stderr = result.stderr
                )
    if result.stdout:
        log.debug("Command Result: {}".format(result.stdout.decode('utf-8')))
    return result

그리고 샘플 사용(코드는 관련이 없지만 이 간단한 구현을 통해 얼마나 읽기 쉽고 오류를 쉽게 처리할 수 있는지 보여주는 예라고 생각합니다.):

try:
    # Unlock PIN Card
    _run_command(
        "sudo qmicli --device=/dev/cdc-wdm0 -p --uim-verify-pin=PIN1,{}"
        .format(pin)
    )

except subprocess.CalledProcessError as error:
    if "couldn't verify PIN" in error.stderr.decode("utf-8"):
        log.error(
                "SIM card could not be unlocked. "
                "Either the PIN is wrong or the card is not properly connected. "
                "Resetting module..."
                )
        _reset_4g_hat()
        return

"내 비트코인 잔액보다 큰 금액을 송금"하려고 시도하는 것은 예상치 못한 오류가 아닙니다.사용할 수 있습니다.Popen.communicate()대에직접 대신에 check_output()불필요하게 예외를 발생시키지 않으려면:

from subprocess import Popen, PIPE

p = Popen(['bitcoin', 'sendtoaddress', ..], stdout=PIPE)
output = p.communicate()[0]
if p.returncode != 0: 
   print("bitcoin failed %d %s" % (p.returncode, output))

Python 3.5부터는check인수:

체크가 참이고 프로세스가 0이 아닌 종료 코드로 종료되면 CalledProcessError 예외가 발생합니다.해당 예외의 속성은 인수, 종료 코드 및 stdout 및 stderr(캡처된 경우)를 보유합니다.

올리고 인쇄할 수 있는 간단한 예CalledProcessError:

import subprocess
try:
    subprocess.run("exit 1", shell=True, check=True, timeout=15, capture_output=True)
except subprocess.CalledProcessError as e:
    print(e)  # Output: Command 'exit 1' returned non-zero exit status 1.

이것은 저에게 효과가 있었습니다.하위 프로세스의 모든 stdout 출력을 캡처합니다(파이썬 3.8의 경우).

from subprocess import check_output, STDOUT
cmd = "Your Command goes here"
try:
    cmd_stdout = check_output(cmd, stderr=STDOUT, shell=True).decode()
except Exception as e:
    print(e.output.decode()) # print out the stdout messages up to the exception
    print(e) # To print out the exception message

여기에는 좋은 답변이 있지만, 이러한 답변에는 예외의 기본 동작인 스택 추적 출력의 텍스트가 나오는 답변이 없습니다.

포맷된 추적 정보를 사용하려는 경우 다음을 수행할 수 있습니다.

import traceback

try:
    check_call( args )
except CalledProcessError:
    tb = traceback.format_exc()
    tb = tb.replace(passwd, "******")
    print(tb)
    exit(1)

위의 내용은 check_call(args)에 비밀번호가 있을 경우 표시되지 않도록 하는 데 유용합니다.

@macetw의 답변을 바탕으로 예외 사항을 장식가의 stderr에 직접 인쇄합니다.

파이썬 3

from functools import wraps
from sys import stderr
from traceback import format_exc
from typing import Callable, Collection, Any, Mapping


def force_error_output(func: Callable):
    @wraps(func)
    def forced_error_output(*args: Collection[Any], **kwargs: Mapping[str, Any]):
        nonlocal func

        try:
            func(*args, **kwargs)
        except Exception as exception:
            stderr.write(format_exc())
            stderr.write("\n")
            stderr.flush()

            raise exception

    return forced_error_output

파이썬 2

from functools import wraps
from sys import stderr
from traceback import format_exc


def force_error_output(func):
    @wraps(func)
    def forced_error_output(*args, **kwargs):
        try:
            func(*args, **kwargs)
        except Exception as exception:
            stderr.write(format_exc())
            stderr.write("\n")
            stderr.flush()

            raise exception

    return forced_error_output

그러면 당신의 직원은 장식기를 사용하세요.

@force_error_output
def da_worker(arg1: int, arg2: str):
    pass

이전 답변의 대부분이 정답이라고 생각합니다. Windows 서버에서 이 작업을 수행해야 했고 명령어는 Powershell(Powershell)이었습니다. 이 작업은 저에게 매우 효과적이었습니다.

    try:
        
    
        print("inpgoress")           

        cmd_exec="Get-Date"
        print(cmd_aws)

        subprocess.run(['powershell', '-Command', cmd_exec],shell=False,check=True,capture_output=True,text=True,encoding="utf-8")

        

    except Exception as e:
        print(e)
        print("ERROR: something went wrong executing powershell command")
        raise e  

호출된 하위 프로세스는 호출된 프로그램의 출력을 캡처하고 예외를 발생시키도록 지시해야 합니다.그것을 하는 것은 간단합니다.

첫째, 사용

subprocess.run() instead of subprocess.call()

"Vijay.py "이라는 파이썬 스크립트를 원한다고 가정해 보겠습니다.예외를 제기하려면 다음을 사용합니다.

subprocess.run("py vijay.py", check=True, capture_output=True, shell=True)

그런 다음 위의 방법을 시도 및 제외 블록에 입력하여 오류를 즉시 발생시키거나 sys.exit(1)을 사용할 수 있습니다. 0이 아닌 종료도 괜찮습니다.

try:
    subprocess.call("py vijay.py", check=True, capture_output=True, shell=True)
except Exception as e:
    print("Exception raised: ", e)

및 의 본체vijay.py다음과 같을 수 있습니다.

vijay.py

try:
    Your code is here...
except Exception as e:
    sys.exit(1) // or can even use raise Exception("ur own exception to raise:)
enter code here

언급URL : https://stackoverflow.com/questions/24849998/how-to-catch-exception-output-from-python-subprocess-check-output

반응형