Skip to content

Commit

Permalink
Provide a list of valid hashers in case blake2b is not present.
Browse files Browse the repository at this point in the history
- Also provide a nice error message in case no hasher is available.

Close #6
  • Loading branch information
hgrecco committed Jan 10, 2024
1 parent 24929a6 commit c734b7d
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
26 changes: 25 additions & 1 deletion flexparser/flexparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from __future__ import annotations

import warnings
import sys
import collections
import dataclasses
Expand Down Expand Up @@ -50,6 +51,29 @@

_SENTINEL = object()

_HASH_ALGORITHMS = "blake2b", "blake2s", "sha3_512", "sha512", "sha1"

for _algo_name in _HASH_ALGORITHMS:
try:
_DEFAULT_HASHER = getattr(hashlib, _algo_name)
_DEFAULT_HASHER(b"Always look at the bright side of life!").hexdigest()
break
except Exception:
pass
else:
msg = (
f"Could not use any of the predefined hash algorithms {_HASH_ALGORITHMS}.\n"
"Your Python distribution's hashlib module is incomplete or not properly installed.\n"
"If you can't fix it, set the algorithm manually in the parser by:\n"
">>> parser._hasher = hasher\n"
)

def _internal(*args, **kwargs):
raise ValueError(msg)

_DEFAULT_HASHER = _internal
warnings.warn(msg)


class HasherProtocol(ty.Protocol):
@property
Expand Down Expand Up @@ -1120,7 +1144,7 @@ class Parser(ty.Generic[RBT, CT], GenericInfo):
bytes,
],
HasherProtocol,
] = hashlib.blake2b
] = _DEFAULT_HASHER

def __init__(self, config: CT, prefer_resource_as_file: bool = True):
self._config = config
Expand Down
16 changes: 16 additions & 0 deletions flexparser/testsuite/test_util.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import hashlib
import typing

import pytest

import flexparser.flexparser as fp
from flexparser.flexparser import _HASH_ALGORITHMS


def test_yield_types():
Expand Down Expand Up @@ -51,3 +54,16 @@ def test_hash_object():
assert ho != hd
assert ho != fp.Hash.from_bytes(hashlib.md5, content)
assert ho == fp.Hash.from_bytes(hashlib.sha1, content)


@pytest.mark.parametrize("algo_name", _HASH_ALGORITHMS)
def test_hash_items(algo_name: str):
content = b"spam \n ham"
hasher = getattr(hashlib, algo_name)

ho = fp.Hash.from_bytes(hasher, content)
hd = hasher(content).hexdigest()
assert ho.algorithm_name == algo_name
assert ho.hexdigest == hd
assert ho != hd
assert ho == fp.Hash.from_bytes(hasher, content)

0 comments on commit c734b7d

Please sign in to comment.