Commits

DasIch  committed ba13009

Initial cython support

  • Participants
  • Parent commits 79ecde1

Comments (0)

Files changed (5)

 ~$
 ^utils/.*3\.py$
 ^distribute-
+^sphinx/_speedups.c$
 		--cover-package=sphinx $(TEST)
 
 build:
+	@which cython > /dev/null && cython sphinx/_speedups.pyx
 	@$(PYTHON) setup.py build
 
 ifeq ($(PYTHON), python3)
 # -*- coding: utf-8 -*-
 try:
-    from setuptools import setup, find_packages
+    from setuptools import setup, find_packages, Feature, Extension
 except ImportError:
     import distribute_setup
     distribute_setup.use_setuptools()
-    from setuptools import setup, find_packages
+    from setuptools import setup, find_packages, Feature, Extension
 
 import os
 import sys
 from distutils import log
+from distutils.command.build_ext import build_ext
+from distutils.errors import CCompilerError, DistutilsExecError, \
+                             DistutilsPlatformError
 
 import sphinx
 
 
     cmdclass['compile_catalog'] = compile_catalog_plusjs
 
+# compiling the c speedups module if present, this is taken from logbook
+class BuildFailed(Exception):
+    pass
 
-setup(
-    name='Sphinx',
-    version=sphinx.__version__,
-    url='http://sphinx.pocoo.org/',
-    download_url='http://pypi.python.org/pypi/Sphinx',
-    license='BSD',
-    author='Georg Brandl',
-    author_email='georg@python.org',
-    description='Python documentation generator',
-    long_description=long_desc,
-    zip_safe=False,
-    classifiers=[
-        'Development Status :: 5 - Production/Stable',
-        'Environment :: Console',
-        'Environment :: Web Environment',
-        'Intended Audience :: Developers',
-        'Intended Audience :: Education',
-        'License :: OSI Approved :: BSD License',
-        'Operating System :: OS Independent',
-        'Programming Language :: Python',
-        'Programming Language :: Python :: 2',
-        'Topic :: Documentation',
-        'Topic :: Text Processing',
-        'Topic :: Utilities',
-    ],
-    platforms='any',
-    packages=find_packages(),
-    include_package_data=True,
-    entry_points={
-        'console_scripts': [
-            'sphinx-build = sphinx:main',
-            'sphinx-quickstart = sphinx.quickstart:main',
-            'sphinx-autogen = sphinx.ext.autosummary.generate:main',
+
+ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
+if sys.platform == 'win32' and sys.version_info > (2, 6):
+    ext_errors += (IOError,)
+
+
+class ve_build_ext(build_ext):
+    """This class allows C extension building to fail."""
+
+    def run(self):
+        try:
+            build_ext.run(self)
+        except ext_errors:
+            raise BuildFailed()
+
+
+cmdclass['build_ext'] = ve_build_ext
+
+
+if os.path.isfile('sphinx/speedups.c'):
+    speedups = Feature('optional C speed-enhancement module',
+        standard=True,
+        ext_modules=[Extension('sphinx._speedups', ['sphinx/_speedups.c'])]
+    )
+else:
+    speedups = None
+
+def run_setup(with_binary):
+    features = {}
+    if with_binary and speedups is not None:
+        features['speedups'] = speedups
+    setup(
+        name='Sphinx',
+        version=sphinx.__version__,
+        url='http://sphinx.pocoo.org/',
+        download_url='http://pypi.python.org/pypi/Sphinx',
+        license='BSD',
+        author='Georg Brandl',
+        author_email='georg@python.org',
+        description='Python documentation generator',
+        long_description=long_desc,
+        zip_safe=False,
+        classifiers=[
+            'Development Status :: 5 - Production/Stable',
+            'Environment :: Console',
+            'Environment :: Web Environment',
+            'Intended Audience :: Developers',
+            'Intended Audience :: Education',
+            'License :: OSI Approved :: BSD License',
+            'Operating System :: OS Independent',
+            'Programming Language :: Python',
+            'Programming Language :: Python :: 2',
+            'Topic :: Documentation',
+            'Topic :: Text Processing',
+            'Topic :: Utilities',
         ],
-        'distutils.commands': [
-            'build_sphinx = sphinx.setup_command:BuildDoc',
-        ],
-    },
-    install_requires=requires,
-    cmdclass=cmdclass,
-    use_2to3=True,
-    use_2to3_fixers=['custom_fixers'],
-)
+        platforms='any',
+        packages=find_packages(),
+        include_package_data=True,
+        entry_points={
+            'console_scripts': [
+                'sphinx-build = sphinx:main',
+                'sphinx-quickstart = sphinx.quickstart:main',
+                'sphinx-autogen = sphinx.ext.autosummary.generate:main',
+            ],
+            'distutils.commands': [
+                'build_sphinx = sphinx.setup_command:BuildDoc',
+            ],
+        },
+        install_requires=requires,
+        cmdclass=cmdclass,
+        use_2to3=True,
+        use_2to3_fixers=['custom_fixers'],
+        features=features
+    )
+
+
+def echo(msg=''):
+    sys.stdout.write(msg + '\n')
+
+
+try:
+    run_setup(True)
+except BuildFailed:
+    LINE = '=' * 74
+    BUILD_EXT_WARNING = ('WARNING: The C extension could not be compiled, '
+                         'speedups are not enabled.')
+    echo(LINE)
+    echo('Failure information, if any, is above.')
+    echo('Retrying the build without the C extension now.')
+    echo()
+    run_setup(False)
+    echo(LINE)
+    echo(BUILD_EXT_WARNING)
+    echo('Plain-Python installation succeeded.')
+    echo(LINE)

File sphinx/_speedups.pyx

+# -*- coding: utf-8 -*-
+"""
+    sphinx._speedups
+    ~~~~~~~~~~~~~~~~
+
+    Fast Cython implementations.
+
+    :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+cdef VERSIONING_RATIO = 65
+
+
+def get_ratio(unicode old, unicode new):
+    return levenshtein_distance(old, new) / len(old) / 100.0
+
+
+cdef levenshtein_distance(unicode a, unicode b):
+    # TODO: this algorithm is very primitive and totally slow compared to how
+    #       it could be using C types, however i wanted something working first
+    cdef list previous_row, current_row
+    cdef int insertions, deletions, substitutions
+    if a == b:
+        return 0
+    if len(a) < len(b):
+        a, b = b, a
+    if not a:
+        return len(b)
+    previous_row = range(len(b) + 1)
+    for i, column1 in enumerate(a):
+        current_row = [i + 1]
+        for j, column2 in enumerate(b):
+            insertions = previous_row[j + 1] + 1
+            deletions = current_row[j] + 1
+            substitutions = previous_row[j] + (column1 != column2)
+            current_row.append(min(insertions, deletions, substitutions))
+        previous_row = current_row
+    return previous_row[-1]

File sphinx/versioning.py

     """Return a "similiarity ratio" (in percent) representing the similarity
     between the two strings where 0 is equal and anything above less than equal.
     """
+    # if you change the implementation make sure to change _speedups.pyx as well
     if not all([old, new]):
         return VERSIONING_RATIO
     return levenshtein_distance(old, new) / (len(old) / 100.0)
 
 def levenshtein_distance(a, b):
     """Return the Levenshtein edit distance between two strings *a* and *b*."""
+    # if you change the implementation make sure to change _speedups.pyx as well
     if a == b:
         return 0
     if len(a) < len(b):
         a, b = b, a
     if not a:
         return len(b)
-    previous_row = xrange(len(b) + 1)
+    previous_row = range(len(b) + 1)
     for i, column1 in enumerate(a):
         current_row = [i + 1]
         for j, column2 in enumerate(b):
             current_row.append(min(insertions, deletions, substitutions))
         previous_row = current_row
     return previous_row[-1]
+
+try:
+    from sphinx._speedups import get_ratio, levenshtein_distance
+except ImportError:
+    pass