1. Thomas Kluyver
  2. mapping

Commits

Thomas Kluyver  committed cbe485c

Initial import

  • Participants
  • Branches default

Comments (0)

Files changed (5)

File .hgignore

View file
  • Ignore whitespace
+syntax: glob
+*.pyc

File mapping.py

View file
  • Ignore whitespace
+import networkx as nx
+from two_way_dict import TwoWayDict
+
+LOAD_TDWG = True
+
+class Region(object):
+    def __init__(self, code, inmap):
+        self.code = code
+        self._inmap = inmap
+        
+    def __repr__(self):
+        name = self._inmap.nameindex.get_key(self.code)
+        if name:
+            return "<Region: {0} ~ {1}, {2} children>"\
+                    .format(self.code, name, len(self.children())) 
+        return "<Region: {0}, {1} children>"\
+                    .format(self.code, len(self.children()))
+        
+    def children(self):
+        return self._inmap._map.successors(self.code)
+        
+    def parents(self):
+        return self._inmap._map.predecessors(self.code)
+        
+    def containsregion(self, code):
+        if code == self.code:
+            return True
+        return any(self._inmap[child].containsregion(code)\
+                    for child in self.children())
+  
+class _NumCode(int):
+    """A meaningless but hashable numeric code."""
+    def __repr__(self):
+        return "[UR{0}]".format(self)
+        
+    def __hash__(self):
+        return hash(self.__class__) ^ int.__hash__(self)
+        
+    def __eq__(self, other):
+        return isinstance(other, _NumCode) and int(self) == int(other)
+    def __ne__(self, other):
+        return not(self == other)
+
+class Map(object):
+    """A map is a collection of regions, which keeps track of relationships,
+    such as 'The Netherlands is in Middle Europe':
+    worldmap.byname("Middle Europe").containsregion("NET")  # --> True
+    """
+    def __init__(self, rootname="!!WORLD"):
+        self.rootname = rootname
+        self.nameindex = TwoWayDict()
+        self._map = nx.DiGraph()
+        self.indices = {}
+        self._next_unused_code_no = 0
+        
+    def _get_unused_code(self):
+        """Get a meaningless numeric code for a region. It is unique when created,
+        but may be overwritten later."""
+        self._next_unused_code_no += 1
+        return _NumCode(self._next_unused_code_no)
+        
+    def add_region(self, code=None, name=None, parent=None, children=[], **indexrefs):
+        """Add a region to the map, by code and  an optional name. If you don't
+        specify a code, a new numeric code will be created for you. The code will
+        be returned.
+        
+        If you specify a parent region (by code), the region will be added
+        within that (specify the smallest region which contains it entirely).
+        If not, it will be a floating region.
+        
+        To build more complex maps (i.e. not a strict hierarchy), you may also
+        pass a list of codes to become children of this region.
+        
+        You can add a series of index=reference pairs, to add the name to
+        different indices.
+        
+        E.g.
+        worldmap.add_region("NET", "Netherlands", "11", ISO="NL")
+        MUTcode = worldmap.add_region(name="Madeupitania",
+                                        children=["MUT-N","MUT-C","MUT-S"])
+        """
+        if not code:
+            code = self._get_unused_code()
+        self._map.add_node(code)
+        
+        if parent:
+            self._map.add_edge(parent, code)
+        for child in children:
+            self._map.add_edge(code, child)
+        
+        if name:
+            self.nameindex[name] = code
+        for index, ref in indexrefs.items():
+            if ref:
+                self.indices[index][ref] = code
+        
+        return code
+                
+    def children(self):
+        """Get first level regions in the map."""
+        return self._map.successors(self.rootname)
+                
+    def __getitem__(self, code):
+        return Region(code, self)
+        
+    def byname(self, name):
+        """Get a region by its name in the nameindex."""
+        return self[self.nameindex[name]]
+        
+    def __repr__(self):
+        return "<Map, with {0} top level regions>"\
+                    .format(len(self.children()))
+    
+    def __len__(self):
+        return len(self._map)
+
+if LOAD_TDWG:
+    import tdwg_data
+    world = Map()
+    world.indices["ISO"] = {}
+
+    for code, name, ISO, parent, notes in tdwg_data.data:
+        if name in world.nameindex:
+            name = None
+        if ISO in world.indices["ISO"]:
+            ISO = None
+        world.add_region(code, name, parent, ISO=ISO)
+        
+    for name, parent, children in tdwg_data.extra_countries:
+        world.add_region(name=name, parent=parent, children=children)
+    
+    for name, refname in tdwg_data.extra_names.items():
+        world.nameindex[name] = world.nameindex[refname]
+        
+    for ISO, name in tdwg_data.extra_ISO.items():
+        world.indices["ISO"][ISO] = world.nameindex[name]
+        
+    tdwg_levels = tdwg_data.tdwg_by_level   

File tdwg_data.py

View file
  • Ignore whitespace
+# -*- coding: utf-8 -*-
+"""This contains data for the TDWG world regions. Do not use this module
+directly, but instead do:
+from taxonome import regions
+regions.names["China"]
+regions.tdwg["NET"]
+regions.tdwg_levels[1]["1"]
+
+If LOAD_TDWG_REGIONS is off in settings, these can be loaded with:
+regions.load_tdwg()
+
+Data is as downloaded from:
+http://www.tdwg.org/standards/109
+(Edition 2)
+
+It also uses an ISO index, available from:
+http://www.iso.org/iso/country_codes/iso_3166_code_lists.htm
+"""
+data = [\
+# TDWG level 1:
+('1','Europe',None,'!!WORLD', None),
+('2','Africa',None,'!!WORLD', None),
+('3','Asia-Temperate',None,'!!WORLD', None),
+('4','Asia-Tropical',None,'!!WORLD', None),
+('5','Australasia',None,'!!WORLD', None),
+('6','Pacific',None,'!!WORLD', None),
+('7','Northern America',None,'!!WORLD', None),
+('8','Southern America',None,'!!WORLD', None),
+('9','Antarctic',None,'!!WORLD', None),
+
+# TDWG level 2:
+('10','Northern Europe',None,'1', None),
+('11','Middle Europe',None,'1', None),
+('12','Southwestern Europe',None,'1', None),
+('13','Southeastern Europe',None,'1', None),
+('14','Eastern Europe',None,'1', None),
+('20','Northern Africa',None,'2', None),
+('21','Macaronesia',None,'2', None),
+('22','West Tropical Africa',None,'2', None),
+('23','West-Central Tropical Africa',None,'2', None),
+('24','Northeast Tropical Africa',None,'2', None),
+('25','East Tropical Africa',None,'2', None),
+('26','South Tropical Africa',None,'2', None),
+('27','Southern Africa',None,'2', None),
+('28','Middle Atlantic Ocean',None,'2', None),
+('29','Western Indian Ocean',None,'2', None),
+('30','Siberia',None,'3', None),
+('31','Russian Far East',None,'3', None),
+('32','Middle Asia',None,'3', None),
+('33','Caucasus',None,'3', None),
+('34','Western Asia',None,'3', None),
+('35','Arabian Peninsula',None,'3', None),
+('36','China','CN','3', None),
+('37','Mongolia','MN','3', None),
+('38','Eastern Asia',None,'3', None),
+('40','Indian Subcontinent',None,'4', None),
+('41','Indo-China',None,'4', None),
+('42','Malesia',None,'4', None),
+('43','Papuasia',None,'4', None),
+('50','Australia','AU','5', None),
+('51','New Zealand','NZ','5', None),
+('60','Southwestern Pacific',None,'6', None),
+('61','South-Central Pacific',None,'6', None),
+('62','Northwestern Pacific',None,'6', None),
+('63','North-Central Pacific',None,'6', None),
+('70','Subarctic America',None,'7', None),
+('71','Western Canada',None,'7', None),
+('72','Eastern Canada',None,'7', None),
+('73','Northwestern U.S.A.',None,'7', None),
+('74','North-Central U.S.A.',None,'7', None),
+('75','Northeastern U.S.A.',None,'7', None),
+('76','Southwestern U.S.A.',None,'7', None),
+('77','South-Central U.S.A.',None,'7', None),
+('78','Southeastern U.S.A.',None,'7', None),
+('79','Mexico','MX','7', None),
+('80','Central America',None,'8', None),
+('81','Caribbean',None,'8', None),
+('82','Northern South America',None,'8', None),
+('83','Western South America',None,'8', None),
+('84','Brazil','BR','8', None),
+('85','Southern South America',None,'8', None),
+('90','Subantarctic Islands',None,'9', None),
+('91','Antarctic Continent',None,'9', None),
+
+# TDWG level 3:
+('ABT','Alberta',None,'71', None),
+('AFG','Afghanistan','AF','34', None),
+('AGE','Argentina Northeast',None,'85', None),
+('AGS','Argentina South',None,'85', None),
+('AGW','Argentina Northwest',None,'85', None),
+('ALA','Alabama',None,'78', None),
+('ALB','Albania','AL','13', None),
+('ALD','Aldabra',None,'29', None),
+('ALG','Algeria','DZ','20', None),
+('ALT','Altay',None,'30', None),
+('ALU','Aleutian Is.',None,'70', None),
+('AMU','Amur',None,'31', None),
+('AND','Andaman Is.',None,'41', None),
+('ANG','Angola','AO','26', None),
+('ANT','Antarctica','AQ','91', None),
+('ARI','Arizona',None,'76', None),
+('ARK','Arkansas',None,'78', None),
+('ARU','Aruba','AW','81', None),
+('ASC','Ascension',None,'28', None),
+('ASK','Alaska',None,'70', None),
+('ASP','Amsterdam-St.Paul Is.',None,'90', None),
+('ASS','Assam',None,'40', None),
+('ATP','Antipodean Is.',None,'51', None),
+('AUT','Austria','AT','11', None),
+('AZO','Azores',None,'21', None),
+('BAH','Bahamas','BS','81', None),
+('BAL','Baleares',None,'12', None),
+('BAN','Bangladesh','BD','40', None),
+('BEN','Benin','BJ','22', None),
+('BER','Bermuda','BM','81', None),
+('BGM','Belgium','BE','11', None),
+('BIS','Bismarck Archipelago',None,'43', None),
+('BKN','Burkina',None,'22', None),
+('BLR','Belarus','BY','14', None),
+('BLT','Baltic States',None,'14', None),
+('BLZ','Belize','BZ','80', None),
+('BOL','Bolivia',None,'83', None),
+('BOR','Borneo',None,'42', None),
+('BOT','Botswana','BW','27', None),
+('BOU','Bouvet I.',None,'90', None),
+('BRC','British Columbia',None,'71', None),
+('BRY','Buryatiya',None,'30', None),
+('BUL','Bulgaria','BG','13', None),
+('BUR','Burundi','BI','23', None),
+('BZC','Brazil West-Central',None,'84', None),
+('BZE','Brazil Northeast',None,'84', None),
+('BZL','Brazil Southeast',None,'84', None),
+('BZN','Brazil North',None,'84', None),
+('BZS','Brazil South',None,'84', None),
+('CAB','Cabinda',None,'23', None),
+('CAF','Central African Republic','CF','23', None),
+('CAL','California',None,'76', None),
+('CAY','Cayman Is.',None,'81', None),
+('CBD','Cambodia','KH','41', None),
+('CGS','Chagos Archipelago',None,'29', None),
+('CHA','Chad','TD','24', None),
+('CHC','China South-Central',None,'36', None),
+('CHH','Hainan',None,'36', None),
+('CHI','Inner Mongolia',None,'36', None),
+('CHM','Manchuria',None,'36', None),
+('CHN','China North-Central',None,'36', None),
+('CHQ','Qinghai',None,'36', None),
+('CHS','China Southeast',None,'36', None),
+('CHT','Tibet',None,'36', None),
+('CHX','Xinjiang',None,'36', None),
+('CKI','Cocos (Keeling) Is.',None,'42', None),
+('CLC','Chile Central',None,'85', None),
+('CLM','Colombia','CO','83', None),
+('CLN','Chile North',None,'85', None),
+('CLS','Chile South',None,'85', None),
+('CMN','Cameroon','CM','23', None),
+('CNT','Connecticut',None,'75', None),
+('CNY','Canary Is.',None,'21', None),
+('COL','Colorado',None,'73', None),
+('COM','Comoros','KM','29', None),
+('CON','Congo','CG','23', None),
+('COO','Cook Is.',None,'61', None),
+('COR','Corse',None,'12', None),
+('COS','Costa Rica','CR','80', None),
+('CPI','Central American Pacific Is.',None,'80', None),
+('CPP','Cape Provinces',None,'27', None),
+('CPV','Caprivi Strip',None,'27', None),
+('CRL','Caroline Is.',None,'62', None),
+('CRZ','Crozet Is.',None,'90', None),
+('CTA','Chita',None,'30', None),
+('CTM','Chatham Is.',None,'51', None),
+('CUB','Cuba','CU','81', None),
+('CVI','Cape Verde','CV','21', None),
+('CYP','Cyprus','CY','34', None),
+('CZE','Czechoslovakia',None,'11', None),
+('DEL','Delaware',None,'78', None),
+('DEN','Denmark','DK','10', None),
+('DJI','Djibouti','DJ','24', None),
+('DOM','Dominican Republic','DO','81', None),
+('DSV','Desventurados Is.',None,'85', None),
+('EAI','East Aegean Is.',None,'34', None),
+('EAS','Easter Is.',None,'61', None),
+('ECU','Ecuador','EC','83', None),
+('EGY','Egypt','EG','20', None),
+('EHM','East Himalaya',None,'40', None),
+('ELS','El Salvador','SV','80', None),
+('EQG','Equatorial Guinea','GQ','23', None),
+('ERI','Eritrea','ER','24', None),
+('ETH','Ethiopia','ET','24', None),
+('FAL','Falkland Is.',None,'90', None),
+('FIJ','Fiji','FJ','60', None),
+('FIN','Finland','FI','10', None),
+('FLA','Florida',None,'78', None),
+('FOR','Føroyar',None,'10', None),
+('FRA','France','FR','12', None),
+('FRG','French Guiana','GF','82', None),
+('GAB','Gabon','GA','23', None),
+('GAL','Galápagos',None,'83', None),
+('GAM','Gambia, The',None,'22', None),
+('GEO','Georgia','GE','78', None),
+('GER','Germany','DE','11', None),
+('GGI','Gulf of Guinea Is.',None,'23', None),
+('GHA','Ghana','GH','22', None),
+('GIL','Gilbert Is.',None,'60', None),
+('GNB','Guinea-Bissau','GW','22', None),
+('GNL','Greenland','GL','70', None),
+('GRB','Great Britain',None,'10', None),
+('GRC','Greece','GR','13', None),
+('GST','Gulf States',None,'35', None),
+('GUA','Guatemala','GT','80', None),
+('GUI','Guinea','GN','22', None),
+('GUY','Guyana','GY','82', None),
+('HAI','Haiti','HT','81', None),
+('HAW','Hawaii',None,'63', None),
+('HBI','Howland-Baker Is.',None,'60', None),
+('HMD','Heard-McDonald Is.',None,'90', None),
+('HON','Honduras','HN','80', None),
+('HUN','Hungary','HU','11', None),
+('ICE','Iceland','IS','10', None),
+('IDA','Idaho',None,'73', None),
+('ILL','Illinois',None,'74', None),
+('IND','India','IN','40', None),
+('INI','Indiana',None,'75', None),
+('IOW','Iowa',None,'74', None),
+('IRE','Ireland','IE','10', None),
+('IRK','Irkutsk',None,'30', None),
+('IRN','Iran',None,'34', None),
+('IRQ','Iraq','IQ','34', None),
+('ITA','Italy','IT','13', None),
+('IVO','Ivory Coast',None,'22', None),
+('JAM','Jamaica','JM','81', None),
+('JAP','Japan','JP','38', None),
+('JAW','Jawa',None,'42', None),
+('JNF','Juan Fernández Is.',None,'85', None),
+('KAM','Kamchatka',None,'31', None),
+('KAN','Kansas',None,'74', None),
+('KAZ','Kazakhstan','KZ','32', None),
+('KEG','Kerguelen',None,'90', None),
+('KEN','Kenya','KE','25', None),
+('KER','Kermadec Is.',None,'51', None),
+('KGZ','Kirgizistan',None,'32', None),
+('KHA','Khabarovsk',None,'31', None),
+('KOR','Korea',None,'38', None),
+('KRA','Krasnoyarsk',None,'30', None),
+('KRI','Kriti',None,'13', None),
+('KRY','Krym',None,'14', None),
+('KTY','Kentucky',None,'78', None),
+('KUR','Kuril Is.',None,'31', None),
+('KUW','Kuwait','KW','35', None),
+('KZN','Kazan-retto',None,'38', None),
+('LAB','Labrador',None,'72', None),
+('LAO','Laos',None,'41', None),
+('LBR','Liberia','LR','22', None),
+('LBS','Lebanon-Syria',None,'34', None),
+('LBY','Libya',None,'20', None),
+('LDV','Laccadive Is.',None,'40', None),
+('LEE','Leeward Is.',None,'81', None),
+('LES','Lesotho','LS','27', None),
+('LIN','Line Is.',None,'61', None),
+('LOU','Louisiana',None,'78', None),
+('LSI','Lesser Sunda Is.',None,'42', None),
+('MAG','Magadan',None,'31', None),
+('MAI','Maine',None,'75', None),
+('MAN','Manitoba',None,'71', None),
+('MAQ','Macquarie Is.',None,'90', None),
+('MAS','Masachusettes',None,'75', None),
+('MAU','Mauritius','MU','29', None),
+('MCI','Mozambique Channel Is.',None,'29', None),
+('MCS','Marcus I.',None,'62', None),
+('MDG','Madagascar','MG','29', None),
+('MDR','Madeira',None,'21', None),
+('MDV','Maldives','MV','40', None),
+('MIC','Michigan',None,'75', None),
+('MIN','Minnesota',None,'74', None),
+('MLI','Mali','ML','22', None),
+('MLW','Malawi','MW','26', None),
+('MLY','Malaya',None,'42', None),
+('MNT','Montana',None,'73', None),
+('MOL','Maluku',None,'42', None),
+('MON','Mongolia','MN','37', None),
+('MOR','Morocco','MA','20', None),
+('MOZ','Mozambique','MZ','26', None),
+('MPE','Marion-Prince Edward Is.',None,'90', None),
+('MRN','Marianas',None,'62', None),
+('MRQ','Marquesas',None,'61', None),
+('MRS','Marshall Is.',None,'62', None),
+('MRY','Maryland',None,'78', None),
+('MSI','Mississippi',None,'78', None),
+('MSO','Missouri',None,'74', None),
+('MTN','Mauritania','MR','22', None),
+('MXC','Mexico Central',None,'79', None),
+('MXE','Mexico Northeast',None,'79', None),
+('MXG','Mexico Gulf',None,'79', None),
+('MXI','Mexican Pacific Is.',None,'79', None),
+('MXN','Mexico Northwest',None,'79', None),
+('MXS','Mexico Southwest',None,'79', None),
+('MXT','Mexico Southeast',None,'79', None),
+('MYA','Myanmar','MM','41', None),
+('NAM','Namibia','NA','27', None),
+('NAT','KwaZulu-Natal',None,'27', None),
+('NBR','New Brunswick',None,'72', None),
+('NCA','North Carolina',None,'78', None),
+('NCB','Nicobar Is.',None,'41', None),
+('NCS','North Caucasus',None,'33', None),
+('NDA','North Dakota',None,'74', None),
+('NEB','Nebraska',None,'74', None),
+('NEP','Nepal','NP','40', None),
+('NET','Netherlands','NL','11', None),
+('NEV','Nevada',None,'76', None),
+('NFK','Norfolk Is.',None,'50', None),
+('NFL','Newfoundland',None,'72', None),
+('NGA','Nigeria','NG','22', None),
+('NGR','Niger','NE','22', None),
+('NIC','Nicaragua','NI','80', None),
+('NLA','Netherlands Antilles','AN','81', None),
+('NNS','Nansei-shoto',None,'38', None),
+('NOR','Norway','NO','10', None),
+('NRU','Nauru','NR','60', None),
+('NSC','Nova Scotia',None,'72', None),
+('NSW','New South Wales',None,'50', None),
+('NTA','Northern Territory',None,'50', None),
+('NUE','Niue','NU','60', None),
+('NUN','Nunavut',None,'70', None),
+('NWC','New Caledonia','NC','60', None),
+('NWG','New Guinea',None,'43', None),
+('NWH','New Hampshire',None,'75', None),
+('NWJ','New Jersey',None,'75', None),
+('NWM','New Mexico',None,'77', None),
+('NWT','Northwest Territories',None,'70', None),
+('NWY','New York',None,'75', None),
+('NZN','New Zealand North',None,'51', None),
+('NZS','New Zealand South',None,'51', None),
+('OFS','Free State',None,'27', None),
+('OGA','Ogasawara-shoto',None,'38', None),
+('OHI','Ohio',None,'75', None),
+('OKL','Oklahoma',None,'74', None),
+('OMA','Oman','OM','35', None),
+('ONT','Ontario',None,'72', None),
+('ORE','Oregon',None,'73', None),
+('PAK','Pakistan','PK','40', None),
+('PAL','Palestine',None,'34', None),
+('PAN','Panamá',None,'80', None),
+('PAR','Paraguay','PY','85', None),
+('PEI','Prince Edward I.',None,'72', None),
+('PEN','Pennsylvania',None,'75', None),
+('PER','Peru','PE','83', None),
+('PHI','Philippines','PH','42', None),
+('PHX','Phoenix Is.',None,'60', None),
+('PIT','Pitcairn Is.',None,'61', None),
+('POL','Poland','PL','11', None),
+('POR','Portugal','PT','12', None),
+('PRM','Primorye',None,'31', None),
+('PUE','Puerto Rico','PR','81', None),
+('QLD','Queensland',None,'50', None),
+('QUE','Québec',None,'72', None),
+('REU','Réunion','RE','29', None),
+('RHO','Rhode I.',None,'75', None),
+('ROD','Rodrigues',None,'29', None),
+('ROM','Romania','RO','13', None),
+('RUC','Central European Russia',None,'14', None),
+('RUE','East European Russia',None,'14', None),
+('RUN','North European Russia',None,'14', None),
+('RUS','South European Russia',None,'14', None),
+('RUW','Northwest European Russia',None,'14', None),
+('RWA','Rwanda','RW','23', None),
+('SAK','Sakhalin',None,'31', None),
+('SAM','Samoa','WS','60', None),
+('SAR','Sardegna',None,'12', None),
+('SAS','Saskatchewan',None,'71', None),
+('SAU','Saudi Arabia','SA','35', None),
+('SCA','South Carolina',None,'78', None),
+('SCI','Society Is.',None,'61', None),
+('SCS','South China Sea',None,'41', None),
+('SCZ','Santa Cruz Is.',None,'60', None),
+('SDA','South Dakota',None,'74', None),
+('SEL','Selvagens',None,'21', None),
+('SEN','Senegal','SN','22', None),
+('SEY','Seychelles','SC','29', None),
+('SGE','South Georgia',None,'90', None),
+('SIC','Sicilia',None,'13', None),
+('SIE','Sierra Leone','SL','22', None),
+('SIN','Sinai',None,'34', None),
+('SOA','South Australia',None,'50', None),
+('SOC','Socotra',None,'24', None),
+('SOL','Solomon Is.',None,'43', None),
+('SOM','Somalia','SO','24', None),
+('SPA','Spain','ES','12', None),
+('SRL','Sri Lanka','LK','40', None),
+('SSA','South Sandwich Is.',None,'90', None),
+('STH','St.Helena',None,'28', None),
+('SUD','Sudan','SD','24', None),
+('SUL','Sulawesi',None,'42', None),
+('SUM','Sumatera',None,'42', None),
+('SUR','Suriname','SR','82', None),
+('SVA','Svalbard',None,'10', None),
+('SWC','Southwest Caribbean',None,'81', None),
+('SWE','Sweden','SE','10', None),
+('SWI','Switzerland','CH','11', None),
+('SWZ','Swaziland','SZ','27', None),
+('TAI','Taiwan',None,'38', None),
+('TAN','Tanzania',None,'25', None),
+('TAS','Tasmania',None,'50', None),
+('TCI','Turks-Caicos Is.',None,'81', None),
+('TCS','Transcaucasus',None,'33', None),
+('TDC','Tristan da Cunha',None,'90', None),
+('TEN','Tennessee',None,'78', None),
+('TEX','Texas',None,'77', None),
+('THA','Thailand','TH','41', None),
+('TKM','Turkmenistan','TM','32', None),
+('TOG','Togo','TG','22', None),
+('TOK','Tokelau-Manihiki',None,'60', None),
+('TON','Tonga','TO','60', None),
+('TRT','Trinidad-Tobago',None,'81', None),
+('TUA','Tuamotu',None,'61', None),
+('TUB','Tubuai Is.',None,'61', None),
+('TUE','Turkey-in-Europe',None,'13', None),
+('TUN','Tunisia','TN','20', None),
+('TUR','Turkey','TR','34', None),
+('TUV','Tuvalu','TV','60', None),
+('TVA','Tuva',None,'30', None),
+('TVL','Northern Provinces',None,'27', None),
+('TZK','Tadzhikistan',None,'32', None),
+('UGA','Uganda','UG','25', None),
+('UKR','Ukraine','UA','14', None),
+('URU','Uruguay','UY','85', None),
+('UTA','Utah',None,'76', None),
+('UZB','Uzbekistan','UZ','32', None),
+('VAN','Vanuatu','VU','60', None),
+('VEN','Venezuela',None,'82', None),
+('VER','Vermont',None,'75', None),
+('VIC','Victoria',None,'50', None),
+('VIE','Vietnam',None,'41', None),
+('VNA','Venezuelan Antilles',None,'81', None),
+('VRG','Virginia',None,'78', None),
+('WAK','Wake I.',None,'62', None),
+('WAL','Wallis-Futuna Is.',None,'60', None),
+('WAS','Washington',None,'73', None),
+('WAU','Western Australia',None,'50', None),
+('WDC','District of Columbia',None,'78', None),
+('WHM','West Himalaya',None,'40', None),
+('WIN','Windward Is.',None,'81', None),
+('WIS','Wisconsin',None,'74', None),
+('WSA','Western Sahara','EH','20', None),
+('WSB','West Siberia',None,'30', None),
+('WVA','West Virginia',None,'75', None),
+('WYO','Wyoming',None,'73', None),
+('XMS','Christmas I.',None,'42', None),
+('YAK','Yakutskiya',None,'30', None),
+('YEM','Yemen','YE','35', None),
+('YUG','Yugoslavia',None,'13', None),
+('YUK','Yukon',None,'70', None),
+('ZAI','Zaire',None,'23', None),
+('ZAM','Zambia','ZM','26', None),
+('ZIM','Zimbabwe','ZW','26', None),
+
+# TDWG level 4:
+('ABT-OO',"Alberta",None,'ABT',''),
+('AFG-OO',"Afghanistan",'AF','AFG',''),
+('AGE-BA',"Buenos Aires",None,'AGE',''),
+('AGE-CH',"Chaco",None,'AGE',''),
+('AGE-CN',"Corrientes",None,'AGE',''),
+('AGE-CO',"Córdoba",None,'AGE',''),
+('AGE-DF',"Argentina Distrito Federal",None,'AGE',''),
+('AGE-ER',"Entre Ríos",None,'AGE',''),
+('AGE-FO',"Formosa",None,'AGE',''),
+('AGE-LP',"La Pampa",None,'AGE',''),
+('AGE-MI',"Misiones",None,'AGE',''),
+('AGS-CB',"Chubut",None,'AGS',''),
+('AGS-NE',"Neuquén",None,'AGS',''),
+('AGS-RN',"Rio Negro",None,'AGS',''),
+('AGS-SC',"Santa Cruz",None,'AGS',''),
+('AGS-SF',"Santa Fé",None,'AGS',''),
+('AGS-TF',"Tierra del Fuego (Argentina)",None,'AGS',''),
+('AGW-CA',"Catamarca",None,'AGW',''),
+('AGW-JU',"Jujuy",None,'AGW',''),
+('AGW-LR',"La Rioja",None,'AGW',''),
+('AGW-ME',"Mendoza",None,'AGW',''),
+('AGW-SA',"Salta",None,'AGW',''),
+('AGW-SE',"Santiago del Estero",None,'AGW',''),
+('AGW-SJ',"San Juan",None,'AGW',''),
+('AGW-SL',"San Luis",None,'AGW',''),
+('AGW-TU',"Tucuman",None,'AGW',''),
+('ALA-OO',"Alabama",None,'ALA',''),
+('ALB-OO',"Albania",'AL','ALB',''),
+('ALD-OO',"Aldabra",None,'ALD',''),
+('ALG-OO',"Algeria",'DZ','ALG',''),
+('ALT-OO',"Altay",None,'ALT',''),
+('ALU-OO',"Aleutian Is.",None,'ALU',''),
+('AMU-OO',"Amur",None,'AMU',''),
+('AND-AN',"Andaman Is.",None,'AND',''),
+('AND-CO',"Coco Is.",None,'AND',''),
+('ANG-OO',"Angola",'AO','ANG',''),
+('ANT-OO',"Antarctica",'AQ','ANT',''),
+('ARI-OO',"Arizona",None,'ARI',''),
+('ARK-OO',"Arkansas",None,'ARK',''),
+('ARU-OO',"Aruba",'AW','ARU',''),
+('ASC-OO',"Ascension",None,'ASC',''),
+('ASK-OO',"Alaska",None,'ASK',''),
+('ASP-OO',"Amsterdam-St.Paul Is.",None,'ASP',''),
+('ASS-AS',"Assam",None,'ASS',''),
+('ASS-MA',"Manipur",None,'ASS',''),
+('ASS-ME',"Meghalaya",None,'ASS',''),
+('ASS-MI',"Mizoram",None,'ASS',''),
+('ASS-NA',"Nagaland",None,'ASS',''),
+('ASS-TR',"Tripura",None,'ASS',''),
+('ATP-OO',"Antipodean Is.",None,'ATP',''),
+('AUT-AU',"Austria",'AT','AUT',''),
+('AUT-LI',"Liechtenstein",'LI','AUT',''),
+('AZO-OO',"Açôres",None,'AZO',''),
+('BAH-OO',"Bahamas",'BS','BAH',''),
+('BAL-OO',"Baleares",None,'BAL',''),
+('BAN-OO',"Bangladesh",'BD','BAN',''),
+('BEN-OO',"Benin",'BJ','BEN',''),
+('BER-OO',"Bermuda",'BM','BER',''),
+('BGM-BE',"Belgium",'BE','BGM',''),
+('BGM-LU',"Luxembourg",'LU','BGM',''),
+('BIS-OO',"Bismarck Archipelago",None,'BIS',''),
+('BKN-OO',"Burkina",None,'BKN',''),
+('BLR-OO',"Belarus",'BY','BLR',''),
+('BLT-ES',"Estonia",'EE','BLT',''),
+('BLT-KA',"Kaliningrad",None,'BLT',''),
+('BLT-LA',"Latvia",'LV','BLT',''),
+('BLT-LI',"Lithuania",'LT','BLT',''),
+('BLZ-OO',"Belize",'BZ','BLZ',''),
+('BOL-OO',"Bolivia",None,'BOL',''),
+('BOR-BR',"Brunei",None,'BOR',''),
+('BOR-KA',"Kalimantan",None,'BOR',''),
+('BOR-SB',"Sabah",None,'BOR',''),
+('BOR-SR',"Sarawak",None,'BOR',''),
+('BOT-OO',"Botswana",'BW','BOT',''),
+('BOU-OO',"Bouvet I.",None,'BOU',''),
+('BRC-OO',"British Columbia",None,'BRC',''),
+('BRY-OO',"Buryatiya",None,'BRY',''),
+('BUL-OO',"Bulgaria",'BG','BUL',''),
+('BUR-OO',"Burundi",'BI','BUR',''),
+('BZC-DF',"Brazilia Distrito Federal",None,'BZC',''),
+('BZC-GO',"Goiás",None,'BZC',''),
+('BZC-MS',"Mato Grosso do Sul",None,'BZC',''),
+('BZC-MT',"Mato Grosso",None,'BZC',''),
+('BZE-AL',"Alagoas",None,'BZE',''),
+('BZE-BA',"Bahia",None,'BZE',''),
+('BZE-CE',"Ceará",None,'BZE',''),
+('BZE-FN',"Fernando de Noronha",None,'BZE',''),
+('BZE-MA',"Maranhao",None,'BZE',''),
+('BZE-PB',"Paraíba",None,'BZE',''),
+('BZE-PE',"Pernambuco",None,'BZE',''),
+('BZE-PI',"Piauí",None,'BZE',''),
+('BZE-RN',"Rio Grande do Norte",None,'BZE',''),
+('BZE-SE',"Sergipe",None,'BZE',''),
+('BZL-ES',"Espirito Santo",None,'BZL',''),
+('BZL-MG',"Minas Gerais",None,'BZL',''),
+('BZL-RJ',"Rio de Janeiro",None,'BZL',''),
+('BZL-SP',"São Paulo",None,'BZL',''),
+('BZL-TR',"Trindade",None,'BZL',''),
+('BZN-AC',"Acre",None,'BZN',''),
+('BZN-AM',"Amazonas",None,'BZN',''),
+('BZN-AP',"Amapá",None,'BZN',''),
+('BZN-PA',"Pará",None,'BZN',''),
+('BZN-RM',"Roraima",None,'BZN',''),
+('BZN-RO',"Rondônia",None,'BZN',''),
+('BZN-TO',"Tocantins",None,'BZN',''),
+('BZS-PR',"Paraná",None,'BZS',''),
+('BZS-RS',"Rio Grande do Sul",None,'BZS',''),
+('BZS-SC',"Santa Catarina",None,'BZS',''),
+('CAB-OO',"Cabinda",None,'CAB',''),
+('CAF-OO',"Central African Republic",'CF','CAF',''),
+('CAL-OO',"California",None,'CAL',''),
+('CAY-OO',"Cayman Is.",None,'CAY',''),
+('CBD-OO',"Cambodia",'KH','CBD',''),
+('CGS-OO',"Chagos Archipelago",None,'CGS',''),
+('CHA-OO',"Chad",'TD','CHA',''),
+('CHC-GZ',"Guizhou",None,'CHC',''),
+('CHC-HU',"Hubei",None,'CHC',''),
+('CHC-SC',"Sichuan",None,'CHC',''),
+('CHC-YN',"Yunnan",None,'CHC',''),
+('CHH-OO',"Hainan",None,'CHH',''),
+('CHI-NM',"Nei Mongol",None,'CHI',''),
+('CHI-NX',"Ningxia",None,'CHI',''),
+('CHM-HJ',"Heilongjiang",None,'CHM',''),
+('CHM-JL',"Jilin",None,'CHM',''),
+('CHM-LN',"Liaoning",None,'CHM',''),
+('CHN-BJ',"Beijing",None,'CHN',''),
+('CHN-GS',"Gansu",None,'CHN',''),
+('CHN-HB',"Hebei",None,'CHN',''),
+('CHN-SA',"Shaanxi",None,'CHN',''),
+('CHN-SD',"Shandong",None,'CHN',''),
+('CHN-SX',"Shanxi",None,'CHN',''),
+('CHN-TJ',"Tianjin",None,'CHN',''),
+('CHQ-OO',"Qinghai",None,'CHQ',''),
+('CHS-AH',"Anhui",None,'CHS',''),
+('CHS-FJ',"Fujian",None,'CHS',''),
+('CHS-GD',"Guangdong",None,'CHS',''),
+('CHS-GX',"Guangxi",None,'CHS',''),
+('CHS-HE',"Henan",None,'CHS',''),
+('CHS-HK',"Hong Kong",'HK','CHS',''),
+('CHS-HN',"Hunan",None,'CHS',''),
+('CHS-JS',"Jiangsu",None,'CHS',''),
+('CHS-JX',"Jiangxi",None,'CHS',''),
+('CHS-KI',"Kin-Men",None,'CHS',''),
+('CHS-MA',"Macau",None,'CHS',''),
+('CHS-MP',"Ma-tsu-Pai-chúan",None,'CHS',''),
+('CHS-SH',"Shanghai",None,'CHS',''),
+('CHS-ZJ',"Zhejiang",None,'CHS',''),
+('CHT-OO',"Tibet",None,'CHT','Sube del nivel 4 al nivel 3. El código en el libro es CHT-XI.'),
+('CHX-OO',"Xinjiang",None,'CHX',''),
+('CKI-OO',"Cocos (Keeling) Is.",None,'CKI',''),
+('CLC-BI',"Biobío",None,'CLC',''),
+('CLC-CO',"Coquimbo",None,'CLC',''),
+('CLC-LA',"La Araucania",None,'CLC',''),
+('CLC-MA',"Maule",None,'CLC',''),
+('CLC-OH',"O'Higgins",None,'CLC',''),
+('CLC-SA',"Santiago",None,'CLC',''),
+('CLC-VA',"Valparaíso",None,'CLC',''),
+('CLM-OO',"Colombia",'CO','CLM',''),
+('CLN-AN',"Antofagasta",None,'CLN',''),
+('CLN-AT',"Atacama",None,'CLN',''),
+('CLN-TA',"Tarapaca",None,'CLN',''),
+('CLS-AI',"Aisén",None,'CLS',''),
+('CLS-LL',"Los Lagos",None,'CLS',''),
+('CLS-MG',"Magellanes",None,'CLS',''),
+('CMN-OO',"Cameroon",'CM','CMN',''),
+('CNT-OO',"Connecticut",None,'CNT',''),
+('CNY-OO',"Canary Is.",None,'CNY',''),
+('COL-OO',"Colorado",None,'COL',''),
+('COM-CO',"Comoros",'KM','COM',''),
+('COM-MA',"Mayotte",'YT','COM',''),
+('CON-OO',"Congo",'CG','CON',''),
+('COO-OO',"Cook Is.",None,'COO',''),
+('COR-OO',"Corse",None,'COR',''),
+('COS-OO',"Costa Rica",'CR','COS',''),
+('CPI-CL',"Clipperton I.",None,'CPI',''),
+('CPI-CO',"Cocos I.",None,'CPI',''),
+('CPI-MA',"Malpelo I.",None,'CPI',''),
+('CPP-EC',"Eastern Cape Province",None,'CPP',''),
+('CPP-NC',"Northern Cape Province",None,'CPP',''),
+('CPP-WC',"Western Cape Province",None,'CPP',''),
+('CPV-OO',"Caprivi Strip",None,'CPV',''),
+('CRL-MF',"Micronesia Federated States",None,'CRL',''),
+('CRL-PA',"Palau",'PW','CRL',''),
+('CRZ-OO',"Crozet Is.",None,'CRZ',''),
+('CTA-OO',"Chita",None,'CTA',''),
+('CTM-OO',"Chatham Is.",None,'CTM',''),
+('CUB-OO',"Cuba",'CU','CUB',''),
+('CVI-OO',"Cape Verde",'CV','CVI',''),
+('CYP-OO',"Cyprus",'CY','CYP',''),
+('CZE-CZ',"Czech Republic",'CZ','CZE',''),
+('CZE-SK',"Slovakia",'SK','CZE',''),
+('DEL-OO',"Delaware",None,'DEL',''),
+('DEN-OO',"Denmark",'DK','DEN',''),
+('DJI-OO',"Djibouti",'DJ','DJI',''),
+('DOM-OO',"Dominican Republic",'DO','DOM',''),
+('DSV-OO',"Desventurados Is.",None,'DSV',''),
+('EAI-OO',"East Aegean Is.",None,'EAI',''),
+('EAS-OO',"Easter Is.",None,'EAS',''),
+('ECU-OO',"Ecuador",'EC','ECU',''),
+('EGY-OO',"Egypt",'EG','EGY',''),
+('EHM-AP',"Arunachal Pradesh",None,'EHM',''),
+('EHM-BH',"Bhutan",'BT','EHM',''),
+('EHM-DJ',"Darjiling",None,'EHM',''),
+('EHM-SI',"Sikkim",None,'EHM',''),
+('ELS-OO',"El Salvador",'SV','ELS',''),
+('EQG-OO',"Equatorial Guinea",'GQ','EQG',''),
+('ERI-OO',"Eritrea",'ER','ERI',''),
+('ETH-OO',"Ethiopia",'ET','ETH',''),
+('FAL-OO',"Falkland Is.",None,'FAL',''),
+('FIJ-OO',"Fiji",'FJ','FIJ',''),
+('FIN-OO',"Finland",'FI','FIN',''),
+('FLA-OO',"Florida",None,'FLA',''),
+('FOR-OO',"Føroyar",None,'FOR',''),
+('FRA-CI',"Channel Is.",None,'FRA',''),
+('FRA-FR',"France",'FR','FRA',''),
+('FRA-MO',"Monaco",'MC','FRA',''),
+('FRG-OO',"French Guiana",'GF','FRG',''),
+('GAB-OO',"Gabon",'GA','GAB',''),
+('GAL-OO',"Galápagos",None,'GAL',''),
+('GAM-OO',"Gambia, The",None,'GAM',''),
+('GEO-OO',"Georgia",'GE','GEO',''),
+('GER-OO',"Germany",'DE','GER',''),
+('GGI-AN',"Annobón",None,'GGI',''),
+('GGI-BI',"Bioko",None,'GGI',''),
+('GGI-PR',"Principe",None,'GGI',''),
+('GGI-ST',"São Tomé",None,'GGI',''),
+('GHA-OO',"Ghana",'GH','GHA',''),
+('GIL-OO',"Gilbert Is.",None,'GIL',''),
+('GNB-OO',"Guinea-Bissau",'GW','GNB',''),
+('GNL-OO',"Greenland",'GL','GNL',''),
+('GRB-OO',"Great Britain",None,'GRB',''),
+('GRC-OO',"Greece",'GR','GRC',''),
+('GST-BA',"Bahrain",'BH','GST',''),
+('GST-QA',"Qatar",'QA','GST',''),
+('GST-UA',"United Arab Emirates",'AE','GST',''),
+('GUA-OO',"Guatemala",'GT','GUA',''),
+('GUI-OO',"Guinea",'GN','GUI',''),
+('GUY-OO',"Guyana",'GY','GUY',''),
+('HAI-HA',"Haiti",'HT','HAI',''),
+('HAI-NI',"Navassa I.",None,'HAI',''),
+('HAW-HI',"Hawaiian Is.",None,'HAW',''),
+('HAW-JI',"Johnston I.",None,'HAW',''),
+('HAW-MI',"Midway Is.",None,'HAW',''),
+('HBI-OO',"Howland-Baker Is.",None,'HBI',''),
+('HMD-OO',"Heard-McDonald Is.",None,'HMD',''),
+('HON-OO',"Honduras",'HN','HON',''),
+('HUN-OO',"Hungary",'HU','HUN',''),
+('ICE-OO',"Iceland",'IS','ICE',''),
+('IDA-OO',"Idaho",None,'IDA',''),
+('ILL-OO',"Illinois",None,'ILL',''),
+('IND-AP',"Andhra Pradesh",None,'IND',''),
+('IND-BI',"Bihar",None,'IND',''),
+('IND-CH',"Chandigarh",None,'IND',''),
+('IND-DD',"Dadra-Nagar-Haveli",None,'IND',''),
+('IND-DE',"Delhi",None,'IND',''),
+('IND-DI',"Diu",None,'IND',''),
+('IND-DM',"Daman",None,'IND',''),
+('IND-GO',"Goa",None,'IND',''),
+('IND-GU',"Gujarat",None,'IND',''),
+('IND-HA',"Haryana",None,'IND',''),
+('IND-KE',"Kerala",None,'IND',''),
+('IND-KL',"Karaikal",None,'IND',''),
+('IND-KT',"Karnataka",None,'IND',''),
+('IND-MH',"Mahé",None,'IND',''),
+('IND-MP',"Madhya Pradesh",None,'IND',''),
+('IND-MR',"Maharashtra",None,'IND',''),
+('IND-OR',"Orissa",None,'IND',''),
+('IND-PO',"Pondicherry",None,'IND',''),
+('IND-PU',"Punjab",None,'IND',''),
+('IND-RA',"Rajasthan",None,'IND',''),
+('IND-TN',"Tamil Nadu",None,'IND',''),
+('IND-UP',"Uttar Pradesh",None,'IND',''),
+('IND-WB',"West Bengal",None,'IND',''),
+('IND-YA',"Yanam",None,'IND',''),
+('INI-OO',"Indiana",None,'INI',''),
+('IOW-OO',"Iowa",None,'IOW',''),
+('IRE-IR',"Ireland",'IE','IRE',''),
+('IRE-NI',"Northern Ireland",None,'IRE',''),
+('IRK-OO',"Irkutsk",None,'IRK',''),
+('IRN-OO',"Iran",None,'IRN',''),
+('IRQ-OO',"Iraq",'IQ','IRQ',''),
+('ITA-IT',"Italy",'IT','ITA',''),
+('ITA-SM',"San Marino",'SM','ITA',''),
+('ITA-VC',"Vatican City",None,'ITA',''),
+('IVO-OO',"Ivory Coast",None,'IVO',''),
+('JAM-OO',"Jamaica",'JM','JAM',''),
+('JAP-HK',"Hokkaido",None,'JAP',''),
+('JAP-HN',"Honshu",None,'JAP',''),
+('JAP-KY',"Kyushu",None,'JAP',''),
+('JAP-SH',"Shikoku",None,'JAP',''),
+('JAW-OO',"Jawa",None,'JAW',''),
+('JNF-OO',"Juan Fernández Is.",None,'JNF',''),
+('KAM-OO',"Kamchatka",None,'KAM',''),
+('KAN-OO',"Kansas",None,'KAN',''),
+('KAZ-OO',"Kazakhstan",'KZ','KAZ',''),
+('KEG-OO',"Kerguelen",None,'KEG',''),
+('KEN-OO',"Kenya",'KE','KEN',''),
+('KER-OO',"Kermadec Is.",None,'KER',''),
+('KGZ-OO',"Kirgizistan",None,'KGZ',''),
+('KHA-OO',"Khabarovsk",None,'KHA',''),
+('KOR-NK',"North Korea",None,'KOR',''),
+('KOR-SK',"South Korea",None,'KOR',''),
+('KRA-OO',"Krasnoyarsk",None,'KRA',''),
+('KRI-OO',"Kriti",None,'KRI',''),
+('KRY-OO',"Krym",None,'KRY',''),
+('KTY-OO',"Kentucky",None,'KTY',''),
+('KUR-OO',"Kuril Is.",None,'KUR',''),
+('KUW-OO',"Kuwait",'KW','KUW',''),
+('KZN-OO',"Kazan-retto",None,'KZN',''),
+('LAB-OO',"Labrador",None,'LAB',''),
+('LAO-OO',"Laos",None,'LAO',''),
+('LBR-OO',"Liberia",'LR','LBR',''),
+('LBS-LB',"Lebanon",'LB','LBS',''),
+('LBS-SY',"Syria",None,'LBS',''),
+('LBY-OO',"Libya",None,'LBY',''),
+('LDV-OO',"Laccadive Is.",None,'LDV',''),
+('LEE-AB',"Antigua-Barbuda",None,'LEE',''),
+('LEE-AG',"Anguilla",'AI','LEE',''),
+('LEE-AV',"Aves I.",None,'LEE',''),
+('LEE-BV',"British Virgin Is.",None,'LEE',''),
+('LEE-GU',"Guadeloupe",'GP','LEE',''),
+('LEE-MO',"Montserrat",'MS','LEE',''),
+('LEE-NL',"Netherlands Leeward Is.",None,'LEE',''),
+('LEE-SK',"St.Kitts-Nevis",None,'LEE',''),
+('LEE-SM',"St.Martin-St.Barthélémy",None,'LEE',''),
+('LEE-VI',"Virgin Is.",None,'LEE',''),
+('LES-OO',"Lesotho",'LS','LES',''),
+('LIN-KI',"Kiribati Line Is.",None,'LIN',''),
+('LIN-US',"U.S. Line Is.",None,'LIN',''),
+('LOU-OO',"Louisiana",None,'LOU',''),
+('LSI-BA',"Bali",None,'LSI',''),
+('LSI-ET',"East Timor",None,'LSI',''),
+('LSI-LS',"Lesser Sunda Is.",None,'LSI',''),
+('MAG-OO',"Magadan",None,'MAG',''),
+('MAI-OO',"Maine",None,'MAI',''),
+('MAN-OO',"Manitoba",None,'MAN',''),
+('MAQ-OO',"Macquarie Is.",None,'MAQ',''),
+('MAS-OO',"Masachusettes",None,'MAS',''),
+('MAU-OO',"Mauritius",'MU','MAU',''),
+('MCI-OO',"Mozambique Channel Is.",None,'MCI',''),
+('MCS-OO',"Marcus I.",None,'MCS',''),
+('MDG-OO',"Madagascar",'MG','MDG',''),
+('MDR-OO',"Madeira",None,'MDR',''),
+('MDV-OO',"Maldives",'MV','MDV',''),
+('MIC-OO',"Michigan",None,'MIC',''),
+('MIN-OO',"Minnesota",None,'MIN',''),
+('MLI-OO',"Mali",'ML','MLI',''),
+('MLW-OO',"Malawi",'MW','MLW',''),
+('MLY-PM',"Peninsular Malaysia",None,'MLY',''),
+('MLY-SI',"Singapore",'SG','MLY',''),
+('MNT-OO',"Montana",None,'MNT',''),
+('MOL-OO',"Maluku",None,'MOL',''),
+('MON-OO',"Mongolia",'MN','MON',''),
+('MOR-MO',"Morocco",'MA','MOR',''),
+('MOR-SP',"Spanish North African Territories",None,'MOR',''),
+('MOZ-OO',"Mozambique",'MZ','MOZ',''),
+('MPE-OO',"Marion-Prince Edward Is.",None,'MPE',''),
+('MRN-GU',"Guam",'GU','MRN',''),
+('MRN-NM',"Northern Marianas",None,'MRN',''),
+('MRQ-OO',"Marquesas",None,'MRQ',''),
+('MRS-OO',"Marshall Is.",None,'MRS',''),
+('MRY-OO',"Maryland",None,'MRY',''),
+('MSI-OO',"Mississippi",None,'MSI',''),
+('MSO-OO',"Missouri",None,'MSO',''),
+('MTN-OO',"Mauritania",'MR','MTN',''),
+('MXC-DF',"Mexico Distrito Federal",None,'MXC',''),
+('MXC-ME',"México State",None,'MXC',''),
+('MXC-MO',"Morelos",None,'MXC',''),
+('MXC-PU',"Puebla",None,'MXC',''),
+('MXC-TL',"Tlaxcala",None,'MXC',''),
+('MXE-AG',"Aguascalientes",None,'MXE',''),
+('MXE-CO',"Coahuila",None,'MXE',''),
+('MXE-CU',"Chihuahua",None,'MXE',''),
+('MXE-DU',"Durango",None,'MXE',''),
+('MXE-GU',"Guanajuato",None,'MXE',''),
+('MXE-HI',"Hidalgo",None,'MXE',''),
+('MXE-NL',"Nuevo León",None,'MXE',''),
+('MXE-QU',"Querétaro",None,'MXE',''),
+('MXE-SL',"San Luis Potosí",None,'MXE',''),
+('MXE-TA',"Tamaulipas",None,'MXE',''),
+('MXE-ZA',"Zacatecas",None,'MXE',''),
+('MXG-VC',"Veracruz",None,'MXG',''),
+('MXI-GU',"Guadalupe I.",None,'MXI',''),
+('MXI-RA',"Rocas Alijos",None,'MXI',''),
+('MXI-RG',"Revillagigedo Is.",None,'MXI',''),
+('MXN-BC',"Baja California",None,'MXN',''),
+('MXN-BS',"Baja California Sur",None,'MXN',''),
+('MXN-SI',"Sinaloa",None,'MXN',''),
+('MXN-SO',"Sonora",None,'MXN',''),
+('MXS-CL',"Colima",None,'MXS',''),
+('MXS-GR',"Guerrero",None,'MXS',''),
+('MXS-JA',"Jalisco",None,'MXS',''),
+('MXS-MI',"Michoacán",None,'MXS',''),
+('MXS-NA',"Nayarit",None,'MXS',''),
+('MXS-OA',"Oaxaca",None,'MXS',''),
+('MXT-CA',"Campeche",None,'MXT',''),
+('MXT-CI',"Chiapas",None,'MXT',''),
+('MXT-QR',"Quintana Roo",None,'MXT',''),
+('MXT-TB',"Tabasco",None,'MXT',''),
+('MXT-YU',"Yucatán",None,'MXT',''),
+('MYA-OO',"Myanmar",'MM','MYA',''),
+('NAM-OO',"Namibia",'NA','NAM',''),
+('NAT-OO',"KwaZulu-Natal",None,'NAT',''),
+('NBR-OO',"New Brunswick",None,'NBR',''),
+('NCA-OO',"North Carolina",None,'NCA',''),
+('NCB-OO',"Nicobar Is.",None,'NCB',''),
+('NCS-DA',"Dagestan",None,'NCS',''),
+('NCS-KB',"Kabardino-Balkariya",None,'NCS',''),
+('NCS-KC',"Karacheyevo-Cherkessiya",None,'NCS',''),
+('NCS-KR',"Krasnodar",None,'NCS',''),
+('NCS-SO',"Severo-Osetiya",None,'NCS',''),
+('NCS-ST',"Stavropol",None,'NCS',''),
+('NDA-OO',"North Dakota",None,'NDA',''),
+('NEB-OO',"Nebraska",None,'NEB',''),
+('NEP-OO',"Nepal",'NP','NEP',''),
+('NET-OO',"Netherlands",'NL','NET',''),
+('NEV-OO',"Nevada",None,'NEV',''),
+('NFK-LH',"Lord Howe I.",None,'NFK',''),
+('NFK-NI',"Norfolk I.",None,'NFK',''),
+('NFL-NE',"Newfoundland",None,'NFL',''),
+('NFL-SP',"St.Pierre-Miquelon",None,'NFL',''),
+('NGA-OO',"Nigeria",'NG','NGA',''),
+('NGR-OO',"Niger",'NE','NGR',''),
+('NIC-OO',"Nicaragua",'NI','NIC',''),
+('NLA-BO',"Bonaire",None,'NLA',''),
+('NLA-CU',"Curaçao",None,'NLA',''),
+('NNS-OO',"Nansei-shoto",None,'NNS',''),
+('NOR-OO',"Norway",'NO','NOR',''),
+('NRU-OO',"Nauru",'NR','NRU',''),
+('NSC-OO',"Nova Scotia",None,'NSC',''),
+('NSW-CT',"Australian Capital Territory",None,'NSW',''),
+('NSW-NS',"New South Wales",None,'NSW',''),
+('NTA-OO',"Northern Territory",None,'NTA',''),
+('NUE-OO',"Niue",'NU','NUE',''),
+('NUN-OO',"Nunavut",None,'NUN',''),
+('NWC-OO',"New Caledonia",'NC','NWC',''),
+('NWG-IJ',"Irian Jaya",None,'NWG',''),
+('NWG-PN',"Papua New Guinea",'PG','NWG',''),
+('NWH-OO',"New Hampshire",None,'NWH',''),
+('NWJ-OO',"New Jersey",None,'NWJ',''),
+('NWM-OO',"New Mexico",None,'NWM',''),
+('NWT-OO',"Northwest Territories",None,'NWT',''),
+('NWY-OO',"New York",None,'NWY',''),
+('NZN-OO',"New Zealand North",None,'NZN',''),
+('NZS-OO',"New Zealand South",None,'NZS',''),
+('OFS-OO',"Free State",None,'OFS',''),
+('OGA-OO',"Ogasawara-shoto",None,'OGA',''),
+('OHI-OO',"Ohio",None,'OHI',''),
+('OKL-OO',"Oklahoma",None,'OKL',''),
+('OMA-OO',"Oman",'OM','OMA',''),
+('ONT-OO',"Ontario",None,'ONT',''),
+('ORE-OO',"Oregon",None,'ORE',''),
+('PAK-OO',"Pakistan",'PK','PAK',''),
+('PAL-IS',"Israel",'IL','PAL',''),
+('PAL-JO',"Jordan",'JO','PAL',''),
+('PAN-OO',"Panamá",None,'PAN',''),
+('PAR-OO',"Paraguay",'PY','PAR',''),
+('PEI-OO',"Prince Edward I.",None,'PEI',''),
+('PEN-OO',"Pennsylvania",None,'PEN',''),
+('PER-OO',"Peru",'PE','PER',''),
+('PHI-OO',"Philippines",'PH','PHI',''),
+('PHX-OO',"Phoenix Is.",None,'PHX',''),
+('PIT-OO',"Pitcairn Is.",None,'PIT',''),
+('POL-OO',"Poland",'PL','POL',''),
+('POR-OO',"Portugal",'PT','POR',''),
+('PRM-OO',"Primorye",None,'PRM',''),
+('PUE-OO',"Puerto Rico",'PR','PUE',''),
+('QLD-CS',"Coral Sea Is. Territory",None,'QLD',''),
+('QLD-QU',"Queensland",None,'QLD',''),
+('QUE-OO',"Québec",None,'QUE',''),
+('REU-OO',"Réunion",'RE','REU',''),
+('RHO-OO',"Rhode I.",None,'RHO',''),
+('ROD-OO',"Rodrigues",None,'ROD',''),
+('ROM-OO',"Romania",'RO','ROM',''),
+('RUC-OO',"Central European Russia",None,'RUC',''),
+('RUE-OO',"East European Russia",None,'RUE',''),
+('RUN-OO',"North European Russia",None,'RUN',''),
+('RUS-OO',"South European Russia",None,'RUS',''),
+('RUW-OO',"Northwest European Russia",None,'RUW',''),
+('RWA-OO',"Rwanda",'RW','RWA',''),
+('SAK-OO',"Sakhalin",None,'SAK',''),
+('SAM-AS',"American Samoa",'AS','SAM',''),
+('SAM-WS',"Samoa",'WS','SAM','Western Samoa'),
+('SAR-OO',"Sardegna",None,'SAR',''),
+('SAS-OO',"Saskatchewan",None,'SAS',''),
+('SAU-OO',"Saudi Arabia",'SA','SAU',''),
+('SCA-OO',"South Carolina",None,'SCA',''),
+('SCI-OO',"Society Is.",None,'SCI',''),
+('SCS-PI',"Paracel Is.",None,'SCS',''),
+('SCS-SI',"Spratly Is.",None,'SCS',''),
+('SCZ-OO',"Santa Cruz Is.",None,'SCZ',''),
+('SDA-OO',"South Dakota",None,'SDA',''),
+('SEL-OO',"Selvagens",None,'SEL',''),
+('SEN-OO',"Senegal",'SN','SEN',''),
+('SEY-OO',"Seychelles",'SC','SEY',''),
+('SGE-OO',"South Georgia",None,'SGE',''),
+('SIC-MA',"Malta",'MT','SIC',''),
+('SIC-SI',"Sicilia",None,'SIC',''),
+('SIE-OO',"Sierra Leone",'SL','SIE',''),
+('SIN-OO',"Sinai",None,'SIN',''),
+('SOA-OO',"South Australia",None,'SOA',''),
+('SOC-OO',"Socotra",None,'SOC',''),
+('SOL-NO',"North Solomons",None,'SOL',''),
+('SOL-SO',"South Solomons",None,'SOL',''),
+('SOM-OO',"Somalia",'SO','SOM',''),
+('SPA-AN',"Andorra",'AD','SPA',''),
+('SPA-GI',"Gilbraltar",None,'SPA',''),
+('SPA-SP',"Spain",'ES','SPA',''),
+('SRL-OO',"Sri Lanka",'LK','SRL',''),
+('SSA-OO',"South Sandwich Is.",None,'SSA',''),
+('STH-OO',"St.Helena",None,'STH',''),
+('SUD-OO',"Sudan",'SD','SUD',''),
+('SUL-OO',"Sulawesi",None,'SUL',''),
+('SUM-OO',"Sumatera",None,'SUM',''),
+('SUR-OO',"Surinam",None,'SUR',''),
+('SVA-OO',"Svalbard",None,'SVA',''),
+('SWC-CC',"Colombian Caribbean Is.",None,'SWC',''),
+('SWC-HC',"Honduran Caribbean Is.",None,'SWC',''),
+('SWC-NC',"Nicaraguan Caribbean Is.",None,'SWC',''),
+('SWE-OO',"Sweden",'SE','SWE',''),
+('SWI-OO',"Switzerland",'CH','SWI',''),
+('SWZ-OO',"Swaziland",'SZ','SWZ',''),
+('TAI-OO',"Taiwan",None,'TAI',''),
+('TAN-OO',"Tanzania",None,'TAN',''),
+('TAS-OO',"Tasmania",None,'TAS',''),
+('TCI-OO',"Turks-Caicos Is.",None,'TCI',''),
+('TCS-AB',"Abkhaziya",None,'TCS',''),
+('TCS-AD',"Adzhariya",None,'TCS',''),
+('TCS-AR',"Armenia",'AM','TCS',''),
+('TCS-AZ',"Azerbaijan",'AZ','TCS',''),
+('TCS-GR',"Georgia",'GE','TCS',''),
+('TCS-NA',"Nakhichevan",None,'TCS',''),
+('TCS-NK',"Nagorno Karabakh",None,'TCS',''),
+('TDC-OO',"Tristan da Cunha",None,'TDC',''),
+('TEN-OO',"Tennessee",None,'TEN',''),
+('TEX-OO',"Texas",None,'TEX',''),
+('THA-OO',"Thailand",'TH','THA',''),
+('TKM-OO',"Turkmenistan",'TM','TKM',''),
+('TOG-OO',"Togo",'TG','TOG',''),
+('TOK-MA',"Manihiki Is.",None,'TOK',''),
+('TOK-SW',"Swains I.",None,'TOK',''),
+('TOK-TO',"Tokelau",'TK','TOK',''),
+('TON-OO',"Tonga",'TO','TON',''),
+('TRT-OO',"Trinidad-Tobago",None,'TRT',''),
+('TUA-OO',"Tuamotu",None,'TUA',''),
+('TUB-OO',"Tubuai Is.",None,'TUB',''),
+('TUE-OO',"Turkey-in-Europe",None,'TUE',''),
+('TUN-OO',"Tunisia",'TN','TUN',''),
+('TUR-OO',"Turkey",'TR','TUR',''),
+('TUV-OO',"Tuvalu",'TV','TUV',''),
+('TVA-OO',"Tuva",None,'TVA',''),
+('TVL-GA',"Gauteng",None,'TVL',''),
+('TVL-MP',"Mpumalanga",None,'TVL',''),
+('TVL-NP',"Northern Province",None,'TVL',''),
+('TVL-NW',"North-West Province",None,'TVL',''),
+('TZK-OO',"Tadzhikistan",None,'TZK',''),
+('UGA-OO',"Uganda",'UG','UGA',''),
+('UKR-MO',"Moldova",None,'UKR',''),
+('UKR-UK',"Ukraine",'UA','UKR',''),
+('URU-OO',"Uruguay",'UY','URU',''),
+('UTA-OO',"Utah",None,'UTA',''),
+('UZB-OO',"Uzbekistan",'UZ','UZB',''),
+('VAN-OO',"Vanuatu",'VU','VAN',''),
+('VEN-OO',"Venezuela",None,'VEN',''),
+('VER-OO',"Vermont",None,'VER',''),
+('VIC-OO',"Victoria",None,'VIC',''),
+('VIE-OO',"Vietnam",None,'VIE',''),
+('VNA-OO',"Venezuelan Antilles",None,'VNA',''),
+('VRG-OO',"Virginia",None,'VRG',''),
+('WAK-OO',"Wake I.",None,'WAK',''),
+('WAL-OO',"Wallis-Futuna Is.",None,'WAL',''),
+('WAS-OO',"Washington",None,'WAS',''),
+('WAU-AC',"Ashmore-Cartier Is.",None,'WAU',''),
+('WAU-WA',"Western Australia",None,'WAU',''),
+('WDC-OO',"District of Columbia",None,'WDC',''),
+('WHM-HP',"Himachal Pradesh",None,'WHM',''),
+('WHM-JK',"Jammu-Kashmir",None,'WHM',''),
+('WHM-UT',"Uttaranchal",None,'WHM',''),
+('WIN-BA',"Barbados",'BB','WIN',''),
+('WIN-DO',"Dominica",'DM','WIN',''),
+('WIN-GR',"Grenada",'GD','WIN',''),
+('WIN-MA',"Martinique",'MQ','WIN',''),
+('WIN-SL',"St.Lucia",None,'WIN',''),
+('WIN-SV',"St.Vincent",None,'WIN',''),
+('WIS-OO',"Wisconsin",None,'WIS',''),
+('WSA-OO',"Western Sahara",'EH','WSA',''),
+('WSB-OO',"West Siberia",None,'WSB',''),
+('WVA-OO',"West Virginia",None,'WVA',''),
+('WYO-OO',"Wyoming",None,'WYO',''),
+('XMS-OO',"Christmas I.",None,'XMS',''),
+('YAK-OO',"Yakutskiya",None,'YAK',''),
+('YEM-NY',"North Yemen",None,'YEM',''),
+('YEM-SY',"South Yemen",None,'YEM',''),
+('YUG-BH',"Bosnia-Herzegovina",None,'YUG',''),
+('YUG-CR',"Croatia",'HR','YUG',''),
+('YUG-KO',"Kosovo",None,'YUG',''),
+('YUG-MA',"Macedonia",None,'YUG',''),
+('YUG-MN',"Montenegro",'ME','YUG',''),
+('YUG-SE',"Serbia",'RS','YUG',''),
+('YUG-SL',"Slovenia",'SI','YUG',''),
+('YUK-OO',"Yukon",None,'YUK',''),
+('ZAI-OO',"Zaire",None,'ZAI',''),
+('ZAM-OO',"Zambia",'ZM','ZAM',''),
+('ZIM-OO',"Zimbabwe",'ZW','ZIM',''),
+('IND-JK',"Jharkhand",None,'IND',''),
+('IND-CT',"Chattisgarh",None,'IND',''),
+('NCS-CH',"Chechnya",None,'NCS','Una de las partes en que se divide Checheno-Ingushetiya'),
+('NCS-IN',"Ingushetiya",None,'NCS','Una de las partes en que se divide Checheno-Ingushetiya'),
+('CHC-CQ',"Chongqing",None,'CHC','Anteriormente parte de Sichuan'),
+]
+
+extra_names = {"Kyrgyzstan":"Kirgizistan",
+"Russia": "Russian Federation",
+"Macao": "Macau",
+"Panama": "Panamá",
+"Burkina Faso": "Burkina",
+"Gambia": "Gambia, The",
+"Côte d'Ivoire": "Ivory Coast",
+"Trinidad and Tobago": "Trinidad-Tobago",
+"Antigua and Barbuda": "Antigua-Barbuda",
+"Tajikstan": "Tadzhikistan",
+"Democratic Republic of the Congo": "Zaire"}
+
+extra_ISO = {"VE": "Venezuela",
+"TZ": "Tanzania",
+"TW": "Taiwan",
+"LY": "Libya",
+"IR": "Iran",
+"KR": "South Korea",
+"KP": "North Korea",
+"LA": "Laos",
+"FK": "Falkland Is.",
+"BO": "Bolivia",
+"SJ": "Svalbard",
+"BA": "Bosnia-Herzegovina",
+"MK": "Macedonia",
+"SY": "Syria",
+"MD": "Moldova",
+"BN": "Brunei",
+"VN": "Vietnam",
+"KG": "Kirgizistan",
+"MO": "Macau",
+"PA": "Panamá",
+"BF": "Burkina",
+"GM": "Gambia, The",
+"CI": "Ivory Coast",
+"TT": "Trinidad-Tobago",
+"AG": "Antigua-Barbuda",
+"TJ": "Tadzhikistan",
+"CD": "Zaire",
+"GB": "United Kingdom"}
+
+extra_countries = [\
+("Russian Federation", None, ["RUC","RUE","RUN","RUS","RUW","NCS","30","31"]),
+("Turkey", None, ["TUE","TUR"]),
+("India", "40", ["IND","WHM","EHM-SI","EHM-DJ","EHM-AP","ASS","LDV"]),
+("United Kingdom", "10", ["GRB","IRE-NI"]),
+# The US here is only the "lower 48"--excluding Alaska and Hawai'i
+("United States", "7", ["78","75","74","77","76","73"]),
+("Canada", "7", ["71","72","NWT","YUK","NUN"]),
+("Chile", "85", ["CLC","CLN","CLS"]),
+("Argentina", "85", ["AGE","AGW","AGS"]),
+("South Africa", "27", ["TVL","CPP","OFS","NAT"]),
+("Malaysia", "42",  ["MLY-PM","BOR-SB","BOR-SR"]),
+("Indonesia", "4", ["LSI-BA","LSI-LS","BOR-KA","SUL","JAW",
+                            "SUM","MOL","NWG-IJ"]),
+]
+
+tdwg_by_level = [None, {'1', '3', '2', '5', '4', '7', '6', '9', '8'},
+{'42', '43', '60', '61', '62', '63', '82', '83', '80', '81', '84', '85', '24', '25', '26', '27', '20', '21', '22', '23', '28', '29', '40', '41', '51', '77', '76', '75', '38', '73', '72', '71', '70', '91', '90', '79', '78', '11', '10', '13', '12', '14', '33', '32', '31', '30', '37', '36', '35', '34', '74', '50'},
+{'CPI', 'MNT', 'AGE', 'SIC', 'YUK', 'SIE', 'CPP', 'AGS', 'SIN', 'CPV', 'TAS', 'SPA', 'TAN', 'TAI', 'VAN', 'SCZ', 'DJI', 'GIL', 'FIN', 'MAQ', 'MAS', 'LAO', 'MAU', 'NWH', 'LAB', 'JNF', 'MAG', 'ALG', 'MAI', 'MAN', 'CMN', 'GUA', 'BEN', 'GUI', 'AGW', 'BER', 'GUY', 'HUN', 'LSI', 'YUG', 'BLZ', 'DSV', 'BLT', 'NFL', 'NFK', 'BLR', 'GRB', 'GRC', 'RWA', 'ALU', 'CBD', 'MXT', 'MXS', 'MXN', 'INI', 'MXI', 'IND', 'MXG', 'MXE', 'MXC', 'NOR', 'BZS', 'DOM', 'REU', 'BZE', 'BZC', 'CTA', 'CTM', 'BZL', 'WHM', 'MDG', 'MDR', 'GGI', 'VER', 'AUT', 'VEN', 'PUE', 'ALD', 'ALB', 'ALA', 'QUE', 'NTA', 'ALT', 'ORE', 'CAY', 'LOU', 'UKR', 'TOK', 'TON', 'CAL', 'BAN', 'CAB', 'BAL', 'KOR', 'TOG', 'BAH', 'CAF', 'ERI', 'ONT', 'NZS', 'KTY', 'STH', 'ABT', 'NZN', 'NCS', 'NCA', 'QLD', 'OGA', 'EGY', 'MIN', 'MIC', 'FIJ', 'GHA', 'SAK', 'LBS', 'EHM', 'SAM', 'LBY', 'EQG', 'SAS', 'SAR', 'SAU', 'CHA', 'CHC', 'MRY', 'CHH', 'JAW', 'CHM', 'CHN', 'MRS', 'CHQ', 'MRN', 'CHS', 'CHT', 'CHX', 'ZIM', 'VIC', 'VIE', 'KAN', 'KAM', 'RHO', 'KAZ', 'NGA', 'NGR', 'UGA', 'TKM', 'NLA', 'HMD', 'RUC', 'AFG', 'SSA', 'CZE', 'SCA', 'ATP', 'WYO', 'ASS', 'ASC', 'ASP', 'SEY', 'NUN', 'ECU', 'ASK', 'SEN', 'SEL', 'CLM', 'CLN', 'FRG', 'CLC', 'YAK', 'CLS', 'KEN', 'OMA', 'NUE', 'KEG', 'TUR', 'TUV', 'ITA', 'TUN', 'TUA', 'TUB', 'TUE', 'SWI', 'SWC', 'SWE', 'FRA', 'SWZ', 'CYP', 'POR', 'POL', 'BIS', 'MLI', 'MLW', 'MLY', 'NCB', 'MCI', 'MCS', 'NRU', 'PAR', 'CKI', 'BGM', 'PAK', 'PAL', 'PAN', 'VNA', 'TZK', 'LIN', 'HAI', 'OFS', 'THA', 'HAW', 'PHI', 'ZAM', 'YEM', 'ZAI', 'NIC', 'PHX', 'WIN', 'CRZ', 'CRL', 'GER', 'BUR', 'TCS', 'LDV', 'BUL', 'TCI', 'GEO', 'FOR', 'LBR', 'AND', 'MOZ', 'ANG', 'MOR', 'KER', 'ANT', 'PRM', 'MON', 'MOL', 'COS', 'COR', 'ILL', 'PER', 'PEN', 'PEI', 'ETH', 'COM', 'COL', 'COO', 'CON', 'TVL', 'VRG', 'TVA', 'KRY', 'WAK', 'NDA', 'SRL', 'KRI', 'WAU', 'KRA', 'WAS', 'XMS', 'RUN', 'TDC', 'PIT', 'RUE', 'RUS', 'RUW', 'SCS', 'WSA', 'WSB', 'GNB', 'CVI', 'GNL', 'SOA', 'SOC', 'NSC', 'SOM', 'SOL', 'GAM', 'GAL', 'FAL', 'CHI', 'GAB', 'NSW', 'UTA', 'IRQ', 'MRQ', 'IRK', 'MTN', 'JAP', 'IRN', 'IRE', 'ARU', 'URU', 'OKL', 'JAM', 'SDA', 'ARI', 'ARK', 'WDC', 'HBI', 'GST', 'BOR', 'BOT', 'BOU', 'NAM', 'BOL', 'NAT', 'OHI', 'IOW', 'MYA', 'KHA', 'NNS', 'SVA', 'DEL', 'DEN', 'BZN', 'FLA', 'NWT', 'SCI', 'ROM', 'ROD', 'NWY', 'NWG', 'NWC', 'NWM', 'WVA', 'AMU', 'NWJ', 'TRT', 'MPE', 'IVO', 'SUD', 'KUW', 'SUM', 'SUL', 'NEB', 'KUR', 'SUR', 'NEV', 'NET', 'NEP', 'IDA', 'TEN', 'NBR', 'BKN', 'TEX', 'CGS', 'CUB', 'ELS', 'LEE', 'BRY', 'MDV', 'LES', 'WIS', 'KZN', 'AZO', 'MSO', 'WAL', 'MSI', 'EAI', 'UZB', 'EAS', 'SGE', 'CNT', 'HON', 'BRC', 'ICE', 'CNY', 'KGZ'},
+{'ASS-NA', 'ALB-OO', 'ARK-OO', 'LEE-BV', 'ILL-OO', 'TCS-GR', 'MXT-CA', 'AGW-JU', 'BOL-OO', 'TOG-OO', 'CLS-MG', 'AFG-OO', 'MLY-SI', 'TOK-TO', 'EHM-BH', 'CPI-CL', 'CPI-CO', 'FIJ-OO', 'MAI-OO', 'AGS-NE', 'TAN-OO', 'NGA-OO', 'GAL-OO', 'ALG-OO', 'HAW-JI', 'SDA-OO', 'TDC-OO', 'NCS-CH', 'ELS-OO', 'UKR-MO', 'MAG-OO', 'CHM-LN', 'CLC-BI', 'WHM-UT', 'IND-JK', 'AGS-RN', 'SUR-OO', 'ECU-OO', 'SAS-OO', 'ARI-OO', 'CHN-GS', 'LES-OO', 'COO-OO', 'MXE-AG', 'BZN-PA', 'ASC-OO', 'BZS-SC', 'MXS-NA', 'SWC-HC', 'VAN-OO', 'BLT-ES', 'RWA-OO', 'CZE-CZ', 'IND-TN', 'SPA-AN', 'SEY-OO', 'IND-KT', 'CLN-TA', 'MXE-SL', 'AGW-CA', 'CMN-OO', 'ZIM-OO', 'CHS-GX', 'BLT-LI', 'CHS-GD', 'MCS-OO', 'NWG-IJ', 'BLT-LA', 'CHC-HU', 'IRK-OO', 'SIC-SI', 'TUN-OO', 'BZE-RN', 'OFS-OO', 'TOK-SW', 'SPA-SP', 'SCI-OO', 'TUB-OO', 'CHA-OO', 'CLS-AI', 'AGE-DF', 'AMU-OO', 'EAS-OO', 'NWT-OO', 'GST-QA', 'MRN-GU', 'IND-MH', 'SUM-OO', 'SAU-OO', 'FRA-CI', 'MXE-HI', 'RUN-OO', 'IND-MP', 'IND-MR', 'TVL-GA', 'WAL-OO', 'NIC-OO', 'VIE-OO', 'INI-OO', 'ASS-AS', 'YUG-SE', 'MXS-OA', 'FLA-OO', 'YUG-SL', 'ITA-VC', 'KUR-OO', 'CRZ-OO', 'AUT-LI', 'GHA-OO', 'KRY-OO', 'SCS-SI', 'CHM-HJ', 'MXE-ZA', 'LEE-SM', 'XMS-OO', 'LEE-SK', 'CPV-OO', 'CHS-ZJ', 'TCI-OO', 'BLT-KA', 'BLR-OO', 'VEN-OO', 'MXC-TL', 'MXS-JA', 'EHM-SI', 'FRG-OO', 'BZN-TO', 'LEE-AV', 'IND-PO', 'CNT-OO', 'CAF-OO', 'LEE-AB', 'COR-OO', 'LEE-AG', 'IND-PU', 'HAI-NI', 'STH-OO', 'KRA-OO', 'BZL-MG', 'ANT-OO', 'WAU-WA', 'LBS-LB', 'SUL-OO', 'IND-BI', 'IRE-NI', 'MXG-VC', 'KAZ-OO', 'EHM-AP', 'CLC-SA', 'DEN-OO', 'BZL-TR', 'MPE-OO', 'BAH-OO', 'BZN-AP', 'LAO-OO', 'BZN-AM', 'MRS-OO', 'BZN-AC', 'ARU-OO', 'BUL-OO', 'CLC-MA', 'BGM-BE', 'JAP-HN', 'IRQ-OO', 'JAP-HK', 'MOR-MO', 'OKL-OO', 'TUV-OO', 'UZB-OO', 'SAR-OO', 'ASS-TR', 'SAM-WS', 'MXS-MI', 'MXE-DU', 'URU-OO', 'WIN-DO', 'BAN-OO', 'KOR-SK', 'BZS-PR', 'JAM-OO', 'PUE-OO', 'PAR-OO', 'LSI-BA', 'YUG-BH', 'QUE-OO', 'MIN-OO', 'PEI-OO', 'IND-UP', 'TKM-OO', 'KAM-OO', 'MRY-OO', 'SIE-OO', 'TVA-OO', 'BOT-OO', 'YUG-KO', 'MXC-PU', 'TRT-OO', 'AGW-LR', 'CHS-FJ', 'NWJ-OO', 'UKR-UK', 'CHS-HK', 'CHC-YN', 'CHS-HN', 'CHS-HE', 'IDA-OO', 'PHI-OO', 'NET-OO', 'GIL-OO', 'NCS-IN', 'BUR-OO', 'OGA-OO', 'PEN-OO', 'AUT-AU', 'SOL-NO', 'PIT-OO', 'HBI-OO', 'CLS-LL', 'BZE-MA', 'MXE-GU', 'YEM-SY', 'CHQ-OO', 'RUS-OO', 'ALT-OO', 'PAL-JO', 'WIN-MA', 'AND-CO', 'NWY-OO', 'MOR-SP', 'IND-GU', 'CPP-WC', 'IND-GO', 'GEO-OO', 'BZC-GO', 'CAB-OO', 'HAW-MI', 'CHN-SA', 'MRQ-OO', 'HON-OO', 'AGS-SF', 'AGS-SC', 'CPP-EC', 'MLI-OO', 'NTA-OO', 'MSO-OO', 'EQG-OO', 'MTN-OO', 'LEE-VI', 'LBR-OO', 'CLN-AN', 'ICE-OO', 'SOL-SO', 'LOU-OO', 'KRI-OO', 'MXI-RG', 'YEM-NY', 'GAB-OO', 'ASK-OO', 'NSC-OO', 'CHS-KI', 'NWC-OO', 'ATP-OO', 'AGE-BA', 'LBY-OO', 'BZL-ES', 'ANG-OO', 'NNS-OO', 'NCB-OO', 'NZN-OO', 'CHC-SC', 'GST-BA', 'VER-OO', 'MXN-BS', 'SAM-AS', 'CVI-OO', 'MXE-NL', 'ONT-OO', 'JAW-OO', 'EHM-DJ', 'ALA-OO', 'RUW-OO', 'BZE-SE', 'NWM-OO', 'AGE-LP', 'AGE-ER', 'TUR-OO', 'JNF-OO', 'CYP-OO', 'YUK-OO', 'CLC-LA', 'PAK-OO', 'GUA-OO', 'BOR-SR', 'NSW-CT', 'BRY-OO', 'NLA-BO', 'GAM-OO', 'BOR-SB', 'BZE-AL', 'NUN-OO', 'CLM-OO', 'NFK-NI', 'MXE-CO', 'AGW-SA', 'SGE-OO', 'AGW-SE', 'MXE-CU', 'AGW-SJ', 'GUY-OO', 'AGW-SL', 'EAI-OO', 'KEN-OO', 'MAN-OO', 'NCS-SO', 'TOK-MA',
+'WHM-JK', 'SCS-PI', 'NCS-ST', 'IVO-OO', 'HAI-HA', 'TZK-OO', 'YAK-OO', 'RUC-OO', 'GRB-OO', 'WIN-GR', 'THA-OO', 'CZE-SK', 'EGY-OO', 'BZC-MS', 'WIS-OO', 'BZC-MT', 'COM-MA', 'CBD-OO', 'MYA-OO', 'LAB-OO', 'NCA-OO', 'WSA-OO', 'NAT-OO', 'CKI-OO', 'AGE-FO', 'VIC-OO', 'NBR-OO', 'LDV-OO', 'TEX-OO', 'MDV-OO', 'SEL-OO', 'CHX-OO', 'BRC-OO', 'CRL-PA', 'MXS-GR', 'MOZ-OO', 'SOM-OO', 'MXT-TB', 'NUE-OO', 'IND-CH', 'IRE-IR', 'WDC-OO', 'IND-CT', 'FRA-MO', 'BZL-SP', 'MXN-SO', 'CON-OO', 'HAW-HI', 'CHT-OO', 'AGS-CB', 'NFL-NE', 'IND-DD', 'AGW-TU', 'LBS-SY', 'MRN-NM', 'IND-DM', 'NWG-PN', 'IND-DI', 'KUW-OO', 'POL-OO', 'AGS-TF', 'GGI-AN', 'KTY-OO', 'MSI-OO', 'TVL-NP', 'TVL-NW', 'TCS-AR', 'CLC-OH', 'WIN-BA', 'BZN-RO', 'BZN-RM', 'FAL-OO', 'ITA-IT', 'MXE-QU', 'MXT-CI', 'MXN-SI', 'YUG-CR', 'SEN-OO', 'LEE-GU', 'CGS-OO', 'SWC-CC', 'AGW-ME', 'KOR-NK', 'MON-OO', 'LEE-NL', 'COL-OO', 'ROM-OO', 'SOA-OO', 'AGE-MI', 'MXC-DF', 'COS-OO', 'NOR-OO', 'CHI-NM', 'BZE-PI', 'MCI-OO', 'WIN-SL', 'SIC-MA', 'BIS-OO', 'MDR-OO', 'BZE-PB', 'CHI-NX', 'BZE-PE', 'IND-YA', 'NEB-OO', 'CHN-HB', 'SOC-OO', 'PAN-OO', 'DEL-OO', 'TAS-OO', 'UGA-OO', 'SCZ-OO', 'LIN-US', 'NCS-KR', 'IND-DE', 'BOR-BR', 'NCS-DA', 'BZC-DF', 'CTM-OO', 'ETH-OO', 'SWC-NC', 'CHS-SH', 'AZO-OO', 'IND-OR', 'BZE-BA', 'MXC-MO', 'KER-OO', 'NSW-NS', 'MXC-ME', 'CLC-VA', 'CHN-SD', 'QLD-CS', 'MXS-CL', 'JAP-SH', 'MXT-QR', 'ALD-OO', 'PRM-OO', 'CLN-AT', 'SSA-OO', 'IND-AP', 'CHN-SX', 'GGI-ST', 'CHS-AH', 'PAL-IS', 'MXE-TA', 'CHM-JL', 'HMD-OO', 'YUG-MN', 'NGR-OO', 'MAU-OO', 'GNL-OO', 'WYO-OO', 'YUG-MA', 'ZAM-OO', 'ITA-SM', 'SVA-OO', 'LEE-MO', 'ASS-ME', 'SWZ-OO', 'CHS-JS', 'ASS-MA', 'DSV-OO', 'CHS-JX', 'ASS-MI', 'CUB-OO', 'VNA-OO', 'IND-RA', 'NCS-KB', 'NCS-KC', 'QLD-QU', 'KHA-OO', 'MOL-OO', 'NZS-OO', 'SPA-GI', 'AGE-CO', 'AGE-CN', 'AGE-CH', 'WVA-OO', 'COM-CO', 'ASP-OO', 'LIN-KI', 'NAM-OO', 'SIN-OO', 'BEN-OO', 'MAQ-OO', 'RHO-OO', 'BOU-OO', 'ALU-OO', 'NRU-OO', 'GUI-OO', 'CTA-OO', 'GNB-OO', 'CHN-TJ', 'ROD-OO', 'CHC-GZ', 'SWI-OO', 'TUA-OO', 'MDG-OO', 'NEP-OO', 'TON-OO', 'WIN-SV', 'AND-AN', 'GGI-PR', 'CNY-OO', 'DJI-OO', 'BZL-RJ', 'CLC-CO', 'POR-OO', 'CHH-OO', 'VRG-OO', 'NLA-CU', 'GRC-OO', 'WAS-OO', 'IND-KL', 'BGM-LU', 'BZE-FN', 'IND-KE', 'MXN-BC', 'TVL-MP', 'CPI-MA', 'MAS-OO', 'BOR-KA', 'ERI-OO', 'NEV-OO', 'BZS-RS', 'GER-OO', 'CAY-OO', 'CHS-MA', 'IND-WB', 'MIC-OO', 'UTA-OO', 'TAI-OO', 'CHS-MP', 'TUE-OO', 'SWE-OO', 'LSI-ET', 'CPP-NC', 'NFL-SP', 'BKN-OO', 'ORE-OO', 'NWH-OO', 'PER-OO', 'BAL-OO', 'WSB-OO', 'TEN-OO', 'SCA-OO', 'KGZ-OO', 'KAN-OO', 'KEG-OO', 'ABT-OO', 'ZAI-OO', 'KZN-OO', 'REU-OO', 'MLY-PM', 'BER-OO', 'CAL-OO', 'TCS-AZ', 'MXT-YU', 'BZE-CE', 'DOM-OO', 'IND-HA', 'TCS-AB', 'MXI-RA', 'CHC-CQ', 'TCS-AD', 'PHX-OO', 'IOW-OO', 'CRL-MF', 'NFK-LH', 'HUN-OO', 'MXI-GU', 'FRA-FR', 'WAK-OO', 'GST-UA', 'SAK-OO', 'MNT-OO', 'WHM-HP', 'NDA-OO', 'BLZ-OO', 'MLW-OO', 'SUD-OO', 'FIN-OO', 'RUE-OO', 'CHN-BJ', 'GGI-BI', 'WAU-AC', 'JAP-KY', 'IRN-OO', 'OMA-OO', 'LSI-LS', 'FOR-OO', 'TCS-NA', 'SRL-OO', 'TCS-NK', 'OHI-OO'}]

File test_two_way_dict.py

View file
  • Ignore whitespace
+#!/usr/bin/env python
+###############################################################################
+# two_way_dict python module
+# Copyright (c) 2005-2008 RADLogic Pty. Ltd. 
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#    * Redistributions of source code must retain the above copyright
+#      notice, this list of conditions and the following disclaimer.
+#    * Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials provided
+#      with the distribution.
+#    * Neither the name of RADLogic nor the names of its contributors
+#      may be used to endorse or promote products derived from this
+#      software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+###############################################################################
+"""Test suite for the two way dict module"""
+
+__author__ = 'Tim Wegener <twegener@radlogic.com.au>'
+__version__ = '$Revision: 0.3 $'
+__date__ = '$Date: 2008/07/31 04:05:17 $'
+__credits__ = '''\
+Stuart Mentzer <Stuart_Mentzer - objexx.com> - suggestions/bugfix for replace
+'''
+
+# $Log: two_way_dict.py,v $
+# Revision 0.3  2008/07/31 04:05:17  twegener
+# Delete old value in _reverse_map when replacing an existing key, reported by
+# Stuart Mentzer <Stuart_Mentzer - objexx.com> - suggestions/bugfix for replace.
+# Changed behavior of setitem when the value already exists, to be more
+# symmetrical, also at Stuart's suggestion.
+# Replaced some 'has_key' method calls with 'in'.
+# Added todo item to replace UnitTest test suite with doctests.
+#
+
+import unittest
+from two_way_dict import TwoWayDict
+
+
+# Test suite
+# todo: Replace this with doctests.
+        
+class TestTwoWayDictBase(unittest.TestCase):
+
+    def setUp(self):
+
+        # Make sure test keys are not in same sort order as values.
+        self.test_keys = ['bbb', 2.0, 'c', 1, 'a']
+        # Use a range for values so that order can be easily tested.
+        self.test_vals = range(len(self.test_keys))
+        self.test_items = zip(self.test_keys, self.test_vals)
+        self.absent_key = 'absent key'
+        self.absent_val = 'absent val'
+        self.default_val = 'default val'
+        self.new_val = 'new val'
+        self.new_key = 'new key'
+
+        self.twd = TwoWayDict()
+        for k, v in self.test_items:
+            self.twd[k] = v
+
+        # Construct another ordered dict that should be equal.
+        self.twd2 = TwoWayDict()
+        for k, v in self.test_items:
+            self.twd2[k] = v
+
+    def test_truth(self):
+
+        self.assert_(self.twd)
+        self.assert_(not TwoWayDict())
+            
+    def test_keys(self):
+
+        keys = self.twd.keys()
+        keys.sort()
+        test_keys_copy = self.test_keys
+        test_keys_copy.sort()
+        self.assertEqual(keys, test_keys_copy)
+
+    def test_values(self):
+
+        values = self.twd.values()
+        values.sort()
+        test_vals_copy = self.test_vals
+        test_vals_copy.sort()
+        self.assertEqual(values, test_vals_copy)
+
+    def test_items(self):
+
+        items = self.twd.items()
+        items.sort()
+        test_items_copy = self.test_items[:]
+        test_items_copy.sort()
+        self.assertEqual(items, test_items_copy)
+
+    def test_reversed_items(self):
+
+        reversed_items = self.twd.reversed_items()
+        reversed_items.sort()
+        reversed_test_items = []
+        for k, v in self.test_items:
+            reversed_test_items.append((v, k))
+        reversed_test_items.sort()
+        self.assertEqual(reversed_items, reversed_test_items)
+
+    def test_getitem(self):
+
+        for k, v in self.test_items:
+            self.assertEqual(v, self.twd[k])
+
+    def test_getitem_absent(self):
+
+        def get_absent_key(key, self=self):
+
+            return self.twd[key]
+
+        self.assertRaises(KeyError, get_absent_key, self.absent_key)
+
+    def test_get(self):
+
+        for k, v in self.test_items:
+            self.assertEqual(v, self.twd.get(k))
+            
+    def test_get_absent(self):
+
+        self.assertEqual(None, self.twd.get(self.absent_key))
+            
+    def test_get_absent_default(self):
+
+        self.assertEqual(self.default_val,
+                         self.twd.get(self.absent_key, self.default_val))
+            
+    def test_get_key(self):
+
+        for k, v in self.test_items:
+            self.assertEqual(k, self.twd.get_key(v))
+            
+    def test_get_key_absent(self):
+
+        self.assertEqual(None, self.twd.get_key(self.absent_val))
+            
+    def test_get_key_absent_default(self):
+
+        self.assertEqual(self.default_val,
+                         self.twd.get_key(self.absent_val, self.default_val))
+            
+    def test_len(self):
+
+        self.assertEqual(0, len(TwoWayDict()))
+        self.assertEqual(len(self.test_keys), len(self.twd))
+        self.assertEqual(len(self.test_vals), len(self.twd))
+
+    def test_has_key(self):
+
+        for k in self.test_keys:
+            self.assert_(self.twd.has_key(k))
+        self.assert_(not self.twd.has_value(self.absent_key))
+
+    def test_has_value(self):
+
+        for v in self.test_vals:
+            self.assert_(self.twd.has_value(v))
+        self.assert_(not self.twd.has_value(self.absent_val))
+
+    def test_equal(self):
+
+        self.assertEqual(self.twd, self.twd2)
+
+    def test_not_equal(self):
+
+        twd_copy = self.twd.copy()
+        twd_copy[self.new_key] = self.new_val
+        self.assertNotEqual(self.twd, twd_copy)
+
+    def test_copy(self):
+
+        twd_copy = self.twd.copy()
+        self.assertEqual(self.twd, twd_copy)
+        self.assert_(self.twd is not twd_copy)
+
+    def test_update(self):
+
+        twd_other = TwoWayDict()
+        twd_other.update(self.twd)
+        self.assertEqual(self.twd, twd_other)
+        orig_items = self.twd.items()
+        orig_items.sort()
+        other_items = twd_other.items()
+        other_items.sort()
+        orig_reversed_items = self.twd.reversed_items()
+        orig_reversed_items.sort()
+        other_reversed_items = twd_other.reversed_items()
+        other_reversed_items.sort()
+        self.assertEqual(orig_items, other_items)
+        self.assertEqual(orig_reversed_items, other_reversed_items)
+
+    def test_init_update(self):
+
+        twd_other = TwoWayDict(self.twd)
+        self.assertEqual(self.twd, twd_other)
+
+    def test_setitem(self):
+
+        twd_copy = self.twd.copy()
+        twd_copy[self.new_key] = self.new_val
+        self.assertNotEqual(self.twd, twd_copy)
+        self.assertEqual(self.new_val, twd_copy[self.new_key])
+        self.assert_(twd_copy.has_key(self.new_key))
+        self.assert_(twd_copy.has_value(self.new_val))
+        self.assert_((self.new_key, self.new_val) in twd_copy.items())
+
+    def test_setitem_replace_key(self):
+
+        twd_copy = self.twd.copy()
+        old_key = twd_copy.key(self.test_vals[0])
+        twd_copy[self.new_key] = self.test_vals[0]
+        self.assert_(twd_copy.key(self.test_vals[0]) == self.new_key)
+        self.assert_(old_key not in twd_copy)
+
+    def test_delitem(self):
+
+        twd_copy = self.twd.copy()
+        del twd_copy[self.test_keys[0]]
+        self.assert_(not twd_copy.has_key(self.test_keys[0]))
+        self.assert_(not twd_copy.has_value(self.test_vals[0]))
+        self.assertNotEqual(self.twd, twd_copy)
+
+    def test_clear(self):
+
+        twd_copy = self.twd.copy()
+        twd_copy.clear()
+        self.assertEqual(TwoWayDict(), twd_copy)
+        self.assertNotEqual(self.twd, twd_copy)
+        self.assert_(not len(twd_copy.reversed_items()))
+
+    def test_setdefault(self):
+
+        twd_copy = self.twd.copy()
+        twd_copy.setdefault(self.test_keys[0])
+        self.assertEqual(self.test_vals[0], twd_copy[self.test_keys[0]])
+
+    def test_setdefault_absent(self):
+
+        twd_copy = self.twd.copy()
+        twd_copy.setdefault(self.absent_key)
+        self.assertEqual(None, twd_copy[self.absent_key])
+
+    def test_setdefault_absent_default(self):
+
+        twd_copy = self.twd.copy()
+        twd_copy.setdefault(self.absent_key, self.default_val)
+        self.assertEqual(self.default_val, twd_copy[self.absent_key])
+
+    def test_pop(self):
+
+        twd_copy = self.twd.copy()
+        v = twd_copy.pop(self.test_keys[0])
+        self.assertEqual(self.test_vals[0], v)
+        self.assert_(not twd_copy.has_key(self.test_keys[0]))
+        self.assert_(not twd_copy.has_value(v))
+
+    def test_pop_absent(self):
+
+        self.assertRaises(KeyError, self.twd.pop, self.absent_key)
+
+    def test_pop_default(self):
+
+        twd_copy = self.twd.copy()
+        v = twd_copy.pop(self.absent_key, self.default_val)
+        self.assertEqual(self.default_val, v)
+
+    def test_popitem(self):
+
+        twd_copy = self.twd.copy()
+        item = twd_copy.popitem()
+        self.assert_(not twd_copy.has_key(item[0]))
+        self.assert_(not twd_copy.has_value(item[1]))
+        self.assert_(self.twd.has_key(item[0]))
+        self.assert_(self.twd.has_value(item[1]))
+        self.assertNotEqual(self.twd, twd_copy)
+
+    def test_fromkeys_many(self):
+
+        d = TwoWayDict.fromkeys(self.test_keys)
+        self.assert_(d)
+        self.assert_(self.test_keys[0] not in d)
+        self.assert_(self.test_keys[-1] in d)
+        
+    def test_fromkeys_one(self):
+
+        keys = [self.new_key]
+        twd = TwoWayDict.fromkeys(keys)
+        self.assertEqual(keys, twd.keys())
+        self.assert_(twd.has_value(None))
+        self.assertEqual(self.new_key, twd.get_key(None))
+        self.assertEqual(None, twd[self.new_key])
+
+    def test_reversed_iteritems(self):
+
+        found_reversed_items = []
+        for v, k in self.twd.reversed_iteritems():
+            self.assertEqual(v, self.twd[k])
+            self.assertEqual(k, self.twd.get_key(v))
+            found_reversed_items.append((v, k))
+        found_reversed_items.sort()
+
+        reversed_items = []
+        for k, v in self.test_items:
+            reversed_items.append((v, k))
+        reversed_items.sort()
+        self.assertEqual(reversed_items, found_reversed_items)
+        
+    def test_iter(self):
+
+        twd_iter = iter(self.twd)
+        found_keys = []
+        for k in twd_iter:
+            found_keys.append(k)
+        found_keys.sort()
+        keys = self.test_keys[:]
+        keys.sort()
+        self.assertEqual(keys, found_keys)
+
+        twd_iter = iter(self.twd)
+        for k in self.test_keys:
+            twd_iter.next()
+        self.assertRaises(StopIteration, twd_iter.next)
+
+    def test_iterkeys(self):
+
+        found_keys = []
+        for k in self.twd.iterkeys():
+            found_keys.append(k)
+        found_keys.sort()
+        keys = self.test_keys[:]
+        keys.sort()
+        self.assertEqual(keys, found_keys)
+
+        twd_keys_iter = self.twd.iterkeys()
+        for k in self.test_keys:
+            twd_keys_iter.next()
+
+        self.assertRaises(StopIteration, twd_keys_iter.next)
+
+    def test_itervalues(self):
+
+        found_values = []
+        for v in self.twd.itervalues():
+            found_values.append(v)
+        found_values.sort()
+        values = self.test_vals[:]
+        values.sort()
+        self.assertEqual(values, found_values)
+
+        twd_values_iter = self.twd.itervalues()
+        for v in self.test_vals:
+            twd_values_iter.next()
+        self.assertRaises(StopIteration, twd_values_iter.next)
+
+    def test_iteritems(self):
+
+        found_items = []
+        for item in self.twd.iteritems():
+            found_items.append(item)
+        found_items.sort()
+
+        items = self.test_items[:]
+        items.sort()
+
+        self.assertEqual(items, found_items)
+
+        twd_items_iter = self.twd.iteritems()
+        for item in self.test_items:
+            twd_items_iter.next()
+            
+        self.assertRaises(StopIteration, twd_items_iter.next)
+
+    def test_replace(self):
+
+        twd_copy = self.twd.copy()
+        twd_copy['abcd'] = 5
+        self.assert_(twd_copy.key(5) == 'abcd')
+
+        twd_copy['abcd'] = 6
+        self.assert_('abcd' in twd_copy)
+        self.assert_(twd_copy.key(6) == 'abcd')
+        self.assertRaises(KeyError, lambda: twd_copy.key(5))
+        
+
+if __name__ == '__main__':
+    unittest.main()

File two_way_dict.py

View file
  • Ignore whitespace
+#!/usr/bin/env python
+###############################################################################
+# two_way_dict python module
+# Copyright (c) 2005-2008 RADLogic Pty. Ltd. 
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#    * Redistributions of source code must retain the above copyright
+#      notice, this list of conditions and the following disclaimer.
+#    * Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials provided
+#      with the distribution.
+#    * Neither the name of RADLogic nor the names of its contributors
+#      may be used to endorse or promote products derived from this
+#      software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+###############################################################################
+"""Provide dictionary-style object with reverse-lookup capabilities.
+
+Running this module as a script will run the unittest suite.
+
+This requires Python 2.2 or greater.
+
+"""
+
+__author__ = 'Tim Wegener <twegener@radlogic.com.au>'
+__version__ = '$Revision: 0.3 $'
+__date__ = '$Date: 2008/07/31 04:05:17 $'
+__credits__ = '''\
+Stuart Mentzer <Stuart_Mentzer - objexx.com> - suggestions/bugfix for replace
+'''
+
+# $Log: two_way_dict.py,v $
+# Revision 0.3  2008/07/31 04:05:17  twegener
+# Delete old value in _reverse_map when replacing an existing key, reported by
+# Stuart Mentzer <Stuart_Mentzer - objexx.com> - suggestions/bugfix for replace.
+# Changed behavior of setitem when the value already exists, to be more
+# symmetrical, also at Stuart's suggestion.
+# Replaced some 'has_key' method calls with 'in'.
+# Added todo item to replace UnitTest test suite with doctests.
+#
+
+import unittest
+
+
+class TwoWayDict(dict):
+    """Dictionary with reverse mapping.
+
+    This class maintains the integrity of the two-way mapping.
+
+    This acts just like a normal dict, but has extra methods such as:
+    key(value)
+    get_key(value)
+    has_value(value)
+    pop_key(value, [default])
+    reversed_items()
+    reversed_iteritems()
+    reversed_popitem()
+
+    Of these, key, get_key, has_value and reversed_items are the more commonly
+    used methods.
+
+    Notes:
+    - Both keys and values must be hashable.
+    - Many to one mappings are allowed, but only the first reverse mapping will be
+      found.
+    - This takes double the storage of a normal dict.
+      (Plus a little overhead.)
+    - x in <TwoWayDict instance> will only return True if x is a forward key
+    - Reverse lookups are implemented using a second dictionary,
+      so has_value, key and get_key are O(1) operations.
+
+    """
+
+    def __init__(self, *args, **kwargs):
+
+        # The user should not tamper with the internal reverse map,
+        # since this enables the integrity of the TwoMayDict to be messed up.
+        # Signify this with a leading underscore.
+        self._reverse_map = {}
+
+        dict.__init__(self)
+
+        # It appears that dict.__init__ does not call self.update,
+        # so need to do that here.
+        self.update(*args, **kwargs)
+
+    def __setitem__(self, k, value):
+        """x.__setitem__(i, y) <==> x[i]=y"""
+        
+        # Check for 1-to-many mappings.
+        #if value in self._reverse_map:
+        #    del self[self._reverse_map[value]]
+
+        if k in self:
+            del self._reverse_map[self[k]]
+        
+        if not value in self._reverse_map:
+            self._reverse_map[value] = k
+        
+        dict.__setitem__(self, k, value)
+
+    def __delitem__(self, k):
+        """x.__delitem__(y) <==> del x[y]"""
+
+        value = self[k]
+        del self._reverse_map[value]
+        dict.__delitem__(self, k)
+        for newk, matchv in self.items():
+            if matchv == value:
+                self._reverse_map[value] = newk
+                break
+
+    def __repr__(self):
+        """x.__repr__() <==> repr(x)"""
+
+        return "%s(%s)" % (self.__class__.__name__, dict.__repr__(self))
+
+    def copy(self):
+        """Return a shallow copy."""
+
+        return self.__class__(self)
+
+    def clear(self):
+        """Remove all items."""
+
+        dict.clear(self)
+        self._reverse_map.clear()
+
+    def key(self, value):
+        """Get key corresponding to value.
+
+        Raise KeyError if value is not present.
+
+        """
+        return self._reverse_map[value]
+
+    def get_key(self, value, default=None):
+        """Get key corresponding to value, or else a default.
+
+        Return default if value not present.
+
+        """
+        return self._reverse_map.get(value, default)
+
+    def has_value(self, value):
+        """Return True if value is present."""
+
+        return value in self._reverse_map
+
+    def reversed_items(self):
+        """Return a list of (value, key) pairs."""
+
+        return self._reverse_map.items()
+
+    def pop(self, key, *args):
+        """Remove specified key and return corresponding value.
+
+        If key is not found, default is returned if given,
+        otherwise KeyError is raised.
+
+        """
+        # Don't use dict.pop, so that it works with Python 2.2.
+        try:
+            val = self[key]
+        except KeyError:
+            if not args:
+                raise
+            else:
+                val = args[0]
+        else:
+            del self[key]
+        return val
+
+    def popitem(self):
+        """Return and remove arbitrary (key, value) pair."""
+
+        item = dict.popitem(self)
+        del self._reverse_map[item[1]]
+        return item
+
+    def pop_key(self, value, *args):
+        """Remove specified value and return corresponding key.
+
+        If value is not found, default is returned if given,
+        otherwise KeyError is raised.
+        
+        """
+        key = self._reverse_map.pop(value, *args)
+        try:
+            del self[key]
+        except KeyError:
+            pass
+        return key
+
+    def reversed_popitem(self):
+        """Return and remove arbitrary (value, key) pair."""
+
+        item = self._reverse_map.popitem()
+        del self[item[0]]
+        return item
+
+    def update(self, dict=None, **kwargs):
+        """Update from dict, or sequence of key, value pairs or kwargs."""
+        
+        # dict.update does not seem to call self.__getitem__,
+        # so need to redefine update method here.
+
+        # todo: Support sequence of (key, value) pairs here.
+        if dict is not None:
+            for k, v in dict.items():
+                self[k] = v
+
+        for k, v in kwargs.items():
+            self[k] = v
+
+    def fromkeys(cls, iterable, value=None):
+        """Return new TwoWayDict with keys from iterable and values set to v.
+
+        value defaults to None.
+
+        This isn't very useful due to the one-to-one mapping restriction,
+        but here to match Py2.3/2.4 dict interface.
+        
+        """
+        # It is redefined here, so that it works in Py2.2.
+
+        twd = cls()
+        for key in iterable:
+            twd[key] = value
+        return twd
+    fromkeys = classmethod(fromkeys)
+
+    def fromvalues(cls, iterable, key=None):
+        """Return new TwoWayDict with values from iterable and keys set to key.
+
+        key defaults to None.
+
+        This isn't very useful due to the one-to-one mapping restriction,
+        but here for symmetry.
+        
+        """
+        d = cls()
+        for value in iterable:
+            d[key] = value
+        return d
+    fromvalues = classmethod(fromvalues)
+