#!/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}")