Commits

Anonymous committed 7aa43c8

pypaste new ersion

Comments (0)

Files changed (17)

friendpaste/ext/__init__.py

Empty file added.

friendpaste/ext/webpylint.py

+# -*- coding: utf-8 -
+
+# Copyright 2008 by Benoît Chesneau <benoit@amisphere.org>
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import re
+
+from logilab.common.ureports import BaseWriter, Section, Table, HTMLWriter
+from pylint.reporters.html import HTMLReporter
+
+from friendpaste.utils import force_unicode
+
+
+PYLINT_ALLMSGS= {
+        'E0100': ('__init__ method is a generator',
+            'Used when the special class method __init__ is turned into a '
+            'generator by a yield in its body.'),    
+        'E0101': ('Explicit return in __init__',
+            'Used when the special class method __init__ has an explicit \
+                    return value.'),    
+        'E0102': ('%s already defined line %s',
+            'Used when a function / class / method is redefined.'),
+        'E0103': ('%r not properly in loop',
+            'Used when break or continue keywords are used outside a loop.'),
+
+        'E0104': ('return outside function',
+            'Used when a "return" statement is found outside a function or '
+            'method.'),
+        'E0105': ('yield outside function',
+            'Used when a "yield" statement is found outside a function or '
+            'method.'),
+        'E0106': ('return with argument inside generator',
+            'Used when a "return" statement with an argument is found '
+            'outside in a generator function or method (e.g. with some '
+            '"yield" statements).'),
+
+        'W0101': ('Unreachable code',
+            'Used when there is some code behind a "return" or "raise" \
+                    statement, which will never be accessed.'),
+        'W0102': ('Dangerous default value %s as argument',
+            'Used when a mutable value as list or dictionary is detected in \
+                    a default value for an argument.'),
+        'W0104': ('Statement seems to have no effect',
+            'Used when a statement doesn\'t have (or at least seems to) \
+                    any effect.'),
+        'W0105': ('String statement has no effect',
+            'Used when a string is used as a statement (which of course \
+                    has no effect). This is a particular case of W0104 with its \
+                    own message so you can easily disable it if you\'re using \
+                    those strings as documentation, instead of comments.'),
+        'W0106': ('Unnecessary semicolon',
+            'Used when a statement is endend by a semi-colon (";"), which \
+                    isn\'t necessary (that\'s python, not C ;).'),
+        'W0107': ('Unnecessary pass statement',
+            'Used when a "pass" statement that can be avoided is '
+            'encountered.)'),
+
+        'W0122': ('Use of the exec statement',
+            'Used when you use the "exec" statement, to discourage its \
+                    usage. That doesn\'t mean you can not use it !'),
+
+        'W0141': ('Used builtin function %r',
+            'Used when a black listed builtin function is used (see the '
+            'bad-function option). Usual black listed functions are the ones '
+            'like map, or filter , where Python offers now some cleaner '
+            'alternative like list comprehension.'),
+        'W0142': ('Used * or ** magic',
+                'Used when a function or method is called using `*args` or '
+                '`**kwargs` to dispatch arguments. This doesn\'t improve '
+                'readability and should be used with care.'),
+
+        'C0102': ('Black listed name "%s"',
+                'Used when the name is listed in the black list (unauthorized \
+                        names).'),
+        'C0103': ('Invalid name "%s" (should match %s)',
+                'Used when the name doesn\'t match the regular expression \
+                        associated to its type (constant, variable, class...).'),
+
+        'C0111': ('Missing docstring', # W0131
+                'Used when a module, function, class or method has no docstring.\
+                        Some special methods like __init__ doesn\'t necessary require a \
+                        docstring.'),
+        'C0112': ('Empty docstring', # W0132
+                'Used when a module, function, class or method has an empty \
+                        docstring (it would be too easy ;).'),
+
+        'C0121': ('Missing required attribute "%s"', # W0103
+                'Used when an attribute required for modules is missing.'),
+        'F0202': ('Unable to check methods signature (%s / %s)',
+                'Used when PyLint has been unable to check methods signature \
+                        compatibility for an unexpected raison. Please report this kind \
+                        if you don\'t make sense of it.'),
+
+        'E0202': ('An attribute inherited from %s hide this method',
+                'Used when a class defines a method which is hiden by an \
+                        instance attribute from an ancestor class.'),
+        'E0203': ('Access to member %r before its definition line %s',
+                'Used when an instance member is accessed before it\'s actually\
+                        assigned.'),
+        'W0201': ('Attribute %r defined outside __init__',
+                'Used when an instance attribute is defined outside the __init__\
+                        method.'),
+
+        'W0212': ('Access to a protected member %s of a client class', # E0214
+                'Used when a protected member (i.e. class member with a name \
+                        beginning with an underscore) is access outside the class or a \
+                        descendant of the class where it\'s defined.'),
+
+        'E0211': ('Method has no argument',
+                'Used when a method which should have the bound instance as \
+                        first argument has no argument defined.'),
+        'E0213': ('Method should have "self" as first argument',
+                'Used when a method has an attribute different the "self" as\
+                        first argument. This is considered as an error since this is\
+                        a soooo common convention that you should\'nt break it!'),
+        'C0202': ('Class method should have "cls" as first argument', # E0212
+                'Used when a class method has an attribute different than "cls"\
+                        as first argument, to easily differentiate them from regular \
+                        instance methods.'),
+        'C0203': ('Metaclass method should have "mcs" as first argument', # E0214
+                'Used when a metaclass method has an attribute different the \
+                        "mcs" as first argument.'),
+
+        'W0211': ('Static method with %r as first argument',
+                'Used when a static method has "self" or "cls" as first argument.'
+                ),
+        'R0201': ('Method could be a function',
+                'Used when a method doesn\'t use its bound instance, and so could\
+                        be written as a function.'
+                        ),
+
+        'E0221': ('Interface resolved to %s is not a class',
+                'Used when a class claims to implement an interface which is not \
+                        a class.'),
+        'E0222': ('Missing method %r from %s interface' ,
+                'Used when a method declared in an interface is missing from a \
+                        class implementing this interface'),
+        'W0221': ('Arguments number differs from %s method',
+                'Used when a method has a different number of arguments than in \
+                        the implemented interface or in an overridden method.'),
+        'W0222': ('Signature differs from %s method',
+                'Used when a method signature is different than in the \
+                        implemented interface or in an overridden method.'),
+        'W0223': ('Method %r is abstract in class %r but is not overridden',
+                'Used when an abstract method (ie raise NotImplementedError) is \
+                        not overridden in concrete class.'
+                        ),
+        'F0220': ('failed to resolve interfaces implemented by %s (%s)', # W0224
+                'Used when a PyLint as failed to find interfaces implemented by \
+                        a class'),
+
+
+        'W0231': ('__init__ method from base class %r is not called',
+                'Used when an ancestor class method has an __init__ method \
+                        which is not called by a derived class.'),
+        'W0232': ('Class has no __init__ method',
+                'Used when a class has no __init__ method, neither its parent \
+                        classes.'),
+        'W0233': ('__init__ method from a non direct base class %r is called',
+                'Used when an __init__ method is called on a class which is not \
+                        in the direct ancestors for the analysed class.'),
+
+        'R0901': ('Too many ancestors (%s/%s)',
+                'Used when class has too many parent classes, try to reduce \
+                        this to get a more simple (and so easier to use) class.'),
+        'R0902': ('Too many instance attributes (%s/%s)',
+                'Used when class has too many instance attributes, try to reduce \
+                        this to get a more simple (and so easier to use) class.'),
+        'R0903': ('Too few public methods (%s/%s)',
+                'Used when class has too few public methods, so be sure it\'s \
+                        really worth it.'),
+        'R0904': ('Too many public methods (%s/%s)',
+                'Used when class has too many public methods, try to reduce \
+                        this to get a more simple (and so easier to use) class.'),
+
+        'R0911': ('Too many return statements (%s/%s)',
+                'Used when a function or method has too many return statement, \
+                        making it hard to follow.'),
+        'R0912': ('Too many branches (%s/%s)',
+                'Used when a function or method has too many branches, \
+                        making it hard to follow.'),
+        'R0913': ('Too many arguments (%s/%s)',
+                'Used when a function or method takes too many arguments.'),
+        'R0914': ('Too many local variables (%s/%s)',
+                'Used when a function or method has too many local variables.'),
+        'R0915': ('Too many statements (%s/%s)',
+                'Used when a function or method has too many statements. You \
+                        should then split it in smaller functions / methods.'),
+
+        'R0921': ('Abstract class not referenced',
+                'Used when an abstract class is not used as ancestor anywhere.'),
+        'R0922': ('Abstract class is only referenced %s times',
+                'Used when an abstract class is used less than X times as \
+                        ancestor.'),
+        'R0923': ('Interface not implemented',
+                'Used when an interface class is not implemented anywhere.'),
+
+        'E0701': (
+                'Bad except clauses order (%s)',
+                'Used when except clauses are not in the correct order (from the \
+                        more specific to the more generic). If you don\'t fix the order, \
+                        some exceptions may not be catched by the most specific handler.'),
+        'E0702': ('Raising %s while only classes, instances or string are allowed',
+                'Used when something which is neither a class, an instance or a \
+                        string is raised (i.e. a `TypeError` will be raised).'),
+
+        'W0701': ('Raising a string exception',
+                'Used when a string exception is raised.'),
+        'W0702': ('No exception type(s) specified',
+                'Used when an except clause doesn\'t specify exceptions type to \
+                        catch.'),
+        'W0703': ('Catch "Exception"',
+                'Used when an except catches Exception instances.'),
+        'W0704': ('Except doesn\'t do anything',
+                'Used when an except clause does nothing but "pass" and there is\
+                        no "else" clause.'),
+        'W0706': (
+                'Identifier %s used to raise an exception is assigned to %s',
+                'Used when a variable used to raise an exception is initially \
+                        assigned to a value which can\'t be used as an exception.'),
+        'C0301': ('Line too long (%s/%s)',
+                'Used when a line is longer than a given number of characters.'),
+        'C0302': ('Too many lines in module (%s)', # was W0302
+                'Used when a module has too much lines, reducing its readibility.'
+                ),
+
+        'W0311': ('Bad indentation. Found %s %s, expected %s',
+                'Used when an unexpected number of indentation\'s tabulations or '
+                'spaces has been found.'),
+        'W0312': ('Found indentation with %ss instead of %ss',
+                'Used when there are some mixed tabs and spaces in a module.'),
+
+        'F0321': ('Format detection error in %r',
+                'Used when an unexpected error occured in bad format detection.'
+                'Please report the error if it occurs.'),
+        'C0321': ('More than one statement on a single line',
+                'Used when more than on statement are found on the same line.'),
+        'C0322': ('Operator not preceded by a space\n%s',
+                'Used when one of the following operator (!= | <= | == | >= | < '
+                '| > | = | \+= | -= | \*= | /= | %) is not preceded by a space.'),
+        'C0323': ('Operator not followed by a space\n%s',
+                'Used when one of the following operator (!= | <= | == | >= | < '
+                '| > | = | \+= | -= | \*= | /= | %) is not followed by a space.'),
+        'C0324': ('Comma not followed by a space\n%s',
+                'Used when a comma (",") is not followed by a space.'),
+
+        'W0331': ('Use of the <> operator',
+                'Used when the deprecated "<>" operator is used instead \
+                        of "!=".'),
+        'W0332': ('Use l as long integer identifier',
+                'Used when a lower case "l" is used to mark a long integer. You '
+                'should use a upper case "L" since the letter "l" looks too much '
+                'like the digit "1"'),
+        'W0333': ('Use of the `` operator',
+                'Used when the deprecated "``" (backtick) operator is used '
+                'instead  of the str() function.'),
+        'F0401': ('Unable to import %r (%s)' ,
+                'Used when pylint has been unable to import a module.'),
+        'R0401': ('Cyclic import (%s)',
+                'Used when a cyclic import between two or more modules is \
+                        detected.'),
+
+        'W0401': ('Wildcard import %s',
+                'Used when `from module import *` is detected.'),
+        'W0402': ('Uses of a deprecated module %r',
+                'Used a module marked as deprecated is imported.'),
+        'W0403': ('Relative import %r',
+                'Used when an import relative to the package directory is \
+                        detected.'),
+        'W0404': ('Reimport %r (imported line %s)',
+                'Used when a module is reimported multiple times.'),
+        'W0406': ('Module import itself',
+                'Used when a module is importing itself.'),
+
+        'W0410': ('__future__ import is not the first non docstring statement',
+                'Python 2.5 and greater require __future__ import to be the \
+                        first non docstring statement in the module.'),
+        'E0501': ('Non ascii characters found but no encoding specified (PEP 263)',
+                'Used when some non ascii characters are detected but now \
+                        encoding is specified, as explicited in the PEP 263.'),
+        'E0502': ('Wrong encoding specified (%s)',
+                'Used when a known encoding is specified but the file doesn\'t \
+                        seem to be actually in this encoding.'),
+        'E0503': ('Unknown encoding specified (%s)',
+                'Used when an encoding is specified, but it\'s unknown to Python.'
+                ),
+
+        'W0511': ('%s',
+                'Used when a warning note as FIXME or XXX is detected.'),
+        'E1001': ('Use __slots__ on an old style class',
+                'Used when an old style class use the __slots__ attribute.'),
+        'E1002': ('Use super on an old style class',
+                'Used when an old style class use the super builtin.'),
+        'E1003': ('Bad first argument %r given to super class',
+                'Used when another argument than the current class is given as \
+                        first argument of the super builtin.'),
+        'E1010': ('Raising a new style class',
+                'Used when a new style class is raised since it\'s not \
+                        possible with python < 2.5.'),
+
+        'W1001': ('Use of "property" on an old style class',
+                'Used when PyLint detect the use of the builtin "property" \
+                        on an old style class while this is relying on new style \
+                        classes features'),
+        'W1010': ('Exception doesn\'t inherit from standard "Exception" class',
+                'Used when a custom exception class is raised but doesn\'t \
+                        inherit from the builtin "Exception" class.'),
+        'E1201': ('Using unavailable keyword %r',
+                'Used when a keyword which is not available in rpython is used.'),
+        'E1202': ('Using unavailable builtin %r',
+                'Used when a built-in which is not available in rpython is used.'
+                ),
+        'E1203': ('generator expressions are not supported',
+                'Used when a generator expression is used while generator are \
+                        not available in rpython.'),    
+        'E1204': ('multiple inheritance only supported under specific rules \
+                which doesn\'t seems to be satisfied',
+                'Multiple inheritance is only supported using pure mixin (no \
+                        instance attribute defined in the mix-in) with "_mixin_" class attribute set \
+                        to True.'),
+        'E1205': ('Using unavailable protocol %r',
+                'Used when a special method not handled by rpython is used *and*'
+                ' that may not be used explicitly is used (see W1201).'),
+
+
+        'E1210': ('Multiple types assigned to %s %r',
+                'Used when an identifier or attribut is infered as having values'
+                ' of different types assigned.'),
+        'E1211': ('Can\'t mix %s and None on %s %r',
+                'Used when an int or float variable is assigned to None.'),    
+        'E1212': ('Non homogeneous values in list',
+                'Used when a list is not containing homogeneous values.'),
+
+
+        ##     'E1205': ('Identifier %r is not properly initialized',
+##               'Used when an identifier is used in some conditional block \
+        ## without being properly initialized before that block.'),
+
+    'E1220': ('Modifying global %r from module %s',
+            'Used when a module variable is modified, which is not allowed '
+            'in rpython since globals are considered as constants.'),
+
+
+    'E1230': ('Using negative slice %s %s (infered to %s)',
+            'Used when a negative integer is used as lower, upper or step of'
+            ' a slice.'),
+    'E1231': ('Using non constant step',
+            'Used when a variable not annotated as a constant is used as '
+            'step of a slice.'),
+
+    'E1240': ('%r format is not supported',
+            'Used when the unavailable "%r" formatting instruction is used.'
+            ),
+
+    'W1201': ('special method %s has to be called explicitly',
+            'Used when a special method is defined on a class, as rpython '
+            'won\'t call the explicitly.'),
+    'R0801': ('Similar lines in %s files\n%s',
+            'Indicates that a set of similar lines has been detected \
+                    among multiple file. This usually means that the code should \
+                    be refactored to avoid this duplication.'),
+    'E1101': ('%s %r has no %r member',
+            'Used when a variable is accessed for an unexistant member.'),
+    'E1102': ('%s is not callable',
+            'Used when an object being called has been infered to a non \
+                    callable object'),
+    'E1103': ('%s %r has no %r member (but some types could not be inferred)',
+            'Used when a variable is accessed for an unexistant member, but \
+                    astng was not able to interpret all possible types of this \
+                    variable.'),
+    'E1111': ('Assigning to function call which doesn\'t return',
+            'Used when an assigment is done on a function call but the \
+                    infered function doesn\'t return anything.'),
+    'W1111': ('Assigning to function call which only returns None',
+            'Used when an assigment is done on a function call but the \
+                    infered function returns nothing but None.'),
+    'E0601': ('Using variable %r before assignment',
+            'Used when a local variable is accessed before it\'s \
+                    assignment.'),
+    'E0602': ('Undefined variable %r',
+            'Used when an undefined variable is accessed.'),
+
+    'E0611': ('No name %r in module %r',
+            'Used when a name cannot be found in a module.'),
+
+    'W0601': ('Global variable %r undefined at the module level',
+            'Used when a variable is defined through the "global" statement \
+                    but the variable is not defined in the module scope.'),
+    'W0602': ('Using global for %r but no assigment is done',
+            'Used when a variable is defined through the "global" statement \
+                    but no assigment to this variable is done.'),
+    'W0603': ('Using the global statement', # W0121
+            'Used when you use the "global" statement to update a global \
+                    variable. PyLint just try to discourage this \
+                    usage. That doesn\'t mean you can not use it !'),
+    'W0604': ('Using the global statement at the module level', # W0103
+            'Used when you use the "global" statement at the module level \
+                    since it has no effect'),
+    'W0611': ('Unused import %s',
+            'Used when an imported module or variable is not used.'),
+    'W0612': ('Unused variable %r',
+            'Used when a variable is defined but not used.'),
+    'W0613': ('Unused argument %r',
+            'Used when a function or method argument is not used.'),
+    'W0614': ('Unused import %s from wildcard import',
+            'Used when an imported module or variable is not used from a \
+                    \'from X import *\' style import.'),
+
+    'W0621': ('Redefining name %r from outer scope (line %s)',
+            'Used when a variable\'s name hide a name defined in the outer \
+                    scope.'),
+    'W0622': ('Redefining built-in %r',
+            'Used when a variable or function override a built-in.'),
+
+    'W0631': ('Using possibly undefined loop variable %r',
+            'Used when an loop variable (i.e. defined by a for loop or \
+                    a list comprehension or a generator expression) is used outside \
+                    the loop.')
+
+    }
+
+
+class PYPHTMLWriter(BaseWriter):
+    """format layouts as HTML"""
+    
+    def __init__(self, snipet=None):
+        super(PYPHTMLWriter, self).__init__(self)
+        self.snipet = snipet 
+        
+    def handle_attrs(self, layout):
+        """get an attribute string from layout member attributes"""
+        attrs = ''
+        klass = getattr(layout, 'klass', None)
+        if klass:
+            attrs += ' class="%s"' % klass
+        nid = getattr(layout, 'id', None)
+        if nid: 
+            attrs += ' id="%s"' % nid
+        return attrs
+    
+    def begin_format(self, layout):
+        """begin to format a layout"""
+        super(PYPHTMLWriter, self).begin_format(layout)
+        if self.snipet is None:
+            self.writeln('<div id="report">')
+        
+    def end_format(self, layout):
+        """finished to format a layout"""
+        if self.snipet is None:
+            self.writeln('</div>')
+
+    def visit_section(self, layout):
+        """display a section as html, using div + h[section level]"""
+        self.section += 1
+        self.writeln('<div%s>' % self.handle_attrs(layout))
+        self.format_children(layout)
+        self.writeln('</div>')
+        self.section -= 1
+
+    def visit_title(self, layout):
+        """display a title using <hX>"""
+        self.write('<h%s%s>' % (self.section, self.handle_attrs(layout)))
+        self.format_children(layout)
+        self.writeln('</h%s>' % self.section)
+
+    def visit_table(self, layout):
+        """display a table as html"""
+        self.writeln('<table%s>' % self.handle_attrs(layout))
+        table_content = self.get_table_content(layout)
+        for i in range(len(table_content)):
+            row = table_content[i]
+            if i == 0 and layout.rheaders:
+                self.writeln('<tr class="header">')
+            elif i+1 == len(table_content) and layout.rrheaders:
+                self.writeln('<tr class="header">')
+            else:
+                self.writeln('<tr class="%s">' % (i%2 and 'even' or 'odd'))
+            for j in range(len(row)):
+                cell = row[j] or '&nbsp;'
+                if (layout.rheaders and i == 0) or \
+                   (layout.cheaders and j == 0) or \
+                   (layout.rrheaders and i+1 == len(table_content)) or \
+                   (layout.rcheaders and j+1 == len(row)):
+                    self.writeln('<th>%s</th>' % cell)
+                else:
+                    self.writeln('<td>%s</td>' % cell)
+            self.writeln('</tr>')
+        self.writeln('</table>')
+        
+    def visit_list(self, layout):
+        """display a list as html"""
+        self.writeln('<ul%s>' % self.handle_attrs(layout))
+        for row in list(self.compute_content(layout)):
+            self.writeln('<li>%s</li>' % row)
+        self.writeln('</ul>')
+        
+    def visit_paragraph(self, layout):
+        """display links (using <p>)"""
+        self.write('<p>')
+        self.format_children(layout)
+        self.write('</p>')
+                   
+    def visit_span(self, layout):
+        """display links (using <p>)"""
+        self.write('<span%s>' % self.handle_attrs(layout))
+        self.format_children(layout)
+        self.write('</span>')
+                   
+    def visit_link(self, layout):
+        """display links (using <a>)"""
+        self.write(' <a href="%s"%s>%s</a>' % (layout.url,
+                                               self.handle_attrs(layout),
+                                               layout.label))
+    def visit_verbatimtext(self, layout):
+        """display verbatim text (using <pre>)"""
+        self.write('<pre>')
+        self.write(layout.data.replace('&', '&amp;').replace('<', '&lt;'))
+        self.write('</pre>')
+        
+    def visit_text(self, layout):
+        """add some text"""
+        data = layout.data
+        if layout.escaped:
+            data = data.replace('&', '&amp;').replace('<', '&lt;')
+        self.write(data)
+
+class PYPHTMLReporter(HTMLReporter):
+    def _display(self, layout):
+        if self.msgs:
+            # add stored messages to the layout
+            msgs = ['type', 'module', 'object', 'line', 'message']
+            msgs += self.msgs
+            sect = Section('Messages')
+            layout.append(sect)
+            sect.append(Table(cols=5, children=msgs, rheaders=1))
+            self.msgs = []
+        PYPHTMLWriter().format(layout, self.out)
+
+
+def replace_tips(dict, text): 
+    regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
+    return regex.sub(lambda mo: '<span class="tips" title="%s|%s">%s</span>' % (mo.string[mo.start():mo.end()],dict[mo.string[mo.start():mo.end()]][1],mo.string[mo.start():mo.end()]), text)
+
+
+def parse_report(report, fname, id):
+    re_module = re.compile('%s' % os.path.basename(fname), re.U)
+    ret = replace_tips(PYLINT_ALLMSGS, report)
+    ret = re_module.sub('<a href="/%s">%s</a>' % (id,id), force_unicode(ret))
+
+    return ret

friendpaste/settings.py

 
 DEBUG = True
 
-SITE_URI='http://www.friendpaste.com'
-ORBITED_HOST = 'orbited.friendpaste.com'
+SITE_URI='http://www.pypaste.com'
+ORBITED_HOST = 'orbited.pypastecom'
 ORBITED_PORT = 80
 
 if DEBUG:
 
 # database
 SERVER_URI='http://127.0.0.1:5984'
-DATABASE_NAME='friendpaste'
+DATABASE_NAME='pypaste'
 
 # path 
 PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))
 SITE_ID=1
 SECRET_KEY='*j4c=nhmvl@up^@)ftp0i8^2r8woplh^tlwen=z1vs=yod^bc%'
 
-TOP_LEXERS=[] 
+TOP_LEXERS=['python', 'pycon', 'pytb', 'text', 'sql', 'html+django', 
+        'html+genshi', 'html+mako', 'css', 'xml', 'diff', 'js', 'bash'] 
 ############
 # SESSIONS #
 ############
-SESSION_COOKIE_NAME = 'FRIENDPASTE_SID'
+SESSION_COOKIE_NAME = 'PYPASTE_SID'
 SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
 SESSION_COOKIE_DOMAIN = None
 SESSION_COOKIE_PATH = '/'

friendpaste/urls.py

         'paste/reviewset': views.snippet_reviews_set,
         'login': views.login,
         'logout': views.logout,
-        'languages': views.fplanguages
-
+        'languages': views.fplanguages,
+        'paste/pylint': views.view_pylint
 }
 
 
     Rule('/<id>/delete', endpoint='paste/delete'),
     Rule('/<id>/lock', endpoint='paste/lock'),
     Rule('/<id>/unlock', endpoint='paste/unlock'),
+    Rule('/<id>/report', endpoint='paste/pylint'),
     Rule('/<id>/changeset', endpoint='paste/changeset'),
     Rule('/<id>/revisions', endpoint='paste/revisions'),
     Rule('/<id>/review/<nb_line>', endpoint='paste/review'),

friendpaste/views.py

 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from cStringIO import StringIO
+
+
 from datetime import datetime
 import os.path
 import socket
+import tempfile
 import time
 from uuid import UUID
 
 
 import simplejson as json
 
+from pylint.lint import PyLinter, Run
+
 from friendpaste import settings
 from friendpaste.feeds import RssFeed, RssFeedEntry 
 from friendpaste.http import FPResponse, send_json
 from friendpaste.template import render_response, highlighter, pretty_type, shighlight, \
 render_template, url_for, ALL_COLORSHEME 
 from friendpaste.utils import local, local_manager, datetimestr_topython,\
-strptime, make_hash, datetime_tojson, send_stomp_msg, force_unicode
+strptime, make_hash, datetime_tojson, send_stomp_msg, force_unicode, utf8, to_str
 from friendpaste.utils.diff import get_unchanged_lines
 from friendpaste.utils.html import sanitize_html
 from friendpaste.utils.base62 import *
-
+from friendpaste.ext.webpylint import PYPHTMLReporter, parse_report
 
 def _get_lexers(request):
     lexers = list(get_all_lexers())
         except ValueError:
             return send_json({'ok': False})
 
-        print data
         request.session['languages'] = data
         return send_json({'ok': True})
     return send_json({'ok': false})
         del request.session[key]
     return redirect(next)
 
+# pylint for pypaste
+@login_required
+def view_pylint(request, id):
+    revid = request.values.get('rev', None)
+    pasteid = UUID(int=b62decode(id)).hex
+    p = Paste.get_paste(local.db,pasteid, revid)
+    
+    if p is None:
+        raise NotFound
+
+    
+    (fd, path) = tempfile.mkstemp()
+    f = os.fdopen(fd, "w")
+    f.write(to_str(p.content))
+    f.close()
+    output = StringIO()
+    Run([path,'--disable-msg', 'C0103','--disable-msg', 'C0111'], reporter=PYPHTMLReporter(output), quiet=1)
+    report=parse_report(utf8(output.getvalue()), path, id)
+    output.close()
+    os.unlink(path)
+    p.pasteid = id
+    return render_response('paste/report.html', snippet=p, report=report)
 
 
 # generic views

static/css/src/colors.css

     border-color: #f7f7f0 ;
 }
 
-#revisions h3, div.txt h2 {
+#revisions h3, 
+div.txt h2,
+#report h2 {
     background-color: #303030;
     color: #fff;
 }
     border-color: #f7f7f0;
 }
 
+
+
+#report th {
+    background:#f8f8f8;
+}
+
+
+
 div.errors,
 li.errors {
     background-color: #ff9898;

static/css/src/layout.css

 #revisions h2 {
     margin-bottom: 15px;
 }
-#revisions h3, div.txt h2 {
+#revisions h3,
+div.txt h2,
+#report h2 {
     margin: 15px 0 15px 0;
     padding: 0.1em;
 }
+#report table {margin-bottom:1.4em;width:100%;}
+#report th {font-weight:bold;}
+#report th, #report td {padding:4px 10px 4px 5px;}
 
 #snippet_title {
     display: block;

static/images/logo.gif

Old
Old image
New
New image

static/images/logo.png

Old
Old image
New
New image

templates/about.html

 {% block content %}
 <div class="txt">
 
-<h1>About Friendpaste</h1>
+<h1>About Pypaste</h1>
 
-<h2>Why another pastebin ?</h2>
+<h2>A Friendpaste service</h2>
 
-<ul>
-    <li><em><strong>Short answer:</strong></em>
-    <p>Because we could do better</p></li>
-
-    <li><em><strong>Long answer :</strong></em>
-    <p>Enki Multimedia launched in september the website <a href="http://www.friendsnippets.com">Friendsnippets</a> a website where you can keep your snippets in one place, bookmark them for yourself or friends. And it seem that friendsnippets need a companion. <strong>A fast service where you can copy/paste your code, recipe, anything else and give the link to your friend.</strong></p>
-    <p><strong>So we dit it.</strong></p>
-    <p>It would have been easy to just take some features from pastebin around and create friendpaste. But we decided that we could do better. In particularly by designing a better interface. We also added some interresting features.</p>
-
-    </li>
-
-</ul>
+<p>Pypaste is a website based on <a href="http://friendpaste.com">Friendpaste</a>. We designed it for pythonists and hope to add soon more features. It may follow or not the friendpaste code in the future.</p>
 
 <h2>Features</h2>
 <ul>
 And the best is coming... Follow news of Friendpaste on <a href="http://twitter.com/friendpaste">twitter</a>.
 
 
-<h2>How is build friendpaste ?</h2>
+<h2>How is build pypaste ?</h2>
 <ul>
 
     <li><strong>No SQL database</strong>. We use the new and powerfull document based database <a href="http://www.couchdb.org"><strong>Apache CouchDB</strong></a>.</li>
 
 <h2>Who ?</h2>
 
-Friendpaste has been produced by <a href="http://www.e-engura.com">Enki Multimedia</a>.
+Pypaste has been produced by <a href="http://www.e-engura.com">Enki Multimedia</a>.
 
 <h2>Privacy</h2>
 

templates/base.html

 </head>
 <body class="{{ theme }}">
     <header id="site_header">
-        <h1><a href="/">Friendpaste</a></h1>
+        <h1><a href="/">Pypaste</a></h1>
         {% block auth %}{% endblock %}
         <ul id="main_nav">
             <li><a href="/">New paste</a></li>

templates/developer.html

 {% extends "base.html" %}
-{% block title %}Friendpaste Services{% endblock %}
+{% block title %}Pypaste Services{% endblock %}
 
 {% block content %}
 <div class="txt">
-    <h1>Friendpaste Services</h1>
-    <p>Friendpaste has an open Application Programming Interface (API for short). This means that anyone can write their own program to post public paste  in new and different ways. The Friendpaste API is available for outside developers without any limits.</p>
+    <h1>Pypaste Services</h1>
+    <p>Pypaste has an open Application Programming Interface (API for short). This means that anyone can write their own program to post public paste  in new and different ways. The Friendpaste API is available for outside developers without any limits.</p>
     <h2>Json API</h2>
     <p>The primary API for programmatically accessing the Friendpaste is a <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a> API. All data sent to the server should be encoded in JSON.</p>
     <h3>Get a paste</h3>
 }
 </pre>
     <h3>Create a paste</h3>
-    <p>To create a paste, perform a POST operation at <a href="http://www.friendpaste.com">http://www.friendpaste.com/</a> .</p>
+    <p>To create a paste, perform a POST operation at <a href="http://www.pypaste.com">http://www.pypaste.com/</a> .</p>
     <p>The following is an example HTTP <em>POST</em>. It will cause the Friendpaste server to generate a new paste ID and save the content with it.</p>
     <pre>
 POST / HTTP/1.0
 Content-Type: application/json
 Connection: close
 
-{"ok": true, "id": "some_paste_id", "url": "http://friendpaste.com/some_paste_id"}
+{"ok": true, "id": "some_paste_id", "url": "http://pypaste.com/some_paste_id"}
     </pre>
     <p>If the paste is created the server return you a JSON  object in which you get the id of created paste and the direct url to the paste.</p>
     <p>If any error happend whil pasting, here is the server response.</p>
 {"ok": "false", "reason": "error message"}
     </pre>
     <h3>Update a paste</h3>
-<p>To update a paste, perform a PUT operation at <a href="http://www.friendpaste.com/">http://www.friendpaste.com/some_paste_id</a> .</p>
+<p>To update a paste, perform a PUT operation at <a href="http://www.pypaste.com/">http://www.pypaste.com/some_paste_id</a> .</p>
     <p>The following is an example HTTP <em>PUT</em>. It will cause the Friendpaste server to generate a new revision of the paste and update current content with it.</p>
     <pre>
 PUT /some_paste_id HTTP/1.0
 Content-Type: application/json
 Connection: close
 
-{"ok": true, "url": "http://friendpaste.com/some_paste_id"}
+{"ok": true, "url": "http://pypaste.com/some_paste_id"}
     </pre>
     <p>If the paste is created the server return you a JSON  object in which you get the id of created paste and the direct url to the paste.</p>
     <p>If any error happend whil pasting, here is the server response.</p>

templates/paste/report.html

+{% extends "base.html" %}
+
+{% block title %}{{ snippet.pasteid }} report{% endblock %}
+
+{% block content %}
+<section id="view">
+    <article id="snippet">
+
+        <header>
+            <h2><a href="/{{ snippet.pasteid }}" class="root">{% if
+        snippet.title %}{{ snippet.title }}{% else %}No title{%
+        endif %}</a></h2>
+        </header>
+        {{ report }}
+    </article>
+</section>
+{% endblock %}

templates/paste/view.html

                         {% endif %}
 
                     </li>
+
                     <li>
                         <form action="/{{ snippet.pasteid }}/fork"
                             method="get">
                             <input type="submit" class="show-history" value="Older revisions..." />
                         </form>
                     </li>
-
+                    {% if snippet.language == "python" %}
+                    <li class="pylint">
+                        <form action="/{{ snippet.pasteid }}/report" method="get">
+                            <input type="submit" value="PyLint Report" />
+                        </form>
+                    </li>
+                    {% endif %}
                 </ul>
             </div>
             <p id="dl"><strong>View in other formats:</strong><br /><a

templates/services.html

 {% extends "base.html" %}
-{% block title %}Friendpaste Services{% endblock %}
+{% block title %}Pypaste Services{% endblock %}
 
 {% block content %}
 <div class="txt">
-    <h1>Friendpaste Services</h1>
+    <h1>Pypaste Services</h1>
      
     <h2>API</h2>
-    <p>Friendpaste has an open Application Programming Interface (API for short). This means that anyone can write their own program to post public paste  in new and different ways. The Friendpaste API is available for outside developers without any limits.</p>
+    <p>Pypaste has an open Application Programming Interface (API for short). This means that anyone can write their own program to post public paste  in new and different ways. The Friendpaste API is available for outside developers without any limits.</p>
 
     <br />
     <ul>
             <li>Install python <a href="http://pypi.python.org/pypi/simplejson">simplejson</a> module.</li>
             <li><a href="http://www.friendpaste.com/static/Friendpaste.tmbundle.zip">Download</a> and unzip the bundle file.</li>
             <li>Double-click the bundle to install into TextMate</li>
+            <li>set <strong>FRIENDPASTE_SERVER</strong> environnment variable to pypaste.com</li>
         <ol>
     </p>
     <p>Once it's installed, you can insert your paste by pressing ⌥⇧⌘V and insert a snippet in your code by pressing  ⌥⇧⌘S. Update a paste by pressing ⌥⇧⌘U (These are just the default settings. You can set them to whatever you want with TextMate.). Put paste url in your clipboard first before update or insert.</p>
     <br />
     <p><strong>Developer, you have made a tool using friendpaste and want to share with others,
         don't hesitate to send us a <a href="friendpaste@e-engura.com">mail</a>. <br />We will addd a link to it on this page.</strong></p>
-    
+
+    <h3>Python tools</h3>
+    <ul>
+        <li><a href="http://pypi.python.org/pypi/pypaster/0.6">Pypaster</a> from Matt Kemp.</li>
+        <li><a href="https://dev.e-engura.org/hg/friendpaste/file/b928fbcd4e23/contrib/fpcli.py">fpcli.py</a> from Mickaël Guérin</li>
+    </ul>
 </div>
     
 {% endblock %}

templates/services/feed.html

 {% extends "base.html" %}
-{% block title %}Friendpaste Services{% endblock %}
+{% block title %}Pypaste Services{% endblock %}
 
 {% block content %}
 <div class="txt">
 
     <h1><a href="/services">Services</a> / Paste feed</h1>
     <h2>Get Paste feed</h2>
-    <p>You can easyly follow the paste activity by retrieving the RSS 2.0 feed on url <a href="http://www.friendpaste.com/some_paste_id/rss">http://www.friendpaste.com/some_paste_id/rss</a></p>
+    <p>You can easyly follow the paste activity by retrieving the RSS 2.0 feed on url <a href="http://www.pypaste.com/some_paste_id/rss">http://www.pypaste.com/some_paste_id/rss</a></p>
     
 </div>
 {% endblock %}

templates/services/json.html

 {% extends "base.html" %}
-{% block title %}Friendpaste Services{% endblock %}
+{% block title %}Pypaste Services{% endblock %}
 
 {% block content %}
 <div class="txt">
 }
 </pre>
     <h2>Create a paste</h2>
-    <p>To create a paste, perform a POST operation at <a href="http://www.friendpaste.com">http://www.friendpaste.com/</a> .</p>
+    <p>To create a paste, perform a POST operation at <a href="http://www.pypaste.com">http://www.pypaste.com/</a> .</p>
     <p>The following is an example HTTP <em>POST</em>. It will cause the Friendpaste server to generate a new paste ID and save the content with it.</p>
     <pre>
 POST / HTTP/1.0
 Content-Type: application/json
 Connection: close
 
-{"ok": true, "id": "some_paste_id", "nb_revision": "paste_revision_id", "url": "http://friendpaste.com/some_paste_id"}
+{"ok": true, "id": "some_paste_id", "nb_revision": "paste_revision_id", "url": "http://pypaste.com/some_paste_id"}
     </pre>
     <p>If the paste is created the server return you a JSON  object in which you get the id of created paste and the direct url to the paste.</p>
     <p>If any error happend whil pasting, here is the server response.</p>
 {"ok": false, "reason": "error message"}
     </pre>
     <h2>Update a paste</h2>
-<p>To update a paste, perform a PUT operation at <a href="http://www.friendpaste.com/">http://www.friendpaste.com/some_paste_id</a> .</p>
+<p>To update a paste, perform a PUT operation at <a href="http://www.pypaste.com/">http://www.pypaste.com/some_paste_id</a> .</p>
     <p>The following is an example HTTP <em>PUT</em>. It will cause the Friendpaste server to generate a new revision of the paste and update current content with it.</p>
     <pre>
 PUT /some_paste_id HTTP/1.0
 Content-Type: application/json
 Connection: close
 
-{"ok": true, "id": "some_paste_id", "nb_revision": "new_revision_number", "url": "http://friendpaste.com/some_paste_id"}
+{"ok": true, "id": "some_paste_id", "nb_revision": "new_revision_number", "url": "http://pypaste.com/some_paste_id"}
     </pre>
     <p>If the paste is created the server return you a JSON  object in which you get the id of created paste and the direct url to the paste.</p>
     <p>If any error happend whil pasting, here is the server response.</p>
 {"ok": false, "reason": "error message"}
     </pre>
     <h2>Get revisions</h2>
-    <p>To retrieve all revisions of a paste, simply perform a <em>GET</em> operation on <a href="http://friendpaste.com/some_paste_id/revisions">http://friendpaste.com/some_paste_id/revisions</a>.</>
+    <p>To retrieve all revisions of a paste, simply perform a <em>GET</em> operation on <a href="http://pypaste.com/some_paste_id/revisions">http://pypaste.com/some_paste_id/revisions</a>.</>
     <pre>
 GET /some_paste_id/revisions HTTP/1.0
 Date: Tue, 29 Apr 2008 05:39:28 +0000GMT
 </pre>
 
     <h2>Get a changeset</h2>
-    <p>To retrieve a changeset, simply perform a <em>GET</em> operation on <a href="http://friendpaste.com/some_paste_id/changeset?rev=some_rev_id">http://friendpaste.com/some_paste_id/changeset?rev=some_rev_id</a>.  Changeset are in unidiff format</>
+    <p>To retrieve a changeset, simply perform a <em>GET</em> operation on <a href="http://pypaste.com/some_paste_id/changeset?rev=some_rev_id">http://pypaste.com/some_paste_id/changeset?rev=some_rev_id</a>.  Changeset are in unidiff format</>
     <pre>
 GET /some_paste_id/changeset?rev=some_rev_id HTTP/1.0
 Date: Tue, 29 Apr 2008 05:39:28 +0000GMT
 }
 </pre>
     <h2>Get all languages</h2>
-    <p>To retrieve list of all languages supported by Friendpaste, simply perform a <em>GET</em> operation on <a href="http://friendpaste.com/_all_languages">http://friendpaste.com/_all_languages</a> url.</>
+    <p>To retrieve list of all languages supported by Friendpaste, simply perform a <em>GET</em> operation on <a href="http://pypaste.com/_all_languages">http://pypaste.com/_all_languages</a> url.</>
     <pre>
 GET /_all_languages HTTP/1.0
 Date: Tue, 29 Apr 2008 05:39:28 +0000GMT