def test_clone_from_class_with_multiple_parents(self): grand_parent = Model('GrandParent', { 'grand_parent': fields.String, }) parent = Model('Parent', { 'name': fields.String, 'age': fields.Integer, 'birthdate': fields.DateTime, }) child = Model.clone('Child', grand_parent, parent, { 'extra': fields.String, }) self.assertEqual(child.__schema__, { 'properties': { 'grand_parent': { 'type': 'string' }, 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' }, 'extra': { 'type': 'string' } } })
def test_polymorph_inherit_common_ancestor(self): class Child1: pass class Child2: pass parent = Model('Person', { 'name': fields.String, 'age': fields.Integer, }) child1 = parent.inherit('Child1', { 'extra1': fields.String, }) child2 = parent.inherit('Child2', { 'extra2': fields.String, }) mapping = { Child1: child1, Child2: child2, } output = Model('Output', { 'child': fields.Polymorph(mapping) }) # Should use the common ancestor self.assertEqual(output.__schema__, { 'properties': { 'child': {'$ref': '#/definitions/Person'}, } })
class ResponseModel(): """ 응답시 사용될 메시지의 구조에 대한 모델 정의 """ success = Model('Success', ResponseSchem.success) not_found = Model('NotFound', ResponseSchem.not_found) bad_request = Model('BadRequest', ResponseSchem.bad_request)
def test_inherit_from_instance_from_multiple_parents(self): grand_parent = Model('GrandParent', { 'grand_parent': fields.String, }) parent = Model('Parent', { 'name': fields.String, 'age': fields.Integer, }) child = grand_parent.inherit('Child', parent, { 'extra': fields.String, }) self.assertEqual(child.__schema__, { 'allOf': [ {'$ref': '#/definitions/GrandParent'}, {'$ref': '#/definitions/Parent'}, { 'properties': { 'extra': {'type': 'string'} }, 'type': 'object' } ] })
class EtonApiModel: eton_product = Model('eton_product', { 'sku': fields.String(required=True, description='Product code'), 'qty': fields.Integer(required=True, description='Quantity'), 'serials': fields.List(fields.String, required=True, description='Serial list') }) eton_po_req = Model('eton_po_req', { 'items': fields.List( fields.Nested(eton_product, required=True, description='List of product information to be processed')) }) eton_so_req = eton_po_req.clone('eton_so_req', { 'eventType': fields.String( description='update SO by type', enum=['picked', 'packed', 'delivered'] ) }) eton_so_returned_req = eton_po_req.clone('eton_so_returned_req', { 'type': fields.String( description='Return type' ) }) eton_error_res = ResponseModel.error_response.clone('eton_error_res') eton_success_res = ResponseModel.success_response.clone('eton_success_res')
class StockQuantModel: stock_quant = Model('stock_quant', { # 'sku': fields.String(required=True, description='product sku'), 'branch': fields.String(required=False, description='Branch code'), 'location': fields.String(required=False, description='Location code'), 'warehouse': fields.String(required=False, description='Warehouse code'), 'reserved': fields.Float(required=False, description='Stock held quantity'), 'incoming': fields.Integer(required=False, description='Quantity about to enter stock'), 'storeCode': fields.String(required=False, description='Asia region type'), 'outgoing': fields.Integer(required=False, description='Stock outgoing quantity'), 'available': fields.Float(required=False, description='Available quantity = Actual inventory number - stock held = onHand- reserved'), 'forecast': fields.Float(required=False, description='Forecast = Physical Stock + Incoming - Outgoing'), 'onHand': fields.Float(required=False, description='Actual quantity in stock'), 'productBizType': fields.String(required=False, description='Type of product business'), }) stock_quant_response = Model('stock_quant_response', { 'sku': fields.String(required=True, description='Product sku'), 'items': fields.Nested(stock_quant, allow_null=True, as_list=True, skip_none=True) }) stock_quant_min = Model('stock_quant_min', { # 'sku': fields.String(required=True, description='product sku'), 'branch': fields.String(required=False, description='Branch code'), 'branchName': fields.String(required=False, description='Branch name'), 'location': fields.String(required=False, description='Location code'), 'locationName': fields.String(required=False, description='Location name'), 'warehouse': fields.String(required=False, description='Warehouse name'), 'warehouseName': fields.String(required=False, description='Warehouse code'), 'timestamp': fields.Float(required=False, description='Time Stamp'), 'reserved': fields.Float(required=False, description='Stock held quantity'), 'storeCode': fields.String(required=False, description='Asia region type'), 'available': fields.Float(required=False, description='Available quantity = Actual inventory number - stock held = onHand- reserved'), 'onHand': fields.Float(required=False, description='Actual quantity in stock'), 'productBizType': fields.String(required=False, description='Type of product business'), }) stock_quant_min_response = Model('stock_quant_min_response', { 'sku': fields.String(required=True, description='Product sku'), 'items': fields.Nested(stock_quant_min, allow_null=True, as_list=True, skip_none=True) }) stock_quant_success = ResponseModel.success_response.clone('stock_quant_success', { 'result': fields.Nested(stock_quant_response, as_list=True) }) stock_quant_min_success = ResponseModel.success_response.clone('stock_quant_min_success', { 'result': fields.Nested(stock_quant_min_response, as_list=True) })
def _assemble_and_regist_model(self, model_name, dic_lis): _new_dic = {} for dic in dic_lis: _new_dic.update(dic) model = Model(model_name, _new_dic) self._models[model_name] = model return model
class ResponseModel: """ Add success model use in marshal_with for success return """ success_response = Model('success_response', { 'code': fields.String(required=True), 'message': fields.String(), 'result': fields.Raw(), }) error_response = Model('error_response', { 'code': fields.String(required=True, description='error code'), 'message': fields.String(required=True, description='error message'), 'extra': fields.Raw(), })
def test_extend_is_deprecated(self): parent = Model('Parent', { 'name': fields.String, 'age': fields.Integer, 'birthdate': fields.DateTime, }) with self.assert_warning(DeprecationWarning): child = parent.extend('Child', { 'extra': fields.String, }) self.assertEqual(child.__schema__, { 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' }, 'extra': { 'type': 'string' } }, 'type': 'object' })
def build_response(message): response = {'message': message} model = Model('PostResponse', {'message': fields.Raw(description='Message for post')}) return response, model
def test_inherit_from_instance(self): parent = Model('Parent', { 'name': fields.String, 'age': fields.Integer, }) child = parent.inherit('Child', { 'extra': fields.String, }) assert parent.__schema__ == { 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, }, 'type': 'object' } assert child.__schema__ == { 'allOf': [{ '$ref': '#/definitions/Parent' }, { 'properties': { 'extra': { 'type': 'string' } }, 'type': 'object' }] }
def test_model_deepcopy(self): parent = Model('Person', { 'name': fields.String, 'age': fields.Integer(description="foo"), }) child = parent.inherit('Child', { 'extra': fields.String, }) parent_copy = copy.deepcopy(parent) assert parent_copy["age"].description == "foo" parent_copy["age"].description = "bar" assert parent["age"].description == "foo" assert parent_copy["age"].description == "bar" child = parent.inherit('Child', { 'extra': fields.String, }) child_copy = copy.deepcopy(child) assert child_copy.__parents__[0] == parent
def test_model_with_required(self): model = Model( 'Person', { 'name': fields.String(required=True), 'age': fields.Integer, 'birthdate': fields.DateTime(required=True), }) self.assertEqual( model.__schema__, { 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' } }, 'required': ['birthdate', 'name'], 'type': 'object' })
def test_model_as_dict_with_list(self): model = Model( 'Person', { 'name': fields.String, 'age': fields.Integer, 'tags': fields.List(fields.String), }) assert model.__schema__ == { 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'tags': { 'type': 'array', 'items': { 'type': 'string' } } }, 'type': 'object' }
def test_model_as_flat_dict(self): model = Model( 'Person', { 'name': fields.String, 'age': fields.Integer, 'birthdate': fields.DateTime, }) assert isinstance(model, dict) assert not isinstance(model, OrderedDict) assert model.__schema__ == { 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' } }, 'type': 'object' }
def test_clone_from_class(self): parent = Model('Parent', { 'name': fields.String, 'age': fields.Integer, 'birthdate': fields.DateTime, }) child = Model.clone('Child', parent, { 'extra': fields.String, }) self.assertEqual(child.__schema__, { 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' }, 'extra': { 'type': 'string' } }, 'type': 'object' })
def test_model_deepcopy(self): parent = Model('Person', { 'name': fields.String, 'age': fields.Integer(description="foo"), }) child = parent.inherit('Child', { 'extra': fields.String, }) parent_copy = copy.deepcopy(parent) self.assertEqual(parent_copy["age"].description, "foo") parent_copy["age"].description = "bar" self.assertEqual(parent["age"].description, "foo") self.assertEqual(parent_copy["age"].description, "bar") child = parent.inherit('Child', { 'extra': fields.String, }) child_copy = copy.deepcopy(child) self.assertEqual(child_copy.__parents__[0], parent)
def test_inherit_from_class(self): parent = Model('Parent', { 'name': fields.String, 'age': fields.Integer, }) child = Model.inherit('Child', parent, { 'extra': fields.String, }) self.assertEqual(parent.__schema__, { 'properties': { 'name': {'type': 'string'}, 'age': {'type': 'integer'}, }, 'type': 'object' }) self.assertEqual(child.__schema__, { 'allOf': [ {'$ref': '#/definitions/Parent'}, { 'properties': { 'extra': {'type': 'string'} }, 'type': 'object' } ] })
def create_collection_response(self, data: Union[List[Dict[str, Any]], List[object]]): """ To create an HTTP response body of a collection of results including paging metadata. :param data: The items in this list will be formatted based on the fields defined in `self.model` and then included in the data field of the returned dictionary. A field included in a data item but not in the model will be left out of the response. A field in the model but not in a data item will be `None` in the response. :return: Dictionary to be translated to JSON for an HTTP response body. """ response = {"data": data, "paging": {"totalResults": len(data)}} model = Model( 'CollectionResponse', { 'data': fields.List( fields.Nested(self.model, description='results of the request')), 'paging': fields.Nested({'totalResults': fields.Integer}, description='number of results') }) return marshal(response, model)
def convert_sqlalchemy_to_restplus_model(table: Table) -> Model: """ Convert an sqlalchemy table to a restplus model. Adds support for the field types defined in map_sqlalchemy_to_restplus_type, as well as description and required. :param table: The sqlalchemy table. :return: a restplus model derived from the table. """ map_sqlalchemy_to_restplus_type = { 'FLOAT': fields.Float, 'INTEGER': fields.Integer, 'VARCHAR': fields.String, 'DATETIME': fields.DateTime, 'DATE': fields.Date, } def _convert_sqlalchemy_to_restplus_column( column: Column) -> (str, fields): """ Inner function used by the map to convert each column. :param column: the sqlalchemy column. :return: a tuple with the name and field, usable for restplus. """ type: str = str(column.type) return column.name, map_sqlalchemy_to_restplus_type[type]( description=column.comment, required=column.nullable) results = map(_convert_sqlalchemy_to_restplus_column, table.columns) return Model(table.name, {row[0]: row[1] for row in results})
def test_clone_from_instance(self): parent = Model( 'Parent', { 'name': fields.String, 'age': fields.Integer, 'birthdate': fields.DateTime, }) child = parent.clone('Child', { 'extra': fields.String, }) assert child.__schema__ == { 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' }, 'extra': { 'type': 'string' } }, 'type': 'object' }
class BranchModel: branch = Model( 'branch', { 'code': fields.String(required=True, description='branch code'), 'name': fields.String(required=True, description='branch name'), }) branch_success = ResponseModel.success_response.clone( 'branch_success', {'result': fields.List(fields.Nested(branch))}) branch_error = ResponseModel.error_response.clone('branch_error') branch_mapping = Model('branch_mapping') branch_mapping_success = ResponseModel.success_response.clone( 'branch_mapping_success', {'result': fields.Raw(description="'branch_code':'branch_name'")})
def test_model_as_nested_dict_with_list(self): address = Model('Address', { 'road': fields.String, }) person = Model( 'Person', { 'name': fields.String, 'age': fields.Integer, 'birthdate': fields.DateTime, 'addresses': fields.List(fields.Nested(address)) }) self.assertEqual( person.__schema__, { # 'required': ['address'], 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' }, 'addresses': { 'type': 'array', 'items': { '$ref': '#/definitions/Address', } } }, 'type': 'object' }) self.assertEqual(address.__schema__, { 'properties': { 'road': { 'type': 'string' }, }, 'type': 'object' })
def test_filter_restplus_columns(): model: Model = Model( 'overview', { 'id': fields.Integer(description='The identifier of the overview'), 'continent': fields.String( description='The continent where the overview is located'), 'lat': fields.Float( description= 'The latitudinal coordinate of the geolocation of the overview' ), 'altitude_min_m': fields.Integer( description='The lowest altitude of the overview (in metres)'), 'altitude_max_m': fields.Integer(description=None), }) mask = ['continent', 'lat'] expected: Model = Model( 'overview', { 'continent': fields.String( description='The continent where the overview is located'), 'lat': fields.Float( description= 'The latitudinal coordinate of the geolocation of the overview' ), }) result: Model = filter_restplus_columns(model, mask) assert isinstance(result, type(expected)) assert result.name == expected.name assert len(result.items()) == len(expected.items()) for key in expected.keys(): assert key in result.keys() assert isinstance(result[key], type(expected[key])) assert expected[key].description == result[key].description
def filter_restplus_columns(model: Model, mask: List[str]) -> Model: """ Filter the columns to your desired list that are specified in the mask. I favored this option instead of the built-in mask possibilities, because the mask can be overridden by the user. :param model: the current restplus model. :param mask: a list of all columns that should be retained. :return: a restplus model with only the columns that are in the given mask. """ return Model(model.name, {key: model[key] for key in model if key in mask})
def test_model_as_nested_dict(self): address = Model('Address', { 'road': fields.String, }) person = Model( 'Person', { 'name': fields.String, 'age': fields.Integer, 'birthdate': fields.DateTime, 'address': fields.Nested(address) }) assert person.__schema__ == { # 'required': ['address'], 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' }, 'address': { '$ref': '#/definitions/Address', } }, 'type': 'object' } assert address.__schema__ == { 'properties': { 'road': { 'type': 'string' }, }, 'type': 'object' }
def test_models(self): todo_fields = Model('Todo', { 'task': fields.String(required=True, description='The task details') }) parser = RequestParser() parser.add_argument('todo', type=todo_fields) assert parser.__schema__ == [{ 'name': 'todo', 'type': 'Todo', 'in': 'body', }]
def test_models(self): # app = Flask(__name__) # api = Api(app) todo_fields = Model('Todo', { 'task': fields.String(required=True, description='The task details') }) parser = RequestParser() parser.add_argument('todo', type=todo_fields) self.assertEqual(parser.__schema__, [{ 'name': 'todo', 'type': 'Todo', 'in': 'body', }])
def test_model_as_nested_dict_and_required(self): address = Model('Address', { 'road': fields.String, }) person = Model('Person', { 'name': fields.String, 'age': fields.Integer, 'birthdate': fields.DateTime, 'address': fields.Nested(address, required=True) }) self.assertEqual(person.__schema__, { 'required': ['address'], 'properties': { 'name': { 'type': 'string' }, 'age': { 'type': 'integer' }, 'birthdate': { 'type': 'string', 'format': 'date-time' }, 'address': { '$ref': '#/definitions/Address', } } }) self.assertEqual(address.__schema__, { 'properties': { 'road': { 'type': 'string' }, } })
def test_parse_model(self): model = Model('Todo', {'task': fields.String(required=True)}) parser = RequestParser() parser.add_argument('todo', type=model, required=True) data = {'todo': {'task': 'aaa'}} with self.app.test_request_context('/', method='post', data=json.dumps(data), content_type='application/json'): args = parser.parse_args() self.assertEqual(args['todo'], {'task': 'aaa'})