[svn] added pylint script for jinja and cleaned code up a bit (and importing is faste...
authorArmin Ronacher <armin.ronacher@active-4.com>
Mon, 28 May 2007 21:15:43 +0000 (23:15 +0200)
committerArmin Ronacher <armin.ronacher@active-4.com>
Mon, 28 May 2007 21:15:43 +0000 (23:15 +0200)
--HG--
branch : trunk

Makefile
jinja/_native.py
jinja/datastructure.py
jinja/filters.py
jinja/lexer.py
jinja/loaders.py
jinja/parser.py
jinja/tests.py
jinja/translators/python.py
jinja/utils.py
scripts/pylintrc [new file with mode: 0644]

index 8f40d473fe740a868cf5af756740b0e21dbdb128..9b1cd17efd07e93aa6273df37bfbaf9269f368bb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -20,5 +20,8 @@ documentation:
 webpage:
        @(cd ../www; ./generate.py)
 
+pylint:
+       @pylint --rcfile scripts/pylintrc jinja
+
 release: documentation
        @(python2.3 setup.py release bdist_egg upload; python2.4 setup.py release bdist_egg upload; python2.5 setup.py release bdist_egg sdist upload)
index 9fa723f53b273cdf26ac153fe7528edf1cb67088..1c01fa08b30d2f1c4c6f699debe166a77fe4bb51 100644 (file)
     :copyright: 2007 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
-from jinja.datastructure import Deferred, Undefined
-try:
-    from collections import deque
-except ImportError:
-    class deque(list):
-        """
-        Minimal subclass of list that provides the deque
-        interface used by the native `BaseContext`.
-        """
-
-        def appendleft(self, item):
-            list.insert(self, 0, item)
-
-        def popleft(self):
-            return list.pop(self, 0)
+from jinja.datastructure import Deferred
+from jinja.utils import deque
 
 
 class BaseContext(object):
index f66e16d44a5123052fc3ff728e7b55b4e28c3aca..0f5d9e932f17769da2ba308dca3dd388ecbf0583 100644 (file)
@@ -9,12 +9,6 @@
     :license: BSD, see LICENSE for more details.
 """
 
-# sets
-try:
-    set
-except NameError:
-    from sets import Set as set
-
 from jinja.exceptions import TemplateSyntaxError, TemplateRuntimeError
 
 
index 17c0ce8c7fb38ddfceddc39cc5581d59beacbb45..1d45fc489b344a8809c61f6eef586b729f08757e 100644 (file)
 import re
 from random import choice
 from urllib import urlencode, quote
-from jinja.utils import urlize, escape
-from jinja.datastructure import Markup, TemplateData
+from jinja.utils import urlize, escape, reversed
+from jinja.datastructure import TemplateData
 from jinja.exceptions import FilterArgumentError
 
 
-try:
-    _reversed = reversed
-except NameError:
-    # python2.3 compatibility hack for the do_reverse function
-    def _reversed(seq):
-        try:
-            return seq[::-1]
-        except:
-            try:
-                return list(seq)[::-1]
-            except:
-                raise TypeError('argument to _reversed must '
-                                'be a sequence')
-
-
 def stringfilter(f):
     """
     Decorator for filters that just work on unicode objects.
@@ -332,7 +317,7 @@ def do_last():
     """
     def wrapped(env, context, seq):
         try:
-            return iter(_reversed(seq)).next()
+            return iter(reversed(seq)).next()
         except StopIteration:
             return env.undefined_singleton
     return wrapped
index 7b98a57c19bad359822ca445d3d6658458a7d1b0..825722b082f3a63ff83617630bec40f644781081 100644 (file)
 import re
 from jinja.datastructure import TokenStream
 from jinja.exceptions import TemplateSyntaxError
+from jinja.utils import set
 from weakref import WeakValueDictionary
 
-try:
-    set
-except NameError:
-    from sets import Set as set
-
 
 __all__ = ['Lexer', 'Failure', 'keywords']
 
index 15d04e6840648e62629d7e789465d3d07edd1202..ae93aaa1ef23d90ed564ebe5cd6b32c09069f578 100644 (file)
@@ -18,11 +18,6 @@ from jinja.parser import Parser
 from jinja.translators.python import PythonTranslator, Template
 from jinja.exceptions import TemplateNotFound, TemplateSyntaxError
 from jinja.utils import CacheDict, raise_syntax_error
-try:
-    from pkg_resources import resource_exists, resource_string, \
-                              resource_filename
-except ImportError:
-    resource_exists = resource_string = resource_filename = None
 
 
 #: when updating this, update the listing in the jinja package too
@@ -131,6 +126,12 @@ class BaseLoader(object):
         ast = self.parse(environment, name, None)
         return translator.process(environment, ast)
 
+    def get_source(self, environment, name, parent):
+        """
+        Override this method to get the source for a template.
+        """
+        raise TemplateNotFound(name)
+
 
 class CachedLoaderMixin(object):
     """
@@ -353,8 +354,10 @@ class PackageLoader(CachedLoaderMixin, BaseLoader):
     def __init__(self, package_name, package_path, use_memcache=False,
                  memcache_size=40, cache_folder=None, auto_reload=True,
                  cache_salt=None):
-        if resource_filename is None:
-            raise ImportError('setuptools not found')
+        try:
+            import pkg_resources
+        except ImportError:
+            raise RuntimeError('setuptools not installed')
         self.package_name = package_name
         self.package_path = package_path
         if cache_salt is None:
@@ -363,6 +366,7 @@ class PackageLoader(CachedLoaderMixin, BaseLoader):
                                    cache_folder, auto_reload, cache_salt)
 
     def get_source(self, environment, name, parent):
+        from pkg_resources import resource_exists, resource_string
         name = '/'.join([self.package_path] + [p for p in name.split('/')
                         if p != '..'])
         if not resource_exists(self.package_name, name):
@@ -371,6 +375,7 @@ class PackageLoader(CachedLoaderMixin, BaseLoader):
         return contents.decode(environment.template_charset)
 
     def check_source_changed(self, environment, name):
+        from pkg_resources import resource_exists, resource_filename
         fn = resource_filename(self.package_name, '/'.join([self.package_path] +
                                [p for p in name.split('/') if p and p[0] != '.']))
         if resource_exists(self.package_name, fn):
index befcbc5389d14f3e56faa6e0d8fe61aaa3f6c0ed..80f4c72ff3edbb9d7625d3edaeffa4b2461e89f0 100644 (file)
     :copyright: 2007 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
-import re
 from compiler import ast, parse
-from compiler.misc import set_filename
 from jinja import nodes
-from jinja.datastructure import TokenStream, StateTest
+from jinja.datastructure import StateTest
 from jinja.exceptions import TemplateSyntaxError
-try:
-    set
-except NameError:
-    from sets import Set as set
+from jinja.utils import set
 
 
 __all__ = ['Parser']
index 8f0e3952b3f2de27f6c8a98430da3b441448d9d5..cdef3a3dfb4dc45fa5ba274b76822587776831f8 100644 (file)
@@ -12,7 +12,6 @@ import re
 
 
 number_re = re.compile(r'^-?\d+(\.\d+)?$')
-
 regex_type = type(number_re)
 
 
index 12a829adf976b82363ae26f540fae294684a6b70..a26299a8f51aa3f2900c6a9ee76a7e81cab5c343 100644 (file)
@@ -43,7 +43,7 @@ from jinja.parser import Parser
 from jinja.exceptions import TemplateSyntaxError
 from jinja.translators import Translator
 from jinja.datastructure import TemplateStream
-from jinja.utils import translate_exception, capture_generator, \
+from jinja.utils import set, translate_exception, capture_generator, \
      RUNTIME_EXCEPTION_OFFSET
 
 
@@ -51,15 +51,9 @@ from jinja.utils import translate_exception, capture_generator, \
 _debug_re = re.compile(r'^\s*\# DEBUG\(filename=(?P<filename>.*?), '
                        r'lineno=(?P<lineno>\d+)\)$')
 
-# For Python2.3 compatibiilty
+# For Python versions without generator exit exceptions
 try:
-    set
-except NameError:
-    from sets import Set as set
-
-# For Python 2.3/2.4 compatibility
-try:
-    GeneratorExit
+    GeneratorExit = GeneratorExit
 except NameError:
     class GeneratorExit(Exception):
         pass
@@ -424,7 +418,6 @@ class PythonTranslator(Translator):
         # handle requirements code
         if requirements:
             requirement_lines = ['def bootstrap(context):']
-            has_requirements = False
             for n in requirements:
                 requirement_lines.append(self.handle_node(n))
             requirement_lines.append('    if 0: yield None\n')
@@ -464,12 +457,6 @@ class PythonTranslator(Translator):
                 self.to_tuple(tmp)
             ))
 
-        # aliases boilerplate
-        aliases = ['%s = environment.%s' % (item, item) for item in
-                   ['get_attribute', 'perform_test', 'apply_filters',
-                    'call_function', 'call_function_simple', 'finish_var',
-                    'undefined_singleton'] if item in self.used_shortcuts]
-
         # bootstrapping code
         lines = ['# Essential imports', 'from __future__ import division']
         if self.used_utils:
index 627498306754cf1d17e74dc53c589bc52867e9b2..410211560004dd2f03f45a1531c25313e6fef1ee 100644 (file)
@@ -17,7 +17,6 @@ import string
 from types import MethodType, FunctionType
 from compiler.ast import CallFunc, Name, Const
 from jinja.nodes import Trans
-from jinja.datastructure import Context
 from jinja.exceptions import SecurityException, TemplateNotFound
 
 # the python2.4 version of deque is missing the remove method
@@ -27,11 +26,34 @@ try:
     from collections import deque
     deque.remove
 except (ImportError, AttributeError):
-    deque = None
+    class deque(list):
+        """
+        Minimal subclass of list that provides the deque
+        interface used by the native `BaseContext` and the
+        `CacheDict`
+        """
+        def appendleft(self, item):
+            list.insert(self, 0, item)
+        def popleft(self):
+            return list.pop(self, 0)
+        def clear(self):
+            del self[:]
+
+# support for a working reversed()
+try:
+    reversed = reversed
+except NameError:
+    def reversed(iterable):
+        if hasattr(iterable, '__reversed__'):
+            return iterable.__reversed__()
+        try:
+            return iter(iterable[::-1])
+        except TypeError:
+            return iter(tuple(iterable)[::-1])
 
 # support for python 2.3/2.4
 try:
-    set
+    set = set
 except NameError:
     from sets import Set as set
 
@@ -276,9 +298,7 @@ def buffereater(f):
     Used by the python translator to capture output of substreams.
     (macros, filter sections etc)
     """
-    def wrapped(*args, **kwargs):
-        return capture_generator(f(*args, **kwargs))
-    return wrapped
+    return lambda *a, **kw: capture_generator(f(*a, **kw))
 
 
 def empty_block(context):
@@ -297,6 +317,8 @@ def fake_template_exception(exception, filename, lineno, source,
     """
     # some traceback systems allow to skip frames
     __traceback_hide__ = True
+
+    from jinja.datastructure import Context
     if isinstance(context_or_env, Context):
         env = context_or_env.environment
         namespace = context_or_env.to_dict()
@@ -541,18 +563,10 @@ class CacheDict(object):
     def __init__(self, capacity):
         self.capacity = capacity
         self._mapping = {}
-
-        # use a deque here if possible
-        if deque is not None:
-            self._queue = deque()
-            self._popleft = self._queue.popleft
-        # python2.3/2.4, just use a list
-        else:
-            self._queue = []
-            pop = self._queue.pop
-            self._popleft = lambda: pop(0)
+        self._queue = deque()
 
         # alias all queue methods for faster lookup
+        self._popleft = self._queue.popleft
         self._pop = self._queue.pop
         self._remove = self._queue.remove
         self._append = self._queue.append
@@ -589,10 +603,7 @@ class CacheDict(object):
         Clear the cache dict.
         """
         self._mapping.clear()
-        try:
-            self._queue.clear()
-        except AttributeError:
-            del self._queue[:]
+        self._queue.clear()
 
     def __contains__(self, key):
         """
@@ -650,10 +661,7 @@ class CacheDict(object):
         Iterate over all values in the cache dict, ordered by
         the most recent usage.
         """
-        try:
-            return reversed(self._queue)
-        except NameError:
-            return iter(self._queue[::-1])
+        return reversed(self._queue)
 
     def __reversed__(self):
         """
diff --git a/scripts/pylintrc b/scripts/pylintrc
new file mode 100644 (file)
index 0000000..4f85b49
--- /dev/null
@@ -0,0 +1,301 @@
+# lint Python modules using external checkers.
+# 
+# This is the main checker controling the other ones and the reports
+# generation. It is itself both a raw checker and an astng checker in order
+# to:
+# * handle message activation / deactivation at the module level
+# * handle some basic but necessary stats'data (number of classes, methods...)
+# 
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Profiled execution.
+profile=no
+
+# Add <file or directory> to the black list. It should be a base name, not a
+# path. You may set this option multiple times.
+ignore=.svn
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Set the cache size for astng objects.
+cache-size=500
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable only checker(s) with the given id(s). This option conflict with the
+# disable-checker option
+#enable-checker=
+
+# Enable all checker(s) except those with the given id(s). This option conflict
+# with the disable-checker option
+#disable-checker=
+
+# Enable all messages in the listed categories.
+#enable-msg-cat=
+
+# Disable all messages in the listed categories.
+#disable-msg-cat=
+
+# Enable the message(s) with the given id(s).
+#enable-msg=
+
+# Disable the message(s) with the given id(s).
+disable-msg=C0323,W0142,C0301,C0103,C0111,E0213,C0302,C0203,W0703,R0201
+
+
+[REPORTS]
+
+# set the output format. Available formats are text, parseable, colorized and
+# html
+output-format=colorized
+
+# Include message's id in output
+include-ids=yes
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells wether to display a full report or only the messages
+reports=yes
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note).You have access to the variables errors warning, statement which
+# respectivly contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (R0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (R0004).
+comment=no
+
+# Enable the report(s) with the given id(s).
+#enable-report=
+
+# Disable the report(s) with the given id(s).
+#disable-report=
+
+
+# checks for
+# * unused variables / imports
+# * undefined variables
+# * redefinition of variable from builtins or from an outer scope
+# * use of variable before assigment
+# 
+[VARIABLES]
+
+# Tells wether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching names used for dummy variables (i.e. not used).
+dummy-variables-rgx=_|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+# try to find bugs in the code using type inference
+# 
+[TYPECHECK]
+
+# Tells wether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# When zope mode is activated, consider the acquired-members option to ignore
+# access to some undefined attributes.
+zope=no
+
+# List of members which are usually get through zope's acquisition mecanism and
+# so shouldn't trigger E0201 when accessed (need zope=yes to be considered).
+acquired-members=REQUEST,acl_users,aq_parent
+
+
+# checks for :
+# * doc strings
+# * modules / classes / functions / methods / arguments / variables name
+# * number of arguments, local variables, branchs, returns and statements in
+# functions, methods
+# * required module attributes
+# * dangerous default values as arguments
+# * redefinition of function / method / class
+# * uses of the global statement
+# 
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# Regular expression which should only match functions or classes name which do
+# not require a docstring
+no-docstring-rgx=__.*__
+
+# Regular expression which should only match correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression which should only match correct module level names
+const-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__))$
+
+# Regular expression which should only match correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression which should only match correct function names
+function-rgx=[a-z_][a-z0-9_]*$
+
+# Regular expression which should only match correct method names
+method-rgx=[a-z_][a-z0-9_]*$
+
+# Regular expression which should only match correct instance attribute names
+attr-rgx=[a-z_][a-z0-9_]*$
+
+# Regular expression which should only match correct argument names
+argument-rgx=[a-z_][a-z0-9_]*$
+
+# Regular expression which should only match correct variable names
+variable-rgx=[a-z_][a-z0-9_]*$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=apply,input
+
+
+# checks for sign of poor/misdesign:
+# * number of methods, attributes, local variables...
+# * size, complexity of functions, methods
+# 
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=12
+
+# Maximum number of locals for function / method body
+max-locals=30
+
+# Maximum number of return / yield for function / method body
+max-returns=12
+
+# Maximum number of branch for function / method body
+max-branchs=30
+
+# Maximum number of statements in function / method body
+max-statements=60
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=20
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=0
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+
+# checks for
+# * external modules dependencies
+# * relative / wildcard imports
+# * cyclic imports
+# * uses of deprecated modules
+# 
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report R0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report R0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report R0402 must
+# not be disabled)
+int-import-graph=
+
+
+# checks for :
+# * methods without self as first argument
+# * overridden methods signature
+# * access only to existant members via self
+# * attributes not defined in the __init__ method
+# * supported interfaces implementation
+# * unreachable code
+# 
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+
+# checks for similarities and duplicated code. This computation may be
+# memory / CPU intensive, so you should disable it if you experiments some
+# problems.
+# 
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=10
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+
+# checks for:
+# * warning notes in the code like FIXME, XXX
+# * PEP 263: source code with non ascii character but no encoding declaration
+# 
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+# checks for :
+# * unauthorized constructions
+# * strict indentation
+# * line length
+# * use of <> instead of !=
+# 
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=90
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '