From a4343c3eb384684b4bb973cd3e3a539972f81e35 Mon Sep 17 00:00:00 2001 From: Roger Ostrander Date: Sat, 3 Feb 2018 23:08:15 -0500 Subject: [PATCH 1/4] API call to blob_list with uri parameter now succeeds --- lbrynet/core/utils.py | 25 ++++++++++++++- lbrynet/daemon/Daemon.py | 5 ++- lbrynet/tests/unit/core/test_utils.py | 44 +++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/lbrynet/core/utils.py b/lbrynet/core/utils.py index 3fc867f4e..7d9683224 100644 --- a/lbrynet/core/utils.py +++ b/lbrynet/core/utils.py @@ -134,8 +134,31 @@ def get_sd_hash(stream_info): return None if isinstance(stream_info, ClaimDict): return stream_info.source_hash - return stream_info['stream']['source']['source'] + path = ['claim', 'value', 'stream', 'source', 'source'] + result = safe_dict_descend(stream_info, *path) + if not result: + log.warn("Unable to get sd_hash via path %s" % path) + return result def json_dumps_pretty(obj, **kwargs): return json.dumps(obj, sort_keys=True, indent=2, separators=(',', ': '), **kwargs) + + +def safe_dict_descend(source, *path): + """ + For when you want to do something like + stream_info['claim']['value']['stream']['source']['source']" + but don't trust that every last one of those keys exists + """ + cur_source = source + for path_entry in path: + try: + if path_entry not in cur_source: + return None + except TypeError: + # This happens if we try to keep going along a path that isn't + # a dictionary (see e.g. test_safe_dict_descend_typeerror) + return None + cur_source = cur_source[path_entry] + return cur_source diff --git a/lbrynet/daemon/Daemon.py b/lbrynet/daemon/Daemon.py index d19ce92b7..e65c76f9a 100644 --- a/lbrynet/daemon/Daemon.py +++ b/lbrynet/daemon/Daemon.py @@ -2881,7 +2881,10 @@ class Daemon(AuthJSONRPCServer): if uri: metadata = yield self._resolve_name(uri) sd_hash = utils.get_sd_hash(metadata) - blobs = yield self.get_blobs_for_sd_hash(sd_hash) + try: + blobs = yield self.get_blobs_for_sd_hash(sd_hash) + except NoSuchSDHash: + blobs = [] elif stream_hash: try: blobs = yield self.get_blobs_for_stream_hash(stream_hash) diff --git a/lbrynet/tests/unit/core/test_utils.py b/lbrynet/tests/unit/core/test_utils.py index b7eecea60..4d55736d4 100644 --- a/lbrynet/tests/unit/core/test_utils.py +++ b/lbrynet/tests/unit/core/test_utils.py @@ -31,3 +31,47 @@ class ObfuscationTest(unittest.TestCase): plain = '☃' obf = utils.obfuscate(plain) self.assertEqual(plain, utils.deobfuscate(obf)) + + +class SafeDictDescendTest(unittest.TestCase): + + def test_safe_dict_descend_happy(self): + nested = { + 'foo': { + 'bar': { + 'baz': 3 + } + } + } + self.assertEqual( + utils.safe_dict_descend(nested, 'foo', 'bar', 'baz'), + 3 + ) + + def test_safe_dict_descend_typeerror(self): + nested = { + 'foo': { + 'bar': 7 + } + } + self.assertIsNone(utils.safe_dict_descend(nested, 'foo', 'bar', 'baz')) + + def test_safe_dict_descend_missing(self): + nested = { + 'foo': { + 'barn': 7 + } + } + self.assertIsNone(utils.safe_dict_descend(nested, 'foo', 'bar', 'baz')) + + def test_empty_dict_doesnt_explode(self): + nested = {} + self.assertIsNone(utils.safe_dict_descend(nested, 'foo', 'bar', 'baz')) + + def test_identity(self): + nested = { + 'foo': { + 'bar': 7 + } + } + self.assertIs(nested, utils.safe_dict_descend(nested)) From 3fdde0f4ce08da229090639d173b9bf758bfeef4 Mon Sep 17 00:00:00 2001 From: Roger Ostrander Date: Sat, 3 Feb 2018 23:23:34 -0500 Subject: [PATCH 2/4] Added CHANGELOG entry for issue 895 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 647f1c7bc..238489da5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ at anytime. * Fixed handling decryption error for blobs encrypted with an invalid key * Fixed handling stream with no data blob (https://github.com/lbryio/lbry/issues/905) * Fixed fetching the external ip + * Fixed API call to blob_list with --uri parameter (https://github.com/lbryio/lbry/issues/895) ### Deprecated * `channel_list_mine`, replaced with `channel_list` From d8e1738f27912ede75cf9895e117e910027e4031 Mon Sep 17 00:00:00 2001 From: Roger Ostrander Date: Tue, 6 Feb 2018 01:16:10 -0500 Subject: [PATCH 3/4] Code review changes (removed safe_dict_descend) --- lbrynet/core/utils.py | 28 +++---------- lbrynet/tests/unit/core/test_utils.py | 57 +++++++++++---------------- 2 files changed, 28 insertions(+), 57 deletions(-) diff --git a/lbrynet/core/utils.py b/lbrynet/core/utils.py index 7d9683224..2d295f718 100644 --- a/lbrynet/core/utils.py +++ b/lbrynet/core/utils.py @@ -134,31 +134,15 @@ def get_sd_hash(stream_info): return None if isinstance(stream_info, ClaimDict): return stream_info.source_hash - path = ['claim', 'value', 'stream', 'source', 'source'] - result = safe_dict_descend(stream_info, *path) + result = stream_info.get('claim', {}).\ + get('value', {}).\ + get('stream', {}).\ + get('source', {}).\ + get('source') if not result: - log.warn("Unable to get sd_hash via path %s" % path) + log.warn("Unable to get sd_hash") return result def json_dumps_pretty(obj, **kwargs): return json.dumps(obj, sort_keys=True, indent=2, separators=(',', ': '), **kwargs) - - -def safe_dict_descend(source, *path): - """ - For when you want to do something like - stream_info['claim']['value']['stream']['source']['source']" - but don't trust that every last one of those keys exists - """ - cur_source = source - for path_entry in path: - try: - if path_entry not in cur_source: - return None - except TypeError: - # This happens if we try to keep going along a path that isn't - # a dictionary (see e.g. test_safe_dict_descend_typeerror) - return None - cur_source = cur_source[path_entry] - return cur_source diff --git a/lbrynet/tests/unit/core/test_utils.py b/lbrynet/tests/unit/core/test_utils.py index 4d55736d4..5aa6cf8ae 100644 --- a/lbrynet/tests/unit/core/test_utils.py +++ b/lbrynet/tests/unit/core/test_utils.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from lbrynet.core import utils +from lbryschema.claim import ClaimDict from twisted.trial import unittest @@ -33,45 +34,31 @@ class ObfuscationTest(unittest.TestCase): self.assertEqual(plain, utils.deobfuscate(obf)) -class SafeDictDescendTest(unittest.TestCase): +class SdHashTests(unittest.TestCase): - def test_safe_dict_descend_happy(self): - nested = { - 'foo': { - 'bar': { - 'baz': 3 + def test_none_in_none_out(self): + self.assertIsNone(utils.get_sd_hash(None)) + + def test_ordinary_dict(self): + claim = { + "claim": { + "value": { + "stream": { + "source": { + "source": "0123456789ABCDEF" + } + } } } } - self.assertEqual( - utils.safe_dict_descend(nested, 'foo', 'bar', 'baz'), - 3 - ) + self.assertEqual("0123456789ABCDEF", utils.get_sd_hash(claim)) - def test_safe_dict_descend_typeerror(self): - nested = { - 'foo': { - 'bar': 7 + def test_old_shape_fails(self): + claim = { + "stream": { + "source": { + "source": "0123456789ABCDEF" + } } } - self.assertIsNone(utils.safe_dict_descend(nested, 'foo', 'bar', 'baz')) - - def test_safe_dict_descend_missing(self): - nested = { - 'foo': { - 'barn': 7 - } - } - self.assertIsNone(utils.safe_dict_descend(nested, 'foo', 'bar', 'baz')) - - def test_empty_dict_doesnt_explode(self): - nested = {} - self.assertIsNone(utils.safe_dict_descend(nested, 'foo', 'bar', 'baz')) - - def test_identity(self): - nested = { - 'foo': { - 'bar': 7 - } - } - self.assertIs(nested, utils.safe_dict_descend(nested)) + self.assertIsNone(utils.get_sd_hash(claim)) From 44df26abd34ef127b35470f77fd4174b9afc4e2a Mon Sep 17 00:00:00 2001 From: Roger Ostrander Date: Tue, 6 Feb 2018 01:32:10 -0500 Subject: [PATCH 4/4] Removing unused import --- lbrynet/tests/unit/core/test_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lbrynet/tests/unit/core/test_utils.py b/lbrynet/tests/unit/core/test_utils.py index 5aa6cf8ae..9575108be 100644 --- a/lbrynet/tests/unit/core/test_utils.py +++ b/lbrynet/tests/unit/core/test_utils.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from lbrynet.core import utils -from lbryschema.claim import ClaimDict from twisted.trial import unittest