Skip to content

Commit

Permalink
Implement entity schematic
Browse files Browse the repository at this point in the history
  • Loading branch information
apryor6 committed Aug 18, 2019
1 parent 619bacf commit 9f5bf6c
Show file tree
Hide file tree
Showing 14 changed files with 404 additions and 0 deletions.
11 changes: 11 additions & 0 deletions flaskerize/schematics/entity/custom_functions.py
@@ -0,0 +1,11 @@
from flaskerize import register_custom_function


@register_custom_function
def capitalize(val: str) -> str:
return val.capitalize()


@register_custom_function
def lower(val: str) -> str:
return val.lower()
@@ -0,0 +1,9 @@
from .model import {{ capitalize(name) }} # noqa
from .schema import {{ capitalize(name) }}Schema # noqa


def register_routes(root_api, root="/api"):
from .controller import api as {{ lower(name) }}_api

root_api.add_namespace({{ lower(name) }}_api, path=f"{root}/{{ lower(name) }}")
return root_api
@@ -0,0 +1,57 @@
from flask_restplus import Resource
from flask import request
from flask_restplus import Namespace
from flask_accepts import accepts, responds
from flask.wrappers import Response
from typing import List

from .schema import {{ capitalize(name) }}Schema
from .model import {{ capitalize(name) }}
from .service import {{ capitalize(name) }}Service

api = Namespace("{{ capitalize(name) }}", description="{{ capitalize(name) }} information")


@api.route("/")
class {{ capitalize(name) }}Resource(Resource):
"""{{ capitalize(name) }}s"""

@responds(schema={{ capitalize(name) }}Schema, many=True)
def get(self) -> List[{{ capitalize(name) }}]:
"""Get all {{ capitalize(name) }}s"""

return {{ capitalize(name) }}Service.get_all()

@accepts(schema={{ capitalize(name) }}Schema, api=api)
@responds(schema={{ capitalize(name) }}Schema)
def post(self):
"""Create a Single {{ capitalize(name) }}"""

return {{ capitalize(name) }}Service.create(request.parsed_obj)


@api.route("/<int:{{ lower(name) }}Id>")
@api.param("{{ lower(name) }}Id", "{{ capitalize(name) }} database ID")
class {{ capitalize(name) }}IdResource(Resource):
@responds(schema={{ capitalize(name) }}Schema)
def get(self, {{ lower(name) }}Id: int) -> {{ capitalize(name) }}:
"""Get Single {{ capitalize(name) }}"""

return {{ capitalize(name) }}Service.get_by_id({{ lower(name) }}Id)

def delete(self, {{ lower(name) }}Id: int) -> Response:
"""Delete Single {{ capitalize(name) }}"""

from flask import jsonify

id = {{ capitalize(name) }}Service.delete_by_id({{ lower(name) }}Id)
return jsonify(dict(status="Success", id=id))

@accepts(schema={{ capitalize(name) }}Schema, api=api)
@responds(schema={{ capitalize(name) }}Schema)
def put(self, {{ lower(name) }}Id: int) -> {{ capitalize(name) }}:
"""Update Single {{ capitalize(name) }}"""

changes = request.parsed_obj
{{ lower(name) }} = {{ capitalize(name) }}Service.get_by_id({{ lower(name) }}Id)
return {{ capitalize(name) }}Service.update({{ lower(name) }}, changes)
@@ -0,0 +1,96 @@
from unittest.mock import patch
from flask.testing import FlaskClient
from flask.wrappers import Response

from app.test.fixtures import client, app # noqa
from .model import {{ capitalize(name) }}
from .schema import {{ capitalize(name) }}Schema
from .service import {{ capitalize(name) }}Service
from .interface import {{ capitalize(name) }}Interface


def {{ lower(name) }}(id: int = 123, name: str = "Test name") -> {{ capitalize(name) }}:
return {{ capitalize(name) }}({{ lower(name) }}_id=id, name="Test name", description="Test description")


class Test{{ capitalize(name) }}Resource:
@patch.object({{ capitalize(name) }}Service, "get_all", lambda: [{{ lower(name) }}(123), {{ lower(name) }}(456)])
def test_get(self, client: FlaskClient): # noqa
with client:
results = client.get("/api/{{ lower(name) }}", follow_redirects=True).get_json()
expected = {{ capitalize(name) }}Schema(many=True).dump([{{ lower(name) }}(456), {{ lower(name) }}(123)]).data
for r in results:
assert r in expected


class Test{{ capitalize(name) }}{{ capitalize(name) }}Resource:
@patch.object(
{{ capitalize(name) }}Service,
"get_all",
lambda: [{{ lower(name) }}(123, name="Test name 1"), {{ lower(name) }}(456, name="Test name 2")],
)
def test_get(self, client: FlaskClient): # noqa
with client:
results: dict = client.get("/api/{{ lower(name) }}", follow_redirects=True).get_json()
expected = (
{{ capitalize(name) }}Schema(many=True)
.dump([{{ lower(name) }}(123, name="Test name 1"), {{ lower(name) }}(456, name="Test name 2")])
.data
)
for r in results:
assert r in expected

@patch.object(
{{ capitalize(name) }}Service,
"create",
lambda create_request: {{ capitalize(name) }}(
{{ lower(name) }}_id=create_request["{{ lower(name) }}_id"],
name=create_request["name"],
description=create_request["description"],
),
)
def test_post(self, client: FlaskClient): # noqa
with client:

payload = dict(name="Test name", description="Test description")
result: dict = client.post("/api/{{ lower(name) }}/", json=payload).get_json()
expected = (
{{ capitalize(name) }}Schema()
.dump({{ capitalize(name) }}(name=payload["name"], description=payload["description"]))
.data
)
assert result == expected


def fake_update({{ lower(name) }}: {{ capitalize(name) }}, changes: {{ capitalize(name) }}Interface) -> {{ capitalize(name) }}:
# To fake an update, just return a new object
updated_{{ lower(name) }} = {{ capitalize(name) }}({{ lower(name) }}_id={{ lower(name) }}.{{ lower(name) }}_id, name=changes["name"])
return updated_{{ lower(name) }}


class Test{{ capitalize(name) }}{{ capitalize(name) }}IdResource:
@patch.object({{ capitalize(name) }}Service, "get_by_id", lambda id: {{ capitalize(name) }}({{ lower(name) }}_id=id))
def test_get(self, client: FlaskClient): # noqa
with client:
result: dict = client.get("/api/{{ lower(name) }}/123").get_json()
expected = {{ capitalize(name) }}({{ lower(name) }}_id=123)
assert result["{{ lower(name) }}Id"] == expected.{{ lower(name) }}_id

@patch.object({{ capitalize(name) }}Service, "delete_by_id", lambda id: [id])
def test_delete(self, client: FlaskClient): # noqa
with client:
result: dict = client.delete("/api/{{ lower(name) }}/123").get_json()
expected = dict(status="Success", id=[123])
assert result == expected

@patch.object({{ capitalize(name) }}Service, "get_by_id", lambda id: {{ capitalize(name) }}({{ lower(name) }}_id=id))
@patch.object({{ capitalize(name) }}Service, "update", fake_update)
def test_put(self, client: FlaskClient): # noqa
with client:
result: dict = client.put(
"/api/{{ lower(name) }}/123", json={"name": "New name"}
).get_json()
expected: dict = {{ capitalize(name) }}Schema().dump(
{{ capitalize(name) }}({{ lower(name) }}_id=123, name="New name")
).data
assert result == expected
@@ -0,0 +1,9 @@
from datetime import datetime
from mypy_extensions import TypedDict


class {{ capitalize(name) }}Interface(TypedDict, total=False):
{{ lower(name) }}_id: int
name: str
description: str

@@ -0,0 +1,24 @@
from pytest import fixture

from app.product import Product
from .model import {{ capitalize(name) }}
from .interface import {{ capitalize(name) }}Interface


@fixture
def interface() -> {{ capitalize(name) }}Interface:

params: {{ capitalize(name) }}Interface = {
"{{ lower(name) }}_id": 1,
"name": "Test name",
"description": "Test description",
}
return params


def test_{{ capitalize(name) }}Interface_create(interface: {{ capitalize(name) }}Interface):
assert interface


def test_{{ capitalize(name) }}Interface_works(interface: {{ capitalize(name) }}Interface):
assert {{ capitalize(name) }}(**interface)
@@ -0,0 +1,17 @@
from sqlalchemy import Integer, Column, String
from app import db # noqa
from .interface import {{ capitalize(name) }}Interface


class {{ capitalize(name) }}(db.Model):
"""A Flaskerific {{ capitalize(name) }}"""

__tablename__ = "{{ lower(name) }}"
{{ lower(name) }}_id = Column(Integer(), primary_key=True)
name = Column(String(255))
description = Column(String(255))

def update(self, changes):
for key, val in changes.items():
setattr(self, key, val)
return
@@ -0,0 +1,21 @@
from pytest import fixture
from flask_sqlalchemy import SQLAlchemy

from app.test.fixtures import app, db # noqa
from .model import {{ capitalize(name) }}


@fixture
def {{ lower(name) }}() -> {{ capitalize(name) }}:
return {{ capitalize(name) }}({{ lower(name) }}_id=1, name="Test name", description="Test description")


def test_{{ capitalize(name) }}_create({{ lower(name) }}: {{ capitalize(name) }}):
assert {{ lower(name) }}


def test_{{ capitalize(name) }}_retrieve({{ lower(name) }}: {{ capitalize(name) }}, db: SQLAlchemy): # noqa
db.session.add({{ lower(name) }})
db.session.commit()
s = {{ capitalize(name) }}.query.first()
assert s.__dict__ == {{ lower(name) }}.__dict__
@@ -0,0 +1,13 @@
from marshmallow import fields, Schema


class {{ capitalize(name) }}Schema(Schema):
"""{{ capitalize(name) }}"""

class Meta:
ordered = True

{{ lower(name) }}Id = fields.Number(attribute="{{ lower(name) }}_id")
name = fields.String(attribute="name")
description = fields.String(attribute="description")

@@ -0,0 +1,26 @@
from pytest import fixture

from .model import {{ capitalize(name) }}
from .schema import {{ capitalize(name) }}Schema
from .interface import {{ capitalize(name) }}Interface


@fixture
def schema() -> {{ capitalize(name) }}Schema:
return {{ capitalize(name) }}Schema()


def test_{{ capitalize(name) }}Schema_create(schema: {{ capitalize(name) }}Schema):
assert schema


def test_{{ capitalize(name) }}Schema_works(schema: {{ capitalize(name) }}Schema):
params: {{ capitalize(name) }}Interface = schema.load(
{"{{ lower(name) }}Id": 1, "name": "Test name", "description": "Test description"}
).data
{{ lower(name) }} = {{ capitalize(name) }}(**params)

assert {{ lower(name) }}.{{ lower(name) }}_id == 1
assert {{ lower(name) }}.name == "Test description"
assert {{ lower(name) }}.description == "Test description"

@@ -0,0 +1,44 @@
from typing import List

from app import db # noqa
from .model import {{ capitalize(name) }}
from .interface import {{ capitalize(name) }}Interface


class {{ capitalize(name) }}Service:
@staticmethod
def get_all() -> List[{{ capitalize(name) }}]:
return {{ capitalize(name) }}.query.all()

@staticmethod
def get_by_id({{ lower(name) }}_id: int) -> {{ capitalize(name) }}:
return {{ capitalize(name) }}.query.get({{ lower(name) }}_id)

@staticmethod
def update({{ lower(name) }}: {{ capitalize(name) }}, {{ lower(name) }}_change_updates: {{ capitalize(name) }}Interface) -> {{ capitalize(name) }}:
{{ lower(name) }}.update({{ lower(name) }}_change_updates)
db.session.commit()
return {{ lower(name) }}

@staticmethod
def delete_by_id({{ lower(name) }}_id: int) -> List[int]:
{{ lower(name) }} = {{ capitalize(name) }}.query.filter({{ capitalize(name) }}.{{ lower(name) }}_id == {{ lower(name) }}_id).first()
if not {{ lower(name) }}:
return []
db.session.delete({{ lower(name) }})
db.session.commit()
return [{{ lower(name) }}_id]

@staticmethod
def create(new_attrs: {{ capitalize(name) }}Interface) -> {{ capitalize(name) }}:
new_{{ lower(name) }} = {{ capitalize(name) }}(
{{ lower(name) }}_id=new_attrs["{{ lower(name) }}_id"],
name=new_attrs["name"],
description=new_attrs["description"],
)

db.session.add(new_{{ lower(name) }})
db.session.commit()

return new_{{ lower(name) }}

@@ -0,0 +1,61 @@
from app.test.fixtures import app, db # noqa
from flask_sqlalchemy import SQLAlchemy

from typing import List
from .model import {{ capitalize(name) }}
from .service import {{ capitalize(name) }}Service # noqa
from .interface import {{ capitalize(name) }}Interface


def test_get_all(db: SQLAlchemy): # noqa
yin: {{ capitalize(name) }} = {{ capitalize(name) }}({{ lower(name) }}_id=1, name="Yin", description="Test description")
yang: {{ capitalize(name) }} = {{ capitalize(name) }}({{ lower(name) }}_id=2, name="Yaang", description="Test description")
db.session.add(yin)
db.session.add(yang)
db.session.commit()

results: List[{{ capitalize(name) }}] = {{ capitalize(name) }}Service.get_all()

assert len(results) == 2
assert yin in results and yang in results


def test_update(db: SQLAlchemy): # noqa
yin: {{ capitalize(name) }} = {{ capitalize(name) }}({{ lower(name) }}_id=1, name="Yin", description="Test description")

db.session.add(yin)
db.session.commit()
updates = dict({{ lower(name) }}="Yang")

{{ capitalize(name) }}Service.update(yin, updates)

result: {{ capitalize(name) }} = {{ capitalize(name) }}.query.get(yin.{{ lower(name) }}_id)
assert result.name == "Yang"


def test_delete_by_id(db: SQLAlchemy): # noqa
yin: {{ capitalize(name) }} = {{ capitalize(name) }}({{ lower(name) }}_id=1, name="Yin", description="Test description")
yang: {{ capitalize(name) }} = {{ capitalize(name) }}({{ lower(name) }}_id=2, name="Yang", description="Test description")
db.session.add(yin)
db.session.add(yang)
db.session.commit()

{{ capitalize(name) }}Service.delete_by_id(1)
results: List[{{ capitalize(name) }}] = {{ capitalize(name) }}.query.all()

assert len(results) == 1
assert yin not in results and yang in results


def test_create(db: SQLAlchemy): # noqa

yin: {{ capitalize(name) }}Interface = {{ capitalize(name) }}Interface(
{{ lower(name) }}_id=1, name="Yin", description="Test description"
)
{{ capitalize(name) }}Service.create(yin)
results: List[{{ capitalize(name) }}] = {{ capitalize(name) }}.query.all()

assert len(results) == 1

for k in yin.keys():
assert getattr(results[0], k) == yin[k]

0 comments on commit 9f5bf6c

Please sign in to comment.