88import pkgutil
99import re
1010import subprocess
11+ import sys
1112import types
1213from dataclasses import dataclass , is_dataclass
1314from enum import Enum
@@ -1264,25 +1265,41 @@ def generate_docs(
12641265
12651266 for path in paths : # lgtm [py/non-iterable-in-for-loop]
12661267 if os .path .isdir (path ):
1268+ path = os .path .abspath (path )
12671269 if validate and subprocess .call (f"{ pydocstyle_cmd } { path } " , shell = True ) > 0 :
12681270 raise Exception (f"Validation for { path } failed." )
12691271
12701272 if not stdout_mode :
12711273 print (f"Generating docs for python package at: { path } " )
12721274
1275+ # Work around for relative imports in top level modules
1276+ # requires adding parent directory to sys path for parent package resolution
1277+ parent_dir , basename = os .path .split (path )
1278+ if parent_dir not in sys .path :
1279+ sys .path .append (parent_dir )
1280+
12731281 # Generate one file for every discovered module
1274- for loader , module_name , _ in pkgutil .walk_packages ([path ]):
1282+ for loader , module_name , _ in pkgutil .walk_packages ([path ],
1283+ # prefix=f"{basename}."
1284+ ):
12751285 if _is_module_ignored (module_name , ignored_modules , private_modules ):
12761286 # Add module to ignore list, so submodule will also be ignored
12771287 ignored_modules .append (module_name )
12781288 continue
1289+ full_module_name = f"{ basename } .{ module_name } "
12791290 try :
12801291 try :
1281- mod_spec = importlib .util .spec_from_loader (module_name , loader )
1292+ mod_spec = loader .find_spec (module_name )
1293+ # Use full module name as workaround for relative imports
1294+ # in top level modules, not required if using walk_package prefix
1295+ if not mod_spec .parent :
1296+ mod_spec = loader .find_spec (full_module_name )
12821297 mod = importlib .util .module_from_spec (mod_spec )
1298+ if mod .__name__ not in sys .modules :
1299+ sys .modules [mod .__name__ ] = mod # Add module to current namespace
12831300 mod_spec .loader .exec_module (mod )
12841301 except AttributeError :
1285- # For older python version compatibility
1302+ # For older python <= 3.4 version compatibility
12861303 mod = loader .find_module (module_name ).load_module (module_name ) # type: ignore
12871304 module_md = generator .module2md (mod , is_mdx = is_mdx , include_toc = include_toc )
12881305 if not module_md :
@@ -1296,7 +1313,7 @@ def generate_docs(
12961313 else :
12971314 to_md_file (
12981315 module_md ,
1299- mod .__name__ ,
1316+ module_name , # Alt to mod.__name__ to be top level package agnostic
13001317 out_path = output_path ,
13011318 watermark = watermark ,
13021319 is_mdx = is_mdx ,
@@ -1306,21 +1323,32 @@ def generate_docs(
13061323 f"Failed to generate docs for module { module_name } : " + repr (ex )
13071324 )
13081325 elif os .path .isfile (path ):
1326+ path = os .path .abspath (path )
13091327 if validate and subprocess .call (f"{ pydocstyle_cmd } { path } " , shell = True ) > 0 :
13101328 raise Exception (f"Validation for { path } failed." )
13111329
13121330 if not stdout_mode :
13131331 print (f"Generating docs for python module at: { path } " )
13141332
1315- module_name = os .path .basename (path )
1333+ # Work around for relative imports usage in top level modules
1334+ # requires adding parent directory to sys path for parent package resolution
1335+ src_dir , filename = os .path .split (path )
1336+ parent_dir = os .path .dirname (src_dir )
1337+ if parent_dir not in sys .path :
1338+ sys .path .append (parent_dir )
1339+
1340+ module_name , _ = os .path .splitext (filename )
1341+ full_module_name = f"{ os .path .basename (src_dir )} .{ module_name } "
13161342
1317- spec = importlib .util .spec_from_file_location (
1318- module_name ,
1343+ mod_spec = importlib .util .spec_from_file_location (
1344+ full_module_name ,
13191345 path ,
13201346 )
1321- assert spec is not None
1322- mod = importlib .util .module_from_spec (spec )
1323- spec .loader .exec_module (mod ) # type: ignore
1347+ assert mod_spec is not None
1348+ mod = importlib .util .module_from_spec (mod_spec )
1349+ if mod .__name__ not in sys .modules :
1350+ sys .modules [mod .__name__ ] = mod # Add module to current namespace
1351+ mod_spec .loader .exec_module (mod ) # type: ignore
13241352
13251353 if mod :
13261354 module_md = generator .module2md (mod , is_mdx = is_mdx , include_toc = include_toc )
@@ -1362,11 +1390,13 @@ def generate_docs(
13621390
13631391 try :
13641392 try :
1365- mod_spec = importlib . util . spec_from_loader (module_name , loader )
1393+ mod_spec = loader . find_spec (module_name )
13661394 mod = importlib .util .module_from_spec (mod_spec )
1395+ if mod .__name__ not in sys .modules :
1396+ sys .modules [mod .__name__ ] = mod # Add module to current namespace
13671397 mod_spec .loader .exec_module (mod )
13681398 except AttributeError :
1369- # For older python version compatibility
1399+ # For older python <= 3.4 version compatibility
13701400 mod = loader .find_module (module_name ).load_module (module_name ) # type: ignore
13711401 module_md = generator .module2md (mod , is_mdx = is_mdx , include_toc = include_toc )
13721402
0 commit comments