Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions example/app.py

This file was deleted.

12 changes: 0 additions & 12 deletions example/controllers/home_controller.py

This file was deleted.

1 change: 0 additions & 1 deletion example/views/index.html

This file was deleted.

12 changes: 0 additions & 12 deletions example/views/post/new.html

This file was deleted.

68 changes: 42 additions & 26 deletions mvc_flask/__init__.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,55 @@
import json
from pathlib import Path
from importlib import import_module
import json

from pathlib import Path
from flask import Flask
from flask.blueprints import Blueprint
from collections import namedtuple


Route = namedtuple("Route", ["method", "path", "controller", "action"])


class FlaskMVC:
def __init__(self, app: Flask = None):
def __init__(self, app: Flask = None, directory: str = "app"):
self.directory = Path(directory)

if app is not None:
self.init_app(app)

def init_app(self, app):
app.template_folder = "views"
app.config.setdefault("FLASK_MVC_DIR", "app")

self.root_path = Path(app.config["FLASK_MVC_DIR"])

self._register_router(app)

def _routes(self):
with open(self.root_path / "routes.json", mode="r") as f:
return json.load(f)

def _register_router(self, app):
for route in self._routes():
controller = route["controller"]

mod = import_module(
f"{self.root_path}.controllers.{controller}_controller"
self.create_blueprint(app)

def routes(self):
routes = []
with open(self.directory / "routes.json", mode="r") as f:
routes = [
Route(
route["method"],
route["path"],
route["controller"],
route["action"],
)
for route in json.load(f)
]
return routes

def create_blueprint(self, app: Flask):
for route in self.routes():
dd = (
self.directory
/ "controllers"
/ f"{route.controller}_controller"
)
clazz = getattr(mod, f"{controller.title()}Controller")

app.add_url_rule(
route["path"],
endpoint=f"{controller}.{route['action']}",
view_func=getattr(clazz(), route["action"]),
methods=[route["method"]],
obj = import_module(dd.as_posix().replace("/", "."))
controller = getattr(obj, f"{route.controller.title()}Controller")

blueprint = Blueprint(route.controller, route.controller)
blueprint.add_url_rule(
rule=route.path,
endpoint=route.action,
view_func=getattr(controller(), route.action),
methods=[route.method],
)
app.register_blueprint(blueprint)
14 changes: 14 additions & 0 deletions sample_app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from flask import Flask
from mvc_flask import FlaskMVC


def create_app():
app = Flask(__name__)
return app


if __name__ == "__main__":
app = create_app()
app.template_folder = "views"
FlaskMVC(app, ".")
app.run()
6 changes: 6 additions & 0 deletions sample_app/controllers/home_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from flask import render_template


class HomeController:
def index(self):
return render_template("index.html")
12 changes: 0 additions & 12 deletions example/routes.json → sample_app/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@
"controller": "home",
"action": "index"
},
{
"method": "get",
"path": "/new",
"controller": "home",
"action": "new"
},
{
"method": "post",
"path": "/create",
"controller": "home",
"action": "create"
},
{
"method": "GET",
"path": "/contact",
Expand Down
1 change: 1 addition & 0 deletions sample_app/views/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Hello, World!</h1>
Empty file added tests/__init__.py
Empty file.
21 changes: 10 additions & 11 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
from example.app import create_app
from mvc_flask import FlaskMVC
from sample_app.app import create_app
from ward import fixture
from mvc_flask import FlaskMVC


@fixture
def test_client():
def test_app():
app = create_app()
app.testing = True
app_contenxt = app.test_request_context()
app_contenxt.push()

return app.test_client()
app.template_folder = "views"
FlaskMVC(app, directory="sample_app")
return app


@fixture
def test_app():
app = create_app()
app.testing = True
def test_client(app=test_app):
app_contenxt = app.test_request_context()
app_contenxt.push()

return app
return app.test_client()
27 changes: 19 additions & 8 deletions tests/test_routes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from ward import test, expect, skip
from fixtures import test_app
from ward import test, expect
from tests.fixtures import test_app, test_client


@test("contains routes")
Expand All @@ -8,17 +8,13 @@ def _(app=test_app):

expect.assert_in("/contact", routes, None)
expect.assert_in("/", routes, None)
expect.assert_in("/new", routes, None)
expect.assert_in("/create", routes, None)


@test("contains endpoints")
def _(app=test_app):
endpoints = [route.endpoint for route in app.url_map.iter_rules()]

expect.assert_in("home.index", endpoints, None)
expect.assert_in("home.new", endpoints, None)
expect.assert_in("home.create", endpoints, None)
expect.assert_in("contact.index", endpoints, None)


Expand All @@ -30,5 +26,20 @@ def _(app=test_app):
for route in routes.methods
]

expect.assert_equal(methods.count("GET"), 4, None)
expect.assert_equal(methods.count("POST"), 1, None)
expect.assert_equal(methods.count("GET"), 3, None)


@test("must contains text")
def _(client=test_client):
res = client.get("/")

expect.assert_equal(res.status_code, 200, None)
expect.assert_in("Hello, World!", res.get_data(as_text=True), None)


@test("must contains text")
def _(client=test_client):
res = client.get("/contact")

expect.assert_equal(res.status_code, 200, None)
expect.assert_in("Contact page", res.get_data(as_text=True), None)
36 changes: 0 additions & 36 deletions tests/test_visitors_visit_routes.py

This file was deleted.