Skip to content

Commit

Permalink
update doc generate
Browse files Browse the repository at this point in the history
  • Loading branch information
Neutree committed Apr 24, 2024
1 parent e596760 commit f82328d
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 12 deletions.
2 changes: 1 addition & 1 deletion components/maix/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ if(EXISTS ${maixpy_wrapper_src})
file(REMOVE ${maixpy_wrapper_src})
endif()
add_custom_command(OUTPUT ${maixpy_wrapper_src}
COMMAND ${python} -u ${CMAKE_CURRENT_SOURCE_DIR}/gen_api.py -o ${maixpy_wrapper_src} --doc ${PROJECT_PATH}/docs/api --sdk_path ${SDK_PATH}
COMMAND ${python} -u ${CMAKE_CURRENT_SOURCE_DIR}/gen_api_cpp.py -o ${maixpy_wrapper_src} --sdk_path ${SDK_PATH}
COMMENT "Generating maixpy_wrapper.cpp"
VERBATIM
)
Expand Down
87 changes: 80 additions & 7 deletions components/maix/gen_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,90 @@ def sort_headers(headers):
headers = sorted(headers, key = lambda x: headers_priority.index(os.path.basename(x)) if os.path.basename(x) in headers_priority else len(headers_priority))
return headers

def parse_pyi(path):
items = {
"class": {},
"func": []
}
with open(path) as f:
lines = f.readlines()
class_item = None
for i, line in enumerate(lines):
if class_item:
if line[0] != " ":
items["class"][class_item["name"]] = class_item
class_item = None
continue
line = line.strip()
if line.startswith("def"):
class_item["func"].append(line.rsplit(":", 1)[0])

if line.startswith("def"):
items["func"].append(line.rsplit(":", 1)[0])
if line.startswith("class"):
class_item = {
"name": line.replace("class", "").replace(":", "").strip(),
"func": []
}
return items

def find_func_def(items, name):
for item in items:
# def check_bool_raise(ok: bool, msg: str = '') -> None:
funcname = item.replace("def", "").strip().split("(")[0]
if funcname == name:
return item
return None

def find_class_func_def(items, mc_k, name, debug):
item = items["class"].get(mc_k, {})
if debug:
print(items, items["class"], mc_k)
if not item:
return None
# {"name": "", "func": {}}
return find_func_def(item["func"], name)

def update_py_def_from_stub_files(api_tree, stub):
'''
parse stub files, add definition to api_tree
'''
maix_pyi_root = os.path.join(stub, "maix", "_maix")
for k, v in api_tree["members"]["maix"]["members"].items():
def parse_module(pyi_path, k, v):
items = parse_pyi(pyi_path)
for m_k, m_v in v["members"].items():
if m_v["type"] == "func":
name = m_v["name"]
func_def = find_func_def(items, name)
if func_def:
m_v["py_def"] = func_def.replace("maix._maix", "maix")
elif m_v["type"] == "class":
for mc_k, mc_v in m_v["members"].items():
if mc_v["type"] == "func":
func_def = find_class_func_def(items, m_k, mc_k, m_v["name"] == "Tensors")
if func_def:
mc_v["py_def"] = func_def.replace("maix._maix", "maix")
module_dir = os.path.join(maix_pyi_root, k)
if os.path.isdir(module_dir):
for m_k, m_v in v["members"].items():
path = os.path.join(maix_pyi_root, k, f"{m_k}.pyi")
# TODO: optimize speed
if os.path.exists(path):
parse_module(path, m_k, m_v)
else:
parse_module(os.path.join(maix_pyi_root, k, f"__init__.pyi"), m_k, m_v)
else:
parse_module(os.path.join(maix_pyi_root, f"{k}.pyi"), k, v)
return api_tree

if __name__ == "__main__":
print("-- Generate MaixPy C/C++ API")
parser = argparse.ArgumentParser(description='Generate MaixPy C/C++ API')
parser.add_argument('--vars', type=str, default="", help="CMake global variables file")
parser.add_argument('-o', '--output', type=str, default="", help="API wrapper output file")
parser.add_argument('--sdk_path', type=str, default="", help="MaixPy SDK path")
parser.add_argument('--doc', type=str, default="", help="API documentation output file")
parser.add_argument('--stub', type=str, default="stub", help="stub dir")
args = parser.parse_args()

t = time.time()
Expand Down Expand Up @@ -91,11 +168,7 @@ def sort_headers(headers):
for r in rm:
headers.remove(r)

# generate API cpp file
content = generate_api_cpp(api_tree, headers)
with open(args.output, "w", encoding="utf-8") as f:
f.write(content)
print("-- Generate MaixPy C/C++ API done")
api_tree = update_py_def_from_stub_files(api_tree, args.stub)

# generate API documenation according to api_tree
print("-- Generating MaixPy API documentation")
Expand Down Expand Up @@ -126,8 +199,8 @@ def sort_headers(headers):
}
sidebar["items"].append(doc_maix_sidebar)
start_comment_template = '''
> You can use `{}` to access this module with MaixPy
> This module is generated from [MaixCDK](https://github.com/sipeed/MaixCDK)
> You can use `{}` to access this module.
'''
top_api_keys = ["maix"]
Expand Down
83 changes: 83 additions & 0 deletions components/maix/gen_api_cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
'''

import os
import argparse
import time
import sys

def generate_api_cpp(api_tree, headers, out_path = None):
content = '''
Expand Down Expand Up @@ -109,3 +112,83 @@ def gen_members(members, _code, parent_var, parent_name, parent_type, parent_nam
with open(out_path, "w", encoding="utf-8") as f:
f.write(content)
return content

def sort_headers(headers):
# read headers_priority.txt
headers_priority = []
priority_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "headers_priority.txt")
with open(priority_file, "r", encoding="utf-8") as f:
for line in f.readlines():
line = line.strip()
if line.startswith("#"):
continue
headers_priority.append(line)
# sort headers
headers = sorted(headers, key = lambda x: headers_priority.index(os.path.basename(x)) if os.path.basename(x) in headers_priority else len(headers_priority))
return headers

if __name__ == "__main__":
print("-- Generate MaixPy C/C++ API")
parser = argparse.ArgumentParser(description='Generate MaixPy C/C++ API')
parser.add_argument('--vars', type=str, default="", help="CMake global variables file")
parser.add_argument('-o', '--output', type=str, default="", help="API wrapper output file")
parser.add_argument('--sdk_path', type=str, default="", help="MaixPy SDK path")
args = parser.parse_args()

t = time.time()

sys.path.insert(0, os.path.join(args.sdk_path, "tools"))
from doc_tool.gen_api import get_headers_recursive, parse_api_from_header
from doc_tool.gen_markdown import module_to_md

# get header files
headers = []
if args.vars:
with open(args.vars, "r", encoding="utf-8") as f:
vars = json.load(f)
for include_dir in vars["includes"]:
headers += get_headers_recursive(include_dir)
else: # add sdk_path/components all .h and .hpp header files, except 3rd_party components
except_dirs = ["3rd_party"]
curr_dir = os.path.dirname(os.path.abspath(__file__))
project_components_dir = os.path.abspath(os.path.join(curr_dir, ".."))
componets_dirs = [os.path.join(args.sdk_path, "components"), project_components_dir]
for componets_dir in componets_dirs:
for root, dirs, files in os.walk(componets_dir):
ignored = False
for except_dir in except_dirs:
if os.path.join(componets_dir, except_dir) in root:
ignored = True
break
if ignored:
continue
for name in files:
path = os.path.join(root, name)
if path.endswith(".h") or path.endswith(".hpp"):
headers.append(path)
# check each header file to find MaixPy API
api_tree = {}
rm = []
all_keys = {}

headers = sort_headers(headers)

for header in headers:
api_tree, updated, keys = parse_api_from_header(header, api_tree, for_sdk = "maixpy")
if not updated:
rm.append(header)
for h, ks in all_keys.items():
for k in ks:
if k in keys:
raise Exception("API {} multiple defined in {} and {}".format(k, h, header))
all_keys[header] = keys

for r in rm:
headers.remove(r)

# generate API cpp file
content = generate_api_cpp(api_tree, headers)
with open(args.output, "w", encoding="utf-8") as f:
f.write(content)
print("-- Generate MaixPy C/C++ API done")

15 changes: 11 additions & 4 deletions docs/doc/zh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ title: MaixPy 快速开始

### 准备 TF 镜像卡和插入到设备

如果你买的套餐里面有 TF 卡,里面已经有出厂镜像了,需要先小心打开外壳(注意里面有排线连接不要扯断了),然后插入 TF 卡。
如果你买的**套餐里面有 TF 卡**,里面已经有出厂镜像了,需要先小心打开外壳(注意里面有排线连接不要扯断了),然后插入 TF 卡。
> 出厂的镜像
如果没买 TF 卡,则需要将系统烧录进自备的 TF 卡中,烧录方法请看[升级和烧录系统](./basic/os.md),然后再安装到板子。

Expand All @@ -50,8 +51,10 @@ title: MaixPy 快速开始

![maixcam](/static/image/maixcam_font.png)

> 如果屏幕没有显示,请确认购买了配套的 TF 卡,如果确认有 TF 卡,可以尝试[更新系统](./basic/os.md)
> 如果你没有购买 TF 卡套餐,你需要按照[升级和烧录系统](./basic/os.md)的方法烧录最新的系统到 TF 卡。
如果屏幕没有显示
* 请确认购买了配套的 TF 卡,如果确认有 TF 卡,并且已经插入到设备,可以**尝试[更新到最新的系统](./basic/os.md)**
* 如果你没有购买 TF 卡套餐,你需要按照[升级和烧录系统](./basic/os.md)的方法烧录最新的系统到 TF 卡。
* 另外请确认屏幕和摄像头的排线没有松动,屏幕的排线在拆开外壳时很容易脱落,需要注意。

### 联网

Expand All @@ -71,6 +74,8 @@ title: MaixPy 快速开始
* 设备上点击 `设置`(`Settings`),选择`安装运行库`
* 安装完成后可以看到更新到了最新版本,然后退出即可。

如果显示`Request failed` 或者`请求失败`,请先检查网络是否已经连接,需要能连接到互联网,如果还不行,请拍照联系客服处理即可。


### 使用内置应用

Expand All @@ -80,7 +85,9 @@ title: MaixPy 快速开始
Classifier Result video
</video>

其它的请自行摸索,以后还会更新更多应用,之后会在 [MaixHub 应用商店](https://maixhub.com/app) 更新。
其它的请自行摸索,以后还会更新更多应用,使用文档以及应用更新请看 [MaixHub 应用商店](https://maixhub.com/app)

**注意:应用只包含了 MaixPy 能实现的一部分功能,使用 MaixPy 能创造更多功能**


## 作为串口模块使用
Expand Down
9 changes: 9 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ def get_python_version():
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.copy(os.path.join(root, name), dst)

# generate api documentation
# COMMAND ${python} -u ${CMAKE_CURRENT_SOURCE_DIR}/gen_api.py -o ${maixpy_wrapper_src} --doc ${PROJECT_PATH}/docs/api --sdk_path ${SDK_PATH}
maixcdk_path = os.environ.get("MAIXCDK_PATH", None)
if not maixcdk_path:
raise Exception("No environment variable MAIXCDK_PATH, please set first by `export MAIXCDK_PATH=xxxxx`")
ret = os.system(f"python -u components/maix/gen_api.py --doc docs/api --sdk_path {maixcdk_path}")
if ret != 0:
raise Exception("Generate doc file failed")

# requirement packages
requirements = []

Expand Down

0 comments on commit f82328d

Please sign in to comment.