Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploying 37728fb #17

Merged
merged 13 commits into from
Jul 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
language: python
python:
- "2.7"
install:
- pip install -r requirements-test.txt
- pip install pytest-cov
- pip install coveralls
script:
py.test --cov-report= --cov=rest_framework_ccbv tests/
after_success:
coveralls
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Classy Django REST Framework.
# Classy Django REST Framework. [![Build Status](https://travis-ci.org/vintasoftware/cdrf.co.svg?branch=develop)](https://travis-ci.org/vintasoftware/cdrf.co) [![Coverage Status](https://coveralls.io/repos/github/vintasoftware/cdrf.co/badge.svg?branch=develop)](https://coveralls.io/github/vintasoftware/cdrf.co?branch=develop)

## What is this?

Expand Down
24 changes: 23 additions & 1 deletion build.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tox]
skipsdist=True
envlist = drf{21,22,23,24,30,31,32,33},drfbuild{21,22,23,24,30,31,32,33}
envlist = drf{21,22,23,24,30,31,32,33,34},drfbuild{21,22,23,24,30,31,32,33,34}

[testenv]
deps=
Expand Down Expand Up @@ -29,10 +29,15 @@ deps32 =
deps33 =
djangorestframework>=3.3,<3.4

deps34 =
djangorestframework>=3.4,<3.5

setenv =
PYTHONPATH = {toxinidir}


# INDEX GENERATION

[index]
commands =
fab index_generator_for_version
Expand Down Expand Up @@ -97,6 +102,15 @@ deps =
commands =
{[index]commands}

[testenv:drf34]
deps =
{[testenv]deps}
{[testenv]deps34}
commands =
{[index]commands}


# SITE GENERATION

[testenv:drfbuild21]
deps =
Expand Down Expand Up @@ -161,3 +175,11 @@ envdir =
{toxworkdir}/drf33
commands =
{[build]commands}

[testenv:drfbuild34]
deps =
{[testenv:drf34]deps}
envdir =
{toxworkdir}/drf34
commands =
{[build]commands}
3 changes: 2 additions & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
-r requirements-tox.txt
djangorestframework==3.1
djangorestframework==3.3
mock==2.0.0
pytest==2.6.4
3 changes: 2 additions & 1 deletion requirements-tox.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Django==1.7.5
Django==1.8.13
Fabric==1.10.1
Jinja2==2.7.3
Pygments==2.0.2
python-decouple==2.3
pycrypto==2.6.1
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Fabric==1.10.1
python-decouple==2.3
pycrypto==2.6.1
tox==1.9.0
1 change: 1 addition & 0 deletions rest_framework_ccbv/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
'3.1',
'3.2',
'3.3',
'3.4',
]


Expand Down
87 changes: 87 additions & 0 deletions rest_framework_ccbv/custom_formatter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import inspect
from collections import deque

from pygments.formatters import HtmlFormatter
from pygments.formatters.html import _escape_html_table
from pygments.token import Token


class CodeHtmlFormatter(HtmlFormatter):
def __init__(self, instance_class, *args, **kwargs):
self.instance_class = instance_class
super(CodeHtmlFormatter, self).__init__(*args, **kwargs)

def _format_lines(self, tokensource):
"""
Just format the tokens, without any wrapping tags.
Yield individual lines.

most of this code is extracted from HtmlFormatter. Sadly there was no easy
way to reuse with the changes we needed without copy pasting.
"""
nocls = self.noclasses
lsep = self.lineseparator
# for <span style=""> lookup only
getcls = self.ttype2class.get
c2s = self.class2style
escape_table = _escape_html_table
lookback = deque()
instance_class = self.instance_class

lspan = ''
line = ''
for ttype, value in tokensource:
lookback.append((ttype, value))
if nocls:
cclass = getcls(ttype)
while cclass is None:
ttype = ttype.parent
cclass = getcls(ttype)
cspan = cclass and '<span style="%s">' % c2s[cclass][0] or ''
else:
cls = self._get_css_class(ttype)
cspan = cls and '<span class="%s">' % cls or ''

parts = value.translate(escape_table).split('\n')

# check if we are dealing with a method
if ttype in Token.Name and lookback[-2][1] == '.' and lookback[-3][1] == 'self':
try:
is_method = inspect.ismethod(getattr(instance_class, value))
except AttributeError:
# This means it's an attribute that is not in the instance_class
pass
else:
if is_method:
parts[0] = "<a href=\"#%s\">%s" % \
(value, parts[0])
parts[-1] = parts[-1] + "</a>"

# for all but the last line
for part in parts[:-1]:
if line:
if lspan != cspan:
line += (lspan and '</span>') + cspan + part + \
(cspan and '</span>') + lsep
else: # both are the same
line += part + (lspan and '</span>') + lsep
yield 1, line
line = ''
elif part:
yield 1, cspan + part + (cspan and '</span>') + lsep
else:
yield 1, lsep
# for the last line
if line and parts[-1]:
if lspan != cspan:
line += (lspan and '</span>') + cspan + parts[-1]
lspan = cspan
else:
line += parts[-1]
elif parts[-1]:
line = cspan + parts[-1]
lspan = cspan
# else we neither have to open a new span nor set lspan

if line:
yield 1, line + (lspan and '</span>') + lsep
7 changes: 2 additions & 5 deletions rest_framework_ccbv/django_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,5 @@ def configure():
),
)

try:
import django
django.setup()
except AttributeError:
pass
import django
django.setup()
49 changes: 43 additions & 6 deletions rest_framework_ccbv/inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
from rest_framework.compat import View
from rest_framework import serializers
from rest_framework.serializers import BaseSerializer
from pygments import highlight
from pygments import highlight, lex
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter
from pygments.token import Token
from custom_formatter import CodeHtmlFormatter


def add_to_klasses_if_its_restframework(klasses, klass):
Expand Down Expand Up @@ -48,10 +49,11 @@ def get_klasses():


class Attribute(object):
def __init__(self, name, value, classobject):
def __init__(self, name, value, classobject, instance_class):
self.name = name
self.value = value
self.classobject = classobject
self.instance_class = instance_class
self.dirty = False

def __eq__(self, obj):
Expand Down Expand Up @@ -84,7 +86,7 @@ def params_string(self):

def code(self):
code = inspect.getsource(self.value)
return highlight(code, PythonLexer(), HtmlFormatter())
return highlight(code, PythonLexer(), CodeHtmlFormatter(self.instance_class))


class Attributes(collections.MutableSequence):
Expand Down Expand Up @@ -154,7 +156,8 @@ def get_attributes(self):
if (not attr_str.startswith('__') and
not isinstance(attr, types.MethodType)):
attrs.append(Attribute(name=attr_str, value=attr,
classobject=klass))
classobject=klass,
instance_class=self.get_klass()))
return attrs

def get_methods(self):
Expand All @@ -167,7 +170,8 @@ def get_methods(self):
isinstance(attr, types.MethodType)):
attrs.append(Method(name=attr_str,
value=attr,
classobject=klass))
classobject=klass,
instance_class=self.get_klass()))
return attrs

def get_direct_ancestors(self):
Expand All @@ -183,3 +187,36 @@ def get_available_versions(self):
for version in klass_versions
if self.module_name in klass_versions[version] and
self.klass_name in klass_versions[version][self.module_name]]

def get_unavailable_methods(self):
def next_token(tokensource, lookahead, is_looking_ahead):
for ttype, value in tokensource:
while lookahead and not is_looking_ahead:
yield lookahead.popleft()
yield ttype, value

def lookahed_token_from_iter(lookahead, next_token_iter):
lookahead_token = next(next_token_iter)
lookahead.append(lookahead_token)
return lookahead_token

not_implemented_methods = []
for method in self.get_methods():
lookahead = collections.deque()
lookback = collections.deque()
is_looking_ahead = False
tokensource = lex(inspect.getsource(method.value), PythonLexer())
next_token_iter = next_token(tokensource, lookahead, is_looking_ahead)
for ttype, value in next_token_iter:
lookback.append((ttype, value))
if ttype in Token.Name and lookback[-2][1] == '.' and lookback[-3][1] == 'self':
if not hasattr(self.get_klass(), value):
is_looking_ahead = True
try:
_, la_value = lookahed_token_from_iter(lookahead, next_token_iter)
if la_value == '(':
not_implemented_methods.append(value)
except StopIteration:
pass
is_looking_ahead = False
return set(not_implemented_methods)
1 change: 1 addition & 0 deletions rest_framework_ccbv/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def get_context(self):

context['children'] = self.inspector.get_children()
context['this_module'] = context['this_klass'].__module__
context['unavailable_methods'] = self.inspector.get_unavailable_methods()
return context


Expand Down
4 changes: 4 additions & 0 deletions static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,7 @@ footer p {
width: 200px;
}
}
.highlight a {
text-decoration: none;
border-bottom: solid 1px rgba(0, 114, 255, 0.21);
}
29 changes: 19 additions & 10 deletions templates/detail_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@
function goToAnchor() {
var anchor = window.location.hash.replace("#", "");
$(".collapse").collapse('hide');
$("#" + anchor).collapse('show');
$('#' + anchor + ' .collapse').collapse('show');
setTimeout(function(){
if ($('#' + anchor)) {
console.log("scrolling");
if (anchor) {
$("#" + anchor).collapse('show');
$('#' + anchor + ' .collapse').collapse('show');
setTimeout(function(){
console.log($('#' + anchor).attr('class'));
$('html, body').animate({
scrollTop: $('#' + anchor).offset().top - 70
}, 0);
}
}, 700);
}, 500);
}
}

$(document).ready(function() {
Expand Down Expand Up @@ -93,8 +93,6 @@ <h2>Descendants</h2>
{% if loop.last %}</ul></div>{% endif %}
{% endfor %}
</div>


<div class="row">
{% for attribute in attributes %}
{% if loop.first %}
Expand Down Expand Up @@ -130,6 +128,17 @@ <h2>Attributes</h2>
{% endif %}
{% endfor %}
</div>
<div class="row">
{% for method in unavailable_methods %}
{% if loop.first %}
<div class="span12" id="unused-methods">
<h2>Methods used but not implemented in this class</h2>
<ul class="unstyled">
{% endif %}
<li><strong>{{method}}</strong></li>
{% if loop.last %}</ul></div>{% endif %}
{% endfor %}
</div>
<div class="row">
{% for method in methods %}
{% if loop.first %}
Expand Down Expand Up @@ -180,6 +189,6 @@ <h4 class="accordion-toggle">{{ child.classobject.__name__ }}</h4>
{% set previous_name=method.name %}
{% endfor %}
</div>

</div>
{% endblock %}
Loading