brucelee


Namebrucelee JSON
Version 1.1.0 PyPI version JSON
download
home_pagehttps://github.com/smjkzsl/brucelee
SummarySimple and elegant use of FastApi in MVC mode
upload_time2023-04-28 11:42:01
maintainer
docs_urlNone
authorBruce chou
requires_python>=3.6
licenseApache License 2.0
keywords web framework mvc framework fastapi framework
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # brucelee
A mvc framework used FastApi
Simple and elegant use of FastApi in MVC mode

[Demo](https://brucelee.2rails.cn/) 

### deploy one click on vercel:
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fsmjkzsl%brucelee&project-name=brucelee&repository-name=brucelee)

## usage:
### install:
```sh
pip install brucelee
```
### generate a project named `myproject` in current directory
```bash
brucelee project -d myproject
```
```bash
cd myproject 
```
now the project like this:
```
+---apps
+---configs
+---data
+---public
+---uploads 
```

### generate app
```bash
brucelee app 
[enter apps directory]
[enter app name like 'admin']
```
will generate an app in apps
### run project
```bash
brucelee run

    Started server process 
    Waiting for application startup.
    Application startup complete.
    Uvicorn running on  http://0.0.0.0:8000  (Press CTRL+C to quit)
```
open browser nav to http://127.0.0.1:8000 will see the web site

controller:
```python

from brucelee import api_router,api,Request,Response,BaseController,application,WebSocket,WebSocketDisconnect,UploadFile,File

from typing import Any, Dict ,List
from pydantic import conlist

application._public_auth_url = '/user/login'
application._user_auth_url = '/user/login'
 
@api_router(auth='public')
class TestController(BaseController): 
    @api.get("/user/login" )
    def login(self):
        """:title Login"""  
        redirect = self.get_param('redirect') if self.get_param('redirect') else '/' 
        return self.view() 
    @api.post("/test/verity_user",auth="none")
    async def verity_user(self):  
        username = self['username']
        password = self['password']
        redirect = self['redirect']
        if username and password:
            #do veritied
            if username in ['bruce','alice'] and password:
                return self._verity_successed(username,redirect)
            else:
                return self._verity_error() 
        return self._verity_error()
    
    @api.get("/user/logout")
    def logout(self):
        return self._user_logout()
    
    @api.post("/test/upload")
    async def upload_test(self, files: List[UploadFile] = File(...) ): 
        p = {}
        for file in files:
            path,url = await self._save_upload_file(file)
            p[file.filename] = [path,url]
        return {"files":p} 
    
    
    @api.get("/",auth='none' )
    def home(self,request:Request): 
        '''
        :title Home
        '''
        c = self.session.get('home',1)
        c = c+1  
        self.cookies["a"] = c
        if c>10:
            del self.cookies["a"]
            c = 0
        self.session['home'] = c
        text = "Hello World! I'm in FastapiMvcFramework"
        routers_map = application.routers_map
        routers = application.routes 
        return self.view()
    
    @api.get("/xml",auth='user')
    def get_legacy_data(self):
        """:title XML(only bruce)"""

        data = """<?xml version="1.0"?>
        <shampoo>
        <Header>
            Apply shampoo here.
        </Header>
        <Body>
            You'll have to use soap here.
        </Body>
        </shampoo>
        """
        return self.view(content=data,media_type="application/xml")
          
    @api.get("/chatgpt",auth="user")
    def chatgpt(self):
        """
        :title Chat(only alice)
        """
        return self.view()


 
 
websockets:Dict[str,WebSocket] = {}
import pusher

pusher_client = pusher.Pusher(
  app_id='1588311',
  key='3eb7cc894586d11b97de',
  secret='b1052d401c7d6542fc4f',
  cluster='ap3',
  ssl=True
)

@api_router(path="/{controller}")
class WSController(BaseController):  
    def __init__(self) -> None:
        super().__init__()
        
    @api.get("/" )
    def ws_home(self):
        """:title WebSocketDemo"""
        return self.view()

    @api.websocket("/chat/{client_id}")
    async def websocket_endpoint(self, websocket: WebSocket,client_id: int):
        await websocket.accept()
        websockets[client_id]=(websocket)
        try:
            while True:
                data = await websocket.receive_text()
                await websocket.send_text(f"You wrote: {data}" )
                for clientid in websockets:
                    if client_id!=clientid:
                        await websockets[clientid].send_text(f"Client #{client_id} says: {data}")
                 
        except WebSocketDisconnect:
            websockets.remove(websocket)
            for connection in websockets:
                await connection.send_text(f"Client #{client_id} left the chat")
             
```

home.html:

```html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>FastApi MVC Framework</title>
    <link rel="stylesheet" href="home.css" />

</head>

<body>
    <header style="text-align:left;display: flex;">
        <h1>Python</h1>
        <h4>on FastApi</h4>

    </header>
    <nav>
        {% for item in routers_map %} {% if 'GET' in routers_map[item]['methods'] %} {% if routers_map[item]['auth']=='none' or request.session['user'] %}
        <a href="{{routers_map[item]['path']}}">{{routers_map[item]['doc']
                and routers_map[item]['doc']['title'] or item}}</a> {% endif %} {% endif %} {% endfor %}

        <a href="#">About</a>
        <a href="#">Contact</a> {% if request.session['user'] %}
        <a href="/user/logout"><b>{{request.session['user']['username']}}</b>
                Logout</a> {% endif %}
    </nav>
    <section>
        <h2>Welcome to my website</h2>
        <p>This is an example of a responsive design that works well on both desktop and mobile devices.</p>
        <p>here is the `text` variable in class method:{{text}}</p>
        <p style="color:red"><b>{{flash}}</b></p>
    </section>
    <footer>
        <p>&copy; 2023 My Website</p>
    </footer>
</body>

</html>
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/smjkzsl/brucelee",
    "name": "brucelee",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "web framework,mvc framework,fastapi framework",
    "author": "Bruce chou",
    "author_email": "smjkzsl@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/19/70/f5d6b6479a3c3f43ac380735a253de31eeffdf71be2c5015b10f9a1fe023/brucelee-1.1.0.tar.gz",
    "platform": null,
    "description": "# brucelee\r\nA mvc framework used FastApi\r\nSimple and elegant use of FastApi in MVC mode\r\n\r\n[Demo](https://brucelee.2rails.cn/) \r\n\r\n### deploy one click on vercel:\r\n[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fsmjkzsl%brucelee&project-name=brucelee&repository-name=brucelee)\r\n\r\n## usage:\r\n### install:\r\n```sh\r\npip install brucelee\r\n```\r\n### generate a project named `myproject` in current directory\r\n```bash\r\nbrucelee project -d myproject\r\n```\r\n```bash\r\ncd myproject \r\n```\r\nnow the project like this:\r\n```\r\n+---apps\r\n+---configs\r\n+---data\r\n+---public\r\n+---uploads \r\n```\r\n\r\n### generate app\r\n```bash\r\nbrucelee app \r\n[enter apps directory]\r\n[enter app name like 'admin']\r\n```\r\nwill generate an app in apps\r\n### run project\r\n```bash\r\nbrucelee run\r\n\r\n    Started server process \r\n    Waiting for application startup.\r\n    Application startup complete.\r\n    Uvicorn running on  http://0.0.0.0:8000  (Press CTRL+C to quit)\r\n```\r\nopen browser nav to http://127.0.0.1:8000 will see the web site\r\n\r\ncontroller:\r\n```python\r\n\r\nfrom brucelee import api_router,api,Request,Response,BaseController,application,WebSocket,WebSocketDisconnect,UploadFile,File\r\n\r\nfrom typing import Any, Dict ,List\r\nfrom pydantic import conlist\r\n\r\napplication._public_auth_url = '/user/login'\r\napplication._user_auth_url = '/user/login'\r\n \r\n@api_router(auth='public')\r\nclass TestController(BaseController): \r\n    @api.get(\"/user/login\" )\r\n    def login(self):\r\n        \"\"\":title Login\"\"\"  \r\n        redirect = self.get_param('redirect') if self.get_param('redirect') else '/' \r\n        return self.view() \r\n    @api.post(\"/test/verity_user\",auth=\"none\")\r\n    async def verity_user(self):  \r\n        username = self['username']\r\n        password = self['password']\r\n        redirect = self['redirect']\r\n        if username and password:\r\n            #do veritied\r\n            if username in ['bruce','alice'] and password:\r\n                return self._verity_successed(username,redirect)\r\n            else:\r\n                return self._verity_error() \r\n        return self._verity_error()\r\n    \r\n    @api.get(\"/user/logout\")\r\n    def logout(self):\r\n        return self._user_logout()\r\n    \r\n    @api.post(\"/test/upload\")\r\n    async def upload_test(self, files: List[UploadFile] = File(...) ): \r\n        p = {}\r\n        for file in files:\r\n            path,url = await self._save_upload_file(file)\r\n            p[file.filename] = [path,url]\r\n        return {\"files\":p} \r\n    \r\n    \r\n    @api.get(\"/\",auth='none' )\r\n    def home(self,request:Request): \r\n        '''\r\n        :title Home\r\n        '''\r\n        c = self.session.get('home',1)\r\n        c = c+1  \r\n        self.cookies[\"a\"] = c\r\n        if c>10:\r\n            del self.cookies[\"a\"]\r\n            c = 0\r\n        self.session['home'] = c\r\n        text = \"Hello World! I'm in FastapiMvcFramework\"\r\n        routers_map = application.routers_map\r\n        routers = application.routes \r\n        return self.view()\r\n    \r\n    @api.get(\"/xml\",auth='user')\r\n    def get_legacy_data(self):\r\n        \"\"\":title XML(only bruce)\"\"\"\r\n\r\n        data = \"\"\"<?xml version=\"1.0\"?>\r\n        <shampoo>\r\n        <Header>\r\n            Apply shampoo here.\r\n        </Header>\r\n        <Body>\r\n            You'll have to use soap here.\r\n        </Body>\r\n        </shampoo>\r\n        \"\"\"\r\n        return self.view(content=data,media_type=\"application/xml\")\r\n          \r\n    @api.get(\"/chatgpt\",auth=\"user\")\r\n    def chatgpt(self):\r\n        \"\"\"\r\n        :title Chat(only alice)\r\n        \"\"\"\r\n        return self.view()\r\n\r\n\r\n \r\n \r\nwebsockets:Dict[str,WebSocket] = {}\r\nimport pusher\r\n\r\npusher_client = pusher.Pusher(\r\n  app_id='1588311',\r\n  key='3eb7cc894586d11b97de',\r\n  secret='b1052d401c7d6542fc4f',\r\n  cluster='ap3',\r\n  ssl=True\r\n)\r\n\r\n@api_router(path=\"/{controller}\")\r\nclass WSController(BaseController):  \r\n    def __init__(self) -> None:\r\n        super().__init__()\r\n        \r\n    @api.get(\"/\" )\r\n    def ws_home(self):\r\n        \"\"\":title WebSocketDemo\"\"\"\r\n        return self.view()\r\n\r\n    @api.websocket(\"/chat/{client_id}\")\r\n    async def websocket_endpoint(self, websocket: WebSocket,client_id: int):\r\n        await websocket.accept()\r\n        websockets[client_id]=(websocket)\r\n        try:\r\n            while True:\r\n                data = await websocket.receive_text()\r\n                await websocket.send_text(f\"You wrote: {data}\" )\r\n                for clientid in websockets:\r\n                    if client_id!=clientid:\r\n                        await websockets[clientid].send_text(f\"Client #{client_id} says: {data}\")\r\n                 \r\n        except WebSocketDisconnect:\r\n            websockets.remove(websocket)\r\n            for connection in websockets:\r\n                await connection.send_text(f\"Client #{client_id} left the chat\")\r\n             \r\n```\r\n\r\nhome.html:\r\n\r\n```html\r\n<!DOCTYPE html>\r\n<html>\r\n\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <title>FastApi MVC Framework</title>\r\n    <link rel=\"stylesheet\" href=\"home.css\" />\r\n\r\n</head>\r\n\r\n<body>\r\n    <header style=\"text-align:left;display: flex;\">\r\n        <h1>Python</h1>\r\n        <h4>on FastApi</h4>\r\n\r\n    </header>\r\n    <nav>\r\n        {% for item in routers_map %} {% if 'GET' in routers_map[item]['methods'] %} {% if routers_map[item]['auth']=='none' or request.session['user'] %}\r\n        <a href=\"{{routers_map[item]['path']}}\">{{routers_map[item]['doc']\r\n                and routers_map[item]['doc']['title'] or item}}</a> {% endif %} {% endif %} {% endfor %}\r\n\r\n        <a href=\"#\">About</a>\r\n        <a href=\"#\">Contact</a> {% if request.session['user'] %}\r\n        <a href=\"/user/logout\"><b>{{request.session['user']['username']}}</b>\r\n                Logout</a> {% endif %}\r\n    </nav>\r\n    <section>\r\n        <h2>Welcome to my website</h2>\r\n        <p>This is an example of a responsive design that works well on both desktop and mobile devices.</p>\r\n        <p>here is the `text` variable in class method:{{text}}</p>\r\n        <p style=\"color:red\"><b>{{flash}}</b></p>\r\n    </section>\r\n    <footer>\r\n        <p>&copy; 2023 My Website</p>\r\n    </footer>\r\n</body>\r\n\r\n</html>\r\n```\r\n",
    "bugtrack_url": null,
    "license": "Apache License 2.0",
    "summary": "Simple and elegant use of FastApi in MVC mode",
    "version": "1.1.0",
    "split_keywords": [
        "web framework",
        "mvc framework",
        "fastapi framework"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e133066c9ae3f1eeaa7738c4de9421bd79b8e497e239ea43042df13182cba104",
                "md5": "3b00435089246e98084f0dddbab1b77f",
                "sha256": "0eab911bc1585e947be57d68628a81c911493ef8f7a667f462225313afc544be"
            },
            "downloads": -1,
            "filename": "brucelee-1.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3b00435089246e98084f0dddbab1b77f",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 49392,
            "upload_time": "2023-04-28T11:41:59",
            "upload_time_iso_8601": "2023-04-28T11:41:59.034881Z",
            "url": "https://files.pythonhosted.org/packages/e1/33/066c9ae3f1eeaa7738c4de9421bd79b8e497e239ea43042df13182cba104/brucelee-1.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1970f5d6b6479a3c3f43ac380735a253de31eeffdf71be2c5015b10f9a1fe023",
                "md5": "28fa3826c53d7db21fc21d6f3ca9dce9",
                "sha256": "bbc0b0198b73637823e97636629a51163ca62138bb627783e3bfdc4db1a16c70"
            },
            "downloads": -1,
            "filename": "brucelee-1.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "28fa3826c53d7db21fc21d6f3ca9dce9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 40869,
            "upload_time": "2023-04-28T11:42:01",
            "upload_time_iso_8601": "2023-04-28T11:42:01.101406Z",
            "url": "https://files.pythonhosted.org/packages/19/70/f5d6b6479a3c3f43ac380735a253de31eeffdf71be2c5015b10f9a1fe023/brucelee-1.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-04-28 11:42:01",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "smjkzsl",
    "github_project": "brucelee",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "brucelee"
}
        
Elapsed time: 0.08407s