使用MkDocstrings生成Markdown文件时,如何在子文件夹无__init__.py的情况下解决构建错误
使用MkDocstrings生成Markdown文件时,如何在子文件夹无__init__.py的情况下解决构建错误
我完全理解你的困扰——看着自己的项目里wrkpkg1、wrkpkg2这类不需要作为Python包的子目录,为了生成文档被迫加一堆没用的__init__.py,确实破坏了原本的结构。结合你给出的项目结构和错误信息,下面给你几个可行的解决方案:
方案1:调整gen_ref_pages.py脚本,适配无__init__.py的目录
你当前用的gen_ref_pages.py(通常是mkdocs-gen-files的默认脚本)可能依赖pkgutil.iter_modules来遍历包,这个方法会跳过没有__init__.py的目录。我们可以修改脚本,直接用文件系统遍历所有.py文件,然后把路径转换为模块名:
import os from pathlib import Path import mkdocs_gen_files # 指向你的packages目录,根据实际路径调整 root = Path(__file__).parent.parent / "packages" nav = mkdocs_gen_files.Nav() # 遍历所有.py文件 for path in sorted(root.rglob("*.py")): # 跳过缓存目录和已有的__init__.py if "__pycache__" in str(path) or path.name == "__init__.py": continue # 将文件路径转换为模块标识:packages/pkg1/subpkg1/wrkpkg1/file1.py → packages.pkg1.subpkg1.wrkpkg1.file1 module_path = path.relative_to(root).with_suffix("") doc_path = path.relative_to(root).with_suffix(".md") full_doc_path = Path("reference", doc_path) # 更新导航结构 parts = tuple(module_path.parts) nav[parts] = doc_path.as_posix() # 生成对应的文档引用文件 with mkdocs_gen_files.open(full_doc_path, "w") as fd: ident = ".".join(parts) fd.write(f"::: {ident}") # 设置编辑路径关联 mkdocs_gen_files.set_edit_path(full_doc_path, path) # 生成导航汇总文件 with mkdocs_gen_files.open("reference/summary.md", "w") as fd: fd.writelines(nav.build_literate_nav())
这个脚本会无视目录是否有__init__.py,直接遍历所有Python文件并生成对应的文档页面。
方案2:配置mkdocstrings的Griffe解析器,支持命名空间包
MkDocstrings依赖Griffe工具收集代码信息,Griffe本身支持识别Python 3.3+引入的命名空间包(无__init__.py的目录)。你可以在mkdocs.yaml中添加Griffe的相关配置:
mkdocstrings: default_handler: python handlers: python: griffe: # 启用嵌套模块识别,即使父目录无__init__.py find_nested_modules: true # 将无__init__.py的目录视为命名空间包的一部分 recognize_nested_packages: true options: # 开启子模块文档展示 show_submodules: true
配置完成后,配合方案1的脚本,就能正常收集无__init__.py目录下的模块信息了。
方案3:临时生成空__init__.py(折中方案)
如果上面的方案暂时无法生效,你可以用脚本临时生成空的__init__.py,构建完成后再删除,既不破坏原有结构,又能满足文档生成的要求:
import os from pathlib import Path import subprocess root = Path("packages") temp_init_files = [] # 生成临时__init__.py for path in root.rglob("*/"): init_path = path / "__init__.py" if not init_path.exists(): init_path.touch() temp_init_files.append(init_path) # 执行mkdocs构建 subprocess.run(["mkdocs", "build"], check=True) # 清理临时生成的__init__.py for init_file in temp_init_files: init_file.unlink()
这个方法属于应急折中,适合快速验证,但不如前两个方案优雅。
最后记得重启mkdocs服务或重新执行mkdocs build,确保配置和脚本的修改生效。
备注:内容来源于stack exchange,提问作者aniruddha das
相关产品推荐
相关产品推荐

