Add a custom JSONEncoder
A custom JSONEncoder allowing to serialize decimal.Decimal instances is defined in several places in the codebase. This provides a common encoder class that supports decimal.Decimal and datetime.datetime objects. Change-Id: Ie65b1f97f2eeb7a8bc6203576bdbc50b109867cc
This commit is contained in:
parent
a9dbe07d41
commit
9c88e50b73
35
cloudkitty/json_utils.py
Normal file
35
cloudkitty/json_utils.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Copyright 2019 Objectif Libre
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
import datetime
|
||||
import decimal
|
||||
import functools
|
||||
import json
|
||||
|
||||
from cloudkitty import utils as ck_utils
|
||||
|
||||
|
||||
class CloudkittyJSONEncoder(json.JSONEncoder):
|
||||
"""Cloudkitty custom json encoder."""
|
||||
|
||||
def default(self, obj):
|
||||
if isinstance(obj, decimal.Decimal):
|
||||
return float(obj)
|
||||
elif isinstance(obj, datetime.datetime):
|
||||
return ck_utils.dt2iso(obj)
|
||||
return super(CloudkittyJSONEncoder, self).default(obj)
|
||||
|
||||
|
||||
dumps = functools.partial(json.dumps, cls=CloudkittyJSONEncoder)
|
||||
loads = json.loads
|
@ -15,10 +15,8 @@
|
||||
#
|
||||
# @author: Stéphane Albert
|
||||
#
|
||||
import decimal
|
||||
import json
|
||||
|
||||
from cloudkitty.db import api
|
||||
from cloudkitty import json_utils as json
|
||||
|
||||
|
||||
class StateManager(object):
|
||||
@ -94,14 +92,6 @@ class StateManager(object):
|
||||
return self._metadata
|
||||
|
||||
|
||||
class DecimalJSONEncoder(json.JSONEncoder):
|
||||
"""Wrapper class to handle decimal.Decimal objects in json.dumps()."""
|
||||
def default(self, obj):
|
||||
if isinstance(obj, decimal.Decimal):
|
||||
return float(obj)
|
||||
return super(DecimalJSONEncoder, self).default(obj)
|
||||
|
||||
|
||||
class DBStateManager(object):
|
||||
def __init__(self, user_id, report_type, distributed=False):
|
||||
self._state_name = self._gen_name(report_type, user_id)
|
||||
@ -132,5 +122,4 @@ class DBStateManager(object):
|
||||
def set_metadata(self, metadata):
|
||||
"""Set metadata attached to the state."""
|
||||
|
||||
self._db.set_metadata(self._state_name,
|
||||
json.dumps(metadata, cls=DecimalJSONEncoder))
|
||||
self._db.set_metadata(self._state_name, json.dumps(metadata))
|
||||
|
@ -17,7 +17,6 @@
|
||||
#
|
||||
import datetime
|
||||
import decimal
|
||||
import json
|
||||
|
||||
from gnocchiclient import client as gclient
|
||||
from gnocchiclient import exceptions as gexceptions
|
||||
@ -28,6 +27,7 @@ from oslo_utils import uuidutils
|
||||
import six
|
||||
|
||||
from cloudkitty.collector import validate_conf
|
||||
from cloudkitty import json_utils as json
|
||||
from cloudkitty.storage.v1.hybrid.backends import BaseHybridBackend
|
||||
import cloudkitty.utils as ck_utils
|
||||
|
||||
@ -67,14 +67,6 @@ RESOURCE_TYPE_NAME_ROOT = 'rating_service_'
|
||||
METADATA_NAME_ROOT = 'ckmeta_'
|
||||
|
||||
|
||||
class DecimalJSONEncoder(json.JSONEncoder):
|
||||
"""Wrapper class to handle decimal.Decimal objects in json.dumps()."""
|
||||
def default(self, obj):
|
||||
if isinstance(obj, decimal.Decimal):
|
||||
return float(obj)
|
||||
return super(DecimalJSONEncoder, self).default(obj)
|
||||
|
||||
|
||||
class UnknownResourceType(Exception):
|
||||
"""Exception raised when an unknown resource type is encountered"""
|
||||
|
||||
|
@ -16,12 +16,12 @@
|
||||
# @author: Stéphane Albert
|
||||
#
|
||||
import decimal
|
||||
import json
|
||||
|
||||
from oslo_db.sqlalchemy import utils
|
||||
import sqlalchemy
|
||||
|
||||
from cloudkitty import db
|
||||
from cloudkitty import json_utils as json
|
||||
from cloudkitty.storage import NoTimeFrame
|
||||
from cloudkitty.storage import v1 as storage
|
||||
from cloudkitty.storage.v1.sqlalchemy import migration
|
||||
@ -29,14 +29,6 @@ from cloudkitty.storage.v1.sqlalchemy import models
|
||||
from cloudkitty import utils as ck_utils
|
||||
|
||||
|
||||
class DecimalJSONEncoder(json.JSONEncoder):
|
||||
"""Wrapper class to handle decimal.Decimal objects in json.dumps()."""
|
||||
def default(self, obj):
|
||||
if isinstance(obj, decimal.Decimal):
|
||||
return float(obj)
|
||||
return super(DecimalJSONEncoder, self).default(obj)
|
||||
|
||||
|
||||
class SQLAlchemyStorage(storage.BaseStorage):
|
||||
"""SQLAlchemy Storage Backend
|
||||
|
||||
@ -185,7 +177,7 @@ class SQLAlchemyStorage(storage.BaseStorage):
|
||||
rate = rating_dict.get('price')
|
||||
if not rate:
|
||||
rate = decimal.Decimal(0)
|
||||
desc = json.dumps(frame['desc'], cls=DecimalJSONEncoder)
|
||||
desc = json.dumps(frame['desc'])
|
||||
self.add_time_frame(begin=self.usage_start_dt.get(tenant_id),
|
||||
end=self.usage_end_dt.get(tenant_id),
|
||||
tenant_id=tenant_id,
|
||||
|
@ -15,14 +15,14 @@
|
||||
#
|
||||
# @author: Stéphane Albert
|
||||
#
|
||||
import json
|
||||
|
||||
from oslo_db.sqlalchemy import models
|
||||
import sqlalchemy
|
||||
from sqlalchemy.ext import declarative
|
||||
|
||||
from cloudkitty import json_utils as json
|
||||
from cloudkitty import utils as ck_utils
|
||||
|
||||
|
||||
Base = declarative.declarative_base()
|
||||
|
||||
|
||||
|
30
cloudkitty/tests/test_json.py
Normal file
30
cloudkitty/tests/test_json.py
Normal file
@ -0,0 +1,30 @@
|
||||
# Copyright 2019 Objectif Libre
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
import datetime
|
||||
import decimal
|
||||
|
||||
from cloudkitty import json_utils as json
|
||||
from cloudkitty import tests
|
||||
|
||||
|
||||
class JSONEncoderTest(tests.TestCase):
|
||||
|
||||
def test_encode_decimal(self):
|
||||
obj = {'nb': decimal.Decimal(42)}
|
||||
self.assertEqual(json.dumps(obj), '{"nb": 42.0}')
|
||||
|
||||
def test_encode_datetime(self):
|
||||
obj = {'date': datetime.datetime(2019, 1, 1)}
|
||||
self.assertEqual(json.dumps(obj), '{"date": "2019-01-01T00:00:00Z"}')
|
@ -15,20 +15,12 @@
|
||||
#
|
||||
# @author: Stéphane Albert
|
||||
#
|
||||
import decimal
|
||||
import json
|
||||
import os
|
||||
|
||||
from cloudkitty import json_utils as json
|
||||
from cloudkitty import writer
|
||||
|
||||
|
||||
class DecimalEncoder(json.JSONEncoder):
|
||||
def default(self, o):
|
||||
if isinstance(o, decimal.Decimal):
|
||||
return float(o)
|
||||
return super(DecimalEncoder, self).default(o)
|
||||
|
||||
|
||||
class OSRFBackend(writer.BaseReportWriter):
|
||||
"""OpenStack Report Format Writer:
|
||||
|
||||
@ -59,7 +51,7 @@ class OSRFBackend(writer.BaseReportWriter):
|
||||
|
||||
def _write_total(self):
|
||||
total = {'total': self.total}
|
||||
self._report.write(json.dumps(total, cls=DecimalEncoder))
|
||||
self._report.write(json.dumps(total))
|
||||
self._report.write(']')
|
||||
self._report.flush()
|
||||
|
||||
@ -96,6 +88,6 @@ class OSRFBackend(writer.BaseReportWriter):
|
||||
'end': self.usage_end_dt.isoformat()}
|
||||
data['usage'] = self._usage_data
|
||||
|
||||
self._report.write(json.dumps(data, cls=DecimalEncoder))
|
||||
self._report.write(json.dumps(data))
|
||||
self._report.write(', ')
|
||||
self._report.flush()
|
||||
|
@ -20,11 +20,12 @@ import calendar
|
||||
import copy
|
||||
import csv
|
||||
import datetime
|
||||
import json
|
||||
import random
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
from cloudkitty import json_utils as json
|
||||
|
||||
|
||||
COMPUTE = {
|
||||
"type": "compute",
|
||||
|
Loading…
x
Reference in New Issue
Block a user