[PATCH] contrib/setup3k.py: added script to build hg with py3k

Renato Cunha renatoc at gmail.com
Tue Aug 3 11:23:25 CDT 2010


# HG changeset patch
# User Renato Cunha <renatoc at gmail.com>
# Date 1280852296 10800
# Node ID 8149f85e77618efcafdf9f145462af038102e20a
# Parent  12d31028102649cd26c3cca9cd0e2dd6a13370f7
contrib/setup3k.py: added script to build hg with py3k

This patch implements a script that inherits most of its functionality from
hg's setup.py and adds support to calling 2to3 during invocation with python3.
The motivation of having this script around is twofold:

 1) It enables py3k crazies to test mercurial in py3k and, hopefully, patch it
    more easily, so it can improve the py3k support to eventually run there.

 2) Being separated from the main setup.py eliminates the need to make hg's
    setup.py even more cluttered, and enables "independent" development until
    the port is done.

Some considerations about the structure of this patch:

Mercurial already overrides the behavior of build_py, this patch tweaks it a bit
more to add support to call 2to3 with a custom fixer* location for Mercurial.
There is also a need of having the core C modules built *before* the
translation process starts, otherwise 2to3 will think those are global modules.

* A fixer is a python module that transforms python 2.x code in python 3.x
code.

diff --git a/contrib/hgfixes/__init__.py b/contrib/hgfixes/__init__.py
new file mode 100644
diff --git a/setup.py b/contrib/setup3k.py
copy from setup.py
copy to contrib/setup3k.py
--- a/setup.py
+++ b/contrib/setup3k.py
@@ -1,10 +1,13 @@
 #!/usr/bin/env python
 #
-# This is the mercurial setup script.
+# This is a py3k-enabled mercurial setup script.
 #
 # 'python setup.py install', or
 # 'python setup.py --help' for more options
 
+from distutils.command.build_py import build_py_2to3
+from lib2to3.refactor import get_fixers_from_package as getfixers
+
 import sys
 if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
     raise SystemExit("Mercurial requires Python 2.4 or later.")
@@ -218,6 +221,11 @@
 # Insert hgbuildmo first so that files in mercurial/locale/ are found
 # when build_py is run next.
 build.sub_commands.insert(0, ('build_mo', None))
+# We also need build_ext before build_py. Otherwise, when 2to3 is called (in
+# build_py), it will not find osutil & friends, thinking that those modules are
+# global and, consequently, making a mess, now that all module imports are
+# global.
+build.sub_commands.insert(1, ('build_ext', None))
 
 Distribution.pure = 0
 Distribution.global_options.append(('pure', None, "use pure (slow) Python "
@@ -234,7 +242,9 @@
             log.warn("Failed to build optional extension '%s' (skipping)",
                      ext.name)
 
-class hgbuildpy(build_py):
+class hgbuildpy(build_py_2to3):
+    fixer_names = sorted(set(getfixers("lib2to3.fixes") +
+                             getfixers("hgfixes")))
 
     def finalize_options(self):
         build_py.finalize_options(self)
@@ -256,6 +266,27 @@
             else:
                 yield module
 
+    def run(self):
+        # In the build_py_2to3 class, self.updated_files = [], but I couldn't
+        # see when that variable was updated to point to the updated files, as
+        # its names suggests. Thus, I decided to just find_all_modules and feed
+        # them to 2to3. Unfortunately, subsequent calls to setup3k.py will
+        # incur in 2to3 analysis overhead.
+        self.updated_files = [i[2] for i in self.find_all_modules()]
+
+        # Base class code
+        if self.py_modules:
+            self.build_modules()
+        if self.packages:
+            self.build_packages()
+            self.build_package_data()
+
+        # 2to3
+        self.run_2to3(self.updated_files)
+
+        # Remaining base class code
+        self.byte_compile(self.get_outputs(include_bytecode=0))
+
 cmdclass = {'build_mo': hgbuildmo,
             'build_ext': hgbuildext,
             'build_py': hgbuildpy}


More information about the Mercurial-devel mailing list