tangerine
1.0.0
?????????????????????????????????????????
████████╗ █████╗ ███╗ ██╗ ██████╗ ███████╗██████╗ ██╗███╗ ██╗███████╗
╚══██╔══╝██╔══██╗████╗ ██║██╔════╝ ██╔════╝██╔══██╗██║████╗ ██║██╔════╝
██║ ███████║██╔██╗ ██║██║ ███╗█████╗ ██████╔╝██║██╔██╗ ██║█████╗
██║ ██╔══██║██║╚██╗██║██║ ██║██╔══╝ ██╔══██╗██║██║╚██╗██║██╔══╝
██║ ██║ ██║██║ ╚████║╚██████╔╝███████╗██║ ██║██║██║ ╚████║███████╗
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝
????????????????????????????????????????
橘子不和諧:https://discord.gg/abzmthch
感謝您檢查橘子!這是我正在研究的新python框架。它幾乎是Beta版本。我之所以開始寫它,是因為燒瓶當時不支持異步視圖功能。他們現在從2.0開始,但仍然沒有開箱即用。該框架的一些目標:
對於來自JavaScript的開發人員來說,是最簡單的Python Web框架。
對於基本API來說,非常輕巧且未經許可,但還具有可選的擴展名,可以根據需要將其開箱即用。基本上,您可以在幾分鐘內啟動極輕的API,以便在幾分鐘內提供靜態站點,但也可以選擇下載提供功能齊全的CLI的插件,而其他工具則可以使其更像Ruby在Rails或Django上。目前,有一個非常易於使用的Auth模塊,它允許您使用默認的哈希算法或僅使用幾行代碼來交換自己的使用。
支持異步/等待開箱即用。
該項目並未以當前狀態達到所有這些目標,但我正在努力。我將在此處發布此信息,以防可能有任何有興趣的人,因此我們可以自信地向PYPI發布工作的Beta版本。祝你有美好的一天:)
我也正在為此使用CLI工具。仍然對我要使用的基本體系結構和模塊進行骨骼/實驗。當前的設置工作在分支體系結構設置下。與此相關的其他存儲庫:佛手柑,佛陀的手和關鍵的酸橙。
以下是這些鏈接:https://github.com/noraa-july-stoke/key-limes https://github.com/noraa-july-stoke/buddhas hand
I use emojis for commit messages. Here's what they mean:
# for updating any readmes or roadmaps
: <relevant comment>:
# for new features
: <relevant comment>:
# for debug commits.
?? : <relevant comment>:
# for refactoring
? : <relevant comment>:
# for documentation
? : <relevant comment>
# branch initialization commit
? : <relevant comment>
# standard merge message
? : <relevant comment>
from tangerine import Tangerine , Ctx , Router
from pymongo import MongoClient
from key_lime import KeyLime
from yuzu import Yuzu
import json
import jwt
app = Tangerine ()
client = MongoClient ( 'mongodb://localhost:27017/' )
keychain = KeyLime ({
"SECRET_KEY" : "ILOVECATS" ,
})
# Initialize Yuzu with the db funcs.
def get_user_by_email ( email ):
db = client [ 'mydatabase' ]
users = db [ 'users' ]
query = { 'email' : email }
user = users . find_one ( query )
if user :
user [ '_id' ] = str ( user [ '_id' ]) # Convert ObjectId to string
return user
def create_user ( user_data ):
db = client [ 'mydatabase' ]
users = db [ 'users' ]
result = users . insert_one ( user_data )
if result . inserted_id :
user_data [ '_id' ] = str ( result . inserted_id ) # Convert ObjectId to string
return user_data
auth = Yuzu ( keychain , get_user_by_email , create_user )
# serve static files to any request not starting with /api
app . static ( '^/(?!api).*$' , './public' )
# This is how you define a custom middleware.
def hello_middle ( ctx : Ctx , next ) -> None :
print ( "Hello from middleware!" )
ctx . hello_message = json . dumps ({ "message" : "Hello from middleware!" })
next ()
# ==================== AUTH HANDLERS ====================
def api_hello_world ( ctx : Ctx ) -> None :
ctx . body = ctx . hello_message
ctx . send ( 200 , content_type = 'application/json' )
def signup ( ctx : Ctx ) -> None :
user_data = ctx . request . body
created_user = auth . sign_up ( user_data )
if created_user :
ctx . body = json . dumps ( created_user )
ctx . send ( 201 , content_type = 'application/json' )
else :
ctx . send ( 500 , content_type = 'application/json' )
def login ( ctx : Ctx ) -> None :
user_data = ctx . request . body
email = user_data [ 'email' ]
password = user_data [ 'password' ]
user_id , token = auth . login ( email , password )
if token :
ctx . body = json . dumps ({ "message" : "Logged in successfully" , "token" : token })
ctx . set_res_header ( "Set-Cookie" , f"auth_token= { token } ; HttpOnly; Path=/" )
ctx . send ( 200 , content_type = 'application/json' )
# Set the token as a cookie or in the response headers
else :
ctx . body = json . dumps ({ "message" : "Invalid credentials" })
ctx . send ( 401 , content_type = 'application/json' )
def logout ( ctx : Ctx ) -> None :
auth . logout ()
ctx . body = json . dumps ({ "message" : "Logged out successfully" })
ctx . send ( 200 , content_type = 'application/json' )
@ Router . auth_required
def get_protected_content ( ctx : Ctx ) -> None :
ctx . body = json . dumps ({ "message" : "This is protected content. Only authenticated users can see this. I hope you feel special ???." })
ctx . send ( 200 , content_type = 'application/json' )
# ==================== API ROUTES ====================
# if you need to bind more variables to your handler, you can pass in a closure
api_router = Router ( prefix = '/api' )
api_router . post ( '/logout' , logout )
api_router . post ( '/login' , login )
api_router . post ( '/signup' , signup )
api_router . get ( '/hello' , api_hello_world )
# api_router.get('/users', get_and_delete_users)
api_router . get ( '/protected' , get_protected_content )
app . use ( hello_middle )
app . use ( auth . jwt_middleware )
app . use_router ( api_router )
app . start () from tangerine import Tangerine , Ctx , Router
from key_lime import KeyLime
from yuzu import Yuzu
import json
import jwt
import psycopg2
# ==================== If you don't have schema and tables this part will set that up for you ====================
conn = psycopg2 . connect ( "postgresql://postgres:<POSTGRESPASSWORD>@localhost:5432/local_development" )
# Open a cursor to perform database operations
cur = conn . cursor ()
# Create schema if it's not there
cur . execute ( """
CREATE SCHEMA IF NOT EXISTS tangerine;
""" )
# Execute a command: this creates a new table named 'users'
cur . execute ( """
CREATE TABLE IF NOT EXISTS tangerine.users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL
)
""" )
# Commit the transaction
conn . commit ()
# Close the connection
cur . close ()
conn . close ()
# =================================================================================================================
app = Tangerine ()
keychain = KeyLime ({
"SECRET_KEY" : "ILOVECATS" ,
})
def get_user_by_email ( email ):
conn = psycopg2 . connect ( "postgresql://postgres:<POSTGRESPASSWORD>@localhost:5432/local_development" )
cur = conn . cursor ()
cur . execute ( "SELECT * FROM tangerine.users WHERE email = %s" , ( email ,))
user = cur . fetchone ()
cur . close ()
conn . close ()
if user :
return { '_id' : user [ 0 ], 'email' : user [ 1 ], 'password' : user [ 2 ]}
else :
return None
def create_user ( user_data ):
conn = psycopg2 . connect ( "postgresql://postgres:<POSTGRESPASSWORD>@localhost:5432/local_development" )
cur = conn . cursor ()
cur . execute ( "INSERT INTO tangerine.users (email, password) VALUES (%s, %s) RETURNING id" , ( user_data [ 'email' ], user_data [ 'password' ]))
user_id = cur . fetchone ()[ 0 ]
conn . commit ()
cur . close ()
conn . close ()
return { '_id' : user_id , 'email' : user_data [ 'email' ], 'password' : user_data [ 'password' ]}
auth = Yuzu ( keychain , get_user_by_email , create_user )
# serve static files to any request not starting with /api
app . static ( '^/(?!api).*$' , './public' )
def signup ( ctx : Ctx ) -> None :
user_data = ctx . request . body
created_user = auth . sign_up ( user_data )
if created_user :
ctx . body = json . dumps ( created_user )
ctx . send ( 201 , content_type = 'application/json' )
else :
ctx . send ( 500 , content_type = 'application/json' )
def login ( ctx : Ctx ) -> None :
user_data = ctx . request . body
email = user_data [ 'email' ]
password = user_data [ 'password' ]
user_id , token = auth . login ( email , password )
if token :
ctx . body = json . dumps ({ "message" : "Logged in successfully" , "token" : token })
ctx . set_res_header ( "Set-Cookie" , f"auth_token= { token } ; HttpOnly; Path=/" )
ctx . send ( 200 , content_type = 'application/json' )
else :
ctx . body = json . dumps ({ "message" : "Invalid credentials" })
ctx . send ( 401 , content_type = 'application/json' )
def logout ( ctx : Ctx ) -> None :
auth . logout ()
ctx . body = json . dumps ({ "message" : "Logged out successfully" })
ctx . send ( 200 , content_type = 'application/json' )
@ Router . auth_required
def get_protected_content ( ctx : Ctx ) -> None :
ctx . body = json . dumps ({ "message" : "This is protected content. Only authenticated users can see this. I hope you feel special ???." })
ctx . send ( 200 , content_type = 'application/json' )
# ==================== API ROUTES ====================
api_router = Router ( prefix = '/api' )
api_router . post ( '/logout' , logout )
api_router . post ( '/login' , login )
api_router . post ( '/signup' , signup )
api_router . get ( '/protected' , get_protected_content )
app . use ( auth . jwt_middleware )
app . use_router ( api_router )
app . start ()
## More Details TBD
## This readme is a work in progress so keep an eye out for more documentation/outlines of the project.