From 96927ec98518a1838ce002ec90215001f66a5038 Mon Sep 17 00:00:00 2001
From: Jack Robison <jackrobison@lbry.io>
Date: Mon, 29 May 2017 16:38:08 -0400
Subject: [PATCH] remove lbrynet.metadata

---
 CHANGELOG.md                                  |   1 +
 lbrynet/core/PaymentRateManager.py            |   1 +
 lbrynet/lbrynet_daemon/Daemon.py              |   9 +-
 lbrynet/lbrynet_daemon/Downloader.py          |  17 +-
 lbrynet/lbrynet_daemon/ExchangeRateManager.py |  23 +-
 lbrynet/metadata/Fee.py                       |  39 ---
 lbrynet/metadata/Metadata.py                  |  44 ---
 lbrynet/metadata/StructuredDict.py            |  64 ----
 lbrynet/metadata/__init__.py                  |   0
 lbrynet/metadata/fee_schemas.py               |  16 -
 lbrynet/metadata/metadata_schemas.py          | 276 ------------------
 tests/unit/core/test_Metadata.py              | 218 --------------
 .../test_ExchangeRateManager.py               |   5 +-
 13 files changed, 28 insertions(+), 685 deletions(-)
 delete mode 100644 lbrynet/metadata/Fee.py
 delete mode 100644 lbrynet/metadata/Metadata.py
 delete mode 100644 lbrynet/metadata/StructuredDict.py
 delete mode 100644 lbrynet/metadata/__init__.py
 delete mode 100644 lbrynet/metadata/fee_schemas.py
 delete mode 100644 lbrynet/metadata/metadata_schemas.py
 delete mode 100644 tests/unit/core/test_Metadata.py

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 414f1e563..d1323716b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ at anytime.
 
 ### Changed
   * Do not catch base exception in API command resolve
+  * Remove deprecated `lbrynet.metadata` and update what used it to instead use `lbryschema`
   *
 
 ### Fixed
diff --git a/lbrynet/core/PaymentRateManager.py b/lbrynet/core/PaymentRateManager.py
index cdda9b630..f72bb5154 100644
--- a/lbrynet/core/PaymentRateManager.py
+++ b/lbrynet/core/PaymentRateManager.py
@@ -45,6 +45,7 @@ class NegotiatedPaymentRateManager(object):
         """
 
         self.base = base
+        self.min_blob_data_payment_rate = base.min_blob_data_payment_rate
         self.points_paid = 0.0
         self.blob_tracker = availability_tracker
         self.generous = generous if generous is not None else conf.settings['is_generous_host']
diff --git a/lbrynet/lbrynet_daemon/Daemon.py b/lbrynet/lbrynet_daemon/Daemon.py
index 1147e329c..7989f5e9e 100644
--- a/lbrynet/lbrynet_daemon/Daemon.py
+++ b/lbrynet/lbrynet_daemon/Daemon.py
@@ -17,6 +17,7 @@ from twisted.python.failure import Failure
 from lbryschema.claim import ClaimDict
 from lbryschema.uri import parse_lbry_uri
 from lbryschema.error import URIParseError
+from lbryschema.fee import Fee
 
 # TODO: importing this when internet is disabled raises a socket.gaierror
 from lbryum.version import LBRYUM_VERSION
@@ -25,8 +26,6 @@ from lbrynet import conf, analytics
 from lbrynet.conf import LBRYCRD_WALLET, LBRYUM_WALLET, PTC_WALLET
 from lbrynet.reflector import reupload
 from lbrynet.reflector import ServerFactory as reflector_server_factory
-from lbrynet.metadata.Fee import FeeValidator
-from lbrynet.metadata.Metadata import verify_name_characters
 
 from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileSaverFactory
 from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileOpenerFactory
@@ -448,7 +447,7 @@ class Daemon(AuthJSONRPCServer):
                 isinstance(settings[key], setting_type) or
                 (
                     key == "max_key_fee" and
-                    isinstance(FeeValidator(settings[key]).amount, setting_type)
+                    isinstance(Fee(settings[key]).amount, setting_type)
                 )
             )
 
@@ -686,7 +685,7 @@ class Daemon(AuthJSONRPCServer):
 
         publisher = Publisher(self.session, self.lbry_file_manager, self.session.wallet,
                               certificate_id)
-        verify_name_characters(name)
+        parse_lbry_uri(name)
         if bid <= 0.0:
             raise Exception("Invalid bid")
         if not file_path:
@@ -1596,7 +1595,7 @@ class Daemon(AuthJSONRPCServer):
 
         name = resolved['name']
         claim_id = resolved['claim_id']
-        stream_info = resolved['value']
+        stream_info = ClaimDict.load_dict(resolved['value'])
 
         if claim_id in self.streams:
             log.info("Already waiting on lbry://%s to start downloading", name)
diff --git a/lbrynet/lbrynet_daemon/Downloader.py b/lbrynet/lbrynet_daemon/Downloader.py
index 826ee58ef..7e5727ee4 100644
--- a/lbrynet/lbrynet_daemon/Downloader.py
+++ b/lbrynet/lbrynet_daemon/Downloader.py
@@ -3,10 +3,10 @@ import os
 from twisted.internet import defer, threads
 from twisted.internet.task import LoopingCall
 
-from lbrynet.core import utils
+from lbryschema.fee import Fee
+
 from lbrynet.core.Error import InsufficientFundsError, KeyFeeAboveMaxAllowed
 from lbrynet.core.StreamDescriptor import download_sd_blob
-from lbrynet.metadata.Fee import FeeValidator
 from lbrynet.lbryfilemanager.EncryptedFileDownloader import ManagedEncryptedFileDownloaderFactory
 from lbrynet import conf
 
@@ -94,7 +94,7 @@ class GetStream(object):
             log.info("Downloading stream descriptor blob (%i seconds)", self.timeout_counter)
 
     def convert_max_fee(self):
-        max_fee = FeeValidator(self.max_key_fee)
+        max_fee = Fee(self.max_key_fee)
         if max_fee.currency_symbol == "LBC":
             return max_fee.amount
         return self.exchange_rate_manager.to_lbc(self.max_key_fee).amount
@@ -104,15 +104,14 @@ class GetStream(object):
         self.code = next(s for s in STREAM_STAGES if s[0] == status)
 
     def check_fee(self, fee):
-        validated_fee = FeeValidator(fee)
         max_key_fee = self.convert_max_fee()
-        converted_fee = self.exchange_rate_manager.to_lbc(validated_fee).amount
+        converted_fee = self.exchange_rate_manager.to_lbc(fee).amount
         if converted_fee > self.wallet.get_balance():
             raise InsufficientFundsError('Unable to pay the key fee of %s' % converted_fee)
         if converted_fee > max_key_fee:
             raise KeyFeeAboveMaxAllowed('Key fee %s above max allowed %s' % (converted_fee,
                                                                              max_key_fee))
-        return validated_fee
+        return fee
 
     def get_downloader_factory(self, factories):
         for factory in factories:
@@ -165,12 +164,12 @@ class GetStream(object):
         self._running = True
 
         self.set_status(INITIALIZING_CODE, name)
-        self.sd_hash = utils.get_sd_hash(stream_info)
+        self.sd_hash = stream_info.source_hash
 
-        if 'fee' in stream_info['stream']['metadata']:
+        if stream_info.has_fee:
             try:
                 fee = yield threads.deferToThread(self.check_fee,
-                                                  stream_info['stream']['metadata']['fee'])
+                                                  stream_info.source_fee)
             except Exception as err:
                 self._running = False
                 self.finished_deferred.errback(err)
diff --git a/lbrynet/lbrynet_daemon/ExchangeRateManager.py b/lbrynet/lbrynet_daemon/ExchangeRateManager.py
index b553ef5be..68262bed2 100644
--- a/lbrynet/lbrynet_daemon/ExchangeRateManager.py
+++ b/lbrynet/lbrynet_daemon/ExchangeRateManager.py
@@ -5,8 +5,9 @@ import json
 from twisted.internet import defer, threads
 from twisted.internet.task import LoopingCall
 
+from lbryschema.fee import Fee
+
 from lbrynet import conf
-from lbrynet.metadata.Fee import FeeValidator
 from lbrynet.core.Error import InvalidExchangeRateResponse
 
 log = logging.getLogger(__name__)
@@ -203,14 +204,14 @@ class ExchangeRateManager(object):
     def to_lbc(self, fee):
         if fee is None:
             return None
-        if not isinstance(fee, FeeValidator):
-            fee_in = FeeValidator(fee)
+        if not isinstance(fee, Fee):
+            fee_in = Fee(fee)
         else:
             fee_in = fee
 
-        return FeeValidator({
-                'currency':fee_in.currency_symbol,
-                'amount': self.convert_currency(fee_in.currency_symbol, "LBC", fee_in.amount),
+        return Fee({
+                'currency':fee_in.currency,
+                'amount': self.convert_currency(fee_in.currency, "LBC", fee_in.amount),
                 'address': fee_in.address
                 })
 
@@ -261,13 +262,13 @@ class DummyExchangeRateManager(object):
     def to_lbc(self, fee):
         if fee is None:
             return None
-        if not isinstance(fee, FeeValidator):
-            fee_in = FeeValidator(fee)
+        if not isinstance(fee, Fee):
+            fee_in = Fee(fee)
         else:
             fee_in = fee
 
-        return FeeValidator({
-                'currency':fee_in.currency_symbol,
-                'amount': self.convert_currency(fee_in.currency_symbol, "LBC", fee_in.amount),
+        return Fee({
+                'currency':fee_in.currency,
+                'amount': self.convert_currency(fee_in.currency, "LBC", fee_in.amount),
                 'address': fee_in.address
                 })
diff --git a/lbrynet/metadata/Fee.py b/lbrynet/metadata/Fee.py
deleted file mode 100644
index c9bc97a55..000000000
--- a/lbrynet/metadata/Fee.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import logging
-import fee_schemas
-
-from lbrynet.metadata.StructuredDict import StructuredDict
-
-log = logging.getLogger(__name__)
-
-
-class FeeValidator(StructuredDict):
-    def __init__(self, fee):
-        self._versions = [
-            ('0.0.1', fee_schemas.VER_001, None)
-        ]
-
-        StructuredDict.__init__(self, fee, fee.get('ver', '0.0.1'))
-
-        self.currency_symbol = self['currency']
-        self.amount = self._get_amount()
-        self.address = self['address']
-
-    def _get_amount(self):
-        amt = self['amount']
-        try:
-            return float(amt)
-        except TypeError:
-            log.error('Failed to convert fee amount %s to float', amt)
-            raise
-
-
-class LBCFeeValidator(StructuredDict):
-    pass
-
-
-class BTCFeeValidator(StructuredDict):
-    pass
-
-
-class USDFeeValidator(StructuredDict):
-    pass
diff --git a/lbrynet/metadata/Metadata.py b/lbrynet/metadata/Metadata.py
deleted file mode 100644
index b1b7de8b0..000000000
--- a/lbrynet/metadata/Metadata.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import logging
-
-from lbrynet.core import Error
-from lbrynet.metadata.StructuredDict import StructuredDict
-import metadata_schemas
-
-log = logging.getLogger(__name__)
-NAME_ALLOWED_CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0987654321-'
-
-
-def verify_name_characters(name):
-    assert len(name) > 0, "Empty uri"
-    invalid_characters = {c for c in name if c not in NAME_ALLOWED_CHARSET}
-    if invalid_characters:
-        raise Error.InvalidName(name, invalid_characters)
-    return True
-
-
-def migrate_001_to_002(metadata):
-    metadata['ver'] = '0.0.2'
-    metadata['nsfw'] = False
-
-def migrate_002_to_003(metadata):
-    metadata['ver'] = '0.0.3'
-    if 'content-type' in metadata:
-        metadata['content_type'] = metadata['content-type']
-        del metadata['content-type']
-
-
-class Metadata(StructuredDict):
-    current_version = '0.0.3'
-
-    _versions = [
-        ('0.0.1', metadata_schemas.VER_001, None),
-        ('0.0.2', metadata_schemas.VER_002, migrate_001_to_002),
-        ('0.0.3', metadata_schemas.VER_003, migrate_002_to_003)
-    ]
-
-    def __init__(self, metadata, migrate=True, target_version=None):
-        if not isinstance(metadata, dict):
-            raise TypeError("{} is not a dictionary".format(metadata))
-        starting_version = metadata.get('ver', '0.0.1')
-
-        StructuredDict.__init__(self, metadata, starting_version, migrate, target_version)
diff --git a/lbrynet/metadata/StructuredDict.py b/lbrynet/metadata/StructuredDict.py
deleted file mode 100644
index 943dcaf3c..000000000
--- a/lbrynet/metadata/StructuredDict.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import jsonschema
-import logging
-
-from jsonschema import ValidationError
-
-log = logging.getLogger(__name__)
-
-
-class StructuredDict(dict):
-    """
-    A dictionary that enforces a structure specified by a schema, and supports
-    migration between different versions of the schema.
-    """
-
-    # To be specified in sub-classes, an array in the format
-    # [(version, schema, migration), ...]
-    _versions = []
-
-    # Used internally to allow schema lookups by version number
-    _schemas = {}
-
-    version = None
-
-    def __init__(self, value, starting_version, migrate=True, target_version=None):
-        dict.__init__(self, value)
-
-        self.version = starting_version
-        self._schemas = dict([(version, schema) for (version, schema, _) in self._versions])
-
-        self.validate(starting_version)
-
-        if migrate:
-            self.migrate(target_version)
-
-    def _upgrade_version_range(self, start_version, end_version):
-        after_starting_version = False
-        for version, schema, migration in self._versions:
-            if not after_starting_version:
-                if version == self.version:
-                    after_starting_version = True
-                continue
-
-            yield version, schema, migration
-
-            if end_version and version == end_version:
-                break
-
-    def validate(self, version):
-        jsonschema.validate(self, self._schemas[version])
-
-    def migrate(self, target_version=None):
-        if target_version:
-            assert self._versions.index(target_version) > self.versions.index(self.version), \
-                "Current version is above target version"
-
-        for version, schema, migration in self._upgrade_version_range(self.version, target_version):
-            migration(self)
-            try:
-                self.validate(version)
-            except ValidationError as e:
-                raise ValidationError(
-                    "Could not migrate to version %s due to validation error: %s" %
-                    (version, e.message))
-            self.version = version
diff --git a/lbrynet/metadata/__init__.py b/lbrynet/metadata/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lbrynet/metadata/fee_schemas.py b/lbrynet/metadata/fee_schemas.py
deleted file mode 100644
index 18efd64b6..000000000
--- a/lbrynet/metadata/fee_schemas.py
+++ /dev/null
@@ -1,16 +0,0 @@
-VER_001 = {
-    '$schema': 'http://json-schema.org/draft-04/schema#',
-    'title': 'LBRY fee schema 0.0.1',
-    'type': 'object',
-
-    'properties': {
-        'amount': {
-            'type': 'number',
-            'minimum': 0,
-            'exclusiveMinimum': True,
-        },
-        'address': {
-            'type': 'string'
-        }
-    },
-}
diff --git a/lbrynet/metadata/metadata_schemas.py b/lbrynet/metadata/metadata_schemas.py
deleted file mode 100644
index 6165ccaa6..000000000
--- a/lbrynet/metadata/metadata_schemas.py
+++ /dev/null
@@ -1,276 +0,0 @@
-VER_001 = {
-    '$schema': 'http://json-schema.org/draft-04/schema#',
-    'title': 'LBRY metadata schema 0.0.1',
-    'definitions': {
-        'fee_info': {
-            'type': 'object',
-            'properties': {
-                'amount': {
-                    'type': 'number',
-                    'minimum': 0,
-                    'exclusiveMinimum': True,
-                },
-                'address': {
-                    'type': 'string'
-                }
-            },
-        }
-    },
-    'type': 'object',
-
-    'properties': {
-        'ver': {
-            'type': 'string',
-            'default': '0.0.1'
-        },
-        'title': {
-            'type': 'string'
-        },
-        'description': {
-            'type': 'string'
-        },
-        'author': {
-            'type': 'string'
-        },
-        'language': {
-            'type': 'string'
-        },
-        'license': {
-            'type': 'string'
-        },
-        'content-type': {
-            'type': 'string'
-        },
-        'sources': {
-            'type': 'object',
-            'properties': {
-                'lbry_sd_hash': {
-                    'type': 'string'
-                },
-                'btih': {
-                    'type': 'string'
-                },
-                'url': {
-                    'type': 'string'
-                }
-            },
-            'additionalProperties': False
-        },
-        'thumbnail': {
-            'type': 'string'
-        },
-        'preview': {
-            'type': 'string'
-        },
-        'fee': {
-            'properties': {
-                'LBC': {'$ref': '#/definitions/fee_info'},
-                'BTC': {'$ref': '#/definitions/fee_info'},
-                'USD': {'$ref': '#/definitions/fee_info'}
-            }
-        },
-        'contact': {
-            'type': 'number'
-        },
-        'pubkey': {
-            'type': 'string'
-        },
-    },
-    'required': [
-        'title', 'description', 'author', 'language', 'license', 'content-type', 'sources'],
-    'additionalProperties': False
-}
-
-
-VER_002 = {
-    '$schema': 'http://json-schema.org/draft-04/schema#',
-    'title': 'LBRY metadata schema 0.0.2',
-    'definitions': {
-        'fee_info': {
-            'type': 'object',
-            'properties': {
-                'amount': {
-                    'type': 'number',
-                    'minimum': 0,
-                    'exclusiveMinimum': True,
-                },
-                'address': {
-                    'type': 'string'
-                }
-            },
-        }
-    },
-    'type': 'object',
-
-    'properties': {
-        'ver': {
-            'type': 'string',
-            'enum': ['0.0.2'],
-        },
-        'title': {
-            'type': 'string'
-        },
-        'description': {
-            'type': 'string'
-        },
-        'author': {
-            'type': 'string'
-        },
-        'language': {
-            'type': 'string'
-        },
-        'license': {
-            'type': 'string'
-        },
-        'content-type': {
-            'type': 'string'
-        },
-        'sources': {
-            'type': 'object',
-            'properties': {
-                'lbry_sd_hash': {
-                    'type': 'string'
-                },
-                'btih': {
-                    'type': 'string'
-                },
-                'url': {
-                    'type': 'string'
-                }
-            },
-            'additionalProperties': False
-        },
-        'thumbnail': {
-            'type': 'string'
-        },
-        'preview': {
-            'type': 'string'
-        },
-        'fee': {
-            'properties': {
-                'LBC': {'$ref': '#/definitions/fee_info'},
-                'BTC': {'$ref': '#/definitions/fee_info'},
-                'USD': {'$ref': '#/definitions/fee_info'}
-            }
-        },
-        'contact': {
-            'type': 'number'
-        },
-        'pubkey': {
-            'type': 'string'
-        },
-        'license_url': {
-            'type': 'string'
-        },
-        'nsfw': {
-            'type': 'boolean',
-            'default': False
-        },
-
-    },
-    'required': [
-        'ver', 'title', 'description', 'author', 'language', 'license',
-        'content-type', 'sources', 'nsfw'
-    ],
-    'additionalProperties': False
-}
-
-
-VER_003 = {
-    '$schema': 'http://json-schema.org/draft-04/schema#',
-    'title': 'LBRY metadata schema 0.0.3',
-    'definitions': {
-        'fee_info': {
-            'type': 'object',
-            'properties': {
-                'amount': {
-                    'type': 'number',
-                    'minimum': 0,
-                    'exclusiveMinimum': True,
-                },
-                'address': {
-                    'type': 'string'
-                }
-            },
-        }
-    },
-    'type': 'object',
-
-    'properties': {
-        'ver': {
-            'type': 'string',
-            'enum': ['0.0.3'],
-        },
-        'title': {
-            'type': 'string'
-        },
-        'description': {
-            'type': 'string'
-        },
-        'author': {
-            'type': 'string'
-        },
-        'language': {
-            'type': 'string'
-        },
-        'license': {
-            'type': 'string'
-        },
-        'content_type': {
-            'type': 'string'
-        },
-        'sources': {
-            'type': 'object',
-            'properties': {
-                'lbry_sd_hash': {
-                    'type': 'string'
-                },
-                'btih': {
-                    'type': 'string'
-                },
-                'url': {
-                    'type': 'string'
-                }
-            },
-            'additionalProperties': False
-        },
-        'thumbnail': {
-            'type': 'string'
-        },
-        'preview': {
-            'type': 'string'
-        },
-        'fee': {
-            'properties': {
-                'LBC': {'$ref': '#/definitions/fee_info'},
-                'BTC': {'$ref': '#/definitions/fee_info'},
-                'USD': {'$ref': '#/definitions/fee_info'}
-            }
-        },
-        'contact': {
-            'type': 'number'
-        },
-        'pubkey': {
-            'type': 'string'
-        },
-        'license_url': {
-            'type': 'string'
-        },
-        'nsfw': {
-            'type': 'boolean',
-            'default': False
-        },
-        'sig': {
-            'type': 'string'
-        }
-    },
-    'required': [
-        'ver', 'title', 'description', 'author', 'language', 'license',
-        'content_type', 'sources', 'nsfw'
-    ],
-    'additionalProperties': False,
-    'dependencies': {
-        'pubkey': ['sig'],
-        'sig': ['pubkey']
-    }
-}
diff --git a/tests/unit/core/test_Metadata.py b/tests/unit/core/test_Metadata.py
deleted file mode 100644
index 0cf6d8168..000000000
--- a/tests/unit/core/test_Metadata.py
+++ /dev/null
@@ -1,218 +0,0 @@
-from twisted.trial import unittest
-from jsonschema import ValidationError
-
-from lbrynet.core import Error
-from lbrynet.metadata import Metadata
-
-
-class MetadataTest(unittest.TestCase):
-    def test_name_error_if_blank(self):
-        with self.assertRaises(AssertionError):
-            Metadata.verify_name_characters("")
-
-    def test_name_error_if_contains_bad_chrs(self):
-        with self.assertRaises(Error.InvalidName):
-            Metadata.verify_name_characters("wu tang")
-        with self.assertRaises(Error.InvalidName):
-            Metadata.verify_name_characters("$wutang")
-        with self.assertRaises(Error.InvalidName):
-            Metadata.verify_name_characters("#wutang")
-
-    def test_validation_error_if_no_metadata(self):
-        metadata = {}
-        with self.assertRaises(ValidationError):
-            Metadata.Metadata(metadata)
-
-    def test_validation_error_if_source_is_missing(self):
-        metadata = {
-            'license': 'Oscilloscope Laboratories',
-            'description': 'Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.',
-            'language': 'en',
-            'title': "It's a Disaster",
-            'author': 'Written and directed by Todd Berger',
-            'content-type': 'audio/mpeg',
-            'thumbnail': 'http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg',
-        }
-        with self.assertRaises(ValidationError):
-            Metadata.Metadata(metadata)
-
-    def test_metadata_works_without_fee(self):
-        metadata = {
-            'license': 'Oscilloscope Laboratories',
-            'description': 'Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.',
-            'language': 'en',
-            'title': "It's a Disaster",
-            'author': 'Written and directed by Todd Berger',
-            'sources': {
-                'lbry_sd_hash': '8d0d6ea64d09f5aa90faf5807d8a761c32a27047861e06f81f41e35623a348a4b0104052161d5f89cf190f9672bc4ead'},
-            'content-type': 'audio/mpeg',
-            'thumbnail': 'http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg',
-        }
-        m = Metadata.Metadata(metadata)
-        self.assertFalse('fee' in m)
-
-    def test_validation_error_if_invalid_source(self):
-        metadata = {
-            'license': 'Oscilloscope Laboratories',
-            'description': 'Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.',
-            'language': 'en',
-            'title': "It's a Disaster",
-            'author': 'Written and directed by Todd Berger',
-            'sources': {
-                'fake': 'source'},
-            'content-type': 'audio/mpeg',
-            'thumbnail': 'http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg',
-        }
-        with self.assertRaises(ValidationError):
-            Metadata.Metadata(metadata)
-
-    def test_validation_error_if_missing_v001_field(self):
-        metadata = {
-            'license': 'Oscilloscope Laboratories',
-            'fee': {'LBC': {'amount': 50.0, 'address': 'bRQJASJrDbFZVAvcpv3NoNWoH74LQd5JNV'}},
-            'description': 'Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.',
-            'language': 'en',
-            'author': 'Written and directed by Todd Berger',
-            'sources': {
-                'lbry_sd_hash': '8d0d6ea64d09f5aa90faf5807d8a761c32a27047861e06f81f41e35623a348a4b0104052161d5f89cf190f9672bc4ead'},
-            'content-type': 'audio/mpeg',
-            'thumbnail': 'http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg'
-        }
-        with self.assertRaises(ValidationError):
-            Metadata.Metadata(metadata)
-
-    def test_version_is_001_if_all_fields_are_present(self):
-        metadata = {
-            'license': 'Oscilloscope Laboratories',
-            'description': 'Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.',
-            'language': 'en',
-            'title': "It's a Disaster",
-            'author': 'Written and directed by Todd Berger',
-            'sources': {
-                'lbry_sd_hash': '8d0d6ea64d09f5aa90faf5807d8a761c32a27047861e06f81f41e35623a348a4b0104052161d5f89cf190f9672bc4ead'},
-            'content-type': 'audio/mpeg',
-            'thumbnail': 'http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg',
-        }
-        m = Metadata.Metadata(metadata, migrate=False)
-        self.assertEquals('0.0.1', m.version)
-
-    def test_validation_error_if_there_is_an_extra_field(self):
-        metadata = {
-            'license': 'Oscilloscope Laboratories',
-            'description': 'Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.',
-            'language': 'en',
-            'title': "It's a Disaster",
-            'author': 'Written and directed by Todd Berger',
-            'sources': {
-                'lbry_sd_hash': '8d0d6ea64d09f5aa90faf5807d8a761c32a27047861e06f81f41e35623a348a4b0104052161d5f89cf190f9672bc4ead'},
-            'content-type': 'audio/mpeg',
-            'thumbnail': 'http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg',
-            'MYSTERYFIELD': '?'
-        }
-        with self.assertRaises(ValidationError):
-            Metadata.Metadata(metadata, migrate=False)
-
-    def test_version_is_002_if_all_fields_are_present(self):
-        metadata = {
-            'license': 'NASA',
-            'fee': {'USD': {'amount': 0.01, 'address': 'baBYSK7CqGSn5KrEmNmmQwAhBSFgo6v47z'}},
-            'ver': '0.0.2',
-            'description': 'SDO captures images of the sun in 10 different wavelengths, each of which helps highlight a different temperature of solar material. Different temperatures can, in turn, show specific structures on the sun such as solar flares, which are gigantic explosions of light and x-rays, or coronal loops, which are stream of solar material travelling up and down looping magnetic field lines',
-            'language': 'en',
-            'author': 'The SDO Team, Genna Duberstein and Scott Wiessinger',
-            'title': 'Thermonuclear Art',
-            'sources': {
-                        'lbry_sd_hash': '8655f713819344980a9a0d67b198344e2c462c90f813e86f0c63789ab0868031f25c54d0bb31af6658e997e2041806eb'},
-            'nsfw': False,
-            'content-type': 'video/mp4',
-            'thumbnail': 'https://svs.gsfc.nasa.gov/vis/a010000/a012000/a012034/Combined.00_08_16_17.Still004.jpg'
-        }
-        m = Metadata.Metadata(metadata, migrate=False)
-        self.assertEquals('0.0.2', m.version)
-
-    def test_version_is_003_if_all_fields_are_present(self):
-        metadata = {
-            'license': 'NASA',
-            'fee': {'USD': {'amount': 0.01, 'address': 'baBYSK7CqGSn5KrEmNmmQwAhBSFgo6v47z'}},
-            'ver': '0.0.3',
-            'description': 'SDO captures images of the sun in 10 different wavelengths, each of which helps highlight a different temperature of solar material. Different temperatures can, in turn, show specific structures on the sun such as solar flares, which are gigantic explosions of light and x-rays, or coronal loops, which are stream of solar material travelling up and down looping magnetic field lines',
-            'language': 'en',
-            'author': 'The SDO Team, Genna Duberstein and Scott Wiessinger',
-            'title': 'Thermonuclear Art',
-            'sources': {
-                'lbry_sd_hash': '8655f713819344980a9a0d67b198344e2c462c90f813e86f0c63789ab0868031f25c54d0bb31af6658e997e2041806eb'},
-            'nsfw': False,
-            'content_type': 'video/mp4',
-            'thumbnail': 'https://svs.gsfc.nasa.gov/vis/a010000/a012000/a012034/Combined.00_08_16_17.Still004.jpg'
-        }
-        m = Metadata.Metadata(metadata, migrate=False)
-        self.assertEquals('0.0.3', m.version)
-
-    def test_version_claimed_is_001_but_version_is_002(self):
-        metadata = {
-            'license': 'NASA',
-            'fee': {'USD': {'amount': 0.01, 'address': 'baBYSK7CqGSn5KrEmNmmQwAhBSFgo6v47z'}},
-            'ver': '0.0.1',
-            'description': 'SDO captures images of the sun in 10 different wavelengths, each of which helps highlight a different temperature of solar material. Different temperatures can, in turn, show specific structures on the sun such as solar flares, which are gigantic explosions of light and x-rays, or coronal loops, which are stream of solar material travelling up and down looping magnetic field lines',
-            'language': 'en',
-            'author': 'The SDO Team, Genna Duberstein and Scott Wiessinger',
-            'title': 'Thermonuclear Art',
-            'sources': {
-                'lbry_sd_hash': '8655f713819344980a9a0d67b198344e2c462c90f813e86f0c63789ab0868031f25c54d0bb31af6658e997e2041806eb'},
-            'nsfw': False,
-            'content-type': 'video/mp4',
-            'thumbnail': 'https://svs.gsfc.nasa.gov/vis/a010000/a012000/a012034/Combined.00_08_16_17.Still004.jpg'
-        }
-        with self.assertRaises(ValidationError):
-            Metadata.Metadata(metadata, migrate=False)
-
-    def test_version_claimed_is_002_but_version_is_003(self):
-        metadata = {
-            'license': 'NASA',
-            'fee': {'USD': {'amount': 0.01, 'address': 'baBYSK7CqGSn5KrEmNmmQwAhBSFgo6v47z'}},
-            'ver': '0.0.2',
-            'description': 'SDO captures images of the sun in 10 different wavelengths, each of which helps highlight a different temperature of solar material. Different temperatures can, in turn, show specific structures on the sun such as solar flares, which are gigantic explosions of light and x-rays, or coronal loops, which are stream of solar material travelling up and down looping magnetic field lines',
-            'language': 'en',
-            'author': 'The SDO Team, Genna Duberstein and Scott Wiessinger',
-            'title': 'Thermonuclear Art',
-            'sources': {
-                'lbry_sd_hash': '8655f713819344980a9a0d67b198344e2c462c90f813e86f0c63789ab0868031f25c54d0bb31af6658e997e2041806eb'},
-            'nsfw': False,
-            'content_type': 'video/mp4',
-            'thumbnail': 'https://svs.gsfc.nasa.gov/vis/a010000/a012000/a012034/Combined.00_08_16_17.Still004.jpg'
-        }
-        with self.assertRaises(ValidationError):
-            Metadata.Metadata(metadata, migrate=False)
-
-    def test_version_001_ports_to_003(self):
-        metadata = {
-            'license': 'Oscilloscope Laboratories',
-            'description': 'Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end.',
-            'language': 'en',
-            'title': "It's a Disaster",
-            'author': 'Written and directed by Todd Berger',
-            'sources': {
-                'lbry_sd_hash': '8d0d6ea64d09f5aa90faf5807d8a761c32a27047861e06f81f41e35623a348a4b0104052161d5f89cf190f9672bc4ead'},
-            'content-type': 'audio/mpeg',
-            'thumbnail': 'http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg',
-        }
-        m = Metadata.Metadata(metadata, migrate=True)
-        self.assertEquals('0.0.3', m.version)
-
-    def test_version_002_ports_to_003(self):
-        metadata = {
-            'license': 'NASA',
-            'fee': {'USD': {'amount': 0.01, 'address': 'baBYSK7CqGSn5KrEmNmmQwAhBSFgo6v47z'}},
-            'ver': '0.0.2',
-            'description': 'SDO captures images of the sun in 10 different wavelengths, each of which helps highlight a different temperature of solar material. Different temperatures can, in turn, show specific structures on the sun such as solar flares, which are gigantic explosions of light and x-rays, or coronal loops, which are stream of solar material travelling up and down looping magnetic field lines',
-            'language': 'en',
-            'author': 'The SDO Team, Genna Duberstein and Scott Wiessinger',
-            'title': 'Thermonuclear Art',
-            'sources': {
-                'lbry_sd_hash': '8655f713819344980a9a0d67b198344e2c462c90f813e86f0c63789ab0868031f25c54d0bb31af6658e997e2041806eb'},
-            'nsfw': False,
-            'content-type': 'video/mp4',
-            'thumbnail': 'https://svs.gsfc.nasa.gov/vis/a010000/a012000/a012034/Combined.00_08_16_17.Still004.jpg'
-        }
-        m = Metadata.Metadata(metadata, migrate=True)
-        self.assertEquals('0.0.3', m.version)
diff --git a/tests/unit/lbrynet_daemon/test_ExchangeRateManager.py b/tests/unit/lbrynet_daemon/test_ExchangeRateManager.py
index 2e8937e75..eacf7708b 100644
--- a/tests/unit/lbrynet_daemon/test_ExchangeRateManager.py
+++ b/tests/unit/lbrynet_daemon/test_ExchangeRateManager.py
@@ -1,6 +1,5 @@
-from lbrynet.metadata import Fee
+from lbryschema.fee import Fee
 from lbrynet.lbrynet_daemon import ExchangeRateManager
-from lbrynet import conf
 from lbrynet.core.Error import InvalidExchangeRateResponse
 
 from twisted.trial import unittest
@@ -15,7 +14,7 @@ class FeeFormatTest(unittest.TestCase):
             'amount': 10.0,
             'address': "bRcHraa8bYJZL7vkh5sNmGwPDERFUjGPP9"
         }
-        fee = Fee.FeeValidator(fee_dict)
+        fee = Fee(fee_dict)
         self.assertEqual(10.0, fee['amount'])
         self.assertEqual('USD', fee['currency'])