Table of Contents

Python 3

Installation

Probably the more straightforward way to download is by installing natively. Modern Linux systems today tend to come with a pre-packaged version of Python in order to run some userspace pre-packaged programs (ufw is one).

To avoid conflicts with system binaries, Python versions can be managed via pyenv instead. Some installation instructions for Ubuntu 20.04 and 22.04 LTS:

# 1. Pull required binaries into build environment, needed to build python
#    See: https://github.com/pyenv/pyenv/wiki
sudo apt-get update
sudo 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

# 2. Ensure git's autocrlf is set to false
#    See: https://github.com/pyenv/pyenv/issues/1725#issuecomment-724689291
#    Symptoms include: `/usr/bin/env: ‘bash\r’: No such file or directory` when running pyenv
git config --global core.autocrlf false

# 3. Run the automated installer
#    See: https://github.com/pyenv/pyenv-installer
curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash

# 4. Add scripts to shell to enable pyenv shims
#    For Bash, run the following commands:
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init -)"' >> ~/.profile
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

# 5. Restart shell
exec "$SHELL"

# 6. Install Python version, e.g. 3.10.4
pyenv install 3.10.4

# 7. Set Python version as global version to use
     To unset, set it to 'system' insetad.
pyenv global 3.10.4

One great benefit of using pyenv is the ability to seamlessly transition between virtual environments when moving into a project directory, simply by creating a virtual environment and assigning a Python version to it. Multiple versions can be assigned as well.

On Windows platforms, Python should be uninstalled manually via the "Add & Remove Programs" settings page, instead of the usual pyenv uninstall .... The former seems to handle additional processes like removing entries from the registry, while the latter only deletes the program directory.

For OpenSUSE

Scripts

Small scripts to park here, until I manage to get my boilerplate library properly setup:

#!/usr/bin/env python3
# Rename files in "Screenshot from 2022-12-07 09-23-06.png" format to "20221207_092306_" 
# Justin, 2022-12-12
 
"""
Old contents:
#!/bin/sh
ls | grep -E "Screenshot .* ([0-9]{4})" | sed -r "s/([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+)-([0-9]+)-([0-9]+)/\1\2\3_\4\5\6/g"
# TODO: Not complete!
"""
 
import pathlib
 
for path in pathlib.Path().glob("Screenshot from *.png"):
 
    # Extract all numbers
    target = "".join([c for c in str(path) if "0" <= c <= "9"])
    target = target[:8] + "_" + target[8:] + "_.png"
 
    # Rename
    path.rename(path.with_name(target).absolute())

setup.py?

PEP517 in a nutshell:

PS C:\Users\Justin> pip install git+https://github.com/pyuxiang/boiler.git
Collecting git+https://github.com/pyuxiang/boiler.git
  Cloning https://github.com/pyuxiang/boiler.git to c:\users\justin\appdata\local\temp\pip-req-build-rzbbiuw0
  Running command git clone --filter=blob:none --quiet https://github.com/pyuxiang/boiler.git 'C:\Users\Justin\AppData\Local\Temp\pip-req-build-rzbbiuw0'
  Resolved https://github.com/pyuxiang/boiler.git to commit 63522bae91982a15919d07160f68d4068169c336
  Preparing metadata (setup.py) ... done
Requirement already satisfied: numpy in c:\users\justin\.pyenv\pyenv-win\versions\3.11.1\lib\site-packages (from boiler==0.0.5) (1.24.1)
Installing collected packages: boiler
  DEPRECATION: boiler is being installed using the legacy 'setup.py install' method, because it does not have a 'pyproject.toml' and the 'wheel' package is not installed. pip 23.1 will enforce this behaviour change. A possible replacement is to enable the '--use-pep517' option. Discussion can be found at https://github.com/pypa/pip/issues/8559
  Running setup.py install for boiler ... done
Successfully installed boiler-0.0.5

Saving Python history file, without outputs, to copy into script:

import readline
readline.write_history_file("history.txt")

For interactive mode, try:

user:~$ python3 -i -c "from {{MODULE}} import *"

To expose all variables from single function (for quick scripting purposes), use globals().update(locals()).

A post-install script from ''freqcd.c''

See libraries that are likely to be manually imported, i.e. libraries that are not dependencies:

user:~$ pip3 list --not-required

A list of popular libraries on my side:

requirements.txt
# General stuff
arrow
joblib
matplotlib
numpy
pandas
pyserial
requests
requests-cache
scipy
tqdm
uncertainties

# Linting
black
isort

# S15 stuff
setuptools
Cython
fpfind @ git+https://github.com/s-fifteen-instruments/fpfind.git
S15lib @ git+https://github.com/s-fifteen-instruments/pyS15.git

# Personal
kochen @ git+https://github.com/pyuxiang/kochen.git

Running a single file code remotely can be done by passing the script via stdin over SSH (assuming the dependency libraries are already available on the remote side), then reading the output back. If a more complex data structure needs to be passed, one could use a message passing service or construct... or just pickle it if it's back to another Python module. See:

# Remote script, "producer.py"
if __name__ == "__main__":
    import contextlib, pickle, sys
    with contextlib.redirect_stdout(None):
        result = myfunc()
    sys.stdout.buffer.write(pickle.dumps(result))
 
# Local script, "consumer.py"
import pickle, sys
result = pickle.loads(sys.stdin.buffer.read())
user:~$ cat producer.py | ssh <HOST> python3 - <ARGS> | ./consumer.py
 
# If using pyenv, then may need to use a login shell to trigger .bashrc source
user:~$ cat producer.py | ssh <HOST> 'bash -lc "python3 - <ARGS>"' | ./consumer.py

The Python interpreter performance can be improved by setting compile-time optimization flags, as shown in this page, e.g.

env PYTHON_CONFIGURE_OPTS='--enable-optimizations --with-lto' PYTHON_CFLAGS='-march=native -mtune=native' pyenv install 3.10.6

Command-line scripts

Some libraries are designed to be installed as a Python module, with command line tools exposed. If the main method was defined, but no command line tool is available, consider mapping your own:

/usr/bin/aubio
#!/usr/bin/env python3
from aubio import cmd
if __name__ == "__main__":
    cmd.main()

In the case of Aubio, it was just that the commands are exposed only after restarting the shell...

uv

uv is fast becoming one of my favorite package + Python managers, by virtue of how blazingly fast it is. It also caches existing compilations so there's no need for manual building which is what pyenv does. Not really a good idea to expect other users to follow though (need to learn the extra uv commands), so the way to transparently add Python:

user:~$ uv python install 3.12
user:~$ uv venv
 
# Hide virtual environment name by setting to empty string
user:~$ sed -i -E 's/(export VIRTUAL_ENV_PROMPT)/\1=""/g' .venv/bin/activate
 
# Source Python installation
user:~$ echo '. "$HOME/.venv/bin/activate"' >> .profile
user:~$ uv pip install pip

Restarting the shell will result in a base Python + Pip, just like pyenv, but with users none the wiser :)