@@ -3351,6 +3351,95 @@ class BufferFlags(enum.IntFlag):
33513351 WRITE = 0x200
33523352
33533353
3354+ def _get_details_for_cli (module , nominal_target , resolved_target ):
3355+ # Determine if the given module name is an alias for another module,
3356+ # or if it is reexporting a name that is actually defined elsewhere
3357+ resolved_module = getmodule (resolved_target )
3358+ if resolved_module is not None and resolved_module is not module :
3359+ # Referenced target indicates it was defined somewhere else,
3360+ # so report the details of that module rather than the lookup module
3361+ module = resolved_module
3362+ reported_module_name = module .__name__
3363+ # Ensure the reported source file reflects the actual defining location
3364+ try :
3365+ source_file = getsourcefile (resolved_target )
3366+ except Exception :
3367+ try :
3368+ source_file = getsourcefile (module )
3369+ except Exception :
3370+ source_file = None
3371+ # Determine if the nominal target location is its defining location
3372+ if resolved_target is module :
3373+ reported_target = reported_module_name
3374+ else :
3375+ reported_qualname = getattr (resolved_target , "__qualname__" , None )
3376+ if not reported_qualname :
3377+ reported_qualname = nominal_target .partition (":" )[2 ]
3378+ reported_target = f"{ reported_module_name } :{ reported_qualname } "
3379+ # Special case for looking up functions in frozen modules
3380+ if source_file == f"<frozen { reported_module_name } >" :
3381+ source_file = module .__file__
3382+ # Populate the actual details to be reported
3383+ details = {
3384+ "target" : reported_target ,
3385+ "origin" : module .__spec__ .origin ,
3386+ "cached" : module .__spec__ .cached ,
3387+ "source" : source_file ,
3388+ }
3389+ if reported_target != nominal_target :
3390+ details ["alias" ] = nominal_target
3391+ error = None
3392+ if not source_file :
3393+ if module .__name__ in sys .builtin_module_names :
3394+ error = "No source code available for builtin module"
3395+ else :
3396+ error = "No source code available for defining module"
3397+ if resolved_target is module :
3398+ details ["loader" ] = repr (module .__spec__ .loader )
3399+ if hasattr (module , '__path__' ):
3400+ details ["submodule_paths" ] = str (module .__path__ )
3401+ elif source_file :
3402+ try :
3403+ __ , lineno = findsource (resolved_target )
3404+ except Exception :
3405+ error = "Failed to retrieve source code for given target"
3406+ else :
3407+ details ["lineno" ] = lineno
3408+ if error :
3409+ details ["error" ] = error
3410+ return details
3411+
3412+ def _render_details_for_cli (details ):
3413+ resolved_target = details ["target" ]
3414+ alias = details .get ("alias" )
3415+ if alias :
3416+ rendered_target = f'{ resolved_target } (looked up as "{ alias } ")'
3417+ else :
3418+ rendered_target = resolved_target
3419+ lines = [
3420+ f'Target: { rendered_target } ' ,
3421+ f'Origin: { details ["origin" ]} ' ,
3422+ f'Source: { details ["source" ]} ' ,
3423+ f'Cached: { details ["cached" ]} ' ,
3424+ ]
3425+ loader = details .get ("loader" )
3426+ if loader :
3427+ lines .append (f'Loader: { loader } ' )
3428+ submodule_paths = details .get ("submodule_paths" )
3429+ if submodule_paths :
3430+ lines .append (f'Submodule search paths: { submodule_paths } ' )
3431+ else :
3432+ error = details .get ("error" )
3433+ if error :
3434+ # The error is only informational when retrieving object details
3435+ lines .append (error )
3436+ else :
3437+ lines .append (f'Line: { details ["lineno" ]} ' )
3438+
3439+ lines .append ("" )
3440+ return "\n " .join (lines )
3441+
3442+
33543443def _main ():
33553444 """ Logic for inspecting an object given at command line """
33563445 import argparse
@@ -3367,6 +3456,8 @@ def _main():
33673456
33683457 args = parser .parse_args ()
33693458
3459+ # We don't use `pkgutil.resolve_name` here because we want to obtain
3460+ # references to both the module *and* the fully resolved target object
33703461 target = args .object
33713462 mod_name , has_attrs , attrs = target .partition (":" )
33723463 try :
@@ -3384,29 +3475,16 @@ def _main():
33843475 for part in parts :
33853476 obj = getattr (obj , part )
33863477
3387- if module .__name__ in sys .builtin_module_names :
3388- print ("Can't get info for builtin modules." , file = sys .stderr )
3389- sys .exit (1 )
3390-
3478+ details = _get_details_for_cli (module , target , obj )
33913479 if args .details :
3392- print (f'Target: { target } ' )
3393- print (f'Origin: { getsourcefile (module )} ' )
3394- print (f'Cached: { module .__spec__ .cached } ' )
3395- if obj is module :
3396- print (f'Loader: { module .__loader__ !r} ' )
3397- if hasattr (module , '__path__' ):
3398- print (f'Submodule search path: { module .__path__ } ' )
3399- else :
3400- try :
3401- __ , lineno = findsource (obj )
3402- except Exception :
3403- pass
3404- else :
3405- print (f'Line: { lineno } ' )
3406-
3407- print ()
3480+ print (_render_details_for_cli (details ))
34083481 else :
3409- print (getsource (obj ))
3482+ # Attempt to render target source details
3483+ error = details .get ("error" )
3484+ if error :
3485+ sys .exit (error )
3486+ else :
3487+ print (getsource (obj ))
34103488
34113489
34123490if __name__ == "__main__" :
0 commit comments