diff --git a/Pipfile b/Pipfile index 5d37048..7b061f6 100644 --- a/Pipfile +++ b/Pipfile @@ -10,5 +10,5 @@ docutils = "==0.15" [scripts] runserver = "sh -c \"./manage.py migrate && ./manage.py runserver 0:8000\"" test = "pytest dpaste" -cleanup = "sh -c \"isort -rc dpaste && black --skip-string-normalization --line-length=80 --exclude='/(migrations)/' dpaste\"" +cleanup = "sh -c \"isort -rc dpaste && black --line-length=80 --exclude='/(migrations)/' dpaste\"" docs = "sphinx-build docs docs/_build/html" diff --git a/dpaste/__init__.py b/dpaste/__init__.py index dc58823..96eba67 100644 --- a/dpaste/__init__.py +++ b/dpaste/__init__.py @@ -1,9 +1,9 @@ -VERSION = (3, 4, 'a0') +VERSION = (3, 4, "a0") -__version__ = '{major}.{minor}{rest}'.format( +__version__ = "{major}.{minor}{rest}".format( major=VERSION[0], minor=VERSION[1], - rest=''.join(str(i) for i in VERSION[2:]), + rest="".join(str(i) for i in VERSION[2:]), ) -default_app_config = 'dpaste.apps.dpasteAppConfig' +default_app_config = "dpaste.apps.dpasteAppConfig" diff --git a/dpaste/apps.py b/dpaste/apps.py index c5a4a0c..6196c52 100644 --- a/dpaste/apps.py +++ b/dpaste/apps.py @@ -1,14 +1,14 @@ from django.apps import AppConfig, apps from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class dpasteAppConfig(AppConfig): - name = 'dpaste' - verbose_name = 'dpaste' + name = "dpaste" + verbose_name = "dpaste" # The application title used throughout the user interface. - APPLICATION_NAME = 'dpaste' + APPLICATION_NAME = "dpaste" # This content is loaded in the section of each template. # You can use it to add any HTML tags, specifically custom CSS styles. @@ -24,7 +24,7 @@ class dpasteAppConfig(AppConfig): # .btn { background-color: blue; border: 3px solid yellow; } # # """ - EXTRA_HEAD_HTML = '' + EXTRA_HEAD_HTML = "" # Integer. Length of the random slug for each new snippet. In the rare # case an existing slug is generated again, the length will increase by @@ -35,12 +35,12 @@ class dpasteAppConfig(AppConfig): # This is intentionally missing l and I as they look too similar with # sans-serif fonts. SLUG_CHOICES = ( - 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890' + "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890" ) # String. The lexer key that is pre-selected in the dropdown. Note that # this is only used if the user has not saved a snippet before, otherwise - LEXER_DEFAULT = 'python' + LEXER_DEFAULT = "python" # Integer. Maximum number of bytes per snippet. MAX_CONTENT_LENGTH = 250 * 1024 * 1024 @@ -48,7 +48,7 @@ class dpasteAppConfig(AppConfig): # A tuple of seconds and a descriptive string used in the lexer # expiration dropdown. Example:: # - # from django.utils.translation import ugettext_lazy as _ + # from django.utils.translation import gettext_lazy as _ # DPASTE_EXPIRE_CHOICES = ( # (3600, _('In one hour')), # (3600 * 24 * 7, _('In one week')), @@ -60,17 +60,17 @@ class dpasteAppConfig(AppConfig): # you set the choice key to ``never``. The management command will ignore # these snippets:: # - # from django.utils.translation import ugettext_lazy as _ + # from django.utils.translation import gettext_lazy as _ # DPASTE_EXPIRE_CHOICES = ( # (3600, _('In one hour')), # ('never', _('Never')), # ) EXPIRE_CHOICES = ( - ('onetime', _('One-Time snippet')), - (3600, _('In one hour')), - (3600 * 24 * 7, _('In one week')), - (3600 * 24 * 30, _('In one month')), - ('never', _('Never')), + ("onetime", _("One-Time snippet")), + (3600, _("In one hour")), + (3600 * 24 * 7, _("In one week")), + (3600 * 24 * 30, _("In one month")), + ("never", _("Never")), ) # Default value for ``EXPIRE_CHOICES`` @@ -81,7 +81,7 @@ class dpasteAppConfig(AppConfig): # enable one-time snippets you have to add a choice ``onetime`` to the # expire choices:: # - # from django.utils.translation import ugettext_lazy as _ + # from django.utils.translation import gettext_lazy as _ # DPASTE_EXPIRE_CHOICES = ( # ('onetime', _('One-Time snippet')), # (3600, _('In one hour')), @@ -102,11 +102,11 @@ class dpasteAppConfig(AppConfig): RAW_MODE_PLAIN_TEXT = True # Lexers which have wordwrap enabled by default - LEXER_WORDWRAP = ('rst',) + LEXER_WORDWRAP = ("rst",) # Key names of the default text and code lexer. - PLAIN_TEXT_SYMBOL = '_text' - PLAIN_CODE_SYMBOL = '_code' + PLAIN_TEXT_SYMBOL = "_text" + PLAIN_CODE_SYMBOL = "_code" @property def TEXT_FORMATTER(self): @@ -129,9 +129,9 @@ class dpasteAppConfig(AppConfig): ) return [ - (self.PLAIN_TEXT_SYMBOL, 'Plain Text', PlainTextHighlighter), - ('_markdown', 'Markdown', MarkdownHighlighter), - ('_rst', 'reStructuredText', RestructuredTextHighlighter), + (self.PLAIN_TEXT_SYMBOL, "Plain Text", PlainTextHighlighter), + ("_markdown", "Markdown", MarkdownHighlighter), + ("_rst", "reStructuredText", RestructuredTextHighlighter), ] @property @@ -159,7 +159,7 @@ class dpasteAppConfig(AppConfig): from jsx.lexer import JsxLexer return [ - (self.PLAIN_CODE_SYMBOL, 'Plain Code', PlainCodeHighlighter), + (self.PLAIN_CODE_SYMBOL, "Plain Code", PlainCodeHighlighter), # ('abap', 'ABAP'), # ('abnf', 'ABNF'), # ('ada', 'Ada'), @@ -180,8 +180,8 @@ class dpasteAppConfig(AppConfig): # ('antlr-ruby', 'ANTLR With Ruby Target'), # ('apacheconf', 'ApacheConf'), # ('apl', 'APL'), - ('applescript', 'AppleScript'), - ('arduino', 'Arduino'), + ("applescript", "AppleScript"), + ("arduino", "Arduino"), # ('as', 'ActionScript'), # ('as3', 'ActionScript 3'), # ('aspectj', 'AspectJ'), @@ -192,8 +192,8 @@ class dpasteAppConfig(AppConfig): # ('autoit', 'AutoIt'), # ('awk', 'Awk'), # ('basemake', 'Base Makefile'), - ('bash', 'Bash'), - ('bat', 'Batchfile'), + ("bash", "Bash"), + ("bat", "Batchfile"), # ('bbcode', 'BBCode'), # ('bc', 'BC'), # ('befunge', 'Befunge'), @@ -207,7 +207,7 @@ class dpasteAppConfig(AppConfig): # ('bro', 'Bro'), # ('bst', 'BST'), # ('bugs', 'BUGS'), - ('c', 'C'), + ("c", "C"), # ('c-objdump', 'c-objdump'), # ('ca65', 'ca65 assembler'), # ('cadl', 'cADL'), @@ -226,15 +226,15 @@ class dpasteAppConfig(AppConfig): # ('cirru', 'Cirru'), # ('clay', 'Clay'), # ('clean', 'Clean'), - ('clojure', 'Clojure'), + ("clojure", "Clojure"), # ('clojurescript', 'ClojureScript'), - ('cmake', 'CMake'), + ("cmake", "CMake"), # ('cobol', 'COBOL'), # ('cobolfree', 'COBOLFree'), - ('coffee-script', 'CoffeeScript'), - ('common-lisp', 'Common Lisp'), + ("coffee-script", "CoffeeScript"), + ("common-lisp", "Common Lisp"), # ('componentpascal', 'Component Pascal'), - ('console', 'Console/Bash Session'), + ("console", "Console/Bash Session"), # ('control', 'Debian Control file'), # ('coq', 'Coq'), # ('cpp', 'C++'), @@ -244,11 +244,11 @@ class dpasteAppConfig(AppConfig): # ('crmsh', 'Crmsh'), # ('croc', 'Croc'), # ('cryptol', 'Cryptol'), - ('csharp', 'C#'), + ("csharp", "C#"), # ('csound', 'Csound Orchestra'), # ('csound-document', 'Csound Document'), # ('csound-score', 'Csound Score'), - ('css', 'CSS'), + ("css", "CSS"), # ('css+django', 'CSS+Django/Jinja'), # ('css+erb', 'CSS+Ruby'), # ('css+genshitext', 'CSS+Genshi Text'), @@ -259,17 +259,17 @@ class dpasteAppConfig(AppConfig): # ('css+php', 'CSS+PHP'), # ('css+smarty', 'CSS+Smarty'), # ('cucumber', 'Gherkin'), - ('cuda', 'CUDA'), + ("cuda", "CUDA"), # ('cypher', 'Cypher'), # ('cython', 'Cython'), # ('d', 'D'), # ('d-objdump', 'd-objdump'), - ('dart', 'Dart'), - ('delphi', 'Delphi'), + ("dart", "Dart"), + ("delphi", "Delphi"), # ('dg', 'dg'), - ('diff', 'Diff'), - ('django', 'Django/Jinja'), - ('docker', 'Docker'), + ("diff", "Diff"), + ("django", "Django/Jinja"), + ("docker", "Docker"), # ('doscon', 'MSDOS Session'), # ('dpatch', 'Darcs Patch'), # ('dtd', 'DTD'), @@ -283,12 +283,12 @@ class dpasteAppConfig(AppConfig): # ('ec', 'eC'), # ('ecl', 'ECL'), # ('eiffel', 'Eiffel'), - ('elixir', 'Elixir'), + ("elixir", "Elixir"), # ('elm', 'Elm'), # ('emacs', 'EmacsLisp'), # ('erb', 'ERB'), # ('erl', 'Erlang erl session'), - ('erlang', 'Erlang'), + ("erlang", "Erlang"), # ('evoque', 'Evoque'), # ('extempore', 'xtlang'), # ('ezhil', 'Ezhil'), @@ -310,7 +310,7 @@ class dpasteAppConfig(AppConfig): # ('genshitext', 'Genshi Text'), # ('glsl', 'GLSL'), # ('gnuplot', 'Gnuplot'), - ('go', 'Go'), + ("go", "Go"), # ('golo', 'Golo'), # ('gooddata-cl', 'GoodData-CL'), # ('gosu', 'Gosu'), @@ -318,15 +318,15 @@ class dpasteAppConfig(AppConfig): # ('groovy', 'Groovy'), # ('gst', 'Gosu Template'), # ('haml', 'Haml'), - ('handlebars', 'Handlebars'), - ('haskell', 'Haskell'), + ("handlebars", "Handlebars"), + ("haskell", "Haskell"), # ('haxeml', 'Hxml'), # ('hexdump', 'Hexdump'), # ('hlsl', 'HLSL'), # ('hsail', 'HSAIL'), - ('html', 'HTML'), + ("html", "HTML"), # ('html+cheetah', 'HTML+Cheetah'), - ('html+django', 'HTML + Django/Jinja'), + ("html+django", "HTML + Django/Jinja"), # ('html+evoque', 'HTML+Evoque'), # ('html+genshi', 'HTML+Genshi'), # ('html+handlebars', 'HTML+Handlebars'), @@ -349,22 +349,22 @@ class dpasteAppConfig(AppConfig): # ('igor', 'Igor'), # ('inform6', 'Inform 6'), # ('inform7', 'Inform 7'), - ('ini', 'INI'), + ("ini", "INI"), # ('io', 'Io'), # ('ioke', 'Ioke'), # ('ipython2', 'IPython'), # ('ipython3', 'IPython3'), - ('ipythonconsole', 'IPython console session'), - ('irc', 'IRC logs'), + ("ipythonconsole", "IPython console session"), + ("irc", "IRC logs"), # ('isabelle', 'Isabelle'), # ('j', 'J'), # ('jags', 'JAGS'), # ('jasmin', 'Jasmin'), - ('java', 'Java'), + ("java", "Java"), # ('javascript+mozpreproc', 'Javascript+mozpreproc'), # ('jcl', 'JCL'), # ('jlcon', 'Julia console'), - ('js', 'JavaScript'), + ("js", "JavaScript"), # ('js+cheetah', 'JavaScript+Cheetah'), # ('js+django', 'JavaScript+Django/Jinja'), # ('js+erb', 'JavaScript+Ruby'), @@ -375,8 +375,8 @@ class dpasteAppConfig(AppConfig): # ('js+php', 'JavaScript+PHP'), # ('js+smarty', 'JavaScript+Smarty'), # ('jsgf', 'JSGF'), - ('json', 'JSON'), - ('jsx', 'JSX/React'), + ("json", "JSON"), + ("jsx", "JSX/React"), # ('json-object', 'JSONBareObject'), # ('jsonld', 'JSON-LD'), # ('jsp', 'Java Server Page'), @@ -385,12 +385,12 @@ class dpasteAppConfig(AppConfig): # ('kal', 'Kal'), # ('kconfig', 'Kconfig'), # ('koka', 'Koka'), - ('kotlin', 'Kotlin'), + ("kotlin", "Kotlin"), # ('lagda', 'Literate Agda'), # ('lasso', 'Lasso'), # ('lcry', 'Literate Cryptol'), # ('lean', 'Lean'), - ('less', 'LessCSS'), + ("less", "LessCSS"), # ('lhs', 'Literate Haskell'), # ('lidr', 'Literate Idris'), # ('lighty', 'Lighttpd configuration file'), @@ -401,14 +401,14 @@ class dpasteAppConfig(AppConfig): # ('logos', 'Logos'), # ('logtalk', 'Logtalk'), # ('lsl', 'LSL'), - ('lua', 'Lua'), - ('make', 'Makefile'), + ("lua", "Lua"), + ("make", "Makefile"), # ('mako', 'Mako'), # ('maql', 'MAQL'), # ('mask', 'Mask'), # ('mason', 'Mason'), # ('mathematica', 'Mathematica'), - ('matlab', 'Matlab'), + ("matlab", "Matlab"), # ('matlabsession', 'Matlab session'), # ('md', 'markdown'), # ('minid', 'MiniD'), @@ -433,16 +433,16 @@ class dpasteAppConfig(AppConfig): # ('newlisp', 'NewLisp'), # ('newspeak', 'Newspeak'), # ('ng2', 'Angular2'), - ('nginx', 'Nginx configuration file'), + ("nginx", "Nginx configuration file"), # ('nim', 'Nimrod'), # ('nit', 'Nit'), # ('nixos', 'Nix'), # ('nsis', 'NSIS'), - ('numpy', 'NumPy'), + ("numpy", "NumPy"), # ('nusmv', 'NuSMV'), # ('objdump', 'objdump'), # ('objdump-nasm', 'objdump-nasm'), - ('objective-c', 'Objective-C'), + ("objective-c", "Objective-C"), # ('objective-c++', 'Objective-C++'), # ('objective-j', 'Objective-J'), # ('ocaml', 'OCaml'), @@ -455,14 +455,14 @@ class dpasteAppConfig(AppConfig): # ('pan', 'Pan'), # ('parasail', 'ParaSail'), # ('pawn', 'Pawn'), - ('perl', 'Perl'), + ("perl", "Perl"), # ('perl6', 'Perl6'), - ('php', 'PHP'), + ("php", "PHP"), # ('pig', 'Pig'), # ('pike', 'Pike'), # ('pkgconfig', 'PkgConfig'), # ('plpgsql', 'PL/pgSQL'), - ('postgresql', 'PostgreSQL SQL dialect'), + ("postgresql", "PostgreSQL SQL dialect"), # ('postscript', 'PostScript'), # ('pot', 'Gettext Catalog'), # ('pov', 'POVRay'), @@ -479,7 +479,7 @@ class dpasteAppConfig(AppConfig): # ('pycon', 'Python console session'), # ('pypylog', 'PyPy Log'), # ('pytb', 'Python Traceback'), - ('python', 'Python'), + ("python", "Python"), # ('python3', 'Python 3'), # ('qbasic', 'QBasic'), # ('qml', 'QML'), @@ -494,7 +494,7 @@ class dpasteAppConfig(AppConfig): # ('ragel-objc', 'Ragel in Objective C Host'), # ('ragel-ruby', 'Ragel in Ruby Host'), # ('raw', 'Raw token data'), - ('rb', 'Ruby'), + ("rb", "Ruby"), # ('rbcon', 'Ruby irb session'), # ('rconsole', 'RConsole'), # ('rd', 'Rd'), @@ -511,17 +511,17 @@ class dpasteAppConfig(AppConfig): # ('robotframework', 'RobotFramework'), # ('rql', 'RQL'), # ('rsl', 'RSL'), - ('rst', 'reStructuredText'), + ("rst", "reStructuredText"), # ('rts', 'TrafficScript'), - ('rust', 'Rust'), + ("rust", "Rust"), # ('sas', 'SAS'), - ('sass', 'Sass'), + ("sass", "Sass"), # ('sc', 'SuperCollider'), # ('scala', 'Scala'), # ('scaml', 'Scaml'), # ('scheme', 'Scheme'), # ('scilab', 'Scilab'), - ('scss', 'SCSS'), + ("scss", "SCSS"), # ('shen', 'Shen'), # ('silver', 'Silver'), # ('slim', 'Slim'), @@ -531,19 +531,19 @@ class dpasteAppConfig(AppConfig): # ('sml', 'Standard ML'), # ('snobol', 'Snobol'), # ('snowball', 'Snowball'), - ('sol', 'Solidity'), + ("sol", "Solidity"), # ('sourceslist', 'Debian Sourcelist'), # ('sp', 'SourcePawn'), # ('sparql', 'SPARQL'), # ('spec', 'RPMSpec'), # ('splus', 'S'), - ('sql', 'SQL'), + ("sql", "SQL"), # ('sqlite3', 'sqlite3con'), # ('squidconf', 'SquidConf'), # ('ssp', 'Scalate Server Page'), # ('stan', 'Stan'), # ('stata', 'Stata'), - ('swift', 'Swift'), + ("swift", "Swift"), # ('swig', 'SWIG'), # ('systemverilog', 'systemverilog'), # ('tads3', 'TADS 3'), @@ -556,7 +556,7 @@ class dpasteAppConfig(AppConfig): # ('termcap', 'Termcap'), # ('terminfo', 'Terminfo'), # ('terraform', 'Terraform'), - ('tex', 'TeX'), + ("tex", "TeX"), # ('text', 'Text only'), # ('thrift', 'Thrift'), # ('todotxt', 'Todotxt'), @@ -566,7 +566,7 @@ class dpasteAppConfig(AppConfig): # ('tsql', 'Transact-SQL'), # ('turtle', 'Turtle'), # ('twig', 'Twig'), - ('typoscript', 'TypoScript'), + ("typoscript", "TypoScript"), # ('typoscriptcssdata', 'TypoScriptCssData'), # ('typoscripthtmldata', 'TypoScriptHtmlData'), # ('urbiscript', 'UrbiScript'), @@ -579,11 +579,11 @@ class dpasteAppConfig(AppConfig): # ('verilog', 'verilog'), # ('vgl', 'VGL'), # ('vhdl', 'vhdl'), - ('vim', 'VimL'), + ("vim", "VimL"), # ('wdiff', 'WDiff'), # ('whiley', 'Whiley'), # ('x10', 'X10'), - ('xml', 'XML'), + ("xml", "XML"), # ('xml+cheetah', 'XML+Cheetah'), # ('xml+django', 'XML+Django/Jinja'), # ('xml+erb', 'XML+Ruby'), @@ -596,10 +596,10 @@ class dpasteAppConfig(AppConfig): # ('xml+velocity', 'XML+Velocity'), # ('xorg.conf', 'Xorg'), # ('xquery', 'XQuery'), - ('xslt', 'XSLT'), + ("xslt", "XSLT"), # ('xtend', 'Xtend'), # ('xul+mozpreproc', 'XUL+mozpreproc'), - ('yaml', 'YAML'), + ("yaml", "YAML"), # ('yaml+jinja', 'YAML+Jinja'), # ('zephir', 'Zephir') ] @@ -612,13 +612,13 @@ class dpasteAppConfig(AppConfig): framework is installed, it uses the current Site domain. Otherwise it falls back to 'https://dpaste.de' """ - if apps.is_installed('django.contrib.sites'): + 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) - return 'https://dpaste.de' + return f"https://{site.domain}" + return "https://dpaste.de" @property def extra_template_context(self): @@ -627,6 +627,6 @@ class dpasteAppConfig(AppConfig): all Template Views. """ return { - 'dpaste_application_name': self.APPLICATION_NAME, - 'dpaste_extra_head_html': mark_safe(self.EXTRA_HEAD_HTML), + "dpaste_application_name": self.APPLICATION_NAME, + "dpaste_extra_head_html": mark_safe(self.EXTRA_HEAD_HTML), } diff --git a/dpaste/forms.py b/dpaste/forms.py index 5ec8cba..93e71eb 100644 --- a/dpaste/forms.py +++ b/dpaste/forms.py @@ -2,19 +2,19 @@ import datetime from django import forms from django.apps import apps -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .highlight import LEXER_CHOICES, LEXER_DEFAULT, LEXER_KEYS from .models import Snippet -config = apps.get_app_config('dpaste') +config = apps.get_app_config("dpaste") def get_expire_values(expires): - if expires == 'never': + if expires == "never": expire_type = Snippet.EXPIRE_KEEP expires = None - elif expires == 'onetime': + elif expires == "onetime": expire_type = Snippet.EXPIRE_ONETIME expires = None else: @@ -28,63 +28,63 @@ def get_expire_values(expires): class SnippetForm(forms.ModelForm): content = forms.CharField( - label=_('Content'), + label=_("Content"), widget=forms.Textarea( - attrs={'placeholder': _('Awesome code goes here...')} + attrs={"placeholder": _("Awesome code goes here...")} ), max_length=config.MAX_CONTENT_LENGTH, 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'), + label=_("Expires"), choices=config.EXPIRE_CHOICES, initial=config.EXPIRE_DEFAULT, ) - rtl = forms.BooleanField(label=_('Right to Left'), required=False) + rtl = forms.BooleanField(label=_("Right to Left"), required=False) # Honeypot field title = forms.CharField( - label=_('Title'), + label=_("Title"), required=False, - widget=forms.TextInput(attrs={'autocomplete': 'off'}), + widget=forms.TextInput(attrs={"autocomplete": "off"}), ) class Meta: model = Snippet - fields = ('content', 'lexer', 'rtl') + fields = ("content", "lexer", "rtl") def __init__(self, request, *args, **kwargs): super(SnippetForm, self).__init__(*args, **kwargs) self.request = request # Set the recently used lexer if we have any - session_lexer = self.request.session.get('lexer') + session_lexer = self.request.session.get("lexer") if session_lexer and session_lexer in LEXER_KEYS: - self.fields['lexer'].initial = session_lexer + self.fields["lexer"].initial = session_lexer # if the lexer is given via GET, set it - if 'l' in request.GET and request.GET['l'] in LEXER_KEYS: - self.fields['lexer'].initial = request.GET['l'] + if "l" in request.GET and request.GET["l"] in LEXER_KEYS: + self.fields["lexer"].initial = request.GET["l"] def clean_content(self): - content = self.cleaned_data.get('content', '') + content = self.cleaned_data.get("content", "") if not content.strip(): - raise forms.ValidationError(_('This field is required.')) + raise forms.ValidationError(_("This field is required.")) return content def clean_expires(self): """ Extract the 'expire_type' from the choice of expire choices. """ - expires = self.cleaned_data['expires'] + expires = self.cleaned_data["expires"] expires, expire_type = get_expire_values(expires) - self.cleaned_data['expire_type'] = expire_type + self.cleaned_data["expire_type"] = expire_type return expires def clean(self): @@ -92,8 +92,8 @@ class SnippetForm(forms.ModelForm): The `title` field is a hidden honeypot field. If its filled, this is likely spam. """ - if self.cleaned_data.get('title'): - raise forms.ValidationError('This snippet was identified as Spam.') + if self.cleaned_data.get("title"): + raise forms.ValidationError("This snippet was identified as Spam.") return self.cleaned_data def save(self, parent=None, *args, **kwargs): @@ -102,17 +102,17 @@ class SnippetForm(forms.ModelForm): # Add expire timestamp. None indicates 'keep forever', use the default # null state of the db column for that. - self.instance.expires = self.cleaned_data['expires'] - self.instance.expire_type = self.cleaned_data['expire_type'] + self.instance.expires = self.cleaned_data["expires"] + self.instance.expire_type = self.cleaned_data["expire_type"] # Save snippet in the db super(SnippetForm, self).save(*args, **kwargs) # Add the snippet to the user session list - self.request.session.setdefault('snippet_list', []) - self.request.session['snippet_list'] += [self.instance.pk] + self.request.session.setdefault("snippet_list", []) + self.request.session["snippet_list"] += [self.instance.pk] # Save the lexer in the session so we can use it later again - self.request.session['lexer'] = self.cleaned_data['lexer'] + self.request.session["lexer"] = self.cleaned_data["lexer"] return self.instance diff --git a/dpaste/highlight.py b/dpaste/highlight.py index a91870e..cd3ba7c 100644 --- a/dpaste/highlight.py +++ b/dpaste/highlight.py @@ -4,7 +4,7 @@ from django.apps import apps from django.template.defaultfilters import escape, linebreaksbr from django.template.loader import render_to_string from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from pygments import highlight from pygments.formatters.html import HtmlFormatter from pygments.lexers import get_lexer_by_name @@ -12,7 +12,7 @@ from pygments.lexers.python import PythonLexer from pygments.util import ClassNotFound logger = getLogger(__file__) -config = apps.get_app_config('dpaste') +config = apps.get_app_config("dpaste") # ----------------------------------------------------------------------------- @@ -21,14 +21,14 @@ config = apps.get_app_config('dpaste') class Highlighter(object): - template_name = 'dpaste/highlight/code.html' + template_name = "dpaste/highlight/code.html" def highlight(self, code_string, lexer_name=None): """Subclasses need to override this.""" return code_string @staticmethod - def get_lexer_display_name(lexer_name, fallback=_('(Deprecated Lexer)')): + def get_lexer_display_name(lexer_name, fallback=_("(Deprecated Lexer)")): for l in config.TEXT_FORMATTER + config.CODE_FORMATTER: if l[0] == lexer_name: return l[1] @@ -37,11 +37,11 @@ class Highlighter(object): def render(self, code_string, lexer_name, direction=None, **kwargs): highlighted_string = self.highlight(code_string, lexer_name=lexer_name) context = { - 'highlighted': highlighted_string, - 'highlighted_splitted': highlighted_string.splitlines(), - 'lexer_name': lexer_name, - 'lexer_display_name': self.get_lexer_display_name(lexer_name), - 'direction': direction, + "highlighted": highlighted_string, + "highlighted_splitted": highlighted_string.splitlines(), + "lexer_name": lexer_name, + "lexer_display_name": self.get_lexer_display_name(lexer_name), + "direction": direction, } context.update(kwargs) return render_to_string(self.template_name, context) @@ -50,7 +50,7 @@ class Highlighter(object): class PlainTextHighlighter(Highlighter): """Plain Text. Just replace linebreaks.""" - template_name = 'dpaste/highlight/text.html' + template_name = "dpaste/highlight/text.html" def highlight(self, code_string, **kwargs): return linebreaksbr(code_string) @@ -60,17 +60,17 @@ class MarkdownHighlighter(PlainTextHighlighter): """Markdown""" extensions = ( - 'tables', - 'fenced-code', - 'footnotes', - 'autolink,', - 'strikethrough', - 'underline', - 'quote', - 'superscript', - 'math', + "tables", + "fenced-code", + "footnotes", + "autolink,", + "strikethrough", + "underline", + "quote", + "superscript", + "math", ) - render_flags = ('skip-html',) + render_flags = ("skip-html",) def highlight(self, code_string, **kwargs): import misaka @@ -87,22 +87,22 @@ class MarkdownHighlighter(PlainTextHighlighter): class RestructuredTextHighlighter(PlainTextHighlighter): """Restructured Text""" - rst_part_name = 'html_body' + rst_part_name = "html_body" publish_args = { - 'writer_name': 'html5_polyglot', - 'settings_overrides': { - 'raw_enabled': False, - 'file_insertion_enabled': False, - 'halt_level': 5, - 'report_level': 2, - 'warning_stream': '/dev/null', + "writer_name": "html5_polyglot", + "settings_overrides": { + "raw_enabled": False, + "file_insertion_enabled": False, + "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 + self.publish_args["source"] = code_string parts = publish_parts(**self.publish_args) return mark_safe(parts[self.rst_part_name]) @@ -126,9 +126,9 @@ class PlainCodeHighlighter(Highlighter): """ def highlight(self, code_string, **kwargs): - return '\n'.join( + return "\n".join( [ - '{}'.format(escape(l) or '​') + '{}'.format(escape(l) or "​") for l in code_string.splitlines() ] ) @@ -149,7 +149,7 @@ class PygmentsHighlighter(Highlighter): try: self.lexer = get_lexer_by_name(lexer_name) except ClassNotFound: - logger.warning('Lexer for given name %s not found', lexer_name) + logger.warning("Lexer for given name %s not found", lexer_name) self.lexer = self.lexer_fallback return highlight(code_string, self.lexer, self.formatter) @@ -190,8 +190,8 @@ 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]), + (_("Text"), [i[:2] for i in config.TEXT_FORMATTER]), + (_("Code"), [i[:2] for i in config.CODE_FORMATTER]), ) # List of all Lexer Keys diff --git a/dpaste/management/commands/cleanup_snippets.py b/dpaste/management/commands/cleanup_snippets.py index d8517a6..1a60cc4 100644 --- a/dpaste/management/commands/cleanup_snippets.py +++ b/dpaste/management/commands/cleanup_snippets.py @@ -9,10 +9,10 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( - '--dry-run', - action='store_true', - dest='dry_run', - help='Don\'t do anything.', + "--dry-run", + action="store_true", + dest="dry_run", + help="Don't do anything.", ), def handle(self, *args, **options): @@ -29,7 +29,7 @@ class Command(BaseCommand): ) for d in deleteable_snippets: self.stdout.write(u"- %s (%s)\n" % (d.secret_id, d.expires)) - if options.get('dry_run'): - self.stdout.write('Dry run - Not actually deleting snippets!\n') + if options.get("dry_run"): + self.stdout.write("Dry run - Not actually deleting snippets!\n") else: deleteable_snippets.delete() diff --git a/dpaste/models.py b/dpaste/models.py index eb1897c..c685276 100644 --- a/dpaste/models.py +++ b/dpaste/models.py @@ -4,12 +4,12 @@ from random import SystemRandom from django.apps import apps from django.db import models from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from six import python_2_unicode_compatible from dpaste import highlight -config = apps.get_app_config('dpaste') +config = apps.get_app_config("dpaste") logger = getLogger(__file__) R = SystemRandom() @@ -17,11 +17,11 @@ R = SystemRandom() def generate_secret_id(length): if length > config.SLUG_LENGTH: logger.warning( - 'Slug creation triggered a duplicate, ' - 'consider increasing the SLUG_LENGTH.' + "Slug creation triggered a duplicate, " + "consider increasing the SLUG_LENGTH." ) - secret_id = ''.join( + secret_id = "".join( [ R.choice(config.SLUG_CHOICES) for i in range(length or config.SLUG_LENGTH) @@ -45,37 +45,37 @@ class Snippet(models.Model): EXPIRE_KEEP = 2 EXPIRE_ONETIME = 3 EXPIRE_CHOICES = ( - (EXPIRE_TIME, _('Expire by timestamp')), - (EXPIRE_KEEP, _('Keep Forever')), - (EXPIRE_ONETIME, _('One-Time snippet')), + (EXPIRE_TIME, _("Expire by timestamp")), + (EXPIRE_KEEP, _("Keep Forever")), + (EXPIRE_ONETIME, _("One-Time snippet")), ) 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')) + content = models.TextField(_("Content")) lexer = models.CharField( - _('Lexer'), max_length=30, default=highlight.LEXER_DEFAULT + _("Lexer"), max_length=30, default=highlight.LEXER_DEFAULT ) - published = models.DateTimeField(_('Published'), auto_now_add=True) + published = models.DateTimeField(_("Published"), auto_now_add=True) expire_type = models.PositiveSmallIntegerField( - _('Expire Type'), choices=EXPIRE_CHOICES, default=EXPIRE_CHOICES[0][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) - rtl = models.BooleanField(_('Right-to-left'), default=False) + expires = models.DateTimeField(_("Expires"), blank=True, null=True) + view_count = models.PositiveIntegerField(_("View count"), default=0) + rtl = models.BooleanField(_("Right-to-left"), default=False) parent = models.ForeignKey( - 'self', + "self", null=True, blank=True, - verbose_name=_('Parent Snippet'), - related_name='children', + verbose_name=_("Parent Snippet"), + related_name="children", on_delete=models.CASCADE, ) class Meta: - ordering = ('-published',) - db_table = 'dpaste_snippet' + ordering = ("-published",) + db_table = "dpaste_snippet" def __str__(self): return self.secret_id @@ -86,14 +86,14 @@ class Snippet(models.Model): super(Snippet, self).save(*args, **kwargs) def get_absolute_url(self): - return reverse('snippet_details', kwargs={'snippet_id': self.secret_id}) + return reverse("snippet_details", kwargs={"snippet_id": self.secret_id}) def highlight(self): HighlighterClass = highlight.get_highlighter_class(self.lexer) return HighlighterClass().render( code_string=self.content, lexer_name=self.lexer, - direction='rtl' if self.rtl else 'ltr', + direction="rtl" if self.rtl else "ltr", ) @property diff --git a/dpaste/settings/base.py b/dpaste/settings/base.py index ba4f98a..d60da0c 100644 --- a/dpaste/settings/base.py +++ b/dpaste/settings/base.py @@ -14,17 +14,17 @@ PROJECT_DIR, PROJECT_MODULE_NAME = os.path.split( ) PYTHON_BIN = os.path.dirname(sys.executable) -if os.path.exists(os.path.join(PYTHON_BIN, 'activate_this.py')): +if os.path.exists(os.path.join(PYTHON_BIN, "activate_this.py")): # Assume that the presence of 'activate_this.py' in the python bin/ # directory means that we're running in a virtual environment. Set the # variable root to $VIRTUALENV/var. - VAR_ROOT = os.path.join(os.path.dirname(PYTHON_BIN), 'var') + VAR_ROOT = os.path.join(os.path.dirname(PYTHON_BIN), "var") if not os.path.exists(VAR_ROOT): os.mkdir(VAR_ROOT) else: # Set the variable root to the local configuration location (which is # ignored by the repository). - VAR_ROOT = os.path.join(PROJECT_DIR, PROJECT_MODULE_NAME, 'conf', 'local') + VAR_ROOT = os.path.join(PROJECT_DIR, PROJECT_MODULE_NAME, "conf", "local") # ============================================================================== # Generic Django project settings @@ -34,13 +34,13 @@ DEBUG = False # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" SITE_ID = 1 # Make this unique, and don't share it with anybody. -SECRET_KEY = '' +SECRET_KEY = "" -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = ["*"] # ============================================================================== # I18N @@ -49,8 +49,8 @@ ALLOWED_HOSTS = ['*'] USE_I18N = True USE_L10N = False -LANGUAGE_CODE = 'en' -LANGUAGES = (('en', 'English'),) +LANGUAGE_CODE = "en" +LANGUAGES = (("en", "English"),) # LOCALE_PATHS = ( # os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'locale')), @@ -61,59 +61,59 @@ LANGUAGES = (('en', 'English'),) # ============================================================================== STATICFILES_STORAGE = ( - 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' + "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" ) STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", ) -STATIC_ROOT = os.path.join(VAR_ROOT, 'static') +STATIC_ROOT = os.path.join(VAR_ROOT, "static") -STATIC_URL = '/static/' -ADMIN_MEDIA_PREFIX = '/static/admin/' +STATIC_URL = "/static/" +ADMIN_MEDIA_PREFIX = "/static/admin/" -ROOT_URLCONF = 'dpaste.urls' +ROOT_URLCONF = "dpaste.urls" -LOGIN_URL = '/accounts/login/' -LOGOUT_URL = '/accounts/logout/' -LOGIN_REDIRECT_URL = '/' +LOGIN_URL = "/accounts/login/" +LOGOUT_URL = "/accounts/logout/" +LOGIN_REDIRECT_URL = "/" # ============================================================================== # Templates # ============================================================================== MIDDLEWARE = [ - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'csp.middleware.CSPMiddleware', + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.locale.LocaleMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django.middleware.security.SecurityMiddleware", + "csp.middleware.CSPMiddleware", ] TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.template.context_processors.i18n', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.template.context_processors.i18n", ] }, } ] INSTALLED_APPS = [ - 'django.contrib.staticfiles', - 'django.contrib.sessions', - 'staticinline.apps.StaticInlineAppConfig', - 'dpaste.apps.dpasteAppConfig', + "django.contrib.staticfiles", + "django.contrib.sessions", + "staticinline.apps.StaticInlineAppConfig", + "dpaste.apps.dpasteAppConfig", ] # DATABASES = { @@ -132,7 +132,7 @@ INSTALLED_APPS = [ SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True -SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") SECURE_BROWSER_XSS_FILTER = True SECURE_CONTENT_TYPE_NOSNIFF = True @@ -141,23 +141,23 @@ CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'") CSP_STYLE_SRC = ("'self'", "'unsafe-inline'") LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'} + "version": 1, + "disable_existing_loggers": False, + "filters": { + "require_debug_false": {"()": "django.utils.log.RequireDebugFalse"} }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler', + "handlers": { + "mail_admins": { + "level": "ERROR", + "filters": ["require_debug_false"], + "class": "django.utils.log.AdminEmailHandler", } }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, + "loggers": { + "django.request": { + "handlers": ["mail_admins"], + "level": "ERROR", + "propagate": True, } }, } diff --git a/dpaste/settings/local.py.example b/dpaste/settings/local.py.example index 4b2293b..fe8e5b5 100644 --- a/dpaste/settings/local.py.example +++ b/dpaste/settings/local.py.example @@ -26,7 +26,7 @@ if not 'runsslserver' in sys.argv: # # from dpaste.apps import dpasteAppConfig -# from django.utils.translation import ugettext_lazy as _ +# from django.utils.translation import gettext_lazy as _ # # class ProductionDpasteAppConfig(dpasteAppConfig): # SLUG_LENGTH = 8 diff --git a/dpaste/settings/tests.py b/dpaste/settings/tests.py index 6ec3d7e..5febd79 100644 --- a/dpaste/settings/tests.py +++ b/dpaste/settings/tests.py @@ -5,13 +5,13 @@ import django from .base import * -SECRET_KEY = 'test-key' +SECRET_KEY = "test-key" DATABASES = { - 'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'} + "default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"} } # Drop CSP middleware for Django 3.0 until it was fixed upstream # https://github.com/mozilla/django-csp/issues/129 -if django.get_version().startswith('3.'): - MIDDLEWARE.remove('csp.middleware.CSPMiddleware') +if django.get_version().startswith("3."): + MIDDLEWARE.remove("csp.middleware.CSPMiddleware") diff --git a/dpaste/tests/test_api.py b/dpaste/tests/test_api.py index e71e730..f50da23 100644 --- a/dpaste/tests/test_api.py +++ b/dpaste/tests/test_api.py @@ -7,12 +7,12 @@ from django.urls import reverse from ..models import Snippet -config = apps.get_app_config('dpaste') +config = apps.get_app_config("dpaste") class SnippetAPITestCase(TestCase): def setUp(self): - self.api_url = reverse('dpaste_api_create_snippet') + self.api_url = reverse("dpaste_api_create_snippet") self.client = Client(enforce_csrf_checks=True) def test_empty(self): @@ -27,19 +27,19 @@ class SnippetAPITestCase(TestCase): self.assertEqual(Snippet.objects.count(), 0) # No content - data['content'] = '' + data["content"] = "" response = self.client.post(self.api_url, data) self.assertEqual(response.status_code, 400) self.assertEqual(Snippet.objects.count(), 0) # Just some spaces - data['content'] = ' ' + data["content"] = " " response = self.client.post(self.api_url, data) self.assertEqual(response.status_code, 400) self.assertEqual(Snippet.objects.count(), 0) # Linebreaks or tabs only are not valid either - data['content'] = '\n\t ' + data["content"] = "\n\t " response = self.client.post(self.api_url, data) self.assertEqual(response.status_code, 400) self.assertEqual(Snippet.objects.count(), 0) @@ -48,10 +48,10 @@ class SnippetAPITestCase(TestCase): """ A valid snippet, contains Unicode, tabs, spaces, linebreaks etc. """ - data = {'content': u"Hello Wörld.\n\tGood Bye"} + data = {"content": u"Hello Wörld.\n\tGood Bye"} response = self.client.post(self.api_url, data) - content = response.content.decode('utf-8') + content = response.content.decode("utf-8") self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -65,36 +65,36 @@ class SnippetAPITestCase(TestCase): response = self.client.get(content[1:-1]) self.assertEqual(response.status_code, 200) - self.assertContains(response, data['content']) + self.assertContains(response, data["content"]) def test_new_url_format(self): """ The 'new' url format is just the link with a linebreak. """ - data = {'content': u"Hello Wörld.\n\tGood Bye", 'format': 'url'} + data = {"content": u"Hello Wörld.\n\tGood Bye", "format": "url"} response = self.client.post(self.api_url, data) - content = response.content.decode('utf-8') + content = response.content.decode("utf-8") self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) # Response is just the link starting with http(s) and ends with a linebreak - self.assertTrue(content.startswith('http')) - self.assertTrue(content.endswith('\n')) + 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. """ data = { - 'content': u"Hello Wörld.\n\tGood Bye", - 'format': 'json', - 'lexer': 'haskell', + "content": u"Hello Wörld.\n\tGood Bye", + "format": "json", + "lexer": "haskell", } response = self.client.post(self.api_url, data) - content = response.content.decode('utf-8') + content = response.content.decode("utf-8") self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -104,9 +104,9 @@ class SnippetAPITestCase(TestCase): json_data = loads(content) # Response is valid json, containing, content, lexer and url - self.assertEqual(json_data['content'], data['content']) - self.assertEqual(json_data['lexer'], data['lexer']) - self.assertTrue(json_data['url'].startswith('http')) + self.assertEqual(json_data["content"], data["content"]) + self.assertEqual(json_data["lexer"], data["lexer"]) + self.assertTrue(json_data["url"].startswith("http")) def test_invalid_format(self): """ @@ -115,9 +115,9 @@ class SnippetAPITestCase(TestCase): """ data = { - 'content': u"Hello Wörld.\n\tGood Bye", - 'format': 'broken-format', - 'lexer': 'haskell', + "content": u"Hello Wörld.\n\tGood Bye", + "format": "broken-format", + "lexer": "haskell", } response = self.client.post(self.api_url, data) @@ -128,7 +128,7 @@ 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) @@ -136,7 +136,7 @@ class SnippetAPITestCase(TestCase): 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"} + self.api_url, {"content": u"Hello Wörld.\n\tGood Bye"} ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -146,7 +146,7 @@ class SnippetAPITestCase(TestCase): # 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'}, + {"content": u"Hello Wörld.\n\tGood Bye", "expires": "foobar"}, ) self.assertEqual(response.status_code, 400) self.assertEqual(Snippet.objects.count(), 0) @@ -159,7 +159,7 @@ class SnippetAPITestCase(TestCase): def test_valid_expiration_choices_onetime(self): response = self.client.post( self.api_url, - {'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'onetime'}, + {"content": u"Hello Wörld.\n\tGood Bye", "expires": "onetime"}, ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -170,7 +170,7 @@ class SnippetAPITestCase(TestCase): def test_valid_expiration_choices_never(self): response = self.client.post( self.api_url, - {'content': u"Hello Wörld.\n\tGood Bye", 'expires': 'never'}, + {"content": u"Hello Wörld.\n\tGood Bye", "expires": "never"}, ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -181,7 +181,7 @@ class SnippetAPITestCase(TestCase): def test_valid_expiration_choices_hour(self): response = self.client.post( self.api_url, - {'content': u"Hello Wörld.\n\tGood Bye", 'expires': 3600}, + {"content": u"Hello Wörld.\n\tGood Bye", "expires": 3600}, ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -190,7 +190,7 @@ class SnippetAPITestCase(TestCase): 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}, + {"content": u"Hello Wörld.\n\tGood Bye", "expires": 3600 * 24 * 7}, ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -199,7 +199,7 @@ class SnippetAPITestCase(TestCase): 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}, + {"content": u"Hello Wörld.\n\tGood Bye", "expires": 3600 * 24 * 30}, ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -212,9 +212,9 @@ class SnippetAPITestCase(TestCase): response = self.client.post( self.api_url, { - 'content': u"Hello Wörld.\n\tGood Bye", - 'lexer': '', - 'filename': '', + "content": u"Hello Wörld.\n\tGood Bye", + "lexer": "", + "filename": "", }, ) self.assertEqual(response.status_code, 400) @@ -226,14 +226,14 @@ class SnippetAPITestCase(TestCase): response = self.client.post( self.api_url, { - 'content': u"Hello Wörld.\n\tGood Bye", - 'lexer': '', - 'filename': 'helloworld.py', + "content": u"Hello Wörld.\n\tGood Bye", + "lexer": "", + "filename": "helloworld.py", }, ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) - self.assertEqual(Snippet.objects.all()[0].lexer, 'python') + self.assertEqual(Snippet.objects.all()[0].lexer, "python") def test_awkward_filename_given(self): """ @@ -242,9 +242,9 @@ class SnippetAPITestCase(TestCase): response = self.client.post( self.api_url, { - 'content': u"Hello Wörld.\n\tGood Bye", - 'lexer': '', - 'filename': 'helloworld.helloworld', + "content": u"Hello Wörld.\n\tGood Bye", + "lexer": "", + "filename": "helloworld.helloworld", }, ) self.assertEqual(response.status_code, 200) @@ -260,19 +260,19 @@ class SnippetAPITestCase(TestCase): response = self.client.post( self.api_url, { - 'content': u"Hello Wörld.\n\tGood Bye", - 'lexer': 'php', - 'filename': 'helloworld.py', + "content": u"Hello Wörld.\n\tGood Bye", + "lexer": "php", + "filename": "helloworld.py", }, ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) - self.assertEqual(Snippet.objects.all()[0].lexer, 'php') + self.assertEqual(Snippet.objects.all()[0].lexer, "php") def test_leading_white_is_retained(self): """ Leading Whitespace is retained in the db. """ - content = ' one\n two\n three\n four' - self.client.post(self.api_url, {'content': content}) + content = " one\n two\n three\n four" + self.client.post(self.api_url, {"content": content}) self.assertEqual(Snippet.objects.all()[0].content, content) diff --git a/dpaste/tests/test_highlight.py b/dpaste/tests/test_highlight.py index f093536..b131349 100644 --- a/dpaste/tests/test_highlight.py +++ b/dpaste/tests/test_highlight.py @@ -16,7 +16,7 @@ class HighlightAPITestCase(TestCase): """ PLAIN_CODE is not run through Pygments, test it separately. """ - input = 'vär' + input = "vär" expected = 'vär' value = PlainCodeHighlighter().highlight(input) self.assertEqual(value, expected) @@ -25,7 +25,7 @@ class HighlightAPITestCase(TestCase): """ Whitespace on the first line is retained. """ - input = ' vär=1' + input = " vär=1" expected = ' vär=1' value = PlainCodeHighlighter().highlight(input) self.assertEqual(value, expected) @@ -34,7 +34,7 @@ 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 = ( ' vär=1\n' ' vär=2\n' @@ -49,32 +49,32 @@ class HighlightAPITestCase(TestCase): Pygemnts highlights the variable name, and also generally adds a trailing \n to all its result. """ - input = 'var' + input = "var" expected = 'var\n' - value = PygmentsHighlighter().highlight(input, 'python') + value = PygmentsHighlighter().highlight(input, "python") self.assertEqual(value, expected) def test_pygments_leading_whitespace(self): """ Whitespace on the first line is retained. """ - input = ' var' + input = " var" expected = ' var\n' - value = PygmentsHighlighter().highlight(input, 'python') + value = PygmentsHighlighter().highlight(input, "python") self.assertEqual(value, expected) def test_pygments_leading_whitespace_multiline(self): """ 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 = ( ' var\n' ' var\n' ' var\n' ' var\n' ) - value = PygmentsHighlighter().highlight(input, 'python') + value = PygmentsHighlighter().highlight(input, "python") self.assertEqual(value, expected) def test_broken_rst_syntax(self): @@ -93,4 +93,4 @@ class HighlightAPITestCase(TestCase): try: RestructuredTextHighlighter().highlight(input) except Exception as e: - self.fail('rst syntax raised unexpected exception: {}'.format(e)) + self.fail(f"rst syntax raised unexpected exception: {e}") diff --git a/dpaste/tests/test_snippet.py b/dpaste/tests/test_snippet.py index 6e2b5e4..e649529 100644 --- a/dpaste/tests/test_snippet.py +++ b/dpaste/tests/test_snippet.py @@ -11,26 +11,26 @@ from django.urls import reverse from ..highlight import PygmentsHighlighter from ..models import Snippet -config = apps.get_app_config('dpaste') +config = apps.get_app_config("dpaste") class SnippetTestCase(TestCase): def setUp(self): self.client = Client() - self.new_url = reverse('snippet_new') + self.new_url = reverse("snippet_new") def valid_form_data(self, **kwargs): data = { - 'content': u"Hello Wörld.\n\tGood Bye", - 'lexer': config.LEXER_DEFAULT, - 'expires': config.EXPIRE_DEFAULT, + "content": u"Hello Wörld.\n\tGood Bye", + "lexer": config.LEXER_DEFAULT, + "expires": config.EXPIRE_DEFAULT, } if kwargs: data.update(kwargs) return data def test_about(self): - response = self.client.get(reverse('dpaste_about')) + response = self.client.get(reverse("dpaste_about")) self.assertEqual(response.status_code, 200) # ------------------------------------------------------------------------- @@ -47,17 +47,17 @@ class SnippetTestCase(TestCase): data = self.valid_form_data() # No content - data['content'] = '' + data["content"] = "" self.client.post(self.new_url, data) self.assertEqual(Snippet.objects.count(), 0) # Just some spaces - data['content'] = ' ' + data["content"] = " " self.client.post(self.new_url, data) self.assertEqual(Snippet.objects.count(), 0) # Linebreaks or tabs only are not valid either - data['content'] = '\n\t ' + data["content"] = "\n\t " self.client.post(self.new_url, data) self.assertEqual(Snippet.objects.count(), 0) @@ -70,7 +70,7 @@ class SnippetTestCase(TestCase): response = self.client.post(self.new_url, data, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) - self.assertContains(response, data['content']) + self.assertContains(response, data["content"]) # The unicode method contains the snippet id so we can easily print # the id using {{ snippet }} @@ -80,7 +80,7 @@ class SnippetTestCase(TestCase): def test_new_snippet_custom_lexer(self): # You can pass a lexer key in GET.l data = self.valid_form_data() - url = '%s?l=haskell' % self.new_url + url = "%s?l=haskell" % self.new_url response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 200) @@ -89,7 +89,7 @@ class SnippetTestCase(TestCase): # If you pass an invalid key it wont fail and just fallback # to the default lexer. data = self.valid_form_data() - url = '%s?l=invalid-lexer' % self.new_url + url = "%s?l=invalid-lexer" % self.new_url response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 200) @@ -101,7 +101,7 @@ class SnippetTestCase(TestCase): the snippet is considered as spam. We let the user know its spam. """ data = self.valid_form_data() - data['title'] = 'Any content' + data["title"] = "Any content" response = self.client.post(self.new_url, data, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 0) @@ -112,27 +112,27 @@ class SnippetTestCase(TestCase): """ # POST data data = self.valid_form_data() - data['expires'] = 'onetime' + data["expires"] = "onetime" # First view, the author gets redirected after posting response = self.client.post(self.new_url, data, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) - self.assertContains(response, data['content']) + self.assertContains(response, data["content"]) # Second View, another user looks at the snippet - response = self.client.get(response.request['PATH_INFO'], follow=True) + response = self.client.get(response.request["PATH_INFO"], follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) - self.assertContains(response, data['content']) + self.assertContains(response, data["content"]) # Third/Further View, another user looks at the snippet but it was deleted - response = self.client.get(response.request['PATH_INFO'], follow=True) + response = self.client.get(response.request["PATH_INFO"], follow=True) 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'}) + url = reverse("snippet_details", kwargs={"snippet_id": "abcd"}) response = self.client.get(url, follow=True) self.assertEqual(response.status_code, 404) @@ -143,18 +143,18 @@ class SnippetTestCase(TestCase): data = self.valid_form_data() response = self.client.post(self.new_url, data, follow=True) response = self.client.post( - response.request['PATH_INFO'], data, follow=True + response.request["PATH_INFO"], data, follow=True ) - self.assertContains(response, data['content']) + self.assertContains(response, data["content"]) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 2) def test_reply_invalid(self): data = self.valid_form_data() response = self.client.post(self.new_url, data, follow=True) - del data['content'] + del data["content"] response = self.client.post( - response.request['PATH_INFO'], data, follow=True + response.request["PATH_INFO"], data, follow=True ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -170,8 +170,8 @@ class SnippetTestCase(TestCase): self.client.post(self.new_url, data, follow=True) snippet_id = Snippet.objects.all()[0].secret_id - url = reverse('snippet_details', kwargs={'snippet_id': snippet_id}) - response = self.client.post(url, {'delete': 1}, follow=True) + url = reverse("snippet_details", kwargs={"snippet_id": snippet_id}) + response = self.client.post(url, {"delete": 1}, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 0) @@ -180,8 +180,8 @@ class SnippetTestCase(TestCase): data = self.valid_form_data() self.client.post(self.new_url, data, follow=True) - url = reverse('snippet_details', kwargs={'snippet_id': 'doesnotexist'}) - response = self.client.post(url, {'delete': 1}, follow=True) + url = reverse("snippet_details", kwargs={"snippet_id": "doesnotexist"}) + response = self.client.post(url, {"delete": 1}, follow=True) self.assertEqual(response.status_code, 404) self.assertEqual(Snippet.objects.count(), 1) @@ -192,7 +192,7 @@ class SnippetTestCase(TestCase): # Do not pass delete=1 snippet_id = Snippet.objects.all()[0].secret_id - url = reverse('snippet_details', kwargs={'snippet_id': snippet_id}) + url = reverse("snippet_details", kwargs={"snippet_id": snippet_id}) response = self.client.post(url, {}, follow=True) # Returns regular snippet details page @@ -210,7 +210,7 @@ class SnippetTestCase(TestCase): # Next time its fetched its automatically deleted. snippet_id = Snippet.objects.all()[0].secret_id - url = reverse('snippet_details', kwargs={'snippet_id': snippet_id}) + url = reverse("snippet_details", kwargs={"snippet_id": snippet_id}) response = self.client.get(url, follow=True) self.assertEqual(response.status_code, 404) @@ -224,19 +224,19 @@ class SnippetTestCase(TestCase): 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}, + "snippet_details_raw", + kwargs={"snippet_id": Snippet.objects.all()[0].secret_id}, ) ) self.assertEqual(response.status_code, 200) - self.assertContains(response, data['content']) + self.assertContains(response, data["content"]) # ------------------------------------------------------------------------- # XSS and correct escaping # ------------------------------------------------------------------------- - XSS_ORIGINAL = '' - XSS_ESCAPED = '<script>hello</script>' + XSS_ORIGINAL = "" + XSS_ESCAPED = "<script>hello</script>" def test_xss_text_lexer(self): # Simple 'text' lexer @@ -256,7 +256,7 @@ class SnippetTestCase(TestCase): 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) @@ -264,13 +264,13 @@ class SnippetTestCase(TestCase): # History # ------------------------------------------------------------------------- def test_snippet_history(self): - response = self.client.get(reverse('snippet_history')) + response = self.client.get(reverse("snippet_history")) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 0) data = self.valid_form_data() self.client.post(self.new_url, data, follow=True) - response = self.client.get(reverse('snippet_history')) + response = self.client.get(reverse("snippet_history")) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 1) @@ -278,7 +278,7 @@ 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 + reverse("snippet_history"), {"delete": 1}, follow=True ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 0) @@ -292,7 +292,7 @@ class SnippetTestCase(TestCase): # Delete all of them response = self.client.post( - reverse('snippet_history'), {'delete': 1}, follow=True + reverse("snippet_history"), {"delete": 1}, follow=True ) self.assertEqual(response.status_code, 200) self.assertEqual(Snippet.objects.count(), 0) @@ -316,11 +316,11 @@ class SnippetTestCase(TestCase): # You can call the management command with --dry-run which will # list snippets to delete, but wont actually do. - management.call_command('cleanup_snippets', dry_run=True) + management.call_command("cleanup_snippets", dry_run=True) self.assertEqual(Snippet.objects.count(), 2) # Calling the management command will delete this one - management.call_command('cleanup_snippets') + management.call_command("cleanup_snippets") self.assertEqual(Snippet.objects.count(), 1) def test_delete_management_snippet_that_never_expires_will_not_get_deleted( @@ -330,18 +330,18 @@ class SnippetTestCase(TestCase): Snippets without an expiration date wont get deleted automatically. """ data = self.valid_form_data() - data['expires'] = 'never' + data["expires"] = "never" self.client.post(self.new_url, data, follow=True) self.assertEqual(Snippet.objects.count(), 1) - management.call_command('cleanup_snippets') + management.call_command("cleanup_snippets") self.assertEqual(Snippet.objects.count(), 1) def test_highlighting(self): # You can pass any lexer to the pygmentize function and it will # never fail loudly. - PygmentsHighlighter().highlight('code', 'python') - PygmentsHighlighter().highlight('code', 'doesnotexist') + PygmentsHighlighter().highlight("code", "python") + PygmentsHighlighter().highlight("code", "doesnotexist") def test_random_slug_generation(self): """ @@ -351,17 +351,17 @@ class SnippetTestCase(TestCase): slugs are extended now. """ for i in range(0, 100): - Snippet.objects.create(content='foobar') + Snippet.objects.create(content="foobar") slug_list = Snippet.objects.values_list( - 'secret_id', flat=True - ).order_by('published') + "secret_id", flat=True + ).order_by("published") self.assertEqual(len(set(slug_list)), 100) def test_leading_white_is_retained_in_db(self): """ Leading Whitespace is retained in the db. """ - content = ' one\n two\n three\n four' + content = " one\n two\n three\n four" data = self.valid_form_data(content=content) self.client.post(self.new_url, data, follow=True) self.assertEqual(Snippet.objects.all()[0].content, content) diff --git a/dpaste/urls/__init__.py b/dpaste/urls/__init__.py index 0a9f56d..163eb58 100644 --- a/dpaste/urls/__init__.py +++ b/dpaste/urls/__init__.py @@ -1,11 +1,11 @@ from django.conf.urls import include, url urlpatterns = [ - url(r'^', include('dpaste.urls.dpaste_api')), - url(r'^', include('dpaste.urls.dpaste')), - url(r'^i18n/', include('django.conf.urls.i18n')), + url(r"^", include("dpaste.urls.dpaste_api")), + url(r"^", include("dpaste.urls.dpaste")), + url(r"^i18n/", include("django.conf.urls.i18n")), ] # Custom error handlers which load `dpaste/.html` instead of `.html` -handler404 = 'dpaste.views.page_not_found' -handler500 = 'dpaste.views.server_error' +handler404 = "dpaste.views.page_not_found" +handler500 = "dpaste.views.server_error" diff --git a/dpaste/urls/dpaste.py b/dpaste/urls/dpaste.py index e116ca3..9786699 100644 --- a/dpaste/urls/dpaste.py +++ b/dpaste/urls/dpaste.py @@ -6,37 +6,37 @@ from django.views.generic import TemplateView from .. import views -L = getattr(settings, 'DPASTE_SLUG_LENGTH', 4) -config = apps.get_app_config('dpaste') +L = getattr(settings, "DPASTE_SLUG_LENGTH", 4) +config = apps.get_app_config("dpaste") urlpatterns = [ - url(r'^$', views.SnippetView.as_view(), name='snippet_new'), + url(r"^$", views.SnippetView.as_view(), name="snippet_new"), url( - r'^about/$', + r"^about/$", TemplateView.as_view( - template_name='dpaste/about.html', + template_name="dpaste/about.html", extra_context=config.extra_template_context, ), - name='dpaste_about', + name="dpaste_about", ), - url(r'^history/$', views.SnippetHistory.as_view(), name='snippet_history'), + url(r"^history/$", views.SnippetHistory.as_view(), name="snippet_history"), url( - r'^(?P[a-zA-Z0-9]{%d,})/?$' % L, + r"^(?P[a-zA-Z0-9]{%d,})/?$" % L, views.SnippetDetailView.as_view(), - name='snippet_details', + name="snippet_details", ), url( - r'^(?P[a-zA-Z0-9]{%d,})/raw/?$' % L, + r"^(?P[a-zA-Z0-9]{%d,})/raw/?$" % L, views.SnippetRawView.as_view(), - name='snippet_details_raw', + name="snippet_details_raw", ), url( - r'^(?P[a-zA-Z0-9]{%d,})/slim/?$' % L, + r"^(?P[a-zA-Z0-9]{%d,})/slim/?$" % L, xframe_options_exempt( views.SnippetDetailView.as_view( - template_name='dpaste/details_slim.html' + template_name="dpaste/details_slim.html" ) ), - name='snippet_details_slim', + name="snippet_details_slim", ), ] diff --git a/dpaste/urls/dpaste_api.py b/dpaste/urls/dpaste_api.py index a11bbb0..f5ed723 100644 --- a/dpaste/urls/dpaste_api.py +++ b/dpaste/urls/dpaste_api.py @@ -5,8 +5,8 @@ from ..views import APIView urlpatterns = [ url( - r'^api/$', + r"^api/$", csrf_exempt(APIView.as_view()), - name='dpaste_api_create_snippet', + name="dpaste_api_create_snippet", ) ] diff --git a/dpaste/views.py b/dpaste/views.py index 8ef960a..4e9acf5 100644 --- a/dpaste/views.py +++ b/dpaste/views.py @@ -27,7 +27,7 @@ from dpaste.forms import SnippetForm, get_expire_values from dpaste.highlight import PygmentsHighlighter from dpaste.models import Snippet -config = apps.get_app_config('dpaste') +config = apps.get_app_config("dpaste") # ----------------------------------------------------------------------------- @@ -41,11 +41,11 @@ class SnippetView(FormView): """ form_class = SnippetForm - template_name = 'dpaste/new.html' + 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): @@ -65,9 +65,9 @@ class SnippetDetailView(SnippetView, DetailView): """ queryset = Snippet.objects.all() - template_name = 'dpaste/details.html' - slug_url_kwarg = 'snippet_id' - slug_field = 'secret_id' + template_name = "dpaste/details.html" + slug_url_kwarg = "snippet_id" + slug_field = "secret_id" def post(self, request, *args, **kwargs): """ @@ -76,14 +76,14 @@ class SnippetDetailView(SnippetView, DetailView): reasons and the chance to abuse this is not given anyway, since snippets always expire. """ - if 'delete' in self.request.POST: + if "delete" in self.request.POST: snippet = get_object_or_404( - Snippet, secret_id=self.kwargs['snippet_id'] + Snippet, secret_id=self.kwargs["snippet_id"] ) snippet.delete() # Append `#` so #delete goes away in Firefox - url = '{0}#'.format(reverse('snippet_new')) + url = "{0}#".format(reverse("snippet_new")) return HttpResponseRedirect(url) return super(SnippetDetailView, self).post(request, *args, **kwargs) @@ -104,16 +104,16 @@ class SnippetDetailView(SnippetView, DetailView): # Increase the view count of the snippet snippet.view_count += 1 - snippet.save(update_fields=['view_count']) + snippet.save(update_fields=["view_count"]) return super(SnippetDetailView, self).get(request, *args, **kwargs) def get_initial(self): snippet = self.get_object() return { - 'content': snippet.content, - 'lexer': snippet.lexer, - 'rtl': snippet.rtl, + "content": snippet.content, + "lexer": snippet.lexer, + "rtl": snippet.rtl, } def form_valid(self, form): @@ -132,12 +132,12 @@ class SnippetDetailView(SnippetView, DetailView): d = difflib.unified_diff( snippet.parent.content.splitlines(), snippet.content.splitlines(), - ugettext('Previous Snippet'), - ugettext('Current Snippet'), + ugettext("Previous Snippet"), + ugettext("Current Snippet"), n=1, ) - diff_code = '\n'.join(d).strip() - highlighted = PygmentsHighlighter().render(diff_code, 'diff') + diff_code = "\n".join(d).strip() + highlighted = PygmentsHighlighter().render(diff_code, "diff") # Remove blank lines return highlighted @@ -148,9 +148,9 @@ class SnippetDetailView(SnippetView, DetailView): ctx = super(SnippetDetailView, self).get_context_data(**kwargs) ctx.update( { - 'wordwrap': self.object.lexer in highlight.LEXER_WORDWRAP, - 'diff': self.get_snippet_diff(), - 'raw_mode': config.RAW_MODE_ENABLED, + "wordwrap": self.object.lexer in highlight.LEXER_WORDWRAP, + "diff": self.get_snippet_diff(), + "raw_mode": config.RAW_MODE_ENABLED, } ) ctx.update(config.extra_template_context) @@ -162,22 +162,20 @@ class SnippetRawView(SnippetDetailView): Display the raw content of a snippet """ - template_name = 'dpaste/raw.html' + template_name = "dpaste/raw.html" def dispatch(self, request, *args, **kwargs): if not config.RAW_MODE_ENABLED: return HttpResponseForbidden( - ugettext( - 'This dpaste installation has Raw view mode disabled.' - ) + ugettext("This dpaste installation has Raw view mode disabled.") ) return super(SnippetRawView, self).dispatch(request, *args, **kwargs) def render_plain_text(self, context, **response_kwargs): snippet = self.get_object() response = HttpResponse(snippet.content) - response['Content-Type'] = 'text/plain;charset=UTF-8' - response['X-Content-Type-Options'] = 'nosniff' + response["Content-Type"] = "text/plain;charset=UTF-8" + response["X-Content-Type-Options"] = "nosniff" return response def render_to_response(self, context, **response_kwargs): @@ -199,26 +197,26 @@ class SnippetHistory(TemplateView): session). """ - template_name = 'dpaste/history.html' + template_name = "dpaste/history.html" def get_user_snippets(self): - snippet_id_list = self.request.session.get('snippet_list', []) + snippet_id_list = self.request.session.get("snippet_list", []) return Snippet.objects.filter(pk__in=snippet_id_list) def post(self, request, *args, **kwargs): """ Delete all user snippets at once. """ - if 'delete' in self.request.POST: + if "delete" in self.request.POST: self.get_user_snippets().delete() # Append `#` so #delete goes away in Firefox - url = '{0}#'.format(reverse('snippet_history')) + url = "{0}#".format(reverse("snippet_history")) return HttpResponseRedirect(url) 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()}) ctx.update(config.extra_template_context) return ctx @@ -238,7 +236,7 @@ class APIView(View): The default response is the snippet URL wrapped in quotes. """ base_url = config.get_base_url(request=self.request) - return '"{url}{path}"'.format(url=base_url, path=s.get_absolute_url()) + return f'"{base_url}{s.get_absolute_url()}"' def _format_url(self, s): """ @@ -246,7 +244,7 @@ class APIView(View): no quotes, but a linebreak at the end. """ base_url = config.get_base_url(request=self.request) - return '{url}{path}\n'.format(url=base_url, path=s.get_absolute_url()) + return f"{base_url}{s.get_absolute_url()}\n" def _format_json(self, s): """ @@ -255,37 +253,35 @@ class APIView(View): base_url = config.get_base_url(request=self.request) return json.dumps( { - 'url': '{url}{path}'.format( - url=base_url, path=s.get_absolute_url() - ), - 'content': s.content, - 'lexer': s.lexer, + "url": f"{base_url}{s.get_absolute_url()}", + "content": s.content, + "lexer": s.lexer, } ) def post(self, request, *args, **kwargs): - content = request.POST.get('content', '') - lexer = request.POST.get('lexer', highlight.LEXER_DEFAULT).strip() - filename = request.POST.get('filename', '').strip() - expires = request.POST.get('expires', '').strip() - response_format = request.POST.get('format', 'default').strip() + content = request.POST.get("content", "") + lexer = request.POST.get("lexer", highlight.LEXER_DEFAULT).strip() + filename = request.POST.get("filename", "").strip() + expires = request.POST.get("expires", "").strip() + response_format = request.POST.get("format", "default").strip() if not content.strip(): - return HttpResponseBadRequest('No content given') + return HttpResponseBadRequest("No content given") # 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) + "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)) + % (lexer, ", ".join(highlight.LEXER_KEYS)) ) # No lexer is given, but we have a filename, try to get the lexer @@ -303,7 +299,7 @@ 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) @@ -321,7 +317,7 @@ class APIView(View): ) # Custom formatter for the API response - formatter = getattr(self, '_format_{0}'.format(response_format), None) + formatter = getattr(self, f"_format_{response_format}", None) if callable(formatter): return HttpResponse(formatter(snippet)) @@ -335,13 +331,13 @@ class APIView(View): # ----------------------------------------------------------------------------- -def page_not_found(request, exception=None, template_name='dpaste/404.html'): +def page_not_found(request, exception=None, template_name="dpaste/404.html"): return django_page_not_found( request, exception, template_name=template_name ) -def server_error(request, template_name='dpaste/500.html'): +def server_error(request, template_name="dpaste/500.html"): return django_server_error( request, template_name=template_name ) # pragma: no cover