Postal Codes Dataset for Poland, PL

623
Updated:
Files:1
Size:7.04 MB
Rows:72,899
Formats:csv
License:CC-BY-4.0

Postal Codes Dataset for Poland, PL including name of the city, town, or place, various administrative divisions and alternative city names.

Part of a Data Solution

  • Postal Codes Solution

    Every worldwide postal-code dataset in one bundle — the ultimate global reference for precise postal codes.

    Explore →

Premium

You're viewing a free sample

Get the complete dataset — all rows and files — delivered instantly after checkout, with lifetime access to the latest version.

  • Secure checkout via Stripe
  • Instant download after payment
  • Lifetime access to the latest version
  • Creative Commons Attribution 4.0 license
20% off
$49.90$39.92
one-time payment

API Access

Access dataset files directly from scripts, code, or AI agents.

Browse dataset files
Dataset Files

Each file has a stable URL (r-link) that you can use directly in scripts, apps, or AI agents. These URLs are permanent and safe to hardcode.

/logistics/postal-codes-pl/
https://datahub.io/logistics/postal-codes-pl/_r/-/.licensing-notes.md
https://datahub.io/logistics/postal-codes-pl/_r/-/.migration-notes.md
https://datahub.io/logistics/postal-codes-pl/_r/-/ATTRIBUTION.txt
https://datahub.io/logistics/postal-codes-pl/_r/-/README.md
https://datahub.io/logistics/postal-codes-pl/_r/-/datapackage.yaml
Key Files

Start with these files — they give you everything you need to understand and access the dataset.

datapackage.yaml— metadata & schema
https://datahub.io/logistics/postal-codes-pl/_r/-/datapackage.yaml
README.md— documentation
https://datahub.io/logistics/postal-codes-pl/_r/-/README.md
Typical Usage
  1. 1. Fetch datapackage.yaml to inspect schema and resources
  2. 2. Download data resources listed in datapackage.yaml
  3. 3. Read README.md for full context

Data Files

postal-codes-pl-sample


About this dataset

Poland (PL): migration notes

Internal record of the P5 migration from the old scripts to the producer: the discrepancies found, their causes, and who decided what. This is a dated record, so the numbers are as of the migration and not kept current. It is not shipped in the zip.

  • Issue: pc-28e.7.45 (closed 2026-10-03)
  • Commit: 36df9c0 (worktree commit 09206b2, landed unchanged), batch 4
  • Parity verdict: unexplained (32 unclassified cells; the gate blocks on any unclassified cell); accepted as upstream drift
  • Producer: custom, refresh disabled

Sources

InputURLNotes
GeoNames postal exporthttps://download.geonames.org/export/zip/PL.zipCarries the official GUS TERYT powiat and gmina codes
GeoNames gazetteer dumphttps://download.geonames.org/export/dump/PL.zipUsed for alternative_city_name; replaces the legacy R2 copy
  • The old recover_alt_names.py read nothing upstream. It copied alternate names from the legacy R2 object pl/pl.csv (an intermediate export of the old scripts/geonames/geonames_parse_to_R2.py job), pulling it from R2 with credentials (--fetch). That object isn't a real source.
  • Poczta Polska's PNA register stays excluded: it is a commercial product whose terms forbid resale, the free PDF edition included (.licensing-notes.md, 2026-08-27 audit).

Parity against the live zip (2026-10-03)

Rows: 72,899 live and 72,899 fresh, none only on one side. Row order identical (the old sort was kept, so there is no row_order class). 32 changed cells, all in alternative_city_name, all unclassified. No other column differs. Before writing the producer, the agent checked the dump rule offline against the live CSV: 72,867 of 72,899 alternate names match exactly.

Cause: edits to the GeoNames dump after the legacy snapshot (upstream drift). Each changed cell maps to a dump entry modified after the legacy R2 copy was taken. 20 cells gained a name, 12 lost one.

PlaceRows (postal codes)Live → freshDump entry that now wins (modified)
Lipnik12 (98-354, 32-412, 19-230, 37-206, 37-220, 27-540, 28-404, 28-221, 42-253, 12-100, 63-507, 73-110)Comuna de Lipnik → empty13665098 (2026-06-29), no alternate names; last matching entry wins
Waksmund3 (34-400, 34-431, 34-433)empty → Vaksmund756227 (2026-09-02)
Widawa2 (98-170, 42-287)empty → Vidava13562336 (2026-09-02)
Binarowa2 (38-306, 38-340)empty → Binarova775917 (2026-09-02)
Skawinki2 (34-100, 34-143)empty → Skavinki3085805 (2026-09-02)
Siestrzechowice2 (48-300, 48-303)empty → Grunau3085928 (2026-09-11)
Bestwinka1 (43-512)empty → Bestvinka3103655 (2026-09-02)
Borowno1 (42-233)empty → Borovno3102819 (2026-09-02)
Lipkowo1 (19-400)empty → Lipkovo12110766 (2026-09-02)
Naprawa1 (34-240)empty → Naprava3091135 (2026-09-02)
Plewiska1 (62-064)empty → Pleviska3088846 (2026-09-02)
Twardawa1 (48-250)empty → Tvardava3082940 (2026-09-02)
Siedliska Pierwsze1 (21-060)empty → Siedliska759385 (2026-04-17)
Stare Kostry1 (18-214)empty → Kostry Stare767974 (2026-05-14)
Stare Warele1 (18-214)empty → Warel Stare756154 (2026-05-14)

The dump entries and dates are from the agent's trace. The per-place row breakdown was recomputed on 2026-10-05 from the live CSV and the committed data/pl.csv (it reproduces the 32 cells; the parity report lists only 10 examples).

The public sample (postal.datahub.io/pl/pl.csv) came out unexplained (informational only): 194 leading_zero_restored and 112 unclassified cells. It is the old generic GeoNames parse that turned TERYT 0201 into 201.0.

Decisions

DecisionByBasis
Rebuild alternative_city_name from the GeoNames dump with the scripts/producers/geonames.py rule (first non-numeric alternate name of the entry whose asciiname equals the cleaned place_name; last match wins), instead of copying the legacy R2 pl/pl.csvAgent, under plan decision D1 (write the producer against the original source); put to the user, who replied with a general rule (row below) and did not address the switch separatelyThe legacy object isn't fetchable from any original source. The old script's docstring said its own re-derivation (name + nearest coordinate) reproduced only ~76%; the asciiname rule matches all but the 32 drift cells. This is the D1 precedent later cited for de (280 cells, described to the user as "the same approach you approved for pl", session 7df0c5be), pt (18 cells) and others
Accept the 32 alt-name cellsUser, 2026-10-03 (session d33e1b7e): "in general I accept any changes that stem from updated source data"Said in reply to the pl/ph question ("Accept both?"), which the user had left unanswered in the form. The orchestrator recorded it as the extended standing rule (upstream drift traced to source) in docs/parity/p5.md and the plan
Keep recover_alt_names.py's "drop aliases that just repeat place_name" ruleAgent: a faithful portThe cleaned name is only the lookup key; place_name ships uncleaned, as live does
admin_code1 for the one row without TERYT (88-420 Jeziora) falls back to the GeoNames region number, mapped through the TERYT prefixAgentLive already has KP there
No row-count assertAgentOld asserts otherwise ported (see below)
Drop row and distinct-code counts from README; keep admin-unit counts (2,476 gminas, 380 powiats, 16 voivodeships), checked against the fresh dataAgent, per the README counts ruleATTRIBUTION.txt untouched

Transforms carried over

Folded from fetch_source.py → build_base.py → recover_alt_names.py → integrity_checker.py (package.py, publish_r2.py and the scripts README deleted):

  • TERYT powiat (4 digits) and gmina (6 digits) codes copied verbatim as text (no pandas 201.0).
  • admin_code1 → ISO 3166-2:PL from the TERYT voivodeship prefix, not GeoNames' sequential region number (72–87). GeoNames number, TERYT prefix and region name must agree 1:1:1, and all 16 voivodeships must be present.
  • Voivodeship names kept as GeoNames spells them (English exonyms, e.g. "Lower Silesia").
  • Rows sorted by (admin_code1, admin_code2, postal_code, place_name).
  • integrity_checker.py's checks are now ProducerErrors: NN-NNN postal codes; 4/6-digit TERYT with the gmina extending the powiat; no literal "nan" or ".0" suffix; coordinates inside Poland's bounding box; unique primary key (postal_code, place_name, admin_code3). The gmina is in the key because 78-650 Pilów is listed in two gminas (321703, 321705); both rows are kept.

Open questions

  • Resolved (user, 2026-10-05, pc-28e.7.59): the D1 switch of alternative_city_name from the legacy R2 copy to the GeoNames dump is confirmed.
  • .licensing-notes.md still says alternative_city_name "was recovered from the existing R2 copy rather than re-derived", which is no longer true, and it carries row counts (72,899 / 72,900 / 20,299). Left for the end-of-epic sweep (pc-hfz).

Provenance

Reconstructed 2026-10-05 from the agent transcript d33e1b7e-5027-498a-a97f-ba914ee2524e/subagents/agent-a651a38384495c267.jsonl, the orchestrator session d33e1b7e-… (hold, question, user reply, landing), session 7df0c5be-… (later citations of the pl precedent), the plan's D1 entry (session 068ca403-…), the commit message, the bd notes and close reason, and docs/parity/p5.md.