Files
Paddy d418f156fa German date display + optional street address for precise geocoding
- Date pickers (entry form + edit dialog) now display TT.MM.JJJJ instead of
  ISO (DATE_DISPLAY_FORMAT). Storage stays YYYY-MM-DD; parse_date() already
  accepted both formats, so existing data and the self-updater are unaffected.
- New optional "Straße" field (street + house number) in the entry form and
  edit dialog, backed by a new `street` CSV column. geocode_city() and
  GeocoderWorker.enqueue() gained a street parameter: when set, a full-address
  query is tried first for a much more precise map point, falling back
  automatically to the existing city/PLZ search if it doesn't resolve.
- Tab 2 and the entry queue show a Straße column; Tab 2 search now also
  matches on street.
- Fix: pandas turns a blank CSV cell into NaN even for a dtype=str column, so
  every existing (blank-street) row would have shown literal "nan" in Tab 2.
  DataStore._load now does street.fillna("") after every read.

Verified with a non-GUI test suite (date parsing, query construction, CSV
round-trip incl. the NaN case) and a full GUI build/drive test on Python
3.12/Tk 9. Docs updated (changelog, overview, architecture, data-model,
dev-notes, improvements).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 11:15:37 +02:00

105 lines
4.8 KiB
Markdown

# Dev notes — assumptions that turned out wrong
Running list so the same mistakes aren't repeated. Add to it whenever reality
contradicts an assumption.
## The macOS system Python can't run the GUI; use a Homebrew Python (2026-09-07)
The macOS **CommandLineTools** Python 3.9 (`/Library/Developer/CommandLineTools/
.../python3.9`) ships **Tk 8.5.9**. `ttkbootstrap` 1.10.1 requires **Tk 8.6+**.
Symptoms: `TclError: couldn't recognize image data` (window icon) and
`TclError: unknown option "-style"` on `ttk.Scrollbar`.
**Fix for local GUI testing:** `brew install python-tk@3.12` (pulls `tcl-tk`,
gives Python 3.12 + **Tk 9.0**), then:
```bash
/opt/homebrew/bin/python3.12 -m venv venv
venv/bin/pip install -r requirements.txt
venv/bin/python app.py
```
`ttkbootstrap` 1.10.1 runs fine on Tk 9.0 in practice (verified: window builds,
Treeview sort, DateEntry, LabelFrame, custom styles all work).
- The **Linux Mint target** uses its own `python3-tk` (Tk 8.6+) and is
unaffected either way.
- `screencapture` from a non-GUI shell fails ("could not create image from
display") without Screen-Recording permission — automated screenshots of the
running app aren't available here; verify by building the widget tree and
driving it programmatically instead.
## `pandas` reads everything as strings by design
`DataStore._load` uses `dtype={...: str}` for `postal_code`, `lat`, `lon`.
Numeric parsing is deliberately deferred to `get_map_data` (`pd.to_numeric(...,
errors="coerce")`). Don't "fix" columns to float on load — blank coordinates and
leading-zero PLZ both depend on the string representation.
## Map tiles: Carto needs a key, OSM 403s file:// — use Esri (2026-09-07)
Two dead ends before landing on Esri:
1. `folium.Map(tiles="CartoDB positron")` → "API KEY REQUIRED" watermark; Carto
moved basemaps behind a key.
2. `tiles="OpenStreetMap"` → worked in `curl` from the dev machine but the
**user's browser got HTTP 403 "referer is required by tile usage policy"**.
OSM's tile CDN graylists refererless requests, and a `karte.html` opened as a
local `file://` sends no `Referer`. A browser can't add one. Dead end for
this app's "open a local HTML file" model.
Now: **Esri "World Light Gray"** base + reference (labels) overlay
(`server.arcgisonline.com/ArcGIS/rest/services/Canvas/…`). No key, no `Referer`
check, light/muted look close to the old positron. `MAP_TILES` /
`MAP_TILES_LABELS` constants; comment lists Esri Street/Topo as swaps.
Lesson: a tile source that works from `curl` or an `http://` page can still fail
from `file://`. Test the map by **opening the generated `karte.html` directly**,
not just by checking the URL in the HTML.
## pandas turns blank CSV cells into NaN even with `dtype=str` (2026-09-12)
Assumption that turned out wrong: forcing a column's dtype (e.g.
`dtype={"street": str}`) does **not** stop `pd.read_csv` from parsing a truly
empty field as `NaN` (a float) instead of `""`. Verified directly:
```python
>>> pd.read_csv(io.StringIO("a\n\n"), dtype={"a": str})["a"][0]
nan # not ''
>>> str(pd.read_csv(io.StringIO("a\n\n"), dtype={"a": str})["a"][0])
'nan' # !!
```
This is *why* `lat`/`lon` already needed `_is_blank()` / `_coord_str()` helpers
— but the new `street` column (added 2026-09-12) hit it immediately and much
harder: it's optional, so *every* existing row has it blank, and without a fix
every one of them would show the literal text `nan` in Tab 2. Fix: after
`pd.read_csv` (all three load paths — normal, empty-file, backup-recovery),
`DataStore._load` runs `self.df["street"] = self.df["street"].fillna("")`.
Rule for this codebase: **any column that can legitimately be blank needs an
explicit `.fillna("")` (or the `_is_blank`/`_coord_str` treatment) right after
`pd.read_csv`** — `dtype=str` alone is not enough. `city`/`postal_code` haven't
needed this only because they're rarely actually blank in practice, not because
they're immune.
## Tk popup menus: bind `<ButtonRelease-3>`, not `<Button-3>` (2026-09-07)
`widget.bind("<Button-3>", …)` + `menu.tk_popup(x, y)` + `finally:
menu.grab_release()` is the Windows idiom and **misfires on X11**: `tk_popup`
returns immediately, `grab_release()` drops the menu's grab, and the pending
`<ButtonRelease-3>` then activates whatever entry is under the cursor (the first
one). Symptom here: right-click a history row → menu flashes → edit dialog opens.
Rules for this codebase:
- bind the release event: `RIGHT_CLICK` constant (`<ButtonRelease-3>`, or
`<ButtonRelease-2>` on macOS),
- build each context menu **once** (store on `self`), don't recreate per click,
- just call `menu.tk_popup(...)` — no `grab_release()`.
## Nominatim query order matters
`geocode_city` returns the **first** hit, trying PLZ-qualified first, then each
region in `GEOCODE_REGIONS`, then a bare `", Germany"`. Reordering changes which
coordinates ambiguous town names resolve to.