-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
revamp of adding type hints for SQLAlchemy models #9
base: main
Are you sure you want to change the base?
Changes from all commits
6ac4693
5198152
9f99cdd
5249b86
2cd02a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
source_url "https://raw.githubusercontent.com/cachix/devenv/95f329d49a8a5289d31e0982652f7058a189bfca/direnvrc" "sha256-d+8cBpDfDBj41inrADaJt+bDWhOktwslgoP5YiGJ1v0=" | ||
|
||
use devenv |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Devenv | ||
.devenv* | ||
devenv.local.nix | ||
|
||
# direnv | ||
.direnv | ||
|
||
# pre-commit | ||
.pre-commit-config.yaml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Flask-SQLAlchemy models | ||
|
||
## Requirements | ||
|
||
* `devenv` | ||
|
||
## Start | ||
|
||
``` | ||
devenv shell | ||
``` |
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,94 @@ | ||||||||||||||||
from datetime import datetime | ||||||||||||||||
import sys | ||||||||||||||||
from typing import Optional, TypedDict | ||||||||||||||||
|
||||||||||||||||
from flask import Flask, Response, jsonify, render_template, request | ||||||||||||||||
|
||||||||||||||||
from flask_sqlalchemy import SQLAlchemy | ||||||||||||||||
|
||||||||||||||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column | ||||||||||||||||
|
||||||||||||||||
# Web Application | ||||||||||||||||
|
||||||||||||||||
app = Flask(__name__) | ||||||||||||||||
|
||||||||||||||||
# Database | ||||||||||||||||
|
||||||||||||||||
class Base(DeclarativeBase): | ||||||||||||||||
pass | ||||||||||||||||
|
||||||||||||||||
db = SQLAlchemy(model_class=Base) | ||||||||||||||||
|
||||||||||||||||
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db" | ||||||||||||||||
|
||||||||||||||||
db.init_app(app) | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
class NotificationModel(TypedDict): | ||||||||||||||||
id: int | ||||||||||||||||
description: Optional[str] | ||||||||||||||||
email: str | ||||||||||||||||
date: datetime | ||||||||||||||||
url: Optional[str] | ||||||||||||||||
read: bool | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
class Notification(db.Model): | ||||||||||||||||
__tablename__ = "notifications" | ||||||||||||||||
|
||||||||||||||||
id: Mapped[int] = mapped_column(primary_key=True, index=True) | ||||||||||||||||
description: Mapped[str] | ||||||||||||||||
email: Mapped[str] = mapped_column(nullable=False) | ||||||||||||||||
date: Mapped[datetime] = mapped_column(nullable=False) | ||||||||||||||||
url: Mapped[str] | ||||||||||||||||
read: Mapped[bool] = mapped_column(default=False) | ||||||||||||||||
|
||||||||||||||||
def to_dict(self) -> NotificationModel: | ||||||||||||||||
return { | ||||||||||||||||
"id": self.id, | ||||||||||||||||
"description": self.description, | ||||||||||||||||
"email": self.email, | ||||||||||||||||
"date": self.date, | ||||||||||||||||
"url": self.url, | ||||||||||||||||
"read": self.read, | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
def get_all(): | ||||||||||||||||
return db.session.query(Notification).all() | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
def get_unread(): | ||||||||||||||||
return db.session.query(Notification).filter(Notification.read.is_(False)).all() | ||||||||||||||||
|
||||||||||||||||
reveal_type(get_all) | ||||||||||||||||
|
||||||||||||||||
reveal_type(get_unread) | ||||||||||||||||
Comment on lines
+64
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might want to wrap these
Suggested change
|
||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
@app.route("/", methods=["GET"]) | ||||||||||||||||
def root(): | ||||||||||||||||
return render_template("root.html") | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
@app.route("/notifications", methods=["GET", "POST"]) | ||||||||||||||||
def notifications() -> Response: | ||||||||||||||||
if request.method == "POST": | ||||||||||||||||
new_notification = Notification( | ||||||||||||||||
**dict(request.form, date=datetime.fromisoformat(request.form["date"])) | ||||||||||||||||
) | ||||||||||||||||
db.session.add(new_notification) | ||||||||||||||||
db.session.commit() | ||||||||||||||||
|
||||||||||||||||
notifications = get_all() | ||||||||||||||||
return jsonify([notification.to_dict() for notification in notifications]) | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
if __name__ == "__main__": | ||||||||||||||||
if len(sys.argv) > 1 and sys.argv[1] == 'db': | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add instructions about this in the README? |
||||||||||||||||
print("Creating db...") | ||||||||||||||||
with app.app_context(): | ||||||||||||||||
db.create_all() | ||||||||||||||||
sys.exit(0) | ||||||||||||||||
|
||||||||||||||||
app.run(debug=True) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Notification Form</title> | ||
</head> | ||
<body> | ||
<h1>Notification Form</h1> | ||
<form action="{{ url_for('notifications') }}" method="POST"> | ||
<label for="description">Description:</label> | ||
<textarea id="description" name="description" placeholder="Enter description (optional)"></textarea> | ||
<br><br> | ||
|
||
<label for="email">Email:</label> | ||
<input type="email" id="email" name="email" required> | ||
<br><br> | ||
|
||
<label for="date">Date:</label> | ||
<input type="datetime-local" id="date" name="date" required> | ||
<br><br> | ||
|
||
<label for="url">URL:</label> | ||
<input type="url" id="url" name="url" placeholder="Enter URL (optional)"> | ||
<br><br> | ||
|
||
<label for="read">Read:</label> | ||
<input type="checkbox" id="read" name="read"> | ||
<br><br> | ||
|
||
<input type="submit" value="Submit Notification"> | ||
</form> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
{ | ||
"nodes": { | ||
"devenv": { | ||
"locked": { | ||
"dir": "src/modules", | ||
"lastModified": 1727098005, | ||
"owner": "cachix", | ||
"repo": "devenv", | ||
"rev": "f318d27a4637aff765a378106d82dfded124c3b3", | ||
"treeHash": "c77efa71afb25615542aed9d7e805a3b6216b6a2", | ||
"type": "github" | ||
}, | ||
"original": { | ||
"dir": "src/modules", | ||
"owner": "cachix", | ||
"repo": "devenv", | ||
"type": "github" | ||
} | ||
}, | ||
"flake-compat": { | ||
"flake": false, | ||
"locked": { | ||
"lastModified": 1696426674, | ||
"owner": "edolstra", | ||
"repo": "flake-compat", | ||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", | ||
"treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb", | ||
"type": "github" | ||
}, | ||
"original": { | ||
"owner": "edolstra", | ||
"repo": "flake-compat", | ||
"type": "github" | ||
} | ||
}, | ||
"flake-compat_2": { | ||
"flake": false, | ||
"locked": { | ||
"lastModified": 1696426674, | ||
"owner": "edolstra", | ||
"repo": "flake-compat", | ||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", | ||
"treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb", | ||
"type": "github" | ||
}, | ||
"original": { | ||
"owner": "edolstra", | ||
"repo": "flake-compat", | ||
"type": "github" | ||
} | ||
}, | ||
"gitignore": { | ||
"inputs": { | ||
"nixpkgs": [ | ||
"pre-commit-hooks", | ||
"nixpkgs" | ||
] | ||
}, | ||
"locked": { | ||
"lastModified": 1709087332, | ||
"owner": "hercules-ci", | ||
"repo": "gitignore.nix", | ||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394", | ||
"treeHash": "ca14199cabdfe1a06a7b1654c76ed49100a689f9", | ||
"type": "github" | ||
}, | ||
"original": { | ||
"owner": "hercules-ci", | ||
"repo": "gitignore.nix", | ||
"type": "github" | ||
} | ||
}, | ||
"nixpkgs": { | ||
"locked": { | ||
"lastModified": 1716977621, | ||
"owner": "cachix", | ||
"repo": "devenv-nixpkgs", | ||
"rev": "4267e705586473d3e5c8d50299e71503f16a6fb6", | ||
"treeHash": "6d9f1f7ca0faf1bc2eeb397c78a49623260d3412", | ||
"type": "github" | ||
}, | ||
"original": { | ||
"owner": "cachix", | ||
"ref": "rolling", | ||
"repo": "devenv-nixpkgs", | ||
"type": "github" | ||
} | ||
}, | ||
"nixpkgs-python": { | ||
"inputs": { | ||
"flake-compat": "flake-compat", | ||
"nixpkgs": [ | ||
"nixpkgs" | ||
] | ||
}, | ||
"locked": { | ||
"lastModified": 1722978926, | ||
"owner": "cachix", | ||
"repo": "nixpkgs-python", | ||
"rev": "7c550bca7e6cf95898e32eb2173efe7ebb447460", | ||
"treeHash": "d9d38ef1b6fc92be18170b74e9889a7ab9174f6e", | ||
"type": "github" | ||
}, | ||
"original": { | ||
"owner": "cachix", | ||
"repo": "nixpkgs-python", | ||
"type": "github" | ||
} | ||
}, | ||
"nixpkgs-stable": { | ||
"locked": { | ||
"lastModified": 1726969270, | ||
"owner": "NixOS", | ||
"repo": "nixpkgs", | ||
"rev": "23cbb250f3bf4f516a2d0bf03c51a30900848075", | ||
"treeHash": "f150876866adcc3af432c103db116c2f516f49b1", | ||
"type": "github" | ||
}, | ||
"original": { | ||
"owner": "NixOS", | ||
"ref": "nixos-24.05", | ||
"repo": "nixpkgs", | ||
"type": "github" | ||
} | ||
}, | ||
"pre-commit-hooks": { | ||
"inputs": { | ||
"flake-compat": "flake-compat_2", | ||
"gitignore": "gitignore", | ||
"nixpkgs": [ | ||
"nixpkgs" | ||
], | ||
"nixpkgs-stable": "nixpkgs-stable" | ||
}, | ||
"locked": { | ||
"lastModified": 1726745158, | ||
"owner": "cachix", | ||
"repo": "pre-commit-hooks.nix", | ||
"rev": "4e743a6920eab45e8ba0fbe49dc459f1423a4b74", | ||
"treeHash": "56fbe2a9610b3ad9163a74011131e7624f6b3b81", | ||
"type": "github" | ||
}, | ||
"original": { | ||
"owner": "cachix", | ||
"repo": "pre-commit-hooks.nix", | ||
"type": "github" | ||
} | ||
}, | ||
"root": { | ||
"inputs": { | ||
"devenv": "devenv", | ||
"nixpkgs": "nixpkgs", | ||
"nixpkgs-python": "nixpkgs-python", | ||
"pre-commit-hooks": "pre-commit-hooks" | ||
} | ||
} | ||
}, | ||
"root": "root", | ||
"version": 7 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ pkgs, lib, config, inputs, ... }: | ||
|
||
{ | ||
packages = [ | ||
pkgs.sqlite | ||
]; | ||
|
||
languages.python = { | ||
enable = true; | ||
version = "3.12.0"; | ||
venv = { | ||
enable = true; | ||
requirements = "requirements.txt"; | ||
}; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
inputs: | ||
nixpkgs: | ||
url: github:cachix/devenv-nixpkgs/rolling | ||
nixpkgs-python: | ||
url: github:cachix/nixpkgs-python | ||
inputs: | ||
nixpkgs: | ||
follows: nixpkgs |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this file in the repository? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
blinker==1.8.2 | ||
click==8.1.7 | ||
Flask==3.0.3 | ||
Flask-SQLAlchemy==3.1.1 | ||
itsdangerous==2.2.0 | ||
Jinja2==3.1.4 | ||
MarkupSafe==2.1.5 | ||
nodeenv==1.9.1 | ||
pyright==1.1.383 | ||
SQLAlchemy==2.0.35 | ||
typing_extensions==4.12.2 | ||
Werkzeug==3.0.4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to add a classical
requirements.txt
flow for non-Nix users. WDYT?