Package: postalcodes-ca
postalcodes-capostalcodes-cais a fork of Scott Rodkey'spypostalcodepackage, which is itself a fork of Nathan Van Gheem'spyzipcodepackage. The zipcode database has been replaced with Canadian cities and their postal codes. The general usage is similar.InstallTo install:pip install postalcodes-caA1A 1A1- a primer on Canadian postal codesCanadian postal codesare six characters in the formatA1A 1A1, whereAis a letter and1is a digit, with a space separating the third and fourth characters. Postal codes do not use the 6 letters D, F, I, O, Q or U. Additionally, W and Z are not used as the first letter of any postal code.The first three characters are theforward sortation area(FSA), and the last three are thelocal delivery unit(LDU). The first letter, called thepostal district, tells you the province. Quebec and Ontario have multiple postal districts andXis used for both Nunavut and the Northwest Territories. The second character (a digit) tells you if the postal code isurbanorrural, a0(e.g.A0A) means it's rural, any other number means it's urban. SeePostal codes in Canadaon Wikipedia for details.This module supports looking up both full postal codes and FSA codes. There are 1,651 (+1 for Santa) FSA codes and 877,409 (+1 for Santa) FSA+LDU combinations (out of a maximum possible 18*10*20 = 3,600 FSA codes and 18*10*20*10*20*10 = 7,200,000 postal codes).Usage>>>frompostalcodes_caimportfsa_codes>>>fsa_codes['V5K']FSA(code='V5K', name='Vancouver (North Hastings-Sunrise)', province='British Columbia', latitude=49.2807, longitude=-123.0397, accuracy=6)>>>fsa_codes.get('V5K')FSA(code='V5K', name='Vancouver (North Hastings-Sunrise)', province='British Columbia', latitude=49.2807, longitude=-123.0397, accuracy=6)>>>fsa_codes.get('v5k')[...]ValueError: invalid FSA, must start with one of ABCEGHJKLMNPRSTVXY: 'v5k'>>>fsa_codes.get('v5kblahblah',strict=False)# only the first 3 characters are usedFSA(code='V5K', name='Vancouver (North Hastings-Sunrise)', province='British Columbia', latitude=49.2807, longitude=-123.0397, accuracy=6)Get a list of FSA codes given a radius in kilometers (multiply by1.609344if you have miles). Note that this actually searches a square area, not a circle with a radius:>>>results=fsa_codes.get_nearby('V5K',radius=4)>>>forrinresults:...print(f"{r.code}:{r.name},{r.province}")...V5K: Vancouver (North Hastings-Sunrise), British ColumbiaV5L: Vancouver (North Grandview-Woodlands), British ColumbiaV5M: Vancouver (South Hastings-Sunrise / North Renfrew-Collingwood), British ColumbiaV5N: Vancouver (South Grandview-Woodlands / NE Kensington), British ColumbiaV7L: North Vancouver South Central, British ColumbiaV5C: Burnaby (Burnaby Heights / Willingdon Heights / West Central Valley), British ColumbiaV5G: Burnaby (Cascade-Schou / Douglas-Gilpin), British ColumbiaSearch by code, city name or province name usingSQL syntax:>>>fsa_codes.search(name='Calgary')# exact match[FSA(code='T3S', name='Calgary', province='Alberta', latitude=50.9153, longitude=-113.8932, accuracy=4)]>>>len(fsa_codes.search(name='Calgary%'))35>>>len(fsa_codes.search(code='T2%'))20>>>len(fsa_codes.search(province='Alberta'))154>>>fsa_codes.search(province='California')# returns None>>>There's an identical API for postal codes, but keep in mind that the data is of a lower quality (seebelow):>>>frompostalcodes_caimportpostal_codes>>>postal_codes['M5V 3L9']PostalCode(code='M5V 3L9', name='Toronto', province='Ontario', latitude=43.642, longitude=-79.386)>>>postal_codes.get('M5V 3L9')PostalCode(code='M5V 3L9', name='Toronto', province='Ontario', latitude=43.642, longitude=-79.386)>>>postal_codes.get('m5v3l9')[...]ValueError: invalid postal code, must be 7 characters: 'm5v3l9'>>>postal_codes.get('m5v3l9blahblah',strict=False)# only the first 6 or 7 characters are usedPostalCode(code='M5V 3L9', name='Toronto', province='Ontario', latitude=43.642, longitude=-79.386)Check if a string matches the format of a postal code or FSA code:>>>frompostalcodes_caimportparse_postal_code,parse_fsa>>>parse_postal_code('m5v3l9 blah  ')'M5V 3L9'>>>parse_postal_code('m5v3l9 blah  ',strict=True)[...]ValueError: invalid postal code, must be 7 characters: 'm5v3l9 blah  '>>>parse_fsa('M5V')'M5V'>>>parse_fsa('M5V 3L9')'M5V'>>>parse_fsa('M5V 3L9',strict=True)[...]ValueError: invalid FSA, must be 3 characters: 'M5V 3L9'NotesH0H 0H0- Santa's postal codeThere is a special postal code for Santa Claus which looks like this:>>>postal_codes["H0H 0H0"]PostalCode(code='H0H 0H0', name='Reserved (Santa Claus)', province='Quebec', latitude=90.0, longitude=0.0)>>>fsa_codes['H0H']FSA(code='H0H', name='Reserved (Santa Claus)', province='Quebec', latitude=90.0, longitude=0.0, accuracy=None)Even though Santa lives at the North Pole, the province is given as "Quebec" becauseHstarts a Quebec postal code.postalcodes-catreatsH0H 0H0like any other postal code because it's a legitimate postal code that gets a million letters each year.Differences between data inpostal_codesandfsa_codesPostalCodenames never have accents but someFSAnames do:>>>fsa_codes["G4X"].name'Gaspé'>>>postal_codes["G4X 6T9"].name'Gaspe'FSAcodes' names can be more descriptive>>>fsa_codes["V5K"].name'Vancouver (North Hastings-Sunrise)'>>>postal_codes["V5K 5G9"].name'Vancouver'FSAcodes have anaccuracyproperty which is eitherNoneor an integer between 1-6 (inclusive) representing the accuracy of their lat/lng coordinates where "1=estimated, 4=geonameid, 6=centroid of addresses or shape">>>fsa_codes["G4X"].accuracy4About a dozenFSAcodes haveNoneas their.accuracy.ForPostalCodes,.accuracyis always6.Postal code location data isn't always accurateThere are at least 92PostalCodeswhose latitude/longitude coordinates are completely outside Canada. I found this using basic sanity checking (seeimport.py), which probably means that there are more datapoints which are wrong. Seethis poston the GeoNames mailing list for details.The data has multiple entries for some postal codesIn the original data there are 4 duplicate entries for FSA codes and 842 duplicate entries for postal codes. Usually those contain extra names for the postal code (for codes that cover multiple places) but sometimes the lat/long coordinates can be different as well.postalcodes-cajust uses the first code to appear in the CSV.Internally reserved codes are not includedThere are some FSA codes such asA9Xwhich are "reserved for internal testing", those are not in the data:>>>fsa_codes['A9X'][...]KeyError: 'A9X'Postal codes and FSAs are not actually pointsWhile this package associates postal codes and FSA codes to points, these codes actually represent areas, as you can see fromthis map of FSA regions:(datafromthe 2016 censusvisualized usingQGIS, seehttps://github.com/inkjet/pypostalcode/issues/6for details)Data is CC BY 4.0https://download.geonames.org/export/zip/The data is fromGeoNames. It's distributed under aCC BY 4.0license. Please respect the license if you use this module.DevelopmentHow to contribute to the dataIf you notice an issue with the data, you can report it by creating a GitHub account andcreating a new issue.If you want to fix the issue yourself, then look atCA.tsv, figure out what needs to be changed and report the issue to the GeoNames project ontheir mailing list. Once it is fixed you can create an issue onpostalcodes-cato tell us to update the data.How to update the vendored datacdpostalcodes-ca/
bashupdate_data.shor you can do it manually:CA.tsv- FSA codescdinto the same directory as this readme filego tohttps://download.geonames.org/export/zip/downloadCA.zip(notCA_full.csv.zip)unzip the file into this directory withunzip CA.zip CA.txtcompare the file you just downloaded against the one that's already used withdiff CA.tsv CA.txt. If that command produces no output, there's nothing more to dorenameCA.txttoCA.tsvwithmv CA.txt CA.tsv(we rename the file so that it renders nicely on GitHub)runpython3 postalcodes-ca/import.pyto update thepostalcodes-ca/postalcodes.dbfileCA_full.tsv- postal codescdinto the same directory as this readme filego tohttps://download.geonames.org/export/zip/downloadCA_full.csv.zip(notCA.zip)unzip the file into this directory withunzip CA_full.csv.zip CA_full.txtrunpython3 postalcodes-ca/import.pyto update thepostalcodes-ca/postalcodes.dbfilePackage sizeJust the database of FSA codes (CA.txt/CA.tsv) is negligible, the original data is 40KB zipped, 124KB unzipped and 250KB as sqlite (with indices).The full postal codes databaseCA_full.txt(downloaded asCA_full.csv.zip) is 6MB zipped, 48MB unzipped. The sqlite .db file with only the 4 important fields (without indices) is 37MB. With a province field it grows to 46MB and with indices further to 95MB. When uploading to PyPI the package is zipped down to 36 MB which is below PyPI's60MB limit, but this might cause issues in the future.