def __init__(self, module, name): self.name = re.sub('Handler', '', name) self.handler = getattr(module, name) if type(self.handler) is not HandlerMetaClass or name == 'BaseHandler': raise HandlerTypeError self.handler_docs = HandlerDocumentation(self.handler) self.model_fields = [] if hasattr(self.handler, 'models'): self.model_fields = [field.get_attname() for model in self.handler.models for field in model._meta._fields()] else: self.model_fields = [str(field.get_attname()) for field in self.handler.model._meta._fields()] self.fields = self._get_base_fields() self.methods = [] for method in self.handler_docs.get_methods(): docstring = method.get_doc() api_handler = self._get_method_api_handler(docstring) if not api_handler: continue http_method = api_handler.get('method').upper() method_params = self._get_method_params(docstring, http_method, api_handler) if not method_params: continue self.methods.append({'name': method.name, 'params': method_params, 'return_path': http_method in ['POST', "PUT", 'DELETE'] and 'success' or 'data.%s' % self.name.lower(), 'http_method': http_method, 'comment': api_handler.get('comment', '').strip(), 'url': api_handler.get('url')})
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 ObjectHandlerMetaClass \ or type(handler_cls) is handler.HandlerMetaClass): raise ValueError("Give me handler, not %s" % type(handler_cls)) return HandlerDocumentation(handler_cls)
class HandlerADL(object): def __init__(self, module, name): self.name = re.sub('Handler', '', name) self.handler = getattr(module, name) if type(self.handler) is not HandlerMetaClass or name == 'BaseHandler': raise HandlerTypeError self.handler_docs = HandlerDocumentation(self.handler) self.model_fields = [] if hasattr(self.handler, 'models'): self.model_fields = [field.get_attname() for model in self.handler.models for field in model._meta._fields()] else: self.model_fields = [str(field.get_attname()) for field in self.handler.model._meta._fields()] self.fields = self._get_base_fields() self.methods = [] for method in self.handler_docs.get_methods(): docstring = method.get_doc() api_handler = self._get_method_api_handler(docstring) if not api_handler: continue http_method = api_handler.get('method').upper() method_params = self._get_method_params(docstring, http_method, api_handler) if not method_params: continue self.methods.append({'name': method.name, 'params': method_params, 'return_path': http_method in ['POST', "PUT", 'DELETE'] and 'success' or 'data.%s' % self.name.lower(), 'http_method': http_method, 'comment': api_handler.get('comment', '').strip(), 'url': api_handler.get('url')}) def __getitem__(self, key): if key in ['id', 'fields', 'methods']: return getattr(self, key) raise KeyError def _get_base_fields(self): docstring = self.handler.__doc__ if not docstring: return [] field_declarations = re.findall(VAR_REGEX, docstring) fields = [self._get_dict_from_var_declaration(declaration) for declaration in field_declarations] return fields def _get_method_params(self, docstring, http_method, api_handler): ret = [] if not docstring: return ret variable_declarations = re.findall(VAR_REGEX, docstring) for declaration in variable_declarations: param = self._get_dict_from_var_declaration(declaration) if param['key'] in self.model_fields: param['field'] = param['key'] fieldDict = copy.deepcopy(param) existing_field = filter(lambda f: f['name'] == fieldDict['name'], self.fields) if existing_field: if http_method in ('POST', 'PUT', 'DELETE') and existing_field[0]['access'] != 'key': existing_field[0]['access'] = 'rw' else: fieldDict['access'] = http_method in ('POST', 'PUT', 'DELETE') and 'rw' or 'ro' self.fields.append(fieldDict) if "{%s}" % param['key'] in api_handler.get('url', ''): param['style'] = 'template' if re.search('(optional)', declaration): param['required'] = '0' else: param['required'] = '1' ret.append(param) return ret def _get_dict_from_var_declaration(self, declaration): param = re.search(r'^\@(?P<name>[\w]+)[\ ]+\[(?P<type>[\w\[\]]+)\]', declaration).groupdict() param['type'] = type_mappings.get(param['type'], param['type']) param['key'] = param['name'] param['access'] = 'ro' if '_' in param['name']: words = param['name'].split('_') # use mixedCase for name instead of under_score, fooId also becomes fooID param['name'] = re.sub('Id', 'ID', words[0] + ''.join(string.capwords(s) for s in words[1:])) if 'id' in param['name'].lower(): param['access'] = 'key' return param def _get_method_api_handler(self, docstring): if not docstring: return {} api_handler = re.search(r'(?P<comment>[\w.\ \n\/]+)?api handler\: (?P<method>post|put|get|delete)[\ ](?P<url>.+)', docstring, flags=re.IGNORECASE) if api_handler: return api_handler.groupdict()