Convert Metadata and Fee validators to use new JSON Schema-based system

This commit is contained in:
Alex Liebowitz 2016-10-14 08:04:40 -04:00
parent 3f22f39ce1
commit d8d462f43c
4 changed files with 329 additions and 169 deletions

View file

@ -1,116 +1,39 @@
import logging
import fee_schemas
from lbrynet.metadata.Validator import Validator, skip_validate
from lbrynet.conf import CURRENCIES
from lbrynet.metadata.StructuredDict import StructuredDict
log = logging.getLogger(__name__)
def verify_supported_currency(fee):
assert len(fee) == 1
for c in fee:
assert c in CURRENCIES
return True
def verify_amount(x):
return isinstance(x, float) or isinstance(x, int) and x > 0
class LBCFeeValidator(Validator):
FV001 = "0.0.1"
CURRENT_FEE_VERSION = FV001
FEE_REVISIONS = {}
FEE_REVISIONS[FV001] = [
(Validator.REQUIRE, 'amount', verify_amount),
(Validator.REQUIRE, 'address', skip_validate),
]
FEE_MIGRATIONS = []
current_version = CURRENT_FEE_VERSION
versions = FEE_REVISIONS
migrations = FEE_MIGRATIONS
class FeeValidator(StructuredDict):
def __init__(self, fee):
Validator.__init__(self, fee)
class BTCFeeValidator(Validator):
FV001 = "0.0.1"
CURRENT_FEE_VERSION = FV001
FEE_REVISIONS = {}
FEE_REVISIONS[FV001] = [
(Validator.REQUIRE, 'amount',verify_amount),
(Validator.REQUIRE, 'address', skip_validate),
self._versions = [
('0.0.1', fee_schemas.VER_001, None)
]
FEE_MIGRATIONS = []
StructuredDict.__init__(self, fee, fee.get('ver', '0.0.1'))
current_version = CURRENT_FEE_VERSION
versions = FEE_REVISIONS
migrations = FEE_MIGRATIONS
def __init__(self, fee):
Validator.__init__(self, fee)
class USDFeeValidator(Validator):
FV001 = "0.0.1"
CURRENT_FEE_VERSION = FV001
FEE_REVISIONS = {}
FEE_REVISIONS[FV001] = [
(Validator.REQUIRE, 'amount',verify_amount),
(Validator.REQUIRE, 'address', skip_validate),
]
FEE_MIGRATIONS = []
current_version = CURRENT_FEE_VERSION
versions = FEE_REVISIONS
migrations = FEE_MIGRATIONS
def __init__(self, fee):
Validator.__init__(self, fee)
class FeeValidator(Validator):
CV001 = "0.0.1"
CURRENT_CURRENCY_VERSION = CV001
CURRENCY_REVISIONS = {}
CURRENCY_REVISIONS[CV001] = [
(Validator.OPTIONAL, 'BTC', BTCFeeValidator.validate),
(Validator.OPTIONAL, 'USD', USDFeeValidator.validate),
(Validator.OPTIONAL, 'LBC', LBCFeeValidator.validate),
]
CURRENCY_MIGRATIONS = []
current_version = CURRENT_CURRENCY_VERSION
versions = CURRENCY_REVISIONS
migrations = CURRENCY_MIGRATIONS
def __init__(self, fee_dict):
Validator.__init__(self, fee_dict)
self.currency_symbol = self.keys()[0]
self.amount = self._get_amount()
self.address = self[self.currency_symbol]['address']
def _get_amount(self):
amt = self[self.currency_symbol]['amount']
if isinstance(amt, float):
return amt
else:
try:
return float(amt)
except TypeError:
log.error('Failed to convert %s to float', amt)
log.error('Failed to convert fee amount %s to float', amt)
raise
class LBCFeeValidator(StructuredDict):
pass
class BTCFeeValidator(StructuredDict):
pass
class USDFeeValidator(StructuredDict):
pass

View file

@ -1,8 +1,8 @@
import logging
from lbrynet.metadata.Validator import Validator, skip_validate
from lbrynet.metadata.Fee import FeeValidator, verify_supported_currency
from lbrynet.metadata.StructuredDict import StructuredDict
from lbrynet.conf import SOURCE_TYPES
import metadata_schemas
log = logging.getLogger(__name__)
NAME_ALLOWED_CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0987654321-'
@ -14,73 +14,25 @@ def verify_name_characters(name):
return True
def validate_sources(sources):
for source in sources:
assert source in SOURCE_TYPES, "Unknown source type: %s" % str(source)
return True
class Metadata(Validator):
MV001 = "0.0.1"
MV002 = "0.0.2"
MV003 = "0.0.3"
CURRENT_METADATA_VERSION = MV003
METADATA_REVISIONS = {}
METADATA_REVISIONS[MV001] = [
(Validator.REQUIRE, 'title', skip_validate),
(Validator.REQUIRE, 'description', skip_validate),
(Validator.REQUIRE, 'author', skip_validate),
(Validator.REQUIRE, 'language', skip_validate),
(Validator.REQUIRE, 'license', skip_validate),
(Validator.REQUIRE, 'content-type', skip_validate),
(Validator.REQUIRE, 'sources', validate_sources),
(Validator.OPTIONAL, 'thumbnail', skip_validate),
(Validator.OPTIONAL, 'preview', skip_validate),
(Validator.OPTIONAL, 'fee', verify_supported_currency),
(Validator.OPTIONAL, 'contact', skip_validate),
(Validator.OPTIONAL, 'pubkey', skip_validate),
class Metadata(StructuredDict):
def __init__(self, metadata, migrate=True, target_version=None):
self._versions = [
('0.0.1', metadata_schemas.VER_001, None),
('0.0.2', metadata_schemas.VER_002, self._migrate_001_to_002),
('0.0.3', metadata_schemas.VER_003, self._migrate_002_to_003)
]
METADATA_REVISIONS[MV002] = [
(Validator.REQUIRE, 'nsfw', skip_validate),
(Validator.REQUIRE, 'ver', skip_validate),
(Validator.OPTIONAL, 'license_url', skip_validate),
]
starting_version = metadata.get('ver', '0.0.1')
METADATA_REVISIONS[MV003] = [
(Validator.REQUIRE, 'content_type', skip_validate),
(Validator.SKIP, 'content-type'),
(Validator.OPTIONAL, 'sig', skip_validate),
(Validator.IF_KEY, 'sig', (Validator.REQUIRE, 'pubkey', skip_validate), Validator.DO_NOTHING),
(Validator.IF_KEY, 'pubkey', (Validator.REQUIRE, 'sig', skip_validate), Validator.DO_NOTHING),
]
StructuredDict.__init__(self, metadata, starting_version, migrate, target_version)
MIGRATE_MV001_TO_MV002 = [
(Validator.IF_KEY, 'nsfw', Validator.DO_NOTHING, (Validator.LOAD, 'nsfw', False)),
(Validator.IF_KEY, 'ver', Validator.DO_NOTHING, (Validator.LOAD, 'ver', MV002)),
]
MIGRATE_MV002_TO_MV003 = [
(Validator.IF_KEY, 'content-type', (Validator.UPDATE, 'content-type', 'content_type'), Validator.DO_NOTHING),
(Validator.IF_VAL, 'ver', MV002, (Validator.LOAD, 'ver', MV003), Validator.DO_NOTHING),
]
def _migrate_001_to_002(self):
self['ver'] = '0.0.2'
METADATA_MIGRATIONS = [
MIGRATE_MV001_TO_MV002,
MIGRATE_MV002_TO_MV003,
]
def _migrate_002_to_003(self):
self['ver'] = '0.0.3'
current_version = CURRENT_METADATA_VERSION
versions = METADATA_REVISIONS
migrations = METADATA_MIGRATIONS
def __init__(self, metadata, process_now=True):
Validator.__init__(self, metadata, process_now)
self.meta_version = self.get('ver', Metadata.MV001)
self._load_fee()
def _load_fee(self):
if 'fee' in self:
self.update({'fee': FeeValidator(self['fee'])})
if 'content-type' in self:
self['content_type'] = self['content-type']
del self['content-type']

View file

@ -0,0 +1,16 @@
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'
}
},
}

View file

@ -0,0 +1,269 @@
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']
}
}