Consolidate all Anki deck generators into python_pkg/anki_decks/

Move warsaw_bridges, warsaw_districts, warsaw_landmarks, warsaw_metro,
warsaw_osiedla, warsaw_streets, and car_brand_logos into the existing
python_pkg/anki_decks/ directory alongside the polish_* generators.

Also move preview_all.html into anki_decks/.

Update all import paths, filesystem references in geo_data.py,
docstrings, READMEs, test imports, and .gitignore accordingly.
This commit is contained in:
Krzysztof kuhy Rudnicki 2026-02-07 15:32:23 +01:00
parent 04c132c9a4
commit 93426490c4
76 changed files with 337 additions and 35 deletions

4
.gitignore vendored
View File

@ -272,8 +272,8 @@ python_pkg/*/cache/
python_pkg/download_cats/http_cat_cache/
# Large geojson files that can be downloaded
python_pkg/warsaw_districts/warszawa-dzielnice.geojson
python_pkg/anki_decks/warsaw_districts/warszawa-dzielnice.geojson
# Wikipedia cache (can be refreshed)
python_pkg/polish_license_plates/.wikipedia_cache/
python_pkg/anki_decks/polish_license_plates/.wikipedia_cache/
python_pkg/cinema_planner/pasted_content.txt

@ -1 +0,0 @@
Subproject commit 4c3c9996956221f0cae49f69e0597e33aee33ee1

View File

@ -0,0 +1 @@
"""Anki flashcard deck generators."""

View File

@ -27,7 +27,7 @@ Polish license plates use a system where:
License plate data is automatically extracted from Wikipedia's authoritative table:
- **Source**: [Vehicle registration plates of Poland](https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Poland)
- **Update**: Run `python -m python_pkg.polish_license_plates.fetch_license_plates` to refresh data
- **Update**: Run `python -m python_pkg.anki_decks.polish_license_plates.fetch_license_plates` to refresh data
This ensures the codes are always based on the most current public information.
@ -37,14 +37,14 @@ This ensures the codes are always based on the most current public information.
```bash
# Generate with default settings
python -m python_pkg.polish_license_plates.polish_license_plates_anki
python -m python_pkg.anki_decks.polish_license_plates.polish_license_plates_anki
# Specify custom output file
python -m python_pkg.polish_license_plates.polish_license_plates_anki \
python -m python_pkg.anki_decks.polish_license_plates.polish_license_plates_anki \
--output my_plates.apkg
# Use custom deck name
python -m python_pkg.polish_license_plates.polish_license_plates_anki \
python -m python_pkg.anki_decks.polish_license_plates.polish_license_plates_anki \
--deck-name "My Polish Plates"
```
@ -54,10 +54,10 @@ To fetch the latest data from Wikipedia:
```bash
# Use cached data if available (default)
python -m python_pkg.polish_license_plates.fetch_license_plates
python -m python_pkg.anki_decks.polish_license_plates.fetch_license_plates
# Force refresh from Wikipedia (ignore cache)
python -m python_pkg.polish_license_plates.fetch_license_plates --force
python -m python_pkg.anki_decks.polish_license_plates.fetch_license_plates --force
```
**Caching**: Downloaded Wikipedia data is cached for 7 days in `.wikipedia_cache/` to avoid unnecessary requests. Use `--force` to bypass the cache.

View File

@ -4,4 +4,6 @@ from __future__ import annotations
__all__ = ["LICENSE_PLATE_CODES"]
from python_pkg.polish_license_plates.license_plate_data import LICENSE_PLATE_CODES
from python_pkg.anki_decks.polish_license_plates.license_plate_data import (
LICENSE_PLATE_CODES,
)

View File

@ -12,10 +12,10 @@ Caching:
Cache expires after 7 days by default.
Usage:
python -m python_pkg.polish_license_plates.fetch_license_plates
python -m python_pkg.anki_decks.polish_license_plates.fetch_license_plates
# Force refresh (ignore cache)
python -m python_pkg.polish_license_plates.fetch_license_plates --force
python -m python_pkg.anki_decks.polish_license_plates.fetch_license_plates --force
Source:
https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Poland
@ -286,7 +286,7 @@ Data source:
https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Poland
Auto-generated by:
python -m python_pkg.polish_license_plates.fetch_license_plates
python -m python_pkg.anki_decks.polish_license_plates.fetch_license_plates
Examples:
WA = Warszawa (Warsaw)
@ -369,11 +369,15 @@ def main() -> int:
sys.stdout.write("Next steps:\n")
sys.stdout.write(" 1. Review the generated file\n")
sys.stdout.write(
" 2. Run tests: " "pytest python_pkg/polish_license_plates/tests/\n"
" 2. Run tests: "
"pytest python_pkg/anki_decks/"
"polish_license_plates/tests/\n"
)
sys.stdout.write(
" 3. Regenerate Anki package: "
"python -m python_pkg.polish_license_plates.polish_license_plates_anki\n"
"python -m python_pkg.anki_decks."
"polish_license_plates."
"polish_license_plates_anki\n"
)
except RuntimeError as e:

View File

@ -31,7 +31,7 @@ Data source:
Note:
This data can be automatically updated by running:
python -m python_pkg.polish_license_plates.fetch_license_plates
python -m python_pkg.anki_decks.polish_license_plates.fetch_license_plates
Examples:
WA = Warszawa (Warsaw)

View File

@ -9,10 +9,10 @@ Creates two types of cards:
Usage:
# Generate Anki cards for all Polish license plates
python -m python_pkg.polish_license_plates.polish_license_plates_anki
python -m python_pkg.anki_decks.polish_license_plates.polish_license_plates_anki
# Specify custom output file
python -m python_pkg.polish_license_plates.polish_license_plates_anki \
python -m python_pkg.anki_decks.polish_license_plates.polish_license_plates_anki \
--output plates.apkg
Output:
@ -30,7 +30,9 @@ from typing import TYPE_CHECKING
import genanki
from python_pkg.polish_license_plates.license_plate_data import LICENSE_PLATE_CODES
from python_pkg.anki_decks.polish_license_plates.license_plate_data import (
LICENSE_PLATE_CODES,
)
if TYPE_CHECKING:
from collections.abc import Sequence

View File

@ -7,21 +7,21 @@ from pathlib import Path
import pytest
try:
from python_pkg.polish_license_plates.license_plate_data import (
from python_pkg.anki_decks.polish_license_plates.license_plate_data import (
LICENSE_PLATE_CODES,
)
from python_pkg.polish_license_plates.polish_license_plates_anki import (
from python_pkg.anki_decks.polish_license_plates.polish_license_plates_anki import (
generate_anki_package,
main,
)
except ImportError:
import sys
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from python_pkg.polish_license_plates.license_plate_data import (
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent.parent))
from python_pkg.anki_decks.polish_license_plates.license_plate_data import (
LICENSE_PLATE_CODES,
)
from python_pkg.polish_license_plates.polish_license_plates_anki import (
from python_pkg.anki_decks.polish_license_plates.polish_license_plates_anki import (
generate_anki_package,
main,
)

View File

@ -52,7 +52,7 @@ pip install matplotlib genanki geopandas
```bash
# From the repository root
python -m python_pkg.warsaw_districts.warsaw_districts_anki
python -m python_pkg.anki_decks.warsaw_districts.warsaw_districts_anki
```
This creates:
@ -63,10 +63,10 @@ This creates:
```bash
# Custom output file
python -m python_pkg.warsaw_districts.warsaw_districts_anki --output my_cards.apkg
python -m python_pkg.anki_decks.warsaw_districts.warsaw_districts_anki --output my_cards.apkg
# Custom deck name
python -m python_pkg.warsaw_districts.warsaw_districts_anki --deck-name "Warszawa - Dzielnice"
python -m python_pkg.anki_decks.warsaw_districts.warsaw_districts_anki --deck-name "Warszawa - Dzielnice"
```
## Importing into Anki

View File

@ -8,7 +8,7 @@ import matplotlib.pyplot as plt
import pytest
try:
from python_pkg.warsaw_districts.warsaw_districts_anki import (
from python_pkg.anki_decks.warsaw_districts.warsaw_districts_anki import (
WARSAW_DISTRICTS,
create_district_map,
generate_anki_package,
@ -18,8 +18,8 @@ try:
except ImportError:
import sys
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from python_pkg.warsaw_districts.warsaw_districts_anki import (
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent.parent))
from python_pkg.anki_decks.warsaw_districts.warsaw_districts_anki import (
WARSAW_DISTRICTS,
create_district_map,
generate_anki_package,

View File

@ -7,10 +7,11 @@ from OpenStreetMap.
Usage:
# Generate Anki cards for all Warsaw districts
python -m python_pkg.warsaw_districts.warsaw_districts_anki
python -m python_pkg.anki_decks.warsaw_districts.warsaw_districts_anki
# Specify custom output file
python -m python_pkg.warsaw_districts.warsaw_districts_anki --output warsaw.apkg
python -m python_pkg.anki_decks.warsaw_districts.warsaw_districts_anki \
--output warsaw.apkg
Output:
Creates a self-contained .apkg file that can be directly imported into Anki.

View File

@ -0,0 +1,287 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "Ratusz-Arsena\u0142",
"line": "",
"osm_id": 35121250
},
"geometry": { "type": "Point", "coordinates": [21.0008823, 52.2452163] }
},
{
"type": "Feature",
"properties": { "name": "Marymont", "line": "", "osm_id": 291414851 },
"geometry": { "type": "Point", "coordinates": [20.9719399, 52.2715768] }
},
{
"type": "Feature",
"properties": {
"name": "Stare Bielany",
"line": "",
"osm_id": 307389114
},
"geometry": { "type": "Point", "coordinates": [20.9493511, 52.2818277] }
},
{
"type": "Feature",
"properties": { "name": "Wawrzyszew", "line": "", "osm_id": 307389115 },
"geometry": { "type": "Point", "coordinates": [20.939515, 52.2863474] }
},
{
"type": "Feature",
"properties": { "name": "M\u0142ociny", "line": "", "osm_id": 307389116 },
"geometry": { "type": "Point", "coordinates": [20.9298678, 52.2907703] }
},
{
"type": "Feature",
"properties": {
"name": "S\u0142odowiec",
"line": "",
"osm_id": 1958108834
},
"geometry": { "type": "Point", "coordinates": [20.9601259, 52.2768261] }
},
{
"type": "Feature",
"properties": {
"name": "Dworzec Wile\u0144ski",
"line": "",
"osm_id": 3390187815
},
"geometry": { "type": "Point", "coordinates": [21.0357972, 52.2537771] }
},
{
"type": "Feature",
"properties": {
"name": "Stadion Narodowy",
"line": "",
"osm_id": 3390197100
},
"geometry": { "type": "Point", "coordinates": [21.042847, 52.2468346] }
},
{
"type": "Feature",
"properties": {
"name": "Centrum Nauki Kopernik",
"line": "",
"osm_id": 3390230685
},
"geometry": { "type": "Point", "coordinates": [21.0317878, 52.2399148] }
},
{
"type": "Feature",
"properties": {
"name": "Nowy \u015awiat-Uniwersytet",
"line": "",
"osm_id": 3390237898
},
"geometry": { "type": "Point", "coordinates": [21.0168168, 52.2368196] }
},
{
"type": "Feature",
"properties": { "name": "Rondo ONZ", "line": "", "osm_id": 3390266492 },
"geometry": { "type": "Point", "coordinates": [20.9981024, 52.2330735] }
},
{
"type": "Feature",
"properties": {
"name": "Rondo Daszy\u0144skiego",
"line": "",
"osm_id": 3390267294
},
"geometry": { "type": "Point", "coordinates": [20.9828946, 52.2300827] }
},
{
"type": "Feature",
"properties": { "name": "Kabaty", "line": "", "osm_id": 3390283399 },
"geometry": { "type": "Point", "coordinates": [21.0650711, 52.1320765] }
},
{
"type": "Feature",
"properties": {
"name": "Stok\u0142osy",
"line": "",
"osm_id": 3390289961
},
"geometry": { "type": "Point", "coordinates": [21.0347233, 52.1560759] }
},
{
"type": "Feature",
"properties": { "name": "Natolin", "line": "", "osm_id": 3390290324 },
"geometry": { "type": "Point", "coordinates": [21.0564351, 52.1411007] }
},
{
"type": "Feature",
"properties": { "name": "Imielin", "line": "", "osm_id": 3390290598 },
"geometry": { "type": "Point", "coordinates": [21.0461062, 52.1493] }
},
{
"type": "Feature",
"properties": {
"name": "Ursyn\u00f3w",
"line": "",
"osm_id": 3390304927
},
"geometry": { "type": "Point", "coordinates": [21.0276283, 52.1620456] }
},
{
"type": "Feature",
"properties": {
"name": "S\u0142u\u017cew",
"line": "",
"osm_id": 3390306374
},
"geometry": { "type": "Point", "coordinates": [21.0262866, 52.1727624] }
},
{
"type": "Feature",
"properties": {
"name": "Rac\u0142awicka",
"line": "",
"osm_id": 3390327068
},
"geometry": { "type": "Point", "coordinates": [21.0122349, 52.1988637] }
},
{
"type": "Feature",
"properties": { "name": "Wierzbno", "line": "", "osm_id": 3390333313 },
"geometry": { "type": "Point", "coordinates": [21.0167966, 52.1898719] }
},
{
"type": "Feature",
"properties": { "name": "Wilanowska", "line": "", "osm_id": 3390336021 },
"geometry": { "type": "Point", "coordinates": [21.0231452, 52.1818168] }
},
{
"type": "Feature",
"properties": {
"name": "Pole Mokotowskie",
"line": "",
"osm_id": 3390342469
},
"geometry": { "type": "Point", "coordinates": [21.0079298, 52.2087775] }
},
{
"type": "Feature",
"properties": {
"name": "Politechnika",
"line": "",
"osm_id": 3390361095
},
"geometry": { "type": "Point", "coordinates": [21.0153031, 52.2186581] }
},
{
"type": "Feature",
"properties": { "name": "Centrum", "line": "", "osm_id": 3390365405 },
"geometry": { "type": "Point", "coordinates": [21.010186, 52.2310069] }
},
{
"type": "Feature",
"properties": {
"name": "Dworzec Gda\u0144ski",
"line": "",
"osm_id": 3416840991
},
"geometry": { "type": "Point", "coordinates": [20.9941857, 52.2580586] }
},
{
"type": "Feature",
"properties": {
"name": "Plac Wilsona",
"line": "",
"osm_id": 3615569910
},
"geometry": { "type": "Point", "coordinates": [20.9844973, 52.2692619] }
},
{
"type": "Feature",
"properties": { "name": "P\u0142ocka", "line": "", "osm_id": 4930657482 },
"geometry": { "type": "Point", "coordinates": [20.9663847, 52.2324542] }
},
{
"type": "Feature",
"properties": { "name": "Trocka", "line": "", "osm_id": 4930657487 },
"geometry": { "type": "Point", "coordinates": [21.0550586, 52.2751021] }
},
{
"type": "Feature",
"properties": {
"name": "\u015awi\u0119tokrzyska",
"line": "",
"osm_id": 5117464830
},
"geometry": { "type": "Point", "coordinates": [21.0078988, 52.2350954] }
},
{
"type": "Feature",
"properties": {
"name": "Ksi\u0119cia Janusza",
"line": "",
"osm_id": 5907821373
},
"geometry": { "type": "Point", "coordinates": [20.9443771, 52.2391822] }
},
{
"type": "Feature",
"properties": {
"name": "M\u0142yn\u00f3w",
"line": "",
"osm_id": 5907821374
},
"geometry": { "type": "Point", "coordinates": [20.9601048, 52.2376624] }
},
{
"type": "Feature",
"properties": { "name": "Szwedzka", "line": "", "osm_id": 6053348692 },
"geometry": { "type": "Point", "coordinates": [21.0455232, 52.2634709] }
},
{
"type": "Feature",
"properties": {
"name": "Targ\u00f3wek Mieszkaniowy",
"line": "",
"osm_id": 6564265270
},
"geometry": { "type": "Point", "coordinates": [21.0513658, 52.2692518] }
},
{
"type": "Feature",
"properties": { "name": "Bemowo", "line": "", "osm_id": 7362922676 },
"geometry": { "type": "Point", "coordinates": [20.9154991, 52.2392071] }
},
{
"type": "Feature",
"properties": {
"name": "Ulrych\u00f3w",
"line": "",
"osm_id": 7362922677
},
"geometry": { "type": "Point", "coordinates": [20.9298652, 52.2403314] }
},
{
"type": "Feature",
"properties": {
"name": "Br\u00f3dno",
"line": "",
"osm_id": 10058224345
},
"geometry": { "type": "Point", "coordinates": [21.0289387, 52.293585] }
},
{
"type": "Feature",
"properties": {
"name": "Kondratowicza",
"line": "",
"osm_id": 10058224348
},
"geometry": { "type": "Point", "coordinates": [21.0486889, 52.2920848] }
},
{
"type": "Feature",
"properties": { "name": "Zacisze", "line": "", "osm_id": 10058224349 },
"geometry": { "type": "Point", "coordinates": [21.062148, 52.2837496] }
}
]
}

View File

@ -5,7 +5,7 @@ Generates Anki-compatible flashcard decks with maps showing individual
Warsaw streets highlighted on a city map.
Usage:
python -m python_pkg.warsaw_streets.warsaw_streets_anki
python -m python_pkg.anki_decks.warsaw_streets.warsaw_streets_anki
Output:
Creates a self-contained .apkg file that can be directly imported into Anki.

View File

@ -262,7 +262,10 @@ def get_warsaw_boundary() -> gpd.GeoDataFrame:
# Try to use districts file first
districts_path = (
Path(__file__).parent / "warsaw_districts" / "warszawa-dzielnice.geojson"
Path(__file__).parent
/ "anki_decks"
/ "warsaw_districts"
/ "warszawa-dzielnice.geojson"
)
if districts_path.exists():
warsaw_gdf = gpd.read_file(districts_path)
@ -315,7 +318,10 @@ def get_warsaw_districts() -> gpd.GeoDataFrame:
GeoDataFrame with district boundaries.
"""
districts_path = (
Path(__file__).parent / "warsaw_districts" / "warszawa-dzielnice.geojson"
Path(__file__).parent
/ "anki_decks"
/ "warsaw_districts"
/ "warszawa-dzielnice.geojson"
)
if districts_path.exists():
gdf = gpd.read_file(districts_path)