sampcd_processor.py 23.8 KB
Newer Older
1
# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
2 3 4 5 6 7 8 9 10 11 12 13
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
T
tianshuo78520a 已提交
14 15

import os
16
import sys
T
tianshuo78520a 已提交
17
import subprocess
18 19 20
import multiprocessing
import math
import platform
21 22 23
import inspect
import paddle
import paddle.fluid
Z
zhangchunle 已提交
24
import json
25 26
"""
please make sure to run in the tools path
27
usage: python sample_test.py {arg1} 
28 29 30
arg1: the first arg defined running in gpu version or cpu version

for example, you can run cpu version python2 testing like this:
31 32 33

    python sampcd_processor.py cpu 

34
"""
T
tianshuo78520a 已提交
35 36 37


def find_all(srcstr, substr):
38
    """
39 40 41 42 43 44
    to find all desired substring in the source string
     and return their starting indices as a list

    Args:
        srcstr(str): the parent string
        substr(str): substr
45

46
    Returns:
47
        list: a list of the indices of the substrings
48
              found
49
    """
T
tianshuo78520a 已提交
50 51 52 53 54 55 56 57 58
    indices = []
    gotone = srcstr.find(substr)
    while (gotone != -1):
        indices.append(gotone)
        gotone = srcstr.find(substr, gotone + 1)
    return indices


def check_indent(cdline):
59
    """
60
    to check the indent of a given code line
61

62 63
    to get the number of starting blank chars,
    e.t. blankspaces and \t
64 65

    \t will be interpreted as 4 single blankspaces,
66
    e.t. '\t'='    '
67

68 69 70 71
    Args:
        cdline(str) : a single line of code from the source file

    Returns:
72
        int : the indent of the number of interpreted
73
             blankspaces
74
    """
T
tianshuo78520a 已提交
75 76 77 78 79 80 81 82 83 84 85
    indent = 0
    for c in cdline:
        if c == '\t':
            indent += 4
        elif c == ' ':
            indent += 1
        if c != ' ' and c != '\t':
            break
    return indent


86 87 88
# srccom: raw comments in the source,including ''' and original indent
def sampcd_extract_and_run(srccom, name, htype="def", hname=""):
    """
89 90 91 92 93 94 95 96 97
    Extract and run sample codes from source comment and
    the result will be returned.

    Args:
        srccom(str): the source comment of some API whose
                     example codes will be extracted and run.
        name(str): the name of the API.
        htype(str): the type of hint banners, def/class/method.
        hname(str): the name of the hint  banners , e.t. def hname.
98

99
    Returns:
100
        result: True or False
101 102
    """

103 104
    result = True

105 106
    def sampcd_header_print(name, sampcd, htype, hname):
        """
107
        print hint banner headers.
108

109 110 111 112 113 114
        Args:
            name(str): the name of the API.
            sampcd(str): sample code string
            htype(str): the type of hint banners, def/class/method.
            hname(str): the name of the hint  banners , e.t. def hname.
            flushed.
115 116 117
        """
        print_header(htype, hname)
        print("Sample code ", str(y), " extracted for ", name, "   :")
118
        print(sampcd)
119 120 121
        print("----example code check----\n")
        print("executing sample code .....")
        print("execution result:")
122 123

    sampcd_begins = find_all(srccom, " code-block:: python")
124
    if len(sampcd_begins) == 0:
125
        print_header(htype, hname)
126 127 128 129
        '''
        detect sample codes using >>> to format
        and consider this situation as wrong
        '''
130 131 132
        if srccom.find("Examples:") != -1:
            print("----example code check----\n")
            if srccom.find(">>>") != -1:
T
tianshuo78520a 已提交
133
                print(
134 135
                    "Deprecated sample code style:\n\n    Examples:\n\n        >>>codeline\n        >>>codeline\n\n\n ",
                    "Please use '.. code-block:: python' to ",
T
tianshuo78520a 已提交
136
                    "format sample code.\n")
137
                result = False
T
tianshuo78520a 已提交
138
        else:
139 140
            print("Error: No sample code!\n")
            result = False
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161

    for y in range(1, len(sampcd_begins) + 1):
        sampcd_begin = sampcd_begins[y - 1]
        sampcd = srccom[sampcd_begin + len(" code-block:: python") + 1:]
        sampcd = sampcd.split("\n")
        # remove starting empty lines
        while sampcd[0].replace(' ', '').replace('\t', '') == '':
            sampcd.pop(0)

        # the minimum indent, which is the indent of the first
        # non-empty line
        min_indent = check_indent(sampcd[0])
        sampcd_to_write = []
        for i in range(0, len(sampcd)):
            cdline = sampcd[i]
            # handle empty lines or those only with spaces/tabs
            if cdline.strip() == '':
                continue
            this_indent = check_indent(cdline)
            if this_indent < min_indent:
                break
Z
zhangchunle 已提交
162
            else:
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
                cdline = cdline.replace('\t', '    ')
                sampcd_to_write.append(cdline[min_indent:])

        sampcd = '\n'.join(sampcd_to_write)
        if sys.argv[1] == "cpu":
            sampcd = '\nimport os\n' + 'os.environ["CUDA_VISIBLE_DEVICES"] = ""\n' + sampcd
        if sys.argv[1] == "gpu":
            sampcd = '\nimport os\n' + 'os.environ["CUDA_VISIBLE_DEVICES"] = "0"\n' + sampcd
        sampcd += '\nprint(' + '\"' + name + ' sample code is executed successfully!\")'

        if len(sampcd_begins) > 1:
            tfname = name + "_example_" + str(y) + ".py"
        else:
            tfname = name + "_example" + ".py"
        tempf = open("samplecode_temp/" + tfname, 'w')
        tempf.write(sampcd)
        tempf.close()
        if platform.python_version()[0] == "2":
            cmd = ["python", "samplecode_temp/" + tfname]
        elif platform.python_version()[0] == "3":
            cmd = ["python3", "samplecode_temp/" + tfname]
        else:
            print("Error: fail to parse python version!")
            result = False
            exit(1)

        subprc = subprocess.Popen(
            cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output, error = subprc.communicate()
        msg = "".join(output.decode(encoding='utf-8'))
        err = "".join(error.decode(encoding='utf-8'))

        if subprc.returncode != 0:
            print("\nSample code error found in ", name, ":\n")
            sampcd_header_print(name, sampcd, htype, hname)
            print("subprocess return code: ", str(subprc.returncode))
            print("Error Raised from Sample Code ", name, " :\n")
            print(err)
            print(msg)
            result = False
        # msg is the returned code execution report
        #os.remove("samplecode_temp/" + tfname)
205

206
    return result
T
tianshuo78520a 已提交
207 208 209


def single_defcom_extract(start_from, srcls, is_class_begin=False):
210
    """
211 212
    to extract a def function/class/method comments body

213
    Args:
214 215 216 217 218 219
        start_from(int): the line num of "def" header
        srcls(list): the source file in lines
        is_class_begin(bool): whether the start_from is a beginning a class. \
        For a sole class body itself may end up with its method if it has no
        docstring. But the body of \
        a common def function can only be ended up by a none-indented def/class
220

221 222 223
    Returns:
        string : the extracted comment body, inclusive of its quote marks.

224
    """
225

T
tianshuo78520a 已提交
226
    i = start_from
227 228 229
    fcombody = ""  # def comment body
    comstart = -1  # the starting line index of comment mark "'''" or """"""
    # if it is not -1, it indicates the loop is in the comment body
230 231
    comstyle = 0  # comment mark style ,comments quoted with ''' is coded as 1
    # comments quoted with """ is coded as 2
T
tianshuo78520a 已提交
232 233
    for x in range(i + 1, len(srcls)):
        if is_class_begin:
234
            if srcls[x].replace('\t', '    ').startswith('    def '):
T
tianshuo78520a 已提交
235
                break
236
        if srcls[x].startswith('def ') or srcls[x].startswith('class '):
T
tianshuo78520a 已提交
237 238
            break
        else:
239 240 241 242 243 244 245
            if comstart == -1:
                s = srcls[x].replace(" ", '').replace("\t",
                                                      '').replace("\n", '')
                if s.startswith("\"\"\"") or s.startswith("r\"\"\""):
                    comstart = x
                    comstyle = 2
                    continue
T
tianshuo78520a 已提交
246 247 248 249
            if (comstyle == 2 and comstart != -1 and
                    srcls[x].replace(" ", '').replace("\t", '').replace(
                        "\n", '').startswith("\"\"\"")):
                break
250 251 252 253 254 255 256
            if comstart == -1:
                s = srcls[x].replace(" ", '').replace("\t",
                                                      '').replace("\n", '')
                if s.startswith("\'\'\'") or s.startswith("r\'\'\'"):
                    comstart = x
                    comstyle = 1
                    continue
T
tianshuo78520a 已提交
257 258 259 260 261
            if (comstyle == 1 and comstart != -1 and
                    srcls[x].replace(" ", '').replace("\t", '').replace(
                        "\n", '').startswith("\'\'\'")):
                break
            if (comstart !=
262
                    -1):  # when the comments start, begin to add line to fcombody
T
tianshuo78520a 已提交
263 264 265 266
                fcombody += srcls[x]
    return fcombody


267 268 269
def print_header(htype, name):
    print(htype, " name:", name)
    print("-----------------------")
270

T
tianshuo78520a 已提交
271

272
def srccoms_extract(srcfile, wlist):
273
    """
274 275 276 277 278 279 280 281 282
    Given a source file ``srcfile``, this function will
    extract its API(doc comments) and run sample codes in the
    API.

    Args:
        srcfile(file): the source file
        wlist(list): white list

    Returns:
283
        result: True or False
284
    """
285

286
    process_result = True
T
tianshuo78520a 已提交
287
    srcc = srcfile.read()
288 289
    # 2. get defs and classes header line number
    # set file pointer to its beginning
T
tianshuo78520a 已提交
290
    srcfile.seek(0, 0)
291
    srcls = srcfile.readlines()  # source lines
292

293
    # 1. fetch__all__ list
T
tianshuo78520a 已提交
294
    allidx = srcc.find("__all__")
295 296 297 298 299 300
    srcfile_new = srcfile.name
    srcfile_new = srcfile_new.replace('.py', '')
    srcfile_list = srcfile_new.split('/')
    srcfile_str = ''
    for i in range(4, len(srcfile_list)):
        srcfile_str = srcfile_str + srcfile_list[i] + '.'
301
    if allidx != -1:
T
tianshuo78520a 已提交
302
        alllist = []
303 304
        # get all list for layers/ops.py
        if srcfile.name.find("ops.py") != -1:
T
tianshuo78520a 已提交
305
            for ai in range(0, len(srcls)):
306
                if srcls[ai].startswith("__all__"):
T
tianshuo78520a 已提交
307 308
                    lb = srcls[ai].find('[')
                    rb = srcls[ai].find(']')
309
                    if lb == -1:
T
tianshuo78520a 已提交
310 311 312 313
                        continue
                    allele = srcls[ai][lb + 1:rb].replace("'", '').replace(
                        " ", '').replace("\"", '')
                    alllist.append(allele)
314 315
            if '' in alllist:
                alllist.remove('')
T
tianshuo78520a 已提交
316 317 318 319 320 321 322 323 324 325 326 327
        else:
            alllist_b = allidx + len("__all__")
            allstr = srcc[alllist_b + srcc[alllist_b:].find("[") + 1:alllist_b +
                          srcc[alllist_b:].find("]")]
            allstr = allstr.replace("\n", '').replace(" ", '').replace(
                "'", '').replace("\"", '')
            alllist = allstr.split(',')
            if '' in alllist:
                alllist.remove('')
        api_alllist_count = len(alllist)
        api_count = 0
        handled = []
328 329
        # get src contents in layers/ops.py
        if srcfile.name.find("ops.py") != -1:
T
tianshuo78520a 已提交
330 331 332 333 334 335 336
            for i in range(0, len(srcls)):
                if srcls[i].find("__doc__") != -1:
                    opname = srcls[i][:srcls[i].find("__doc__") - 1]
                    if opname in wlist:
                        continue
                    comstart = i
                    for j in range(i, len(srcls)):
337
                        if srcls[j].find("\"\"\"") != -1:
T
tianshuo78520a 已提交
338 339 340 341
                            comstart = i
                    opcom = ""
                    for j in range(comstart + 1, len(srcls)):
                        opcom += srcls[j]
342
                        if srcls[j].find("\"\"\"") != -1:
T
tianshuo78520a 已提交
343 344
                            break
                    api_count += 1
345
                    handled.append(
346 347 348
                        opname)  # ops.py also has normal formatted functions
                    # use list 'handled'  to mark the functions have been handled here
                    # which will be ignored in the following step
T
tianshuo78520a 已提交
349
        for i in range(0, len(srcls)):
350
            if srcls[i].startswith(
351
                    'def '):  # a function header is detected in line i
T
tianshuo78520a 已提交
352
                f_header = srcls[i].replace(" ", '')
353
                fn = f_header[len('def'):f_header.find('(')]  # function name
354 355
                if "%s%s" % (srcfile_str, fn) not in methods:
                    continue
T
tianshuo78520a 已提交
356 357 358 359
                if fn in handled:
                    continue
                if fn in alllist:
                    api_count += 1
360
                    if fn in wlist or fn + "@" + srcfile.name in wlist:
T
tianshuo78520a 已提交
361 362
                        continue
                    fcombody = single_defcom_extract(i, srcls)
363
                    if fcombody == "":  # if no comment
364
                        print_header("def", fn)
365 366
                        print("WARNING: no comments in function ", fn,
                              ", but it deserves.")
T
tianshuo78520a 已提交
367 368
                        continue
                    else:
369 370
                        if not sampcd_extract_and_run(fcombody, fn, "def", fn):
                            process_result = False
371

T
tianshuo78520a 已提交
372 373
            if srcls[i].startswith('class '):
                c_header = srcls[i].replace(" ", '')
374
                cn = c_header[len('class'):c_header.find('(')]  # class name
375 376
                if '%s%s' % (srcfile_str, cn) not in methods:
                    continue
T
tianshuo78520a 已提交
377 378 379 380
                if cn in handled:
                    continue
                if cn in alllist:
                    api_count += 1
381
                    if cn in wlist or cn + "@" + srcfile.name in wlist:
T
tianshuo78520a 已提交
382
                        continue
383
                    # class comment
T
tianshuo78520a 已提交
384
                    classcom = single_defcom_extract(i, srcls, True)
385
                    if classcom != "":
386 387
                        if not sampcd_extract_and_run(classcom, cn, "class",
                                                      cn):
388

389
                            process_result = False
T
tianshuo78520a 已提交
390
                    else:
391 392 393
                        print("WARNING: no comments in class itself ", cn,
                              ", but it deserves.\n")
                    # handling methods in class bodies
T
tianshuo78520a 已提交
394 395
                    for x in range(
                            i + 1,
396
                            len(srcls)):  # from the next line of class header
T
tianshuo78520a 已提交
397 398 399 400
                        if (srcls[x].startswith('def ') or
                                srcls[x].startswith('class ')):
                            break
                        else:
401
                            # member method def header
402
                            srcls[x] = srcls[x].replace('\t', '    ')
T
tianshuo78520a 已提交
403
                            if (srcls[x].startswith(
404
                                    '    def ')):  # detect a mehtod header..
T
tianshuo78520a 已提交
405 406 407
                                thisl = srcls[x]
                                indent = len(thisl) - len(thisl.lstrip())
                                mn = thisl[indent + len('def '):thisl.find(
408 409
                                    '(')]  # method name
                                name = cn + "." + mn  # full name
410 411 412 413
                                if '%s%s' % (
                                        srcfile_str, name
                                ) not in methods:  # class method not in api.spec 
                                    continue
T
tianshuo78520a 已提交
414 415
                                if mn.startswith('_'):
                                    continue
416
                                if name in wlist or name + "@" + srcfile.name in wlist:
T
tianshuo78520a 已提交
417
                                    continue
418 419 420 421 422
                                thismethod = [thisl[indent:]
                                              ]  # method body lines
                                # get all the lines of a single method body
                                # into thismethod(list)
                                # and send it to single_defcom_extract
T
tianshuo78520a 已提交
423
                                for y in range(x + 1, len(srcls)):
424
                                    srcls[y] = srcls[y].replace('\t', '    ')
T
tianshuo78520a 已提交
425 426
                                    if (srcls[y].startswith('def ') or
                                            srcls[y].startswith('class ')):
427
                                        # end of method
T
tianshuo78520a 已提交
428
                                        break
429 430
                                    elif srcls[y].startswith('    def '):
                                        # end of method
T
tianshuo78520a 已提交
431 432 433 434 435
                                        break
                                    else:
                                        thismethod.append(srcls[y][indent:])
                                thismtdcom = single_defcom_extract(0,
                                                                   thismethod)
436
                                if thismtdcom != "":
437 438 439
                                    if not sampcd_extract_and_run(
                                            thismtdcom, name, "method", name):
                                        process_result = False
440

441
    return process_result
T
tianshuo78520a 已提交
442 443


444
def test(file_list):
445
    process_result = True
446
    for file in file_list:
447 448 449 450
        with open(file, 'r') as src:
            if not srccoms_extract(src, wlist):
                process_result = False
    return process_result
451 452


453
def get_filenames():
454
    '''
455
    this function will get the modules that pending for check.
456 457 458 459 460 461 462 463

    Returns:

        list: the modules pending for check .

    '''
    filenames = []
    global methods
464
    global whl_error
465
    methods = []
466
    whl_error = []
467 468
    get_incrementapi()
    API_spec = 'dev_pr_diff_api.spec'
469 470
    with open(API_spec) as f:
        for line in f.readlines():
471
            api = line.replace('\n', '')
472 473 474
            try:
                module = eval(api).__module__
            except AttributeError:
475
                whl_error.append(api)
476
                continue
477
            if len(module.split('.')) > 1:
478 479 480 481 482 483
                filename = '../python/'
                module_py = '%s.py' % module.split('.')[-1]
                for i in range(0, len(module.split('.')) - 1):
                    filename = filename + '%s/' % module.split('.')[i]
                filename = filename + module_py
            else:
484
                filename = ''
485
                print("\nWARNING:----Exception in get api filename----\n")
486
                print("\n" + api + ' module is ' + module + "\n")
Z
zhangchunle 已提交
487 488
            if filename != '' and filename not in filenames:
                filenames.append(filename)
489 490 491 492 493 494 495 496 497 498
            # get all methods
            method = ''
            if inspect.isclass(eval(api)):
                name = api.split('.')[-1]
            elif inspect.isfunction(eval(api)):
                name = api.split('.')[-1]
            elif inspect.ismethod(eval(api)):
                name = '%s.%s' % (api.split('.')[-2], api.split('.')[-1])
            else:
                name = ''
499
                print("\nWARNING:----Exception in get api methods----\n")
500 501 502 503 504 505 506
                print("\n" + line + "\n")
                print("\n" + api + ' method is None!!!' + "\n")
            for j in range(2, len(module.split('.'))):
                method = method + '%s.' % module.split('.')[j]
            method = method + name
            if method not in methods:
                methods.append(method)
507
    os.remove(API_spec)
508 509 510
    return filenames


511 512 513 514 515 516 517 518 519 520 521 522
def get_incrementapi():
    '''
    this function will get the apis that difference between API_DEV.spec and API_PR.spec.
    '''

    def get_api_md5(path):
        api_md5 = {}
        API_spec = '%s/%s' % (os.path.abspath(os.path.join(os.getcwd(), "..")),
                              path)
        with open(API_spec) as f:
            for line in f.readlines():
                api = line.split(' ', 1)[0]
523 524 525
                md5 = line.split("'document', ")[1].replace(')', '').replace(
                    '\n', '')
                api_md5[api] = md5
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
        return api_md5

    dev_api = get_api_md5('paddle/fluid/API_DEV.spec')
    pr_api = get_api_md5('paddle/fluid/API_PR.spec')
    with open('dev_pr_diff_api.spec', 'w') as f:
        for key in pr_api:
            if key in dev_api:
                if dev_api[key] != pr_api[key]:
                    f.write(key)
                    f.write('\n')
            else:
                f.write(key)
                f.write('\n')


541
def get_wlist():
Z
zhangchunle 已提交
542 543 544 545 546 547 548 549 550
    '''
    this function will get the white list of API.

    Returns:

        wlist: a list of API that should not trigger the example check .

    '''
    wlist = []
Z
zhangchunle 已提交
551
    wlist_file = []
552 553
    # only white on CPU
    gpu_not_white = []
554
    with open("wlist.json", 'r') as load_f:
Z
zhangchunle 已提交
555 556
        load_dict = json.load(load_f)
        for key in load_dict:
557 558 559 560 561 562 563 564
            if key == 'wlist_dir':
                for item in load_dict[key]:
                    wlist_file.append(item["name"])
            elif key == "gpu_not_white":
                gpu_not_white = load_dict[key]
            elif key == "wlist_api":
                for item in load_dict[key]:
                    wlist.append(item["name"])
Z
zhangchunle 已提交
565 566
            else:
                wlist = wlist + load_dict[key]
567
    return wlist, wlist_file, gpu_not_white
Z
zhangchunle 已提交
568 569


570
wlist, wlist_file, gpu_not_white = get_wlist()
571 572

if len(sys.argv) < 2:
573
    print("Error: inadequate number of arguments")
574 575 576 577 578
    print('''If you are going to run it on 
        "CPU: >>> python sampcd_processor.py cpu
        "GPU: >>> python sampcd_processor.py gpu
        ''')
    sys.exit("lack arguments")
T
tianshuo78520a 已提交
579
else:
580 581 582 583
    if sys.argv[1] == "gpu":
        for _gnw in gpu_not_white:
            wlist.remove(_gnw)
    elif sys.argv[1] != "cpu":
584 585
        print("Unrecognized argument:'", sys.argv[1], "' , 'cpu' or 'gpu' is ",
              "desired\n")
586
        sys.exit("Invalid arguments")
587 588
    print("API check -- Example Code")
    print("sample_test running under python", platform.python_version())
589 590
    if not os.path.isdir("./samplecode_temp"):
        os.mkdir("./samplecode_temp")
591
    cpus = multiprocessing.cpu_count()
592
    filenames = get_filenames()
593
    if len(filenames) == 0 and len(whl_error) == 0:
594 595
        print("-----API_PR.spec is the same as API_DEV.spec-----")
        exit(0)
Z
zhangchunle 已提交
596 597 598 599 600 601 602 603
    rm_file = []
    for f in filenames:
        for w_file in wlist_file:
            if f.startswith(w_file):
                rm_file.append(f)
                filenames.remove(f)
    if len(rm_file) != 0:
        print("REMOVE white files: %s" % rm_file)
604
    print("API_PR is diff from API_DEV: %s" % filenames)
605
    one_part_filenum = int(math.ceil(len(filenames) / cpus))
606 607
    if one_part_filenum == 0:
        one_part_filenum = 1
608 609 610 611
    divided_file_list = [
        filenames[i:i + one_part_filenum]
        for i in range(0, len(filenames), one_part_filenum)
    ]
612

613 614
    po = multiprocessing.Pool()
    results = po.map_async(test, divided_file_list)
615 616
    po.close()
    po.join()
617

618
    result = results.get()
619

620
    # delete temp files
621 622 623 624 625
    for root, dirs, files in os.walk("./samplecode_temp"):
        for fntemp in files:
            os.remove("./samplecode_temp/" + fntemp)
    os.rmdir("./samplecode_temp")

626
    print("----------------End of the Check--------------------")
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
    if len(whl_error) != 0:
        print("%s is not in whl." % whl_error)
        print("")
        print("Please check the whl package and API_PR.spec!")
        print("You can follow these steps in order to generate API.spec:")
        print("1. cd ${paddle_path}, compile paddle;")
        print("2. pip install build/python/dist/(build whl package);")
        print(
            "3. run 'python tools/print_signatures.py paddle > paddle/fluid/API.spec'."
        )
        for temp in result:
            if not temp:
                print("")
                print("In addition, mistakes found in sample codes.")
                print("Please check sample codes.")
        print("----------------------------------------------------")
        exit(1)
    else:
        for temp in result:
            if not temp:
                print("Mistakes found in sample codes.")
                print("Please check sample codes.")
                exit(1)
650
    print("Sample code check is successful!")