test em
This commit is contained in:
parent
daf81343bf
commit
a2b33b25f8
11 changed files with 479 additions and 55 deletions
|
|
@ -4,15 +4,15 @@ from fastapi import APIRouter, Depends
|
|||
from sqlmodel import SQLModel
|
||||
|
||||
from learn_sql_model.api.user import oauth2_scheme
|
||||
from learn_sql_model.config import get_config
|
||||
from learn_sql_model.config import Config, get_config
|
||||
from learn_sql_model.models.hero import Hero
|
||||
|
||||
hero_router = APIRouter()
|
||||
|
||||
|
||||
@hero_router.on_event("startup")
|
||||
def on_startup() -> None:
|
||||
SQLModel.metadata.create_all(get_config().database.engine)
|
||||
def on_startup(config: Config = Depends(get_config)) -> None:
|
||||
SQLModel.metadata.create_all(config.database.engine)
|
||||
|
||||
|
||||
@hero_router.get("/items/")
|
||||
|
|
@ -21,21 +21,22 @@ async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
|
|||
|
||||
|
||||
@hero_router.get("/hero/{id}")
|
||||
def get_hero(id: int) -> Hero:
|
||||
def get_hero(id: int, config: Config = Depends(get_config)) -> Hero:
|
||||
"get one hero"
|
||||
return Hero().get(id=id)
|
||||
return Hero().get(id=id, config=config)
|
||||
|
||||
|
||||
@hero_router.post("/hero/")
|
||||
def post_hero(hero: Hero) -> Hero:
|
||||
def post_hero(hero: Hero, config: Config = Depends(get_config)) -> Hero:
|
||||
"read all the heros"
|
||||
return hero.post()
|
||||
hero.post(config=config)
|
||||
return hero
|
||||
|
||||
|
||||
@hero_router.get("/heros/")
|
||||
def get_heros() -> list[Hero]:
|
||||
def get_heros(config: Config = Depends(get_config)) -> list[Hero]:
|
||||
"get all heros"
|
||||
return Hero().get()
|
||||
return Hero().get(config=config)
|
||||
# Alternatively
|
||||
# with get_config().database.session as session:
|
||||
# statement = select(Hero)
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ from learn_sql_model.cli.tui import tui_app
|
|||
|
||||
app = typer.Typer(
|
||||
name="learn_sql_model",
|
||||
help="A rich terminal report for coveragepy.",
|
||||
help="learn-sql-model cli for managing the project",
|
||||
)
|
||||
app.add_typer(config_app)
|
||||
app.add_typer(tui_app)
|
||||
app.add_typer(model_app)
|
||||
app.add_typer(api_app)
|
||||
app.add_typer(config_app, name="config")
|
||||
app.add_typer(tui_app, name="tui")
|
||||
app.add_typer(model_app, name="model")
|
||||
app.add_typer(api_app, name="api")
|
||||
app.add_typer(hero_app, name="hero")
|
||||
|
||||
|
||||
|
|
@ -38,6 +38,17 @@ def version_callback(value: bool) -> None:
|
|||
raise typer.Exit()
|
||||
|
||||
|
||||
@app.callback()
|
||||
def main(
|
||||
version: bool = typer.Option(
|
||||
False,
|
||||
callback=version_callback,
|
||||
help="show the version of the learn-sql-model package.",
|
||||
),
|
||||
):
|
||||
"configuration cli"
|
||||
|
||||
|
||||
@app.command()
|
||||
def tui(ctx: typer.Context) -> None:
|
||||
Trogon(get_group(app), click_context=ctx).run()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import List, Union
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pydantic_typer import expand_pydantic_args
|
||||
from rich.console import Console
|
||||
|
|
@ -9,6 +9,7 @@ from learn_sql_model.factories.hero import HeroFactory
|
|||
from learn_sql_model.factories.pet import PetFactory
|
||||
from learn_sql_model.models.hero import Hero
|
||||
from learn_sql_model.models.pet import Pet
|
||||
import sys
|
||||
|
||||
hero_app = typer.Typer()
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ def hero():
|
|||
@hero_app.command()
|
||||
@expand_pydantic_args(typer=True)
|
||||
def get(
|
||||
id: int = None,
|
||||
id: Optional[int] = None,
|
||||
config: Config = None,
|
||||
) -> Union[Hero, List[Hero]]:
|
||||
"get one hero"
|
||||
|
|
@ -52,12 +53,11 @@ def populate(
|
|||
config: Config = None,
|
||||
) -> Hero:
|
||||
"read all the heros"
|
||||
config.init()
|
||||
if config is None:
|
||||
config = Config()
|
||||
if config.env == "prod":
|
||||
Console().print("populate is not supported in production")
|
||||
return
|
||||
sys.exit(1)
|
||||
|
||||
for hero in HeroFactory().batch(n):
|
||||
pet = PetFactory().build()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
from contextvars import ContextVar
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastapi import Depends
|
||||
from pydantic import BaseModel, BaseSettings
|
||||
from sqlalchemy import create_engine
|
||||
from sqlmodel import SQLModel, Session
|
||||
|
|
@ -24,6 +26,13 @@ class Database:
|
|||
self.config = get_config()
|
||||
else:
|
||||
self.config = config
|
||||
self.db_state_default = {
|
||||
"closed": None,
|
||||
"conn": None,
|
||||
"ctx": None,
|
||||
"transactions": None,
|
||||
}
|
||||
self.db_state = ContextVar("db_state", default=self.db_state_default.copy())
|
||||
|
||||
@property
|
||||
def engine(self) -> "Engine":
|
||||
|
|
@ -60,6 +69,24 @@ def get_database(config: Config = None) -> Database:
|
|||
return Database(config)
|
||||
|
||||
|
||||
async def reset_db_state(config: Config = None) -> None:
|
||||
if config is None:
|
||||
config = get_config()
|
||||
config.database.db._state._state.set(db_state_default.copy())
|
||||
config.database.db._state.reset()
|
||||
|
||||
|
||||
def get_db(config: Config = None, reset_db_state=Depends(reset_db_state)):
|
||||
if config is None:
|
||||
config = get_config()
|
||||
try:
|
||||
config.database.db.connect()
|
||||
yield
|
||||
finally:
|
||||
if not config.database.db.is_closed():
|
||||
config.database.db.close()
|
||||
|
||||
|
||||
def get_config(overrides: dict = {}) -> Config:
|
||||
raw_config = load("learn_sql_model")
|
||||
config = Config(**raw_config, **overrides)
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from learn_sql_model.models.fast_model import FastModel
|
||||
from sqlmodel import Field
|
||||
|
||||
|
||||
class Hero(FastModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
name: str
|
||||
secret_name: str
|
||||
age: Optional[int] = None
|
||||
# new_attribute: Optional[str] = None
|
||||
# pets: List["Pet"] = Relationship(back_populates="hero")
|
||||
|
|
@ -29,6 +29,8 @@ class FastModel(SQLModel):
|
|||
with config.database.session as session:
|
||||
session.add(self)
|
||||
session.commit()
|
||||
session.refresh(self)
|
||||
return
|
||||
|
||||
def get(
|
||||
self, id: int = None, config: "Config" = None, where=None
|
||||
|
|
@ -52,6 +54,16 @@ class FastModel(SQLModel):
|
|||
results = session.exec(statement).one()
|
||||
return results
|
||||
|
||||
def flags(self, config: "Config" = None) -> None:
|
||||
if config is None:
|
||||
config = get_config()
|
||||
flags = []
|
||||
for k, v in self.dict().items():
|
||||
if v:
|
||||
flags.append(f"--{k.replace('_', '-').lower()}")
|
||||
flags.append(v)
|
||||
return flags
|
||||
|
||||
# TODO
|
||||
# update
|
||||
# delete
|
||||
|
|
|
|||
275
markata.toml
Normal file
275
markata.toml
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
#
|
||||
# __ __ _ _ _ _
|
||||
# | \/ | __ _ _ __| | ____ _| |_ __ _ | |_ ___ _ __ ___ | |
|
||||
# | |\/| |/ _` | '__| |/ / _` | __/ _` || __/ _ \| '_ ` _ \| |
|
||||
# | | | | (_| | | | < (_| | || (_| || || (_) | | | | | | |
|
||||
# |_| |_|\__,_|_| |_|\_\__,_|\__\__,_(_)__\___/|_| |_| |_|_|
|
||||
#
|
||||
# learn-sql-model.dev
|
||||
|
||||
[markata.nav]
|
||||
'learn-sql-model'='https://learn-sql-model.dev/'
|
||||
'GitHub'='https://github.com/WaylonWalker/learn-sql-model'
|
||||
|
||||
[markata]
|
||||
# bump site version to bust GitHub actions cache
|
||||
site_version = 13
|
||||
|
||||
## choose your markdown backend
|
||||
# markdown_backend='markdown'
|
||||
# markdown_backend='markdown2'
|
||||
markdown_backend='markdown-it-py'
|
||||
|
||||
# 2 weeks in seconds
|
||||
default_cache_expire = 1209600
|
||||
# subroute = "docs"
|
||||
|
||||
## Markata Setup
|
||||
output_dir = "markout"
|
||||
assets_dir = "static"
|
||||
hooks = [
|
||||
"markata.plugins.publish_source",
|
||||
"markata.plugins.docs",
|
||||
"default",
|
||||
]
|
||||
disabled_hooks = [
|
||||
'markata.plugins.heading_link',
|
||||
'markata.plugins.manifest',
|
||||
'markata.plugins.rss'
|
||||
]
|
||||
|
||||
## Site Config
|
||||
url = "https://learn-sql-model.dev"
|
||||
title = "Learn SQLModel's Docs"
|
||||
description = "Documentation for using the Learn SQLModel"
|
||||
rss_description = "Learn SQLModel docs"
|
||||
author_name = "Waylon Walker"
|
||||
author_email = "waylon@waylonwalaker.com"
|
||||
icon = "favicon.ico"
|
||||
lang = "en"
|
||||
# post_template = "pages/templates/post_template.html"
|
||||
repo_url = "https://github.com/waylonwalker/learn-sql-model"
|
||||
repo_branch = "main"
|
||||
theme_color = "#322D39"
|
||||
background_color = "#B73CF6"
|
||||
start_url = "/"
|
||||
site_name = "Learn SQLModel's Docs"
|
||||
short_name = "ww"
|
||||
display = "minimal-ui"
|
||||
twitter_card = "summary_large_image"
|
||||
twitter_creator = "@_waylonwalker"
|
||||
twitter_site = "@_waylonwalker"
|
||||
|
||||
# markdown_it flavor
|
||||
# [markata.markdown_it_py]
|
||||
# config='gfm-like'
|
||||
# # markdown_it built-in plugins
|
||||
# enable = [ "table" ]
|
||||
# disable = [ "image" ]
|
||||
|
||||
# # markdown_it built-in plugin options
|
||||
# [markata.markdown_it_py.options_update]
|
||||
# linkify = true
|
||||
# html = true
|
||||
# typographer = true
|
||||
# highlight = 'markata.plugins.md_it_highlight_code:highlight_code'
|
||||
|
||||
# # add custom markdown_it plugins
|
||||
# [[markata.markdown_it_py.plugins]]
|
||||
# plugin = "mdit_py_plugins.admon:admon_plugin"
|
||||
|
||||
# [[markata.markdown_it_py.plugins]]
|
||||
# plugin = "mdit_py_plugins.admon:admon_plugin"
|
||||
|
||||
# [[markata.markdown_it_py.plugins]]
|
||||
# plugin = "mdit_py_plugins.attrs:attrs_plugin"
|
||||
# config = {spans = true}
|
||||
|
||||
# [[markata.markdown_it_py.plugins]]
|
||||
# plugin = "mdit_py_plugins.attrs:attrs_block_plugin"
|
||||
|
||||
# [[markata.markdown_it_py.plugins]]
|
||||
# plugin = "markata.plugins.mdit_details:details_plugin"
|
||||
|
||||
# [[markata.markdown_it_py.plugins]]
|
||||
# plugin = "mdit_py_plugins.anchors:anchors_plugin"
|
||||
|
||||
# [markata.markdown_it_py.plugins.config]
|
||||
# permalink = true
|
||||
# permalinkSymbol = '<svg class="heading-permalink" aria-hidden="true" fill="currentColor" focusable="false" height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M9.199 13.599a5.99 5.99 0 0 0 3.949 2.345 5.987 5.987 0 0 0 5.105-1.702l2.995-2.994a5.992 5.992 0 0 0 1.695-4.285 5.976 5.976 0 0 0-1.831-4.211 5.99 5.99 0 0 0-6.431-1.242 6.003 6.003 0 0 0-1.905 1.24l-1.731 1.721a.999.999 0 1 0 1.41 1.418l1.709-1.699a3.985 3.985 0 0 1 2.761-1.123 3.975 3.975 0 0 1 2.799 1.122 3.997 3.997 0 0 1 .111 5.644l-3.005 3.006a3.982 3.982 0 0 1-3.395 1.126 3.987 3.987 0 0 1-2.632-1.563A1 1 0 0 0 9.201 13.6zm5.602-3.198a5.99 5.99 0 0 0-3.949-2.345 5.987 5.987 0 0 0-5.105 1.702l-2.995 2.994a5.992 5.992 0 0 0-1.695 4.285 5.976 5.976 0 0 0 1.831 4.211 5.99 5.99 0 0 0 6.431 1.242 6.003 6.003 0 0 0 1.905-1.24l1.723-1.723a.999.999 0 1 0-1.414-1.414L9.836 19.81a3.985 3.985 0 0 1-2.761 1.123 3.975 3.975 0 0 1-2.799-1.122 3.997 3.997 0 0 1-.111-5.644l3.005-3.006a3.982 3.982 0 0 1 3.395-1.126 3.987 3.987 0 0 1 2.632 1.563 1 1 0 0 0 1.602-1.198z"></path></svg>'
|
||||
|
||||
# [[markata.markdown_it_py.plugins]]
|
||||
# plugin = "markata.plugins.md_it_wikilinks:wikilinks_plugin"
|
||||
# config = {markata = "markata"}
|
||||
|
||||
# markata feeds
|
||||
# creating pages of posts
|
||||
# [markata.feeds_config]
|
||||
|
||||
## feed template
|
||||
# [markata.feeds.<slug>]
|
||||
# title="Project Gallery"
|
||||
## python eval to True adds post to the feed
|
||||
# filter="'project-gallery' in path"
|
||||
## the key to sort on
|
||||
# sort='title'
|
||||
## the template for each post to use when added to the page
|
||||
# card_template="""
|
||||
# """
|
||||
|
||||
[[markata.feeds]]
|
||||
slug='project-gallery'
|
||||
title="Project Gallery"
|
||||
filter="'project-gallery' in str(path)"
|
||||
sort='title'
|
||||
card_template="""
|
||||
<li class='post' style='background:rgba(255, 255, 255, .05); border:1px solid rgba(255, 255, 255, .2); padding:1rem; margin: 2rem auto;' >
|
||||
<a href='/{{ slug }}/'><h2>{{ title }}</h2></a>
|
||||
<ul style='display: flex; list-style-type: None;'>
|
||||
<li><a href='{{ codeUrl }}'>Source Code</a></li>
|
||||
<li><a href='{{ url }}'>Public Site</a></li>
|
||||
|
||||
</ul>
|
||||
{{ article_html }}
|
||||
</li>
|
||||
"""
|
||||
|
||||
[[markata.feeds]]
|
||||
slug='docs'
|
||||
title="Documentation"
|
||||
filter='"markata" not in slug and "tests" not in slug and "404" not in slug'
|
||||
sort='slug'
|
||||
card_template="<li class='post'><a href='/{{ slug }}/'>{{ title }}<p style='color: white; text-decoration: none;'>{{ description }}</p></a> </li>"
|
||||
|
||||
[[markata.feeds]]
|
||||
slug='all'
|
||||
title="All Learn SQLModel Modules"
|
||||
filter="True"
|
||||
card_template="""
|
||||
<li class='post' style='background:rgba(255, 255, 255, .05); border:1px solid rgba(255, 255, 255, .2); padding:1rem; margin: 2rem auto;' >
|
||||
<a href='/{{ slug }}/'>
|
||||
<a href='/{{ slug }}/'>{{ title }}</a>
|
||||
<p>
|
||||
{{ article_html[:article_html.find('</p>')] }}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
"""
|
||||
|
||||
[[markata.feeds]]
|
||||
slug='core-modules'
|
||||
title="Learn SQLModel Core Modules"
|
||||
filter="'plugin' not in slug and 'test' not in slug and title.endswith('.py')"
|
||||
card_template="""
|
||||
<li class='post' style='background:rgba(255, 255, 255, .05); border:1px solid rgba(255, 255, 255, .2); padding:1rem; margin: 2rem auto;' >
|
||||
<a href='/{{ slug }}/'>
|
||||
<a href='/{{ slug }}/'>{{ title }}</a>
|
||||
<p>
|
||||
{{ article_html[:article_html.find('</p>')] }}
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
"""
|
||||
|
||||
|
||||
[markata.jinja_md]
|
||||
ignore=[
|
||||
'jinja_md.md',
|
||||
'post_template.md',
|
||||
'publish_html.md',
|
||||
]
|
||||
|
||||
[[markata.head.meta]]
|
||||
name = "og:author_email"
|
||||
content = "waylon@waylonwalker.com"
|
||||
|
||||
[markata.tui]
|
||||
new_cmd=['tmux', 'popup', 'markata', 'new', 'post']
|
||||
|
||||
[[markata.tui.keymap]]
|
||||
name='new'
|
||||
key='n'
|
||||
|
||||
[markata.summary]
|
||||
grid_attr = ['tags', 'series']
|
||||
|
||||
[[markata.summary.filter_count]]
|
||||
name='drafts'
|
||||
filter="not published"
|
||||
color='red'
|
||||
|
||||
[[markata.summary.filter_count]]
|
||||
name='articles'
|
||||
color='dark_orange'
|
||||
|
||||
[[markata.summary.filter_count]]
|
||||
name='py_modules'
|
||||
filter='"plugin" not in slug and "docs" not in str(path)'
|
||||
color="yellow1"
|
||||
|
||||
[[markata.summary.filter_count]]
|
||||
name='published'
|
||||
filter="published"
|
||||
color='green1'
|
||||
|
||||
[[markata.summary.filter_count]]
|
||||
name='plugins'
|
||||
filter='"plugin" in slug and "docs" not in str(path)'
|
||||
color="blue"
|
||||
|
||||
[[markata.summary.filter_count]]
|
||||
name='docs'
|
||||
filter="'docs' in str(path)"
|
||||
color='purple'
|
||||
|
||||
[markata.post_model]
|
||||
include = ['date', 'description', 'published', 'slug', 'title', 'content', 'html']
|
||||
repr_include = ['date', 'description', 'published', 'slug', 'title', 'output_html']
|
||||
|
||||
[markata.render_markdown]
|
||||
backend='markdown-it-py'
|
||||
|
||||
# [markata.markdown_it_py]
|
||||
# config='gfm-like'
|
||||
# # markdown_it built-in plugins
|
||||
# enable = [ "table" ]
|
||||
# disable = [ "image" ]
|
||||
|
||||
# # markdown_it built-in plugin options
|
||||
# [markata.markdown_it_py.options_update]
|
||||
# linkify = true
|
||||
# html = true
|
||||
# typographer = true
|
||||
# highlight = 'markata.plugins.md_it_highlight_code:highlight_code'
|
||||
|
||||
# add custom markdown_it plugins
|
||||
[[markata.render_markdown.md_it_extensions]]
|
||||
plugin = "mdit_py_plugins.admon:admon_plugin"
|
||||
|
||||
[[markata.render_markdown.md_it_extensions]]
|
||||
plugin = "mdit_py_plugins.admon:admon_plugin"
|
||||
|
||||
[[markata.render_markdown.md_it_extensions]]
|
||||
plugin = "mdit_py_plugins.attrs:attrs_plugin"
|
||||
config = {spans = true}
|
||||
|
||||
[[markata.render_markdown.md_it_extensions]]
|
||||
plugin = "mdit_py_plugins.attrs:attrs_block_plugin"
|
||||
|
||||
[[markata.render_markdown.md_it_extensions]]
|
||||
plugin = "markata.plugins.mdit_details:details_plugin"
|
||||
|
||||
[[markata.render_markdown.md_it_extensions]]
|
||||
plugin = "mdit_py_plugins.anchors:anchors_plugin"
|
||||
|
||||
[markata.render_markdown.md_it_extensions.config]
|
||||
permalink = true
|
||||
permalinkSymbol = '<svg class="heading-permalink" aria-hidden="true" fill="currentColor" focusable="false" height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M9.199 13.599a5.99 5.99 0 0 0 3.949 2.345 5.987 5.987 0 0 0 5.105-1.702l2.995-2.994a5.992 5.992 0 0 0 1.695-4.285 5.976 5.976 0 0 0-1.831-4.211 5.99 5.99 0 0 0-6.431-1.242 6.003 6.003 0 0 0-1.905 1.24l-1.731 1.721a.999.999 0 1 0 1.41 1.418l1.709-1.699a3.985 3.985 0 0 1 2.761-1.123 3.975 3.975 0 0 1 2.799 1.122 3.997 3.997 0 0 1 .111 5.644l-3.005 3.006a3.982 3.982 0 0 1-3.395 1.126 3.987 3.987 0 0 1-2.632-1.563A1 1 0 0 0 9.201 13.6zm5.602-3.198a5.99 5.99 0 0 0-3.949-2.345 5.987 5.987 0 0 0-5.105 1.702l-2.995 2.994a5.992 5.992 0 0 0-1.695 4.285 5.976 5.976 0 0 0 1.831 4.211 5.99 5.99 0 0 0 6.431 1.242 6.003 6.003 0 0 0 1.905-1.24l1.723-1.723a.999.999 0 1 0-1.414-1.414L9.836 19.81a3.985 3.985 0 0 1-2.761 1.123 3.975 3.975 0 0 1-2.799-1.122 3.997 3.997 0 0 1-.111-5.644l3.005-3.006a3.982 3.982 0 0 1 3.395-1.126 3.987 3.987 0 0 1 2.632 1.563 1 1 0 0 0 1.602-1.198z"></path></svg>'
|
||||
|
||||
[[markata.render_markdown.md_it_extensions]]
|
||||
plugin = "markata.plugins.md_it_wikilinks:wikilinks_plugin"
|
||||
config = {markata = "markata"}
|
||||
|
||||
[markata.glob]
|
||||
glob_patterns = "docs/**/*.md,CHANGELOG.md"
|
||||
use_gitignore = true
|
||||
|
|
@ -57,17 +57,20 @@ path = "learn_sql_model/__about__.py"
|
|||
dependencies = [
|
||||
"black",
|
||||
"ipython",
|
||||
"coverage[toml]",
|
||||
"coverage-rich",
|
||||
"markata",
|
||||
"mypy",
|
||||
"pyflyby",
|
||||
"pytest",
|
||||
"pytest-cov",
|
||||
"pytest-mock",
|
||||
"ruff",
|
||||
"alembic",
|
||||
]
|
||||
[tool.hatch.envs.default.scripts]
|
||||
test = "coverage run -m pytest"
|
||||
cov = "coverage-rich"
|
||||
cov = "coverage-rich report"
|
||||
test-cov = ['test', 'cov']
|
||||
lint = "ruff learn_sql_model"
|
||||
format = "black learn_sql_model"
|
||||
format-check = "black --check learn_sql_model"
|
||||
|
|
@ -84,6 +87,7 @@ test-lint = "lint-test"
|
|||
python = ["37", "38", "39", "310", "311"]
|
||||
|
||||
[tool.coverage.run]
|
||||
source=["learn_sql_model"]
|
||||
branch = true
|
||||
parallel = true
|
||||
omit = [
|
||||
|
|
|
|||
15
tests/test_cli_app.py
Normal file
15
tests/test_cli_app.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
from typer.testing import CliRunner
|
||||
|
||||
from learn_sql_model.cli.app import app
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
|
||||
def test_cli_app_version():
|
||||
result = runner.invoke(app, ["--version"])
|
||||
assert result.exit_code == 0
|
||||
|
||||
|
||||
def test_cli_help():
|
||||
result = runner.invoke(app, ["--help"])
|
||||
assert result.exit_code == 0
|
||||
14
tests/test_console.py
Normal file
14
tests/test_console.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
from learn_sql_model.console import console
|
||||
|
||||
|
||||
def test_default_console_not_quiet(capsys):
|
||||
console.print("hello")
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == "hello\n"
|
||||
|
||||
|
||||
def test_default_console_is_quiet(capsys):
|
||||
console.quiet = True
|
||||
console.print("hello")
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == ""
|
||||
|
|
@ -2,6 +2,9 @@ import tempfile
|
|||
|
||||
from fastapi.testclient import TestClient
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlmodel import SQLModel
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from learn_sql_model.api.app import app
|
||||
|
|
@ -18,11 +21,31 @@ client = TestClient(app)
|
|||
def config() -> Config:
|
||||
tmp_db = tempfile.NamedTemporaryFile(suffix=".db")
|
||||
config = get_config({"database_url": f"sqlite:///{tmp_db.name}"})
|
||||
|
||||
engine = create_engine(
|
||||
config.database_url, connect_args={"check_same_thread": False}
|
||||
)
|
||||
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
# breakpoint()
|
||||
SQLModel.metadata.create_all(config.database.engine)
|
||||
|
||||
# def override_get_db():
|
||||
# try:
|
||||
# db = TestingSessionLocal()
|
||||
# yield db
|
||||
# finally:
|
||||
# db.close()
|
||||
def override_get_config():
|
||||
return config
|
||||
|
||||
app.dependency_overrides[get_config] = override_get_config
|
||||
|
||||
yield config
|
||||
# tmp_db automatically deletes here
|
||||
|
||||
|
||||
def test_post_hero(config: Config) -> None:
|
||||
config.init() # required for python api, and no existing db
|
||||
hero = HeroFactory().build(name="Batman", age=50, id=1)
|
||||
hero = hero.post(config=config)
|
||||
db_hero = Hero().get(id=1, config=config)
|
||||
|
|
@ -31,48 +54,105 @@ def test_post_hero(config: Config) -> None:
|
|||
|
||||
|
||||
def test_update_hero(config: Config) -> None:
|
||||
config.init() # required for python api, and no existing db
|
||||
hero = HeroFactory().build(name="Batman", age=50, id=1)
|
||||
hero = hero.post(config=config)
|
||||
db_hero = Hero().get(id=1, config=config)
|
||||
db_hero.name = "Superman"
|
||||
db_hero.name = "Superbman"
|
||||
hero = db_hero.post(config=config)
|
||||
db_hero = Hero().get(id=1, config=config)
|
||||
assert db_hero.age == 50
|
||||
assert db_hero.name == "Superman"
|
||||
assert db_hero.name == "Superbman"
|
||||
|
||||
|
||||
def test_cli_get(config):
|
||||
hero = HeroFactory().build(name="Steelman", age=25, id=99)
|
||||
hero.post(config=config)
|
||||
result = runner.invoke(
|
||||
hero_app,
|
||||
["get", "--id", 99, "--database-url", config.database_url],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
db_hero = Hero().get(id=99, config=config)
|
||||
assert db_hero.age == 25
|
||||
assert db_hero.name == "Steelman"
|
||||
|
||||
|
||||
def test_cli_create(config):
|
||||
hero = HeroFactory().build(name="Steelman", age=25, id=99)
|
||||
result = runner.invoke(
|
||||
hero_app,
|
||||
[
|
||||
"create",
|
||||
"--name",
|
||||
"Darth Vader",
|
||||
"--secret-name",
|
||||
"Anakin",
|
||||
"--id",
|
||||
"2",
|
||||
"--age",
|
||||
"100",
|
||||
*hero.flags(config=config),
|
||||
"--database-url",
|
||||
config.database_url,
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
db_hero = Hero().get(id=2, config=config)
|
||||
assert db_hero.age == 100
|
||||
assert db_hero.name == "Darth Vader"
|
||||
db_hero = Hero().get(id=99, config=config)
|
||||
assert db_hero.age == 25
|
||||
assert db_hero.name == "Steelman"
|
||||
|
||||
|
||||
def test_read_main(config):
|
||||
config.init()
|
||||
hero = HeroFactory().build(name="Ironman", age=25, id=99)
|
||||
def test_cli_populate(config):
|
||||
result = runner.invoke(
|
||||
hero_app,
|
||||
[
|
||||
"populate",
|
||||
"--n",
|
||||
10,
|
||||
"--database-url",
|
||||
config.database_url,
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
db_hero = Hero().get(config=config)
|
||||
assert len(db_hero) == 10
|
||||
|
||||
|
||||
def test_cli_populate_fails_prod(config):
|
||||
result = runner.invoke(
|
||||
hero_app,
|
||||
["populate", "--n", 10, "--database-url", config.database_url, "--env", "prod"],
|
||||
)
|
||||
assert result.exit_code == 1
|
||||
assert result.output.strip() == "populate is not supported in production"
|
||||
|
||||
|
||||
def test_api_read(config):
|
||||
hero = HeroFactory().build(name="Steelman", age=25, id=99)
|
||||
hero_id = hero.id
|
||||
hero = hero.post(config=config)
|
||||
response = client.get(f"/hero/{hero_id}")
|
||||
assert response.status_code == 200
|
||||
reponse_hero = Hero.parse_obj(response.json())
|
||||
assert reponse_hero.id == hero_id
|
||||
assert reponse_hero.name == "Ironman"
|
||||
assert reponse_hero.name == "Steelman"
|
||||
assert reponse_hero.age == 25
|
||||
|
||||
|
||||
def test_api_post(config):
|
||||
hero = HeroFactory().build(name="Steelman", age=25)
|
||||
hero_dict = hero.dict()
|
||||
response = client.post("/hero/", json={"hero": hero_dict})
|
||||
assert response.status_code == 200
|
||||
|
||||
response_hero = Hero.parse_obj(response.json())
|
||||
db_hero = Hero().get(id=response_hero.id, config=config)
|
||||
|
||||
assert db_hero.name == "Steelman"
|
||||
assert db_hero.age == 25
|
||||
|
||||
|
||||
def test_api_read_all(config):
|
||||
hero = HeroFactory().build(name="Mothman", age=25, id=99)
|
||||
hero_id = hero.id
|
||||
hero = hero.post(config=config)
|
||||
response = client.get("/heros/")
|
||||
assert response.status_code == 200
|
||||
heros = response.json()
|
||||
response_hero_json = [hero for hero in heros if hero["id"] == hero_id][0]
|
||||
response_hero = Hero.parse_obj(response_hero_json)
|
||||
assert response_hero.id == hero_id
|
||||
assert response_hero.name == "Mothman"
|
||||
assert response_hero.age == 25
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue