Browse Source

make json coding a thing...

main
John-Mark Gurney 2 years ago
parent
commit
1accd1392a
1 changed files with 80 additions and 6 deletions
  1. +80
    -6
      ui/medashare/cli.py

+ 80
- 6
ui/medashare/cli.py View File

@@ -11,6 +11,7 @@ from unittest import mock

from .hostid import hostuuid

import base64
import base58
import copy
import datetime
@@ -61,7 +62,23 @@ def _makeuuid(s):
if isinstance(s, uuid.UUID):
return s

return uuid.UUID(bytes=s)
if isinstance(s, bytes):
return uuid.UUID(bytes=s)
else:
return uuid.UUID(s)

def _makedatetime(s):
if isinstance(s, datetime.datetime):
return s

return datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%fZ').replace(
tzinfo=datetime.timezone.utc)

def _makebytes(s):
if isinstance(s, bytes):
return s

return base64.urlsafe_b64decode(s)

# XXX - known issue, store is not atomic/safe, overwrites in place instead of
# renames
@@ -84,8 +101,10 @@ class MDBase(object):
# to get the correct type
_instance_properties = {
'uuid': _makeuuid,
'modified': _makedatetime,
'created_by_ref': _makeuuid,
#'parent_refs': lambda x: [ _makeuuid(y) for y in x ],
'sig': _makebytes,
}

# Override on a per subclass basis
@@ -197,12 +216,20 @@ class MDBase(object):
return [ (k, v) for k, v in self._obj.items() if
not skipcommon or k not in self._common_names ]

def encode(self):
return _asn1coder.dumps(self)
def encode(self, meth='asn1'):
if meth == 'asn1':
return _asn1coder.dumps(self)

return _jsonencoder.encode(self._obj)

@classmethod
def decode(cls, s):
return cls.create_obj(_asn1coder.loads(s))
def decode(cls, s, meth='asn1'):
if meth == 'asn1':
obj = _asn1coder.loads(s)
else:
obj = json.loads(s)

return cls.create_obj(obj)

class MetaData(MDBase):
_type = 'metadata'
@@ -237,6 +264,20 @@ class CanonicalCoder(pasn1.ASN1DictCoder):

_asn1coder = CanonicalCoder(coerce=_trytodict)

class _JSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, uuid.UUID):
return str(o)
elif isinstance(o, datetime.datetime):
o = o.astimezone(datetime.timezone.utc)
return o.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
elif isinstance(o, bytes):
return base64.urlsafe_b64encode(o).decode('US-ASCII')

return json.JSONEncoder.default(self, o)

_jsonencoder = _JSONEncoder()

class Persona(object):
'''The object that represents a persona, or identity. It will
create the proper identity object, serialize for saving keys,
@@ -546,6 +587,7 @@ class FileObject(MDBase):
_class_instance_properties = {
'hostid': _makeuuid,
'id': _makeuuid,
'mtime': _makedatetime,
}

@staticmethod
@@ -892,6 +934,15 @@ class _TestCases(unittest.TestCase):
# make sure the file's id is still a UUID
self.assertIsInstance(a.id, uuid.UUID)

# That it can be encoded to json
jsfo = a.encode('json')

# that it can be decoded from json
jsloadedfo = MDBase.decode(jsfo, 'json')

# and that it is equal
self.assertEqual(jsloadedfo, a)

def test_mdbase(self):
self.assertRaises(ValueError, MDBase, created_by_ref='')
self.assertRaises(ValueError, MDBase.create_obj, { 'type': 'unknosldkfj' })
@@ -929,7 +980,7 @@ class _TestCases(unittest.TestCase):
self.assertEqual(md2['dc:creator'], [ 'Jim Bob' ])

# that providing a value from common property
fvalue = 'fakesig'
fvalue = b'fakesig'
md3 = md.new_version(('sig', fvalue))

# gets set directly, and is not a list
@@ -964,6 +1015,29 @@ class _TestCases(unittest.TestCase):
# and has the length of 16
self.assertEqual(len(eobj['uuid']), 16)

# and that json can be used to encode
js = obj.encode('json')

# and that it is valid json
jsobj = json.loads(js)

# and that it can be decoded
jsdecobj = MDBase.decode(js, 'json')

# and that it matches
self.assertEqual(jsdecobj, obj)

for key, inval in [
('modified', '2022-08-19T01:27:34.258676'),
('modified', '2022-08-19T01:27:34Z'),
('modified', '2022-08-19T01:27:34.258676+00:00'),
('uuid', 'z5336176-8086-4c21-984f-fda60ddaa172'),
('uuid', '05336176-8086-421-984f-fda60ddaa172'),
]:
jsobj['modified'] = inval
jstest = json.dumps(jsobj)
self.assertRaises(ValueError, MDBase.decode, jstest, 'json')

def test_mdbase_wrong_type(self):
# that created_by_ref can be passed by kw
obj = MetaData(created_by_ref=self.created_by_ref)


Loading…
Cancel
Save