How to install aย specific Python version on Linux

Hello, ๐Ÿ‘‹

In this article I will show you how to install Python versions on Linux using the following methods: compiling from source, dead snakes ppa and pyenv.

To make things easier, if you want to follow along in an environment that you can break, you can create a local Kubernetes cluster using Minikube.

Next, I’m going to use the following yaml file to create an Ubuntu pod:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
  labels:
    app: ubuntu
spec:
  containers:
  - image: ubuntu
    command:
      - "sleep"
      - "604800"
    imagePullPolicy: IfNotPresent
    name: ubuntu
  restartPolicy: Always

Save the above yaml in a file ubuntu_pod.yaml and run:

kubectl apply -f ./ubuntu_pod.yaml

To get a shell on the Ubuntu pod, run:

kubectl exec -it ubuntu -- /bin/bash

To start from scratch, simply delete the pod with kubectl delete pod/ubuntu and then recreate it.

Compiling Python from source

Before compiling Python, you will need to setup the build environment, thankfully, it is straightforward.

Pyenv has great instructions on it: https://github.com/pyenv/pyenv/wiki#suggested-build-environment.

On Ubuntu, to build Python, install the following packages:

apt-get update; apt-get install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

Then, search the desired python version here and, for example to install Python 3.9, run:

wget https://www.python.org/ftp/python/3.9.9/Python-3.9.9.tgz
tar -xzf Python-3.9.9.tgz
cd Python-3.9.9

Then, run configure:

./configure --enable-optimizations

And finally run make install if you want to replace the default Python installation or make altinstall to install python under the binary name of python3.9

make altinstall

To test the installation run:

python3.9 --version
Python 3.9.9

pip3.9 --version
pip 21.2.4 from /usr/local/lib/python3.9/site-packages/pip (python 3.9)

Installing Python via a third party PPA deadsnakes

To install Python using the deadsnakes ppa run:

apt-get update
apt-get install software-properties-common
add-apt-repository ppa:deadsnakes/ppa
apt-get update
apt install python3.9 python3-pip

Then, to test the installation run:

root@ubuntu:/# python3.9 --version
Python 3.9.10

root@ubuntu:/# python3.9 -m pip --version
pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.9)

Installing Python via Pyenv

I already written an article on how to install Python using Pyenv, check it out if you wish.

https://nuculabs.wordpress.com//2020/06/27/pyenv-for-linux-users/

Thanks for reading! ๐Ÿ“š

Pytest Fixtures and Yield

Hi ๐Ÿ‘‹

In this short article I want to explain the use of the yield keyword in pytest fixtures.

What is pytest?

Pytest is a complex python framework used for writing tests. It has lots of advanced features and it supports plugins. Many projects prefer pytest in addition to Python’s unitttest library.

What is a fixture?

A test fixture is a piece of code that fixes some common functionality that is required for writing the unit tests. This functionality can be

  • a connection to the database
  • a testing http server or client
  • creation of a complex object

You can read more about test fixtures on Wikipedia.

What does yield keyword do?

In Python, the yield keyword is used for writing generator functions, in pytest, the yield can be used to finalize (clean-up) after the fixture code is executed. Pytest’s documentation states the following.

โ€œYieldโ€ fixtures yield instead of return. With these fixtures, we can run some code and pass an object back to the requesting fixture/test, just like with the other fixtures.

https://docs.pytest.org/en/6.2.x/fixture.html

An example code could be the following:

@pytest.fixture()
def my_object_fixture():
    print("1. fixture code.")
    yield MyObjectThatRequiresCleanUp()
    print("4. fixture code after yield.")

Running a sample test which utilizes the fixture will output:

collected 1 item                                                                                                                                                                       

tests\test_my_object.py 1. fixture code.
2. Initializing MyObjectThatRequiresCleanUp
3. test code.
.4. fixture code after yield.

Running the same test but now with the fixture my_object_fixture2, will output:

tests\test_my_object.py 1. fixture code.
2. Initializing MyObjectThatRequiresCleanUp
2.1 Entering
3. test code.
.3.1 Exiting
Clean exit
4. fixture code after yield.

I hope I could successfully ilustrate with these examples the order in which the testing and fixture code is run.

To run the tests, I’ve used pytest --capture=tee-sys . in the project root. The file contents are attached to the end of this article. The --capture parameter is used to capture and print the tests stdout. Pytest will only output stdout of failed tests and since our example test always passes this parameter was required.

Conclusion

Pytest is a python testing framework that contains lots of features and scales well with large projects.

Test fixtures is a piece of code for fixing the test environment, for example a database connection or an object that requires a specific set of parameters when built. Instead of duplicating code, fixing the object’s creation into a fixture makes the tests easier to maintain and write.

yield is a python keyword and when it is used in conjunction with pytest fixtures it gives you a nice pythonic way of cleaning up the fixtures.

Thanks for reading! ๐Ÿ“š


Contents of the Pytest fixtures placed in tests/__init__.py

import pytest

from my_object import MyObjectThatRequiresCleanUp


@pytest.fixture()
def my_object_fixture():
    print("1. fixture code.")
    yield MyObjectThatRequiresCleanUp()
    print("4. fixture code after yield.")


@pytest.fixture()
def my_object_fixture2():
    print("1. fixture code.")
    with MyObjectThatRequiresCleanUp() as obj:
        yield obj
    print("4. fixture code after yield.")

Contents of my_object.py

class MyObjectThatRequiresCleanUp:
    def __init__(self):
        print("2. Initializing MyObjectThatRequiresCleanUp")

    def __enter__(self):
        print("2.1 Entering")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("3.1 Exiting")
        if exc_type is None:
            print("Clean exit")
        else:
            print("Exception occurred: {}".format(exc_type))

Contents of test_my_object.py placed in tests/test_my_object.py

from tests import my_object_fixture


def test_my_object(my_object_fixture):
    print("3. test code.")

How to write parametrized tests in Python with pytest ๐ŸŽฅ

Hi ๐Ÿ‘‹

Welcome to another video tutorial on how to write parametrized tests in Python using pytest.

If you want to follow along, here’s the code that I’ve tested in the video.

from typing import List


class Solution:
    def move_zeroes(self, nums: List[int]) -> None:
        last_zero = 0
        index = 0
        while index < len(nums):
            if nums[index] != 0:
                nums[last_zero], nums[index] = nums[index], nums[last_zero]
                last_zero += 1
            index += 1


def main():
    solution = Solution()
    arr = [1,0,1]
    solution.move_zeroes(arr)
    print(arr)


if __name__ == '__main__':
    main()

Thanks for watching! ๐Ÿ˜„