Skip to content

Commit 01046b8

Browse files
committed
v0.1.4
All dependencies relative to hash function implementation are now optional, dynamically imported only when the hash functions using them are used for the first time. Running `pip install --upgrade multiformats` will not install any of them, but they can be all installed by running `pip install --upgrade multiformats[full]`. In particular, this closes #4. Hash function implementations are loaded and registered transparently on first use, to reduce memory footprint and module loading times. Analogously, a number of multibases are created and registered transparently on first use. All hash functions with a readily available, well-supported existing Python implementation are now supported. Finally, closes #3.
1 parent b76a9ea commit 01046b8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1547
-550
lines changed

MULTIFORMATS-LICENSE renamed to ADDITIONAL-LICENSES

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
The following items are subject to MIT License by Protocol Labs Inc:
1+
The following items are subject to MIT License by Protocol Labs Inc, included below:
22

33
- multibase table, downloaded from https://github.com/multiformats/multibase/raw/master/multibase.csv
44
- multicodec table, downloaded from https://github.com/multiformats/multicodec/raw/master/table.csv
5-
- test vectors for multihash, downloaded from https://github.com/multiformats/multihash/raw/master/tests/values/test_cases.csv on 14 Dec 2021
5+
- the test vectors for multihash in multihash-test-str-vectors.csv, downloaded from https://github.com/multiformats/multihash/raw/master/tests/values/test_cases.csv on 14 Dec 2021
6+
7+
Test vectors for murmur3 hash are public domain, courtesy of Ian Boyd https://stackoverflow.com/questions/14747343/murmurhash3-test-vectors#31929528
68

79

810
The MIT License (MIT)

README.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,27 @@ You can install the latest release from `PyPI <https://pypi.org/project/multifor
4444
4545
$ pip install --upgrade multiformats
4646
47+
The following are mandatory dependencies for this module:
48+
49+
- `typing-extensions <https://github.com/python/typing_extensions>`_, for backward compatibility of static typing.
50+
- `typing-validation <https://github.com/hashberg-io/typing-validation>`_, for dynamic typechecking
51+
- `bases <https://github.com/hashberg-io/bases>`_, for implementation of base encodings used by Multibase
52+
53+
The following are optional dependencies for this module:
54+
55+
- `pysha3 <https://github.com/tiran/pysha3>`_, for the ``keccak`` hash functions.
56+
- `blake3 <https://github.com/oconnor663/blake3-py>`_, for the ``blake3`` hash function.
57+
- `pyskein <https://pythonhosted.org/pyskein/>`_, for the ``skein`` hash functions.
58+
- `mmh3 <https://github.com/hajimes/mmh3>`_, for the ``murmur3`` hash functions.
59+
- `pycryptodomex <https://github.com/Legrandin/pycryptodome/>`_, for the ``ripemd-160`` hash function, \
60+
the ``kangarootwelve`` hash function and the ``sha2-512-224``/``sha2-512-256`` hash functions.
61+
62+
You can install the latest release together with all optional dependencies as follows:
63+
64+
.. code-block:: console
65+
66+
$ pip install --upgrade multiformats[full]
67+
4768
4869
Usage
4970
-----
@@ -311,3 +332,5 @@ License
311332
-------
312333

313334
`MIT © Hashberg Ltd. <LICENSE>`_
335+
336+
See `additional Licenses <ADDITIONAL-LICENSES>`_ for licensing of the multicodec table, the multibase table and test vectors for multihashes.

docs/api/multiformats.multihash.raw.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ multiformats.multihash.raw
66
Hashfun
77
-------
88

9-
.. autodata:: multiformats.multihash.raw.Hashfun
9+
.. autoclass:: multiformats.multihash.raw.Hashfun
10+
:members:
1011

1112
MultihashImpl
1213
-------------

docs/getting-started.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,25 @@ The above will import the following names:
2929
The first five are modules implementing the homonymous specifications,
3030
while :class:`~multiformats.cid.CID` is a class for Content IDentifiers.
3131

32+
The following are mandatory dependencies for this module:
33+
34+
- `typing-extensions <https://github.com/python/typing_extensions>`_, for backward compatibility of static typing.
35+
- `typing-validation <https://github.com/hashberg-io/typing-validation>`_, for dynamic typechecking
36+
- `bases <https://github.com/hashberg-io/bases>`_, for implementation of base encodings used by Multibase
37+
38+
The following are optional dependencies for this module:
39+
40+
- `pysha3 <https://github.com/tiran/pysha3>`_, for the ``keccak`` hash functions.
41+
- `blake3 <https://github.com/oconnor663/blake3-py>`_, for the ``blake3`` hash function.
42+
- `pyskein <https://pythonhosted.org/pyskein/>`_, for the ``skein`` hash functions.
43+
- `mmh3 <https://github.com/hajimes/mmh3>`_, for the ``murmur3`` hash functions.
44+
- `pycryptodomex <https://github.com/Legrandin/pycryptodome/>`_, for the ``ripemd-160`` hash function, \
45+
the ``kangarootwelve`` hash function and the ``sha2-512-224``/``sha2-512-256`` hash functions.
46+
47+
You can install the latest release together with all optional dependencies as follows:
48+
49+
.. code-block:: console
50+
51+
$ pip install --upgrade multiformats[full]
52+
3253
GitHub repo: https://github.com/hashberg-io/multiformats

docs/make-api.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
"exclude_members": {
1212
"multiformats.multicodec": ["build_multicodec_tables"],
1313
"multiformats.multibase": ["build_multibase_tables"],
14-
"multiformats.multibase.raw": ["identity_raw_encoder", "identity_raw_decoder", "proquint_raw_encoder", "proquint_raw_decoder", "RawEncoder", "RawDecoder"],
14+
"multiformats.multibase.raw": ["RawEncoder", "RawDecoder"],
1515
"multiformats.cid": ["CIDVersionNumbers", "byteslike"],
1616
"multiformats.multiaddr.raw": ["ip4_encoder", "ip4_decoder", "ip6_encoder", "ip6_decoder", "tcp_udp_encoder", "tcp_udp_decoder"]
1717
},
1818
"include_modules": [],
19-
"exclude_modules": []
20-
}
19+
"exclude_modules": [
20+
"multiformats.multihash._hashfuns"
21+
]
22+
}

docs/make-api.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,12 @@ def make_apidocs() -> None:
8787
os.remove(apidoc_file)
8888
print()
8989

90+
mod_name_to_del: List[str] = []
91+
9092
for mod_name, mod in modules_dict.items():
91-
if mod_name in exclude_modules:
93+
if any(mod_name.startswith(name) for name in exclude_modules):
94+
# if mod_name in exclude_modules:
95+
mod_name_to_del.append(mod_name)
9296
continue
9397
filename = f"{apidocs_folder}/{mod_name}.rst"
9498
print(f"Writing API docfile {filename}")
@@ -164,6 +168,10 @@ def make_apidocs() -> None:
164168
f.write("\n".join(lines))
165169
print("")
166170

171+
172+
for mod_name in mod_name_to_del:
173+
del modules_dict[mod_name]
174+
167175
toctable_lines = [
168176
".. toctree::",
169177
" :maxdepth: 2",

docs/requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@ sphinx_autodoc_typehints
44
bases
55
typing-extensions
66
typing-validation
7-
pyskein

multiformats/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
while :class:`~multiformats.cid.CID` is a class for Content IDentifiers.
1616
"""
1717

18-
__version__ = "0.1.3"
18+
__version__ = "0.1.4"
1919

2020
from . import varint
2121
from . import multicodec

multiformats/multiaddr/err.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66

77
class MultiaddrKeyError(builtins.KeyError): # pylint: disable = redefined-builtin
88
""" Class for :mod:`~multiformats.multiaddr` key errors. """
9-
...
9+
1010

1111
class MultiaddrValueError(builtins.ValueError): # pylint: disable = redefined-builtin
1212
""" Class for :mod:`~multiformats.multiaddr` value errors. """
13-
...

multiformats/multibase/__init__.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class Multibase:
3939
4040
:param name: the multibase name
4141
:type name: :obj:`str`
42-
:param code: the multibase code, as single-char string or ``0xYZ`` hex-string of a byte
42+
:param code: the multibase code, as single-char string or ``0x...`` hex-string of a non-empty bytestring
4343
:type code: :obj:`str`
4444
:param status: the multibase status
4545
:type status: ``'draft'``, ``'candidate'`` or ``'default'``, *optional*
@@ -91,20 +91,20 @@ def validate_code(code: str) -> str:
9191
MultibaseValueError: Multibase codes must be single-character strings
9292
or the hex digits '0xYZ' of a single byte.
9393
94-
:param code: the multibase code, as single character or ``0xYZ`` hex-string of a single byte
94+
:param code: the multibase code, as single character or ``0x...`` hex-string of a non-empty bytestring
9595
:type code: :obj:`str`
9696
9797
:raises ValueError: if the code is invalid
9898
9999
"""
100100
validate(code, str)
101-
if re.match(r"^0x[0-9a-zA-Z][0-9a-zA-Z]$", code):
101+
if re.match(r"^0x([0-9a-zA-Z][0-9a-zA-Z])+$", code):
102102
ord_code = int(code, base=16)
103+
if ord_code in range(0x20, 0x7F):
104+
raise MultibaseValueError("Multibase codes in hex format cannot be printable ASCII characters.")
103105
code = chr(ord_code)
104106
elif len(code) != 1:
105-
raise MultibaseValueError("Multibase codes must be single-character strings or the hex digits '0xYZ' of a single byte.")
106-
if ord(code) not in range(0x00, 0x80):
107-
raise MultibaseValueError("Multibase codes must be ASCII characters.")
107+
raise MultibaseValueError("Multibase codes must be single-character strings or the hex digits '0x...' of a non-empty bytestring.")
108108
return code
109109

110110
@staticmethod
@@ -145,7 +145,9 @@ def code_printable(self) -> str:
145145
code = self.code
146146
ord_code = ord(code)
147147
if ord_code not in range(0x20, 0x7F):
148-
return "0x"+base16.encode(bytes([ord_code]))
148+
ord_code_num_bytes = max(1, math.ceil(ord_code.bit_length()/8))
149+
ord_code_bytes = ord_code.to_bytes(ord_code_num_bytes, byteorder="big")
150+
return "0x"+base16.encode(ord_code_bytes)
149151
return code
150152

151153
@property
@@ -555,6 +557,6 @@ def build_multibase_tables(bases: Iterable[Multibase]) -> Tuple[Dict[str, Multib
555557
# Create the global code->multibase and name->multibase mappings.
556558
_code_table: Dict[str, Multibase]
557559
_name_table: Dict[str, Multibase]
558-
with importlib_resources.open_text("multiformats.multibase", "multibase-table.json") as _table_f:
560+
with importlib_resources.open_text("multiformats.multibase", "multibase-table.json", encoding="utf8") as _table_f:
559561
_table_json = json.load(_table_f)
560562
_code_table, _name_table = build_multibase_tables(Multibase(**row) for row in _table_json)

0 commit comments

Comments
 (0)