diff --git a/dill/_dill.py b/dill/_dill.py index 5aefe121..e398e04e 100644 --- a/dill/_dill.py +++ b/dill/_dill.py @@ -186,10 +186,11 @@ def get_file_type(*args, **kwargs): #FIXME: additionally calls ForkingPickler.register several times from multiprocessing.reduction import _reduce_socket as reduce_socket try: - __IPYTHON__ is True # is ipython + IS_IPYTHON = __IPYTHON__ # is True ExitType = None # IPython.core.autocall.ExitAutocall singletontypes = ['exit', 'quit', 'get_ipython'] except NameError: + IS_IPYTHON = False try: ExitType = type(exit) # apparently 'exit' can be removed except NameError: ExitType = None singletontypes = [] diff --git a/dill/source.py b/dill/source.py index 7e70a635..229a3575 100644 --- a/dill/source.py +++ b/dill/source.py @@ -12,7 +12,7 @@ """ Extensions to python's 'inspect' module, which can be used to retrieve information from live python objects. The methods -defined in this module are augmented to facilitate access to +defined in this module are augmented to facilitate access to source code of interactively defined functions and classes, as well as provide access to source code for objects defined in a file. @@ -29,6 +29,8 @@ ismodule, istraceback) from tokenize import TokenError +from ._dill import IS_IPYTHON + def isfrommain(obj): "check if object was built in __main__" @@ -41,7 +43,7 @@ def isfrommain(obj): def isdynamic(obj): "check if object was built in the interpreter" try: file = getfile(obj) - except TypeError: file = None + except TypeError: file = None if file == '' and isfrommain(obj): return True return False @@ -112,10 +114,32 @@ def findsource(object): module = getmodule(object) try: file = getfile(module) - except TypeError: file = None + except TypeError: file = None + is_module_main = (module and module.__name__ == '__main__' and not file) + if IS_IPYTHON and is_module_main: + #FIXME: quick fix for functions and classes in IPython interpreter + try: + file = getfile(object) + sourcefile = getsourcefile(object) + except TypeError: + if isclass(object): + for object_method in filter(isfunction, object.__dict__.values()): + # look for a method of the class + file_candidate = getfile(object_method) + if not file_candidate.startswith(' indent or spaces < 0: spaces = indent for i in range(len(lines) if all else 1): #FIXME: works... but shouldn't outdent 2nd+ lines of multiline doc @@ -498,7 +522,7 @@ def _outdent(lines, spaces=None, all=True): def outdent(code, spaces=None, all=True): '''outdent a block of code (default is to strip all leading whitespace)''' - indent = indentsize(code) + indent = indentsize(code) if spaces is None or spaces > indent or spaces < 0: spaces = indent #XXX: will this delete '\n' in some cases? if not all: return code[spaces:] @@ -554,7 +578,7 @@ def dumpsource(object, alias='', new=False, enclose=True): else: stub = alias pre = '%s = ' % stub if alias else alias - + # if a 'new' instance is not needed, then just dump and load if not new or not _isinstance(object): code += pre + 'dill.loads(%s)\n' % pik @@ -829,7 +853,7 @@ def _closuredimport(func, alias='', builtin=False): re.match(pat, line)] if not candidate: mod = getname(getmodule(fobj)) - #HACK: get file containing 'inner' function; is func there? + #HACK: get file containing 'inner' function; is func there? lines,_ = findsource(fobj) candidate = [line for line in lines \ if getname(fobj) in line and re.match(pat, line)]