os icon indicating copy to clipboard operation
os copied to clipboard

testing python is too hard / cannot use 'python3' / python transition will cause problems

Open smoser opened this issue 1 year ago • 1 comments

Because we have multiple pythons and we want them to be co-installable, we have packages like:

  1. python-3.12-base
  2. python-3.12
  3. python-3.11-base
  4. python-3.11

The -base package provides basically everything and the python-3.11 package provides a symlink making 'python3' default to python 3.11 ( /usr/bin/python3 -> python3.11)

When we build packages, melange correctly identifies that a package that installs python files into /usr/lib/python3.12/site-packages/ depends on python-3.12-base. It does not depend on python-3.12 (it never uses that symlink. even the installed scripts have /usr/bin/python3.12).

The pipeline 'python/imports' pipeline takes a 'python' input, but if it is not provided it will use a shell snippet to find the right one (if there is only one installed).

That works well for the imports pipeline.

The problem is that anything that wants to run 'python3' in a test has to have a similar snippet of code.

Consider py3-async-generator.yaml.

It looks like this:

package:
  name: py3-async-generator
  version: 1.10
  epoch: 1
  description: Async generators and context managers for Python 3.5+
  copyright:
    - license: MIT OR Apache-2.0
  dependencies:
    runtime:
      - python-3
...
test:
  environment:
    contents:
      packages:
        - python-3
  pipeline:
    - runs: |
        python -c "import async_generator; print(async_generator.__version__)"

Two things to call out there

  1. It has 'python-3' as a runtime dep. The package built today will have the python-3.12 dep written by melange but will also have python-3 dep. In the future, when python-3.13 exists, python-3.13 will also provide python-3 and will be preferred to python-3.12. So installation of this package would install 2 python versions. Yikes.
  2. It includes python-3 in the test environment in order to get a python program to execute. But similarly to 1, that will install the wrong python in the future, and the test will begin to fail (it works today, but as soon as there is a python-3 package it will fail).

So, how should that test look? Do we have to copy a shell snippet like this:

python=$(m=/usr/bin/python3.*; set +x; set -- $m
    [ $# -eq 1 -a -x "$1" ] && echo "$1" && exit 0
    echo "found $# matches to $m"; exit 1;)
$python -c '...'

smoser avatar Aug 21 '24 14:08 smoser

Here is one thought, in py3-pendelum.yaml. Similar to the multi-version building, we use a var and manually have to change that. Things to note:

  • right now py3-typing does not provide py3.12-typing , as it just builds a single python version. Note below that this is providing py3.12-pendulum via 'provides'
  • The test can directly execute python${{vars.pyver}} which be changed by an external factor such as availabitly of python 3.13
package:
  name: py3-pendulum
  version: 3.0.0
  epoch: 1
  description: Python datetimes made easy
  copyright:
    - license: MIT
  dependencies:
    runtime:
      - py${{vars.pyver}}-dateutil
      - py${{vars.pyver}}-tzdata
      - py3-typing
    provides:
      - py${{vars.pyver}}-pendulum

vars:
  pyver: "3.12"

environment:
  contents:
    packages:
      - build-base
      - busybox
      - ca-certificates-bundle
      - py${{vars.pyver}}-maturin-bin
      - py${{vars.pyver}}-pip
      - py${{vars.pyver}}-wheel
      - python-${{vars.pyver}}
      - python-${{vars.pyver}}-dev
      - rust
      - wolfi-base

pipeline:
  - uses: git-checkout
    with:
      repository: https://github.com/sdispater/pendulum
      tag: ${{package.version}}
      expected-commit: 0fcd10217af0469b3edda072f2b152d5273f3d58

  - uses: py/pip-build-install

test:
  pipeline:
    - uses: python/import
      with:
        imports: |
          import pendulum
    - runs: |
        # test verifies that timezone data is present.
        python${{vars.pyver}} -c '
        from pendulum import datetime
        tor = datetime(2012, 1, 1, tz="America/Toronto")
        van = datetime(2012, 1, 1, tz="America/Vancouver")
        assert 3 == van.diff(tor).in_hours()
        print("PASS: time zones check out")
        '

smoser avatar Aug 21 '24 18:08 smoser

I'm going to close this. the py/one-python really helps and most things being multi-versioned helps.

smoser avatar Nov 07 '24 17:11 smoser