PROCITY/pipeline/godverse_town.py
type-two 223fbcaf72 Lane G (GODVERSE, ultra) R1: real-shop census adapter — 18 real Newtown shops on the real road graph
godverse_town.py marries a donor OSM cache's roads[] with thriftgod's DealGod-scraped
shop census (2,928 real AU secondhand shops) -> <town>_godverse.json, schema v2 unchanged.
First artifact newtown_godverse boots clean (?plansrc=osm&town=newtown_godverse).
Lane brief + asks (Draco ruling, per-town bookmarks, enterShop selector) in
docs/LANES/LANE_G_GODVERSE.md + G-progress.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 20:19:14 +10:00

52 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Lane G — GODVERSE town adapter: thriftgod's REAL shop census -> a procity-town-cache/2.
Marries the two halves: roads[] come from an existing OSM cache (Lane E's build_towns.py),
shops[] come from thriftgod's Postgres (the real-business census DealGod scraped). Result:
walk the town's actual streets past its actual secondhand shops.
python3 pipeline/godverse_town.py newtown_real newtown_godverse # roads-donor key, out key
Runs on ultra (needs the local `thriftgod` PG + psycopg2 — the thriftgod server's own deps).
"""
import json, os, sys
import psycopg2, psycopg2.extras
DONOR, OUT = sys.argv[1], sys.argv[2]
HERE = os.path.dirname(os.path.abspath(__file__))
TOWNS = os.path.join(HERE, '..', 'web', 'assets', 'towns')
# thriftgod shop_type -> procity SHOP_TYPES (registry.js is the vocabulary of record)
TYPE_MAP = {'music': 'record', 'charity': 'opshop', 'second_hand': 'opshop', 'antiques': 'opshop',
'books': 'book', 'toys': 'toy', 'video_games': 'video', 'games': 'toy',
'pawnbroker': 'pawn', 'market': 'dept'}
donor = json.load(open(os.path.join(TOWNS, f'{DONOR}.json')))
bb = donor['bbox']
db = psycopg2.connect(os.environ.get('THRIFTGOD_DSN', 'dbname=thriftgod'))
c = db.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
c.execute("""SELECT id, name, shop_type, lat, lng, suburb FROM shop
WHERE lat BETWEEN %s AND %s AND lng BETWEEN %s AND %s ORDER BY id""",
(bb['minLat'], bb['maxLat'], bb['minLon'], bb['maxLon']))
shops = [{'id': r['id'], 'name': r['name'],
'type': TYPE_MAP.get(r['shop_type'], 'opshop'),
'lat': float(r['lat']), 'lon': float(r['lng']),
'suburb': (r['suburb'] or '').split('|')[0]} for r in c.fetchall()]
out = dict(donor)
out.update({
'key': OUT,
'town': donor['town'],
'source': 'godverse+osm', # shops = thriftgod census, roads = OSM (donor)
'generator': 'pipeline/godverse_town.py',
'attribution': donor['attribution'] + ' · shop census: GODVERSE/thriftgod',
'shops': shops,
'counts': {**donor.get('counts', {}), 'shops': len(shops)},
})
dst = os.path.join(TOWNS, f'{OUT}.json')
json.dump(out, open(dst, 'w'), indent=1)
types = {}
for s in shops: types[s['type']] = types.get(s['type'], 0) + 1
print(f"{OUT}: {len(shops)} REAL shops ({types}) + {len(out.get('roads', []))} OSM roads -> {dst}")