I have a project which runs on both Python 2 and 3, however not every dependency also runs on both Python versions. But my problem is with the installation stage, rather than the runtime, because it can always check and tell users that certain dependency isn’t supported since he or she is running with Python 3.

The installation stage is a bit of an issue for me, you can see the problem from the following pip installation command:

$ pip-python3.2 install --user --upgrade dist/b.py-0.6.2.tar.gz
[snip]
  Running setup.py install for b.py
    changing mode of build/scripts-3.2/b.py from 644 to 755
      File "/home/livibetter/.local/lib64/python3.2/site-packages/bpy/api/asciidocapi.py", line 246
        except SystemExit, e:
                         ^
    SyntaxError: invalid syntax
[snip]

Note that this doesn’t stop the installation process, the installation is still completed nonetheless.

When installing a package or module, at least with distutils, those will be compiled into bytecode automatically and that is the problem for the project. There is a simple way to skip that step, that’s to set sys.dont_write_bytecode = True, but I don’t like this workaround.

The asciidocapi.py is copied from asciidoc, which is Python 2 only. For some reason, Gentoo doesn’t install that, therefore I assume some distributions’ packages also don’t install that module. So, I must ship it with my project source, and that means the syntax error message. If asciidoc installed the API module, then I can get away from this syntax error and don’t even have to put the module wihtin my source distribution.

I have been aware of the error for a while, but never could think of a good solution. One candidate solution I have come up with is to skip installing the problematic file in setup.py:

if sys.version_info >= (3, ):
  from distutils.command.build_py import build_py

  _build_module = build_py.build_module

  def build_module(self, module, module_file, package):

    if 'asciidoc' in module:
      return None, None
    return _build_module(self, module, module_file, package)

  build_py.build_module = build_module

Or, you can use distutils’ use2to3, but that option seems to be setup.py-wide, meaning it would also try to work on scripts which already run on both Python versions.

By monkey patching build_py.build_module, any module with asciidoc in its name would be skipped, they wouldn’t be installed. Therefore, no bytecode compilation on them since there are not on the list.

An important note is I have also tried to patch build_py.byte_compile. But even though the file is removed from the list, there is some piece of code still compiling it from installed place which I can’t find the source. That is the reason I patched build_module.

In the end, I didn’t use this, because this is not a solution I was looking for. Of course, you can extend build_py command class and make it accept new option, say exclude. But still, not looking forward to such way, just to get around the syntax error.

There might be some standard options of distutils can somehow get around without tinkering code of distutils. Nevertheless, the real, acceptable solution for me is to make asciidoc compatible with Python 3. But that seems to require a lot of work. Certainly, I could just fix asciidocapi.py in my project, but I rather not to edit that file, and to keep the original code and that syntax error. Yes, that’s a sort-of-error during installation process, but it doesn’t actually stop the installation.

Still, the code may help anyone who wants to intercept module building for whatever reason.