===================================================== Supporting both Python 2 and Python 3 with Setuptools ===================================================== Starting with Distribute version 0.6.2 and Setuptools 0.7, the Setuptools project supported Python 3. Installing and using setuptools for Python 3 code works exactly the same as for Python 2 code, but Setuptools also helps you to support Python 2 and Python 3 from the same source code by letting you run 2to3 on the code as a part of the build process, by setting the keyword parameter ``use_2to3`` to True. Setuptools as help during porting ================================= Setuptools can make the porting process much easier by automatically running 2to3 as a part of the test running. To do this you need to configure the setup.py so that you can run the unit tests with ``python setup.py test``. See :ref:`test` for more information on this. Once you have the tests running under Python 2, you can add the use_2to3 keyword parameters to setup(), and start running the tests under Python 3. The test command will now first run the build command during which the code will be converted with 2to3, and the tests will then be run from the build directory, as opposed from the source directory as is normally done. Setuptools will convert all Python files, and also all doctests in Python files. However, if you have doctests located in separate text files, these will not automatically be converted. By adding them to the ``convert_2to3_doctests`` keyword parameter Setuptools will convert them as well. By default, the conversion uses all fixers in the ``lib2to3.fixers`` package. To use additional fixers, the parameter ``use_2to3_fixers`` can be set to a list of names of packages containing fixers. To exclude fixers, the parameter ``use_2to3_exclude_fixers`` can be set to fixer names to be skipped. A typical setup.py can look something like this:: from setuptools import setup setup( name='your.module', version = '1.0', description='This is your awesome module', author='You', author_email='your@email', package_dir = {'': 'src'}, packages = ['your', 'you.module'], test_suite = 'your.module.tests', use_2to3 = True, convert_2to3_doctests = ['src/your/module/README.txt'], use_2to3_fixers = ['your.fixers'], use_2to3_exclude_fixers = ['lib2to3.fixes.fix_import'], ) Differential conversion ----------------------- Note that a file will only be copied and converted during the build process if the source file has been changed. If you add a file to the doctests that should be converted, it will not be converted the next time you run the tests, since it hasn't been modified. You need to remove it from the build directory. Also if you run the build, install or test commands before adding the use_2to3 parameter, you will have to remove the build directory before you run the test command, as the files otherwise will seem updated, and no conversion will happen. In general, if code doesn't seem to be converted, deleting the build directory and trying again is a good saferguard against the build directory getting "out of sync" with the source directory. Distributing Python 3 modules ============================= You can distribute your modules with Python 3 support in different ways. A normal source distribution will work, but can be slow in installing, as the 2to3 process will be run during the install. But you can also distribute the module in binary format, such as a binary egg. That egg will contain the already converted code, and hence no 2to3 conversion is needed during install. Advanced features ================= If you don't want to run the 2to3 conversion on the doctests in Python files, you can turn that off by setting ``setuptools.use_2to3_on_doctests = False``. Note on compatibility with older versions of setuptools ======================================================= Setuptools earlier than 0.7 does not know about the new keyword parameters to support Python 3. As a result it will warn about the unknown keyword parameters if you use those versions of setuptools instead of Distribute under Python 2. This output is not an error, and install process will continue as normal, but if you want to get rid of that error this is easy. Simply conditionally add the new parameters into an extra dict and pass that dict into setup():: from setuptools import setup import sys extra = {} if sys.version_info >= (3,): extra['use_2to3'] = True extra['convert_2to3_doctests'] = ['src/your/module/README.txt'] extra['use_2to3_fixers'] = ['your.fixers'] setup( name='your.module', version = '1.0', description='This is your awesome module', author='You', author_email='your@email', package_dir = {'': 'src'}, packages = ['your', 'you.module'], test_suite = 'your.module.tests', **extra ) This way the parameters will only be used under Python 3, where Distribute or Setuptools 0.7 or later is required.