提交 98f1cebd 编写于 作者: Y Yucheng 提交者: Dong Daxiang

add sample code test under python3 and enabled multi-thread (#20950)

* test=develop
上级 394edd86
...@@ -1002,8 +1002,7 @@ function build_document_preview() { ...@@ -1002,8 +1002,7 @@ function build_document_preview() {
function example() { function example() {
pip install ${PADDLE_ROOT}/build/python/dist/*.whl pip install ${PADDLE_ROOT}/build/python/dist/*.whl
paddle version paddle version
cp ${PADDLE_ROOT}/tools/sampcd_processor.py ${PADDLE_ROOT}/python/paddle/fluid cd ${PADDLE_ROOT}/tools
cd ${PADDLE_ROOT}/python/paddle/fluid
python sampcd_processor.py cpu python sampcd_processor.py cpu
if [ "$?" != "0" ];then if [ "$?" != "0" ];then
echo "Code instance execution failed" echo "Code instance execution failed"
......
# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. # Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
...@@ -15,53 +15,60 @@ ...@@ -15,53 +15,60 @@
import os import os
import sys import sys
import subprocess import subprocess
import multiprocessing
import math
import platform
"""
please make sure to run in the tools path
usage: python sample_test.py {arg1} {arg2}
arg1: the first arg defined running in gpu version or cpu version
arg2: the second arg defined testing python2 or python3
for example, you can run cpu version python2 testing like this:
python sample_test.py cpu 2
"""
def find_all(srcstr, substr): def find_all(srcstr, substr):
''' """
to find all desired substring in the source string to find all desired substring in the source string
and return their starting indices as a list and return their starting indices as a list
Args: Args:
srcstr(str): the parent string srcstr(str): the parent string
substr(str): substr substr(str): substr
Returns: Returns:
list: a list of the indices of the substrings list: a list of the indices of the substrings
found found
''' """
indices = [] indices = []
gotone = srcstr.find(substr) gotone = srcstr.find(substr)
while (gotone != -1): while (gotone != -1):
indices.append(gotone) indices.append(gotone)
gotone = srcstr.find(substr, gotone + 1) gotone = srcstr.find(substr, gotone + 1)
return indices return indices
def check_indent(cdline): def check_indent(cdline):
''' """
to check the indent of a given code line to check the indent of a given code line
to get the number of starting blank chars, to get the number of starting blank chars,
e.t. blankspaces and \t e.t. blankspaces and \t
\t will be interpreted as 4 single blankspaces, \t will be interpreted as 4 single blankspaces,
e.t. '\t'=' ' e.t. '\t'=' '
Args: Args:
cdline(str) : a single line of code from the source file cdline(str) : a single line of code from the source file
Returns: Returns:
int : the indent of the number of interpreted int : the indent of the number of interpreted
blankspaces blankspaces
''' """
indent = 0 indent = 0
for c in cdline: for c in cdline:
if c == '\t': if c == '\t':
...@@ -70,24 +77,16 @@ def check_indent(cdline): ...@@ -70,24 +77,16 @@ def check_indent(cdline):
indent += 1 indent += 1
if c != ' ' and c != '\t': if c != ' ' and c != '\t':
break break
return indent return indent
#srccom: raw comments in the source,including ''' and original indent # srccom: raw comments in the source,including ''' and original indent
def sampcd_extract_and_run(srccom, name, htype="def", hname=""):
"""
def sampcd_extract_and_run(srccom,
name,
logf,
htype="def",
hname="",
show_details=False):
'''
Extract and run sample codes from source comment and Extract and run sample codes from source comment and
the result will be returned. the result will be returned.
As an ultimate result, this function returns a list of As an ultimate result, this function returns a list of
status codes for each sample code (in top-down order) status codes for each sample code (in top-down order)
found in srccom. found in srccom.
...@@ -97,12 +96,12 @@ def sampcd_extract_and_run(srccom, ...@@ -97,12 +96,12 @@ def sampcd_extract_and_run(srccom,
2:have sample code but format is wrong 2:have sample code but format is wrong
1:no sample code 1:no sample code
0:successful 0:successful
-1:no comments found -1:no comments found
-2:in white list -2:in white list
there may be several examples in a source comment there may be several examples in a source comment
so status deserves a list to contain the states. so status deserves a list to contain the states.
For instance, some API has three example codes, For instance, some API has three example codes,
code 1 is successful, code 2 is error, code 3 is successful code 1 is successful, code 2 is error, code 3 is successful
so the list to return is [0,3,0] so the list to return is [0,3,0]
...@@ -110,111 +109,79 @@ def sampcd_extract_and_run(srccom, ...@@ -110,111 +109,79 @@ def sampcd_extract_and_run(srccom,
srccom(str): the source comment of some API whose srccom(str): the source comment of some API whose
example codes will be extracted and run. example codes will be extracted and run.
name(str): the name of the API. name(str): the name of the API.
logf(file): for logging the output in case they are
flushed.
htype(str): the type of hint banners, def/class/method. htype(str): the type of hint banners, def/class/method.
hname(str): the name of the hint banners , e.t. def hname. hname(str): the name of the hint banners , e.t. def hname.
show_details(bool): Set it to False to print wrong sample
codes only.
Returns: Returns:
list: the status code of all the sample codes found in srccom. list: the status code of all the sample codes found in srccom.
'''
def sampcd_header_print(name, sampcd, htype, hname, logf):
''' """
def sampcd_header_print(name, sampcd, htype, hname):
"""
print hint banner headers. print hint banner headers.
Args: Args:
name(str): the name of the API. name(str): the name of the API.
sampcd(str): sample code string sampcd(str): sample code string
htype(str): the type of hint banners, def/class/method. htype(str): the type of hint banners, def/class/method.
hname(str): the name of the hint banners , e.t. def hname. hname(str): the name of the hint banners , e.t. def hname.
logf(file): for logging the output in case they are
flushed. flushed.
''' """
print_header(logf, htype, hname) print_header(htype, hname)
print("Sample code ", str(y), " extracted for ", name, " :")
print "Sample code " + str(y) + " extracted for " + name + " :"
print "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
print(sampcd) print(sampcd)
print "----example code check----\n" print("----example code check----\n")
print "executing sample code ....." print("executing sample code .....")
print "execution result:" print("execution result:")
logf.write("\nSample code extracted for " + name + " :\n")
logf.write("\n" + sampcd + "\n")
logf.write("\n----example code check----\n")
logf.write("\nexecuting sample code .....\n")
logf.write("\nexecution result:\n")
sampcd_begins = find_all(srccom, " code-block:: python") sampcd_begins = find_all(srccom, " code-block:: python")
status = [] status = []
if len(sampcd_begins) == 0:
if (len(sampcd_begins) == 0): print_header(htype, hname)
print_header(logf, htype, hname)
''' '''
detect sample codes using >>> to format detect sample codes using >>> to format
and consider this situation as wrong and consider this situation as wrong
''' '''
if (srccom.find("Examples:") != -1): if srccom.find("Examples:") != -1:
print "----example code check----\n" print("----example code check----\n")
logf.write("\n----example code check----\n") if srccom.find(">>>") != -1:
if (srccom.find(">>>") != -1):
logf.write(
"Deprecated sample code style:\n\n Examples:\n\n >>>codeline\n >>>codeline\n\n\n "
+ "Please use '.. code-block:: python' to " +
"format sample code.\n")
print( print(
"Deprecated sample code style:\n\n Examples:\n\n >>>codeline\n >>>codeline\n\n\n " "Deprecated sample code style:\n\n Examples:\n\n >>>codeline\n >>>codeline\n\n\n ",
+ "Please use '.. code-block:: python' to " + "Please use '.. code-block:: python' to ",
"format sample code.\n") "format sample code.\n")
status.append(2) status.append(2)
print "status code for all sample codes in " + name + " : " + str( print("status code for all sample codes in ", name, " : ",
status) str(status))
else: else:
print "No sample code!\n" print("No sample code!\n")
logf.write("\nNo sample code!\n")
status.append(1) status.append(1)
print "status code for all sample codes in " + name + " : " + str( print("status code for all sample codes in ", name, " : ",
status) str(status))
for y in range(1, len(sampcd_begins) + 1): for y in range(1, len(sampcd_begins) + 1):
sampcd_begin = sampcd_begins[y - 1] sampcd_begin = sampcd_begins[y - 1]
sampcd = srccom[sampcd_begin + len(" code-block:: python") + 1:] sampcd = srccom[sampcd_begin + len(" code-block:: python") + 1:]
sampcd = sampcd.split("\n") sampcd = sampcd.split("\n")
# remove starting empty lines
#remove starting empty lines
while sampcd[0].replace(' ', '').replace('\t', '') == '': while sampcd[0].replace(' ', '').replace('\t', '') == '':
sampcd.pop(0) sampcd.pop(0)
#the mininmum indent, which is the indent of the first # the minimum indent, which is the indent of the first
#non-empty line # non-empty line
min_indent = check_indent(sampcd[0]) min_indent = check_indent(sampcd[0])
sampcd_to_write = [] sampcd_to_write = []
for i in range(0, len(sampcd)): for i in range(0, len(sampcd)):
cdline = sampcd[i] cdline = sampcd[i]
# handle empty lines or those only with spaces/tabs
#handle empty lines or those only with spaces/tabs
if cdline.strip() == '': if cdline.strip() == '':
continue continue
this_indent = check_indent(cdline) this_indent = check_indent(cdline)
if (this_indent < min_indent): if this_indent < min_indent:
break break
else: else:
cdline = cdline.replace('\t', ' ') cdline = cdline.replace('\t', ' ')
sampcd_to_write.append(cdline[min_indent:]) sampcd_to_write.append(cdline[min_indent:])
...@@ -224,94 +191,75 @@ def sampcd_extract_and_run(srccom, ...@@ -224,94 +191,75 @@ def sampcd_extract_and_run(srccom,
sampcd = '\nimport os\n' + 'os.environ["CUDA_VISIBLE_DEVICES"] = ""\n' + sampcd sampcd = '\nimport os\n' + 'os.environ["CUDA_VISIBLE_DEVICES"] = ""\n' + sampcd
if sys.argv[1] == "gpu": if sys.argv[1] == "gpu":
sampcd = '\nimport os\n' + 'os.environ["CUDA_VISIBLE_DEVICES"] = "0"\n' + sampcd sampcd = '\nimport os\n' + 'os.environ["CUDA_VISIBLE_DEVICES"] = "0"\n' + sampcd
sampcd += '\nprint ' + '\"' + name + ' sample code is executed successfully!\"\n' sampcd += '\nprint(' + '\"' + name + ' sample code is executed successfully!\")'
if (len(sampcd_begins) > 1): if len(sampcd_begins) > 1:
tfname = name + "_example_" + str(y) + ".py" tfname = name + "_example_" + str(y) + ".py"
else: else:
tfname = name + "_example" + ".py" tfname = name + "_example" + ".py"
tempf = open("samplecode_temp/" + tfname, 'w') tempf = open("samplecode_temp/" + tfname, 'w')
tempf.write(sampcd) tempf.write(sampcd)
tempf.close() tempf.close()
if platform.python_version()[0] == "2":
cmd = ["python", "samplecode_temp/" + tfname] cmd = ["python", "samplecode_temp/" + tfname]
elif platform.python_version()[0] == "3":
cmd = ["python3", "samplecode_temp/" + tfname]
else:
print("fail to parse python version!")
exit(1)
subprc = subprocess.Popen( subprc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = subprc.communicate() output, error = subprc.communicate()
msg = "".join(output.decode(encoding='utf-8'))
msg = "".join(output) err = "".join(error.decode(encoding='utf-8'))
err = "".join(error)
if subprc.returncode != 0:
if (subprc.returncode != 0): print("\nSample code error found in ", name, ":\n")
sampcd_header_print(name, sampcd, htype, hname)
print("\nSample code error found in " + name + ":\n") print("subprocess return code: ", str(subprc.returncode))
sampcd_header_print(name, sampcd, htype, hname, logf) print("Error Raised from Sample Code ", name, " :\n")
print "subprocess return code: " + str(subprc.returncode) print(err)
print("Error Raised from Sample Code " + name + " :\n") print(msg)
print err
print msg
logf.write("\nError Raised from Sample Code " + name + " :\n")
logf.write("\n" + msg + "\n")
status.append(3) status.append(3)
print "status code for all sample codes in " + name + str(status) print("status code for all sample codes in ", name, str(status))
#It works! # It works!
else: else:
status.append(0) status.append(0)
if show_details: # msg is the returned code execution report
sampcd_header_print(name, sampcd, htype, hname, logf)
print "subprocess return code: " + str(subprc.returncode)
print msg
logf.write("\n" + msg + "\n")
print "status code for all sample codes in " + name + " : " + str(
status)
#msg is the returned code execution report
os.remove("samplecode_temp/" + tfname) os.remove("samplecode_temp/" + tfname)
return status return status
def single_defcom_extract(start_from, srcls, is_class_begin=False): def single_defcom_extract(start_from, srcls, is_class_begin=False):
''' """
to extract a def function/class/method comments body to extract a def function/class/method comments body
Args: Args:
start_from(int): the line num of "def" header start_from(int): the line num of "def" header
srcls(list): the source file in lines srcls(list): the source file in lines
is_class_begin(bool): whether the start_from is a beginning a class. \ 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 For a sole class body itself may end up with its method if it has no
docstring. But the body of \ docstring. But the body of \
a common def function can only be ended up by a none-indented def/class a common def function can only be ended up by a none-indented def/class
Returns: Returns:
string : the extracted comment body, inclusive of its quote marks. string : the extracted comment body, inclusive of its quote marks.
''' """
i = start_from i = start_from
fcombody = "" # def comment body
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
comstart = -1 # the starting line index of comment mark "'''" or """"""
#if it is not -1, it indicates the loop is in the comment body
comstyle = 0 # comment mark style ,comments quoted with ''' is coded as 1 comstyle = 0 # comment mark style ,comments quoted with ''' is coded as 1
# comments quoted with """ is coded as 2 # comments quoted with """ is coded as 2
for x in range(i + 1, len(srcls)): for x in range(i + 1, len(srcls)):
if is_class_begin: if is_class_begin:
if srcls[x].replace('\t', ' ').startswith(' def '):
if (srcls[x].replace('\t', ' ').startswith(' def ')):
break break
if srcls[x].startswith('def ') or srcls[x].startswith('class '):
if ((srcls[x].startswith('def ') or srcls[x].startswith('class '))):
break break
else: else:
if (comstart == -1 and srcls[x].replace(" ", '').replace( if (comstart == -1 and srcls[x].replace(" ", '').replace(
"\t", '').replace("\n", '').startswith("\"\"\"")): "\t", '').replace("\n", '').startswith("\"\"\"")):
comstart = x comstart = x
...@@ -321,7 +269,6 @@ def single_defcom_extract(start_from, srcls, is_class_begin=False): ...@@ -321,7 +269,6 @@ def single_defcom_extract(start_from, srcls, is_class_begin=False):
srcls[x].replace(" ", '').replace("\t", '').replace( srcls[x].replace(" ", '').replace("\t", '').replace(
"\n", '').startswith("\"\"\"")): "\n", '').startswith("\"\"\"")):
break break
if (comstart == -1 and srcls[x].replace(" ", '').replace( if (comstart == -1 and srcls[x].replace(" ", '').replace(
"\t", '').replace("\n", '').startswith("\'\'\'")): "\t", '').replace("\n", '').startswith("\'\'\'")):
comstart = x comstart = x
...@@ -332,99 +279,61 @@ def single_defcom_extract(start_from, srcls, is_class_begin=False): ...@@ -332,99 +279,61 @@ def single_defcom_extract(start_from, srcls, is_class_begin=False):
"\n", '').startswith("\'\'\'")): "\n", '').startswith("\'\'\'")):
break break
if (comstart != if (comstart !=
-1): #when the comments start, begin to add line to fcombody -1): # when the comments start, begin to add line to fcombody
fcombody += srcls[x] fcombody += srcls[x]
return fcombody return fcombody
def print_header(logf, htype, name): def print_header(htype, name):
print(htype, " name:", name)
print htype + " name:" + name print("-----------------------")
print "-----------------------"
logf.write("\n\n" + htype + " name:" + name + "\n")
logf.write("-----------------------\n")
def srcf_print(srcfile):
print "source file name:" + srcfile.name
print "---------------------------------------------------"
logf.write("source file name:" + srcfile.name + "\n") def srccoms_extract(srcfile, status_all, wlist):
logf.write("---------------------------------------------------\n\n") """
def show_alllist(alllist):
print "__all__:" + str(alllist) + "\n"
logf.write("__all__:" + str(alllist) + "\n\n")
def srccoms_extract(srcfile, logf, status_all, wlist, show_details):
'''
Given a source file ``srcfile``, this function will Given a source file ``srcfile``, this function will
extract its API(doc comments) and run sample codes in the extract its API(doc comments) and run sample codes in the
API. API.
Args: Args:
srcfile(file): the source file srcfile(file): the source file
logf(file): log recording file
status_all(dict): record all the sample code execution states. status_all(dict): record all the sample code execution states.
wlist(list): white list wlist(list): white list
show_details(bool): if show_details is True, the whole process will be printed for you
to debug it locally
Returns: Returns:
string: the length of __all__ list in srcfile versus the exact number of string: the length of __all__ list in srcfile versus the exact number of
analysed API to make sure no API is missed in this srcfile and it analysed API to make sure no API is missed in this srcfile and it
is useful for statistic practices. is useful for statistic practices.
''' """
srcc = srcfile.read() srcc = srcfile.read()
#2. get defs and classes header line number # 2. get defs and classes header line number
#set file pointer to its beginning # set file pointer to its beginning
srcfile.seek(0, 0) srcfile.seek(0, 0)
srcls = srcfile.readlines() #source lines srcls = srcfile.readlines() # source lines
if show_details:
srcf_print(srcfile)
#1. fetch__all__ list # 1. fetch__all__ list
allidx = srcc.find("__all__") allidx = srcc.find("__all__")
if (allidx != -1): if allidx != -1:
alllist = [] alllist = []
# get all list for layers/ops.py
#get all list for layers/ops.py if srcfile.name.find("ops.py") != -1:
if (srcfile.name.find("ops.py") != -1):
for ai in range(0, len(srcls)): for ai in range(0, len(srcls)):
if srcls[ai].startswith("__all__"):
if (srcls[ai].startswith("__all__")):
lb = srcls[ai].find('[') lb = srcls[ai].find('[')
rb = srcls[ai].find(']') rb = srcls[ai].find(']')
if (lb == -1): if lb == -1:
continue continue
allele = srcls[ai][lb + 1:rb].replace("'", '').replace( allele = srcls[ai][lb + 1:rb].replace("'", '').replace(
" ", '').replace("\"", '') " ", '').replace("\"", '')
alllist.append(allele) alllist.append(allele)
if '' in alllist: if '' in alllist:
alllist.remove('') alllist.remove('')
if show_details:
show_alllist(alllist)
else: else:
alllist_b = allidx + len("__all__") alllist_b = allidx + len("__all__")
allstr = srcc[alllist_b + srcc[alllist_b:].find("[") + 1:alllist_b + allstr = srcc[alllist_b + srcc[alllist_b:].find("[") + 1:alllist_b +
srcc[alllist_b:].find("]")] srcc[alllist_b:].find("]")]
allstr = allstr.replace("\n", '').replace(" ", '').replace( allstr = allstr.replace("\n", '').replace(" ", '').replace(
...@@ -432,295 +341,184 @@ def srccoms_extract(srcfile, logf, status_all, wlist, show_details): ...@@ -432,295 +341,184 @@ def srccoms_extract(srcfile, logf, status_all, wlist, show_details):
alllist = allstr.split(',') alllist = allstr.split(',')
if '' in alllist: if '' in alllist:
alllist.remove('') alllist.remove('')
if show_details:
show_alllist(alllist)
api_alllist_count = len(alllist) api_alllist_count = len(alllist)
api_count = 0 api_count = 0
handled = [] handled = []
#get src contents in layers/ops.py # get src contents in layers/ops.py
if (srcfile.name.find("ops.py") != -1): if srcfile.name.find("ops.py") != -1:
for i in range(0, len(srcls)): for i in range(0, len(srcls)):
if srcls[i].find("__doc__") != -1: if srcls[i].find("__doc__") != -1:
opname = srcls[i][:srcls[i].find("__doc__") - 1] opname = srcls[i][:srcls[i].find("__doc__") - 1]
if opname in wlist: if opname in wlist:
status_all[srcfile.name + '/' + opname] = [-2] status_all[srcfile.name + '/' + opname] = [-2]
if show_details:
print_header(logf, "def", opname)
print opname + " is in white list, thus skipped"
logf.write("\n" + opname +
" is in white list, thus skipped\n")
print status_all[srcfile.name + '/' + opname]
logf.write("\n" + "execution status" + str(
status_all[srcfile.name + '/' + opname]) + "\n")
continue continue
comstart = i comstart = i
for j in range(i, len(srcls)): for j in range(i, len(srcls)):
if (srcls[j].find("\"\"\"") != -1): if srcls[j].find("\"\"\"") != -1:
comstart = i comstart = i
opcom = "" opcom = ""
for j in range(comstart + 1, len(srcls)): for j in range(comstart + 1, len(srcls)):
opcom += srcls[j] opcom += srcls[j]
if (srcls[j].find("\"\"\"") != -1): if srcls[j].find("\"\"\"") != -1:
break break
status = sampcd_extract_and_run(opcom, opname, "def",
status = sampcd_extract_and_run(opcom, opname, logf, "def", opname)
opname, show_details)
api_count += 1 api_count += 1
status_all[srcfile.name + '/' + opname] = status status_all[srcfile.name + '/' + opname] = status
handled.append( handled.append(
opname) #ops.py also has normal formatted functions opname) # ops.py also has normal formatted functions
#use list 'handled' to mark the functions have been handled here # use list 'handled' to mark the functions have been handled here
#which will be ignored in the following step # which will be ignored in the following step
for i in range(0, len(srcls)): for i in range(0, len(srcls)):
if srcls[i].startswith( if srcls[i].startswith(
'def '): #a function header is detected in line i 'def '): # a function header is detected in line i
f_header = srcls[i].replace(" ", '') f_header = srcls[i].replace(" ", '')
fn = f_header[len('def'):f_header.find('(')] #function name fn = f_header[len('def'):f_header.find('(')] # function name
if fn in handled: if fn in handled:
continue continue
if fn in alllist: if fn in alllist:
api_count += 1 api_count += 1
if fn in wlist or fn + "@" + srcfile.name in wlist: if fn in wlist or fn + "@" + srcfile.name in wlist:
status_all[srcfile.name + '/' + fn] = [-2] status_all[srcfile.name + '/' + fn] = [-2]
if show_details:
print_header(logf, "def", fn)
print fn + " is in white list, thus skipped"
logf.write("\n" + fn +
" is in white list, thus skipped\n")
print status_all[srcfile.name + '/' + fn]
logf.write("\n" + "execution status" + str(
status_all[srcfile.name + '/' + fn]) + "\n")
continue continue
fcombody = single_defcom_extract(i, srcls) fcombody = single_defcom_extract(i, srcls)
if (fcombody == ""): #if no comment if fcombody == "": # if no comment
print_header(logf, "def", fn) print_header("def", fn)
print "WARNING: no comments in function " + fn + ", but it deserves." print("WARNING: no comments in function ", fn,
logf.write("no comments in function " + fn + "\n\n") ", but it deserves.")
status_all[srcfile.name + '/' + fn] = [-1] status_all[srcfile.name + '/' + fn] = [-1]
print status_all[srcfile.name + '/' + fn] print(status_all[srcfile.name + '/' + fn])
logf.write("\n" + "execution status" + str(status_all[
srcfile.name + '/' + fn]) + "\n")
continue continue
else: else:
status = sampcd_extract_and_run(fcombody, fn, logf, status = sampcd_extract_and_run(fcombody, fn, "def", fn)
"def", fn, show_details)
status_all[srcfile.name + '/' + fn] = status status_all[srcfile.name + '/' + fn] = status
else:
if show_details:
print_header(logf, "def", fn)
print fn + " not in __all__ list"
logf.write(fn + " not in __all__ list\n\n")
if srcls[i].startswith('class '): if srcls[i].startswith('class '):
c_header = srcls[i].replace(" ", '') c_header = srcls[i].replace(" ", '')
cn = c_header[len('class'):c_header.find('(')] #class name cn = c_header[len('class'):c_header.find('(')] # class name
if cn in handled: if cn in handled:
continue continue
if cn in alllist: if cn in alllist:
api_count += 1 api_count += 1
if cn in wlist or cn + "@" + srcfile.name in wlist: if cn in wlist or cn + "@" + srcfile.name in wlist:
status_all[srcfile.name + '/' + cn] = [-2] status_all[srcfile.name + '/' + cn] = [-2]
if show_details:
print cn + " is in white list, thus skipped"
logf.write("\n" + cn +
" is in white list, thus skipped\n")
print status_all[srcfile.name + '/' + cn]
logf.write("\n" + "execution status" + str(
status_all[srcfile.name + '/' + cn]) + "\n")
continue continue
# class comment
#class comment
classcom = single_defcom_extract(i, srcls, True) classcom = single_defcom_extract(i, srcls, True)
if classcom != "":
if (classcom != ""): status = sampcd_extract_and_run(classcom, cn, "class",
cn)
status = sampcd_extract_and_run(
classcom, cn, logf, "class", cn, show_details)
status_all[srcfile.name + '/' + cn] = status status_all[srcfile.name + '/' + cn] = status
else: else:
print "WARNING: no comments in class itself " + cn + ", but it deserves.\n" print("WARNING: no comments in class itself ", cn,
logf.write("no comments in class itself " + cn + ", but it deserves.\n")
"\n\n\n")
status_all[srcfile.name + '/' + cn] = [-1] status_all[srcfile.name + '/' + cn] = [-1]
print status_all[srcfile.name + '/' + cn] print(status_all[srcfile.name + '/' + cn])
logf.write("\n" + "execution status" + str(status_all[ # handling methods in class bodies
srcfile.name + '/' + cn]) + "\n")
#handling methods in class bodies
for x in range( for x in range(
i + 1, i + 1,
len(srcls)): #from the next line of class header len(srcls)): # from the next line of class header
if (srcls[x].startswith('def ') or if (srcls[x].startswith('def ') or
srcls[x].startswith('class ')): srcls[x].startswith('class ')):
break break
else: else:
#member method def header # member method def header
srcls[x] = srcls[x].replace('\t', ' ') srcls[x] = srcls[x].replace('\t', ' ')
if (srcls[x].startswith( if (srcls[x].startswith(
' def ')): #detect a mehtod header.. ' def ')): # detect a mehtod header..
thisl = srcls[x] thisl = srcls[x]
indent = len(thisl) - len(thisl.lstrip()) indent = len(thisl) - len(thisl.lstrip())
mn = thisl[indent + len('def '):thisl.find( mn = thisl[indent + len('def '):thisl.find(
'(')] #method name '(')] # method name
name = cn + "." + mn # full name
name = cn + "." + mn #full name
if mn.startswith('_'): if mn.startswith('_'):
if show_details:
print mn + " is hidden, not visible to users\n"
logf.write(
"\n" + mn +
" is hidden, not visible to users\n")
continue continue
if name in wlist or name + "@" + srcfile.name in wlist: if name in wlist or name + "@" + srcfile.name in wlist:
status_all[srcfile.name + '/' + name] = [-2] status_all[srcfile.name + '/' + name] = [-2]
if show_details:
print name + " is in white list, thus skipped"
logf.write(
"\n" + name +
" is in white list, thus skipped\n")
print status_all[srcfile.name + '/' +
name]
logf.write(
"\n" + "execution status" + str(
status_all[srcfile.name + '/' +
name]) + "\n")
continue continue
thismethod = [thisl[indent:]
thismethod = [] #method body lines ] # method body lines
thismethod.append(thisl[indent:]) # get all the lines of a single method body
# into thismethod(list)
#get all the lines of a single method body # and send it to single_defcom_extract
#into thismethod(list)
#and send it to single_defcom_extract
for y in range(x + 1, len(srcls)): for y in range(x + 1, len(srcls)):
srcls[y] = srcls[y].replace('\t', ' ') srcls[y] = srcls[y].replace('\t', ' ')
if (srcls[y].startswith('def ') or if (srcls[y].startswith('def ') or
srcls[y].startswith('class ')): srcls[y].startswith('class ')):
#end of method # end of method
break break
elif (srcls[y].startswith(' def ')): elif srcls[y].startswith(' def '):
#end of method # end of method
break break
else: else:
thismethod.append(srcls[y][indent:]) thismethod.append(srcls[y][indent:])
thismtdcom = single_defcom_extract(0, thismtdcom = single_defcom_extract(0,
thismethod) thismethod)
if thismtdcom != "":
if (thismtdcom != ""):
status = sampcd_extract_and_run( status = sampcd_extract_and_run(
thismtdcom, name, logf, "method", name, thismtdcom, name, "method", name)
show_details)
status_all[srcfile.name + '/' + status_all[srcfile.name + '/' +
name] = status name] = status
else:
if show_details:
print "no comments in method " + name + "\n"
logf.write("no comments in method " +
name + "\n\n\n")
status_all[srcfile.name + '/' +
name] = [-1]
print status_all[srcfile.name + '/' +
name]
logf.write(
"\n" + "execution status" + str(
status_all[srcfile.name + '/' +
name]) + "\n")
else:
if show_details:
print cn + " is not in __all__ list"
logf.write(cn + " is not in __all__ list\n\n")
return [ return [
srcfile.name + " all list length: " + str(api_alllist_count), srcfile.name + " all list length: " + str(api_alllist_count),
"analysed api count: " + str(api_count) "analysed api count: " + str(api_count)
] ]
def test(file_list):
for file in file_list:
src = open(file, 'r')
counts = srccoms_extract(src, status_all, wlist)
src.close()
''' '''
Important constant lists: Important constant lists:
filenames : the modules pending for check . filenames : the modules pending for check .
wlist : a list of API that should not trigger the example check . wlist : a list of API that should not trigger the example check .
It is composed of wlist_temp + wlist_inneed + wlist_ignore. It is composed of wlist_temp + wlist_inneed + wlist_ignore.
show_details: a boolean value to indicate whether it should be run
in debugging mode.
status_all: a status list containing all the execution status of all status_all: a status list containing all the execution status of all
APIs APIs
srcfile: the source .py code file srcfile: the source .py code file
''' '''
filenames = [ filenames = [
"layers/control_flow.py", "layers/io.py", "layers/nn.py", "layers/ops.py", "../python/paddle/fluid/layers/control_flow.py",
"layers/tensor.py", "layers/learning_rate_scheduler.py", "../python/paddle/fluid/layers/io.py",
"layers/detection.py", "layers/metric_op.py" "../python/paddle/fluid/layers/nn.py",
"../python/paddle/fluid/layers/ops.py",
"../python/paddle/fluid/layers/tensor.py",
"../python/paddle/fluid/layers/learning_rate_scheduler.py",
"../python/paddle/fluid/layers/detection.py",
"../python/paddle/fluid/layers/metric_op.py"
] ]
filenames += [ filenames += [
"dygraph/layers.py", "dygraph/base.py", "dygraph/nn.py", "../python/paddle/fluid/dygraph/layers.py",
"dygraph/tracer.py", "dygraph/profiler.py", "dygraph/parallel.py", "../python/paddle/fluid/dygraph/base.py",
"dygraph/checkpoint.py", "dygraph/learning_rate_scheduler.py", "../python/paddle/fluid/dygraph/nn.py",
"dygraph/backward_strategy.py" "../python/paddle/fluid/dygraph/tracer.py",
"../python/paddle/fluid/dygraph/profiler.py",
"../python/paddle/fluid/dygraph/parallel.py",
"../python/paddle/fluid/dygraph/checkpoint.py",
"../python/paddle/fluid/dygraph/learning_rate_scheduler.py",
"../python/paddle/fluid/dygraph/backward_strategy.py"
] ]
filenames += [ filenames += [
"data_feeder.py", "dataset.py", "clip.py", "metrics.py", "executor.py", "../python/paddle/fluid/data_feeder.py",
"initializer.py", "io.py", "nets.py", "optimizer.py", "profiler.py", "../python/paddle/fluid/dataset.py", "../python/paddle/fluid/clip.py",
"regularizer.py", "backward.py", "average.py", "unique_name.py", "../python/paddle/fluid/metrics.py", "../python/paddle/fluid/executor.py",
"framework.py", "evaluator.py", "param_attr.py" "../python/paddle/fluid/initializer.py", "../python/paddle/fluid/io.py",
"../python/paddle/fluid/nets.py", "../python/paddle/fluid/optimizer.py",
"../python/paddle/fluid/profiler.py",
"../python/paddle/fluid/regularizer.py",
"../python/paddle/fluid/backward.py", "../python/paddle/fluid/average.py",
"../python/paddle/fluid/unique_name.py",
"../python/paddle/fluid/framework.py",
"../python/paddle/fluid/evaluator.py",
"../python/paddle/fluid/param_attr.py"
] ]
wlist_inneed = [ wlist_inneed = [
"append_LARS", "BuildStrategy.debug_graphviz_path", "append_LARS", "BuildStrategy.debug_graphviz_path",
"BuildStrategy.enable_sequential_execution", "BuildStrategy.enable_sequential_execution",
...@@ -752,7 +550,6 @@ wlist_inneed = [ ...@@ -752,7 +550,6 @@ wlist_inneed = [
'StaticRNN.output', "cuda_places", "CUDAPinnedPlace", "CUDAPlace", 'StaticRNN.output', "cuda_places", "CUDAPinnedPlace", "CUDAPlace",
"Program.parse_from_string" "Program.parse_from_string"
] ]
wlist_temp = [ wlist_temp = [
'ChunkEvaluator', 'ChunkEvaluator',
'EditDistance', 'EditDistance',
...@@ -851,7 +648,6 @@ wlist_ignore = [ ...@@ -851,7 +648,6 @@ wlist_ignore = [
'Precision.update', 'WeightedAverage.eval', 'Conv3D.forward', 'Precision.update', 'WeightedAverage.eval', 'Conv3D.forward',
'Embedding.forward', 'Recall.eval', 'FC.forward', 'While.block' 'Embedding.forward', 'Recall.eval', 'FC.forward', 'While.block'
] ]
# only white on CPU # only white on CPU
gpu_not_white = [ gpu_not_white = [
"deformable_conv", "cuda_places", "CUDAPinnedPlace", "CUDAPlace", "deformable_conv", "cuda_places", "CUDAPinnedPlace", "CUDAPlace",
...@@ -861,146 +657,65 @@ gpu_not_white = [ ...@@ -861,146 +657,65 @@ gpu_not_white = [
wlist = wlist_temp + wlist_inneed + wlist_ignore wlist = wlist_temp + wlist_inneed + wlist_ignore
if len(sys.argv) < 2: if len(sys.argv) < 2:
print "Error: inadequate number of arguments" print("Error: inadequate number of arguments")
print('''If you are going to run it on print('''If you are going to run it on
"CPU: >>> python sampcd_processor.py cpu "CPU: >>> python sampcd_processor.py cpu
"GPU: >>> python sampcd_processor.py gpu "GPU: >>> python sampcd_processor.py gpu
''') ''')
sys.exit("lack arguments") sys.exit("lack arguments")
else: else:
show_details = False
if sys.argv[1] == "gpu": if sys.argv[1] == "gpu":
for _gnw in gpu_not_white: for _gnw in gpu_not_white:
wlist.remove(_gnw) wlist.remove(_gnw)
elif sys.argv[1] != "cpu": elif sys.argv[1] != "cpu":
print("Unrecognized argument:'" + sys.argv[1] + "' , 'cpu' or 'gpu' is " print("Unrecognized argument:'", sys.argv[1], "' , 'cpu' or 'gpu' is ",
+ "desired\n") "desired\n")
sys.exit("Invalid arguments") sys.exit("Invalid arguments")
print("API check -- Example Code")
if len(sys.argv) == 3: print("sample_test running under python", platform.python_version())
if sys.argv[2] == "sd":
show_details = True
else:
print("Unrecognized argument:'" + sys.argv[2] + "' , 'sd' is " +
"desired\n")
sys.exit("Invalid arguments")
print("* * * * * * * * * * * * * * * * * * * * * * * *\n" +
"* *\n" +
"* API check -- Example Code Cheker *\n" +
"* *\n" +
"* *\n" +
"* This process is meant to check *\n" +
"* all example codes per CI to ensure *\n" +
"* the example codes can be run successfully *\n" +
"* *\n" +
"* *\n" +
"* Refer to the comments for detailed *\n" +
"* introduction *\n" +
"* *\n" +
"* *\n" +
"* * * * * * * * * * * * * * * * * * * * * * * *\n")
status_all = {} status_all = {}
#a file to record the terminal output
logf = open("example-code-check-log.txt", 'w')
# a temp directory to store temporary sample code file # a temp directory to store temporary sample code file
# subprocess needs a single file to run the code # subprocess needs a single file to run the code
if not os.path.isdir("./samplecode_temp"): if not os.path.isdir("./samplecode_temp"):
os.mkdir("./samplecode_temp") os.mkdir("./samplecode_temp")
to_check = filenames one_part_filenum = int(math.ceil(len(filenames) / 10))
for filename in to_check: divided_file_list = [
filenames[i:i + one_part_filenum]
srcfile = open(filename, 'r') for i in range(0, len(filenames), one_part_filenum)
]
counts = srccoms_extract(srcfile, logf, status_all, wlist, show_details) po = multiprocessing.Pool(10)
for file_list in divided_file_list:
if show_details: po.apply_async(test, (file_list, ))
logf.write("\n\n" + str(counts) + "\n\n") po.close()
po.join()
srcfile.close()
# clear temp files # clear temp files
for root, dirs, files in os.walk("./samplecode_temp"): for root, dirs, files in os.walk("./samplecode_temp"):
for fntemp in files: for fntemp in files:
os.remove("./samplecode_temp/" + fntemp) os.remove("./samplecode_temp/" + fntemp)
os.rmdir("./samplecode_temp") os.rmdir("./samplecode_temp")
status_groups = {-2: [], -1: [], 0: [], 1: [], 2: [], 3: []} status_groups = {-2: [], -1: [], 0: [], 1: [], 2: [], 3: []}
ci_pass = True ci_pass = True
for key in status_all: for key in status_all:
statusl = status_all[key] statusl = status_all[key]
for ele in statusl: for ele in statusl:
if (ele != 0 and ele != -2 and ele != -1): if ele != 0 and ele != -2 and ele != -1:
ci_pass = False ci_pass = False
break break
if len(statusl) == 1: if len(statusl) == 1:
status_groups[statusl[0]].append(key) status_groups[statusl[0]].append(key)
else: else:
for u in range(0, len(statusl)): for u in range(0, len(statusl)):
status_groups[statusl[u]].append(key + '_' + str(u + 1)) status_groups[statusl[u]].append(key + '_' + str(u + 1))
print("----------------End of the Check--------------------")
logf.close()
print(
"\n\n------------------End of the Check-------------------------------------------\n\n"
)
errorapisl = status_groups[1] + status_groups[2] + status_groups[3] errorapisl = status_groups[1] + status_groups[2] + status_groups[3]
if len(errorapisl) > 0: if len(errorapisl) > 0:
print "Error raised from: " + str(errorapisl) print("Error raised from: ", str(errorapisl))
if not ci_pass: if not ci_pass:
print("Mistakes found in sample codes")
print(
"\nOh no.. Mistakes found in sample codes, refer to the log for details\n\n"
)
print('''
- How to run it locally?
Simply put this script under directory:
Paddle/python/paddle/fluid/
and run in python 2.7 (as some interfaces of subprocess may
not work in python 3)
You must specify the device type to run the sample code on:
CPU: >>> python sampcd_processor.py cpu
GPU: >>> python sampcd_processor.py gpu
- How to debug?
This script has an option for showing the details of
the execution status:
>>> python sampcd_processor.py cpu sd
- NOTE:
Please ensure your are using
.. code-block:: python
[sample code starts here]
ONLY 1 BLANKSPACE between '::' and 'python'
''')
exit(1) exit(1)
else: else:
print("Sample code check is successful!")
print "Sample code check is successful!"
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册