Skip to content

Commit 2c93c1d

Browse files
authored
Adds initial test framework; adds PrivateKey.from_nsec() (jeffthibault#13)
* Adds initial test framework; adds PrivateKey.from_nsec() * Update setup.py
1 parent b5e99fc commit 2c93c1d

File tree

7 files changed

+93
-2
lines changed

7 files changed

+93
-2
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
venv/
2-
nostr/__pycache__/
2+
__pycache__/
3+
nostr.egg-info/

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,13 @@ pip install -r requirements.txt
114114

115115
Note: I wrote this with Python 3.9.5.
116116

117+
## Test Suite
118+
See the [Test Suite README](test/README.md)
119+
117120
## Disclaimer
118121
- This library is in very early development and still a WIP.
119122
- It might have some bugs.
120-
- I need to add tests.
123+
- I need to add more tests.
121124
- I will try to publish this as a [PyPI](https://pypi.org/) package at some point.
122125

123126
Please feel free to add issues, add PRs, or provide any feedback!

nostr/key.py

+11
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ def __init__(self, raw_secret: bytes=None) -> None:
3131
sk = secp256k1.PrivateKey(self.raw_secret)
3232
self.public_key = PublicKey(sk.pubkey.serialize()[1:])
3333

34+
@classmethod
35+
def from_nsec(cls, nsec: str):
36+
""" Load a PrivateKey from its bech32/nsec form """
37+
hrp, data, spec = bech32.bech32_decode(nsec)
38+
raw_secret = bech32.convertbits(data, 5, 8)[:-1]
39+
return cls(bytes(raw_secret))
40+
3441
def bech32(self) -> str:
3542
converted_bits = bech32.convertbits(self.raw_secret, 8, 5)
3643
return bech32.bech32_encode("nsec", converted_bits, bech32.Encoding.BECH32)
@@ -78,6 +85,10 @@ def sign_message_hash(self, hash: bytes) -> str:
7885
sk = secp256k1.PrivateKey(self.raw_secret)
7986
sig = sk.schnorr_sign(hash, None, raw=True)
8087
return sig.hex()
88+
89+
def __eq__(self, other):
90+
return self.raw_secret == other.raw_secret
91+
8192

8293
ffi = FFI()
8394
@ffi.callback("int (unsigned char *, const unsigned char *, const unsigned char *, void *)")

setup.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from setuptools import setup, find_packages
2+
3+
4+
with open("README.md", "r") as f:
5+
long_description = f.read()
6+
7+
setup(
8+
name='nostr',
9+
version="0.0.1",
10+
packages=find_packages(include=['nostr']),
11+
python_requires='>3.6.0',
12+
url='https://github.com/jeffthibault/python-nostr',
13+
description="A Python library for making Nostr clients.",
14+
long_description=long_description,
15+
long_description_content_type="text/markdown",
16+
classifiers=[
17+
'Operating System :: POSIX :: Linux',
18+
'Operating System :: Microsoft :: Windows',
19+
'Operating System :: MacOS :: MacOS X',
20+
],
21+
)

test/README.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Testing python-nostr
2+
3+
## Set up the test environment
4+
5+
Install the test-runner dependencies:
6+
```
7+
pip3 install -r test/requirements.txt
8+
```
9+
10+
Then make the `nostr` python module visible/importable to the tests by installing the local dev dir as an editable module:
11+
```
12+
# from the repo root
13+
pip3 install -e .
14+
```
15+
16+
## Running the test suite
17+
Run the whole test suite:
18+
```
19+
# from the repo root
20+
pytest
21+
```
22+
23+
Run a specific test file:
24+
```
25+
pytest test/test_this_file.py
26+
```
27+
28+
Run a specific test:
29+
```
30+
pytest test/test_this_file.py::test_this_specific_test
31+
```

test/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pytest>=7.2.0

test/test_key.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from nostr.key import PrivateKey
2+
3+
4+
def test_eq_true():
5+
""" __eq__ should return True when PrivateKeys are equal """
6+
pk1 = PrivateKey()
7+
pk2 = PrivateKey(pk1.raw_secret)
8+
assert pk1 == pk2
9+
10+
11+
def test_eq_false():
12+
""" __eq__ should return False when PrivateKeys are not equal """
13+
pk1 = PrivateKey()
14+
pk2 = PrivateKey()
15+
assert pk1.raw_secret != pk2.raw_secret
16+
assert pk1 != pk2
17+
18+
19+
def test_from_nsec():
20+
""" PrivateKey.from_nsec should yield the source's raw_secret """
21+
pk1 = PrivateKey()
22+
pk2 = PrivateKey.from_nsec(pk1.bech32())
23+
assert pk1.raw_secret == pk2.raw_secret

0 commit comments

Comments
 (0)