diff --git a/README.md b/README.md
index 1915809..5b14093 100644
--- a/README.md
+++ b/README.md
@@ -108,8 +108,10 @@ Please don't: this is my little human-created thing.
Where `segment` is one of: major, minor, patch, stable, alpha, beta, rc,
post, dev
* commit
-* When we really really want to release:
- * `just release {Release Name can be several words}`
+* push commits
+* use lazygit to create the new version tag
+ * remember to prefix it with "v"
+* push the tags, using lazygit
----
diff --git a/__snapshots__/tests/test_initial_layout.raw b/__snapshots__/tests/test_initial_layout.raw
index ab8578c..7c612d4 100644
--- a/__snapshots__/tests/test_initial_layout.raw
+++ b/__snapshots__/tests/test_initial_layout.raw
@@ -19,208 +19,208 @@
font-weight: 700;
}
- .terminal-2753228840-matrix {
+ .terminal-1669918775-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-2753228840-title {
+ .terminal-1669918775-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-2753228840-r1 { fill: #c5c8c6 }
-.terminal-2753228840-r2 { fill: #e0e0e0 }
-.terminal-2753228840-r3 { fill: #121212 }
-.terminal-2753228840-r4 { fill: #0178d4 }
-.terminal-2753228840-r5 { fill: #7ae998 }
-.terminal-2753228840-r6 { fill: #2d2d2d }
-.terminal-2753228840-r7 { fill: #797979 }
-.terminal-2753228840-r8 { fill: #0a180e;font-weight: bold }
-.terminal-2753228840-r9 { fill: #e0e0e0;font-weight: bold }
-.terminal-2753228840-r10 { fill: #008139 }
-.terminal-2753228840-r11 { fill: #0d0d0d }
-.terminal-2753228840-r12 { fill: #000000 }
-.terminal-2753228840-r13 { fill: #495259 }
-.terminal-2753228840-r14 { fill: #ffa62b;font-weight: bold }
+ .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 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- SammlerApp
+ SammlerApp
-
-
-
- ⭘SammlerApp
-▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
-▊This is a name. "This is the description" #these #are #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
+ 019c5d37-d43b-72d0-a4dd-b4816f4c5b3a name0 description0 9001 tag0 tag0-0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+▆▆
+
+▏^p palette
diff --git a/justfile b/justfile
index 0c8c3d7..4a25b54 100644
--- a/justfile
+++ b/justfile
@@ -9,6 +9,14 @@ default:
setup:
uv sync
+# builds a package
+build:
+ uv build --wheel --clear
+
+# upload to Package Registry
+upload: build
+ uv run twine upload --repository code.cbo --config-file ~/.config/pypirc dist/*.whl
+
# console to observe log messages
console:
uv run textual console
@@ -21,16 +29,16 @@ run-console:
run:
uv run python -m {{ the_app }}
-# Update dependencies to new versions
-update-deps:
- uv lock --upgrade
- uv sync
-
# export dependencies into requirements files
exports-deps:
uv export {{ uv_export_options }} --output-file requirements.txt
uv export {{ uv_export_options }} --output-file requirements.dev.txt --only-dev
+# Update dependencies to new versions
+update-deps:
+ uv lock --upgrade
+ uv sync
+
# Run tests, ARGS are passed-through to pytest
test *ARGS:
uv run pytest tests.py -m "not final" {{ ARGS }}
@@ -42,18 +50,26 @@ alltests *ARGS:
coverage:
uv run pytest tests.py --cov=src/ --cov-report term --cov-report xml --cov-report html --cov-config pyproject.toml
-# lint python, markdown, wheel file names, prek config
+# run python and markdown
lint:
uv run ruff check .
markdownlint-cli2 .
uv run twine check --strict dist/*
- prek validate-config prek.toml
-release *release_name:
+# pretend we are CI
+ci: lint
+ prek run --all-files
+# woodpecker-cli exec "whatever"
+
+[private]
+bump segment:
+ uv version --bump {{ segment }}
+
+[private]
+release segment *release_name:
#!/usr/bin/env fish
- set -l release_name {{ release_name }}
test -f releasenotes.md; and set -l body "$(cat releasenotes.md)"; or set -l body ""
- set -l tag (uv version --short --output-format text)
+ set -l tag (uv version --short --output-format text --bump {{ segment }})
git add pyproject.toml uv.lock
git commit -m "Release version $tag"
@@ -62,15 +78,7 @@ release *release_name:
git push
git push origin tag "v$tag"
- just build
-
- fj release create "v$tag: $release_name" --tag "v$tag" --attach dist/*.whl --body "$body"
- # just upload
-
-# builds a package
-build:
uv build --wheel --clear
-# upload to Package Registry
-upload:
- uv run twine upload --repository code.cbo --config-file ~/.config/pypirc dist/*.whl
+ fj release create "v$tag: $release_name" --prerelease --tag "v$tag" --attach dist/*.whl --body "$body"
+ # uv run twine upload --config-file ~/.config/pypirc --repository code.cbo dist/*.whl
diff --git a/mise.toml b/mise.toml
index cc420a6..ca3c768 100644
--- a/mise.toml
+++ b/mise.toml
@@ -1,7 +1,6 @@
[env]
'_'.python.venv = { path = ".venv", create = true }
DATABASE_URL = "sqlite:///database.db"
-PREK_COLOR = "never"
[tools]
difftastic = "latest"
diff --git a/prek.toml b/prek.toml
index e22ef62..083a1dc 100644
--- a/prek.toml
+++ b/prek.toml
@@ -1,7 +1,5 @@
#:tombi schema.strict = false
-# see also: https://prek.j178.dev/builtin/
-
exclude = { glob = ["__snapshots__/**", "__pycache__", "dist/**"] }
[[repos]]
@@ -9,10 +7,19 @@ repo = "builtin"
hooks = [
{ id = "check-case-conflict" },
{ id = "check-merge-conflict" },
+ { id = "check-json" },
+ { id = "check-symlinks" },
{ id = "check-toml" },
+ { id = "check-yaml", args = [
+ # "--allow-multiple-documents", #https://prek.j178.dev/builtin/#check-yaml
+ ] },
{ id = "end-of-file-fixer" },
- { id = "mixed-line-ending", args = [ "--fix=lf" ] },
- { id = "trailing-whitespace", args = [ "--markdown-linebreak-ext=md" ] },
+ { id = "mixed-line-ending", args = [
+ "--fix=lf", # https://prek.j178.dev/builtin/#mixed-line-ending
+ ] },
+ { id = "trailing-whitespace", args = [
+ "--markdown-linebreak-ext=md", # https://prek.j178.dev/builtin/#trailing-whitespace
+ ] },
]
[[repos]]
diff --git a/pyproject.toml b/pyproject.toml
index 6356117..2fd07df 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "teilchensammler-cli"
-version = "0.5.0"
+version = "0.4.9"
description = "Build up and maintain an inventory of electronics parts and tools."
readme = "README.md"
requires-python = ">=3.14,<4.0"
diff --git a/src/teilchensammler_cli/main.py b/src/teilchensammler_cli/main.py
index 42feda2..c89c61a 100644
--- a/src/teilchensammler_cli/main.py
+++ b/src/teilchensammler_cli/main.py
@@ -4,16 +4,11 @@ This is where the application is implemented.
import logging
-from textual import on
-from textual.app import App, ComposeResult
-from textual.containers import HorizontalGroup
+from textual.app import App
from textual.logging import TextualHandler
-from textual.screen import Screen
-from textual.widget import Widget
-from textual.widgets import Button, DataTable, Footer, Header, Input, Static
from .database import create_db_and_tables
-from .models import add_to_database, load_initial_data, make_teilchen_input
+from .tui import AddInventoryScreen
logging.basicConfig(
level="NOTSET",
@@ -21,8 +16,6 @@ logging.basicConfig(
)
logger = logging.getLogger(__name__)
-TEILCHEN_DATA_HEADER = "pk Name Description Number Tags".split()
-
class SammlerApp(App):
async def on_mount(self) -> None:
@@ -30,68 +23,6 @@ class SammlerApp(App):
self.push_screen(AddInventoryScreen())
-class SearchBar(Static):
- DEFAULT_CSS = """
- #teilchen-input {
- width: 4fr;
- }
- #button-search, #button-add {
- width: 1fr;
- }
- """
-
- def compose(self) -> ComposeResult:
- with HorizontalGroup(id="search-bar-widget"):
- yield Input(
- placeholder='This is a name. "This is the description" #these #are #tags',
- tooltip=(
- "Enter a name followed by a period, then a description "
- 'enclosed in double quotes ("). You should use #hashtags for any meta information. '
- "Hashtags can be placed anywhere."
- ),
- id="teilchen-input",
- type="text",
- )
- yield Button("Add", variant="success", classes="search-bar-buttons", id="button-add")
- yield Button(
- "Search",
- variant="default",
- classes="search-bar-buttons",
- id="button-search",
- )
-
- @on(Input.Submitted)
- async def parse_input(self, event: Input.Submitted) -> None:
-
- if not (tc := await make_teilchen_input(event.value)):
- return
-
- event.input.value = ""
-
- teilchen = await add_to_database(tc)
- self.screen.query_one(DataTable).add_row(
- teilchen.id, teilchen.name, teilchen.description, teilchen.number, teilchen.tags
- )
-
-
-class SearchResults(Widget):
- def compose(self) -> ComposeResult:
- yield DataTable(id="table-search-result", cursor_type="row", zebra_stripes=True)
-
- async def on_mount(self) -> None:
- table: DataTable = self.query_one(DataTable)
- table.add_columns(*TEILCHEN_DATA_HEADER)
- table.add_rows(await load_initial_data())
-
-
-class AddInventoryScreen(Screen):
- def compose(self) -> ComposeResult:
- yield Header()
- yield SearchBar()
- yield SearchResults()
- yield Footer()
-
-
# so we can import it without running it
app = SammlerApp()
diff --git a/src/teilchensammler_cli/models.py b/src/teilchensammler_cli/models.py
index bca6c42..77619a8 100644
--- a/src/teilchensammler_cli/models.py
+++ b/src/teilchensammler_cli/models.py
@@ -3,14 +3,12 @@ import uuid
from sqlmodel import (
Field,
- Sequence,
- Session,
SQLModel,
+ Session,
select,
+ Sequence,
)
-from .database import engine
-
logger = logging.getLogger(__name__)
@@ -37,7 +35,6 @@ async def make_teilchen_input(text: str) -> TeilchenCreate | None:
Returns `None` otherwise.
"""
import re
-
from natsort import natsorted
text = text.strip()
@@ -91,13 +88,3 @@ async def load_initial_data() -> Sequence[Teilchen]:
) # ty:ignore[no-matching-overload]
all_teilchen = session.exec(statement).all()
return all_teilchen
-
-
-async def add_to_database(tc: TeilchenCreate) -> Teilchen:
- with Session(engine) as session:
- teilchen = Teilchen.model_validate(tc)
- session.add(teilchen)
- session.commit()
- session.refresh(teilchen)
-
- return teilchen
diff --git a/src/teilchensammler_cli/tui.py b/src/teilchensammler_cli/tui.py
new file mode 100644
index 0000000..fd5cd32
--- /dev/null
+++ b/src/teilchensammler_cli/tui.py
@@ -0,0 +1,59 @@
+from textual.app import ComposeResult
+from textual.containers import HorizontalGroup
+from textual.screen import Screen
+from textual.widget import Widget
+from textual.widgets import Button, DataTable, Footer, Header, Input, Static
+
+from .models import load_initial_data
+
+
+TEILCHEN_DATA_HEADER = "pk Name Description Number Tags".split()
+
+
+class SearchBar(Static):
+ DEFAULT_CSS = """
+ #teilchen-input {
+ width: 4fr;
+ }
+ #button-search, #button-add {
+ width: 1fr;
+ }
+ """
+
+ def compose(self) -> ComposeResult:
+ with HorizontalGroup(id="search-bar-widget"):
+ yield Input(
+ placeholder='This is a name. "This is the description" #these #are #tags',
+ tooltip=(
+ "Enter a name followed by a period, then a description "
+ 'enclosed in double quotes ("). You should use #hashtags for any meta information. '
+ "Hashtags can be placed anywhere."
+ ),
+ id="teilchen-input",
+ type="text",
+ )
+ yield Button("Add", variant="success", classes="search-bar-buttons", id="button-add")
+ yield Button(
+ "Search",
+ variant="default",
+ classes="search-bar-buttons",
+ id="button-search",
+ )
+
+
+class SearchResults(Widget):
+ def compose(self) -> ComposeResult:
+ yield DataTable(id="table-search-result", cursor_type="row", zebra_stripes=True)
+
+ async def on_mount(self) -> None:
+ table: DataTable = self.query_one(DataTable)
+ table.add_columns(*TEILCHEN_DATA_HEADER)
+ table.add_rows(await load_initial_data())
+
+
+class AddInventoryScreen(Screen):
+ def compose(self) -> ComposeResult:
+ yield Header()
+ yield SearchBar()
+ yield SearchResults()
+ yield Footer()
diff --git a/uv.lock b/uv.lock
index 0c0c8bc..e6597d8 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1153,7 +1153,7 @@ wheels = [
[[package]]
name = "teilchensammler-cli"
-version = "0.5.0"
+version = "0.4.9"
source = { editable = "." }
dependencies = [
{ name = "ciso8601" },