pynostr


Namepynostr JSON
Version 0.6.2 PyPI version JSON
download
home_page
SummaryPython Library for nostr.
upload_time2023-03-16 20:54:02
maintainer
docs_urlNone
author
requires_python>3.7.0
licenseMIT License Copyright (c) 2023 Holger Nahrstaedt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords nostr
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pynostr

| | |
| --- | --- |
| CI/CD | [![codecov](https://codecov.io/gh/holgern/pynostr/branch/main/graph/badge.svg?token=jIyk1cnhIx)](https://codecov.io/gh/holgern/pynostr) [![CircleCI](https://dl.circleci.com/status-badge/img/gh/holgern/pynostr/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/holgern/pynostr/tree/main) |
| Package | [![PyPI - Version](https://img.shields.io/pypi/v/pynostr.svg?logo=pypi&label=PyPI&logoColor=gold)](https://pypi.org/project/pynostr/) [![PyPI - Downloads](https://img.shields.io/pypi/dm/pynostr.svg?color=blue&label=Downloads&logo=pypi&logoColor=gold)](https://pypi.org/project/pynostr/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pynostr.svg?logo=python&label=Python&logoColor=gold)](https://pypi.org/project/pynostr/) |

-----

Python library for for [Nostr](https://github.com/nostr-protocol/nostr).

This library is using coincurve instead of secp256k1, so pynostr can be used on windows. pynostr started as a fork from [python-nostr](https://github.com/jeffthibault/python-nostr)
and is now developed on its own.

This library works with python >= 3.7

## Features

[NIPs](https://github.com/nostr-protocol/nips) with a relay-specific implementation are listed here.

- [x] NIP-01: Basic protocol flow description
- [x] NIP-02: Contact List and Petnames
- [x] NIP-03: OpenTimestamps Attestations for Events
- [x] NIP-04: Encrypted Direct Message
- [x] NIP-05: Mapping Nostr keys to DNS-based internet identifiers
- [ ] NIP-06: Basic key derivation from mnemonic seed phrase
- [ ] NIP-08: Handling Mentions
- [ ] NIP-09: Event Deletion
- [x] NIP-10: Conventions for clients' use of e and p tags in text events
- [x] NIP-11: Relay Information Document
- [ ] NIP-12: Generic Tag Queries
- [x] NIP-13: Proof of Work
- [ ] NIP-14: Subject tag in text events.
- [x] NIP-15: End of Stored Events Notice
- [ ] NIP-16: Event Treatment
- [x] NIP-19: bech32-encoded entities
- [ ] NIP-20: Command Results
- [ ] NIP-21: nostr: URL scheme
- [ ] NIP-22: Event created_at Limits
- [ ] NIP-23: Long-form Content
- [ ] NIP-25: Reactions
- [x] NIP-26: Delegated Event Signing
- [ ] NIP-28: Public Chat
- [ ] NIP-33: Parameterized Replaceable Events
- [ ] NIP-36: Sensitive Content
- [ ] NIP-40: Expiration Timestamp
- [ ] NIP-42: Authentication of clients to relays
- [ ] NIP-46: Nostr Connect
- [ ] NIP-50: Keywords filter
- [x] NIP-56: Reporting
- [ ] NIP-57: Lightning Zaps
- [ ] NIP-58: Badges
- [x] NIP-65: Relay List Metadata

## Differences from python-nostr

* tornado websockets
* coincurve secp256k1 implementation
* no proxies
* no ssl_options
* relay can be used to open a connection to a relay

| python-nostr | pynostr |
| --- | --- |
| Filter | Filters |
| Filters | FiltersList |
| relay_manager.open_connections | relay_manager.run_sync() |
| relay_manager.close_connections() | - |
| private_key.sign_event(event) | event.sign(private_key.hex()) |



## Installation
```bash
pip install pynostr
```
with websocket-client support
```bash
pip install pynostr[websocket-client]
```
The necessary coincurve can be installed on android inside termux:
```bash
pkg update
pkg install build-essential
pkg install binutils
pkg install python-cryptography
pip install coincurve --no-binary all
```

## Usage
**Generate a key**
```python
from pynostr.key import PrivateKey

private_key = PrivateKey()
public_key = private_key.public_key
print(f"Private key: {private_key.bech32()}")
print(f"Public key: {public_key.bech32()}")
```

**Connect to relays**
```python
from pynostr.relay_manager import RelayManager
from pynostr.filters import FiltersList, Filters
from pynostr.event import EventKind
import time
import uuid

relay_manager = RelayManager(timeout=2)
relay_manager.add_relay("wss://nostr-pub.wellorder.net")
relay_manager.add_relay("wss://relay.damus.io")
filters = FiltersList([Filters(kinds=[EventKind.TEXT_NOTE], limit=100)])
subscription_id = uuid.uuid1().hex
relay_manager.add_subscription_on_all_relays(subscription_id, filters)
relay_manager.run_sync()
while relay_manager.message_pool.has_notices():
    notice_msg = relay_manager.message_pool.get_notice()
    print(notice_msg.content)
while relay_manager.message_pool.has_events():
    event_msg = relay_manager.message_pool.get_event()
    print(event_msg.event.content)
relay_manager.close_all_relay_connections()
```

**Connect to single relay**
```python
from pynostr.relay import Relay
from pynostr.filters import FiltersList, Filters
from pynostr.event import EventKind
from pynostr.base_relay import RelayPolicy
from pynostr.message_pool import MessagePool
import tornado.ioloop
from tornado import gen
import time
import uuid

message_pool = MessagePool(first_response_only=False)
policy = RelayPolicy()
io_loop = tornado.ioloop.IOLoop.current()
r = Relay(
    "wss://relay.damus.io",
    message_pool,
    io_loop,
    policy,
    timeout=2
)
filters = FiltersList([Filters(kinds=[EventKind.TEXT_NOTE], limit=100)])
subscription_id = uuid.uuid1().hex

r.add_subscription(subscription_id, filters)

try:
    io_loop.run_sync(r.connect)
except gen.Return:
    pass
io_loop.stop()

while message_pool.has_notices():
    notice_msg = message_pool.get_notice()
    print(notice_msg.content)
while message_pool.has_events():
    event_msg = message_pool.get_event()
    print(event_msg.event.content)
```


**Publish to relays**
```python
import json
import ssl
import time
import uuid
from pynostr.event import Event
from pynostr.relay_manager import RelayManager
from pynostr.filters import FiltersList, Filters
from pynostr.message_type import ClientMessageType
from pynostr.key import PrivateKey

relay_manager = RelayManager(timeout=6)
relay_manager.add_relay("wss://nostr-pub.wellorder.net")
relay_manager.add_relay("wss://relay.damus.io")
private_key = PrivateKey()

filters = FiltersList([Filters(authors=[private_key.public_key.hex()], limit=100)])
subscription_id = uuid.uuid1().hex
relay_manager.add_subscription_on_all_relays(subscription_id, filters)

event = Event("Hello Nostr")
event.sign(private_key.hex())

relay_manager.publish_event(event)
relay_manager.run_sync()
time.sleep(5) # allow the messages to send
while relay_manager.message_pool.has_ok_notices():
    ok_msg = relay_manager.message_pool.get_ok_notice()
    print(ok_msg)
while relay_manager.message_pool.has_events():
    event_msg = relay_manager.message_pool.get_event()
    print(event_msg.event.to_dict())

```

**Reply to a note**
```python
from pynostr.event import Event
reply = Event(
  content="Sounds good!",
)
# create 'e' tag reference to the note you're replying to
reply.add_event_ref(original_note_id)
# create 'p' tag reference to the pubkey you're replying to
reply.add_pubkey_ref(original_note_author_pubkey)
reply.sign(private_key.hex())
```

**Send a DM**
```python
from pynostr.encrypted_dm import EncryptedDirectMessage
from pynostr.key import PrivateKey
private_key = PrivateKey()
recipient_pubkey = PrivateKey().public_key.hex()
dm = EncryptedDirectMessage()
dm.encrypt(private_key.hex(),
  recipient_pubkey=recipient_pubkey,
  cleartext_content="Secret message!"
)
dm_event = dm.to_event()
dm_event.sign(private_key.hex())
```

**NIP-26 delegation**
```python
from pynostr.delegation import Delegation
from pynostr.event import EventKind, Event
from pynostr.key import PrivateKey

# Load your "identity" PK that you'd like to keep safely offline
identity_pk = PrivateKey.from_nsec("nsec1...")

# Create a new, disposable PK as the "delegatee" that can be "hot" in a Nostr client
delegatee_pk = PrivateKey()

# the "identity" PK will authorize "delegatee" to sign TEXT_NOTEs on its behalf for the next month
delegation = Delegation(
    delegator_pubkey=identity_pk.public_key.hex(),
    delegatee_pubkey=delegatee_pk.public_key.hex(),
    event_kind=EventKind.TEXT_NOTE,
    duration_secs=30*24*60*60
)

identity_pk.sign_delegation(delegation)

event = Event(
    "Hello, NIP-26!",
    tags=[delegation.get_tag()],
)
event.sign(self.delegatee_pk.hex())

# ...normal broadcast steps...
```
**NIP-13: Proof of Work**
```python
from pynostr.event import Event
from pynostr.pow import PowEvent
pe = PowEvent(difficulty=25)
e=Event()
e=pe.mine(e)
assert pe.check_difficulty(e)
```

## Test Suite

### Set up the test environment

Install the test-runner dependencies:
```
pip3 install -r test-requirements.txt
```

Then make the `pynostr` python module visible/importable to the tests by installing the local dev dir as an editable module:
```
# from the repo root
pip3 install -e .
```

### Running the test suite
Run the whole test suite:
```
# from the repo root
pytest
```

Run a specific test file:
```
pytest test/test_this_file.py
```

Run a specific test:
```
pytest test/test_this_file.py::test_this_specific_test
```

### Running tests with tox

Install tox

```
pip install tox
```

Run tests

```
tox
```

## Pre-commit-config

### Installation

```
$ pip install pre-commit
```

### Using homebrew:
```
$ brew install pre-commit
```

```
$ pre-commit --version
pre-commit 2.10.0
```

### Install the git hook scripts

```
$ pre-commit install
```

### Run against all the files
```
pre-commit run --all-files
pre-commit run --show-diff-on-failure --color=always --all-files
```

### Update package rev in pre-commit yaml
```bash
pre-commit autoupdate
pre-commit run --show-diff-on-failure --color=always --all-files
```

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "pynostr",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">3.7.0",
    "maintainer_email": "",
    "keywords": "nostr",
    "author": "",
    "author_email": "Holger Nahrstaedt <nahrstaedt@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/08/b6/818c072bd98c6472c305fa0ce9822592a3c8601ebe550b02465404fa629b/pynostr-0.6.2.tar.gz",
    "platform": null,
    "description": "# pynostr\n\n| | |\n| --- | --- |\n| CI/CD | [![codecov](https://codecov.io/gh/holgern/pynostr/branch/main/graph/badge.svg?token=jIyk1cnhIx)](https://codecov.io/gh/holgern/pynostr) [![CircleCI](https://dl.circleci.com/status-badge/img/gh/holgern/pynostr/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/holgern/pynostr/tree/main) |\n| Package | [![PyPI - Version](https://img.shields.io/pypi/v/pynostr.svg?logo=pypi&label=PyPI&logoColor=gold)](https://pypi.org/project/pynostr/) [![PyPI - Downloads](https://img.shields.io/pypi/dm/pynostr.svg?color=blue&label=Downloads&logo=pypi&logoColor=gold)](https://pypi.org/project/pynostr/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pynostr.svg?logo=python&label=Python&logoColor=gold)](https://pypi.org/project/pynostr/) |\n\n-----\n\nPython library for for [Nostr](https://github.com/nostr-protocol/nostr).\n\nThis library is using coincurve instead of secp256k1, so pynostr can be used on windows. pynostr started as a fork from [python-nostr](https://github.com/jeffthibault/python-nostr)\nand is now developed on its own.\n\nThis library works with python >= 3.7\n\n## Features\n\n[NIPs](https://github.com/nostr-protocol/nips) with a relay-specific implementation are listed here.\n\n- [x] NIP-01: Basic protocol flow description\n- [x] NIP-02: Contact List and Petnames\n- [x] NIP-03: OpenTimestamps Attestations for Events\n- [x] NIP-04: Encrypted Direct Message\n- [x] NIP-05: Mapping Nostr keys to DNS-based internet identifiers\n- [ ] NIP-06: Basic key derivation from mnemonic seed phrase\n- [ ] NIP-08: Handling Mentions\n- [ ] NIP-09: Event Deletion\n- [x] NIP-10: Conventions for clients' use of e and p tags in text events\n- [x] NIP-11: Relay Information Document\n- [ ] NIP-12: Generic Tag Queries\n- [x] NIP-13: Proof of Work\n- [ ] NIP-14: Subject tag in text events.\n- [x] NIP-15: End of Stored Events Notice\n- [ ] NIP-16: Event Treatment\n- [x] NIP-19: bech32-encoded entities\n- [ ] NIP-20: Command Results\n- [ ] NIP-21: nostr: URL scheme\n- [ ] NIP-22: Event created_at Limits\n- [ ] NIP-23: Long-form Content\n- [ ] NIP-25: Reactions\n- [x] NIP-26: Delegated Event Signing\n- [ ] NIP-28: Public Chat\n- [ ] NIP-33: Parameterized Replaceable Events\n- [ ] NIP-36: Sensitive Content\n- [ ] NIP-40: Expiration Timestamp\n- [ ] NIP-42: Authentication of clients to relays\n- [ ] NIP-46: Nostr Connect\n- [ ] NIP-50: Keywords filter\n- [x] NIP-56: Reporting\n- [ ] NIP-57: Lightning Zaps\n- [ ] NIP-58: Badges\n- [x] NIP-65: Relay List Metadata\n\n## Differences from python-nostr\n\n* tornado websockets\n* coincurve secp256k1 implementation\n* no proxies\n* no ssl_options\n* relay can be used to open a connection to a relay\n\n| python-nostr | pynostr |\n| --- | --- |\n| Filter | Filters |\n| Filters | FiltersList |\n| relay_manager.open_connections | relay_manager.run_sync() |\n| relay_manager.close_connections() | - |\n| private_key.sign_event(event) | event.sign(private_key.hex()) |\n\n\n\n## Installation\n```bash\npip install pynostr\n```\nwith websocket-client support\n```bash\npip install pynostr[websocket-client]\n```\nThe necessary coincurve can be installed on android inside termux:\n```bash\npkg update\npkg install build-essential\npkg install binutils\npkg install python-cryptography\npip install coincurve --no-binary all\n```\n\n## Usage\n**Generate a key**\n```python\nfrom pynostr.key import PrivateKey\n\nprivate_key = PrivateKey()\npublic_key = private_key.public_key\nprint(f\"Private key: {private_key.bech32()}\")\nprint(f\"Public key: {public_key.bech32()}\")\n```\n\n**Connect to relays**\n```python\nfrom pynostr.relay_manager import RelayManager\nfrom pynostr.filters import FiltersList, Filters\nfrom pynostr.event import EventKind\nimport time\nimport uuid\n\nrelay_manager = RelayManager(timeout=2)\nrelay_manager.add_relay(\"wss://nostr-pub.wellorder.net\")\nrelay_manager.add_relay(\"wss://relay.damus.io\")\nfilters = FiltersList([Filters(kinds=[EventKind.TEXT_NOTE], limit=100)])\nsubscription_id = uuid.uuid1().hex\nrelay_manager.add_subscription_on_all_relays(subscription_id, filters)\nrelay_manager.run_sync()\nwhile relay_manager.message_pool.has_notices():\n    notice_msg = relay_manager.message_pool.get_notice()\n    print(notice_msg.content)\nwhile relay_manager.message_pool.has_events():\n    event_msg = relay_manager.message_pool.get_event()\n    print(event_msg.event.content)\nrelay_manager.close_all_relay_connections()\n```\n\n**Connect to single relay**\n```python\nfrom pynostr.relay import Relay\nfrom pynostr.filters import FiltersList, Filters\nfrom pynostr.event import EventKind\nfrom pynostr.base_relay import RelayPolicy\nfrom pynostr.message_pool import MessagePool\nimport tornado.ioloop\nfrom tornado import gen\nimport time\nimport uuid\n\nmessage_pool = MessagePool(first_response_only=False)\npolicy = RelayPolicy()\nio_loop = tornado.ioloop.IOLoop.current()\nr = Relay(\n    \"wss://relay.damus.io\",\n    message_pool,\n    io_loop,\n    policy,\n    timeout=2\n)\nfilters = FiltersList([Filters(kinds=[EventKind.TEXT_NOTE], limit=100)])\nsubscription_id = uuid.uuid1().hex\n\nr.add_subscription(subscription_id, filters)\n\ntry:\n    io_loop.run_sync(r.connect)\nexcept gen.Return:\n    pass\nio_loop.stop()\n\nwhile message_pool.has_notices():\n    notice_msg = message_pool.get_notice()\n    print(notice_msg.content)\nwhile message_pool.has_events():\n    event_msg = message_pool.get_event()\n    print(event_msg.event.content)\n```\n\n\n**Publish to relays**\n```python\nimport json\nimport ssl\nimport time\nimport uuid\nfrom pynostr.event import Event\nfrom pynostr.relay_manager import RelayManager\nfrom pynostr.filters import FiltersList, Filters\nfrom pynostr.message_type import ClientMessageType\nfrom pynostr.key import PrivateKey\n\nrelay_manager = RelayManager(timeout=6)\nrelay_manager.add_relay(\"wss://nostr-pub.wellorder.net\")\nrelay_manager.add_relay(\"wss://relay.damus.io\")\nprivate_key = PrivateKey()\n\nfilters = FiltersList([Filters(authors=[private_key.public_key.hex()], limit=100)])\nsubscription_id = uuid.uuid1().hex\nrelay_manager.add_subscription_on_all_relays(subscription_id, filters)\n\nevent = Event(\"Hello Nostr\")\nevent.sign(private_key.hex())\n\nrelay_manager.publish_event(event)\nrelay_manager.run_sync()\ntime.sleep(5) # allow the messages to send\nwhile relay_manager.message_pool.has_ok_notices():\n    ok_msg = relay_manager.message_pool.get_ok_notice()\n    print(ok_msg)\nwhile relay_manager.message_pool.has_events():\n    event_msg = relay_manager.message_pool.get_event()\n    print(event_msg.event.to_dict())\n\n```\n\n**Reply to a note**\n```python\nfrom pynostr.event import Event\nreply = Event(\n  content=\"Sounds good!\",\n)\n# create 'e' tag reference to the note you're replying to\nreply.add_event_ref(original_note_id)\n# create 'p' tag reference to the pubkey you're replying to\nreply.add_pubkey_ref(original_note_author_pubkey)\nreply.sign(private_key.hex())\n```\n\n**Send a DM**\n```python\nfrom pynostr.encrypted_dm import EncryptedDirectMessage\nfrom pynostr.key import PrivateKey\nprivate_key = PrivateKey()\nrecipient_pubkey = PrivateKey().public_key.hex()\ndm = EncryptedDirectMessage()\ndm.encrypt(private_key.hex(),\n  recipient_pubkey=recipient_pubkey,\n  cleartext_content=\"Secret message!\"\n)\ndm_event = dm.to_event()\ndm_event.sign(private_key.hex())\n```\n\n**NIP-26 delegation**\n```python\nfrom pynostr.delegation import Delegation\nfrom pynostr.event import EventKind, Event\nfrom pynostr.key import PrivateKey\n\n# Load your \"identity\" PK that you'd like to keep safely offline\nidentity_pk = PrivateKey.from_nsec(\"nsec1...\")\n\n# Create a new, disposable PK as the \"delegatee\" that can be \"hot\" in a Nostr client\ndelegatee_pk = PrivateKey()\n\n# the \"identity\" PK will authorize \"delegatee\" to sign TEXT_NOTEs on its behalf for the next month\ndelegation = Delegation(\n    delegator_pubkey=identity_pk.public_key.hex(),\n    delegatee_pubkey=delegatee_pk.public_key.hex(),\n    event_kind=EventKind.TEXT_NOTE,\n    duration_secs=30*24*60*60\n)\n\nidentity_pk.sign_delegation(delegation)\n\nevent = Event(\n    \"Hello, NIP-26!\",\n    tags=[delegation.get_tag()],\n)\nevent.sign(self.delegatee_pk.hex())\n\n# ...normal broadcast steps...\n```\n**NIP-13: Proof of Work**\n```python\nfrom pynostr.event import Event\nfrom pynostr.pow import PowEvent\npe = PowEvent(difficulty=25)\ne=Event()\ne=pe.mine(e)\nassert pe.check_difficulty(e)\n```\n\n## Test Suite\n\n### Set up the test environment\n\nInstall the test-runner dependencies:\n```\npip3 install -r test-requirements.txt\n```\n\nThen make the `pynostr` python module visible/importable to the tests by installing the local dev dir as an editable module:\n```\n# from the repo root\npip3 install -e .\n```\n\n### Running the test suite\nRun the whole test suite:\n```\n# from the repo root\npytest\n```\n\nRun a specific test file:\n```\npytest test/test_this_file.py\n```\n\nRun a specific test:\n```\npytest test/test_this_file.py::test_this_specific_test\n```\n\n### Running tests with tox\n\nInstall tox\n\n```\npip install tox\n```\n\nRun tests\n\n```\ntox\n```\n\n## Pre-commit-config\n\n### Installation\n\n```\n$ pip install pre-commit\n```\n\n### Using homebrew:\n```\n$ brew install pre-commit\n```\n\n```\n$ pre-commit --version\npre-commit 2.10.0\n```\n\n### Install the git hook scripts\n\n```\n$ pre-commit install\n```\n\n### Run against all the files\n```\npre-commit run --all-files\npre-commit run --show-diff-on-failure --color=always --all-files\n```\n\n### Update package rev in pre-commit yaml\n```bash\npre-commit autoupdate\npre-commit run --show-diff-on-failure --color=always --all-files\n```\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2023 Holger Nahrstaedt  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "Python Library for nostr.",
    "version": "0.6.2",
    "split_keywords": [
        "nostr"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "674cd76378abc44c15375708cb3eb8ee9f199879b905b4c2ceda9ea108dfae79",
                "md5": "bdcf3732218a4cf35a23093cce0afc6a",
                "sha256": "d43fb236c73174093275ee0080b2f8ed17e974b2b516f0d73da4c9a3e908ddc5"
            },
            "downloads": -1,
            "filename": "pynostr-0.6.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "bdcf3732218a4cf35a23093cce0afc6a",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">3.7.0",
            "size": 36301,
            "upload_time": "2023-03-16T20:54:01",
            "upload_time_iso_8601": "2023-03-16T20:54:01.055073Z",
            "url": "https://files.pythonhosted.org/packages/67/4c/d76378abc44c15375708cb3eb8ee9f199879b905b4c2ceda9ea108dfae79/pynostr-0.6.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "08b6818c072bd98c6472c305fa0ce9822592a3c8601ebe550b02465404fa629b",
                "md5": "aa7b075fc00e60186f6a9369259a8b81",
                "sha256": "2974ea05b3ff41a1a4060e3b1813eb0ce0e60c0b81fbe668afaa65164c7f82f4"
            },
            "downloads": -1,
            "filename": "pynostr-0.6.2.tar.gz",
            "has_sig": false,
            "md5_digest": "aa7b075fc00e60186f6a9369259a8b81",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">3.7.0",
            "size": 52310,
            "upload_time": "2023-03-16T20:54:02",
            "upload_time_iso_8601": "2023-03-16T20:54:02.826512Z",
            "url": "https://files.pythonhosted.org/packages/08/b6/818c072bd98c6472c305fa0ce9822592a3c8601ebe550b02465404fa629b/pynostr-0.6.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-03-16 20:54:02",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "lcname": "pynostr"
}
        
Elapsed time: 0.04894s