diff --git a/base-requirements.txt b/base-requirements.txt
index b3865ebb5..bbdac559a 100644
--- a/base-requirements.txt
+++ b/base-requirements.txt
@@ -36,3 +36,5 @@ django-waffle==0.14
djangorestframework==3.8.2
django-filter==1.1.0
+
+pygments==2.1.3
diff --git a/peps/converters.py b/peps/converters.py
index a0282d72a..86aab9993 100644
--- a/peps/converters.py
+++ b/peps/converters.py
@@ -10,11 +10,16 @@
from django.core.files import File
from django.db.models import Max
+from pygments import highlight
+from pygments.lexers import PythonLexer
+from pygments.formatters import HtmlFormatter
+
from pages.models import Page, Image
PEP_TEMPLATE = 'pages/pep-page.html'
pep_url = lambda num: 'dev/peps/pep-{}/'.format(num)
+PURE_PYTHON_PEPS = [483, 484, 526]
def get_peps_last_updated():
last_update = Page.objects.filter(
@@ -140,6 +145,21 @@ def convert_pep_page(pep_number, content):
# Fix PEP links
pep_content = BeautifulSoup(data['content'], 'lxml')
body_links = pep_content.find_all("a")
+ # Fix hihglighting code
+ code_blocks = pep_content.find_all("pre", class_="code")
+ for cb in code_blocks:
+ del cb['class']
+ div = pep_content.new_tag('div')
+ div['class'] = ['highlight']
+ cb.wrap(div)
+ # Highlight existing pure-Python PEPs
+ if int(pep_number) in PURE_PYTHON_PEPS:
+ literal_blocks = pep_content.find_all("pre", class_="literal-block")
+ for lb in literal_blocks:
+ block = lb.string
+ if block:
+ highlighted = highlight(block, PythonLexer(), HtmlFormatter())
+ lb.replace_with(BeautifulSoup(highlighted).html.body.div)
pep_href_re = re.compile(r'pep-(\d+)\.html')
diff --git a/static/stylesheets/pygments_default.css b/static/stylesheets/pygments_default.css
new file mode 100644
index 000000000..0af5bf6a2
--- /dev/null
+++ b/static/stylesheets/pygments_default.css
@@ -0,0 +1,123 @@
+.highlight .c { color: #408080; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #008000; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
+.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #808080 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #008000 } /* Keyword.Pseudo */
+.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #B00040 } /* Keyword.Type */
+.highlight .m { color: #666666 } /* Literal.Number */
+.highlight .s { color: #BA2121 } /* Literal.String */
+.highlight .na { color: #7D9029 } /* Name.Attribute */
+.highlight .nb { color: #008000 } /* Name.Builtin */
+.highlight .nc { color: #3333cc; font-weight: bold } /* Name.Class */
+.highlight .no { color: #880000 } /* Name.Constant */
+.highlight .nd { color: #AA22FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #3333cc } /* Name.Function */
+.highlight .nl { color: #A0A000 } /* Name.Label */
+.highlight .nn { color: #3333cc; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #19177C } /* Name.Variable */
+.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #666666 } /* Literal.Number.Float */
+.highlight .mh { color: #666666 } /* Literal.Number.Hex */
+.highlight .mi { color: #666666 } /* Literal.Number.Integer */
+.highlight .mo { color: #666666 } /* Literal.Number.Oct */
+.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
+.highlight .sc { color: #BA2121 } /* Literal.String.Char */
+.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
+.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.highlight .sx { color: #008000 } /* Literal.String.Other */
+.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
+.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
+.highlight .ss { color: #19177C } /* Literal.String.Symbol */
+.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #19177C } /* Name.Variable.Class */
+.highlight .vg { color: #19177C } /* Name.Variable.Global */
+.highlight .vi { color: #19177C } /* Name.Variable.Instance */
+.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
+.highlight .lineno { color: #000000; background-color: #dddddd; }
+
+.highlight .comment { color: #408080; font-style: italic } /* Comment */
+.highlight .error { border: 1px solid #FF0000 } /* Error */
+.highlight .keyword { color: #008000; font-weight: bold } /* Keyword */
+.highlight .operator { color: #666666 } /* Operator */
+.highlight .comment.multiline { color: #408080; font-style: italic } /* Comment.Multiline */
+.highlight .comment.preproc { color: #BC7A00 } /* Comment.Preproc */
+.highlight .comment.single { color: #408080; font-style: italic } /* Comment.Single */
+.highlight .comment.special { color: #408080; font-style: italic } /* Comment.Special */
+.highlight .generic.deleted { color: #A00000 } /* Generic.Deleted */
+.highlight .generic.emph { font-style: italic } /* Generic.Emph */
+.highlight .generic.error { color: #FF0000 } /* Generic.Error */
+.highlight .generic.heading { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .generic.inserted { color: #00A000 } /* Generic.Inserted */
+.highlight .generic.output { color: #808080 } /* Generic.Output */
+.highlight .generic.prompt { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .generic.strong { font-weight: bold } /* Generic.Strong */
+.highlight .generic.subheading { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .generic.traceback { color: #0040D0 } /* Generic.Traceback */
+.highlight .keyword.constant { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .keyword.declaration { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .keyword.namespace { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.highlight .keyword.pseudo { color: #008000 } /* Keyword.Pseudo */
+.highlight .keyword.reserved { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .keyword.type { color: #B00040 } /* Keyword.Type */
+.highlight .number { color: #666666 } /* Literal.Number */
+.highlight .string { color: #BA2121 } /* Literal.String */
+.highlight .name.attribute { color: #7D9029 } /* Name.Attribute */
+.highlight .name.builtin { color: #008000 } /* Name.Builtin */
+.highlight .name.class { color: #3333cc; font-weight: bold } /* Name.Class */
+.highlight .name.constant { color: #880000 } /* Name.Constant */
+.highlight .name.decorator { color: #AA22FF } /* Name.Decorator */
+.highlight .name.entity { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .name.exception { color: #D2413A; font-weight: bold } /* Name.Exception */
+.highlight .name.function { color: #3333cc } /* Name.Function */
+.highlight .name.label { color: #A0A000 } /* Name.Label */
+.highlight .name.namespace { color: #3333cc; font-weight: bold } /* Name.Namespace */
+.highlight .name.tag { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .name.variable { color: #19177C } /* Name.Variable */
+.highlight .operator.word { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .whitespace { color: #bbbbbb } /* Text.Whitespace */
+.highlight .number.float { color: #666666 } /* Literal.Number.Float */
+.highlight .number.hex { color: #666666 } /* Literal.Number.Hex */
+.highlight .number.integer { color: #666666 } /* Literal.Number.Integer */
+.highlight .number.oct { color: #666666 } /* Literal.Number.Oct */
+.highlight .string.backtick { color: #BA2121 } /* Literal.String.Backtick */
+.highlight .string.char { color: #BA2121 } /* Literal.String.Char */
+.highlight .string.doc { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.highlight .string.double { color: #BA2121 } /* Literal.String.Double */
+.highlight .string.escape { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.highlight .string.heredoc { color: #BA2121 } /* Literal.String.Heredoc */
+.highlight .string.interpol { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.highlight .string.other { color: #008000 } /* Literal.String.Other */
+.highlight .string.regex { color: #BB6688 } /* Literal.String.Regex */
+.highlight .string.single { color: #BA2121 } /* Literal.String.Single */
+.highlight .string.symbol { color: #19177C } /* Literal.String.Symbol */
+.highlight .name.builtin.pseudo { color: #008000 } /* Name.Builtin.Pseudo */
+.highlight .name.variable.class { color: #19177C } /* Name.Variable.Class */
+.highlight .name.variable.global { color: #19177C } /* Name.Variable.Global */
+.highlight .name.variable.instance { color: #19177C } /* Name.Variable.Instance */
+.highlight .number.integer.long { color: #666666 } /* Literal.Number.Integer.Long */
+.highlight .lineno { color: #000000; background-color: #dddddd; }
diff --git a/templates/pages/pep-page.html b/templates/pages/pep-page.html
index bee66015e..6bef6ea1c 100644
--- a/templates/pages/pep-page.html
+++ b/templates/pages/pep-page.html
@@ -25,6 +25,7 @@
{% endblock %}
.
{% block content %}
+