Experimental Python interpreter snap

James Henstridge james.henstridge at canonical.com
Mon Feb 20 04:09:11 UTC 2017


On 20 February 2017 at 10:41, Spencer <spencertparkin at gmail.com> wrote:
> I thought a main feature of snaps was to include all dependencies so that they couldn't be changed out from underneath a package.  For example, my script was written for 3.6, but would be incompatible with a future release, say 4.0.

I've included two content interface slots on my snap: one with the
content ID "python3" and the other with the content ID "python3.6".
The idea being that a program that doesn't care about getting new
versions (e.g. my trivial hello world snap) could use the first, while
ones that really want python 3.6.x (e.g. if they contain compiled
extensions) could request the second.

I don't think there is any point in distinguishing micro releases
though, since the Python core developers have a good track record when
it comes to releasing security/bug fix updates to their previous
releases.


> Still, the ability to share a dependency like the Python interpreter among python snaps may be a good idea if there are zillions of Python snaps.
>
> At my work, we got tired of everyone maintaining their own local python installation, because we all ended up with slightly different versions of various python modules installed.  Worse, some modules installed for some while not for others.  So we started tracking a shared Python installation in git.  One problem we found is that Python is not relocatable.  This showed up when people cloned our repository in a different place.  Are you sure that your snapped Python is relocatable?  If so, I'd like to know how that works.  Is the $ORIGIN variable standard?

Note that the the only things being shared here is the Python
interpreter and the standard library.  If one snap includes a bunch of
third party Python packages in their $SNAP/lib/python3.6/site-packages
directory, they won't be visible to a second snap that has also used
the interface.  The effect is quite similar to the isolation you get
from virtualenv.

As far as relocatability goes, part of it is provided by Python
proper.  Here's sys.path from the interpreter provided by the
python36-jamesh snap:

    $ python36-jamesh.python3
    Python 3.6.0 (default, Feb 20 2017, 01:27:20)
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>> sys.path
    ['', '/snap/python36-jamesh/7/lib/python36.zip',
'/snap/python36-jamesh/7/lib/python3.6',
'/snap/python36-jamesh/7/lib/python3.6/lib-dynload']

And here it is when running in the context of my hello-world snap:

    $ snap run --shell hello-world
    To run a command as administrator (user "root"), use "sudo <command>".
    See "man sudo_root" for details.

    $ $SNAP/python/bin/python3
    Python 3.6.0 (default, Feb 20 2017, 01:27:20)
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>> sys.path
    ['', '/snap/hello-world/x1/python/lib/python36.zip',
'/snap/hello-world/x1/python/lib/python3.6',
'/snap/hello-world/x1/python/lib/python3.6/lib-dynload']

What I added was configuring DT_RUNPATH for the executable and
extensions.  This augments the set of directories the dynamic linker
searches for shared library dependencies.  If a directory in this list
contains the token "$ORIGIN", it will be expanded to the the directory
containing the program or library.  So by including "$ORIGIN/../lib"
in the runpath for bin/python3.6, I can make sure it will find the
libpython in the directory next to it, no matter where it happens to
be bind mounted.  You can find more information about this in the
ld.so(8) man page.

James.




More information about the Snapcraft mailing list