Black'ed the entire codebase

black dpaste/ --skip-string-normalization --exclude="migrations"
This commit is contained in:
Martin Mahner 2018-07-04 12:06:48 +02:00
parent 3b85c0e910
commit 00c6f058b9
15 changed files with 248 additions and 202 deletions

View file

@ -1,9 +1,7 @@
VERSION = (3, 0, 'a', 1)
__version__ = '{major}.{minor}{rest}'.format(
major=VERSION[0],
minor=VERSION[1],
rest=''.join(str(i) for i in VERSION[2:])
major=VERSION[0], minor=VERSION[1], rest=''.join(str(i) for i in VERSION[2:])
)
default_app_config = 'dpaste.apps.dpasteAppConfig'

View file

@ -96,8 +96,9 @@ class dpasteAppConfig(AppConfig):
from dpaste.highlight import (
PlainTextHighlighter,
MarkdownHighlighter,
RestructuredTextHighlighter
RestructuredTextHighlighter,
)
return [
(self.PLAIN_TEXT_SYMBOL, 'Plain Text', PlainTextHighlighter),
('_markdown', 'Markdown', MarkdownHighlighter),
@ -116,10 +117,8 @@ class dpasteAppConfig(AppConfig):
If the Highlight Class is not given, PygmentsHighlighter is used.
"""
from dpaste.highlight import (
PlainCodeHighlighter,
SolidityHighlighter
)
from dpaste.highlight import PlainCodeHighlighter, SolidityHighlighter
return [
(self.PLAIN_CODE_SYMBOL, 'Plain Code', PlainCodeHighlighter),
('abap', 'ABAP'),
@ -204,6 +203,7 @@ class dpasteAppConfig(AppConfig):
"""
if apps.is_installed('django.contrib.sites'):
from django.contrib.sites.shortcuts import get_current_site
site = get_current_site(request)
if site:
return 'https://{0}'.format(site.domain)

View file

@ -29,34 +29,27 @@ class SnippetForm(forms.ModelForm):
label=_('Content'),
widget=forms.Textarea(attrs={'placeholder': _('Awesome code goes here...')}),
max_length=config.MAX_CONTENT_LENGTH,
strip=False
strip=False,
)
lexer = forms.ChoiceField(
label=_('Lexer'),
initial=LEXER_DEFAULT,
choices=LEXER_CHOICES
label=_('Lexer'), initial=LEXER_DEFAULT, choices=LEXER_CHOICES
)
expires = forms.ChoiceField(
label=_('Expires'),
choices=config.EXPIRE_CHOICES,
initial=config.EXPIRE_DEFAULT
label=_('Expires'), choices=config.EXPIRE_CHOICES, initial=config.EXPIRE_DEFAULT
)
# Honeypot field
title = forms.CharField(
label=_('Title'),
required=False,
widget=forms.TextInput(attrs={'autocomplete': 'off'})
widget=forms.TextInput(attrs={'autocomplete': 'off'}),
)
class Meta:
model = Snippet
fields = (
'content',
'lexer',
)
fields = ('content', 'lexer')
def __init__(self, request, *args, **kwargs):
super(SnippetForm, self).__init__(*args, **kwargs)

View file

@ -19,6 +19,7 @@ config = apps.get_app_config('dpaste')
# Highlight Code Snippets
# -----------------------------------------------------------------------------
class Highlighter(object):
template_name = 'dpaste/highlight/code.html'
@ -47,6 +48,7 @@ class Highlighter(object):
class PlainTextHighlighter(Highlighter):
"""Plain Text. Just replace linebreaks."""
template_name = 'dpaste/highlight/text.html'
def highlight(self, code_string, **kwargs):
@ -55,20 +57,33 @@ class PlainTextHighlighter(Highlighter):
class MarkdownHighlighter(PlainTextHighlighter):
"""Markdown"""
extensions = ('tables', 'fenced-code', 'footnotes', 'autolink,',
'strikethrough', 'underline', 'quote', 'superscript',
'math')
extensions = (
'tables',
'fenced-code',
'footnotes',
'autolink,',
'strikethrough',
'underline',
'quote',
'superscript',
'math',
)
render_flags = ('skip-html',)
def highlight(self, code_string, **kwargs):
import misaka
return mark_safe(misaka.html(code_string,
extensions=self.extensions,
render_flags=self.render_flags))
return mark_safe(
misaka.html(
code_string, extensions=self.extensions, render_flags=self.render_flags
)
)
class RestructuredTextHighlighter(PlainTextHighlighter):
"""Restructured Text"""
rst_part_name = 'html_body'
publish_args = {
'writer_name': 'html5_polyglot',
@ -78,11 +93,12 @@ class RestructuredTextHighlighter(PlainTextHighlighter):
'halt_level': 5,
'report_level': 2,
'warning_stream': '/dev/null',
}
},
}
def highlight(self, code_string, **kwargs):
from docutils.core import publish_parts
self.publish_args['source'] = code_string
parts = publish_parts(**self.publish_args)
return mark_safe(parts[self.rst_part_name])
@ -93,6 +109,7 @@ class RestructuredTextHighlighter(PlainTextHighlighter):
class NakedHtmlFormatter(HtmlFormatter):
"""Pygments HTML formatter with no further HTML tags."""
def wrap(self, source, outfile):
return self._wrap_code(source)
@ -105,11 +122,14 @@ class PlainCodeHighlighter(Highlighter):
"""
Plain Code. No highlighting but Pygments like span tags around each line.
"""
def highlight(self, code_string, **kwargs):
return '\n'.join([
return '\n'.join(
[
'<span class="plain">{}</span>'.format(escape(l) or '&#8203;')
for l in code_string.splitlines()
])
]
)
class PygmentsHighlighter(Highlighter):
@ -117,6 +137,7 @@ class PygmentsHighlighter(Highlighter):
Highlight code string with Pygments. The lexer is automatically
determined by the lexer name.
"""
formatter = NakedHtmlFormatter()
lexer = None
lexer_fallback = PythonLexer()
@ -139,6 +160,7 @@ class SolidityHighlighter(PygmentsHighlighter):
# SolidityLexer does not necessarily need to be installed
# since its imported here and not used later.
from pygments_lexer_solidity import SolidityLexer
self.lexer = SolidityLexer()
@ -167,12 +189,13 @@ def get_highlighter_class(lexer_name):
# Generate a list of Form choices of all lexer.
LEXER_CHOICES = (
(_('Text'), [i[:2] for i in config.TEXT_FORMATTER]),
(_('Code'), [i[:2] for i in config.CODE_FORMATTER])
(_('Code'), [i[:2] for i in config.CODE_FORMATTER]),
)
# List of all Lexer Keys
LEXER_KEYS = [i[0] for i in config.TEXT_FORMATTER] + \
[i[0] for i in config.CODE_FORMATTER]
LEXER_KEYS = [i[0] for i in config.TEXT_FORMATTER] + [
i[0] for i in config.CODE_FORMATTER
]
# The default lexer which we fallback in case of
# an error or if not supplied in an API call.

View file

@ -8,14 +8,15 @@ class Command(BaseCommand):
help = "Purges snippets that are expired"
def add_arguments(self, parser):
parser.add_argument('--dry-run', action='store_true', dest='dry_run',
help='Don\'t do anything.'),
parser.add_argument(
'--dry-run', action='store_true', dest='dry_run', help='Don\'t do anything.'
),
def handle(self, *args, **options):
deleteable_snippets = Snippet.objects.filter(
expires__isnull=False,
expire_type=Snippet.EXPIRE_TIME,
expires__lte=timezone.now()
expires__lte=timezone.now(),
)
if len(deleteable_snippets) == 0:
self.stdout.write(u"No snippets to delete.")

View file

@ -16,11 +16,14 @@ R = SystemRandom()
def generate_secret_id(length):
if length > config.SLUG_LENGTH:
logger.warning('Slug creation triggered a duplicate, '
'consider increasing the SLUG_LENGTH.')
logger.warning(
'Slug creation triggered a duplicate, '
'consider increasing the SLUG_LENGTH.'
)
secret_id = ''.join([R.choice(config.SLUG_CHOICES)
for i in range(length or config.SLUG_LENGTH)])
secret_id = ''.join(
[R.choice(config.SLUG_CHOICES) for i in range(length or config.SLUG_LENGTH)]
)
# Check if this slug already exists, if not, return this new slug
try:
@ -30,7 +33,7 @@ def generate_secret_id(length):
# Otherwise create a new slug which is +1 character longer
# than the previous one.
return generate_secret_id(length=length+1)
return generate_secret_id(length=length + 1)
@python_2_unicode_compatible
@ -45,21 +48,24 @@ class Snippet(models.Model):
)
secret_id = models.CharField(
_('Secret ID'), max_length=255, blank=True, null=True, unique=True)
_('Secret ID'), max_length=255, blank=True, null=True, unique=True
)
content = models.TextField(_('Content'))
lexer = models.CharField(
_('Lexer'), max_length=30, default=highlight.LEXER_DEFAULT)
published = models.DateTimeField(
_('Published'), auto_now_add=True)
lexer = models.CharField(_('Lexer'), max_length=30, default=highlight.LEXER_DEFAULT)
published = models.DateTimeField(_('Published'), auto_now_add=True)
expire_type = models.PositiveSmallIntegerField(
_('Expire Type'), choices=EXPIRE_CHOICES, default=EXPIRE_CHOICES[0][0])
expires = models.DateTimeField(
_('Expires'), blank=True, null=True)
view_count = models.PositiveIntegerField(
_('View count'), default=0)
_('Expire Type'), choices=EXPIRE_CHOICES, default=EXPIRE_CHOICES[0][0]
)
expires = models.DateTimeField(_('Expires'), blank=True, null=True)
view_count = models.PositiveIntegerField(_('View count'), default=0)
parent = models.ForeignKey(
'self', null=True, blank=True, verbose_name=_('Parent Snippet'),
related_name='children', on_delete=models.CASCADE)
'self',
null=True,
blank=True,
verbose_name=_('Parent Snippet'),
related_name='children',
on_delete=models.CASCADE,
)
class Meta:
ordering = ('-published',)

View file

@ -49,9 +49,7 @@ USE_I18N = True
USE_L10N = False
LANGUAGE_CODE = 'en'
LANGUAGES = (
('en', 'English'),
)
LANGUAGES = (('en', 'English'),)
# LOCALE_PATHS = (
# os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'locale')),
@ -63,9 +61,7 @@ LANGUAGES = (
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
STATICFILES_DIRS = (
os.path.join(PROJECT_DIR, 'build'),
)
STATICFILES_DIRS = (os.path.join(PROJECT_DIR, 'build'),)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
@ -107,9 +103,9 @@ TEMPLATES = [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.template.context_processors.i18n',
],
},
]
},
}
]
INSTALLED_APPS = [
@ -146,16 +142,12 @@ CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'filters': {'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
'class': 'django.utils.log.AdminEmailHandler',
}
},
'loggers': {
@ -163,6 +155,6 @@ LOGGING = {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
},
}

View file

@ -4,9 +4,4 @@ Settings for the test suite
from .base import *
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
}
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}}

View file

@ -11,7 +11,6 @@ config = apps.get_app_config('dpaste')
class SnippetAPITestCase(TestCase):
def setUp(self):
self.api_url = reverse('dpaste_api_create_snippet')
self.client = Client(enforce_csrf_checks=True)
@ -84,7 +83,6 @@ class SnippetAPITestCase(TestCase):
self.assertTrue(content.startswith('http'))
self.assertTrue(content.endswith('\n'))
def test_json_format(self):
"""
The 'new' url format is just the link with a linebreak.
@ -92,7 +90,7 @@ class SnippetAPITestCase(TestCase):
data = {
'content': u"Hello Wörld.\n\tGood Bye",
'format': 'json',
'lexer': 'haskell'
'lexer': 'haskell',
}
response = self.client.post(self.api_url, data)
@ -102,6 +100,7 @@ class SnippetAPITestCase(TestCase):
self.assertEqual(Snippet.objects.count(), 1)
from json import loads
json_data = loads(content)
# Response is valid json, containing, content, lexer and url
@ -118,7 +117,7 @@ class SnippetAPITestCase(TestCase):
data = {
'content': u"Hello Wörld.\n\tGood Bye",
'format': 'broken-format',
'lexer': 'haskell'
'lexer': 'haskell',
}
response = self.client.post(self.api_url, data)
@ -129,26 +128,25 @@ class SnippetAPITestCase(TestCase):
"""
A broken lexer will fail loudly.
"""
data = {
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': 'foobar'
}
data = {'content': u"Hello Wörld.\n\tGood Bye", 'lexer': 'foobar'}
response = self.client.post(self.api_url, data)
self.assertEqual(response.status_code, 400)
self.assertEqual(Snippet.objects.count(), 0)
def test_expire_choices_none_given(self):
# No expire choice given will set a default expiration of one month
response = self.client.post(self.api_url, {
'content': u"Hello Wörld.\n\tGood Bye"})
response = self.client.post(
self.api_url, {'content': u"Hello Wörld.\n\tGood Bye"}
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertTrue(Snippet.objects.all()[0].expires)
def test_expire_choices_invalid_given(self):
# A expire choice that does not exist returns a BadRequest
response = self.client.post(self.api_url, {
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'foobar'})
response = self.client.post(
self.api_url, {'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'foobar'}
)
self.assertEqual(response.status_code, 400)
self.assertEqual(Snippet.objects.count(), 0)
@ -156,37 +154,45 @@ class SnippetAPITestCase(TestCase):
Test all the different expiration choices. We dont actually test
the deletion, since thats handled in the `test_snippet` section.
"""
def test_valid_expiration_choices_onetime(self):
response = self.client.post(self.api_url, {
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'onetime'})
response = self.client.post(
self.api_url, {'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'onetime'}
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertEqual(Snippet.objects.all()[0].expire_type, Snippet.EXPIRE_ONETIME)
def test_valid_expiration_choices_never(self):
response = self.client.post(self.api_url, {
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'never'})
response = self.client.post(
self.api_url, {'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'never'}
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertEqual(Snippet.objects.all()[0].expire_type, Snippet.EXPIRE_KEEP)
def test_valid_expiration_choices_hour(self):
response = self.client.post(self.api_url, {
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600})
response = self.client.post(
self.api_url, {'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600}
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertTrue(Snippet.objects.all()[0].expires)
def test_valid_expiration_choices_week(self):
response = self.client.post(self.api_url, {
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 7})
response = self.client.post(
self.api_url,
{'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 7},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertTrue(Snippet.objects.all()[0].expires)
def test_valid_expiration_choices_month(self):
response = self.client.post(self.api_url, {
'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 30})
response = self.client.post(
self.api_url,
{'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600 * 24 * 30},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertTrue(Snippet.objects.all()[0].expires)
@ -195,22 +201,24 @@ class SnippetAPITestCase(TestCase):
"""
No lexer and no filename given returns a BadRequest.
"""
response = self.client.post(self.api_url, {
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': '',
'filename': ''
})
response = self.client.post(
self.api_url,
{'content': u"Hello Wörld.\n\tGood Bye", 'lexer': '', 'filename': ''},
)
self.assertEqual(response.status_code, 400)
def test_filename_given(self):
"""
No lexer and a Python filename will set a 'python' lexer.
"""
response = self.client.post(self.api_url, {
response = self.client.post(
self.api_url,
{
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': '',
'filename': 'helloworld.py'
})
'filename': 'helloworld.py',
},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertEqual(Snippet.objects.all()[0].lexer, 'python')
@ -219,11 +227,14 @@ class SnippetAPITestCase(TestCase):
"""
A unknown filename will create a 'plain' code snippet.
"""
response = self.client.post(self.api_url, {
response = self.client.post(
self.api_url,
{
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': '',
'filename': 'helloworld.helloworld'
})
'filename': 'helloworld.helloworld',
},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertEqual(Snippet.objects.all()[0].lexer, config.PLAIN_CODE_SYMBOL)
@ -232,11 +243,14 @@ class SnippetAPITestCase(TestCase):
"""
A given lexer will overwrite whats the filename guessing.
"""
response = self.client.post(self.api_url, {
response = self.client.post(
self.api_url,
{
'content': u"Hello Wörld.\n\tGood Bye",
'lexer': 'php',
'filename': 'helloworld.py'
})
'filename': 'helloworld.py',
},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 1)
self.assertEqual(Snippet.objects.all()[0].lexer, 'php')
@ -248,5 +262,3 @@ class SnippetAPITestCase(TestCase):
content = ' one\n two\n three\n four'
self.client.post(self.api_url, {'content': content})
self.assertEqual(Snippet.objects.all()[0].content, content)

View file

@ -4,12 +4,14 @@ from textwrap import dedent
from django.test import TestCase
from dpaste.highlight import PlainCodeHighlighter, PygmentsHighlighter, \
RestructuredTextHighlighter
from dpaste.highlight import (
PlainCodeHighlighter,
PygmentsHighlighter,
RestructuredTextHighlighter,
)
class HighlightAPITestCase(TestCase):
def test_plain_code(self):
"""
PLAIN_CODE is not run through Pygments, test it separately.
@ -32,15 +34,13 @@ class HighlightAPITestCase(TestCase):
"""
Whitespace on the first line is retained, also on subsequent lines.
"""
input = (' vär=1\n'
' vär=2\n'
' vär=3\n'
' vär=4')
input = ' vär=1\n' ' vär=2\n' ' vär=3\n' ' vär=4'
expected = (
'<span class="plain"> vär=1</span>\n'
'<span class="plain"> vär=2</span>\n'
'<span class="plain"> vär=3</span>\n'
'<span class="plain"> vär=4</span>')
'<span class="plain"> vär=4</span>'
)
value = PlainCodeHighlighter().highlight(input)
self.assertEqual(value, expected)
@ -67,15 +67,13 @@ class HighlightAPITestCase(TestCase):
"""
Whitespace on the first line is retained, also on subsequent lines.
"""
input = (' var\n'
' var\n'
' var\n'
' var')
input = ' var\n' ' var\n' ' var\n' ' var'
expected = (
' <span class="n">var</span>\n'
' <span class="n">var</span>\n'
' <span class="n">var</span>\n'
' <span class="n">var</span>\n')
' <span class="n">var</span>\n'
)
value = PygmentsHighlighter().highlight(input, 'python')
self.assertEqual(value, expected)
@ -84,12 +82,14 @@ class HighlightAPITestCase(TestCase):
rst Syntax thats not valid must not raise an exception (SystemMessage)
"""
# (SEVERE/4) Missing matching underline for section title overline.
input = dedent("""
input = dedent(
"""
=========================
Generate 15 random numbers
70 180 3 179 192 117 75 72 90 190 49 159 63 14 55
=========================
""")
"""
)
try:
RestructuredTextHighlighter().highlight(input)
except Exception as e:

View file

@ -15,7 +15,6 @@ config = apps.get_app_config('dpaste')
class SnippetTestCase(TestCase):
def setUp(self):
self.client = Client()
self.new_url = reverse('snippet_new')
@ -132,7 +131,6 @@ class SnippetTestCase(TestCase):
self.assertEqual(response.status_code, 404)
self.assertEqual(Snippet.objects.count(), 0)
def test_snippet_notfound(self):
url = reverse('snippet_details', kwargs={'snippet_id': 'abcd'})
response = self.client.get(url, follow=True)
@ -203,8 +201,12 @@ class SnippetTestCase(TestCase):
def test_raw(self):
data = self.valid_form_data()
self.client.post(self.new_url, data, follow=True)
response = self.client.get(reverse('snippet_details_raw', kwargs={
'snippet_id': Snippet.objects.all()[0].secret_id}))
response = self.client.get(
reverse(
'snippet_details_raw',
kwargs={'snippet_id': Snippet.objects.all()[0].secret_id},
)
)
self.assertEqual(response.status_code, 200)
self.assertContains(response, data['content'])
@ -217,22 +219,23 @@ class SnippetTestCase(TestCase):
def test_xss_text_lexer(self):
# Simple 'text' lexer
data = self.valid_form_data(content=self.XSS_ORIGINAL,
lexer=config.PLAIN_TEXT_SYMBOL)
data = self.valid_form_data(
content=self.XSS_ORIGINAL, lexer=config.PLAIN_TEXT_SYMBOL
)
response = self.client.post(self.new_url, data, follow=True)
self.assertContains(response, self.XSS_ESCAPED)
def test_xss_code_lexer(self):
# Simple 'code' lexer
data = self.valid_form_data(content=self.XSS_ORIGINAL,
lexer=config.PLAIN_CODE_SYMBOL)
data = self.valid_form_data(
content=self.XSS_ORIGINAL, lexer=config.PLAIN_CODE_SYMBOL
)
response = self.client.post(self.new_url, data, follow=True)
self.assertContains(response, self.XSS_ESCAPED)
def test_xss_pygments_lexer(self):
# Pygments based lexer
data = self.valid_form_data(content=self.XSS_ORIGINAL,
lexer='python')
data = self.valid_form_data(content=self.XSS_ORIGINAL, lexer='python')
response = self.client.post(self.new_url, data, follow=True)
self.assertContains(response, self.XSS_ESCAPED)
@ -253,8 +256,9 @@ class SnippetTestCase(TestCase):
def test_snippet_history_delete_all(self):
# Empty list, delete all raises no error
response = self.client.post(reverse('snippet_history'),
{'delete': 1}, follow=True)
response = self.client.post(
reverse('snippet_history'), {'delete': 1}, follow=True
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 0)
@ -266,8 +270,9 @@ class SnippetTestCase(TestCase):
self.assertEqual(Snippet.objects.count(), 2)
# Delete all of them
response = self.client.post(reverse('snippet_history'),
{'delete': 1}, follow=True)
response = self.client.post(
reverse('snippet_history'), {'delete': 1}, follow=True
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Snippet.objects.count(), 0)
@ -315,7 +320,6 @@ class SnippetTestCase(TestCase):
PygmentsHighlighter().highlight('code', 'python')
PygmentsHighlighter().highlight('code', 'doesnotexist')
def test_random_slug_generation(self):
"""
Set the max length of a slug to 1, so we wont have more than 60
@ -325,8 +329,9 @@ class SnippetTestCase(TestCase):
"""
for i in range(0, 100):
Snippet.objects.create(content='foobar')
slug_list = Snippet.objects.values_list(
'secret_id', flat=True).order_by('published')
slug_list = Snippet.objects.values_list('secret_id', flat=True).order_by(
'published'
)
self.assertEqual(len(set(slug_list)), 100)
def test_leading_white_is_retained_in_db(self):

View file

@ -7,18 +7,21 @@ from .. import views
L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4)
urlpatterns = [
url(r'^$',
views.SnippetView.as_view(), name='snippet_new'),
url(r'^about/$',
TemplateView.as_view(template_name='dpaste/about.html'), name='dpaste_about'),
url(r'^history/$',
views.SnippetHistory.as_view(), name='snippet_history'),
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$' % L,
views.SnippetDetailView.as_view(), name='snippet_details'),
url(r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$' % L,
views.SnippetRawView.as_view(), name='snippet_details_raw'),
url(r'^$', views.SnippetView.as_view(), name='snippet_new'),
url(
r'^about/$',
TemplateView.as_view(template_name='dpaste/about.html'),
name='dpaste_about',
),
url(r'^history/$', views.SnippetHistory.as_view(), name='snippet_history'),
url(
r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$' % L,
views.SnippetDetailView.as_view(),
name='snippet_details',
),
url(
r'^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$' % L,
views.SnippetRawView.as_view(),
name='snippet_details_raw',
),
]

View file

@ -4,5 +4,5 @@ from django.views.decorators.csrf import csrf_exempt
from ..views import APIView
urlpatterns = [
url(r'^api/$', csrf_exempt(APIView.as_view()), name='dpaste_api_create_snippet'),
url(r'^api/$', csrf_exempt(APIView.as_view()), name='dpaste_api_create_snippet')
]

View file

@ -3,13 +3,19 @@ import difflib
import json
from django.apps import apps
from django.http import Http404, HttpResponse, HttpResponseBadRequest, \
HttpResponseRedirect
from django.http import (
Http404,
HttpResponse,
HttpResponseBadRequest,
HttpResponseRedirect,
)
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils.translation import ugettext
from django.views.defaults import page_not_found as django_page_not_found, \
server_error as django_server_error
from django.views.defaults import (
page_not_found as django_page_not_found,
server_error as django_server_error,
)
from django.views.generic import FormView
from django.views.generic.base import TemplateView, View
from django.views.generic.detail import DetailView
@ -28,18 +34,18 @@ config = apps.get_app_config('dpaste')
# Snippet Handling
# -----------------------------------------------------------------------------
class SnippetView(FormView):
"""
Create a new snippet.
"""
form_class = SnippetForm
template_name = 'dpaste/new.html'
def get_form_kwargs(self):
kwargs = super(SnippetView, self).get_form_kwargs()
kwargs.update({
'request': self.request,
})
kwargs.update({'request': self.request})
return kwargs
def form_valid(self, form):
@ -52,6 +58,7 @@ class SnippetDetailView(SnippetView, DetailView):
Details list view of a snippet. Handles the actual view, reply and
tree/diff view.
"""
queryset = Snippet.objects.all()
template_name = 'dpaste/details.html'
slug_url_kwarg = 'snippet_id'
@ -78,8 +85,10 @@ class SnippetDetailView(SnippetView, DetailView):
snippet = self.get_object()
# One-Time snippet get deleted if the view count matches our limit
if (snippet.expire_type == Snippet.EXPIRE_ONETIME and
snippet.view_count >= config.ONETIME_LIMIT):
if (
snippet.expire_type == Snippet.EXPIRE_ONETIME
and snippet.view_count >= config.ONETIME_LIMIT
):
snippet.delete()
raise Http404()
@ -91,10 +100,7 @@ class SnippetDetailView(SnippetView, DetailView):
def get_initial(self):
snippet = self.get_object()
return {
'content': snippet.content,
'lexer': snippet.lexer,
}
return {'content': snippet.content, 'lexer': snippet.lexer}
def form_valid(self, form):
snippet = form.save(parent=self.get_object())
@ -114,7 +120,7 @@ class SnippetDetailView(SnippetView, DetailView):
snippet.content.splitlines(),
ugettext('Previous Snippet'),
ugettext('Current Snippet'),
n=1
n=1,
)
diff_code = '\n'.join(d).strip()
highlighted = PygmentsHighlighter().render(diff_code, 'diff')
@ -126,10 +132,12 @@ class SnippetDetailView(SnippetView, DetailView):
self.object = self.get_object()
ctx = super(SnippetDetailView, self).get_context_data(**kwargs)
ctx.update({
ctx.update(
{
'wordwrap': self.object.lexer in highlight.LEXER_WORDWRAP,
'diff': self.get_snippet_diff(),
})
}
)
return ctx
@ -137,6 +145,7 @@ class SnippetRawView(SnippetDetailView):
"""
Display the raw content of a snippet
"""
def render_to_response(self, context, **response_kwargs):
snippet = self.get_object()
response = HttpResponse(snippet.content)
@ -150,6 +159,7 @@ class SnippetHistory(TemplateView):
Display the last `n` snippets created by this user (and saved in his
session).
"""
template_name = 'dpaste/history.html'
def get_user_snippets(self):
@ -169,9 +179,7 @@ class SnippetHistory(TemplateView):
def get_context_data(self, **kwargs):
ctx = super(SnippetHistory, self).get_context_data(**kwargs)
ctx.update({
'snippet_list': self.get_user_snippets(),
})
ctx.update({'snippet_list': self.get_user_snippets()})
return ctx
@ -184,6 +192,7 @@ class APIView(View):
"""
API View
"""
def _format_default(self, s):
"""
The default response is the snippet URL wrapped in quotes.
@ -204,11 +213,13 @@ class APIView(View):
The `json` format export.
"""
base_url = config.get_base_url(request=self.request)
return json.dumps({
return json.dumps(
{
'url': '{url}{path}'.format(url=base_url, path=s.get_absolute_url()),
'content': s.content,
'lexer': s.lexer,
})
}
)
def post(self, request, *args, **kwargs):
content = request.POST.get('content', '')
@ -222,13 +233,18 @@ class APIView(View):
# We need at least a lexer or a filename
if not lexer and not filename:
return HttpResponseBadRequest('No lexer or filename given. Unable to '
'determine a highlight. Valid lexers are: %s' % ', '.join(highlight.LEXER_KEYS))
return HttpResponseBadRequest(
'No lexer or filename given. Unable to '
'determine a highlight. Valid lexers are: %s'
% ', '.join(highlight.LEXER_KEYS)
)
# A lexer is given, check if its valid at all
if lexer and lexer not in highlight.LEXER_KEYS:
return HttpResponseBadRequest('Invalid lexer "%s" given. Valid lexers are: %s' % (
lexer, ', '.join(highlight.LEXER_KEYS)))
return HttpResponseBadRequest(
'Invalid lexer "%s" given. Valid lexers are: %s'
% (lexer, ', '.join(highlight.LEXER_KEYS))
)
# No lexer is given, but we have a filename, try to get the lexer
# out of it. In case Pygments cannot determine the lexer of the
@ -245,17 +261,16 @@ class APIView(View):
if expires not in expire_options:
return HttpResponseBadRequest(
'Invalid expire choice "{}" given. Valid values are: {}'.format(
expires, ', '.join(expire_options)))
expires, ', '.join(expire_options)
)
)
expires, expire_type = get_expire_values(expires)
else:
expires = datetime.datetime.now() + datetime.timedelta(seconds=60 * 60 * 24)
expire_type = Snippet.EXPIRE_TIME
snippet = Snippet.objects.create(
content=content,
lexer=lexer,
expires=expires,
expire_type=expire_type,
content=content, lexer=lexer, expires=expires, expire_type=expire_type
)
# Custom formatter for the API response
@ -272,6 +287,7 @@ class APIView(View):
# handle them here.
# -----------------------------------------------------------------------------
def page_not_found(request, exception=None, template_name='dpaste/404.html'):
return django_page_not_found(request, exception, template_name=template_name)

View file

@ -8,7 +8,9 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dpaste.settings.local")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()