Python return code

Check Python Return Code at C/C++

Usually, the sys.exit() function is used to specify the return value of the Python program.

 

sys.exit([arg])

Exit from Python. This is implemented by raising the SystemExit exception, so cleanup actions specified by finally clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.

The optional argument arg can be an integer giving the exit status (defaulting to zero), or another type of object. If it is an integer, zero is considered “successful termination” and any nonzero value is considered “abnormal termination” by shells and the like. Most systems require it to be in the range 0–127, and produce undefined results otherwise. Some systems have a convention for assigning specific meanings to specific exit codes, but these are generally underdeveloped; Unix programs generally use 2 for command line syntax errors and 1 for all other kind of errors. If another type of object is passed, None is equivalent to passing zero, and any other object is printed to stderr and results in an exit code of 1. In particular, sys.exit("some error message") is a quick way to exit a program when an error occurs.

 

If sys.exit() is used without parameters, it returns the default value of 0 and means that it has ended normally without error. In the event of an error, return a value of 1 to 127. However, this rule is not mandatory. If necessary, a value of 1 to 127 may be returned even if it is not an error.

 

import time
import sys

now = time.time()
print(now)
sys.exit(123)

 <test.py>

 

The following test shows that 123 has been returned.

[root@gcloud-seoul-a093086b769c683771dee9c71e694a73 exit_chk]# python3 test.py
1599283020.377871
[root@gcloud-seoul-a093086b769c683771dee9c71e694a73 exit_chk]# echo $?
123

 However, testing in a C/C++ program causes a little bit of a strange phenomenon:

#include <stdio.h>
#include <stdlib.h> 
#include <stdint.h> 
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <list>
#include <iostream>
#include <string>
using namespace std;

int exec_command2(const char *cmd)
{
    char buffer[1024];
    int ret = -1;

    FILE* pipe = popen(cmd, "r");
    if (pipe){
        try {
            while (!feof(pipe)) {
                if (fgets(buffer, sizeof(buffer), pipe) != NULL)
                   continue;
            }
        } catch (...) {
        } 
        ret = pclose(pipe);
    }
    return ret;
}

int main(int argc, char *argv[])
{
    int ret = exec_command2("python ./test.py");
    printf("ret:%d\n", ret);

    return 0;
}

 

 Let's build the code above and run it.

[root@gcloud-seoul-a093086b769c683771dee9c71e694a73 exit_chk]# g++ test.cpp -o test
[root@gcloud-seoul-a093086b769c683771dee9c71e694a73 exit_chk]# ./test
ret:31488

 At C/C++, Python code has been executed using the popen function and the return value has been received in pclose.
The result was 31488.

This is because the return value was treated as int. The return value of sys.exit is treated as short, which is 2 bytes. Then the lower byte value of the two bytes becomes the return value.

Therefore, the above C/C++ codes should be changed as follows in x86 CPU:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> 
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <list>
#include <iostream>
#include <string>
using namespace std;


int exec_command2(const char *cmd)
{
    char buffer[1024];
    int ret = -1;

    FILE* pipe = popen(cmd, "r");
    if (pipe){
        try {
            while (!feof(pipe)) {
                if (fgets(buffer, sizeof(buffer), pipe) != NULL)
                   continue;
            }
        } catch (...) {
        }  
        ret = pclose(pipe);
    }
    return ret;
}


int main(int argc, char *argv[])
{
    string retstr;

    char val[2];
    int16_t ret = exec_command2("python ./test.py");
    memcpy(val, &ret, 2);

    printf("ret:%d\n", ret);
    printf("ret Hi:%d\n", val[0]);
    printf("ret Low:%d\n", val[1]);

    return 0;
}

 

 Now let's compile and run it again.

[root@gcloud-seoul-a093086b769c683771dee9c71e694a73 exit_chk]# g++ test.cpp -o test
[root@gcloud-seoul-a093086b769c683771dee9c71e694a73 exit_chk]# ./test
ret:31488
ret Hi:0
ret Low:123

 

Check Bash Return Code at Python

Unlike c/c++, Python can process return codes without operation.

#-*- coding: utf-8 -*-
import subprocess, os, sys

def process_test():
        command = './test.sh'
        process = subprocess.Popen(["sh", command],  stdout=subprocess.PIPE)
        output, err = process.communicate()
        exit_code = process.wait()
        print('bash script output:%s'%output.decode('utf-8'))
        if err:
            print('bash script err:%s'%err.decode('utf-8'))
        print('bash script call exit:%d'%exit_code)


process_test()

 <chk.py>

 

Now let's make a simple bash script "test.sh".

#!/bin/bash

ls -al
echo $?

if [ $? -eq 0 ];
then
echo "command return 0 ->success. But I'm going to return 3 for testing"
exit 3
else
echo "command return non 0 ->fail"
exit $?
fi

 

Run the python script.

[root@gcloud-seoul-a093086b769c683771dee9c71e694a73 exit_chk]# python3 chk.py
bash script output:합계 44
drwxr-xr-x  2 root root       120  9  6 22:50 .
drwxr-xr-x 21 root spypiggy  4096  9  5 13:40 ..
-rw-r--r--  1 root root       382  9  5 15:17 check_phone.py
-rw-r--r--  1 root root       484  9  6 22:40 chk.py
-rw-r--r--  1 root root      3021  9  6 18:38 rec_table_update.py
-rwxr-xr-x  1 root root     14240  9  6 22:00 test
-rw-r--r--  1 root root      3023  9  6 22:00 test.cpp
-rw-r--r--  1 root root        79  9  5 14:36 test.py
-rw-r--r--  1 root root       184  9  6 22:50 test.sh
0
command return 0 ->success. But I'm going to return 3 for testing

bash script call exit:3

 In Python, you can see that the return code is handled properly.

Wrapping Up

When processing Python return values at C/C++, do not treat them as int, but instead receive them as two-byte short values and then take only the lower byte values again.
This rule is also valid if the Python code is terminated using an exit() function other than sys.exit().



 

 

 

 

댓글

이 블로그의 인기 게시물

MQTT - C/C++ Client

RabbitMQ - C++ Client #1 : Installing C/C++ Libraries

C/C++ - Everything about time, date