Python site package script as command

I’ve been working through trying to get my Python 3.6 application which has a command-line interface to be packaged with Snap. I’ve managed to solve most problems through a combination of the documentation and brute force. However, I think I am stuck on the last hurdle.

I’ve managed to install both Python 3.6 and then my application using parts. But my apps command appears to be isolated from the build parts so I’m unable to get the command to call my python program.

As I understand it the final build will not contain any of the things created in the parts and I need to specify what I want to bring over (using things like prime). However, I can’t seem to figure out exactly how.

Here’s what I have currently:

name: mzo
version: '0.0.1'
summary: my summary
description: |
  My description.

grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots

apps:
  mzo:
    command: /usr/local/bin/mzo
    plugs: [network, network-bind]

parts:
  python36:
    plugin: nil
    stage-packages:
      - make
      - zlib1g-dev
      - openssl
      - libssl-dev
      - libffi-dev
    source: https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz
    source-checksum: md5/9f49654a4d6f733ff3284ab9d227e9fd
    override-build: |
      ./configure --enable-optimizations
      make
      sudo make install
  mzo:
    after: [python36]
    plugin: nil
    source: https://github.com/jamesstidard/Mzo-Cli/archive/v0.0.5.tar.gz
    source-checksum: sha256/ad70091661bc3bf920022b59423999d82c7f050338832f14c84a3044a431d48c
    override-build: |
      /usr/local/bin/python3 -m pip install --upgrade pip wheel setuptools pipenv
      pipenv lock --requirements > requirements.txt
      /usr/local/bin/python3 -m pip install -r requirements.txt

Any pointers would be very much appreciated; I’m not getting very far very fast.

Thanks

The command must not be anchored to the root directory because that will be outside of your snap’s readable filesystem. If you install your mzo into your snap at usr/local/bin/mzo then you may reference it as:

apps:
  mzo:
    command: usr/local/bin/mzo

Note that this will be in your snap’s filesystem, such that when you run it the command will expand to $SNAP/usr/local/bin/mzo where $SNAP points into your snap.

Here you’re running commands outside of the snap build directory, so the resulting files will not be added into your snap. You need to use the python plugin and the requirements: key to install the requirements and your application into $SNAPCRAFT_PART_INSTALL. From there snapcraft will copy the files into $SNAPCRAFT_STAGE followed by ./prime before finally packaging the ./prime directory into a .snap file:

parts:
  mzo:
    plugin: python
    python-version: python3
    source: https://github.com/jamesstidard/Mzo-Cli/archive/v0.0.5.tar.gz
    requirements: requirements.txt

You can generate the requirements.txt using the method you already are if you do not include it directly in the download and then call back into snapcraft to run the build:

    override-build: |
      pipenv lock --requirements > requirements.txt
      snapcraftctl build

Even better would be to generate the requirements.txt at pull so that snapcraft can discover it before running the build:

    override-pull: |
      snapcraftctl pull
      pipenv lock --requirements > requirements.txt

Hi @lucyllewy, really appreciate the help and the detail. I will give this a shot this evening.

I am building Python 3.6 and not using the Python plugin as my code has some 3.6 specific syntax and I believe the plugin currently only supports 2.7.x and 3.5.x.

If I want to use 3.6 should I then be installing python to somewhere like $SNAPCRAFT_PART_INSTALL/python. Or maybe it is easier to fork the existing Python plugin and edit it to use 3.6.

Thanks again.

You could wait till building against core18 works out of the box, but I’m not sure how far away that is yet…

Alternatively, your theory about using a modified plugin is actually a good one. The process to do so is to find the snapcraft plugin’s source (if you installed snapcraft as a snap then it’s at less /snap/snapcraft/current/lib/python3.5/site-packages/snapcraft/plugins/python.py) and copy that into your project so that it is inside a directory called plugins, which sits alongside your snapcraft.yaml:

project/
  - snap/
    - plugins/
      - x-python.py
    - snapcraft.yaml

Here I’ve called the plugin x-python so that is the name you need to use in your snapcraft.yaml instead of python - this is to prevent undefined behaviour where the python plugin might exist in two places.