X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/d0ab1d8908cadac9f51a17e2fe9e1193f14e28cc..0e87ae0739ed3e72301b7b718098f97a7f06a5d8:/apps/piston/doc.py?ds=sidebyside diff --git a/apps/piston/doc.py b/apps/piston/doc.py new file mode 100644 index 000000000..63f89ecd4 --- /dev/null +++ b/apps/piston/doc.py @@ -0,0 +1,195 @@ +import inspect, handler + +from piston.handler import typemapper +from piston.handler import handler_tracker + +from django.core.urlresolvers import get_resolver, get_callable, get_script_prefix +from django.shortcuts import render_to_response +from django.template import RequestContext + +def generate_doc(handler_cls): + """ + Returns a `HandlerDocumentation` object + for the given handler. Use this to generate + documentation for your API. + """ + if not type(handler_cls) is handler.HandlerMetaClass: + raise ValueError("Give me handler, not %s" % type(handler_cls)) + + return HandlerDocumentation(handler_cls) + +class HandlerMethod(object): + def __init__(self, method, stale=False): + self.method = method + self.stale = stale + + def iter_args(self): + args, _, _, defaults = inspect.getargspec(self.method) + + for idx, arg in enumerate(args): + if arg in ('self', 'request', 'form'): + continue + + didx = len(args)-idx + + if defaults and len(defaults) >= didx: + yield (arg, str(defaults[-didx])) + else: + yield (arg, None) + + @property + def signature(self, parse_optional=True): + spec = "" + + for argn, argdef in self.iter_args(): + spec += argn + + if argdef: + spec += '=%s' % argdef + + spec += ', ' + + spec = spec.rstrip(", ") + + if parse_optional: + return spec.replace("=None", "=") + + return spec + + @property + def doc(self): + return inspect.getdoc(self.method) + + @property + def name(self): + return self.method.__name__ + + @property + def http_name(self): + if self.name == 'read': + return 'GET' + elif self.name == 'create': + return 'POST' + elif self.name == 'delete': + return 'DELETE' + elif self.name == 'update': + return 'PUT' + + def __repr__(self): + return "" % self.name + +class HandlerDocumentation(object): + def __init__(self, handler): + self.handler = handler + + def get_methods(self, include_default=False): + for method in "read create update delete".split(): + met = getattr(self.handler, method, None) + + if not met: + continue + + stale = inspect.getmodule(met) is handler + + if not self.handler.is_anonymous: + if met and (not stale or include_default): + yield HandlerMethod(met, stale) + else: + if not stale or met.__name__ == "read" \ + and 'GET' in self.allowed_methods: + + yield HandlerMethod(met, stale) + + def get_all_methods(self): + return self.get_methods(include_default=True) + + @property + def is_anonymous(self): + return handler.is_anonymous + + def get_model(self): + return getattr(self, 'model', None) + + @property + def has_anonymous(self): + return self.handler.anonymous + + @property + def anonymous(self): + if self.has_anonymous: + return HandlerDocumentation(self.handler.anonymous) + + @property + def doc(self): + return self.handler.__doc__ + + @property + def name(self): + return self.handler.__name__ + + @property + def allowed_methods(self): + return self.handler.allowed_methods + + def get_resource_uri_template(self): + """ + URI template processor. + + See http://bitworking.org/projects/URI-Templates/ + """ + def _convert(template, params=[]): + """URI template converter""" + paths = template % dict([p, "{%s}" % p] for p in params) + return u'%s%s' % (get_script_prefix(), paths) + + try: + resource_uri = self.handler.resource_uri() + + components = [None, [], {}] + + for i, value in enumerate(resource_uri): + components[i] = value + + lookup_view, args, kwargs = components + lookup_view = get_callable(lookup_view, True) + + possibilities = get_resolver(None).reverse_dict.getlist(lookup_view) + + for possibility, pattern in possibilities: + for result, params in possibility: + if args: + if len(args) != len(params): + continue + return _convert(result, params) + else: + if set(kwargs.keys()) != set(params): + continue + return _convert(result, params) + except: + return None + + resource_uri_template = property(get_resource_uri_template) + + def __repr__(self): + return u'' % self.name + +def documentation_view(request): + """ + Generic documentation view. Generates documentation + from the handlers you've defined. + """ + docs = [ ] + + for handler in handler_tracker: + docs.append(generate_doc(handler)) + + def _compare(doc1, doc2): + #handlers and their anonymous counterparts are put next to each other. + name1 = doc1.name.replace("Anonymous", "") + name2 = doc2.name.replace("Anonymous", "") + return cmp(name1, name2) + + docs.sort(_compare) + + return render_to_response('documentation.html', + { 'docs': docs }, RequestContext(request))