Commits

Ilia Choly  committed 9b9740b

refactored formatter mapping.

  • Participants
  • Parent commits 5cc9495

Comments (0)

Files changed (2)

File pygments/formatters/__init__.py

     :copyright: Copyright 2006-2012 by the Pygments team, see AUTHORS.
     :license: BSD, see LICENSE for details.
 """
-import os.path
 import fnmatch
+import sys
+import types
+from os.path import basename
 
 from pygments.formatters._mapping import FORMATTERS
 from pygments.plugin import find_plugin_formatters
 from pygments.util import ClassNotFound
 
-ns = globals()
-for fcls in FORMATTERS:
-    ns[fcls.__name__] = fcls
-del fcls
+__all__ = ['get_formatter_by_name', 'get_formatter_for_filename',
+           'get_all_formatters'] + FORMATTERS.keys()
 
-__all__ = ['get_formatter_by_name', 'get_formatter_for_filename',
-           'get_all_formatters'] + [cls.__name__ for cls in FORMATTERS]
+_formatter_cache = {}
 
+def _load_formatters(module_name):
+    """
+    Load a formatter (and all others in the module too).
+    """
+    mod = __import__(module_name, None, None, ['__all__'])
+    for formatter_name in mod.__all__:
+        cls = getattr(mod, formatter_name)
+        _formatter_cache[cls.name] = cls
 
-_formatter_alias_cache = {}
-_formatter_filename_cache = []
+def get_all_formatters():
+    """
+    Return a generator of all know formatters.
+    """
+    for item in FORMATTERS.itervalues():
+        yield item[1:]
+    for _, formatter in find_plugin_formatters():
+        yield formatter
 
-def _init_formatter_cache():
-    if _formatter_alias_cache:
-        return
-    for cls in get_all_formatters():
-        for alias in cls.aliases:
-            _formatter_alias_cache[alias] = cls
-        for fn in cls.filenames:
-            _formatter_filename_cache.append((fn, cls))
 
+def get_formatter_by_name(_alias, **options):
+    """
+    Get a formatter by an alias.
+    """
+    # lookup builtin formatters
+    for module_name, name, aliases, _, _ in FORMATTERS.itervalues():
+        if _alias in aliases:
+            if name not in _formatter_cache:
+                _load_formatters(module_name)
+            return _formatter_cache[name](**options)
+    # continue with formatters from setuptools entrypoints
+    for _, cls in find_plugin_formatters():
+        if _alias in cls.aliases:
+            return cls(**options)
+    raise ClassNotFound('no formatter for alias %r found' % _alias)
 
-def find_formatter_class(name):
-    _init_formatter_cache()
-    cls = _formatter_alias_cache.get(name, None)
-    return cls
-
-
-def get_formatter_by_name(name, **options):
-    _init_formatter_cache()
-    cls = _formatter_alias_cache.get(name, None)
-    if not cls:
-        raise ClassNotFound("No formatter found for name %r" % name)
-    return cls(**options)
-
-
-def get_formatter_for_filename(fn, **options):
-    _init_formatter_cache()
-    fn = os.path.basename(fn)
-    for pattern, cls in _formatter_filename_cache:
-        if fnmatch.fnmatch(fn, pattern):
-            return cls(**options)
+def get_formatter_for_filename(_fn, **options):
+    """
+    Get a formatter for a filename.
+    """
+    matches = []
+    fn = basename(_fn)
+    print fn
+    for modname, name, _, filenames, _ in FORMATTERS.itervalues():
+        for filename in filenames:
+            if fnmatch.fnmatch(fn, filename):
+                if name not in _formatter_cache:
+                    _load_formatters(modname)
+                return _formatter_cache[name]
+    for _, cls in find_plugin_formatters():
+        for filename in cls.filenames:
+            if fnmatch.fnmatch(fn, filename):
+                return cls
     raise ClassNotFound("No formatter found for file name %r" % fn)
 
+class _automodule(types.ModuleType):
+    """Automatically import formatters."""
 
-def get_all_formatters():
-    """Return a generator for all formatters."""
-    for formatter in FORMATTERS:
-        yield formatter
-    for _, formatter in find_plugin_formatters():
-        yield formatter
+    def __getattr__(self, name):
+        info = FORMATTERS.get(name)
+        if info:
+            _load_formatters(info[0])
+            cls = _formatter_cache[info[1]]
+            setattr(self, name, cls)
+            return cls
+        raise AttributeError(name)
+
+
+oldmod = sys.modules['pygments.formatters']
+newmod = _automodule('pygments.formatter')
+newmod.__dict__.update(oldmod.__dict__)
+sys.modules['pygments.formatters'] = newmod
+del newmod.newmod, newmod.oldmod, newmod.sys, newmod.types

File pygments/formatters/_mapping.py

     :license: BSD, see LICENSE for details.
 """
 
-from pygments.util import docstring_headline
 
 # start
-from pygments.formatters.bbcode import BBCodeFormatter
-from pygments.formatters.html import HtmlFormatter
-from pygments.formatters.img import BmpImageFormatter
-from pygments.formatters.img import GifImageFormatter
-from pygments.formatters.img import ImageFormatter
-from pygments.formatters.img import JpgImageFormatter
-from pygments.formatters.latex import LatexFormatter
-from pygments.formatters.other import NullFormatter
-from pygments.formatters.other import RawTokenFormatter
-from pygments.formatters.rtf import RtfFormatter
-from pygments.formatters.svg import SvgFormatter
-from pygments.formatters.terminal import TerminalFormatter
-from pygments.formatters.terminal256 import Terminal256Formatter
-
 FORMATTERS = {
-    BBCodeFormatter: ('BBCode', ('bbcode', 'bb'), (), 'Format tokens with BBcodes. These formatting codes are used by many bulletin boards, so you can highlight your sourcecode with pygments before posting it there.'),
-    BmpImageFormatter: ('img_bmp', ('bmp', 'bitmap'), ('*.bmp',), 'Create a bitmap image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
-    GifImageFormatter: ('img_gif', ('gif',), ('*.gif',), 'Create a GIF image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
-    HtmlFormatter: ('HTML', ('html',), ('*.html', '*.htm'), "Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass` option."),
-    ImageFormatter: ('img', ('img', 'IMG', 'png'), ('*.png',), 'Create a PNG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
-    JpgImageFormatter: ('img_jpg', ('jpg', 'jpeg'), ('*.jpg',), 'Create a JPEG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
-    LatexFormatter: ('LaTeX', ('latex', 'tex'), ('*.tex',), 'Format tokens as LaTeX code. This needs the `fancyvrb` and `color` standard packages.'),
-    NullFormatter: ('Text only', ('text', 'null'), ('*.txt',), 'Output the text unchanged without any formatting.'),
-    RawTokenFormatter: ('Raw tokens', ('raw', 'tokens'), ('*.raw',), 'Format tokens as a raw representation for storing token streams.'),
-    RtfFormatter: ('RTF', ('rtf',), ('*.rtf',), 'Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft\xc2\xae Word\xc2\xae documents.'),
-    SvgFormatter: ('SVG', ('svg',), ('*.svg',), 'Format tokens as an SVG graphics file.  This formatter is still experimental. Each line of code is a ``<text>`` element with explicit ``x`` and ``y`` coordinates containing ``<tspan>`` elements with the individual token styles.'),
-    Terminal256Formatter: ('Terminal256', ('terminal256', 'console256', '256'), (), 'Format tokens with ANSI color sequences, for output in a 256-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'),
-    TerminalFormatter: ('Terminal', ('terminal', 'console'), (), 'Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly.')
+    'BBCodeFormatter': ('pygments.formatters.bbcode', 'BBCode', ('bbcode', 'bb'), (), 'Format tokens with BBcodes. These formatting codes are used by many bulletin boards, so you can highlight your sourcecode with pygments before posting it there.'),
+    'BmpImageFormatter': ('pygments.formatters.img', 'img_bmp', ('bmp', 'bitmap'), ('*.bmp',), 'Create a bitmap image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
+    'GifImageFormatter': ('pygments.formatters.img', 'img_gif', ('gif',), ('*.gif',), 'Create a GIF image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
+    'HtmlFormatter': ('pygments.formatters.html', 'HTML', ('html',), ('*.html', '*.htm'), "Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass` option."),
+    'ImageFormatter': ('pygments.formatters.img', 'img', ('img', 'IMG', 'png'), ('*.png',), 'Create a PNG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
+    'JpgImageFormatter': ('pygments.formatters.img', 'img_jpg', ('jpg', 'jpeg'), ('*.jpg',), 'Create a JPEG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
+    'LatexFormatter': ('pygments.formatters.latex', 'LaTeX', ('latex', 'tex'), ('*.tex',), 'Format tokens as LaTeX code. This needs the `fancyvrb` and `color` standard packages.'),
+    'NullFormatter': ('pygments.formatters.other', 'Text only', ('text', 'null'), ('*.txt',), 'Output the text unchanged without any formatting.'),
+    'RawTokenFormatter': ('pygments.formatters.other', 'Raw tokens', ('raw', 'tokens'), ('*.raw',), 'Format tokens as a raw representation for storing token streams.'),
+    'RtfFormatter': ('pygments.formatters.rtf', 'RTF', ('rtf',), ('*.rtf',), 'Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft\xc2\xae Word\xc2\xae documents.'),
+    'SvgFormatter': ('pygments.formatters.svg', 'SVG', ('svg',), ('*.svg',), 'Format tokens as an SVG graphics file.  This formatter is still experimental. Each line of code is a ``<text>`` element with explicit ``x`` and ``y`` coordinates containing ``<tspan>`` elements with the individual token styles.'),
+    'Terminal256Formatter': ('pygments.formatters.terminal256', 'Terminal256', ('terminal256', 'console256', '256'), (), 'Format tokens with ANSI color sequences, for output in a 256-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'),
+    'TerminalFormatter': ('pygments.formatters.terminal', 'Terminal', ('terminal', 'console'), (), 'Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly.')
 }
 
 if __name__ == '__main__':
     import sys
     import os
 
+    sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
+
+    from pygments.util import docstring_headline
+
     # lookup formatters
     found_formatters = []
-    imports = []
-    sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
     for filename in os.listdir('.'):
         if filename.endswith('.py') and not filename.startswith('_'):
             module_name = 'pygments.formatters.%s' % filename[:-3]
             print module_name
             module = __import__(module_name, None, None, [''])
             for formatter_name in module.__all__:
-                imports.append((module_name, formatter_name))
                 formatter = getattr(module, formatter_name)
                 found_formatters.append(
-                    '%s: %r' % (formatter_name,
-                                (formatter.name,
+                    '%r: %r' % (formatter_name,
+                                (module_name,
+                                 formatter.name,
                                  tuple(formatter.aliases),
                                  tuple(formatter.filenames),
                                  docstring_headline(formatter))))
     # sort them, that should make the diff files for svn smaller
     found_formatters.sort()
-    imports.sort()
 
     # extract useful sourcecode from this file
     f = open(__file__)
     f = open(__file__, 'w')
     f.write(header)
     f.write('# start\n')
-    f.write('\n'.join(['from %s import %s' % imp for imp in imports]))
-    f.write('\n\n')
     f.write('FORMATTERS = {\n    %s\n}\n\n' % ',\n    '.join(found_formatters))
     f.write(footer)
     f.close()