From: Tim Serong Date: Thu, 30 Jun 2016 06:38:11 +0000 (+1000) Subject: mgr: api_docs.py: Update for use outside Calamari X-Git-Tag: v11.0.1~60^2~50 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=eafe2e94463987caf8cdb2d5315598551916e940;p=ceph.git mgr: api_docs.py: Update for use outside Calamari The ceph_state module is implemented in C++, and isn't available at build time, which causes import failures when api_docs.py tries to import calamari_rest in order to introspect it (MgrModule is eventually imported, which in turn tries to import ceph_state, which fails unless we stub it out). Additional changes: * Search calamari_rest.urls (not calamari_web) calamari_web isn't available - it largely held static content in Calamari, and in turn included calamari_rest.urls. Here in ceph-mgr we only have calamari_rest. * note that --list-urls does nothing, apparently * Pass actions to old as_view method django-rest-framework 3.x raises TypeError if the actions argument isn't passed to as_view(). * Use view().get_view_name() instead of metadata Attempting to access view().metadata(None)['name'] results in "AttributeError: 'super' object has no attribute 'metadata'". * Use somewhat unfriendly field class names django-rest-framework 3.x seems to have done away with type_label for fields, so instead use the field's class name, which is somewhat unfriendly, but arguably better than nothing. * import global_instance to fix ImportError This is necessary to avoid what seems to be weird import loops (if this isn't present, we later get "ImportError: cannot import name UserRequest" or similar). * Make api_examples.json optional This way we at least get bare docs with no examples, rather than no docs at all. * Explain how to generate API docs Signed-off-by: Tim Serong --- diff --git a/src/pybind/mgr/calamari_rest/management/commands/api_docs.py b/src/pybind/mgr/calamari_rest/management/commands/api_docs.py index c9922ee73f2c..bbaca1777598 100644 --- a/src/pybind/mgr/calamari_rest/management/commands/api_docs.py +++ b/src/pybind/mgr/calamari_rest/management/commands/api_docs.py @@ -1,3 +1,18 @@ +# +# If Django is installed locally, run the following command from the top of +# the ceph source tree: +# +# PYTHONPATH=src/pybind/mgr \ +# DJANGO_SETTINGS_MODULE=calamari_rest.settings \ +# CALAMARI_CONFIG=src/pybind/mgr/calamari.conf \ +# django-admin api_docs +# +# This will create resources.rst (the API docs), and rest.log (which will +# probably just be empty). +# +# TODO: Add the above to a makefile, so the docs land somewhere sane. +# + from collections import defaultdict import json from optparse import make_option @@ -12,8 +27,15 @@ from django.core.urlresolvers import RegexURLPattern, RegexURLResolver import sys import codecs -from calamari_rest.serializers.v2 import ValidatingSerializer +class ceph_state: + pass + +sys.modules["ceph_state"] = ceph_state +# Needed to avoid weird import loops +from rest import global_instance + +from calamari_rest.serializers.v2 import ValidatingSerializer GENERATED_PREFIX = "." @@ -28,7 +50,7 @@ old_as_view = rest_framework.viewsets.ViewSetMixin.as_view @classmethod def as_view(cls, actions=None, **initkwargs): - view = old_as_view.__func__(cls) + view = old_as_view.__func__(cls, actions, **initkwargs) view._actions = actions return view @@ -193,7 +215,7 @@ class ApiIntrospector(object): continue view_to_url_patterns[view_cls].append(url_pattern) - self.prefix = _find_prefix("calamari_web.urls", url_module) + self.prefix = _find_prefix("calamari_rest.urls", url_module) parse_urls(importlib.import_module(url_module).urlpatterns) self.view_to_url_patterns = sorted(view_to_url_patterns.items(), cmp=lambda x, y: cmp(x[0].__name__, y[0].__name__)) @@ -208,7 +230,7 @@ class ApiIntrospector(object): """ Output RsT for one API view """ - name = view().metadata(None)['name'] + name = view().get_view_name() if view.__doc__: view_help_text = view.__doc__ @@ -261,7 +283,7 @@ class ApiIntrospector(object): field_help_text = "" field_table.append( [field_name, - field.type_label, + field.__class__.__name__, str(field.read_only), create, modify, @@ -286,7 +308,7 @@ class ApiIntrospector(object): row = [_pretty_url(self.prefix, url_pattern)] - view_name = view().metadata(None)['name'] + view_name = view().get_view_name() row.append( u":ref:`{0} <{1}>`".format(view_name.replace(" ", unichr(0x00a0)), view.__name__) ) @@ -368,14 +390,15 @@ class Command(NoArgsCommand): def handle_noargs(self, list_urls, **options): introspector = ApiIntrospector("calamari_rest.urls.v2") if list_urls: + # TODO: this just prints an empty array (not sure why) print json.dumps(introspector.get_url_list()) else: try: try: examples = json.load(open(EXAMPLES_FILE, 'r')) except IOError: - print >>sys.stderr, "Examples data '%s' not found, have you run test_rest_api?" % EXAMPLES_FILE - return + examples = {} + print >>sys.stderr, "Examples data '%s' not found, no examples will be generated" % EXAMPLES_FILE introspector.write_docs(examples) except: