def decorate(func, caller, signature=None): """Decorate func with caller.""" if signature is not None: argnames, varargs, kwargs, defaults = signature else: argnames, varargs, kwargs, defaults = getargspec(func) if defaults is None: defaults = () parameters = formatargspec(argnames, varargs, kwargs, defaults)[1:-1] defval = itertools.count(len(argnames)-len(defaults)) args = formatargspec(argnames, varargs, kwargs, defaults, formatvalue=lambda value:"=%s" % ( argnames[defval.next()]))[1:-1] func_str = """ def %s(%s): return caller(func, %s) """ % (func.__name__, parameters, args) exec_dict = dict(func=func, caller=caller) exec func_str in exec_dict newfunc = exec_dict[func.__name__] newfunc.__doc__ = func.__doc__ newfunc.__dict__ = func.__dict__.copy() newfunc.__module__ = func.__module__ if hasattr(func, "__composition__"): newfunc.__composition__ = copy(func.__composition__) else: newfunc.__composition__ = [func] newfunc.__composition__.append(newfunc) return newfunc
def switchpoint(func): """Mark *func* as a switchpoint. Use this function as a decorator to mark any method or function that may call :meth:`Hub.switch`:: @switchpoint def myfunc(): # May call Hub.switch here pass You only need to mark methods and functions that invoke :meth:`Hub.switch` directly, not via intermediate callables. """ name = func.__name__ doc = func.__doc__ or '' if not doc.endswith('*This method is a switchpoint.*\n'): indent = [len(list(itertools.takewhile(str.isspace, line))) for line in doc.splitlines() if line and not line.isspace()] indent = indent[0] if len(indent) == 1 else min(indent[1:] or [0]) doc += '\n\n' + ' ' * indent + '*This method is a switchpoint.*\n' argspec = inspect.getargspec(func) signature = inspect.formatargspec(*argspec) arglist = inspect.formatargspec(*argspec, formatvalue=lambda x: '') funcdef = _switchpoint_template.format(name=name, signature=signature, docstring=doc, arglist=arglist) namespace = {'get_hub': get_hub, 'getcurrent': fibers.current, '_{0}'.format(name): func} compat.exec_(funcdef, namespace) return namespace[name]
def decorate(f): argspec = inspect.getargspec(func) args_call = inspect.formatargspec(argspec[0]) argspec = inspect.formatargspec(argspec[0], defaults=argspec[3]) argspec = argspec.lstrip("(").rstrip(")") wrap = eval("lambda %s: f%s" % (argspec, args_call), locals()) return functools.wraps(func)(wrap)
def _method_to_func(name, method, factory): """ Creates a procedural variant of *method* on the instance returned by calling *factory*. """ template = """\ def {name}{defargs}: return {factory}().{name}{callargs}""" spec = inspect.getargspec(method) defargs = inspect.formatargspec(spec.args[1:], spec.varargs, spec.keywords, spec.defaults) callargs = inspect.formatargspec(spec.args[1:], spec.varargs, spec.keywords, ()) exec(template.format( name=name, defargs=defargs, callargs=callargs, factory=factory.__name__, ), globals()) # If the method has a doc-string, copy it to the new function ... but only # when the method isn't an alias (name==method.__name__) or we're not # building the picraft docs (in which we don't want to repeat all the docs # for the aliases) if method.__doc__ is not None: if 'PICRAFTDOCS' not in os.environ or name == method.__name__: # Replace "turtle." in all the examples with a blank string globals()[name].__doc__ = re.sub( r'^( *(?:>>>|\.\.\.).*)turtle\.', r'\1', method.__doc__, flags=re.MULTILINE)
def _wrap_higher_order(func, test): # NOTE: builtin housekeeping: # map(None, ...) is much faster than map(identity, ...), # also map(None, ...) works as zip() for multiple seqs builtin = PY2 and func in set([map, filter, imap, ifilter, ifilterfalse]) # We are going to construct function using eval to preserve signature. # So we need to inspect it first. try: spec = getargspec(func) except TypeError: spec = ArgSpec(('f',), 'seqs', None, None) # HACK: due to bug in python 3.4 - http://bugs.python.org/issue22203 if not spec.args: spec = ArgSpec(('f',), 'seqs', None, None) # Slicing with [1:-1] to get rid of parentheses spec_str = formatargspec(*spec)[1:-1] rest = ArgSpec(spec.args[1:], *spec[1:]) rest_str = formatargspec(*rest)[1:-1] # We use nested lambda to make func and make_func locals which are faster func_str = "lambda __func, __make_func: " \ "lambda {spec}: __func(__make_func({f}, {builtin}, {test}), {rest})" \ .format(spec=spec_str, f=spec.args[0], rest=rest_str, builtin=builtin, test=test) wrapper = eval(func_str, {}, {})(func, make_func) return wraps(func)(wrapper)
def adapter(fn): spec = list(inspect.getargspec(sigfn)) if dropargs is not None: posargs = [arg for i, arg in enumerate(spec[0]) if i not in dropargs and arg not in dropargs] if len(spec) >= 4 and spec[3]: odefs = spec[3] nodefs = len(spec[0]) - len(odefs) defs = [odefs[i] for i, arg in enumerate(spec[0][-len(odefs):]) if i + nodefs not in dropargs and arg not in dropargs] else: defs = [] spec = [posargs, spec[1], spec[2], defs] fargs = inspect.formatargspec(*spec) fargs = fargs.lstrip("(").rstrip(")") bfargs = inspect.formatargspec(*(spec[:3])) # eval is the only way to preserve function signature # prior to PEP 362 included in py3.3 # (note that bfargs needs to drop any default values for arguments) l = "lambda %s: fn%s" % (fargs, bfargs) fn = eval(l, dict(fn=fn)) functools.update_wrapper(fn, sigfn) if name is not None: fn.__name__ = name return fn
def csrf_only(wrapped): args, varargs, kwargs, defaults = inspect.getargspec(wrapped) if 'REQUEST' not in args: raise ValueError("Method doesn't name request") r_index = args.index('REQUEST') arglen = len(args) if defaults is not None: defaults = zip(args[arglen - len(defaults):], defaults) arglen -= len(defaults) spec = (args, varargs, kwargs, defaults) argspec = inspect.formatargspec(formatvalue=lambda v: '=None', *spec) callargs = inspect.formatargspec(formatvalue=lambda v: '', *spec) lines = ['def wrapper' + argspec + ':', ' if IBrowserRequest.providedBy(REQUEST):', ' checkCSRFToken(REQUEST)', ' return wrapped(' + ','.join(args) + ')', ] g = globals().copy() l = locals().copy() g['wrapped'] = wrapped exec '\n'.join(lines) in g, l return functools.wraps(wrapped)(l['wrapper'])
def run(self, args): proc = self.proc arg = proc.cmd_argstr try: if not proc.curframe: # ?? Should we have set up a dummy globals # to have persistence? value = eval(arg, None, None) else: value = eval(arg, proc.curframe.f_globals, proc.curframe.f_locals) except: t, v = sys.exc_info()[:2] if type(t) == str: exc_type_name = t else: exc_type_name = t.__name__ if exc_type_name == 'NameError': self.errmsg("Name Error: %s" % arg) else: self.errmsg("%s: %s" % (exc_type_name, proc._saferepr(v))) return False self.section("What is for %s" % arg) get_doc = False if inspect.ismethod(value): get_doc = True self.msg('method %s%s' % (value.func_code.co_name, inspect.formatargspec(inspect.getargspec(value)))) elif inspect.isfunction(value): get_doc = True self.msg('function %s%s' % (value.func_code.co_name, inspect.formatargspec(inspect.getargspec(value)))) elif inspect.isabstract(value) or \ inspect.isbuiltin(value) or \ inspect.isclass(value) or \ inspect.isgeneratorfunction(value) or \ inspect.ismethoddescriptor(value): get_doc = True self.msg(type(value)) doc = inspect.getdoc(value) if get_doc and doc: self.msg(' doc:\n%s' % doc) comments = inspect.getcomments(value) if comments: self.msg(' comments:\n%s' % comments) try: m = inspect.getmodule(value) if m: self.msg(" module:\t%s" % m) except: try: f = inspect.getfile(value) self.msg(" file: %s" % f) except: pass pass return False
def monkeypatch_proxied_specials(into_cls, from_cls, skip=None, only=None, name='self.proxy', from_instance=None): """Automates delegation of __specials__ for a proxying type.""" if only: dunders = only else: if skip is None: skip = ('__slots__', '__del__', '__getattribute__', '__metaclass__', '__getstate__', '__setstate__') dunders = [m for m in dir(from_cls) if (m.startswith('__') and m.endswith('__') and not hasattr(into_cls, m) and m not in skip)] for method in dunders: try: spec = inspect.getargspec(getattr(from_cls, method)) fn_args = inspect.formatargspec(spec[0]) d_args = inspect.formatargspec(spec[0][1:]) except TypeError: fn_args = '(self, *args, **kw)' d_args = '(*args, **kw)' py = ("def %(method)s%(fn_args)s: " "return %(name)s.%(method)s%(d_args)s" % locals()) env = from_instance is not None and {name: from_instance} or {} exec py in env setattr(into_cls, method, env[method])
def rearrange_args_for_tornado(function): ''' Tornado's gen.Task(...) code expects a callback to be keyword-specifiable and at the end of the function def. We have the opposite form. So use inspect to generate named functions with named arguments that have callback as a default of None (at the end). In order to make the closure reference 'function', we have to make a function that defines the true re-arranged function that we want. ''' argspec = inspect.getargspec(function) original_args = inspect.getargspec(function) original_args.args.remove('self') fixed_args = argspec.args fixed_args.remove('callback') fixed_args.remove('self') func_def = \ "def wrapped{0}: return function{1}".format( inspect.formatargspec( fixed_args + ['callback'], argspec.varargs, argspec.keywords, (argspec.defaults or ()) + (None,)), inspect.formatargspec(*original_args)) func_maker_body = \ ("def make_fn(function):\n {0}\n " "return functools.wraps(function)(wrapped)").format(func_def) namespace = {'functools': functools} exec(func_maker_body, namespace) wrapped_func = namespace['make_fn'](function) return wrapped_func
def identical_signature_wrapper(original_function, wrapped_function): ''' Return a function with identical signature as ``original_function``'s which will call the ``wrapped_function``. ''' context = {'__wrapped__': wrapped_function} function_def = compile( 'def {0}({1}):\n' ' return __wrapped__({2})'.format( # Keep the original function name original_function.__name__, # The function signature including defaults, ie, 'timeout=1' inspect.formatargspec( *inspect.getargspec(original_function) )[1:-1], # The function signature without the defaults inspect.formatargspec( formatvalue=lambda val: '', *inspect.getargspec(original_function) )[1:-1] ), '<string>', 'exec' ) exec function_def in context return wraps(original_function)(context[original_function.__name__])
def report_on_item_ourselves(name, value): lines = [] if isfunction(value): lines.append(wrapargs('FUNCTION %s%s'%(name, formatargspec(*getargspec(value))))) lines.extend(report__doc__(value)) elif ismethod(value): lines.append(wrapargs('METHOD %s%s'%(name, formatargspec(*getargspec(value))))) lines.extend(report__doc__(value)) elif isgenerator(value): lines.append(wrapargs('GENERATOR %s%s'%(name, formatargspec(*getargspec(value))))) lines.extend(report__doc__(value)) elif isclass(value): mro = getmro(value) supers = [] for c in mro[1:]: supers.append(c.__name__) lines.append('CLASS %s(%s)'%(name, ', '.join(supers))) lines.extend(report__doc__(value)) lines.append('') lines.append(wrapargs('METHOD %s.__init__%s'%(name, formatargspec(*getargspec(value.__init__))))) lines.extend(report__doc__(value.__init__)) lines.append('') lines.extend(describe_contents(name, value)) elif ismodule(value): lines.append('MODULE %s'%name) lines.extend(report__doc__(value)) lines.append('') lines.extend(describe_contents(name, value)) else: lines.append('SOMETHING ELSE: %s'%name) lines.append(value) lines.append('') lines.extend(describe_contents(name, value)) return lines
def informPlotters(_func_): """ Invoke the instance method of the same name inside each of the registered plotters """ def _wrap_(self, *args, **kwargs): _func_(self, *args, **kwargs) for plotter in self.plotters: plotter_func = getattr(plotter, _func_.__name__) plotter_func(*args, **kwargs) # code snippet for preserving function's name, doc, and signature # (from http://numericalrecipes.wordpress.com/2009/05/25/signature-preserving-function-decorators/) sig = list(inspect.getargspec(_func_)) wrap_sig = list(inspect.getargspec(_wrap_)) if not sig[2] : sig[2] = wrap_sig[2] src = 'def %s%s :\n' %(_func_.__name__, inspect.formatargspec(*sig)) sig[3] = None # if not, all vars with defaults are set to default value src += ' return _wrap_%s\n' % (inspect.formatargspec(*sig)) evaldict = {'_wrap_' : _wrap_} code = compile(src, '<string>', 'single') exec code in evaldict ret = evaldict[_func_.__name__] ret.__doc__ = _func_.__doc__ return ret
def advanced_wrap(f, wrapper): """ Wrap a decorated function while keeping the same keyword arguments """ f_sig = list(inspect.getargspec(f)) wrap_sig = list(inspect.getargspec(wrapper)) # Update the keyword arguments of the wrapper if f_sig[3] is None or f_sig[3] == []: f_sig[3], f_kwargs = [], [] else: f_kwargs = f_sig[0][-len(f_sig[3]):] for key, default in zip(f_kwargs, f_sig[3]): wrap_sig[0].append(key) wrap_sig[3] = wrap_sig[3] + (default, ) wrap_sig[2] = None # Remove kwargs src = "lambda %s: " % (inspect.formatargspec(*wrap_sig)[1:-1]) new_args = inspect.formatargspec( wrap_sig[0], wrap_sig[1], wrap_sig[2], f_kwargs, formatvalue=lambda x: '=' + x) src += 'wrapper%s\n' % new_args decorated = eval(src, locals()) return update_wrapper(decorated, f)
def get_signatures(self, prefix="", start=0): """ Return an iterator containing all possible function signatures. If prefix is given, use it as function name in signatures, else leave it out. If start is given, leave out first n elements. If start is -1, leave out first element if the function was created by run_cls. """ for fun, condition, types in self.funcs: if start == -1: st = getattr(fun, 'run_cls', 0) else: st = start if types is not None: yield prefix + fmt_argspec_types(condition, types, st) else: args, varargs, keywords, defaults = correct_argspec(condition) args = args[st:] yield prefix + inspect.formatargspec( args, varargs, keywords, defaults ) for fun, types in self.nones: if types is not None: yield prefix + fmt_argspec_types(fun, types, st) else: args, varargs, keywords, defaults = correct_argspec(condition) args = args[st:] yield prefix + inspect.formatargspec( args, varargs, keywords, defaults )
def _mkGeneric(oldfunc,argname): funcname = oldfunc.__name__ args, varargs, kwargs, defaults = inspect.getargspec(oldfunc) if defaults: tmpd = ["=__gfDefaults[%s]" % i for i in range(len(defaults))] else: tmpd = None argspec = inspect.formatargspec( args, varargs, kwargs, tmpd, formatvalue=lambda x:x) outargs = inspect.formatargspec(args,varargs,kwargs) protocol = protocols.Protocol() d={} s= """ def setup(__gfProtocol, __gfDefaults): def %(funcname)s%(argspec)s: __gfWhat = __gfProtocol(%(argname)s,None) if __gfWhat is None: raise NoApplicableMethods(%(argname)s) else: %(argname)s = __gfWhat[0] return __gfWhat[1]%(outargs)s return %(funcname)s """ % locals() exec(s, globals(),d); func = d['setup'](protocol,defaults) def when(cond): """Add following function to this GF, using 'cond' as a guard""" def callback(frm,name,value,old_locals): declarePredicate(cond, protocol, lambda ob: (ob,value)) if old_locals.get(name) is func: return func return value return decorate_assignment(callback) def addMethod(cond,func): """Use 'func' when dispatch argument matches 'cond'""" declarePredicate(cond, protocol, lambda ob: (ob,func)) def clone(): """Return a simple generic function that "inherits" from this one""" f = _mkGeneric(oldfunc,argname) protocols.declareAdapter( protocols.NO_ADAPTER_NEEDED,[f.protocol],forProtocols=[protocol] ) return f func.addMethod = addMethod func.when = when func.clone = clone func.protocol = protocol func.__doc__ = oldfunc.__doc__ protocols.adviseObject(func,provides=[IExtensibleFunction]) return func
def docroutine(self, object, name, mod=None, funcs={}, classes={}, methods={}, cl=None): """Produce HTML documentation for a function or method object.""" anchor = (cl and cl.__name__ or "") + "-" + name note = "" title = '<a name="%s"><strong>%s</strong></a>' % (self.escape(anchor), self.escape(name)) if inspect.ismethod(object): args, varargs, varkw, defaults = inspect.getargspec(object) # exclude the argument bound to the instance, it will be # confusing to the non-Python user argspec = inspect.formatargspec(args[1:], varargs, varkw, defaults, formatvalue=self.formatvalue) elif inspect.isfunction(object): args, varargs, varkw, defaults = inspect.getargspec(object) argspec = inspect.formatargspec(args, varargs, varkw, defaults, formatvalue=self.formatvalue) else: argspec = "(...)" if isinstance(object, tuple): argspec = object[0] or argspec docstring = object[1] or "" else: docstring = pydoc.getdoc(object) decl = title + argspec + (note and self.grey('<font face="helvetica, arial">%s</font>' % note)) doc = self.markup(docstring, self.preformat, funcs, classes, methods) doc = doc and "<dd><tt>%s</tt></dd>" % doc return "<dl><dt>%s</dt>%s</dl>\n" % (decl, doc)
def extract_tb(tb, limit = None): list = [] n = 0 while tb is not None and (limit is None or n < limit): f = tb.tb_frame lineno = tb.tb_lineno co = f.f_code filename = co.co_filename name = co.co_name linecache.checkcache(filename) line = "" if '__file__' in f.f_globals: for global_name, x in f.f_globals.items(): if global_name.startswith('_'): continue if inspect.isfunction(x): if global_name == name and x.__code__ == co: args, varargs, varkw, defaults = inspect.getargspec(x) name += inspect.formatargspec(args, varargs, varkw, defaults) elif inspect.isclass(x): method = find_method_in_class(name,co,x) if not method is None: args, varargs, varkw, defaults = inspect.getargspec(method) name += inspect.formatargspec(args, varargs, varkw, defaults) name = x.__name__ + '.' + name if line: line = line.strip() else: line = None list.append((filename, lineno, name, line)) tb = tb.tb_next n = n+1 return list
def help2md(filepath, output='README.md', name='code'): """help2md Converts python help to a .md file. params: - filename - The full path of the input file - output - The full path of the output file ( defaults to README.md ) - name - The name of the file. It puts this at the top of the document. """ document = '#' + name + '\n' c = imp.load_source(name, filepath) doc = inspect.getdoc(c) if doc: document += doc + '\n' else: document += '\n' main_file = getattr(c, '__file__') modules = [] items = dir(c) for i in items: item = getattr(c, i) if inspect.isfunction(item): doc = inspect.getdoc(item) if doc == None: doc = 'No documentation' params = inspect.formatargspec(*inspect.getfullargspec(item)) document += ('\n\n##' + i + '\n```python\ndef ' + i + params + ':\n\t"""' + '\n\t'.join(doc.split('\n')) + '"""\n```') if inspect.isclass(item): doc = inspect.getdoc(item) if doc == None: doc = 'No documentation' document += ('\n\n##' + i + '\n```python\nclass ' + i + '():\n\t"""' + '\n\t'.join(doc.split('\n')) + '"""\n```') methods = dir(item) for m in methods: mitem = getattr(item, m) if inspect.isfunction(mitem): params = inspect.formatargspec( *inspect.getfullargspec(mitem)) doc = inspect.getdoc(mitem) if doc == None: doc = 'No documentation' document += ('\n\n###' + m + '\n```python\n\tdef ' + m + params + ':\n\t\t"""' + '\n\t\t'.join( doc.split('\n')) + '"""\n```') if inspect.ismodule(item): modules.append(i) document += '\n\n# Dependencies\n- ' + '\n- '.join(modules) document += '\n\n***Made with help2md***' with open(output, 'w') as ofile: ofile.write(document) return None
def pprinthook(value): """Pretty print an object to sys.stdout and also save it in __builtin__. """ if value is None: return __builtin__._ = value if isinstance(value, help_types): reprstr = repr(value) try: if inspect.isfunction(value): parts = reprstr.split(' ') parts[1] += inspect.formatargspec(*getargspec(value)) reprstr = ' '.join(parts) elif inspect.ismethod(value): parts = reprstr[:-1].split(' ') parts[2] += inspect.formatargspec(*getargspec(value)) reprstr = ' '.join(parts) + '>' except TypeError: pass sys.stdout.write(reprstr) sys.stdout.write('\n') if getattr(value, '__doc__', None): sys.stdout.write('\n') sys.stdout.write(pydoc.getdoc(value)) sys.stdout.write('\n') else: pphighlight(value, width=get_width() or 80)
def inner(decorator): """ Actual decorator """ # Compile wrapper function space = {proxy_name: decorator} if argspec[3]: kwnames = argspec[0][-len(argspec[3]):] else: kwnames = None passed = _inspect.formatargspec(argspec[0], argspec[1], argspec[2], kwnames, formatvalue=lambda value: '=' + value ) # pylint: disable = W0122 exec "def %s%s: return %s%s" % ( name, _inspect.formatargspec(*argspec), proxy_name, passed ) in space wrapper = space[name] wrapper.__dict__ = decorated.__dict__ wrapper.__doc__ = decorated.__doc__ if extra and decorated.__doc__ is not None: if not decorated.__doc__.startswith('%s(' % name): wrapper.__doc__ = "%s%s\n\n%s" % ( name, _inspect.formatargspec(*dargspec), decorated.__doc__, ) return wrapper
def buffer_defaults(func): def indent(code): return "\n".join([" " + line for line in code.split("\n")[:-1]]) + "\n" argspec = inspect.getargspec(func) kwargs = argspec.keywords or "kwargs" wrapper = "def wrapper" + inspect.formatargspec(argspec.args, argspec.varargs, kwargs, argspec.defaults) + ":\n" wrapper += " from core.sessions.buffers.buffers.buffer import Buffer\n" wrapper += " import sessions\n" if 'buffer' in argspec.args: set_buffer = "if buffer is None: buffer = sessions.current_session.current_buffer\n" elif argspec.args[0] == "self": set_buffer = "if isinstance(self, Buffer): buffer = self\n" set_buffer += "elif isinstance({kwargs}.get('buffer', None), Buffer): buffer = {kwargs}['buffer']\n" set_buffer += "else: buffer = sessions.current_session.current_buffer\n" else: set_buffer = "if isinstance({kwargs}.get('buffer', None), Buffer): buffer = {kwargs}['buffer']\n" set_buffer += "else: buffer = sessions.current_session.current_buffer\N" set_index = set_buffer if 'index' in argspec.args: set_index += "if index is None: index = buffer.index\n" else: set_index += "if {kwargs}.get('index', None) is not None: index = {kwargs}['index']\n" set_index += "else: index = buffer.index\n" if 'item' in argspec.args: set_item = "if item is None:\n" set_item += indent(set_index) set_item += " item = buffer[index] #1\n" else: set_item = "if {kwargs}.get('item', None) is not None: item = {kwargs}['item']\n" set_item += "else:\n" set_item += indent(set_index) set_item += " item = buffer[index] #2\n" if argspec.keywords is not None: wrapper += indent(set_item) if 'buffer' not in argspec.args: if argspec.args[0] == "self": wrapper += " if not isinstance(self, Buffer): {kwargs}['buffer'] = buffer\n" else: wrapper += " {kwargs}['buffer'] = buffer\n" elif 'index' not in argspec.args: wrapper += " {kwargs}['index'] = index\n" elif 'item' not in argspec.args: wrapper += " {kwargs}['item'] = item\n" elif 'item' in argspec.args: wrapper += indent(set_item) elif 'index' in argspec.args: wrapper += indent(set_index) elif 'buffer' in argspec.args: wrapper += indent(set_buffer) wrapper += " return func" + inspect.formatargspec(argspec.args, argspec.varargs, argspec.keywords) + "\n" wrapper += "f = wrapper\n" wrapper = wrapper.format(kwargs=kwargs) bindings = {'func':func, 'f':None} exec wrapper in bindings update_wrapper(bindings['f'], func) return bindings['f']
def wrap(template): actual_argspec = inspect.getargspec(actual) template_argspec = inspect.getargspec(template) if actual_argspec != template_argspec: msg = "Expected: %s; got: %s" % ( inspect.formatargspec(*template_argspec), inspect.formatargspec(*actual_argspec)) self.fail(msg) return template # just in case it's useful
def __str__(self): return ( "Function `{function}` does not comply with interface definition." " Expected arguments: {expected}" " Observed arguments: {observed}" ).format( function=self.function.__name__, expected=inspect.formatargspec(*self.expected_argspec), observed=inspect.formatargspec(*self.observed_argspec) )
def decorate(func, dec): argspec = inspect.getargspec(func) name = func.__name__ signature = inspect.formatargspec(*argspec) params = inspect.formatargspec(formatvalue=(lambda value: ''), *argspec) source = 'def %s%s: return __dec%s\n' % (name, signature, params) code = compile(source, '<decorator-gen>', 'single') env = {'__dec': dec} eval(code, env) return update_wrapper(env[name], func)
def wrap(template, func, globs=None, depth=1, ismethod=False): """Wrap a function or method. This is similar to :func:`functools.wraps` but rather than using a closure this compiles a new function using compile(). The advantage is that it allows sphinx autodoc to document the arguments. Without this, a generic wrapper would need to have a signature of ``func(*args, **kwargs)`` and would show up as such in the documentation. The *template* argument is a string containing the wrapper template. The template should be a valid function definition. It is passed through format() with the following keywoard arguments before compilation: * {name} - the function name * {signature} - function signature including parens and default values * {arglist} - function argument list, including parens, no default values * {docstring} - docstring The *globs* argument specifies global variables accessible to the wrapper. If *depth* is given, file and line numbers are tweaked so that the generated function appears to be in the file and on the (single) line of the frame at this depth. """ name = func.__name__ doc = func.__doc__ or '' if globs is None: globs = {} argspec = inspect.getargspec(func) signature = inspect.formatargspec(*argspec) if ismethod: arglist = inspect.formatargspec( argspec[0][1:], *argspec[1:], formatvalue=lambda x: '') else: arglist = inspect.formatargspec(*argspec, formatvalue=lambda x: '') funcdef = template.format( name=name, signature=signature, docstring=doc, arglist=arglist) node = ast.parse(funcdef) # If "depth" is provided, make the generated code appear to be on a single # line in the file of the frame at this depth. This makes backtraces more # readable. if depth > 0: frame = sys._getframe(depth) fname = frame.f_code.co_filename lineno = frame.f_lineno for child in ast.walk(node): if 'lineno' in child._attributes: child.lineno = lineno if 'col_offset' in child._attributes: child.col_offset = 0 else: fname = '<wrap>' code = compile(node, fname, 'exec') six.exec_(code, globs) return globs[name]
def wrap(template): actual_argspec = filter( inspect.getargspec(remove_decorators(actual))) template_argspec = filter( inspect.getargspec(remove_decorators(template))) if actual_argspec != template_argspec: msg = "Expected: %s; got: %s" % ( inspect.formatargspec(*template_argspec), inspect.formatargspec(*actual_argspec)) self.fail(msg) return template # just in case it's useful
def _buildFacade(name, spec, docstring): """Build a facade function, matching the decorated method in signature. Note that defaults are replaced by _default, and _curried will reconstruct these to preserve mutable defaults. """ args = inspect.formatargspec(formatvalue=lambda v: '=_default', *spec) callargs = inspect.formatargspec(formatvalue=lambda v: '', *spec) return 'def %s%s:\n """%s"""\n return _curried%s' % ( name, args, docstring, callargs)
def print_argspec(func): print('------------') print('func_name = %r' % func.func_name) # Extract argspec from orig function argspec = inspect.getargspec(func) # Get the function definition signature defsig = inspect.formatargspec(*argspec) # Get function call signature (no defaults) callsig = inspect.formatargspec(*argspec[0:3]) print('argspec = %r' % (argspec,)) print('callsig = %r' % (callsig,)) print('defsig = %r' % (defsig,)) print('------------')
def __init__(self, func=None, name=None, signature=None, defaults=None, doc=None, module=None, funcdict=None): if func: # func can be a class or a callable, but not an instance method self.name = func.__name__ if self.name == '<lambda>': # small hack for lambda functions self.name = '_lambda_' self.doc = func.__doc__ try: self.module = func.__module__ except AttributeError: pass if inspect.isfunction(func): argspec = inspect.getargspec(func) self.args, self.varargs, self.keywords, self.defaults = argspec for i, arg in enumerate(self.args): setattr(self, 'arg%d' % i, arg) self.signature = inspect.formatargspec( formatvalue=lambda val: "", *argspec)[1:-1] self.dict = func.__dict__.copy() elif isinstance(func, objc_selector): name = func.selector.replace(":", "_") self.args = ["self"] reserved = set(self.args) | reserved_words for arg in func.selector.split(":")[:-1]: while arg in reserved or not arg: arg += "_" reserved.add(arg) self.args.append(arg) self.varargs, self.keywords, self.defaults = None, None, None for i, arg in enumerate(self.args): setattr(self, 'arg%d' % i, arg) self.signature = inspect.formatargspec( self.args, formatvalue=lambda val: "")[1:-1] self.dict = {} if name: self.name = name if signature is not None: self.signature = signature if defaults: self.defaults = defaults if doc: self.doc = doc if module: self.module = module if funcdict: self.dict = funcdict # check existence required attributes assert hasattr(self, 'name') if not hasattr(self, 'signature'): raise TypeError('You are decorating a non function: %s' % func)
def boilerplate_gen(): """Generator of lines for the automated part of pyplot.""" # these methods are all simple wrappers of Axes methods by the same # name. _plotcommands = ( 'acorr', 'angle_spectrum', 'arrow', 'axhline', 'axhspan', 'axvline', 'axvspan', 'bar', 'barh', 'broken_barh', 'boxplot', 'cohere', 'clabel', 'contour', 'contourf', 'csd', 'errorbar', 'eventplot', 'fill', 'fill_between', 'fill_betweenx', 'hexbin', 'hist', 'hist2d', 'hlines', 'imshow', 'loglog', 'magnitude_spectrum', 'pcolor', 'pcolormesh', 'phase_spectrum', 'pie', 'plot', 'plot_date', 'psd', 'quiver', 'quiverkey', 'scatter', 'semilogx', 'semilogy', 'specgram', # 'spy', 'stackplot', 'stem', 'step', 'streamplot', 'tricontour', 'tricontourf', 'tripcolor', 'triplot', 'violinplot', 'vlines', 'xcorr', 'barbs', ) _misccommands = ( 'cla', 'grid', 'legend', 'table', 'text', 'annotate', 'ticklabel_format', 'locator_params', 'tick_params', 'margins', 'autoscale', ) cmappable = { 'contour': 'if %(ret)s._A is not None: sci(%(ret)s)', 'contourf': 'if %(ret)s._A is not None: sci(%(ret)s)', 'hexbin': 'sci(%(ret)s)', 'scatter': 'sci(%(ret)s)', 'pcolor': 'sci(%(ret)s)', 'pcolormesh': 'sci(%(ret)s)', 'hist2d': 'sci(%(ret)s[-1])', 'imshow': 'sci(%(ret)s)', #'spy' : 'sci(%(ret)s)', ### may return image or Line2D 'quiver': 'sci(%(ret)s)', 'specgram': 'sci(%(ret)s[-1])', 'streamplot': 'sci(%(ret)s.lines)', 'tricontour': 'if %(ret)s._A is not None: sci(%(ret)s)', 'tricontourf': 'if %(ret)s._A is not None: sci(%(ret)s)', 'tripcolor': 'sci(%(ret)s)', } def format_value(value): """ Format function default values as needed for inspect.formatargspec. The interesting part is a hard-coded list of functions used as defaults in pyplot methods. """ if isinstance(value, types.FunctionType): if value.__name__ in ('detrend_none', 'window_hanning'): return '=mlab.' + value.__name__ if value.__name__ == 'mean': return '=np.' + value.__name__ raise ValueError(('default value %s unknown to boilerplate.' + 'formatvalue') % value) return '=' + repr(value) text_wrapper = textwrap.TextWrapper(break_long_words=False) for fmt, cmdlist in [(PLOT_TEMPLATE, _plotcommands), (MISC_FN_TEMPLATE, _misccommands)]: for func in cmdlist: # For some commands, an additional line is needed to set the # color map if func in cmappable: mappable = ' ' + cmappable[func] % locals() else: mappable = '' # Get argspec of wrapped function base_func = getattr(Axes, func) has_data = 'data' in inspect.signature(base_func).parameters work_func = inspect.unwrap(base_func) (args, varargs, varkw, defaults, kwonlyargs, kwonlydefs, annotations) = inspect.getfullargspec(work_func) args.pop(0) # remove 'self' argument defaults = tuple(defaults or ()) # Add a data keyword argument if needed (fmt is PLOT_TEMPLATE) and # possible (if *args is used, we can't just add a data # argument in front of it since it would gobble one of the # arguments the user means to pass via *args) # This needs to be done here so that it goes into call if not varargs and fmt is PLOT_TEMPLATE and has_data: args.append('data') defaults = defaults + (None,) # How to call the wrapped function call = [] for i, arg in enumerate(args): if len(defaults) < len(args) - i: call.append('%s' % arg) else: call.append('%s=%s' % (arg, arg)) # remove the data keyword as it was needed above to go into the # call but should go after `hold` in the signature. # This is janky as all get out, but hopefully boilerplate will # be retired soon. if not varargs and fmt is PLOT_TEMPLATE and has_data: args.pop() defaults = defaults[:-1] if varargs is not None: call.append('*' + varargs) if varkw is not None: call.append('**' + varkw) call = ', '.join(call) text_wrapper.width = 80 - 19 - len(func) join_with = '\n' + ' ' * (18 + len(func)) call = join_with.join(text_wrapper.wrap(call)) # Add a hold keyword argument if needed (fmt is PLOT_TEMPLATE) and # possible (if *args is used, we can't just add a hold # argument in front of it since it would gobble one of the # arguments the user means to pass via *args) if varargs: sethold = " hold = %(varkw)s.pop('hold', None)" % locals() elif fmt is PLOT_TEMPLATE: args.append('hold') defaults = defaults + (None,) if has_data: args.append('data') defaults = defaults + (None,) sethold = '' # Now we can build the argspec for defining the wrapper argspec = inspect.formatargspec(args, varargs, varkw, defaults, formatvalue=format_value) argspec = argspec[1:-1] # remove parens text_wrapper.width = 80 - 5 - len(func) join_with = '\n' + ' ' * (5 + len(func)) argspec = join_with.join(text_wrapper.wrap(argspec)) # A gensym-like facility in case some function takes an # argument named washold, ax, or ret washold, ret, ax = 'washold', 'ret', 'ax' bad = set(args) | {varargs, varkw} while washold in bad or ret in bad or ax in bad: washold = 'washold' + str(random.randrange(10 ** 12)) ret = 'ret' + str(random.randrange(10 ** 12)) ax = 'ax' + str(random.randrange(10 ** 12)) # Since we can't avoid using some function names, # bail out if they are used as argument names for reserved in ('gca', 'gci'): if reserved in bad: msg = 'Axes method %s has kwarg named %s' % (func, reserved) raise ValueError(msg) yield fmt % locals() cmaps = ( 'autumn', 'bone', 'cool', 'copper', 'flag', 'gray', 'hot', 'hsv', 'jet', 'pink', 'prism', 'spring', 'summer', 'winter', 'magma', 'inferno', 'plasma', 'viridis', "nipy_spectral" ) deprecated_cmaps = ("spectral", ) # add all the colormaps (autumn, hsv, ....) for name in cmaps: yield CMAP_TEMPLATE.format(name=name) for name in deprecated_cmaps: yield CMAP_TEMPLATE_DEPRECATED.format(name=name) yield '' yield '_setup_pyplot_info_docstrings()'
def run(self): env = self.state.document.settings.env # Interface function name = self.arguments[0].strip() obj = _import_object(name) args, varargs, keywords, defaults = getargspec_no_self(obj) # Implementation function impl_name = self.options['impl'] impl_obj = _import_object(impl_name) impl_args, impl_varargs, impl_keywords, impl_defaults = getargspec_no_self( impl_obj) # Format signature taking implementation into account args = list(args) defaults = list(defaults) def set_default(arg, value): j = args.index(arg) defaults[len(defaults) - (len(args) - j)] = value def remove_arg(arg): if arg not in args: return j = args.index(arg) if j < len(args) - len(defaults): del args[j] else: del defaults[len(defaults) - (len(args) - j)] del args[j] options = [] for j, opt_name in enumerate(impl_args): if opt_name in args: continue if j >= len(impl_args) - len(impl_defaults): options.append( (opt_name, impl_defaults[len(impl_defaults) - (len(impl_args) - j)])) else: options.append((opt_name, None)) set_default('options', dict(options)) set_default('method', self.options['method'].strip()) for arg in list(args): if arg not in impl_args and arg not in ('fun', 'x0', 'args', 'tol', 'callback', 'method', 'options'): remove_arg(arg) # XXX deprecation that we should fix someday using Signature (?) with warnings.catch_warnings(record=True): warnings.simplefilter('ignore') signature = inspect.formatargspec(args, varargs, keywords, defaults) # Produce output self.options['noindex'] = True self.arguments[0] = name + signature lines = textwrap.dedent(pydoc.getdoc(impl_obj)).splitlines() # Change "Options" to "Other Parameters", run numpydoc, reset new_lines = [] for line in lines: if line.strip() == 'Options': line = "Other Parameters" elif line.strip() == "-" * len('Options'): line = "-" * len("Other Parameters") new_lines.append(line) # use impl_name instead of name here to avoid duplicate refs mangle_docstrings(env.app, 'function', impl_name, None, None, new_lines) lines = new_lines new_lines = [] for line in lines: if line.strip() == ':Other Parameters:': new_lines.extend((BLURB % (name, )).splitlines()) new_lines.append('\n') new_lines.append(':Options:') else: new_lines.append(line) self.content = ViewList(new_lines, self.content.parent) return base_directive.run(self)
def update(self): self.path = '/'.join(self.context.getPhysicalPath()) self.cls = self.context.__class__ self.fti = None self.methodAliases = None if IDynamicType.providedBy(self.context): self.fti = self.context.getTypeInfo() self.methodAliases = sorted(self.fti.getMethodAliases().items()) self.defaultView = None self.viewMethods = [] if IDynamicViewTypeInformation.providedBy(self.fti): self.defaultView = self.fti.defaultView(self.context) self.viewMethods = self.fti.getAvailableViewMethods(self.context) directly_provided = directlyProvidedBy(self.context) self.provided = list(providedBy(self.context).flattened()) self.provided.sort(key=lambda i: i.__identifier__) self.provided = ({ 'dottedname': i.__identifier__, 'is_marker': i in directly_provided } for i in self.provided) self.views = [] generator = getAdapters(( self.context, self.request, ), Interface) while True: try: name, view = generator.next() if not IView.providedBy(view): continue cls = view.__class__ module = cls.__module__ template = None if isinstance(view, ViewMixinForTemplates): template = view.index.filename else: for attr in ('index', 'template', '__call__'): pt = getattr(view, attr, None) if hasattr(pt, 'filename'): template = pt.filename break # Deal with silly Five metaclasses if (module == 'Products.Five.metaclass' and len(cls.__bases__) > 0): cls = cls.__bases__[0] elif cls == ViewMixinForTemplates: cls = None self.views.append({ 'name': name, 'class': cls, 'template': template, }) except StopIteration: break except: # Some adapters don't initialise cleanly pass self.views.sort(key=lambda v: v['name']) self.methods = [] self.variables = [] _marker = object() for name in sorted(dir(aq_base(self.context))): attr = getattr(aq_base(self.context), name, _marker) if attr is _marker: continue # FIXME: Should we include ComputedAttribute here ? [glenfant] if isinstance(attr, (int, long, float, basestring, bool, list, tuple, dict, set, frozenset)): self.variables.append({ 'name': name, 'primitive': True, 'value': attr, }) elif (isinstance(attr, (types.MethodType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType)) or attr.__class__.__name__ == 'method-wrapper', ): source = None if name.endswith('__roles__'): # name without '__roles__' is the last in self.methods since we're in a sorted(...) loop if callable(attr): secu_infos = attr() else: secu_infos = attr if secu_infos is None: secu_label = 'Public' else: secu_label = '' try: secu_label += 'Roles: ' + ', '.join( [r for r in secu_infos[:-1]]) except TypeError: # Avoid "TypeError: sequence index must be # integer, not 'slice'", which occurs with the # ``C`` security implementation. This is a rare # case. In development you normally use the # ``Python`` security implementation, where this # error doesn't occur. pass secu_label += '. Permission: ' + secu_infos[-1][ 1:-11] # _x_Permission -> x self.methods[-1]['secu_infos'] = secu_label else: try: source = inspect.getsourcefile(attr) except TypeError: None signature = name + "()" try: signature = name + inspect.formatargspec( *inspect.getargspec(attr)) except TypeError: pass self.methods.append({ 'signature': signature, 'filename': source, 'help': inspect.getdoc(attr), }) else: self.variables.append({ 'name': name, 'primitive': False, 'value': str(attr), })
def arg_string(func): """Returns a nice argstring for a function or method""" return inspect.formatargspec(*inspect.getargspec(func))
# Get the arguments of the command and strip out the method 'self' argument # and the internally used 'client' argument. argspec = getfullargspec(f) if "self" in argspec.args: argspec.args.remove("self") if "client" in argspec.args: argspec.args.remove("client") if "_client" in argspec.args: argspec.args.remove("_client") # Modify the docstring to include the modified function prototype and to # modify references to other commands from being method references to # function references. globals()[name].__doc__ = "{}{}\n{}".format( name, formatargspec(*argspec), # pylint: disable=deprecated-method f.__doc__.replace(":py:meth:`.", ":py:func:`.").replace( "`~spalloc_server.controller.JobState", "`.JobState")) ############################################################################### # Document job states ############################################################################### # A 'fake' JobState class which simply enumerates the job IDs in its docstring _JobState_doc = """ A job may be in any of the following (numbered) states. ====== ===== Number State ====== ===== """
pass print("Function inspect.isfunction:", inspect.isfunction(compiledFunction)) print( "Function isinstance types.FunctionType:", isinstance(compiledFunction, types.FunctionType), ) print( "Function isinstance tuple containing types.FunctionType:", isinstance(compiledFunction, (int, types.FunctionType)), ) print("Compiled spec:", inspect.getargspec(compiledFunction)) print("Compiled args:", inspect.formatargspec(*inspect.getargspec(compiledFunction))) # Even this works. assert type(compiledFunction) == types.FunctionType class CompiledClass: def __init__(self): pass def compiledMethod(self): pass assert inspect.isfunction(CompiledClass) is False assert isinstance(CompiledClass, types.FunctionType) is False
def assert_same_argspec(expected, actual): if expected != actual: msg = "Expected: %s; got: %s" % (inspect.formatargspec( *expected), inspect.formatargspec(*actual)) self.fail(msg)
def wraps(origfunc, lshift=0): """ Decorator factory: used to create a decorator that assumes the same attributes (name, docstring, signature) as its decorated function when sphinx has been imported. This is necessary because sphinx uses introspection to construct the documentation. This logic is inspired from Michele Simionato's decorator module. >>> def decorator(func): ... @wraps(func) ... def newfunc(*args, **kwargs): ... # custom logic here ... ... return func(*args, **kwargs) ... return newfunc :param origfunc: the original function being decorated which is to be wrapped. :param lshift: number of arguments to shift from the left of the original function's call spec. Wrapped function will have this nubmer of arguments removed. :returns: a decorator which has the attributes of the decorated function. """ if 'sphinx.builders' not in sys.modules: # sphinx not imported, so return a decorator that passes the func through. return functools.wraps(origfunc) elif lshift == 0: # Simple case, we don't need to munge args, so we can pass origfunc. return lambda func: origfunc # The idea here is to turn an origfunc with a signature like: # origfunc(progress, a, b, c=42, *args, **kwargs) # into: # lambda a, b, c=42, *args, **kwargs: log.error("...") spec = list(inspect.getargspec(origfunc)) # Wrapped function needs a different signature. Currently we can just # shift from the left of the args (e.g. for kaa.threaded progress arg). # FIXME: doesn't work if the shifted arg is a kwarg. spec[0] = spec[0][lshift:] if spec[-1]: # For the lambda signature's kwarg defaults, remap them into values # that can be referenced from the eval's local scope. Otherwise only # intrinsics could be used as kwarg defaults. # Preserve old kwarg value list, to be passed into eval's locals scope. kwarg_values = spec[-1] # Changes (a=1, b=Foo) to a='__kaa_kw_defs[1]', b='__kaa_kw_defs[2]' sigspec = spec[:3] + [[ '__kaa_kw_defs[%d]' % n for n in range(len(spec[-1])) ]] sig = inspect.formatargspec(*sigspec)[1:-1] # Removes the quotes between __kaa_kw_defs[x] sig = re.sub(r"'(__kaa_kw_defs\[\d+\])'", '\\1', sig) else: sig = inspect.formatargspec(*spec)[1:-1] kwarg_values = None src = 'lambda %s: __kaa_log_.error("doc generation mode: decorated function \'%s\' was called")' % ( sig, origfunc.__name__) def decorator(func): dec_func = eval(src, { '__kaa_log_': log, '__kaa_kw_defs': kwarg_values }) return update_wrapper(dec_func, origfunc) return decorator
def scan(name, o, prefix=""): doc_type = "function" # The section it's going into. section = None # The formatted arguments. args = None # Get the function's docstring. doc = inspect.getdoc(o) if not doc: return # Break up the doc string, scan it for specials. lines = [ ] for l in doc.split("\n"): m = re.match(r':doc: *(\w+) *(\w+)?', l) if m: section = m.group(1) if m.group(2): doc_type = m.group(2) continue m = re.match(r':args: *(.*)', l) if m: args = m.group(1) continue m = re.match(r':name: *(\S+)', l) if m: if name != m.group(1): return continue lines.append(l) if section is None: return if args is None: # Get the arguments. if inspect.isclass(o): init = getattr(o, "__init__", None) if not init: return init_doc = inspect.getdoc(init) if init_doc and not init_doc.startswith("x.__init__("): lines.append("") lines.extend(init_doc.split("\n")) try: args = inspect.getargspec(init) except: args = None elif inspect.isfunction(o): args = inspect.getargspec(o) elif inspect.ismethod(o): args = inspect.getargspec(o) else: print "Warning: %s has section but not args." % name return # Format the arguments. if args is not None: args = inspect.formatargspec(*args) args = args.replace("(self, ", "(") else: args = "()" # Put it into the line buffer. lb = line_buffer[section] lb.append(prefix + ".. %s:: %s%s" % (doc_type, name, args)) for l in lines: lb.append(prefix + " " + l) lb.append(prefix + "") if inspect.isclass(o): for i in dir(o): scan(i, getattr(o, i), prefix + " ")
def _format_args(func): return inspect.formatargspec(*inspect.getargspec(func))
def _format_predicate(pred): args = inspect.formatargspec(*inspect.getargspec(pred)) return "<lambda>" if pred.__name__ == "<lambda>" else "{pred.__name__}{args}".format( **locals())
# Add a hold keyword argument if needed (fmt is _fmtplot) and # possible (if *args is used, we can't just add a hold # argument in front of it since it would gobble one of the # arguments the user means to pass via *args) if varargs: sethold = "hold = %(varkw)s.pop('hold', None)" % locals() elif fmt is _fmtplot: args.append('hold') defaults = defaults + (None, ) sethold = '' # Now we can build the argspec for defining the wrapper argspec = inspect.formatargspec(args, varargs, varkw, defaults, formatvalue=format_value) argspec = argspec[1:-1] # remove parens # A gensym-like facility in case some function takes an # argument named washold, ax, or ret washold, ret, ax = 'washold', 'ret', 'ax' bad = set(args) | set((varargs, varkw)) while washold in bad or ret in bad or ax in bad: washold = 'washold' + str(random.randrange(10**12)) ret = 'ret' + str(random.randrange(10**12)) ax = 'ax' + str(random.randrange(10**12)) # Since we can't avoid using some function names, # bail out if they are used as argument names
def log_to_metadata(func): """ Decorator that adds logging to ccdproc functions. The decorator adds the optional argument _LOG_ARGUMENT to function signature and updates the function's docstring to reflect that. It also sets the default value of the argument to the name of the function and the arguments it was called with. """ func.__doc__ = func.__doc__.format(log=_LOG_ARG_HELP) (original_args, varargs, keywords, defaults) = inspect.getargspec(func) # grab the names of positional arguments for use in automatic logging try: original_positional_args = original_args[:-len(defaults)] except TypeError: original_positional_args = original_args # Add logging keyword and its default value for docstring original_args.append(_LOG_ARGUMENT) try: defaults = list(defaults) except TypeError: defaults = [] defaults.append(True) signature_with_arg_added = inspect.formatargspec(original_args, varargs, keywords, defaults) signature_with_arg_added = "{0}{1}".format(func.__name__, signature_with_arg_added) func.__doc__ = "\n".join([signature_with_arg_added, func.__doc__]) @wraps(func) def wrapper(*args, **kwd): # Grab the logging keyword, if it is present. log_result = kwd.pop(_LOG_ARGUMENT, True) result = func(*args, **kwd) if not log_result: # No need to add metadata.... meta_dict = {} elif log_result is not True: meta_dict = _metadata_to_dict(log_result) else: # Logging is not turned off, but user did not provide a value # so construct one. key = func.__name__ all_args = chain(zip(original_positional_args, args), six.iteritems(kwd)) all_args = ["{0}={1}".format(name, _replace_array_with_placeholder(val)) for name, val in all_args] log_val = ", ".join(all_args) log_val = log_val.replace("\n", "") meta_dict = {key: log_val} for k, v in six.iteritems(meta_dict): result._insert_in_metadata_fits_safe(k, v) return result return wrapper
def __call__(self, function): import inspect if self.name is None: name = function.__name__ else: name = self.name function_name = function.__name__ if self.docstring is not None: function_docstring = ("\n----- ADDITIONAL DOCSTRING -----\n" + self.docstring) else: function_docstring = "" if function.__doc__ is not None: function_docstring += ("\n----- FUNCTION DOCSTRING -----\n" + function.__doc__) if function_docstring is None: function_docstring = "" if self.args is None: args = [] else: args = self.args if not (isinstance(args, list) or isinstance(args, tuple)): raise TypeError('args must be a list or a tuple') function_args = repr(args) try: assert ast.literal_eval(function_args) == args except Exception: raise ValueError('Argument list can contain only Python literals') if self.kwargs is None: kwargs = {} else: kwargs = self.kwargs if not isinstance(kwargs, dict): raise TypeError('kwargs must be a dictionary') function_kwargs = repr(kwargs) try: assert ast.literal_eval(function_kwargs) == kwargs except Exception: raise TypeError( 'Keyword argument list can contain only Python literals') argspec = inspect.getargspec(function) function_signature = function_name + inspect.formatargspec(*argspec) try: function_source = inspect.getsource(function) except Exception: raise TypeError( 'Could not get source code of %s %s. ' % (type(function).__name__, repr(function)) + 'Only ordinary Python functions defined in Python source code can be saved.' ) function_lines = function_source.splitlines() indentation = min( len(line) - len(line.lstrip(' ')) for line in function_lines) # Remove this decorator from the source, if present: if function_lines[0][indentation:].startswith('@'): del function_lines[0] # Remove initial indentation from the source: function_source = '\n'.join(line[indentation:] for line in function_lines) with File(self.filename) as f: group = f.require_group(self.groupname, h5scripting_id='functions_group') try: del group[name] except KeyError: pass dataset = group.create_dataset(name, data=function_source, docstring=function_docstring, h5scripting_id='function') dataset.attrs['__h5scripting__function_name__'] = function_name dataset.attrs[ '__h5scripting__function_signature__'] = function_signature dataset.attrs['__h5scripting__function_args__'] = function_args dataset.attrs['__h5scripting__function_kwargs__'] = function_kwargs saved_function = SavedFunction(dataset) return saved_function
if remove_key in d: d = dict(d) del d[remove_key] return pprint.pformat(d) def compiledFunction(a, b): pass assert inspect.isfunction(compiledFunction) is True assert isinstance(compiledFunction, types.FunctionType) assert isinstance(compiledFunction, (int, types.FunctionType)) print("Compiled spec:", inspect.getargspec(compiledFunction)) print("Compiled args:", inspect.formatargspec(*inspect.getargspec(compiledFunction))) # Even this works. assert type(compiledFunction) == types.FunctionType class CompiledClass: def __init__(self): pass def compiledMethod(self): pass assert inspect.isfunction(CompiledClass) is False assert isinstance(CompiledClass, types.FunctionType) is False assert inspect.ismethod(compiledFunction) is False
def format_argspec_plus(fn, grouped=True): """Returns a dictionary of formatted, introspected function arguments. A enhanced variant of inspect.formatargspec to support code generation. fn An inspectable callable or tuple of inspect getargspec() results. grouped Defaults to True; include (parens, around, argument) lists Returns: args Full inspect.formatargspec for fn self_arg The name of the first positional argument, varargs[0], or None if the function defines no positional arguments. apply_pos args, re-written in calling rather than receiving syntax. Arguments are passed positionally. apply_kw Like apply_pos, except keyword-ish args are passed as keywords. Example:: >>> format_argspec_plus(lambda self, a, b, c=3, **d: 123) {'args': '(self, a, b, c=3, **d)', 'self_arg': 'self', 'apply_kw': '(self, a, b, c=c, **d)', 'apply_pos': '(self, a, b, c, **d)'} """ if compat.callable(fn): spec = compat.inspect_getfullargspec(fn) else: # we accept an existing argspec... spec = fn args = inspect.formatargspec(*spec) if spec[0]: self_arg = spec[0][0] elif spec[1]: self_arg = '%s[0]' % spec[1] else: self_arg = None if compat.py3k: apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2], None, spec[4]) num_defaults = 0 if spec[3]: num_defaults += len(spec[3]) if spec[4]: num_defaults += len(spec[4]) name_args = spec[0] + spec[4] else: apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2]) num_defaults = 0 if spec[3]: num_defaults += len(spec[3]) name_args = spec[0] if num_defaults: defaulted_vals = name_args[0 - num_defaults:] else: defaulted_vals = () apply_kw = inspect.formatargspec(name_args, spec[1], spec[2], defaulted_vals, formatvalue=lambda x: '=' + x) if grouped: return dict(args=args, self_arg=self_arg, apply_pos=apply_pos, apply_kw=apply_kw) else: return dict(args=args[1:-1], self_arg=self_arg, apply_pos=apply_pos[1:-1], apply_kw=apply_kw[1:-1])
def getCallTip(command='', locals=None): """For a command, return a tuple of object name, argspec, tip text. The call tip information will be based on the locals namespace.""" calltip = ('', '', '') # object name, argspec, tip text. # Get the proper chunk of code from the command. root = getRoot(command, terminator='(') try: if locals is not None: obj = eval(root, locals) else: obj = eval(root) except: return calltip name = '' obj, dropSelf = getBaseObject(obj) try: name = obj.__name__ except AttributeError: pass tip1 = '' argspec = '' if inspect.isbuiltin(obj): # Builtin functions don't have an argspec that we can get. pass elif inspect.isfunction(obj): # tip1 is a string like: "getCallTip(command='', locals=None)" argspec = inspect.getargspec(obj) if not PY3 else inspect.getfullargspec(obj) argspec = inspect.formatargspec(*argspec) if dropSelf: # The first parameter to a method is a reference to an # instance, usually coded as "self", and is usually passed # automatically by Python; therefore we want to drop it. temp = argspec.split(',') if len(temp) == 1: # No other arguments. argspec = '()' elif temp[0][:2] == '(*': # first param is like *args, not self pass else: # Drop the first argument. argspec = '(' + ','.join(temp[1:]).lstrip() tip1 = name + argspec doc = '' if callable(obj): try: doc = inspect.getdoc(obj) except: pass if doc: # tip2 is the first separated line of the docstring, like: # "Return call tip text for a command." # tip3 is the rest of the docstring, like: # "The call tip information will be based on ... <snip> firstline = doc.split('\n')[0].lstrip() if tip1 == firstline or firstline[:len(name)+1] == name+'(': tip1 = '' else: tip1 += '\n\n' docpieces = doc.split('\n\n') tip2 = docpieces[0] tip3 = '\n\n'.join(docpieces[1:]) tip = '%s%s\n\n%s' % (tip1, tip2, tip3) else: tip = tip1 calltip = (name, argspec[1:-1], tip.strip()) return calltip
def get_signature(func): regargs, varargs, varkwargs, defaults = inspect.getargspec(func) return inspect.formatargspec(regargs, varargs, varkwargs, defaults, formatvalue=lambda value: "")[1:-1]
def entry_for_one_class(nom, cls): """ Generate a BUILD dictionary entry for a class. nom: name like 'python_binary' cls: class like pants.python_binary""" if issubclass(cls, Target): # special case for Target classes: "inherit" information up the class tree. args_accumulator = [] defaults_accumulator = () docs_accumulator = [] for c in inspect.getmro(cls): if not issubclass(c, Target): continue if not inspect.ismethod(c.__init__): continue args, _, _, defaults = inspect.getargspec(c.__init__) args_accumulator = args[1:] + args_accumulator defaults_accumulator = (defaults or ()) + defaults_accumulator dedented_doc = indent_docstring_by_n(c.__init__.__doc__, 0) docs_accumulator.append(shard_param_docstring(dedented_doc)) # Suppress these from BUILD dictionary: they're legit args to the # Target implementation, but they're not for BUILD files: assert(args_accumulator[1] == 'address') assert(args_accumulator[2] == 'build_graph') assert(args_accumulator[3] == 'payload') args_accumulator = [args_accumulator[0]] + args_accumulator[4:] defaults_accumulator = (defaults_accumulator[0],) + defaults_accumulator[4:] argspec = inspect.formatargspec(args_accumulator, None, None, defaults_accumulator) # Suppress these from BUILD dictionary: they're legit args to the # Target implementation, but they're not for BUILD files: suppress = set(['address', 'build_graph', 'payload']) funcdoc = '' for shard in docs_accumulator: for param, parts in shard.items(): if param in suppress: continue suppress.add(param) # only show things once if 'param' in parts: funcdoc += '\n:param {0}: {1}'.format(param, parts['param']) if 'type' in parts: funcdoc += '\n:type {0}: {1}'.format(param, parts['type']) else: args, varargs, varkw, defaults = inspect.getargspec(cls.__init__) argspec = inspect.formatargspec(args[1:], varargs, varkw, defaults) funcdoc = cls.__init__.__doc__ methods = [] for attrname in dir(cls): attr = getattr(cls, attrname) attr_bdi = get_builddict_info(attr) if attr_bdi is None: continue if inspect.ismethod(attr): methods.append(entry_for_one_method(attrname, attr)) continue raise TaskError('@manual.builddict on non-method %s within class %s ' 'but I only know what to do with methods' % (attrname, nom)) return entry(nom, classdoc=cls.__doc__, argspec=argspec, funcdoc=funcdoc, methods=methods, impl='{0}.{1}'.format(cls.__module__, cls.__name__))
def _signature_str(function_name, arg_spec): """Helper function to output a function signature""" arg_spec_str = inspect.formatargspec(*arg_spec) return '{}{}'.format(function_name, arg_spec_str)
def format_motor_args(pymongo_method, is_async_method): argspec = get_motor_argspec(pymongo_method, is_async_method) formatted_argspec = inspect.formatargspec(*argspec) # escape backslashes for reST return formatted_argspec.replace('\\', '\\\\')
def filter_args(func, ignore_lst, *args, **kwargs): """ Filters the given args and kwargs using a list of arguments to ignore, and a function specification. Parameters ---------- func: callable Function giving the argument specification ignore_lst: list of strings List of arguments to ignore (either a name of an argument in the function spec, or '*', or '**') *args: list Positional arguments passed to the function. **kwargs: dict Keyword arguments passed to the function Returns ------- filtered_args: list List of filtered positional arguments. filtered_kwdargs: dict List of filtered Keyword arguments. """ args = list(args) if isinstance(ignore_lst, basestring): # Catch a common mistake raise ValueError('ignore_lst must be a list of parameters to ignore ' '%s (type %s) was given' % (ignore_lst, type(ignore_lst))) # Special case for functools.partial objects if (not inspect.ismethod(func) and not inspect.isfunction(func)): if ignore_lst: warnings.warn('Cannot inspect object %s, ignore list will ' 'not work.' % func, stacklevel=2) return {'*': args, '**': kwargs} arg_spec = inspect.getargspec(func) # We need to if/them to account for different versions of Python if hasattr(arg_spec, 'args'): arg_names = arg_spec.args arg_defaults = arg_spec.defaults arg_keywords = arg_spec.keywords arg_varargs = arg_spec.varargs else: arg_names, arg_varargs, arg_keywords, arg_defaults = arg_spec arg_defaults = arg_defaults or {} if inspect.ismethod(func): # First argument is 'self', it has been removed by Python # we need to add it back: args = [ func.im_self, ] + args # XXX: Maybe I need an inspect.isbuiltin to detect C-level methods, such # as on ndarrays. _, name = get_func_name(func, resolv_alias=False) arg_dict = dict() arg_position = -1 for arg_position, arg_name in enumerate(arg_names): if arg_position < len(args): # Positional argument or keyword argument given as positional arg_dict[arg_name] = args[arg_position] else: position = arg_position - len(arg_names) if arg_name in kwargs: arg_dict[arg_name] = kwargs.pop(arg_name) else: try: arg_dict[arg_name] = arg_defaults[position] except (IndexError, KeyError): # Missing argument raise ValueError( 'Wrong number of arguments for %s%s:\n' ' %s(%s, %s) was called.' % (name, inspect.formatargspec( *inspect.getargspec(func)), name, repr(args)[1:-1], ', '.join('%s=%s' % (k, v) for k, v in kwargs.iteritems()))) varkwargs = dict() for arg_name, arg_value in kwargs.iteritems(): if arg_name in arg_dict: arg_dict[arg_name] = arg_value elif arg_keywords is not None: varkwargs[arg_name] = arg_value else: raise TypeError("Ignore list for %s() contains an unexpected " "keyword argument '%s'" % (name, arg_name)) if arg_keywords is not None: arg_dict['**'] = varkwargs if arg_varargs is not None: varargs = args[arg_position + 1:] arg_dict['*'] = varargs # Now remove the arguments to be ignored for item in ignore_lst: if item in arg_dict: arg_dict.pop(item) else: raise ValueError("Ignore list: argument '%s' is not defined for " "function %s%s" % (item, name, inspect.formatargspec( arg_names, arg_varargs, arg_keywords, arg_defaults, ))) # XXX: Return a sorted list of pairs? return arg_dict
obj = eval(line, GLOB, LOC) except (SystemError, KeyboardInterrupt), e: raise except: print "Object '%s' not found" % line else: try: print '\t', obj.__class__ except AttributeError: pass try: print '\t', inspect.getabsfile(obj) except (NameError, TypeError): pass if inspect.isfunction(obj): print '\tDefinition: ' + obj.__name__ + inspect.formatargspec( *inspect.getargspec(obj)) print ' ', obj.__doc__ def execute(line): global LOC, GLOB try: exec 'print repr(' + line + ')' in LOC, GLOB except (SystemError, KeyboardInterrupt), e: raise except: try: exec line in LOC, GLOB except (SystemError, KeyboardInterrupt), e: raise except:
def _formatdef(func): return "%s%s" % ( func.__name__, inspect.formatargspec(*inspect.getargspec(func)), )
def _wrap_sig(func, requiredArgs, optionalArgs, withVarkw=False, withVarargs=False): """ Wrap a function in a function with a definied signature (i.e. args, *args and **kwargs). This function works around a problem PEP-0262 is designed to address. When wrapping functions using decorators you loose the function signature (visible via inspect.getargspec()). This is a problem for Pylons because it uses inspection to dispatch controller actions. Not all signature information is retained in the wrapper. Optional arguments are supported but their default values are not visible (the wrapped method will handle them as usual). @param func: A function to be wrapped @param requiredArgs: Required argument names @param optionalArgs: Optional argument names @param withVarargs: If True allow variable arguments @param withVarkw: If True allow variable keyword arguments @return: A function with the given argument signature which wraps func. """ # Default acts as a singleton to mark optional arguments class Default: pass if withVarkw: varkw = 'varkw_in' else: varkw = None if withVarargs: varargs = 'varargs_in' else: varargs = None args = requiredArgs + optionalArgs first_default = len(requiredArgs) def formatarg(arg): i = args.index(arg) if i < first_default: return arg else: return '%s=_wrap_default' % arg def process(localVars): args = [localVars[x] for x in requiredArgs] args += localVars.get('varargs_in', []) kwargs = localVars.get('varkw_in', {}) for arg in optionalArgs: if localVars[arg] != Default: kwargs[arg] = localVars[arg] return args, kwargs wrap_vars = dict(_wrap_func=func, _wrap_process=process, _wrap_default=Default) wrap_sig = inspect.formatargspec(args, varargs, varkw, formatarg=formatarg) wrap_expr = """ def %s%s: args, kwargs = _wrap_process(locals()) return _wrap_func(*args, **kwargs)""" % (func.__name__, wrap_sig) exec wrap_expr in wrap_vars return wrap_vars[func.__name__]
def __init__(self, func=None, name=None, signature=None, defaults=None, doc=None, module=None, funcdict=None): self.shortsignature = signature if func: # func can be a class or a callable, but not an instance method self.name = func.__name__ if self.name == '<lambda>': # small hack for lambda functions self.name = '_lambda_' self.doc = func.__doc__ self.module = func.__module__ if inspect.isfunction(func): argspec = getfullargspec(func) self.annotations = getattr(func, '__annotations__', {}) for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs', 'kwonlydefaults'): setattr(self, a, getattr(argspec, a)) for i, arg in enumerate(self.args): setattr(self, 'arg%d' % i, arg) if sys.version < '3': # easy way self.shortsignature = self.signature = \ inspect.formatargspec( formatvalue=lambda val: "", *argspec)[1:-1] else: # Python 3 way allargs = list(self.args) allshortargs = list(self.args) if self.varargs: allargs.append('*' + self.varargs) allshortargs.append('*' + self.varargs) elif self.kwonlyargs: allargs.append('*') # single star syntax for a in self.kwonlyargs: allargs.append('%s=None' % a) allshortargs.append('%s=%s' % (a, a)) if self.varkw: allargs.append('**' + self.varkw) allshortargs.append('**' + self.varkw) self.signature = ', '.join(allargs) self.shortsignature = ', '.join(allshortargs) self.dict = func.__dict__.copy() # func=None happens when decorating a caller if name: self.name = name if signature is not None: self.signature = signature if defaults: self.defaults = defaults if doc: self.doc = doc if module: self.module = module if funcdict: self.dict = funcdict # check existence required attributes assert hasattr(self, 'name') if not hasattr(self, 'signature'): raise TypeError('You are decorating a non function: %s' % func)
def generate_networkx_graph_reference(generators='all', print=print, output=sys.stdout): """ Introspect and iterate over network.generators.<module>.<fn>_graph For when sphinx would be too much. """ tests_path = resource_filename('networkx', 'generators/tests') sys.path.append(tests_path) # generators=('classic', 'small', ...) if generators == 'all': generatorsrc = resource_stream('networkx', 'generators/__init__.py') generatorlist = tuple( n.split('.')[2].split()[0] for n in generatorsrc if n.startswith('from networkx.generators.')) else: generatorlist = tuple(generators) c = RSTContext(output=output) c.title = "networkx reference graphs" c.print_rest_title(c.title) c.print_rest_meta("Version", nx.__version__) c.print_rest_meta( "Copyright", "Copyright NetworkX: %s. `<%s>`_\n" % (nx.__license__, "http://networkx.lanl.gov")) c.print_rest_meta("SeeAlso", "`<https://github.com/networkx/networkx>`_") c.print_rest_directive("contents", depth=2) c.print_rest_directive("sectnum") generators = OrderedDict() for g in generatorlist: c.print_rest_header(str(g), "=") Generators = getattr(nx.generators, g) generators[g] = [] if Generators.__doc__: c.print_rest_docstring(Generators) fn_filter = lambda x: x.endswith('_graph') Functions = filter(fn_filter, dir(Generators)) if Functions: c.print(".. Functions:") c.print_rest_list(Functions, indentstr=('.. ')) generators[g] = dict(izip(Functions, repeat([]))) c.print_rest_directive("contents", local='', depth=1) TestsFile, Tests, TestClass, TestFuncs = None, None, None, None # nx.generators.tests.test_${g} TestsFile = 'test_%s' % g TestsFilePath = resource_filename('networkx', 'generators/tests/%s.py' % TestsFile) TestClassName = 'TestGenerator%s' % g.capitalize() TestMethodFilter = lambda x: x.startswith("test") try: Tests = __import__(TestsFile) except ImportError: pass try: TestClass = getattr(Tests, TestClassName) TestFuncs = filter(TestMethodFilter, dir(TestClass)) except AttributeError: pass for graph_fn in Functions: graph_fn_path = "%s.%s" % (g, graph_fn) GraphFunction = getattr(Generators, graph_fn) c.print_rest_header(graph_fn_path, '-') c.print_rest_directive("contents", local='', depth=1) if GraphFunction.__doc__: c.print_rest_docstring(GraphFunction) argspec = inspect.getargspec(GraphFunction) # asr.add_argspec(argspec) c.print_rest_preformatted(inspect.formatargspec(argspec), header="``%s`` argspec" % graph_fn) #c.print_rest_argspec( # sage_getargspec(GraphFunction), # header = "``%s`` argspec ast" % graph_fn) c.print_rest_header('src: ``%s``' % graph_fn_path, '~') c.print_rest_source_lines(GraphFunction, header="source") if TestFuncs: for fn in ifilter(lambda x: graph_fn in x, TestFuncs): # ... c.print_rest_header("test_function: ``%s``" % fn, "~") c.print_rest_source_lines(getattr(TestClass, fn), header="``%s``" % fn) #else: # c.print_rest_preformatted("# No tests found"), if Tests: c.print_rest_header('tests grep for ``%s``' % graph_fn, "~") test_examples = [] c.print_rest_preformatted( format_numbered_line_iter( parse_for_examples(grep_file( filename=TestsFilePath, searchfn=lambda x: graph_fn in x), func_name=graph_fn, examples=test_examples)), header="``networkx.generators.tests.%s``" % TestsFile) c.print_rest_header('ast examples', '~') #c.print_rest_preformatted( # parse_for_examples_ast( # source=inspect.getsourcelines(GraphFunction)[0]), # header='ast examples') c.print_rest_header('test_examples for ``%s``' % graph_fn, "~") c.print_rest_preformatted(test_examples, header='examples') generators[g][graph_fn] = test_examples c.print_rest_args_summary(c.argspecs) c.print_rest_header("generators", "=") c.print_rest_preformatted(pformat(dict(generators))) return c.file
def format_args(fn): argspec = inspect.getargspec(fn) return inspect.formatargspec(*argspec)
def GenerateForFunction(name, val, obj, indent, file): """ Generate for the callable with given name. val is the callable. """ import_line = None args = '' retval = '' # Try to get the signature in 3.4+, which uses argument clinic text if inspect and sys.version_info[:2] >= (3, 4) and (not kPyQt or name != '__init__'): try: sig = inspect.signature(val) except ValueError: sig = None if sig: for i, (arg_name, param) in enumerate(sig.parameters.items()): if i != 0: args += ', ' args += arg_name if param.default != param.empty: args += '=' + str(param.default) if sig.return_annotation != sig.empty: # Currently this is never reached pass if not args or not retval: # Prefer argument clinic args if found above if args: saved_args = args else: saved_args = None # Trick to get init docs from class level doc where it usually is if name == '__init__': doc1 = getattr(val, '__doc__', '') if doc1 is None: doc1 = '' elif version >= ( 3, 0 ) and doc1 == object.__init__.__doc__ and val != object.__init__: doc1 = '' doc2 = getattr(obj, '__doc__', '') if doc2 is None: doc2 = '' args, retval = _GetCallableSignature(doc2 + '\n' + doc1) if not args.startswith('self'): if args: args = 'self, ' + args else: args = 'self' elif kIronPython: args, import_line, retval = GetCallableSignatureIPy(val, obj, name) else: args, retval = GetCallableSignature(val) # Restore argument clinic args, if any if saved_args: args = saved_args # Try to fall back on inspect, tho this only works if the module # is not an extension module or contains some methods defined in Python if args == '' and inspect is not None: try: fval = getattr(val, 'im_func', val) args = inspect.formatargspec(inspect.getargspec(fval)[0]) args = args[1:-1] except: args = '' if type(obj) == PyType_Type or hasattr(val, 'im_func'): if len(args) > 0 and string_find(args, 'self') != 0: args = 'self, ' + args elif string_find(args, 'self') < 0: args = 'self' # Write the definition write(file, indent + 'def %s(%s):\n' % (name, args)) WriteDocString(val, file, indent + ' ') if import_line is not None: write(file, indent + ' %s\n' % import_line) for line in retval.splitlines(): write(file, indent + ' %s\n' % line) write(file, '\n')
def dumpDocs(self): #try: result = dialog.directoryDialog(None, 'Create widgets_documention in:', '') if result.accepted: widgetsDir = result.path else: return widgetsDir = os.path.join(widgetsDir, 'components') if not os.path.exists(widgetsDir): os.mkdir(widgetsDir) imagesDir = os.path.join(widgetsDir, 'images') if not os.path.exists(imagesDir): os.mkdir(imagesDir) toc = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">' toc += '<html>\n<head><title>%s</title></head><body>\n' % 'PythonCard Components' toc += '<h1>PythonCard Components</h1>\n' componentsList = [] for w in self.components.itervalues(): if w.__class__.__name__.startswith(w.name[3:]): # document each widget name = w.__class__.__name__ spec = w._spec doc = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">' doc += '<html>\n<head><title>%s</title></head><body>\n' % ( name + ': PythonCard component') doc += '<h1>Component: %s</h1>' % name doc += '\n<img src="%s"><BR>\n' % ('images/' + name + '.png') doc += '\n<h2>Required Attributes</h2>\n' doc += '<table border="1">\n' doc += '<tr><td><b>Name<b></td><td><b>Default value</b></td></tr>\n' for a in self.getAttributesList(spec.getRequiredAttributes()): doc += "<tr><td>%s</td><td>%s</td></tr>\n" % (a[0], a[1]) doc += '</table>' doc += '\n\n<h2>Optional Attributes</h2>\n' doc += '<table border="1">\n' doc += '<tr><td><b>Name<b></td><td><b>Default value</b></td></tr>\n' for a in self.getAttributesList(spec.getOptionalAttributes()): doc += "<tr><td>%s</td><td>%s</td></tr>\n" % (a[0], a[1]) doc += '</table>' doc += '\n\n<h2>Events:</h2>\n' doc += '<table border="1">\n' for e in self.getEventsList(spec): doc += "<tr><td>%s</td></tr>\n" % e doc += '</table>' doc += '\n\n<h2>Methods:</h2>\n' doc += '<table border="1">\n' td = '<td><b>%s</b></td>' * 4 tr = '<tr>' + td + '</tr>\n' doc += tr % ('method', 'args', 'doc string', 'comments') for e in self.getMethodsList(w): method = getattr(w, e) docstring = inspect.getdoc(method) if docstring is None: docstring = " " comments = inspect.getcomments(method) if comments is None: comments = " " #source = inspect.getcomments(method) argspec = inspect.getargspec(method) formattedargs = inspect.formatargspec( argspec[0], argspec[1], argspec[2], argspec[3]) doc += "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n" % \ (e, formattedargs, docstring, comments) doc += '</table>' # need to decide what we want to dump from the methods # we probably don't want to dump everything including # wxPython methods, so this is where we need to decide # on the case of the first letter of the method # whatever is done here should be the same thing used # to display methods in the shell # arg lists and tooltips (docstrings) will be used here too # write out the documentation for the component doc += '\n<hr><img src="http://sourceforge.net/sflogo.php?group_id=19015&type=1" width="88" height="31" border="0" alt="SourceForge Logo">' doc += '\n</body>\n</html>' filename = name + '.html' path = os.path.join(widgetsDir, filename) f = open(path, 'w') f.write(doc) f.close() # create an image using the actual component # on screen # comment this out once you have created the images # you want bmp = wx.EmptyBitmap(w.size[0], w.size[1]) memdc = wx.MemoryDC() memdc.SelectObject(bmp) dc = wx.WindowDC(w) memdc.BlitPointSize((0, 0), w.size, dc, (0, 0)) imgfilename = os.path.join(imagesDir, name + '.png') bmp.SaveFile(imgfilename, wx.BITMAP_TYPE_PNG) dc = None memdc.SelectObject(wx.NullBitmap) memdc = None bmp = None componentsList.append('<a href="%s">%s</a><br>\n' % (filename, name)) # now create the table of contents, index.html componentsList.sort() for c in componentsList: toc += c toc += '\n<hr><img src="http://sourceforge.net/sflogo.php?group_id=19015&type=1" width="88" height="31" border="0" alt="SourceForge Logo">' toc += '\n</body>\n</html>' filename = os.path.join(widgetsDir, 'index.html') f = open(filename, 'w') f.write(toc) f.close()