11import gzip
22import io
33import json
4- import pathlib
54import unicodedata
65from urllib .error import HTTPError
76from urllib .request import urlopen
87
8+ IBGE_MUNICIPALITY_BY_CODE_URL = (
9+ "https://servicodados.ibge.gov.br/api/v1/localidades/municipios/{code}"
10+ )
11+ IBGE_MUNICIPALITIES_BY_UF_URL = "https://servicodados.ibge.gov.br/api/v1/localidades/estados/{uf}/municipios"
912
10- def get_municipality_by_code (code ): # type: (str) -> Tuple[str, str] | None
13+
14+ def get_municipality_by_code (code : str ) -> tuple [str , str ] | None :
1115 """
1216 Returns the municipality name and UF for a given IBGE code.
1317
@@ -18,62 +22,34 @@ def get_municipality_by_code(code): # type: (str) -> Tuple[str, str] | None
1822 code (str): The IBGE code of the municipality.
1923
2024 Returns:
21- tuple: A tuple formatted as ("Município", "UF").
22- - Returns None if the code is not valid.
25+ tuple: A tuple formatted as ("Município", "UF") or
26+ None if the code is not valid.
2327
2428 Example:
2529 >>> get_municipality_by_code("3550308")
2630 ("São Paulo", "SP")
31+ >>> get_municipality_by_code("3304557")
32+ ("Rio de Janeiro", "RJ")
33+ >>> get_municipality_by_code("1234567")
34+ None
2735 """
28- baseUrl = (
29- f"https://servicodados.ibge.gov.br/api/v1/localidades/municipios/{ code } "
30- )
31- try :
32- with urlopen (baseUrl ) as f :
33- compressed_data = f .read ()
34- if f .info ().get ("Content-Encoding" ) == "gzip" :
35- try :
36- with gzip .GzipFile (
37- fileobj = io .BytesIO (compressed_data )
38- ) as gzip_file :
39- decompressed_data = gzip_file .read ()
40- except OSError as e :
41- print (f"Erro ao descomprimir os dados: { e } " )
42- return None
43- except Exception as e :
44- print (f"Erro desconhecido ao descomprimir os dados: { e } " )
45- return None
46- else :
47- decompressed_data = compressed_data
36+ base_url = IBGE_MUNICIPALITY_BY_CODE_URL .format (code = code )
4837
49- if _is_empty (decompressed_data ):
50- print (f"{ code } é um código inválido" )
51- return None
38+ decompressed_data = _fetch_ibge_data (base_url )
5239
53- except HTTPError as e :
54- if e .code == 404 :
55- print (f"{ code } é um código inválido" )
56- return None
57- else :
58- print (f"Erro HTTP ao buscar o código { code } : { e } " )
59- return None
60-
61- except Exception as e :
62- print (f"Erro desconhecido ao buscar o código { code } : { e } " )
40+ if decompressed_data is None :
6341 return None
6442
6543 try :
6644 json_data = json .loads (decompressed_data )
6745 return _get_values (json_data )
68- except json .JSONDecodeError as e :
69- print (f"Erro ao decodificar os dados JSON: { e } " )
70- return None
71- except KeyError as e :
72- print (f"Erro ao acessar os dados do município: { e } " )
46+ except (json .JSONDecodeError , KeyError ):
7347 return None
7448
7549
76- def get_code_by_municipality_name (municipality_name : str , uf : str ): # type: (str, str) -> str | None
50+ def get_code_by_municipality_name (
51+ municipality_name : str , uf : str
52+ ) -> str | None :
7753 """
7854 Returns the IBGE code for a given municipality name and uf code.
7955
@@ -87,76 +63,109 @@ def get_code_by_municipality_name(municipality_name: str, uf: str): # type: (st
8763 uf (str): The uf code of the state.
8864
8965 Returns:
90- str: The IBGE code of the municipality.
91- - Returns None if the name is not valid or does not exist.
66+ str: The IBGE code of the municipality or
67+ None if the name is not valid or does not exist.
9268
9369 Example:
9470 >>> get_code_by_municipality_name("São Paulo", "SP")
9571 "3550308"
96- >>> get_code_by_municipality_name("goiania", "go")
97- "5208707"
98- >>> get_code_by_municipality_name("Conceição do Coité", "BA")
72+ >>> get_code_by_municipality_name("Conceição do Coité", "Ba")
9973 "2908408"
100- >>> get_code_by_municipality_name("conceicao do Coite", "Ba")
101- "2908408"
102- >>> get_code_by_municipality_name("Municipio Inexistente", "")
103- None
10474 >>> get_code_by_municipality_name("Municipio Inexistente", "RS")
10575 None
10676 """
107-
108- abs_path = pathlib .Path (__file__ ).resolve ()
109- script_dir = abs_path .parent .parent
110-
111- json_cities_code_path = script_dir / "data" / "cities_code.json"
11277 uf = uf .upper ()
11378
114- with open (json_cities_code_path , "r" , encoding = "utf-8" ) as file :
115- cities_uf_code = json .load (file )
79+ base_url = IBGE_MUNICIPALITIES_BY_UF_URL .format (uf = uf )
11680
117- if uf not in cities_uf_code .keys ():
81+ decompressed_data = _fetch_ibge_data (base_url )
82+ if decompressed_data is None :
11883 return None
11984
120- cities_code = cities_uf_code .get (uf )
121- name_city = _transform_text (municipality_name )
85+ try :
86+ json_data = json .loads (decompressed_data )
87+ normalized_municipality_name = _transform_text (municipality_name )
88+
89+ for municipality in json_data :
90+ municipality_name_from_api = municipality .get ("nome" , "" )
91+ normalized_name_from_api = _transform_text (
92+ municipality_name_from_api
93+ )
94+
95+ if normalized_name_from_api == normalized_municipality_name :
96+ return str (municipality .get ("id" ))
12297
123- if name_city not in cities_code .keys ():
12498 return None
12599
126- code = cities_code .get (name_city )
100+ except (json .JSONDecodeError , KeyError ):
101+ return None
127102
128- return code
129103
104+ def _fetch_ibge_data (url : str ) -> bytes | None :
105+ """
106+ Fetch data from IBGE API with gzip decompression support.
130107
131- def _get_values (data ):
108+ Args:
109+ url (str): The URL to fetch data from.
110+
111+ Returns:
112+ bytes | None: The decompressed data or None if failed.
113+ """
114+ try :
115+ with urlopen (url ) as f :
116+ compressed_data = f .read ()
117+ if f .info ().get ("Content-Encoding" ) == "gzip" :
118+ try :
119+ with gzip .GzipFile (
120+ fileobj = io .BytesIO (compressed_data )
121+ ) as gzip_file :
122+ decompressed_data = gzip_file .read ()
123+ except (OSError , Exception ):
124+ return None
125+ else :
126+ decompressed_data = compressed_data
127+
128+ if _is_empty (decompressed_data ):
129+ return None
130+
131+ return decompressed_data
132+
133+ except HTTPError :
134+ return None
135+ except Exception :
136+ return None
137+
138+
139+ def _get_values (data : dict ) -> tuple [str , str ]:
140+ """Extract municipality name and UF from IBGE API response."""
132141 municipio = data ["nome" ]
133142 estado = data ["microrregiao" ]["mesorregiao" ]["UF" ]["sigla" ]
134143 return (municipio , estado )
135144
136145
137- def _is_empty (zip ):
138- return zip == b"[]" or len (zip ) == 0
146+ def _is_empty (data : bytes ) -> bool :
147+ """Check if the response data is empty."""
148+ return data == b"[]" or len (data ) == 0
139149
140150
141- def _transform_text (municipality_name : str ): # type: (str) -> str
151+ def _transform_text (municipality_name : str ) -> str :
142152 """
143153 Normalize municipality name and returns the normalized string.
144154
145155 Args:
146- municipality_name (str): The name of the municipality.
147-
148- Returns:
149- str: The normalized string
150-
151- Example:
152- >>> _transform_text("São Paulo")
153- "sao paulo"
154- >>> _transform_text("Goiânia")
155- "goiania"
156- >>> _transform_text("Conceição do Coité")
157- "'conceicao do coite'
158- """
156+ municipality_name (str): The name of the municipality.
159157
158+ Returns:
159+ str: The normalized string
160+
161+ Example:
162+ >>> _transform_text("São Paulo")
163+ 'sao paulo'
164+ >>> _transform_text("Goiânia")
165+ 'goiania'
166+ >>> _transform_text("Conceição do Coité")
167+ 'conceicao do coite'
168+ """
160169 normalized_string = (
161170 unicodedata .normalize ("NFKD" , municipality_name )
162171 .encode ("ascii" , "ignore" )
0 commit comments