Compare commits

...

9 commits

6 changed files with 134 additions and 142 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before After
Before After

View file

@ -21,8 +21,8 @@ exports-deps:
uv export {{ uv_export_options }} --output-file requirements.txt uv export {{ uv_export_options }} --output-file requirements.txt
uv export {{ uv_export_options }} --only-dev --output-file requirements.dev.txt uv export {{ uv_export_options }} --only-dev --output-file requirements.dev.txt
test: test *ARGS:
uv run pytest tests.py uv run pytest tests.py {{ ARGS }}
coverage: coverage:
uv run pytest tests.py --cov=src/ --cov-report term --cov-report xml --cov-report html --cov-config pyproject.toml uv run pytest tests.py --cov=src/ --cov-report term --cov-report xml --cov-report html --cov-config pyproject.toml

View file

@ -1,6 +1,6 @@
from sqlmodel import SQLModel, create_engine from sqlmodel import SQLModel, create_engine
sqlite_url = "sqlite:///:memory:" # TODO: get url from environment sqlite_url = "sqlite:///database.db" # TODO: get url from environment
engine = create_engine(sqlite_url, echo=True) engine = create_engine(sqlite_url, echo=True)

View file

@ -4,12 +4,10 @@ This is where the application is implemented.
import logging import logging
from sqlmodel import Session
from textual.app import App from textual.app import App
from textual.logging import TextualHandler from textual.logging import TextualHandler
from .database import create_db_and_tables, engine from .database import create_db_and_tables
from .models import Teilchen, make_teilchen_input
from .tui import AddInventoryScreen from .tui import AddInventoryScreen
logging.basicConfig( logging.basicConfig(
@ -19,29 +17,9 @@ logging.basicConfig(
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
FAKE_INPUT = """
Ein Teilchen. #Tag03 #tag12 "Dieses Teilchen ist nur zum testen" #tag1 #tag2
""".strip(" \n")
def try_this():
teilchen_data = make_teilchen_input(FAKE_INPUT)
if not teilchen_data:
logger.error("oh no!")
with Session(engine) as session:
db_teilchen = Teilchen.model_validate(teilchen_data)
session.add(db_teilchen)
session.commit()
session.refresh(db_teilchen)
logger.info(f"{db_teilchen=}")
class SammlerApp(App[None]): class SammlerApp(App[None]):
async def on_mount(self) -> None: async def on_mount(self) -> None:
create_db_and_tables() create_db_and_tables()
try_this()
_ = self.push_screen(AddInventoryScreen()) _ = self.push_screen(AddInventoryScreen())

View file

@ -4,14 +4,14 @@ import uuid
from sqlmodel import ( from sqlmodel import (
Field, Field,
SQLModel, SQLModel,
Session,
select,
Sequence,
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
TeilchenDatum = tuple[int, str, str, str, str]
class TeilchenCreate(SQLModel): class TeilchenCreate(SQLModel):
description: str | None description: str | None
name: str = Field(index=True) name: str = Field(index=True)
@ -25,6 +25,15 @@ class Teilchen(TeilchenCreate, table=True):
async def make_teilchen_input(text: str) -> TeilchenCreate | None: async def make_teilchen_input(text: str) -> TeilchenCreate | None:
"""Constructor to create new Teilchen from user input.
Args:
text: The whole input string as provided by the user.
Returns:
Returns new Teilchen instance if enough parts could be extracted.
Returns `None` otherwise.
"""
import re import re
from natsort import natsorted from natsort import natsorted
@ -36,6 +45,7 @@ async def make_teilchen_input(text: str) -> TeilchenCreate | None:
name = text[0:name_end] name = text[0:name_end]
if not name: if not name:
logger.error("Could not extract name.") logger.error("Could not extract name.")
logger.debug("Could not extract name from input: %s", text)
return None return None
description_start = text.find('"', name_end + 1) description_start = text.find('"', name_end + 1)
@ -47,22 +57,26 @@ async def make_teilchen_input(text: str) -> TeilchenCreate | None:
tags = re.findall(r"#\w+", text.lower()) tags = re.findall(r"#\w+", text.lower())
if not tags: if not tags:
logger.info("No tags found in text.") logger.info("Could not extract tags.")
logger.debug("Could not extract tags from input: %s", text)
return TeilchenCreate( teilchen = TeilchenCreate(
name=name, name=name,
description=description, description=description,
tags=" ".join(natsorted(tags)), tags=" ".join(natsorted(tags)),
text=text, text=text,
) )
logger.debug("Created new Teilchen: %r", teilchen)
return teilchen
async def load_initial_data() -> list[TeilchenDatum]: async def load_initial_data() -> Sequence[Teilchen]:
return [ from .database import engine
(0, "Name0", "Description0", "9000", "#tag0 #tag00 #tag000"),
(1, "Name1", "Description1", "9001", "#tag1 #tag11 #tag111"), with Session(engine) as session:
(2, "Name2", "Description2", "9002", "#tag2 #tag22 #tag222"), statement = select(
(3, "Name3", "Description3", "9003", "#tag3 #tag33 #tag333"), Teilchen.id, Teilchen.name, Teilchen.description, Teilchen.number, Teilchen.tags
(4, "Name4", "Description4", "9004", "#tag4 #tag44 #tag444"), )
(5, "Name5", "Description5", "9005", "#tag5 #tag55 #tag555"), all_teilchen = session.exec(statement).all()
] return all_teilchen

View file

@ -7,7 +7,7 @@ from textual.widgets import Button, DataTable, Footer, Header, Input, Static
from .models import load_initial_data from .models import load_initial_data
FAKE_DATA_HEADER = "pk Name Description Number Tags" FAKE_DATA_HEADER = "pk Name Description Number Tags".split()
class SearchBar(Static): class SearchBar(Static):
@ -47,7 +47,7 @@ class SearchResults(Widget):
async def on_mount(self) -> None: async def on_mount(self) -> None:
table: DataTable[None] = self.query_one(DataTable[None]) table: DataTable[None] = self.query_one(DataTable[None])
_ = table.add_columns(FAKE_DATA_HEADER) _ = table.add_columns(*FAKE_DATA_HEADER)
_ = table.add_rows(await load_initial_data()) # ty:ignore[invalid-argument-type] _ = table.add_rows(await load_initial_data()) # ty:ignore[invalid-argument-type]