.. image:: https://github.com/peterbe/hashin/workflows/Python/badge.svg :target: https://github.com/peterbe/hashin/actions
.. image:: https://badge.fury.io/py/hashin.svg :target: https://pypi.python.org/pypi/hashin
Helps you write your requirements.txt
with hashes so you can
install with pip install --require-hashes -r ...
If you want to add a package or edit the version of one you're currently using you have to do the following steps:
.tgz
file.whl
filepip hash downloadedpackage-1.2.3.tgz
pip hash downloadedpackage-1.2.3.whl
requirements.txt
This script does all those things. Hackishly wonderfully so.
The whole point of hashing is that you vet the packages that you use on your laptop and that they haven't been tampered with. Then you can confidently install them on a server.
This tool downloads from PyPI (over HTTPS) and runs pip hash
on the downloaded files.
You should check that the packages that are downloaded
are sane and not tampered with. The way you do that is to run
hashin
as normal but with the --verbose
flag. When you do that
it will print where it downloaded the relevant files and those
files are not deleted. For example::
$ hashin --verbose bgg /tmp/reqs.txt
https://pypi.python.org/pypi/bgg/json
* Latest version for 0.22.1
* Found URL https://pypi.python.org/packages/2.7/b/bgg/bgg-0.22.1-py2-none-any.whl
* Re-using /var/folders/1x/2hf5hbs902q54g3bgby5bzt40000gn/T/bgg-0.22.1-py2-none-any.whl
* Hash e5172c3fda0e8a42d1797fd1ff75245c3953d7c8574089a41a219204dbaad83d
* Found URL https://pypi.python.org/packages/source/b/bgg/bgg-0.22.1.tar.gz
* Re-using /var/folders/1x/2hf5hbs902q54g3bgby5bzt40000gn/T/bgg-0.22.1.tar.gz
* Hash aaa53aea1cecb8a6e1288d6bfe52a51408a264a97d5c865c38b34ae16c9bff88
* Editing /tmp/reqs.txt
You might not have time to go through the lines one by one but you should be aware that the vetting process is your responsibility.
This is something you only do or ever need in a development environment. Ie. your laptop::
pip install hashin
Suppose you want to install futures
. You can either do this::
hashin futures
Which will download the latest version tarball (and wheel) and
calculate their pip hash and edit your requirements.txt
file.
Or you can be specific about exactly which version you want::
hashin "futures==2.1.3"
You can also specify more than one package at a time::
hashin "futures==2.1.3" requests
Suppose you don't have a requirements.txt
right there in the same
directory you can specify --requirements-file
::
hashin futures --requirements-file=stuff/requirements/prod.txt
By default sha256
hashes are used, but this can be overridden using the
--algorithm
argument::
hashin futures --algorithm=sha512
If there's no output, it worked. Check how it edited your requirements file.
Some requirements have many releases built for different versions of Python and
different architectures. These hashes aren't useful in some cases, if those
wheels don't work with your project. hashin
can filter on the Python
version to skip these extraneous hashes.
For example, the cffi
package offers wheels built for many versions of
CPython from 2.6 to 3.5. To select only one of them, you can use the
--python-version
option::
hashin "cffi==1.5.2" --python-version 3.5
If you need to support multiple versions, you can pass this option multiple times::
hashin "cffi==1.5.2" --python-version 2.7 --python-version 3.5
hashin
will expand these Python versions to a full list of identifers that
could be found on PyPI. For example, 3.5
will expand to match any of
3.5
, py3
, py3.5
, py2.py3
, or cp3.5
. You can also specify
these exact identifiers directly, if you need something specific.
The source
release is always automatically included. pip
will use
this as a fallback in the case a suitable wheel cannot be found.
There are some use cases, when you maybe don't want to edit your requirements.txt
right away. You can use the --dry-run
argument to show the diff, so you
can preview the changes to your requirements.txt
file.
Example::
hashin --dry-run requests==2.19.1
Would result in a printout on the command line::
--- Old
+++ New
@@ -0,0 +1,3 @@
+requests==2.19.1 \
+ --hash=sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1 \
+ --hash=sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a
Requirements can use PEP-0496
_ style specifiers (e.g. like
cffi==1.5.2; python_version >= '3.4'
) and these will be passed
through when re-writing the requirements.txt
file. hashin
doesn't
parse the specifiers themselves and will take anything after the
semicolon. If you are using python_version
you will still need to
pass appropriate options if you don't want every available hash.
An example of this might be::
hashin "pywin32-ctypes ; sys_platform == 'win32'"
which will result it something like this in the requirements.txt
file::
pywin32-ctypes==0.1.2; sys_platform == 'win32' \
--hash=sha256:4820b830f42e6889d34142bcd07b3896018c3620d8c31f5e13b72caf1f4d1d0f
And if you want to limit it to certain Python versions, here's an example::
hashin "cffi==1.5.2; python_version >= '3.4'" -p 3.4 -p 3.5
.. _PEP-0496
: https://www.python.org/dev/peps/pep-0496/
Everything you can do with hashin
on the command line you can do
in running Python too. For example::
import hashin
from pprint import pprint
pprint(hashin.get_package_hashes('Django'))
This will print out::
{'hashes': [{'hash': 'fbc7ffaa45a4a67cb45f77dbd94e8eceecebe1d0959fe9c665dfbf28b41899e6',
'url': 'https://pypi.python.org/packages/41/c1/68dd27946b03a3d756b0ff665baad25aee1f59918891d86ab76764209208/Django-1.11b1-py2.py3-none-any.whl'}],
'package': 'Django',
'version': '1.11b1'}
Or with specific version, algorithm and certain Python versions::
import hashin
from pprint import pprint
pprint(hashin.get_package_hashes(
'Django',
version='1.10',
algorithm='sha512',
python_versions=('3.5',)
))
After you have cloned the project, created a virtual environment and run:
pip install -e ".[dev]"
Now, to run it you can use the installed executable hashin
and do things
like::
touch /tmp/reqs.txt
hashin -r /tmp/reqs.txt Django
Simply run::
python setup.py test
When you use pip install ".[dev]"
it will install tox
which you can use
to run the full test suites (plus linting) in different Python environments::
tox
To run the tests with test coverage, with pytest
run something like
this::
$ pip install pytest-cover
$ pytest --cov=hashin --cov-report=html
$ open htmlcov/index.html
To avoid having to install hashin
just to test it or debug a feature
you can simply just run it like this::
touch /tmp/whatever.txt
python hashin.py --verbose Django /tmp/whatever.txt
All Python code should be run through Black <https://pypi.org/project/black/>
_.
This is checked in CI and you can test it locally with tox
.
Also, this project uses pre-commit <https://pre-commit.com/>
_
which helps with checking code style as a git pre-commit hook. pre-commit
is used in tox
. To run all code style checks, use tox -e lint
but
make sure your version of tox
is built on a Python 3.
This program is a "fork" of https://pypi.python.org/pypi/peepin
peepin
was a companion to the program peep
https://pypi.python.org/pypi/peep/ but the functionality of peep
has been put directly into pip
as of version 8.
If this script proves itself to work and be useful, I hope we can
put it directly into pip
.
1.0.1
1.0.0
setup.py
, tox.ini
and GitHub Actions to use Python >=3.8
and up to 3.12.0.17.0
Add python 3.9 and 3.10 to the test matrix.
Preserve lexigraphical order of hashes for the output of the
get_releases_hashes
function.
See https://github.com/peterbe/hashin/issues/126
0.16.0
Preserve indented comments when updating requirements files. See https://github.com/peterbe/hashin/issues/124
Switch to GitHub Actions instead of TravisCI. And test tox
in
Python 3.7 and 3.8 additionally as well as upgrading lint requirements.
See https://github.com/peterbe/hashin/pull/118
0.15.0
0.14.6
Indentation in the requirements file is preserved. See https://github.com/peterbe/hashin/issues/112 Thanks @techtonik
If you use --update-all
and forget the -r
when specifying your
requirements file, instead of complaining, it corrects the intentions.
See https://github.com/peterbe/hashin/issues/104
0.14.5
0.14.4
--index-url
option feature in version 0.14.3.
See https://github.com/peterbe/hashin/issues/1080.14.3
--index-url
which allows to override the default which
is https://pypi.org
. Thanks @nmacinnis
See https://github.com/peterbe/hashin/pull/1070.14.2
--update-all
and parsing requirements file it could be fooled
by comments that look like package specs (e.g # check out foo==1.0
)
See https://github.com/peterbe/hashin/issues/1030.14.1
0.14.0
--interactive
(when you use --update-all
) will iterate over all outdated
versions in your requirements file and ask, for each one, if you want to
updated it.
See https://github.com/peterbe/hashin/issues/90
Order of hashes should not affect if a package in the requirements file should be replaced or not. See https://github.com/peterbe/hashin/issues/93
(Internal) All tests have been rewritten as plain pytest functions.
In Python 3, if the package can't be found you get a more explicit exception pointing out which package (URL) that failed. See https://github.com/peterbe/hashin/issues/87
New flag --update-all
(alias -u
) will parse the requirements file,
ignore the version, and update all packages that have new versions.
See https://github.com/peterbe/hashin/pull/88
Support for "extras syntax". E.g. hashin "requests[security]"
. Doesn't
actually get hashes for security
(in this case, that's not even a
package) but allows that syntax into your requirements.txt
file.
See https://github.com/peterbe/hashin/issues/70
All code is now formatted with Black <https://pypi.org/project/black/>
_.
0.13.4
Ability to pass --dry-run
which prints a diff of what it would
do to your requirements file. See https://github.com/peterbe/hashin/pull/78
Better error message when no versions, but some pre-releases found. See https://github.com/peterbe/hashin/issues/76
Don't show URLs when using --verbose
if files don't need to be
downloaded. See https://github.com/peterbe/hashin/issues/73
0.13.3
nltk
on Windows.
Thanks @chrispbailey! <https://github.com/peterbe/hashin/pull/72>
_0.13.2
py{major}{minor}
additionally. Solves
problem with installing packages with files like
Paste-2.0.3-py34-none-any.whl
.
Thanks @danfoster! <https://github.com/peterbe/hashin/pull/67>
_0.13.1
--include-prereleases
if you're trying to add
a package that only has pre-releases.0.13.0
hashin
: pip-api
and packaging
.
This means we no longer need to import pip
and rely on private
APIs.
Thanks @di! <https://github.com/peterbe/hashin/pull/59>
_
This also means you can no longer install hashin
on Python 2.6 and
Python <=3.3
.0.12.0
Switch from pypi.python.org/pypi/<package>/json
to
pypi.org/pypi/<package>/json
which also means the sha256 hash is part
of the JSON payload immediately instead of having to download and run
pip
to get the hash.
Testing no runs Python 2.6 and Python 3.3.
All hashes, per package, are sorted (by the hash) to make it more predictable.
0.11.5
requirements.txt
file.
Thanks @meejah0.11.4
0.11.3
0.11.2
0.11.1
hashin --version
to see what version of hashin is
installed.
See https://github.com/peterbe/hashin/issues/410.11.0
0.10.0
0.9.0
redis==x.y.z
when django-redis==a.b.c
was
already in the requirements file.0.8.0
Ability to make hashin
work as a library. Thanks @jayfk !
pep8 cleanups.
0.7.2
0.7.1
hashin dJaNgO
0.7.0
0.6.1
.msi
file.0.6.0
0.5.0
pytest-selenium==...
already in your requirements.txt
file and add selenium==x.y.z
it would touch the line with pytest-selenium
too.0.4.1
0.4.1
0.4
0.3
0.2
0.1