General documentation / cheat sheets for various languages and services

String formatting

Supply a variable precision as well as number in a string formatting:

from math import pi
precision = 2
# via interpolation
'%0.*f' % (precision, pi)
=> '3.14'
# via format
'{1:0.{0}f}'.format(precision, pi)
=> '3.14'
# with f-strings
f'{pi:0.{precision}f}'
=> '3.14'

References:

Distribution

First, create a setup.py. Here’s a minimal-ish template:

import setuptools

setuptools.setup(
    name='helloworld',
    version='1.0.0',
    author='Christopher Brown',
    author_email='[email protected]',
    description='Greet world',
    long_description=open('README.md').read(),
    long_description_content_type='text/markdown',
    url='https://github.com/chbrown/helloworld-python',
    license='MIT',
    packages=setuptools.find_packages(),
    install_requires=[
        'cytoolz',
    ],
    zip_safe=True,
    classifiers=(
        'Development Status :: 3 - Alpha',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
    ),
)

References:

Local development

The easiest way to link a package into Python’s default site-packages is via pip:

# from a directory containing a setup.py
pip install -e .

If you don’t have an proper package set up, there are a couple ways to manually link in specific directories:

  1. Permanently, via a *.pth file:
    # from a directory containing Python files
    SITE_PACKAGES=$(python -c 'import os,site;print(os.path.realpath(next(iter(site.getsitepackages()))))')
    pwd > "$SITE_PACKAGES"/my-python-modules.pth
    

    That python call gets the canonical/default/first site-packages path for your active python. The site.getsitepackages() call returns a list of full paths to your active site-packages directories, but we only want the first one, and they can be unwieldy; calling os.path.realpath cleans up the relative paths and resolves symlinks.

  2. Via environment variable:
    export PYTHONPATH=~/path/to/Python/files
    

Versioning

Bump the version in setup.py manually and commit the change. Then use the following to tag that commit and push to remote:

git tag v$(python setup.py --version)
git push --tags

Publishing to PyPI

These instructions are current as of 2017-10-22, and reflect the instructions from https://packaging.python.org/tutorials/distributing-packages/.

Definitely the first time you do this, and probably every so often besides, you’ll want to install the required packages:

pip install -U twine wheel

Now we can build the source distribution and a universal (Python 2/3) “wheel”.

python setup.py sdist
python setup.py bdist_wheel --universal

Ensure that ~/.pypirc includes your PyPI credentials. Then, finally:

twine upload dist/*

Clean up:

python setup.py clean --all
rm -rf dist/

Or just ignore the build clutter:

printf '%s\n' build/ dist/ >> .git/info/exclude

Dependency management

Install pip if you don’t have it:

curl -sO https://bootstrap.pypa.io/get-pip.py
python get-pip.py

Upgrade pip if you don’t have the latest:

pip install --upgrade pip

pip does a lot but doesn’t provide much inspection/maintenance tooling. Luckily, there are some handy packages that fill in some of pip’s gaps.

IPython / Jupyter interactivity

As of IPython 6.2, you can automatically print the result of the last assignment, as if it were an expression.

The default behavior:

[chbrown@air ~]$ ipython
Python 3.6.5 (default, Mar 30 2018, 06:42:10)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: pi = 3

In [2]: 

With the new “AST Node Interactivity” option:

[chbrown@air ~]$ ipython --InteractiveShell.ast_node_interactivity=last_expr_or_assign
Python 3.6.5 (default, Mar 30 2018, 06:42:10)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: pi = 3
Out[1]: 3

In [2]: 

In both IPython and Jupyter, this can be activated in a live session with the magic:

%config InteractiveShell.ast_node_interactivity = 'last_expr_or_assign'

This same config approach can be specified in the IPython default profile to apply to all sessions of both IPython and Jupyter; simply add the following to your ~/.ipython/profile_default/ipython_config.py file:

c.InteractiveShell.ast_node_interactivity = 'last_expr_or_assign'