From 1fc8fe9c58a33a591be40a24e92195a25059f67b Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Mon, 31 Jan 2022 18:24:26 -0500 Subject: [PATCH 1/3] final tests --- tests/fixtures/xumm_api.json | 2 +- tests/fixtures/xumm_ws.py | 3 +- tests/test_common.py | 3 +- tests/test_payload_cancel.py | 3 +- tests/test_payload_create.py | 4 +- tests/test_payload_get.py | 4 +- tests/test_payload_subscribe.py | 155 +++++++++++++++++++++++--------- xumm/client.py | 17 ++-- xumm/resource/payload.py | 45 +++------- xumm/ws_client.py | 5 +- 10 files changed, 145 insertions(+), 96 deletions(-) diff --git a/tests/fixtures/xumm_api.json b/tests/fixtures/xumm_api.json index d6fb695..db92563 100644 --- a/tests/fixtures/xumm_api.json +++ b/tests/fixtures/xumm_api.json @@ -161,7 +161,7 @@ }, "error": { "error": { - "reference": "a61ba59a-0304-44ae-a86e-d74808bd5190", + "reference": "a61ba59a-0304-44ae-a86e-efefegewgew4", "code": 602 } }, diff --git a/tests/fixtures/xumm_ws.py b/tests/fixtures/xumm_ws.py index 485b12c..a4ab653 100644 --- a/tests/fixtures/xumm_ws.py +++ b/tests/fixtures/xumm_ws.py @@ -7,6 +7,7 @@ from xumm.util import read_json import websockets +import time json_fixtures = read_json('./tests/fixtures/xumm_api.json') @@ -39,7 +40,7 @@ async def start_server(ws, path): async def main(): print('STARTING SOCKET') - async with websockets.serve(start_server, "localhost", 8765): + async with websockets.serve(start_server, "127.0.0.1", 8765): print('SERVING SOCKET') await asyncio.Future() # run forever diff --git a/tests/test_common.py b/tests/test_common.py index efb4c5d..bb8ddc5 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -69,8 +69,7 @@ def test_invalid_credentials(cls, mock_get): sdk.ping() cls.fail("ping() raised Exception unexpectedly!") except Exception as e: - cls.assertEqual(e.error['reference'], cls.json_fixtures['invalidCredentials']['error']['reference']) - cls.assertEqual(e.error['code'], cls.json_fixtures['invalidCredentials']['error']['code']) + cls.assertEqual(str(e), 'Error code 813, see XUMM Dev Console, reference: 26279bfe-c7e1-4b12-a680-26119d8f5062') @patch('xumm.client.requests.get') def test_fetch_curated_assets(cls, mock_get): diff --git a/tests/test_payload_cancel.py b/tests/test_payload_cancel.py index 08d2cc3..1b50b2f 100644 --- a/tests/test_payload_cancel.py +++ b/tests/test_payload_cancel.py @@ -50,8 +50,7 @@ def test_payload_not_found_errors(cls, mock_delete): cls.sdk.payload.cancel(payloadId, True) cls.fail("payload_cancel() raised Exception unexpectedly!") except Exception as e: - cls.assertEqual(e.error['reference'], cls.json_fixtures['payload']['notfound']['error']['reference']) - cls.assertEqual(e.error['code'], cls.json_fixtures['payload']['notfound']['error']['code']) + cls.assertEqual(str(e), 'Error code 404, see XUMM Dev Console, reference: a61ba59a-0304-44ae-a86e-d74808bd5190') @patch('xumm.client.requests.delete') @patch('xumm.client.requests.post') diff --git a/tests/test_payload_create.py b/tests/test_payload_create.py index e67c9d4..56b96e7 100644 --- a/tests/test_payload_create.py +++ b/tests/test_payload_create.py @@ -54,6 +54,4 @@ def test_payload_create_invalid_errors(cls, mock_post): cls.sdk.payload.create(test_fixtures.invalid_payload(), True) cls.fail("payload_create() raised Exception unexpectedly!") except Exception as e: - cls.assertEqual(e.error['reference'], cls.json_fixtures['payload']['error']['error']['reference']) - cls.assertEqual(e.error['code'], cls.json_fixtures['payload']['error']['error']['code']) - # cls.assertEqual(e.error['message'], cls.json_fixtures['payload']['error']['error']['message']) + cls.assertEqual(str(e), 'Error code 602, see XUMM Dev Console, reference: a61ba59a-0304-44ae-a86e-efefegewgew4') diff --git a/tests/test_payload_get.py b/tests/test_payload_get.py index f443ab2..9c10cbf 100644 --- a/tests/test_payload_get.py +++ b/tests/test_payload_get.py @@ -61,6 +61,4 @@ def test_payload_get_invalid_errors(cls, mock_get): cls.sdk.payload.get('00000000-0000-4839-af2f-f794874a80b0', True) cls.fail("payload_get() raised Exception unexpectedly!") except Exception as e: - cls.assertEqual(e.error['reference'], cls.json_fixtures['payload']['notfound']['error']['reference']) - cls.assertEqual(e.error['code'], cls.json_fixtures['payload']['notfound']['error']['code']) - # cls.assertEqual(e.error['message'], cls.json_fixtures['payload']['error']['error']['message']) + cls.assertEqual(str(e), 'Error code 404, see XUMM Dev Console, reference: a61ba59a-0304-44ae-a86e-d74808bd5190') diff --git a/tests/test_payload_subscribe.py b/tests/test_payload_subscribe.py index 19aea65..8e2d433 100644 --- a/tests/test_payload_subscribe.py +++ b/tests/test_payload_subscribe.py @@ -1,48 +1,129 @@ #!/usr/bin/env python # coding: utf-8 +from multiprocessing.sharedctypes import Value import sys import time import json -from testing_config import AsyncioTestCase +from testing_config import BaseTestConfig, AsyncioTestCase from tests.fixtures import ( xumm_api as test_fixtures, ) -from tests.fixtures.xumm_ws import main as ws_main from unittest.mock import Mock, patch from xumm.ws_client import WSClient -from typing import Callable import xumm import asyncio +import websockets from threading import Thread, main_thread +from xumm.error import APIError +from xumm.resource.payload import CallbackPromise +COUNT = 0 -import pytest -@pytest.mark.skip(reason="Using Prod Cert") -class TestPayloadSubscribe(AsyncioTestCase): +# import pytest +# @pytest.mark.skip(reason="Using Prod Cert") +class TestPayloadSubscribe(BaseTestConfig): + + server = None + thread = None + + @classmethod + async def start_server(cls, ws, path): + try: + print('MOCK SOCKET OPEN: {}'.format(ws.open)) + + await ws.send(json.dumps(test_fixtures.subscription_updates()['expire'])) # noqa: E501 + print('SENT EXPIRE') + print(test_fixtures.subscription_updates()['expire']) + + await ws.send(json.dumps(test_fixtures.subscription_updates()['opened'])) # noqa: E501 + print('SENT OPENED') + print(test_fixtures.subscription_updates()['opened']) + + await ws.send(json.dumps(test_fixtures.subscription_updates()['rejected'])) # noqa: E501 + print('SENT REJECTED') + print(test_fixtures.subscription_updates()['rejected']) + + await asyncio.sleep(1) + + except KeyboardInterrupt: + ws.close() + + except Exception as e: + print('on_open Error: {}'.format(e)) + ws.close() + + @classmethod + def startup_server(cls): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + start_server = websockets.serve(cls.start_server, "127.0.0.1", 8765) + asyncio.get_event_loop().run_until_complete(start_server) + asyncio.get_event_loop().run_forever() + print('WS RUNNING') @classmethod def setUp(cls): print('SET UP TEST') + + thread = Thread( + target=cls.startup_server, + daemon=True + ) + thread.start() + xumm.env = 'sandbox' cls.sdk = xumm.XummSdk( cls.json_fixtures['api']['key'], cls.json_fixtures['api']['secret'] ) + + print('SDK INIT') def tearDown(cls): print('TEAR DOWN TEST') + # print(ee) + + def _test_callback_promise_result(cls): + callback_promise = CallbackPromise() + callback_promise._resolve({'data': 'something'}) + cls.assertEqual(callback_promise.data, {'data': 'something'}) + cls.assertEqual(callback_promise.error, None) + + def _test_callback_promise_reject(cls): + callback_promise = CallbackPromise() + callback_promise._reject(APIError('Invalid Rejection')) + cls.assertEqual(callback_promise.data, None) + cls.assertEqual(str(callback_promise.error), 'Invalid Rejection') + + def _test_callback_promise_await(cls): + callback_promise = CallbackPromise() + + async def run_pass(cb: CallbackPromise = None): + result = await cb._resolved() + cls.assertEqual(result, {'data': 'something'}) + + callback_promise._resolve({'data': 'something'}) + asyncio.run(run_pass(callback_promise)) + + async def run_fail(cb: CallbackPromise = None): + result = await cb._resolved() + cls.assertEqual(result, None) + + callback_promise._reject(APIError('Invalid Rejection')) + asyncio.run(run_fail(callback_promise)) @patch('xumm.client.requests.get') async def _test_payload_subscribe_inner(cls, mock_get): print('should susbscribe & resolve using inner resolve method @ callback') + mock_get.return_value = Mock(status_code=200) mock_get.return_value.json.return_value = cls.json_fixtures['payload']['get'] def callback_func(event): if 'signed' in event['data']: - return event['resolve'](event['data']) # FIX + return event['resolve'](event['data']) subscription_socket = await cls.sdk.payload.subscribe( '0ef943e9-18ae-4fa2-952a-6f55dce363f0', @@ -63,23 +144,25 @@ def callback_func(event): 'websocket': WSClient.__name__, }) - # cls.assertEqual(subscription_socket.websocket.status(), 101) + cls.assertEqual(subscription_socket.websocket.status(), 101) cls.assertEqual(await subscription_socket.resolved(), test_fixtures.subscription_updates()['rejected']) # expect(wsEol).toEqual(expect.arrayContaining([subscriptionSocket.websocket.readyState])) - cls.sdk.payload.unsubscribe() + time.sleep(3) + @patch('xumm.client.requests.get') async def _test_payload_subscribe_return(cls, mock_get): print('should susbscribe & resolve using return @ callback') mock_get.return_value = Mock(status_code=200) mock_get.return_value.json.return_value = cls.json_fixtures['payload']['get'] - def callback_func(event): - if 'signed' in event['data']: - return event['resolve'](event['data']) # FIX + + def received_ws_message(event): + global COUNT + COUNT = COUNT + 1 subscription_socket = await cls.sdk.payload.subscribe( '0ef943e9-18ae-4fa2-952a-6f55dce363f0', - callback_func, + received_ws_message, ) test_dict = { @@ -96,26 +179,18 @@ def callback_func(event): 'websocket': WSClient.__name__, }) - # cls.assertEqual(subscription_socket.websocket.status(), 101) - - received_messages = 0 - - def received_ws_message(received_messages=received_messages): - received_messages += 1 - - subscription_socket.websocket._on_message = received_ws_message - - time.sleep(1) + cls.assertEqual(subscription_socket.websocket.status(), 101) + # cls.assertEqual(COUNT, 3) subscription_socket.resolve({'dummyObject': True}) - # cls.assertEqual(received_messages, 3) cls.assertEqual(await subscription_socket.resolved(), {'dummyObject': True}) # expect(wsEol).toEqual(expect.arrayContaining([subscriptionSocket.websocket.readyState])) - cls.sdk.payload.unsubscribe() + time.sleep(3) + @patch('xumm.client.requests.get') @patch('xumm.client.requests.post') async def _test_payload_create_subscribe_inner(cls, mock_post, mock_get): - print('should create, susbscribe & resolve using return @ callback') + print('should create, susbscribe & resolve using inner @ callback') mock_post.return_value = Mock(status_code=200) mock_post.return_value.json.return_value = cls.json_fixtures['payload']['created'] mock_get.return_value = Mock(status_code=200) @@ -144,15 +219,17 @@ def callback_func(event): 'websocket': WSClient.__name__, }) - # cls.assertEqual(subscription_socket.websocket.sock.getstatus(), 101) + cls.assertEqual(subscription_socket.websocket.status(), 101) cls.assertEqual(await subscription_socket.resolved(), test_fixtures.subscription_updates()['rejected']) # expect(wsEol).toEqual(expect.arrayContaining([subscriptionSocket.websocket.readyState])) - cls.sdk.payload.unsubscribe() + time.sleep(3) + @patch('xumm.client.requests.get') @patch('xumm.client.requests.post') async def _test_payload_create_subscribe_return(cls, mock_post, mock_get): print('should create, susbscribe & resolve using return @ callback') + mock_post.return_value = Mock(status_code=200) mock_post.return_value.json.return_value = cls.json_fixtures['payload']['created'] mock_get.return_value = Mock(status_code=200) @@ -160,7 +237,7 @@ async def _test_payload_create_subscribe_return(cls, mock_post, mock_get): def callback_func(event): if 'signed' in event['data']: - return event['resolve'](event['data']) # FIX + return event['resolve'](event['data']) subscription_socket = await cls.sdk.payload.subscribe( '0ef943e9-18ae-4fa2-952a-6f55dce363f0', @@ -181,19 +258,13 @@ def callback_func(event): 'websocket': WSClient.__name__, }) - # cls.assertEqual(subscription_socket.websocket.sock.getstatus(), 101) + cls.assertEqual(subscription_socket.websocket.status(), 101) cls.assertEqual(await subscription_socket.resolved(), test_fixtures.subscription_updates()['rejected']) # expect(wsEol).toEqual(expect.arrayContaining([subscriptionSocket.websocket.readyState])) - cls.sdk.payload.unsubscribe() + time.sleep(3) async def _test_payload_subscribe(cls): - def start_server(): - return asyncio.run(ws_main()) - - thread = Thread(target=start_server) - thread.start() - await asyncio.sleep(3) await cls._test_payload_subscribe_inner() @@ -204,13 +275,11 @@ def start_server(): await cls._test_payload_create_subscribe_return() - await asyncio.sleep(2) - return True - def test_test_payload(cls): - loop = asyncio.get_event_loop() + + def test_ws_tests(cls): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) loop.run_until_complete(cls._test_payload_subscribe()) loop.close() - - diff --git a/xumm/client.py b/xumm/client.py index 37f4d7e..7bdd79c 100644 --- a/xumm/client.py +++ b/xumm/client.py @@ -182,20 +182,27 @@ def handle_error_code( :type: Dict[str, object] :return: throws """ + + if 'error' not in json: + raise ValueError('Invalid XUMM API Error') + + if 'code' not in json['error'] or 'reference' not in json['error']: + raise ValueError('Invalid XUMM API Error') + + err = 'Error code {}, see XUMM Dev Console, reference: {}'.format( + json['error']['code'], + json['error']['reference'], + ) + if status_code == 400: - err = json.get('error', 'Bad request') raise error.InvalidRequestError(err, status_code, headers) elif status_code == 401: - err = json.get('error', 'Not authorized') raise error.AuthenticationError(err, status_code, headers) elif status_code == 404: - err = json.get('error', 'Not found') raise error.InvalidRequestError(err, status_code, headers) elif status_code == 500: - err = json.get('error', 'Internal server error') raise error.APIError(err, status_code, headers) else: - err = json.get('error', 'Unknown status code ({})'.format(status_code)) raise error.APIError(err, status_code, headers) diff --git a/xumm/resource/payload.py b/xumm/resource/payload.py index 0864b44..15740d1 100644 --- a/xumm/resource/payload.py +++ b/xumm/resource/payload.py @@ -2,6 +2,7 @@ # coding: utf-8 import logging +import time from typing import Any, Union, Callable from xumm import ( client, @@ -35,58 +36,37 @@ class CallbackPromise: data = None def in_res(cls, args): + # print('RES') cls.data = args return args def in_rej(cls, error): + # print('REJ') cls.error = error return error def __init__(cls): cls.resolve_fn = cls.in_res - cls.reject_fn = cls.in_res + cls.reject_fn = cls.in_rej cls.data = None def _resolve(cls, arg: Any): - cls.resolve_fn(arg) + if not cls.data and not cls.error: + cls.resolve_fn(arg) def _reject(cls, error): - cls.reject_fn(error) + if not cls.data and not cls.error: + cls.reject_fn(error) async def _resolved(cls): while not cls.data and not cls.error: continue if cls.error: - # return {'data': str(cls.error)} return None return cls.data -# class CallbackPromise: - -# resolved = None -# args = None -# kwargs = None - -# def in_res(cls, *args, **kwargs): -# cls.args = args -# cls.kwargs = kwargs -# return cls - -# def __init__(cls, *args, **kwargs): -# cls.resolve_fn = cls.in_res -# cls.data = None - -# def _resolve(cls, *args, **kwargs): -# cls.resolve_fn(*args, **kwargs) - -# async def _resolved(cls): -# while not cls.args or not cls.kwargs: -# continue - -# return cls.args, cls.kwargs - class PayloadResource(XummResource): @@ -246,10 +226,6 @@ async def subscribe( callback_promise = CallbackPromise() payload_details = cls.resolve_payload(payload) - # callback_promise.promise.then(() => { - # cls._conn.disconnect() - # }) - if payload_details: def on_open(connection): @@ -290,17 +266,18 @@ def on_close(): 'Payload {}: Subscription ended (WebSocket closed)' .format(payload_details.meta.uuid) ) + callback_promise._reject('closed') cls._callback = callback cls._conn = WSClient( log_level=logging.DEBUG if env == 'sandbox' else logging.ERROR, - server='ws://localhost:8765' if env == 'sandbox' else 'wss://xumm.app/sign/{}'.format(payload_details.meta.uuid), # noqa: E501 + server='ws://127.0.0.1:8765' if env == 'sandbox' else 'wss://xumm.app/sign/{}'.format(payload_details.meta.uuid), # noqa: E501 on_response=on_message, on_error=on_error, on_close=on_close, on_open=on_open ) - cls._conn.connect() + cls._conn.connect(nowait=False) resp = { 'payload': payload_details.to_dict(), diff --git a/xumm/ws_client.py b/xumm/ws_client.py index fb0fbaa..167b9a0 100644 --- a/xumm/ws_client.py +++ b/xumm/ws_client.py @@ -127,8 +127,9 @@ def status(cls) -> int: Get socket status. :return: """ - if cls.socket.sock: - return cls.socket.sock.getstatus() + if cls.connected.is_set(): + return 101 + return 500 def reconnect(cls) -> None: """ From 656c2ecb983561de5588b7f19549682b25b29a1e Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Mon, 31 Jan 2022 18:27:45 -0500 Subject: [PATCH 2/3] fixup & lint --- xumm/client.py | 6 +++--- xumm/resource/payload.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/xumm/client.py b/xumm/client.py index 7bdd79c..1499dac 100644 --- a/xumm/client.py +++ b/xumm/client.py @@ -184,11 +184,11 @@ def handle_error_code( """ if 'error' not in json: - raise ValueError('Invalid XUMM API Error') + raise ValueError('Error parsing Xumm JSON response: error') if 'code' not in json['error'] or 'reference' not in json['error']: - raise ValueError('Invalid XUMM API Error') - + raise ValueError('Error parsing Xumm JSON response: code/reference') + err = 'Error code {}, see XUMM Dev Console, reference: {}'.format( json['error']['code'], json['error']['reference'], diff --git a/xumm/resource/payload.py b/xumm/resource/payload.py index 15740d1..310eaa1 100644 --- a/xumm/resource/payload.py +++ b/xumm/resource/payload.py @@ -2,7 +2,6 @@ # coding: utf-8 import logging -import time from typing import Any, Union, Callable from xumm import ( client, From 09f39126f12eecaca1ffd26a9138eb11d0b8e77b Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Mon, 31 Jan 2022 18:35:38 -0500 Subject: [PATCH 3/3] RELEASE 1.0.0 --- README.md | 32 ++++++++++++++++---------------- RELEASE.md | 18 +++++++++--------- setup.py | 2 +- tests/test_payload_subscribe.py | 4 ++++ 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 704f95b..3810304 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# XUMM SDK (PYTHON) [![python version](https://badge.fury.io/py/xumm-sdk-py.svg)](https://test.pypi.org/project/xumm-sdk-py-dangell7/) [![GitHub Actions Python status](https://github.com/CASL-AE/xumm-sdk-py/workflows/Python/badge.svg?branch=main)](https://github.com/CASL-AE/xumm-sdk-py/actions) +# XUMM SDK (PYTHON) [![python version](https://badge.fury.io/py/xumm-sdk-py.svg)](https://pypi.org/project/xumm-sdk-py/) [![GitHub Actions Python status](https://github.com/XRPL-Labs/xumm-sdk-py/workflows/Python/badge.svg?branch=main)](https://github.com/XRPL-Labs/xumm-sdk-py/actions) Interact with the XUMM SDK from Python environments. @@ -28,7 +28,7 @@ sdk = xumm.XummSdk('someAppKey', 'someAppSecret') ### Credentials #### In case of backend use -The SDK will look in your environment or dotenv file (`.env`) for the `XUMM_APIKEY` and `XUMM_APISECRET` values. A `.env.sample` file is provided in this repository. A [sample dotenv file looks like this](https://github.com/CASL-AE/xumm-sdk-py/blob/main/.env.sample). Alternatively you can provide your XUMM API Key & Secret by passing them to the XummSdk constructor. +The SDK will look in your environment or dotenv file (`.env`) for the `XUMM_APIKEY` and `XUMM_APISECRET` values. A `.env.sample` file is provided in this repository. A [sample dotenv file looks like this](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/.env.sample). Alternatively you can provide your XUMM API Key & Secret by passing them to the XummSdk constructor. If both your environment and the SDK constructor contain credentials, the values provided to the constructor will be used. @@ -52,7 +52,7 @@ The `ping` method allows you to verify API access (valid credentials) and return pong = sdk.ping() ``` -Returns [``](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/meta/application_details.py#L294): +Returns [``](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/meta/application_details.py#L294): ```python pong.quota # {} pong.application.name # 'My XUMM APP' @@ -71,7 +71,7 @@ populate the "Add Asset" button at the XUMM home screan. curated_assets = sdk.get_curated_assets() ``` -Returns [``](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/meta/curated_assets_response.py#L426): +Returns [``](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/meta/curated_assets_response.py#L426): ```python curated_assets.issuers # [ 'Bitstamp', 'GateHub' ] curated_assets.currencies # [ 'USD', 'BTC', 'EUR', 'ETH' ] @@ -101,7 +101,7 @@ kyc_status = sdk.get_kyc_status('00000000-0000-0000-0000-000000000000') kyc_status = sdk.get_kyc_status('rwu1dgaUq8DCj3ZLFXzRbc1Aco5xLykMMQ') ``` -Returns [``](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/meta/kyc_status_response.py#L66). +Returns [``](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/meta/kyc_status_response.py#L66). ###### Notes on KYC information @@ -120,7 +120,7 @@ live from the XRP ledger, as fetched for you by the XUMM backend. tx_info = sdk.get_transaction(tx_hash) ``` -Returns: [``](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/meta/xrpl_transaction.py#L114). +Returns: [``](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/meta/xrpl_transaction.py#L114). #### App Storage @@ -175,7 +175,7 @@ payload = { As you can see the payload looks like a regular XRPL transaction, wrapped in an `txjson` object, omitting the mandatory `Account`, `Fee` and `Sequence` properties. They will be added containing the correct values when the payload is signed by an app user. -Optionally (besides `txjson`) a payload can contain these properties ([PY definition](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/xumm_api/__init__.py#L836)): +Optionally (besides `txjson`) a payload can contain these properties ([PY definition](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/xumm_api/__init__.py#L836)): - `options` to define payload options like a return URL, expiration, etc. - `custom_meta` to add metadata, user insruction, your own unique ID, ... @@ -265,7 +265,7 @@ To cancel a payload, provide a payload UUID (string), a `` (by perf **Please note**: *if a user already opened the payload in XUMM APP, the payload cannot be cancelled: the user may still be resolving the payload in the XUMM App, and should have a chance to complete that process*. -A response (generic API types [here](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/xumm_api/__init__.py)) looks like: +A response (generic API types [here](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/xumm_api/__init__.py)) looks like: ```python response.result.cancelled # bool response.result.reason # XummCancelReason @@ -303,11 +303,11 @@ sdk.payload.subscribe( If a callback function is not provided, the subscription will stay active until the `.resolve()` method is called manually, eg. based on handling `.websocket.onmessage` events. -When a callback function is provided, for every paylaod specific event the callback function will be called with [``](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/payload/subscription_callback_params.py). The `.data` property contains parsed JSON containing event information. Either by calling `.resolve()` or by returning a non-void value in the *callback function* the subscription will be ended, and the `.resolved` promise will resolve with the value returned or passed to the `.resolve()` method. +When a callback function is provided, for every paylaod specific event the callback function will be called with [``](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/payload/subscription_callback_params.py). The `.data` property contains parsed JSON containing event information. Either by calling `.resolve()` or by returning a non-void value in the *callback function* the subscription will be ended, and the `.resolved` promise will resolve with the value returned or passed to the `.resolve()` method. Resolving (by returning non-void in the callback or calling `resolve()` manually) closes the WebSocket client the XUMM SDK sets up 'under the hood'. -The [``](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/payload/payload_subscription.py) object looks like this: +The [``](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/payload/payload_subscription.py) object looks like this: ```python response.payload # XummPayload @@ -318,10 +318,10 @@ response.websocket # WSClient Examples: -- [Async process after returning data in the callback function](https://github.com/CASL-AE/xumm-sdk-py/blob/main/samples/ws/async_callback.py) -- [Await based on returning data in the callback function](https://github.com/CASL-AE/xumm-sdk-py/blob/main/samples/ws/await_callback.py) -- [Await based on resolving a callback event](https://github.com/CASL-AE/xumm-sdk-py/blob/main/samples/ws/await_event.py) -- [Await based on resolving without using a callback function](https://github.com/CASL-AE/xumm-sdk-py/blob/main/samples/ws/await_no_callback.py) +- [Async process after returning data in the callback function](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/samples/ws/async_callback.py) +- [Await based on returning data in the callback function](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/samples/ws/await_callback.py) +- [Await based on resolving a callback event](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/samples/ws/await_event.py) +- [Await based on resolving without using a callback function](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/samples/ws/await_no_callback.py) ##### sdk.payload.create_subscribe @@ -332,7 +332,7 @@ sdk.payload.create_and_subscribe( ): -> PayloadAndSubscription ``` -The [``](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/payload/payload_and_subscription.py) object is basically a [``](https://github.com/CASL-AE/xumm-sdk-py/blob/main/xumm/resource/types/payload/payload_subscription.py) object with the created payload results in the `created` property: +The [``](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/payload/payload_and_subscription.py) object is basically a [``](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/xumm/resource/types/payload/payload_subscription.py) object with the created payload results in the `created` property: All information that applies on [`sdk.payload.create()`](#sdkpayloadcreate) and [`sdk.payload.create_and_subscribe()`](#sdkpayloadsubscribe) applies. Differences are: @@ -375,4 +375,4 @@ Lint the code using `python3 -m flake8 --output-file=./logs/linter.txt --exclude Build, run, show debug output & watch `dist/samples/dev.py`, compiled from `samples/dev.py` using `python3`. The `samples/dev.py` file is **not included by default**. -[Here's a sample `samples/dev.py` file](https://github.com/CASL-AE/xumm-sdk-py/blob/main/samples/dev.py). +[Here's a sample `samples/dev.py` file](https://github.com/XRPL-Labs/xumm-sdk-py/blob/main/samples/dev.py). diff --git a/RELEASE.md b/RELEASE.md index e5af59c..7a8ff2c 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -5,20 +5,20 @@ The full process for cutting a release is as follows: 0. Checkout a new branch: - `git checkout -b 0.9.9-beta.5` # 1.0.0-release + `git checkout -b 1.0.0` # 1.0.0-release 1. Python / Pip Bumpversion `pip3 install bumpversion` - `bumpversion --current-version 0.9.9-beta.5 minor setup.py xumm/__init__.py` + `bumpversion --current-version 1.0.0 minor setup.py xumm/__init__.py` 2. Change the version in the setup.py file: - `VERSION = "0.9.9-beta.5"` + `VERSION = "1.0.0"` 3. Add, and commit the changes, push up the branch, and open a PR: `git add .` - `git commit -m 'RELEASE 0.9.9-beta.5'` + `git commit -m 'RELEASE 1.0.0'` `git push --set-upstream origin HEAD` 4. Open PR request @@ -29,13 +29,13 @@ The full process for cutting a release is as follows: `git checkout main` 5. Delete `main` branch (Optional): - `git branch -d 0.9.9-beta.5` + `git branch -d 1.0.0` 5. Make a new Git tag that matches the new version (make sure it is associated with the right commit SHA): FIXUP - `git tag -a 0.9.9-beta.5 -m "cut 0.9.9-beta.5"` + `git tag -a 1.0.0 -m "cut 1.0.0"` 7. Push up the tag from `main`: - `git push origin 0.9.9-beta.5` + `git push origin 1.0.0` ## Packaging & Releasing @@ -50,8 +50,8 @@ Build Repo ``` dist/ - xumm-sdk-py-dangell-0.9.9-beta.5-py3-none-any.whl - xumm-sdk-py-dangell-0.9.9-beta.5.tar.gz + xumm-sdk-py-dangell-1.0.0-py3-none-any.whl + xumm-sdk-py-dangell-1.0.0.tar.gz ``` Install Twine diff --git a/setup.py b/setup.py index b81acdf..efb18fe 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from codecs import open NAME = "xumm-sdk-py-dangell7" -VERSION = "0.9.9-beta.5" +VERSION = "1.0.0" # To install the library, run the following # # python setup.py install diff --git a/tests/test_payload_subscribe.py b/tests/test_payload_subscribe.py index 8e2d433..6d88010 100644 --- a/tests/test_payload_subscribe.py +++ b/tests/test_payload_subscribe.py @@ -283,3 +283,7 @@ def test_ws_tests(cls): asyncio.set_event_loop(loop) loop.run_until_complete(cls._test_payload_subscribe()) loop.close() + + cls._test_callback_promise_result() + cls._test_callback_promise_reject() + # cls._test_callback_promise_await()