Contents of .git/hooks/pre-push
:
#!/bin/sh
printf '%s: running pytest\n' "$0"
pytest -q --no-cov
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:
*
interpolation / f-strings + nestingAs of v30.3.0
(released on 2016-12-08), setuptools
allows basic package configuration fields to be specified in a text file,
setup.cfg
(inspired by distutils2
)
Here’s a template to initialize setup.cfg
:
[metadata]
name = helloworld
author = Christopher Brown
author_email = io@henrian.com
url = https://github.com/chbrown/helloworld
description = Greet world
keywords = hello, world
license = MIT
classifiers =
Development Status :: 1 - Planning
License :: OSI Approved :: MIT License
Programming Language :: Python
long_description = file: README.md
long_description_content_type = text/markdown
[options]
zip_safe = False
packages = find:
python_requires = >=3.6
install_requires =
cytoolz>=0.10.0
numpy
setup_requires =
pytest-runner
setuptools-scm
tests_require =
pytest
pytest-black
pytest-cov
[options.entry_points]
console_scripts =
helloworld = helloworld.__main__:main
[aliases]
test = pytest
[tool:pytest]
addopts =
--black
--cov=helloworld
--cov-branch
All the information is now in setup.cfg
, but you’ll still need a setup.py
stub:
from setuptools import setup
setup(use_scm_version=True)
Expose the installed version in helloworld/__init__.py
:
__version__ = None
try:
import pkg_resources
__version__ = pkg_resources.get_distribution("helloworld").version
except Exception:
pass
References:
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 .
Which mostly just calls:
python setup.py develop
If you don’t have an proper package set up, there are a couple ways to manually link in specific directories:
*.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.
export PYTHONPATH=~/path/to/Python/files
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
These instructions are current as of 2019-03-31, and reflect the instructions from https://packaging.python.org/tutorials/packaging-projects/.
Definitely the first time you do this, and probably every so often besides, you’ll want to install / upgrade twine and wheel:
pip install -U twine wheel
Now we can build the source distribution and a universal (Python 2/3) “wheel”.
python setup.py sdist bdist_wheel
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
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.
piprot
compares the versions of packages specified in a requirements.txt
file with the latest available versions on PyPI.
This is like pip list --outdated
, but pip
does not have an option to limit the listing to just the packages in a requirements file.
pipdeptree
draws trees of dependencies, recursively.
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'
Key(s) | Action |
---|---|
ctrl + shift + - |
split cell at cursor (all contents before the cursor will be moved to a new cell above the current one) |