Commit 2ce96a76 authored by Kirill Smelkov's avatar Kirill Smelkov

Fix develop install for setuptools >= 19.4

Starting from setuptools 19.4, more concrete from the following commit:

    https://github.com/pypa/setuptools/commit/ebc54982

setuptools sorts namespaced packages .__path__ to be in sync with sys.path .
That however breaks for wendelin.core used from in-tree or installed in
development mode, because we are doing tricks in top-level import redirector
(see e870781d "Top-level in-tree import redirector"):

    (z+numpy.v2)kirr@teco:~/tmp/trashme/wendelin.core$ python -c 'import wendelin'
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "wendelin.py", line 39, in <module>
        __import__('pkg_resources').declare_namespace(__name__)
      File "/home/kirr/src/wendelin/venv/z+numpy.v2/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2081, in declare_namespace
        _handle_ns(packageName, path_item)
      File "/home/kirr/src/wendelin/venv/z+numpy.v2/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2026, in _handle_ns
        _rebuild_mod_path(path, packageName, module)
      File "/home/kirr/src/wendelin/venv/z+numpy.v2/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2050, in _rebuild_mod_path
        orig_path.sort(key=position_in_sys_path)
      File "/home/kirr/src/wendelin/venv/z+numpy.v2/local/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2045, in position_in_sys_path
        return sys_path.index(_normalize_cached(os.sep.join(parts)))
    ValueError: '/home/kirr/tmp/trashme' is not in list

Here wendelin.py added /home/kirr/tmp/trashme/wendelin.core to .__path__ and
setuptools' _handle_ns() wants to order that dir's parent in correspondence
with sys.path, but parent path is not there - oops.

We can workaround the problem, by first not initializing .__path__ and letting

    __import__('pkg_resources').declare_namespace(__name__)

fully handle and initialize it, and only after it is done we make the
correction for wendelin modules located not under .../wendelin.core/wendelin/
but under .../wendelin.core/ .

Importing was tested to work with the fix with both setuptools 20.6.7 and older
setuptools 17.1.1, i.e. here we should not be breaking backward compatibility.

/reported-by @tatuya, @Camata, @Tyagov

/reviewed-on kirr/wendelin.core!1
parent 2ca0f076
......@@ -28,24 +28,39 @@
# see https://www.python.org/doc/essays/packages/ about __path__
# XXX avoid being imported twice, e.g. `import wendelin.wendelin` should not work.
from os.path import dirname, realpath
__path__ = [realpath(dirname(__file__))]
del dirname, realpath
# first make sure setuptools will recognize wendelin.py as package,
# but do not setup proper __path__ yet.
# ( _handle_ns() checks for __path__ attribute presence and refuses to further
# process "not a package"
#
# https://github.com/pypa/setuptools/blob/9803058d/pkg_resources/__init__.py#L2012 )
__path__ = []
# Also tell setuptools/pkg_resources 'wendelin' is a namespace package
# tell setuptools/pkg_resources 'wendelin' is a namespace package
# ( so that wendelin.core installed in development mode does not brake
# 'wendelin' namespacing wrt other wendelin software )
__import__('pkg_resources').declare_namespace(__name__)
# pkg_resources will append '.../wendelin' to __path__ which is not right for
# in-tree setup and thus is not needed here. Remove it.
del __path__[1:]
# pkg_resources will append '.../wendelin.core/wendelin' to __path__ which is
# not right for in-tree setup and thus needs to be corrected:
# Rewrite '.../wendelin.core/wendelin' -> '.../wendelin.core'
from os.path import dirname, realpath, splitext
myfile = realpath(__file__)
mymod = splitext(myfile)[0] # .../wendelin.py -> .../wendelin
mydir = dirname(myfile) # .../wendelin -> ...
i = None # in case vvv loop is empty, so we still can `del i` in the end
for i in range(len(__path__)):
# NOTE realpath(...) for earlier setuptools, where __path__ entry could be
# added as relative
if realpath(__path__[i]) == mymod:
__path__[i] = mydir
del dirname, realpath, splitext, myfile, mymod, mydir, i
# in the end we have:
# __path__ has 1 item
# __path__[0] points to working tree
# __path__ has >= 1 items
# __path__ entry for wendelin.core points to top of working tree
# __name__ registered as namespace package
#
# so the following should work:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment