From 1913850b3d2fc5f7fee684500a8723da814643b0 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 12 Dec 2015 20:24:46 +0000 Subject: [PATCH 1/8] Split to Api Docs & Api Endpoint --- drfdocs/api_docs.py | 14 ++++++++------ drfdocs/api_endpoint.py | 18 ++++++++++++++++++ drfdocs/templates/drfdocs/home.html | 6 ++++-- drfdocs/views.py | 2 +- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/drfdocs/api_docs.py b/drfdocs/api_docs.py index 809f214..e673462 100644 --- a/drfdocs/api_docs.py +++ b/drfdocs/api_docs.py @@ -1,22 +1,24 @@ from django.conf import settings from django.core.urlresolvers import RegexURLResolver, RegexURLPattern +from drfdocs.api_endpoint import ApiEndpoint class ApiDocumentation(object): excluded_apps = ["admin", "drfdocs"] excluded_endpoints = ["serve"] - root_urlconf = __import__(settings.ROOT_URLCONF) def __init__(self): - self.view_names = [] - self.get_all_view_names(self.root_urlconf.urls.urlpatterns) + self.endpoints = [] + root_urlconf = __import__(settings.ROOT_URLCONF) + self.get_all_view_names(root_urlconf.urls.urlpatterns) def get_all_view_names(self, urlpatterns): for pattern in urlpatterns: if isinstance(pattern, RegexURLResolver) and (pattern.app_name not in self.excluded_apps): self.get_all_view_names(pattern.url_patterns) elif isinstance(pattern, RegexURLPattern) and (pattern.callback.__name__ not in self.excluded_endpoints): - self.view_names.append(pattern.callback.__name__) + api_endpoint = ApiEndpoint(pattern) + self.endpoints.append(api_endpoint) - def get_views(self): - return self.view_names + def get_endpoints(self): + return self.endpoints diff --git a/drfdocs/api_endpoint.py b/drfdocs/api_endpoint.py index e69de29..100e679 100644 --- a/drfdocs/api_endpoint.py +++ b/drfdocs/api_endpoint.py @@ -0,0 +1,18 @@ +from django.contrib.admindocs.views import simplify_regex +from rest_framework.views import APIView + + +class ApiEndpoint(object): + + def __init__(self, pattern): + self.pattern = pattern + self.regex = simplify_regex(pattern._regex) + self.view_name = pattern.callback.__name__ + # self._get_api_callback(pattern) + + def _get_api_callback(self, pattern): + """ + Verifies that pattern callback is a subclass of APIView, and returns the class + """ + if (hasattr(pattern.callback, 'cls') and issubclass(pattern.callback.cls, APIView)): + return pattern.callback.cls diff --git a/drfdocs/templates/drfdocs/home.html b/drfdocs/templates/drfdocs/home.html index be7a304..65d3817 100644 --- a/drfdocs/templates/drfdocs/home.html +++ b/drfdocs/templates/drfdocs/home.html @@ -2,8 +2,10 @@ {% block content %} {% endblock %} diff --git a/drfdocs/views.py b/drfdocs/views.py index e014e3e..f577391 100644 --- a/drfdocs/views.py +++ b/drfdocs/views.py @@ -9,5 +9,5 @@ class DRFDocsView(TemplateView): def get_context_data(self, **kwargs): context = super(DRFDocsView, self).get_context_data(**kwargs) docs = ApiDocumentation() - context['views'] = docs.get_views() + context['endpoints'] = docs.get_endpoints() return context From 49f1cea20d4429f1f2019d784a924951c04dc97d Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 12 Dec 2015 20:36:20 +0000 Subject: [PATCH 2/8] Initialize website styling --- drfdocs/static/css/style.css | 27 ++++++++++++++++++++++++ drfdocs/templates/drfdocs/base.html | 32 +++++++++++++++++++++++++++-- drfdocs/templates/drfdocs/home.html | 5 ++--- 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 drfdocs/static/css/style.css diff --git a/drfdocs/static/css/style.css b/drfdocs/static/css/style.css new file mode 100644 index 0000000..62e8b9a --- /dev/null +++ b/drfdocs/static/css/style.css @@ -0,0 +1,27 @@ +body { + background-color: #FEFEFE; +} + +h1, h2, h3, h4 { + text-align: center; +} + +.jumbotron { + margin: 50px 0 40px; + text-align: center; +} + +.footer { + text-align: center; + padding: 20px; + margin-bottom: 20px; +} + +.footer .links { + padding: 20px 0; +} + +.footer .links .fa { + margin: 0 10px; + font-size: 22px; +} diff --git a/drfdocs/templates/drfdocs/base.html b/drfdocs/templates/drfdocs/base.html index 68b55d9..b9d30f8 100644 --- a/drfdocs/templates/drfdocs/base.html +++ b/drfdocs/templates/drfdocs/base.html @@ -1,13 +1,41 @@ +{% load staticfiles %} + + + + DRF Docs + + + + + + + + + + -

Django Rest Frameworks Docs

+
+
+

DRF Docs

+

Documentation for Web APIs made with Django Rest Framework.

+
- {% block content %}{% endblock %} + {% block content %}{% endblock %} + +
diff --git a/drfdocs/templates/drfdocs/home.html b/drfdocs/templates/drfdocs/home.html index 65d3817..902051d 100644 --- a/drfdocs/templates/drfdocs/home.html +++ b/drfdocs/templates/drfdocs/home.html @@ -1,11 +1,10 @@ {% extends "drfdocs/base.html" %} {% block content %} - {% endblock %} From c4f38dc0cbbf95383ebcbecb8f22c11bf59e473c Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 12 Dec 2015 20:49:57 +0000 Subject: [PATCH 3/8] Style website --- drfdocs/static/css/style.css | 29 +++++++++++++++++++++++++---- drfdocs/templates/drfdocs/base.html | 18 +++++++++--------- drfdocs/templates/drfdocs/home.html | 2 +- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/drfdocs/static/css/style.css b/drfdocs/static/css/style.css index 62e8b9a..77ee0c6 100644 --- a/drfdocs/static/css/style.css +++ b/drfdocs/static/css/style.css @@ -1,16 +1,35 @@ +/* @group Misc */ + body { background-color: #FEFEFE; } -h1, h2, h3, h4 { - text-align: center; -} - .jumbotron { margin: 50px 0 40px; text-align: center; } +/* @end Misc */ + + +/* @group Endpoint */ + +.endpoint { + padding: 5px 20px; + margin: 20px 0; + background-color: #ecf0f1; +} + +.endpoint .title { + font-family: Menlo,Monaco,Consolas,"Courier New",monospace; +} + +/* @end Endpoint */ + + + +/* @group Footer */ + .footer { text-align: center; padding: 20px; @@ -25,3 +44,5 @@ h1, h2, h3, h4 { margin: 0 10px; font-size: 22px; } + +/* @end Footer */ diff --git a/drfdocs/templates/drfdocs/base.html b/drfdocs/templates/drfdocs/base.html index b9d30f8..e2e3f9b 100644 --- a/drfdocs/templates/drfdocs/base.html +++ b/drfdocs/templates/drfdocs/base.html @@ -10,11 +10,11 @@ DRF Docs - + - + - + @@ -29,12 +29,12 @@

Documentation for Web APIs made with - - Copyright © 2015 Emmanouil Konstantinidis. + + Copyright © 2015 Emmanouil Konstantinidis. diff --git a/drfdocs/templates/drfdocs/home.html b/drfdocs/templates/drfdocs/home.html index 902051d..5904f26 100644 --- a/drfdocs/templates/drfdocs/home.html +++ b/drfdocs/templates/drfdocs/home.html @@ -3,7 +3,7 @@ {% block content %} {% for endpoint in endpoints %}
-
{{ endpoint.regex }}
+

{{ endpoint.regex }}

{{ endpoint.view_name }}

{% endfor %} From fcdb4c3038a8dd99e7a44e3a5f074bebce393380 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 12 Dec 2015 20:50:48 +0000 Subject: [PATCH 4/8] Add page title --- drfdocs/templates/drfdocs/home.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drfdocs/templates/drfdocs/home.html b/drfdocs/templates/drfdocs/home.html index 5904f26..ee836df 100644 --- a/drfdocs/templates/drfdocs/home.html +++ b/drfdocs/templates/drfdocs/home.html @@ -1,6 +1,8 @@ {% extends "drfdocs/base.html" %} {% block content %} +

API Endpoints

+ {% for endpoint in endpoints %}

{{ endpoint.regex }}

From f0882dec764cc9a4150e802552162bafd2474def Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 12 Dec 2015 20:55:52 +0000 Subject: [PATCH 5/8] Github Ribbon SVG --- drfdocs/static/css/style.css | 46 ++++++++++++++++++++++++++++- drfdocs/templates/drfdocs/base.html | 8 +++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drfdocs/static/css/style.css b/drfdocs/static/css/style.css index 77ee0c6..c53d20d 100644 --- a/drfdocs/static/css/style.css +++ b/drfdocs/static/css/style.css @@ -27,7 +27,6 @@ body { /* @end Endpoint */ - /* @group Footer */ .footer { @@ -46,3 +45,48 @@ body { } /* @end Footer */ + + +/* @group Github Ribbon - SVG */ + +.github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out; +} + +@keyframes octocat-wave { + 0% { + transform: rotate(0deg); + } + + 20% { + transform: rotate(-25deg); + } + + 40% { + transform: rotate(10deg); + } + + 60% { + transform: rotate(-25deg); + } + + 80% { + transform: rotate(10deg); + } + + 100% { + transform: rotate(0deg); + } +} + +@media (max-width: 500px) { + .github-corner:hover .octo-arm { + animation: none; + } + + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } +} + +/* @end Github Ribbon - SVG */ diff --git a/drfdocs/templates/drfdocs/base.html b/drfdocs/templates/drfdocs/base.html index e2e3f9b..37526ab 100644 --- a/drfdocs/templates/drfdocs/base.html +++ b/drfdocs/templates/drfdocs/base.html @@ -20,6 +20,14 @@ + + + + + + + +

DRF Docs

From 09b9e94a13f169d2f2fb2cabc3a01cf58d6400bf Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 12 Dec 2015 21:54:18 +0000 Subject: [PATCH 6/8] List urls with namespaces' urls (parent patterns) --- drfdocs/api_docs.py | 10 +++++++--- drfdocs/api_endpoint.py | 5 ++++- drfdocs/templates/drfdocs/base.html | 2 +- drfdocs/templates/drfdocs/home.html | 5 +++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drfdocs/api_docs.py b/drfdocs/api_docs.py index e673462..9ab27e6 100644 --- a/drfdocs/api_docs.py +++ b/drfdocs/api_docs.py @@ -12,13 +12,17 @@ def __init__(self): root_urlconf = __import__(settings.ROOT_URLCONF) self.get_all_view_names(root_urlconf.urls.urlpatterns) - def get_all_view_names(self, urlpatterns): + def get_all_view_names(self, urlpatterns, parent_pattern=None): for pattern in urlpatterns: if isinstance(pattern, RegexURLResolver) and (pattern.app_name not in self.excluded_apps): - self.get_all_view_names(pattern.url_patterns) + self.get_all_view_names(urlpatterns=pattern.url_patterns, parent_pattern=pattern) elif isinstance(pattern, RegexURLPattern) and (pattern.callback.__name__ not in self.excluded_endpoints): - api_endpoint = ApiEndpoint(pattern) + api_endpoint = ApiEndpoint(pattern, parent_pattern) self.endpoints.append(api_endpoint) + def _filter_drf_views(self, endpoints): + # Should keep only the endpoints with views that inherit from DRF's APIView + pass + def get_endpoints(self): return self.endpoints diff --git a/drfdocs/api_endpoint.py b/drfdocs/api_endpoint.py index 100e679..a6c5ca5 100644 --- a/drfdocs/api_endpoint.py +++ b/drfdocs/api_endpoint.py @@ -4,8 +4,11 @@ class ApiEndpoint(object): - def __init__(self, pattern): + def __init__(self, pattern, parent_pattern=None): self.pattern = pattern + self.url_parent_regex = simplify_regex(parent_pattern.regex.pattern)[:-1] if parent_pattern else None + self.url_regex = ("{0}{1}".format(self.url_parent_regex, simplify_regex(pattern.regex.pattern))) if self.url_parent_regex else simplify_regex(pattern.regex.pattern) + self.url_name = pattern.name self.regex = simplify_regex(pattern._regex) self.view_name = pattern.callback.__name__ # self._get_api_callback(pattern) diff --git a/drfdocs/templates/drfdocs/base.html b/drfdocs/templates/drfdocs/base.html index 37526ab..580641a 100644 --- a/drfdocs/templates/drfdocs/base.html +++ b/drfdocs/templates/drfdocs/base.html @@ -21,7 +21,7 @@ - + diff --git a/drfdocs/templates/drfdocs/home.html b/drfdocs/templates/drfdocs/home.html index ee836df..b77f250 100644 --- a/drfdocs/templates/drfdocs/home.html +++ b/drfdocs/templates/drfdocs/home.html @@ -5,8 +5,9 @@

API Endpoints

{% for endpoint in endpoints %}
-

{{ endpoint.regex }}

-

{{ endpoint.view_name }}

+

{{ endpoint.url_regex }}

+

View Name: {{ endpoint.view_name }}

+

URL Name: {{ endpoint.url_name }}

{% endfor %} {% endblock %} From 036fe14bfbd35bf1906d526f2b50c399572c0fe4 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 12 Dec 2015 22:15:26 +0000 Subject: [PATCH 7/8] Check if each view inherits from DRF's ApiView --- drfdocs/api_docs.py | 11 +++++++---- drfdocs/api_endpoint.py | 9 --------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/drfdocs/api_docs.py b/drfdocs/api_docs.py index 9ab27e6..93bc46a 100644 --- a/drfdocs/api_docs.py +++ b/drfdocs/api_docs.py @@ -1,6 +1,7 @@ from django.conf import settings from django.core.urlresolvers import RegexURLResolver, RegexURLPattern from drfdocs.api_endpoint import ApiEndpoint +from rest_framework.views import APIView class ApiDocumentation(object): @@ -16,13 +17,15 @@ def get_all_view_names(self, urlpatterns, parent_pattern=None): for pattern in urlpatterns: if isinstance(pattern, RegexURLResolver) and (pattern.app_name not in self.excluded_apps): self.get_all_view_names(urlpatterns=pattern.url_patterns, parent_pattern=pattern) - elif isinstance(pattern, RegexURLPattern) and (pattern.callback.__name__ not in self.excluded_endpoints): + elif isinstance(pattern, RegexURLPattern) and (pattern.callback.__name__ not in self.excluded_endpoints) and self._is_drf_view(pattern): api_endpoint = ApiEndpoint(pattern, parent_pattern) self.endpoints.append(api_endpoint) - def _filter_drf_views(self, endpoints): - # Should keep only the endpoints with views that inherit from DRF's APIView - pass + def _is_drf_view(self, pattern): + # Should check whether a pattern inherits from DRF's APIView + if (hasattr(pattern.callback, 'cls') and issubclass(pattern.callback.cls, APIView)): + return True + return False def get_endpoints(self): return self.endpoints diff --git a/drfdocs/api_endpoint.py b/drfdocs/api_endpoint.py index a6c5ca5..d0e3ea6 100644 --- a/drfdocs/api_endpoint.py +++ b/drfdocs/api_endpoint.py @@ -1,5 +1,4 @@ from django.contrib.admindocs.views import simplify_regex -from rest_framework.views import APIView class ApiEndpoint(object): @@ -11,11 +10,3 @@ def __init__(self, pattern, parent_pattern=None): self.url_name = pattern.name self.regex = simplify_regex(pattern._regex) self.view_name = pattern.callback.__name__ - # self._get_api_callback(pattern) - - def _get_api_callback(self, pattern): - """ - Verifies that pattern callback is a subclass of APIView, and returns the class - """ - if (hasattr(pattern.callback, 'cls') and issubclass(pattern.callback.cls, APIView)): - return pattern.callback.cls From 6f2f5c8ba13dee7f8f8357bc3a23021c40fa6302 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 12 Dec 2015 22:45:21 +0000 Subject: [PATCH 8/8] Split get_path method --- drfdocs/api_endpoint.py | 12 ++++++++---- drfdocs/templates/drfdocs/home.html | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drfdocs/api_endpoint.py b/drfdocs/api_endpoint.py index d0e3ea6..e0a57ef 100644 --- a/drfdocs/api_endpoint.py +++ b/drfdocs/api_endpoint.py @@ -5,8 +5,12 @@ class ApiEndpoint(object): def __init__(self, pattern, parent_pattern=None): self.pattern = pattern - self.url_parent_regex = simplify_regex(parent_pattern.regex.pattern)[:-1] if parent_pattern else None - self.url_regex = ("{0}{1}".format(self.url_parent_regex, simplify_regex(pattern.regex.pattern))) if self.url_parent_regex else simplify_regex(pattern.regex.pattern) - self.url_name = pattern.name - self.regex = simplify_regex(pattern._regex) + self.name = pattern.name + self.path = self._get_path(parent_pattern) self.view_name = pattern.callback.__name__ + + def _get_path(self, parent_pattern): + if parent_pattern: + parent_path = simplify_regex(parent_pattern.regex.pattern)[:-1] + return "{0}{1}".format(parent_path, simplify_regex(self.pattern.regex.pattern)) + return simplify_regex(self.pattern.regex.pattern) diff --git a/drfdocs/templates/drfdocs/home.html b/drfdocs/templates/drfdocs/home.html index b77f250..5a06225 100644 --- a/drfdocs/templates/drfdocs/home.html +++ b/drfdocs/templates/drfdocs/home.html @@ -5,9 +5,9 @@

API Endpoints

{% for endpoint in endpoints %}
-

{{ endpoint.url_regex }}

+

{{ endpoint.path }}

View Name: {{ endpoint.view_name }}

-

URL Name: {{ endpoint.url_name }}

+

URL Name: {{ endpoint.name }}

{% endfor %} {% endblock %}