def __new__(cls, name, bases, attributes): model = attributes.get(Meta.MODEL_NAME) resource_fields = {} if model: ignore_fields = attributes.get(Meta.IGNORE_FIELDS, []) raw_fields = [x for x in model.__dict__ if x not in ignore_fields and not x.startswith('_')] for field in raw_fields: value = getattr(model, field) if isinstance(value, InstrumentedAttribute): field_type = value.comparator.type if isinstance(field_type, (sqltypes.String, sqltypes.Text)): resource_fields[field] = fields.String elif isinstance(field_type, sqltypes.Integer): resource_fields[field] = fields.Integer elif isinstance(field_type, sqltypes.Boolean): resource_fields[field] = fields.Boolean elif isinstance(field_type, sqltypes.DateTime): resource_fields[field] = fields.DateTime(dt_format='iso8601') elif isinstance(field_type, sqltypes.DECIMAL): resource_fields[field] = fields.MyDecimal else: resource_fields[field] = fields.String # add extra fields extra_fields = attributes.get(Meta.EXTRA_FIELDS, {}) if isinstance(extra_fields, dict): resource_fields.update(extra_fields) attributes['resource_fields'] = resource_fields meta = type.__new__(cls, name, bases, attributes) swagger.add_model(meta) return meta
def __new__(cls, name, bases, attributes): if name == 'Serializer': return type.__new__(cls, name, bases, attributes) model = attributes.pop('__model__', None) # type: User exclude_fields = attributes.pop('__exclude_fields__', []) include_fields = attributes.pop('__include_fields__', {}) new_entity_fields = attributes.pop('__new_entity_fields__', []) class_dict = attributes.copy() class_dict['resource_fields'] = resource_fields = {} class_dict['exclude_fields'] = exclude_fields class_dict['include_fields'] = include_fields class_dict['new_entity_fields'] = new_entity_fields if model: for column in model.__table__.columns: if column.name in exclude_fields: continue field_type_name = column.type.__visit_name__ field_type = MAPPING.get(field_type_name) if not field_type: field_type = fields.String resource_fields[column.name] = field_type if include_fields: resource_fields.update(include_fields) s = type.__new__(cls, name, bases, class_dict) swagger.add_model(s) return s
def test_add_model_with_resource_fields_nested_swagger_metadata(model_class, ): """Test for model with resource fields, nested subclass, swagger metadata * resource_fields: YES * nested subclass: YES * __init__: NO * swagger_metadata:YES """ pdst = patch_deduce_swagger_type pr = patch_registry ppd = patch_parse_doc pha = patch_hasattr with pr(), ppd(), patch_isinstance(True) as mock_isinstance: with pha() as mock_hasattr: with patch_dir(["resource_fields"]) as mock_dir: with pdst() as mock_deduce_swagger_type: swagger.add_model(model_class) mock_dir.assert_called_with(model_class) assert mock_dir.call_count == 2 mock_hasattr.assert_called_once_with( model_class, "required") mock_isinstance.assert_called_with(model_class, swagger._Nested) assert mock_deduce_swagger_type.call_count == len( model_class.resource_fields.items())
def __new__(cls, name, bases, attributes): if name == 'EntityBase': return type.__new__(cls, name, bases, attributes) parser = RequestParser() fields = [(name, field) for name, field in iteritems(attributes) if isinstance(field, Field)] field_names = set() resource_fields = dict() for name, field in fields: if inspect.isclass(field.type) and issubclass( field.type, EntityBase): field.type = field.type.parse field.location = 'json' parser.add_argument(field) field_names.add(name) resource_fields[name] = get_field_type(field.type) del attributes[name] attributes['entity_parser'] = parser attributes['entity_fields'] = field_names attributes['resource_fields'] = resource_fields schema = type.__new__(cls, name, bases, attributes) # support swagger swagger.add_model(schema) return schema
def test_integration_test_add_model(test_input, properties, required, defaults): """Integration test for `add_model(...)` method. Ensures models are added to `registry["models"]` with expected structure. Example each model should have 'description', 'id','notes', 'properties', etc. Example `registry["models"]`: # print(registry["models"]) { 'models': { ..... 'MockTodoItem': { 'description': 'This is an example of a ' 'model class that has ' 'parameters in its ' 'constructor', 'id': 'MockTodoItem', 'notes': 'and the fields in the swagger spec ' 'are derived from the ' 'parameters<br/>to __init__.<br/>In ' 'this case we would have args, arg2 ' 'as required parameters and arg3 ' 'as<br/>optional parameter.', 'properties': { 'arg1': {'type': 'string'}, 'arg2': {'type': 'string'}, 'arg3': { 'default': '123', 'type': 'string'}}, 'required': ['arg1', 'arg2']}, .......... """ with patch_registry() as registry: swagger.add_model(test_input) assert test_input.__name__ in registry["models"] assert "description" in registry["models"][test_input.__name__] assert "notes" in registry["models"][test_input.__name__] if "resource_fields" not in dir(test_input) and "__init__" not in dir( test_input): # in py2, classes without __init__ or resource_fields defined # will cause issues. # note, no issue in PY3. pytest.fail( "do not call without resource_fields or __init__ defined.") if "resource_fields" in dir(test_input): if hasattr(test_input, "required"): assert "required" in registry["models"][test_input.__name__] elif "__init__" in dir(test_input): assert "required" in registry["models"][test_input.__name__] assert "properties" in registry["models"][test_input.__name__]
def test_add_model_init_parsing_args(model_class, required, defaults): """Test to verify args parsed correctly """ with patch_registry() as registry, patch_parse_doc(), patch_dir( ["__init__"]): swagger.add_model(model_class) assert model_class.__name__ in registry["models"] assert registry["models"][model_class.__name__]["required"] == required for key, default_value in defaults: _name = model_class.__name__ assert key in registry["models"][_name]["properties"] assert (default_value == registry["models"][_name]["properties"] [key]["default"])
def wrapper(func): attr = func.__dict__['__swagger_attr'] params = attr.get('parameters', []) resource_fields = {} for field in cls.new_entity_fields: if isinstance(field, tuple): name, schema_type = field else: name, schema_type = field, cls.resource_fields.get(field) resource_fields[name] = schema_type attributes = { 'resource_fields': resource_fields, '__doc__': 'create new entity' } entity_model = type(entity_name, (object, ), attributes) swagger.add_model(entity_model) params.append(post_parameter(entity_model)) attr['parameters'] = params return func
def test_add_model_no_init(model_class): """Test for model with only init * resource_fields: NO * nested subclass: NO * __init__: NO * swagger_metadata: NO """ pdst = patch_deduce_swagger_type pr = patch_registry ppd = patch_parse_doc pgas = patch_getargspec pha = patch_hasattr with pdst() as mock_deduce_swagger_type: with pr(), ppd(), pgas() as mock_getargspec: with pha() as mock_hasattr: swagger.add_model(model_class) mock_getargspec.assert_not_called() mock_hasattr.assert_not_called() mock_deduce_swagger_type.assert_not_called()
def test_add_model_with_resource_fields_without_swagger_metadata( mock_nested, mock_model_class, ): """Test adding model with resource fields, no init, without swagger metadata. """ pdst = patch_deduce_swagger_type pr = patch_registry ppd = patch_parse_doc pha = patch_hasattr with pr(), ppd(), patch_isinstance(False) as mock_isinstance: with pha() as mock_hasattr, patch_dir(["resource_fields"]) as mock_dir: with pdst() as mock_deduce_swagger_type: swagger.add_model(mock_model_class) mock_dir.assert_called_with(mock_model_class) assert mock_dir.call_count == 2 mock_hasattr.assert_called_once_with(mock_model_class, "required") mock_isinstance.assert_called_with(mock_model_class, mock_nested) assert mock_deduce_swagger_type.call_count == len( mock_model_class.resource_fields.items())
class Exchanges(Resource): @swagger.operation( responseClass=StockMarket.__name__, nickname='get', parameters=[ { "name": "Authorization", "required": True, "allowMultiple": False, "dataType": "string", "paramType": "header", "description": "Bearer <token>" } ], responseMessages=[ { "code": 403, "message": "For this endpoint your need one of these permissions: {0}, {1}".format('exchanges', 'exchanges_only_read') }, { "code": 401, "message": "Token has expired" } ] ) @jwt_required @roles_required('exchanges', 'exchanges_only_read') def get(self): """ List Stock market endpoint :return: """ stock_markets = [] for stock in StockMarket.query.all(): stock_markets.append(stock.to_json()) return stock_markets, 200 @jwt_required @roles_required('exchanges') def post(self): """ :return: status """ return Response(status=201) @jwt_required @roles_required('exchanges') def delete(self): """ Delete endpoint method Remove from db Stock Market object by it's name :data_example:{"id":"1"} :return: status """ json_data = request.get_json() try: delete_sm = StockMarket.query.filter_by(id=json_data['id']).first() create_action_log("{0} was removed".format(delete_sm.name), "Exchanges") delete_sm.delete() return Response(status=204) except: BadRequest(description="Can't delete the object with current name or id") @swagger.operation( responseClass=StockMarket.__name__, parameters=[ { "name": "body", "required": True, "allowMultiple": False, "dataType": "json", "paramType": "body", "description": '{"leverage": integer, "balance_percentage": integer, "id":string}' }, { "name": "Authorization", "required": True, "allowMultiple": False, "dataType": "string", "paramType": "header" } ], responseMessages=[ { "code": 403, "message": "For this endpoint your need one of these permissions: {0}".format('exchanges') }, { "code": 401, "message": "Token has expired" }, { "message": 'ID is not in request', "code": 400 }, { "message": "Stock Market with current id is not found", "code": 204 } ] ) @jwt_required @roles_required('exchanges') def put(self): """ The update Exchanges endpoint method :data_example:{"leverage": 11, "balance_percentage": 50, "id":"1"} :return: status code """ json_data = request.get_json() if 'id' not in json_data: return 'ID is not in request', 400 current_sm = StockMarket.query.filter_by(id=json_data['id']).first() if not current_sm: return "Stock Market with current id is not found", 204 action = "" if 'balance_percentage' in json_data: balance_percentage = check_0_max(json_data['balance_percentage'], 100) if balance_percentage != current_sm.balance_percentage: action += "Balance percentage for {2} was changed from {0} to {1}.\n".format( current_sm.balance_percentage, balance_percentage, current_sm.name) current_sm.balance_percentage = balance_percentage if 'leverage' in json_data: leverage = check_0_max(json_data['leverage'], current_sm.max_leverage) if leverage != current_sm.leverage: action += "Leverage for {2} was changed from {0} to {1}.".format( current_sm.leverage, leverage, current_sm.name) current_sm.leverage = leverage current_sm.save() create_action_log(action, "Exchanges") return Response(status=200) swagger.add_model(StockMarket)
def test_add_model_get_docs(input_model): """Ensure `_parse_doc(...)` is called without issues""" with patch_registry(), patch_parse_doc() as mock_parse_doc: swagger.add_model(input_model) mock_parse_doc.assert_called_once_with(input_model)