diff --git a/__snapshots__/tests/test_initial_layout.raw b/__snapshots__/tests/test_initial_layout.raw index 7c612d4..c498016 100644 --- a/__snapshots__/tests/test_initial_layout.raw +++ b/__snapshots__/tests/test_initial_layout.raw @@ -19,208 +19,208 @@ font-weight: 700; } - .terminal-1669918775-matrix { + .terminal-1161314305-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1669918775-title { + .terminal-1161314305-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1669918775-r1 { fill: #c5c8c6 } -.terminal-1669918775-r2 { fill: #e0e0e0 } -.terminal-1669918775-r3 { fill: #121212 } -.terminal-1669918775-r4 { fill: #0178d4 } -.terminal-1669918775-r5 { fill: #7ae998 } -.terminal-1669918775-r6 { fill: #2d2d2d } -.terminal-1669918775-r7 { fill: #797979 } -.terminal-1669918775-r8 { fill: #0a180e;font-weight: bold } -.terminal-1669918775-r9 { fill: #e0e0e0;font-weight: bold } -.terminal-1669918775-r10 { fill: #008139 } -.terminal-1669918775-r11 { fill: #0d0d0d } -.terminal-1669918775-r12 { fill: #000000 } -.terminal-1669918775-r13 { fill: #495259 } -.terminal-1669918775-r14 { fill: #ffa62b;font-weight: bold } + .terminal-1161314305-r1 { fill: #c5c8c6 } +.terminal-1161314305-r2 { fill: #e0e0e0 } +.terminal-1161314305-r3 { fill: #121212 } +.terminal-1161314305-r4 { fill: #0178d4 } +.terminal-1161314305-r5 { fill: #7ae998 } +.terminal-1161314305-r6 { fill: #2d2d2d } +.terminal-1161314305-r7 { fill: #797979 } +.terminal-1161314305-r8 { fill: #0a180e;font-weight: bold } +.terminal-1161314305-r9 { fill: #e0e0e0;font-weight: bold } +.terminal-1161314305-r10 { fill: #008139 } +.terminal-1161314305-r11 { fill: #0d0d0d } +.terminal-1161314305-r12 { fill: #000000 } +.terminal-1161314305-r13 { fill: #495259 } +.terminal-1161314305-r14 { fill: #ffa62b;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - SammlerApp + SammlerApp - - - - SammlerApp -▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -Enter Teilchen information: name, description, #tags Add  Search  -▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - pk                                    Name   Description   Number  Tags         - 019c5d37-d43b-72d0-a4dd-b4816f4c5b3a  name0  description0  9001    tag0 tag0-0  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -▆▆ - -^p palette + + + + SammlerApp +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Enter Teilchen information: name, description, #tags Add  Search  +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + pk  Name   Description   Number  Tags                  + 0   Name0  Description0  9000    #tag0 #tag00 #tag000  + 1   Name1  Description1  9001    #tag1 #tag11 #tag111  + 2   Name2  Description2  9002    #tag2 #tag22 #tag222  + 3   Name3  Description3  9003    #tag3 #tag33 #tag333  + 4   Name4  Description4  9004    #tag4 #tag44 #tag444  + 5   Name5  Description5  9005    #tag5 #tag55 #tag555  + + + + + + + + + + + + + + + + + + + + + + + + + + +▆▆ + +^p palette diff --git a/justfile b/justfile index 5196518..bfc462d 100644 --- a/justfile +++ b/justfile @@ -21,8 +21,8 @@ exports-deps: uv export {{ uv_export_options }} --output-file requirements.txt uv export {{ uv_export_options }} --only-dev --output-file requirements.dev.txt -test *ARGS: - uv run pytest tests.py {{ ARGS }} +test: + uv run pytest tests.py coverage: uv run pytest tests.py --cov=src/ --cov-report term --cov-report xml --cov-report html --cov-config pyproject.toml diff --git a/src/teilchensammler_cli/database.py b/src/teilchensammler_cli/database.py index d919349..6f39922 100644 --- a/src/teilchensammler_cli/database.py +++ b/src/teilchensammler_cli/database.py @@ -1,6 +1,6 @@ from sqlmodel import SQLModel, create_engine -sqlite_url = "sqlite:///database.db" # TODO: get url from environment +sqlite_url = "sqlite:///:memory:" # TODO: get url from environment engine = create_engine(sqlite_url, echo=True) diff --git a/src/teilchensammler_cli/main.py b/src/teilchensammler_cli/main.py index c1706ef..fc4d680 100644 --- a/src/teilchensammler_cli/main.py +++ b/src/teilchensammler_cli/main.py @@ -4,10 +4,12 @@ This is where the application is implemented. import logging +from sqlmodel import Session from textual.app import App from textual.logging import TextualHandler -from .database import create_db_and_tables +from .database import create_db_and_tables, engine +from .models import Teilchen, make_teilchen_input from .tui import AddInventoryScreen logging.basicConfig( @@ -17,9 +19,29 @@ logging.basicConfig( 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]): async def on_mount(self) -> None: create_db_and_tables() + try_this() _ = self.push_screen(AddInventoryScreen()) diff --git a/src/teilchensammler_cli/models.py b/src/teilchensammler_cli/models.py index 7a49d5c..1cc6633 100644 --- a/src/teilchensammler_cli/models.py +++ b/src/teilchensammler_cli/models.py @@ -4,14 +4,14 @@ import uuid from sqlmodel import ( Field, SQLModel, - Session, - select, - Sequence, ) logger = logging.getLogger(__name__) +TeilchenDatum = tuple[int, str, str, str, str] + + class TeilchenCreate(SQLModel): description: str | None name: str = Field(index=True) @@ -25,15 +25,6 @@ class Teilchen(TeilchenCreate, table=True): 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 from natsort import natsorted @@ -45,7 +36,6 @@ async def make_teilchen_input(text: str) -> TeilchenCreate | None: name = text[0:name_end] if not name: logger.error("Could not extract name.") - logger.debug("Could not extract name from input: %s", text) return None description_start = text.find('"', name_end + 1) @@ -57,26 +47,22 @@ async def make_teilchen_input(text: str) -> TeilchenCreate | None: tags = re.findall(r"#\w+", text.lower()) if not tags: - logger.info("Could not extract tags.") - logger.debug("Could not extract tags from input: %s", text) + logger.info("No tags found in text.") - teilchen = TeilchenCreate( + return TeilchenCreate( name=name, description=description, tags=" ".join(natsorted(tags)), text=text, ) - logger.debug("Created new Teilchen: %r", teilchen) - - return teilchen -async def load_initial_data() -> Sequence[Teilchen]: - from .database import engine - - with Session(engine) as session: - statement = select( - Teilchen.id, Teilchen.name, Teilchen.description, Teilchen.number, Teilchen.tags - ) - all_teilchen = session.exec(statement).all() - return all_teilchen +async def load_initial_data() -> list[TeilchenDatum]: + return [ + (0, "Name0", "Description0", "9000", "#tag0 #tag00 #tag000"), + (1, "Name1", "Description1", "9001", "#tag1 #tag11 #tag111"), + (2, "Name2", "Description2", "9002", "#tag2 #tag22 #tag222"), + (3, "Name3", "Description3", "9003", "#tag3 #tag33 #tag333"), + (4, "Name4", "Description4", "9004", "#tag4 #tag44 #tag444"), + (5, "Name5", "Description5", "9005", "#tag5 #tag55 #tag555"), + ] diff --git a/src/teilchensammler_cli/tui.py b/src/teilchensammler_cli/tui.py index 288bc8a..f1ccd78 100644 --- a/src/teilchensammler_cli/tui.py +++ b/src/teilchensammler_cli/tui.py @@ -7,7 +7,7 @@ from textual.widgets import Button, DataTable, Footer, Header, Input, Static from .models import load_initial_data -FAKE_DATA_HEADER = "pk Name Description Number Tags".split() +FAKE_DATA_HEADER = "pk Name Description Number Tags" class SearchBar(Static): @@ -47,7 +47,7 @@ class SearchResults(Widget): async def on_mount(self) -> 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]