Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/dill/source.py: 6%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python
2#
3# Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
4# Copyright (c) 2008-2016 California Institute of Technology.
5# Copyright (c) 2016-2025 The Uncertainty Quantification Foundation.
6# License: 3-clause BSD. The full license text is available at:
7# - https://github.com/uqfoundation/dill/blob/master/LICENSE
8#
9# inspired by inspect.py from Python-2.7.6
10# inspect.py author: 'Ka-Ping Yee <ping@lfw.org>'
11# inspect.py merged into original dill.source by Mike McKerns 4/13/14
12"""
13Extensions to python's 'inspect' module, which can be used
14to retrieve information from live python objects. The methods
15defined in this module are augmented to facilitate access to
16source code of interactively defined functions and classes,
17as well as provide access to source code for objects defined
18in a file.
19"""
21__all__ = ['findsource', 'getsourcelines', 'getsource', 'indent', 'outdent', \
22 '_wrap', 'dumpsource', 'getname', '_namespace', 'getimport', \
23 '_importable', 'importable','isdynamic', 'isfrommain']
25import linecache
26import re
27from inspect import (getblock, getfile, getmodule, getsourcefile, indentsize,
28 isbuiltin, isclass, iscode, isframe, isfunction, ismethod,
29 ismodule, istraceback)
30from tokenize import TokenError
32from ._dill import IS_IPYTHON
35def isfrommain(obj):
36 "check if object was built in __main__"
37 module = getmodule(obj)
38 if module and module.__name__ == '__main__':
39 return True
40 return False
43def isdynamic(obj):
44 "check if object was built in the interpreter"
45 try: file = getfile(obj)
46 except TypeError: file = None
47 if file == '<stdin>' and isfrommain(obj):
48 return True
49 return False
52def _matchlambda(func, line):
53 """check if lambda object 'func' matches raw line of code 'line'"""
54 from .detect import code as getcode
55 from .detect import freevars, globalvars, varnames
56 dummy = lambda : '__this_is_a_big_dummy_function__'
57 # process the line (removing leading whitespace, etc)
58 lhs,rhs = line.split('lambda ',1)[-1].split(":", 1) #FIXME: if !1 inputs
59 try: #FIXME: unsafe
60 _ = eval("lambda %s : %s" % (lhs,rhs), globals(),locals())
61 except Exception: _ = dummy
62 # get code objects, for comparison
63 _, code = getcode(_).co_code, getcode(func).co_code
64 # check if func is in closure
65 _f = [line.count(i) for i in freevars(func).keys()]
66 if not _f: # not in closure
67 # check if code matches
68 if _ == code: return True
69 return False
70 # weak check on freevars
71 if not all(_f): return False #XXX: VERY WEAK
72 # weak check on varnames and globalvars
73 _f = varnames(func)
74 _f = [line.count(i) for i in _f[0]+_f[1]]
75 if _f and not all(_f): return False #XXX: VERY WEAK
76 _f = [line.count(i) for i in globalvars(func).keys()]
77 if _f and not all(_f): return False #XXX: VERY WEAK
78 # check if func is a double lambda
79 if (line.count('lambda ') > 1) and (lhs in freevars(func).keys()):
80 _lhs,_rhs = rhs.split('lambda ',1)[-1].split(":",1) #FIXME: if !1 inputs
81 try: #FIXME: unsafe
82 _f = eval("lambda %s : %s" % (_lhs,_rhs), globals(),locals())
83 except Exception: _f = dummy
84 # get code objects, for comparison
85 _, code = getcode(_f).co_code, getcode(func).co_code
86 if len(_) != len(code): return False
87 #NOTE: should be same code same order, but except for 't' and '\x88'
88 _ = set((i,j) for (i,j) in zip(_,code) if i != j)
89 if len(_) != 1: return False #('t','\x88')
90 return True
91 # check indentsize
92 if not indentsize(line): return False #FIXME: is this a good check???
93 # check if code 'pattern' matches
94 #XXX: or pattern match against dis.dis(code)? (or use uncompyle2?)
95 _ = _.split(_[0]) # 't' #XXX: remove matching values if starts the same?
96 _f = code.split(code[0]) # '\x88'
97 #NOTE: should be same code different order, with different first element
98 _ = dict(re.match(r'([\W\D\S])(.*)', _[i]).groups() for i in range(1,len(_)))
99 _f = dict(re.match(r'([\W\D\S])(.*)', _f[i]).groups() for i in range(1,len(_f)))
100 if (_.keys() == _f.keys()) and (sorted(_.values()) == sorted(_f.values())):
101 return True
102 return False
105def findsource(object):
106 """Return the entire source file and starting line number for an object.
107 For interactively-defined objects, the 'file' is the interpreter's history.
109 The argument may be a module, class, method, function, traceback, frame,
110 or code object. The source code is returned as a list of all the lines
111 in the file and the line number indexes a line in that list. An IOError
112 is raised if the source code cannot be retrieved, while a TypeError is
113 raised for objects where the source code is unavailable (e.g. builtins)."""
115 module = getmodule(object)
116 try: file = getfile(module)
117 except TypeError: file = None
118 is_module_main = (module and module.__name__ == '__main__' and not file)
119 if IS_IPYTHON and is_module_main:
120 #FIXME: quick fix for functions and classes in IPython interpreter
121 try:
122 file = getfile(object)
123 sourcefile = getsourcefile(object)
124 except TypeError:
125 if isclass(object):
126 for object_method in filter(isfunction, object.__dict__.values()):
127 # look for a method of the class
128 file_candidate = getfile(object_method)
129 if not file_candidate.startswith('<ipython-input-'):
130 continue
131 file = file_candidate
132 sourcefile = getsourcefile(object_method)
133 break
134 if file:
135 lines = linecache.getlines(file)
136 else:
137 # fallback to use history
138 history = '\n'.join(get_ipython().history_manager.input_hist_parsed)
139 lines = [line + '\n' for line in history.splitlines()]
140 # use readline when working in interpreter (i.e. __main__ and not file)
141 elif is_module_main:
142 try:
143 import readline
144 err = ''
145 except ImportError:
146 import sys
147 err = sys.exc_info()[1].args[0]
148 if sys.platform[:3] == 'win':
149 err += ", please install 'pyreadline'"
150 if err:
151 raise IOError(err)
152 lbuf = readline.get_current_history_length()
153 lines = [readline.get_history_item(i)+'\n' for i in range(1,lbuf+1)]
154 else:
155 try: # special handling for class instances
156 if not isclass(object) and isclass(type(object)): # __class__
157 file = getfile(module)
158 sourcefile = getsourcefile(module)
159 else: # builtins fail with a TypeError
160 file = getfile(object)
161 sourcefile = getsourcefile(object)
162 except (TypeError, AttributeError): # fail with better error
163 file = getfile(object)
164 sourcefile = getsourcefile(object)
165 if not sourcefile and file[:1] + file[-1:] != '<>':
166 raise IOError('source code not available')
167 file = sourcefile if sourcefile else file
169 module = getmodule(object, file)
170 if module:
171 lines = linecache.getlines(file, module.__dict__)
172 else:
173 lines = linecache.getlines(file)
175 if not lines:
176 raise IOError('could not extract source code')
178 #FIXME: all below may fail if exec used (i.e. exec('f = lambda x:x') )
179 if ismodule(object):
180 return lines, 0
182 #NOTE: beneficial if search goes from end to start of buffer history
183 name = pat1 = obj = ''
184 pat2 = r'^(\s*@)'
185# pat1b = r'^(\s*%s\W*=)' % name #FIXME: finds 'f = decorate(f)', not exec
186 if ismethod(object):
187 name = object.__name__
188 if name == '<lambda>': pat1 = r'(.*(?<!\w)lambda(:|\s))'
189 else: pat1 = r'^(\s*def\s)'
190 object = object.__func__
191 if isfunction(object):
192 name = object.__name__
193 if name == '<lambda>':
194 pat1 = r'(.*(?<!\w)lambda(:|\s))'
195 obj = object #XXX: better a copy?
196 else: pat1 = r'^(\s*def\s)'
197 object = object.__code__
198 if istraceback(object):
199 object = object.tb_frame
200 if isframe(object):
201 object = object.f_code
202 if iscode(object):
203 if not hasattr(object, 'co_firstlineno'):
204 raise IOError('could not find function definition')
205 stdin = object.co_filename == '<stdin>'
206 if stdin:
207 lnum = len(lines) - 1 # can't get lnum easily, so leverage pat
208 if not pat1: pat1 = r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)'
209 else:
210 lnum = object.co_firstlineno - 1
211 pat1 = r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)'
212 pat1 = re.compile(pat1); pat2 = re.compile(pat2)
213 #XXX: candidate_lnum = [n for n in range(lnum) if pat1.match(lines[n])]
214 while lnum > 0: #XXX: won't find decorators in <stdin> ?
215 line = lines[lnum]
216 if pat1.match(line):
217 if not stdin: break # co_firstlineno does the job
218 if name == '<lambda>': # hackery needed to confirm a match
219 if _matchlambda(obj, line): break
220 else: # not a lambda, just look for the name
221 if name in line: # need to check for decorator...
222 hats = 0
223 for _lnum in range(lnum-1,-1,-1):
224 if pat2.match(lines[_lnum]): hats += 1
225 else: break
226 lnum = lnum - hats
227 break
228 lnum = lnum - 1
229 return lines, lnum
231 try: # turn instances into classes
232 if not isclass(object) and isclass(type(object)): # __class__
233 object = object.__class__ #XXX: sometimes type(class) is better?
234 #XXX: we don't find how the instance was built
235 except AttributeError: pass
236 if isclass(object):
237 name = object.__name__
238 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
239 # make some effort to find the best matching class definition:
240 # use the one with the least indentation, which is the one
241 # that's most probably not inside a function definition.
242 candidates = []
243 for i in range(len(lines)-1,-1,-1):
244 match = pat.match(lines[i])
245 if match:
246 # if it's at toplevel, it's already the best one
247 if lines[i][0] == 'c':
248 return lines, i
249 # else add whitespace to candidate list
250 candidates.append((match.group(1), i))
251 if candidates:
252 # this will sort by whitespace, and by line number,
253 # less whitespace first #XXX: should sort high lnum before low
254 candidates.sort()
255 return lines, candidates[0][1]
256 else:
257 raise IOError('could not find class definition')
258 raise IOError('could not find code object')
261def getblocks(object, lstrip=False, enclosing=False, locate=False):
262 """Return a list of source lines and starting line number for an object.
263 Interactively-defined objects refer to lines in the interpreter's history.
265 If enclosing=True, then also return any enclosing code.
266 If lstrip=True, ensure there is no indentation in the first line of code.
267 If locate=True, then also return the line number for the block of code.
269 DEPRECATED: use 'getsourcelines' instead
270 """
271 lines, lnum = findsource(object)
273 if ismodule(object):
274 if lstrip: lines = _outdent(lines)
275 return ([lines], [0]) if locate is True else [lines]
277 #XXX: 'enclosing' means: closures only? or classes and files?
278 indent = indentsize(lines[lnum])
279 block = getblock(lines[lnum:]) #XXX: catch any TokenError here?
281 if not enclosing or not indent:
282 if lstrip: block = _outdent(block)
283 return ([block], [lnum]) if locate is True else [block]
285 pat1 = r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))'; pat1 = re.compile(pat1)
286 pat2 = r'^(\s*@)'; pat2 = re.compile(pat2)
287 #pat3 = r'^(\s*class\s)'; pat3 = re.compile(pat3) #XXX: enclosing class?
288 #FIXME: bound methods need enclosing class (and then instantiation)
289 # *or* somehow apply a partial using the instance
291 skip = 0
292 line = 0
293 blocks = []; _lnum = []
294 target = ''.join(block)
295 while line <= lnum: #XXX: repeat lnum? or until line < lnum?
296 # see if starts with ('def','lambda') and contains our target block
297 if pat1.match(lines[line]):
298 if not skip:
299 try: code = getblock(lines[line:])
300 except TokenError: code = [lines[line]]
301 if indentsize(lines[line]) > indent: #XXX: should be >= ?
302 line += len(code) - skip
303 elif target in ''.join(code):
304 blocks.append(code) # save code block as the potential winner
305 _lnum.append(line - skip) # save the line number for the match
306 line += len(code) - skip
307 else:
308 line += 1
309 skip = 0
310 # find skip: the number of consecutive decorators
311 elif pat2.match(lines[line]):
312 try: code = getblock(lines[line:])
313 except TokenError: code = [lines[line]]
314 skip = 1
315 for _line in code[1:]: # skip lines that are decorators
316 if not pat2.match(_line): break
317 skip += 1
318 line += skip
319 # no match: reset skip and go to the next line
320 else:
321 line +=1
322 skip = 0
324 if not blocks:
325 blocks = [block]
326 _lnum = [lnum]
327 if lstrip: blocks = [_outdent(block) for block in blocks]
328 # return last match
329 return (blocks, _lnum) if locate is True else blocks
332def getsourcelines(object, lstrip=False, enclosing=False):
333 """Return a list of source lines and starting line number for an object.
334 Interactively-defined objects refer to lines in the interpreter's history.
336 The argument may be a module, class, method, function, traceback, frame,
337 or code object. The source code is returned as a list of the lines
338 corresponding to the object and the line number indicates where in the
339 original source file the first line of code was found. An IOError is
340 raised if the source code cannot be retrieved, while a TypeError is
341 raised for objects where the source code is unavailable (e.g. builtins).
343 If lstrip=True, ensure there is no indentation in the first line of code.
344 If enclosing=True, then also return any enclosing code."""
345 code, n = getblocks(object, lstrip=lstrip, enclosing=enclosing, locate=True)
346 return code[-1], n[-1]
349#NOTE: broke backward compatibility 4/16/14 (was lstrip=True, force=True)
350def getsource(object, alias='', lstrip=False, enclosing=False, \
351 force=False, builtin=False):
352 """Return the text of the source code for an object. The source code for
353 interactively-defined objects are extracted from the interpreter's history.
355 The argument may be a module, class, method, function, traceback, frame,
356 or code object. The source code is returned as a single string. An
357 IOError is raised if the source code cannot be retrieved, while a
358 TypeError is raised for objects where the source code is unavailable
359 (e.g. builtins).
361 If alias is provided, then add a line of code that renames the object.
362 If lstrip=True, ensure there is no indentation in the first line of code.
363 If enclosing=True, then also return any enclosing code.
364 If force=True, catch (TypeError,IOError) and try to use import hooks.
365 If builtin=True, force an import for any builtins
366 """
367 # hascode denotes a callable
368 hascode = _hascode(object)
369 # is a class instance type (and not in builtins)
370 instance = _isinstance(object)
372 # get source lines; if fail, try to 'force' an import
373 try: # fails for builtins, and other assorted object types
374 lines, lnum = getsourcelines(object, enclosing=enclosing)
375 except (TypeError, IOError): # failed to get source, resort to import hooks
376 if not force: # don't try to get types that findsource can't get
377 raise
378 if not getmodule(object): # get things like 'None' and '1'
379 if not instance: return getimport(object, alias, builtin=builtin)
380 # special handling (numpy arrays, ...)
381 _import = getimport(object, builtin=builtin)
382 name = getname(object, force=True)
383 _alias = "%s = " % alias if alias else ""
384 if alias == name: _alias = ""
385 return _import+_alias+"%s\n" % name
386 else: #FIXME: could use a good bit of cleanup, since using getimport...
387 if not instance: return getimport(object, alias, builtin=builtin)
388 # now we are dealing with an instance...
389 name = object.__class__.__name__
390 module = object.__module__
391 if module in ['builtins','__builtin__']:
392 return getimport(object, alias, builtin=builtin)
393 else: #FIXME: leverage getimport? use 'from module import name'?
394 lines, lnum = ["%s = __import__('%s', fromlist=['%s']).%s\n" % (name,module,name,name)], 0
395 obj = eval(lines[0].lstrip(name + ' = '))
396 lines, lnum = getsourcelines(obj, enclosing=enclosing)
398 # strip leading indent (helps ensure can be imported)
399 if lstrip or alias:
400 lines = _outdent(lines)
402 # instantiate, if there's a nice repr #XXX: BAD IDEA???
403 if instance: #and force: #XXX: move into findsource or getsourcelines ?
404 if '(' in repr(object): lines.append('%r\n' % object)
405 #else: #XXX: better to somehow to leverage __reduce__ ?
406 # reconstructor,args = object.__reduce__()
407 # _ = reconstructor(*args)
408 else: # fall back to serialization #XXX: bad idea?
409 #XXX: better not duplicate work? #XXX: better new/enclose=True?
410 lines = dumpsource(object, alias='', new=force, enclose=False)
411 lines, lnum = [line+'\n' for line in lines.split('\n')][:-1], 0
412 #else: object.__code__ # raise AttributeError
414 # add an alias to the source code
415 if alias:
416 if hascode:
417 skip = 0
418 for line in lines: # skip lines that are decorators
419 if not line.startswith('@'): break
420 skip += 1
421 #XXX: use regex from findsource / getsourcelines ?
422 if lines[skip].lstrip().startswith('def '): # we have a function
423 if alias != object.__name__:
424 lines.append('\n%s = %s\n' % (alias, object.__name__))
425 elif 'lambda ' in lines[skip]: # we have a lambda
426 if alias != lines[skip].split('=')[0].strip():
427 lines[skip] = '%s = %s' % (alias, lines[skip])
428 else: # ...try to use the object's name
429 if alias != object.__name__:
430 lines.append('\n%s = %s\n' % (alias, object.__name__))
431 else: # class or class instance
432 if instance:
433 if alias != lines[-1].split('=')[0].strip():
434 lines[-1] = ('%s = ' % alias) + lines[-1]
435 else:
436 name = getname(object, force=True) or object.__name__
437 if alias != name:
438 lines.append('\n%s = %s\n' % (alias, name))
439 return ''.join(lines)
442def _hascode(object):
443 '''True if object has an attribute that stores it's __code__'''
444 return getattr(object,'__code__',None) or getattr(object,'func_code',None)
446def _isinstance(object):
447 '''True if object is a class instance type (and is not a builtin)'''
448 if _hascode(object) or isclass(object) or ismodule(object):
449 return False
450 if istraceback(object) or isframe(object) or iscode(object):
451 return False
452 # special handling (numpy arrays, ...)
453 if not getmodule(object) and getmodule(type(object)).__name__ in ['numpy']:
454 return True
455# # check if is instance of a builtin
456# if not getmodule(object) and getmodule(type(object)).__name__ in ['__builtin__','builtins']:
457# return False
458 _types = ('<class ',"<type 'instance'>")
459 if not repr(type(object)).startswith(_types): #FIXME: weak hack
460 return False
461 if not getmodule(object) or object.__module__ in ['builtins','__builtin__'] or getname(object, force=True) in ['array']:
462 return False
463 return True # by process of elimination... it's what we want
466def _intypes(object):
467 '''check if object is in the 'types' module'''
468 import types
469 # allow user to pass in object or object.__name__
470 if type(object) is not type(''):
471 object = getname(object, force=True)
472 if object == 'ellipsis': object = 'EllipsisType'
473 return True if hasattr(types, object) else False
476def _isstring(object): #XXX: isstringlike better?
477 '''check if object is a string-like type'''
478 return isinstance(object, (str, bytes))
481def indent(code, spaces=4):
482 '''indent a block of code with whitespace (default is 4 spaces)'''
483 indent = indentsize(code)
484 from numbers import Integral
485 if isinstance(spaces, Integral): spaces = ' '*spaces
486 # if '\t' is provided, will indent with a tab
487 nspaces = indentsize(spaces)
488 # blank lines (etc) need to be ignored
489 lines = code.split('\n')
490## stq = "'''"; dtq = '"""'
491## in_stq = in_dtq = False
492 for i in range(len(lines)):
493 #FIXME: works... but shouldn't indent 2nd+ lines of multiline doc
494 _indent = indentsize(lines[i])
495 if indent > _indent: continue
496 lines[i] = spaces+lines[i]
497## #FIXME: may fail when stq and dtq in same line (depends on ordering)
498## nstq, ndtq = lines[i].count(stq), lines[i].count(dtq)
499## if not in_dtq and not in_stq:
500## lines[i] = spaces+lines[i] # we indent
501## # entering a comment block
502## if nstq%2: in_stq = not in_stq
503## if ndtq%2: in_dtq = not in_dtq
504## # leaving a comment block
505## elif in_dtq and ndtq%2: in_dtq = not in_dtq
506## elif in_stq and nstq%2: in_stq = not in_stq
507## else: pass
508 if lines[-1].strip() == '': lines[-1] = ''
509 return '\n'.join(lines)
512def _outdent(lines, spaces=None, all=True):
513 '''outdent lines of code, accounting for docs and line continuations'''
514 indent = indentsize(lines[0])
515 if spaces is None or spaces > indent or spaces < 0: spaces = indent
516 for i in range(len(lines) if all else 1):
517 #FIXME: works... but shouldn't outdent 2nd+ lines of multiline doc
518 _indent = indentsize(lines[i])
519 if spaces > _indent: _spaces = _indent
520 else: _spaces = spaces
521 lines[i] = lines[i][_spaces:]
522 return lines
524def outdent(code, spaces=None, all=True):
525 '''outdent a block of code (default is to strip all leading whitespace)'''
526 indent = indentsize(code)
527 if spaces is None or spaces > indent or spaces < 0: spaces = indent
528 #XXX: will this delete '\n' in some cases?
529 if not all: return code[spaces:]
530 return '\n'.join(_outdent(code.split('\n'), spaces=spaces, all=all))
533# _wrap provides an wrapper to correctly exec and load into locals
534__globals__ = globals()
535__locals__ = locals()
536def _wrap(f):
537 """ encapsulate a function and it's __import__ """
538 def func(*args, **kwds):
539 try:
540 # _ = eval(getsource(f, force=True)) #XXX: safer but less robust
541 exec(getimportable(f, alias='_'), __globals__, __locals__)
542 except Exception:
543 raise ImportError('cannot import name ' + f.__name__)
544 return _(*args, **kwds)
545 func.__name__ = f.__name__
546 func.__doc__ = f.__doc__
547 return func
550def _enclose(object, alias=''): #FIXME: needs alias to hold returned object
551 """create a function enclosure around the source of some object"""
552 #XXX: dummy and stub should append a random string
553 dummy = '__this_is_a_big_dummy_enclosing_function__'
554 stub = '__this_is_a_stub_variable__'
555 code = 'def %s():\n' % dummy
556 code += indent(getsource(object, alias=stub, lstrip=True, force=True))
557 code += indent('return %s\n' % stub)
558 if alias: code += '%s = ' % alias
559 code += '%s(); del %s\n' % (dummy, dummy)
560 #code += "globals().pop('%s',lambda :None)()\n" % dummy
561 return code
564def dumpsource(object, alias='', new=False, enclose=True):
565 """'dump to source', where the code includes a pickled object.
567 If new=True and object is a class instance, then create a new
568 instance using the unpacked class source code. If enclose, then
569 create the object inside a function enclosure (thus minimizing
570 any global namespace pollution).
571 """
572 from dill import dumps
573 pik = repr(dumps(object))
574 code = 'import dill\n'
575 if enclose:
576 stub = '__this_is_a_stub_variable__' #XXX: *must* be same _enclose.stub
577 pre = '%s = ' % stub
578 new = False #FIXME: new=True doesn't work with enclose=True
579 else:
580 stub = alias
581 pre = '%s = ' % stub if alias else alias
583 # if a 'new' instance is not needed, then just dump and load
584 if not new or not _isinstance(object):
585 code += pre + 'dill.loads(%s)\n' % pik
586 else: #XXX: other cases where source code is needed???
587 code += getsource(object.__class__, alias='', lstrip=True, force=True)
588 mod = repr(object.__module__) # should have a module (no builtins here)
589 code += pre + 'dill.loads(%s.replace(b%s,bytes(__name__,"UTF-8")))\n' % (pik,mod)
590 #code += 'del %s' % object.__class__.__name__ #NOTE: kills any existing!
592 if enclose:
593 # generation of the 'enclosure'
594 dummy = '__this_is_a_big_dummy_object__'
595 dummy = _enclose(dummy, alias=alias)
596 # hack to replace the 'dummy' with the 'real' code
597 dummy = dummy.split('\n')
598 code = dummy[0]+'\n' + indent(code) + '\n'.join(dummy[-3:])
600 return code #XXX: better 'dumpsourcelines', returning list of lines?
603def getname(obj, force=False, fqn=False): #XXX: throw(?) to raise error on fail?
604 """get the name of the object. for lambdas, get the name of the pointer """
605 if fqn: return '.'.join(_namespace(obj)) #NOTE: returns 'type'
606 module = getmodule(obj)
607 if not module: # things like "None" and "1"
608 if not force: return None #NOTE: returns 'instance' NOT 'type' #FIXME?
609 # handle some special cases
610 if hasattr(obj, 'dtype') and not obj.shape:
611 return getname(obj.__class__) + "(" + repr(obj.tolist()) + ")"
612 return repr(obj)
613 try:
614 #XXX: 'wrong' for decorators and curried functions ?
615 # if obj.func_closure: ...use logic from getimportable, etc ?
616 name = obj.__name__
617 if name == '<lambda>':
618 return getsource(obj).split('=',1)[0].strip()
619 # handle some special cases
620 if module.__name__ in ['builtins','__builtin__']:
621 if name == 'ellipsis': name = 'EllipsisType'
622 return name
623 except AttributeError: #XXX: better to just throw AttributeError ?
624 if not force: return None
625 name = repr(obj)
626 if name.startswith('<'): # or name.split('('):
627 return None
628 return name
631def _namespace(obj):
632 """_namespace(obj); return namespace hierarchy (as a list of names)
633 for the given object. For an instance, find the class hierarchy.
635 For example:
637 >>> from functools import partial
638 >>> p = partial(int, base=2)
639 >>> _namespace(p)
640 [\'functools\', \'partial\']
641 """
642 # mostly for functions and modules and such
643 #FIXME: 'wrong' for decorators and curried functions
644 try: #XXX: needs some work and testing on different types
645 module = qual = str(getmodule(obj)).split()[1].strip('>').strip('"').strip("'")
646 qual = qual.split('.')
647 if ismodule(obj):
648 return qual
649 # get name of a lambda, function, etc
650 name = getname(obj) or obj.__name__ # failing, raise AttributeError
651 # check special cases (NoneType, ...)
652 if module in ['builtins','__builtin__']: # BuiltinFunctionType
653 if _intypes(name): return ['types'] + [name]
654 return qual + [name] #XXX: can be wrong for some aliased objects
655 except Exception: pass
656 # special case: numpy.inf and numpy.nan (we don't want them as floats)
657 if str(obj) in ['inf','nan','Inf','NaN']: # is more, but are they needed?
658 return ['numpy'] + [str(obj)]
659 # mostly for classes and class instances and such
660 module = getattr(obj.__class__, '__module__', None)
661 qual = str(obj.__class__)
662 try: qual = qual[qual.index("'")+1:-2]
663 except ValueError: pass # str(obj.__class__) made the 'try' unnecessary
664 qual = qual.split(".")
665 if module in ['builtins','__builtin__']:
666 # check special cases (NoneType, Ellipsis, ...)
667 if qual[-1] == 'ellipsis': qual[-1] = 'EllipsisType'
668 if _intypes(qual[-1]): module = 'types' #XXX: BuiltinFunctionType
669 qual = [module] + qual
670 return qual
673#NOTE: 05/25/14 broke backward compatibility: added 'alias' as 3rd argument
674def _getimport(head, tail, alias='', verify=True, builtin=False):
675 """helper to build a likely import string from head and tail of namespace.
676 ('head','tail') are used in the following context: "from head import tail"
678 If verify=True, then test the import string before returning it.
679 If builtin=True, then force an import for builtins where possible.
680 If alias is provided, then rename the object on import.
681 """
682 # special handling for a few common types
683 if tail in ['Ellipsis', 'NotImplemented'] and head in ['types']:
684 head = len.__module__
685 elif tail in ['None'] and head in ['types']:
686 _alias = '%s = ' % alias if alias else ''
687 if alias == tail: _alias = ''
688 return _alias+'%s\n' % tail
689 # we don't need to import from builtins, so return ''
690# elif tail in ['NoneType','int','float','long','complex']: return '' #XXX: ?
691 if head in ['builtins','__builtin__']:
692 # special cases (NoneType, Ellipsis, ...) #XXX: BuiltinFunctionType
693 if tail == 'ellipsis': tail = 'EllipsisType'
694 if _intypes(tail): head = 'types'
695 elif not builtin:
696 _alias = '%s = ' % alias if alias else ''
697 if alias == tail: _alias = ''
698 return _alias+'%s\n' % tail
699 else: pass # handle builtins below
700 # get likely import string
701 if not head: _str = "import %s" % tail
702 else: _str = "from %s import %s" % (head, tail)
703 _alias = " as %s\n" % alias if alias else "\n"
704 if alias == tail: _alias = "\n"
705 _str += _alias
706 # FIXME: fails on most decorators, currying, and such...
707 # (could look for magic __wrapped__ or __func__ attr)
708 # (could fix in 'namespace' to check obj for closure)
709 if verify and not head.startswith('dill.'):# weird behavior for dill
710 #print(_str)
711 try: exec(_str) #XXX: check if == obj? (name collision)
712 except ImportError: #XXX: better top-down or bottom-up recursion?
713 _head = head.rsplit(".",1)[0] #(or get all, then compare == obj?)
714 if not _head: raise
715 if _head != head:
716 _str = _getimport(_head, tail, alias, verify)
717 return _str
720#XXX: rename builtin to force? vice versa? verify to force? (as in getsource)
721#NOTE: 05/25/14 broke backward compatibility: added 'alias' as 2nd argument
722def getimport(obj, alias='', verify=True, builtin=False, enclosing=False):
723 """get the likely import string for the given object
725 obj is the object to inspect
726 If verify=True, then test the import string before returning it.
727 If builtin=True, then force an import for builtins where possible.
728 If enclosing=True, get the import for the outermost enclosing callable.
729 If alias is provided, then rename the object on import.
730 """
731 if enclosing:
732 from .detect import outermost
733 _obj = outermost(obj)
734 obj = _obj if _obj else obj
735 # get the namespace
736 qual = _namespace(obj)
737 head = '.'.join(qual[:-1])
738 tail = qual[-1]
739 # for named things... with a nice repr #XXX: move into _namespace?
740 try: # look for '<...>' and be mindful it might be in lists, dicts, etc...
741 name = repr(obj).split('<',1)[1].split('>',1)[1]
742 name = None # we have a 'object'-style repr
743 except Exception: # it's probably something 'importable'
744 if head in ['builtins','__builtin__']:
745 name = repr(obj) #XXX: catch [1,2], (1,2), set([1,2])... others?
746 elif _isinstance(obj):
747 name = getname(obj, force=True).split('(')[0]
748 else:
749 name = repr(obj).split('(')[0]
750 #if not repr(obj).startswith('<'): name = repr(obj).split('(')[0]
751 #else: name = None
752 if name: # try using name instead of tail
753 try: return _getimport(head, name, alias, verify, builtin)
754 except ImportError: pass
755 except SyntaxError:
756 if head in ['builtins','__builtin__']:
757 _alias = '%s = ' % alias if alias else ''
758 if alias == name: _alias = ''
759 return _alias+'%s\n' % name
760 else: pass
761 try:
762 #if type(obj) is type(abs): _builtin = builtin # BuiltinFunctionType
763 #else: _builtin = False
764 return _getimport(head, tail, alias, verify, builtin)
765 except ImportError:
766 raise # could do some checking against obj
767 except SyntaxError:
768 if head in ['builtins','__builtin__']:
769 _alias = '%s = ' % alias if alias else ''
770 if alias == tail: _alias = ''
771 return _alias+'%s\n' % tail
772 raise # could do some checking against obj
775def _importable(obj, alias='', source=None, enclosing=False, force=True, \
776 builtin=True, lstrip=True):
777 """get an import string (or the source code) for the given object
779 This function will attempt to discover the name of the object, or the repr
780 of the object, or the source code for the object. To attempt to force
781 discovery of the source code, use source=True, to attempt to force the
782 use of an import, use source=False; otherwise an import will be sought
783 for objects not defined in __main__. The intent is to build a string
784 that can be imported from a python file. obj is the object to inspect.
785 If alias is provided, then rename the object with the given alias.
787 If source=True, use these options:
788 If enclosing=True, then also return any enclosing code.
789 If force=True, catch (TypeError,IOError) and try to use import hooks.
790 If lstrip=True, ensure there is no indentation in the first line of code.
792 If source=False, use these options:
793 If enclosing=True, get the import for the outermost enclosing callable.
794 If force=True, then don't test the import string before returning it.
795 If builtin=True, then force an import for builtins where possible.
796 """
797 if source is None:
798 source = True if isfrommain(obj) else False
799 if source: # first try to get the source
800 try:
801 return getsource(obj, alias, enclosing=enclosing, \
802 force=force, lstrip=lstrip, builtin=builtin)
803 except Exception: pass
804 try:
805 if not _isinstance(obj):
806 return getimport(obj, alias, enclosing=enclosing, \
807 verify=(not force), builtin=builtin)
808 # first 'get the import', then 'get the instance'
809 _import = getimport(obj, enclosing=enclosing, \
810 verify=(not force), builtin=builtin)
811 name = getname(obj, force=True)
812 if not name:
813 raise AttributeError("object has no atribute '__name__'")
814 _alias = "%s = " % alias if alias else ""
815 if alias == name: _alias = ""
816 return _import+_alias+"%s\n" % name
818 except Exception: pass
819 if not source: # try getsource, only if it hasn't been tried yet
820 try:
821 return getsource(obj, alias, enclosing=enclosing, \
822 force=force, lstrip=lstrip, builtin=builtin)
823 except Exception: pass
824 # get the name (of functions, lambdas, and classes)
825 # or hope that obj can be built from the __repr__
826 #XXX: what to do about class instances and such?
827 obj = getname(obj, force=force)
828 # we either have __repr__ or __name__ (or None)
829 if not obj or obj.startswith('<'):
830 raise AttributeError("object has no atribute '__name__'")
831 _alias = '%s = ' % alias if alias else ''
832 if alias == obj: _alias = ''
833 return _alias+'%s\n' % obj
834 #XXX: possible failsafe... (for example, for instances when source=False)
835 # "import dill; result = dill.loads(<pickled_object>); # repr(<object>)"
837def _closuredimport(func, alias='', builtin=False):
838 """get import for closured objects; return a dict of 'name' and 'import'"""
839 import re
840 from .detect import freevars, outermost
841 free_vars = freevars(func)
842 func_vars = {}
843 # split into 'funcs' and 'non-funcs'
844 for name,obj in list(free_vars.items()):
845 if not isfunction(obj): continue
846 # get import for 'funcs'
847 fobj = free_vars.pop(name)
848 src = getsource(fobj)
849 if src.lstrip().startswith('@'): # we have a decorator
850 src = getimport(fobj, alias=alias, builtin=builtin)
851 else: # we have to "hack" a bit... and maybe be lucky
852 encl = outermost(func)
853 # pattern: 'func = enclosing(fobj'
854 pat = r'.*[\w\s]=\s*'+getname(encl)+r'\('+getname(fobj)
855 mod = getname(getmodule(encl))
856 #HACK: get file containing 'outer' function; is func there?
857 lines,_ = findsource(encl)
858 candidate = [line for line in lines if getname(encl) in line and \
859 re.match(pat, line)]
860 if not candidate:
861 mod = getname(getmodule(fobj))
862 #HACK: get file containing 'inner' function; is func there?
863 lines,_ = findsource(fobj)
864 candidate = [line for line in lines \
865 if getname(fobj) in line and re.match(pat, line)]
866 if not len(candidate): raise TypeError('import could not be found')
867 candidate = candidate[-1]
868 name = candidate.split('=',1)[0].split()[-1].strip()
869 src = _getimport(mod, name, alias=alias, builtin=builtin)
870 func_vars[name] = src
871 if not func_vars:
872 name = outermost(func)
873 mod = getname(getmodule(name))
874 if not mod or name is func: # then it can be handled by getimport
875 name = getname(func, force=True) #XXX: better key?
876 src = getimport(func, alias=alias, builtin=builtin)
877 else:
878 lines,_ = findsource(name)
879 # pattern: 'func = enclosing('
880 candidate = [line for line in lines if getname(name) in line and \
881 re.match(r'.*[\w\s]=\s*'+getname(name)+r'\(', line)]
882 if not len(candidate): raise TypeError('import could not be found')
883 candidate = candidate[-1]
884 name = candidate.split('=',1)[0].split()[-1].strip()
885 src = _getimport(mod, name, alias=alias, builtin=builtin)
886 func_vars[name] = src
887 return func_vars
889#XXX: should be able to use __qualname__
890def _closuredsource(func, alias=''):
891 """get source code for closured objects; return a dict of 'name'
892 and 'code blocks'"""
893 #FIXME: this entire function is a messy messy HACK
894 # - pollutes global namespace
895 # - fails if name of freevars are reused
896 # - can unnecessarily duplicate function code
897 from .detect import freevars
898 free_vars = freevars(func)
899 func_vars = {}
900 # split into 'funcs' and 'non-funcs'
901 for name,obj in list(free_vars.items()):
902 if not isfunction(obj):
903 # get source for 'non-funcs'
904 free_vars[name] = getsource(obj, force=True, alias=name)
905 continue
906 # get source for 'funcs'
907 fobj = free_vars.pop(name)
908 src = getsource(fobj, alias) # DO NOT include dependencies
909 # if source doesn't start with '@', use name as the alias
910 if not src.lstrip().startswith('@'): #FIXME: 'enclose' in dummy;
911 src = importable(fobj,alias=name)# wrong ref 'name'
912 org = getsource(func, alias, enclosing=False, lstrip=True)
913 src = (src, org) # undecorated first, then target
914 else: #NOTE: reproduces the code!
915 org = getsource(func, enclosing=True, lstrip=False)
916 src = importable(fobj, alias, source=True) # include dependencies
917 src = (org, src) # target first, then decorated
918 func_vars[name] = src
919 src = ''.join(free_vars.values())
920 if not func_vars: #FIXME: 'enclose' in dummy; wrong ref 'name'
921 org = getsource(func, alias, force=True, enclosing=False, lstrip=True)
922 src = (src, org) # variables first, then target
923 else:
924 src = (src, None) # just variables (better '' instead of None?)
925 func_vars[None] = src
926 # FIXME: remove duplicates (however, order is important...)
927 return func_vars
929def importable(obj, alias='', source=None, builtin=True):
930 """get an importable string (i.e. source code or the import string)
931 for the given object, including any required objects from the enclosing
932 and global scope
934 This function will attempt to discover the name of the object, or the repr
935 of the object, or the source code for the object. To attempt to force
936 discovery of the source code, use source=True, to attempt to force the
937 use of an import, use source=False; otherwise an import will be sought
938 for objects not defined in __main__. The intent is to build a string
939 that can be imported from a python file.
941 obj is the object to inspect. If alias is provided, then rename the
942 object with the given alias. If builtin=True, then force an import for
943 builtins where possible.
944 """
945 #NOTE: we always 'force', and 'lstrip' as necessary
946 #NOTE: for 'enclosing', use importable(outermost(obj))
947 if source is None:
948 source = True if isfrommain(obj) else False
949 elif builtin and isbuiltin(obj):
950 source = False
951 tried_source = tried_import = False
952 while True:
953 if not source: # we want an import
954 try:
955 if _isinstance(obj): # for instances, punt to _importable
956 return _importable(obj, alias, source=False, builtin=builtin)
957 src = _closuredimport(obj, alias=alias, builtin=builtin)
958 if len(src) == 0:
959 raise NotImplementedError('not implemented')
960 if len(src) > 1:
961 raise NotImplementedError('not implemented')
962 return list(src.values())[0]
963 except Exception:
964 if tried_source: raise
965 tried_import = True
966 # we want the source
967 try:
968 src = _closuredsource(obj, alias=alias)
969 if len(src) == 0:
970 raise NotImplementedError('not implemented')
971 # groan... an inline code stitcher
972 def _code_stitcher(block):
973 "stitch together the strings in tuple 'block'"
974 if block[0] and block[-1]: block = '\n'.join(block)
975 elif block[0]: block = block[0]
976 elif block[-1]: block = block[-1]
977 else: block = ''
978 return block
979 # get free_vars first
980 _src = _code_stitcher(src.pop(None))
981 _src = [_src] if _src else []
982 # get func_vars
983 for xxx in src.values():
984 xxx = _code_stitcher(xxx)
985 if xxx: _src.append(xxx)
986 # make a single source string
987 if not len(_src):
988 src = ''
989 elif len(_src) == 1:
990 src = _src[0]
991 else:
992 src = '\n'.join(_src)
993 # get source code of objects referred to by obj in global scope
994 from .detect import globalvars
995 obj = globalvars(obj) #XXX: don't worry about alias? recurse? etc?
996 obj = list(getsource(_obj,name,force=True) for (name,_obj) in obj.items() if not isbuiltin(_obj))
997 obj = '\n'.join(obj) if obj else ''
998 # combine all referred-to source (global then enclosing)
999 if not obj: return src
1000 if not src: return obj
1001 return obj + src
1002 except Exception:
1003 if tried_import: raise
1004 tried_source = True
1005 source = not source
1006 # should never get here
1007 return
1010# backward compatibility
1011def getimportable(obj, alias='', byname=True, explicit=False):
1012 return importable(obj,alias,source=(not byname),builtin=explicit)
1013 #return outdent(_importable(obj,alias,source=(not byname),builtin=explicit))
1014def likely_import(obj, passive=False, explicit=False):
1015 return getimport(obj, verify=(not passive), builtin=explicit)
1016def _likely_import(first, last, passive=False, explicit=True):
1017 return _getimport(first, last, verify=(not passive), builtin=explicit)
1018_get_name = getname
1019getblocks_from_history = getblocks
1023# EOF