airportsdata 2026.3.25__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020- Mike Borsetti <mike@borsetti.com>
4
+
5
+ This project includes data from https://github.com/mwgg/Airports Copyright
6
+ (c) 2014 mwgg
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: airportsdata
3
+ Version: 2026.3.25
4
+ Summary: Extensive database of location and timezone data for nearly every airport and landing strip in the world.
5
+ Author-email: Mike Borsetti <mike+airportsdata@borsetti.com>
6
+ Maintainer-email: Mike Borsetti <mike+airportsdata@borsetti.com>
7
+ License-Expression: MIT
8
+ Project-URL: Documentation, https://github.com/mborsetti/airportsdata/blob/main/README.rst
9
+ Project-URL: Repository, https://github.com/mborsetti/airportsdata/
10
+ Project-URL: Database (csv), https://github.com/mborsetti/airportsdata/blob/main/airportsdata/airports.csv
11
+ Project-URL: Changelog, https://github.com/mborsetti/airportsdata/blob/main/CHANGELOG.rst
12
+ Project-URL: Issues, https://github.com/mborsetti/airportsdata/issues
13
+ Project-URL: CI, https://github.com/mborsetti/airportsdata/actions
14
+ Keywords: airports,aerodromes,ICAO,IATA
15
+ Classifier: Development Status :: 5 - Production/Stable
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Natural Language :: English
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3 :: Only
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: Implementation :: CPython
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/x-rst
30
+ License-File: LICENSE
31
+ Dynamic: license-file
32
+
33
+ ========================
34
+ airportsdata |downloads|
35
+ ========================
36
+
37
+ .. |ICAO| replace:: 28,428
38
+
39
+ .. |IATA| replace:: 7,884
40
+
41
+ .. |LID| replace:: 12,746
42
+
43
+ .. |pyversion| image:: https://img.shields.io/pypi/v/airportsdata.svg
44
+ :target: https://pypi.org/project/airportsdata/
45
+ :alt: pypi version
46
+ .. |support| image:: https://img.shields.io/pypi/pyversions/airportsdata.svg
47
+ :target: https://pypi.org/project/airportsdata/
48
+ :alt: supported Python version
49
+ .. |pypi_version| image:: https://img.shields.io/pypi/v/airportsdata.svg?label=
50
+ :target: https://pypi.org/project/airportsdata/
51
+ :alt: PyPI version
52
+ .. |format| image:: https://img.shields.io/pypi/format/airportsdata.svg
53
+ :target: https://pypi.org/project/airportsdata/
54
+ :alt: Kit format
55
+ .. |downloads| image:: https://static.pepy.tech/badge/airportsdata
56
+ :target: https://www.pepy.tech/project/airportsdata
57
+ :alt: PyPI downloads
58
+ .. |license| image:: https://img.shields.io/pypi/l/airportsdata.svg
59
+ :target: https://pypi.org/project/airportsdata/
60
+ :alt: license
61
+ .. |issues| image:: https://img.shields.io/github/issues-raw/mborsetti/airportsdata
62
+ :target: https://github.com/mborsetti/airportsdata/issues
63
+ :alt: issues
64
+ .. |CI| image:: https://github.com/mborsetti/airportsdata/actions/workflows/ci-cd.yaml/badge.svg?event=push
65
+ :target: https://github.com/mborsetti/airportsdata/actions
66
+ :alt: CI testing status
67
+ .. |coveralls| image:: https://coveralls.io/repos/github/mborsetti/airportsdata/badge.svg?branch=main
68
+ :target: https://coveralls.io/github/mborsetti/airportsdata?branch=main
69
+ :alt: code coverage by Coveralls
70
+ .. |status| image:: https://img.shields.io/pypi/status/airportsdata.svg
71
+ :target: https://pypi.org/project/airportsdata/
72
+ :alt: Package stability
73
+ .. |security| image:: https://img.shields.io/badge/security-bandit-yellow.svg
74
+ :target: https://github.com/PyCQA/bandit
75
+ :alt: Security Status
76
+
77
+ Extensive database of location and timezone data for nearly every operational airport and landing strip in the world,
78
+ with |ICAO| entries.
79
+
80
+ Each entry consists of the following data:
81
+
82
+ * ``icao``: ICAO 4-letter Location Indicator (Doc 7910) or (if none) an internal Pseudo-ICAO Identifier [#]_ (|ICAO|
83
+ entries);
84
+ * ``iata``: IATA 3-letter Location Code (|IATA| entries) or an empty string [#]_;
85
+ * ``name``: Official name (diacritized latin script);
86
+ * ``city``: City (diacritized latin script), ideally using the local language or English;
87
+ * ``subd``: Subdivision (e.g. state, province, region, etc.), ideally using the local-language or English names of
88
+ `ISO 3166-2 <https://en.wikipedia.org/wiki/ISO_3166-2#Current_codes>`__;
89
+ * ``country``: `ISO 3166-1 <https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes>`__ alpha-2 country code
90
+ (plus ``XK`` for Kosovo);
91
+ * ``elevation``: MSL elevation of the highest point of the landing area, in feet (warning: it is often wrong);
92
+ * ``lat``: Latitude (decimal) of the `airport reference point
93
+ <https://en.wikipedia.org/wiki/Airport_reference_point>`__ (max 5 or 6 decimal digits);
94
+ * ``lon``: Longitude (decimal) of the `airport reference point
95
+ <https://en.wikipedia.org/wiki/Airport_reference_point>`__ (max 5 or 6 decimal digits);
96
+ * ``tz``: Timezone expressed as a `tz database name <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>`__
97
+ (IANA-compliant);
98
+ * ``lid``: U.S. FAA Location Identifier (|LID| entries), or an empty string.
99
+
100
+ .. [#] See `here <https://github.com/mborsetti/airportsdata/blob/main/README_identifiers.rst>`__ for an explanation on
101
+ how the Pseudo-ICAO Identifier is generated for airports and seaplane bases without an ICAO 4-letter Location
102
+ Indicator.
103
+
104
+ .. [#] IATA Multi Airport Cities (MAC) are not not airports and therfore not included, but we provide a database and a
105
+ Python function that returns the above data for all the airports of a IATA MAC. Please see documentation `here
106
+ <https://github.com/mborsetti/airportsdata/blob/main/README_IATA.rst>`__.
107
+
108
+ Best efforts are placed to review all contributions for accuracy, but accuracy cannot be guaranteed nor should be
109
+ expected by users.
110
+
111
+ Important notes:
112
+
113
+ * Timezone was originally sourced from `TimeZoneDB <https://timezonedb.com>`__;
114
+ * No historical data (closed airports are removed);
115
+ * No seaplane bases or heliports unless they have a IATA code;
116
+ * No surface transportation stations, even if they have an official IATA code;
117
+ * Airports under construction may be included if they have ICAO and IATA codes and scheduled airline service.
118
+
119
+ Please report any issues you may find `here
120
+ <https://github.com/mborsetti/airportsdata/blob/main/CONTRIBUTING.rst>`__.
121
+
122
+ This project is a fork of `mwgg/Airports <https://github.com/mwgg/Airports>`__. All new data submitted in this fork have
123
+ been validated against national `Aeronautical Information Publications (AIP)
124
+ <https://github.com/mborsetti/airportsdata/blob/main/README_AIP.rst>`__ or equivalent, ARINC database,
125
+ `IATA <https://www.iata.org/en/publications/directories/code-search/>`__ or
126
+ `ch-aviation.com <https://about.ch-aviation.com/airports/>`_ before publishing.
127
+
128
+ Raw data
129
+ ========
130
+
131
+ A CSV (comma separated values) file, with headers and encoded in UTF-8, is downloadable from GitHub `here
132
+ <https://github.com/mborsetti/airportsdata/raw/main/airportsdata/airports.csv>`__.
133
+
134
+ Python
135
+ ======
136
+ |pyversion| |support| |format| |status| |security| |CI| |coveralls| |issues|
137
+
138
+ Install from `PyPi <https://pypi.org/project/airportsdata/>`__ using ``uv`` (recommended):
139
+
140
+ .. code-block:: bash
141
+
142
+ uv pip install --update airportsdata
143
+
144
+ Or, using ``pip``:
145
+
146
+ .. code-block:: bash
147
+
148
+ pip install --update airportsdata
149
+
150
+ Once installed, to load the data into a dict:
151
+
152
+ .. code-block:: python
153
+
154
+ import airportsdata
155
+ icao_airports = airportsdata.load() # key is the ICAO identifier (the default)
156
+ print(icao_airports['KJFK'])
157
+
158
+ or
159
+
160
+ .. code-block:: python
161
+
162
+ import airportsdata
163
+ iata_airports = airportsdata.load('IATA') # key is the IATA location code
164
+ print(iata_airports['JFK'])
165
+
166
+ or
167
+
168
+ .. code-block:: python
169
+
170
+ import airportsdata
171
+ lid_airports = airportsdata.load('LID') # key is the FAA LID
172
+ print(lid_airports['01AA'])
173
+
174
+ Older Python versions are supported for 3 years after being obsoleted by a new major release (i.e. about 4 years
175
+ since their original release).
176
+
177
+ License |license|
178
+ =================
179
+
180
+ Released under the `MIT License <https://opensource.org/licenses/MIT>`__ (see license `here
181
+ <https://github.com/mborsetti/airportsdata/blob/main/LICENSE>`__).
@@ -0,0 +1,149 @@
1
+ ========================
2
+ airportsdata |downloads|
3
+ ========================
4
+
5
+ .. |ICAO| replace:: 28,428
6
+
7
+ .. |IATA| replace:: 7,884
8
+
9
+ .. |LID| replace:: 12,746
10
+
11
+ .. |pyversion| image:: https://img.shields.io/pypi/v/airportsdata.svg
12
+ :target: https://pypi.org/project/airportsdata/
13
+ :alt: pypi version
14
+ .. |support| image:: https://img.shields.io/pypi/pyversions/airportsdata.svg
15
+ :target: https://pypi.org/project/airportsdata/
16
+ :alt: supported Python version
17
+ .. |pypi_version| image:: https://img.shields.io/pypi/v/airportsdata.svg?label=
18
+ :target: https://pypi.org/project/airportsdata/
19
+ :alt: PyPI version
20
+ .. |format| image:: https://img.shields.io/pypi/format/airportsdata.svg
21
+ :target: https://pypi.org/project/airportsdata/
22
+ :alt: Kit format
23
+ .. |downloads| image:: https://static.pepy.tech/badge/airportsdata
24
+ :target: https://www.pepy.tech/project/airportsdata
25
+ :alt: PyPI downloads
26
+ .. |license| image:: https://img.shields.io/pypi/l/airportsdata.svg
27
+ :target: https://pypi.org/project/airportsdata/
28
+ :alt: license
29
+ .. |issues| image:: https://img.shields.io/github/issues-raw/mborsetti/airportsdata
30
+ :target: https://github.com/mborsetti/airportsdata/issues
31
+ :alt: issues
32
+ .. |CI| image:: https://github.com/mborsetti/airportsdata/actions/workflows/ci-cd.yaml/badge.svg?event=push
33
+ :target: https://github.com/mborsetti/airportsdata/actions
34
+ :alt: CI testing status
35
+ .. |coveralls| image:: https://coveralls.io/repos/github/mborsetti/airportsdata/badge.svg?branch=main
36
+ :target: https://coveralls.io/github/mborsetti/airportsdata?branch=main
37
+ :alt: code coverage by Coveralls
38
+ .. |status| image:: https://img.shields.io/pypi/status/airportsdata.svg
39
+ :target: https://pypi.org/project/airportsdata/
40
+ :alt: Package stability
41
+ .. |security| image:: https://img.shields.io/badge/security-bandit-yellow.svg
42
+ :target: https://github.com/PyCQA/bandit
43
+ :alt: Security Status
44
+
45
+ Extensive database of location and timezone data for nearly every operational airport and landing strip in the world,
46
+ with |ICAO| entries.
47
+
48
+ Each entry consists of the following data:
49
+
50
+ * ``icao``: ICAO 4-letter Location Indicator (Doc 7910) or (if none) an internal Pseudo-ICAO Identifier [#]_ (|ICAO|
51
+ entries);
52
+ * ``iata``: IATA 3-letter Location Code (|IATA| entries) or an empty string [#]_;
53
+ * ``name``: Official name (diacritized latin script);
54
+ * ``city``: City (diacritized latin script), ideally using the local language or English;
55
+ * ``subd``: Subdivision (e.g. state, province, region, etc.), ideally using the local-language or English names of
56
+ `ISO 3166-2 <https://en.wikipedia.org/wiki/ISO_3166-2#Current_codes>`__;
57
+ * ``country``: `ISO 3166-1 <https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes>`__ alpha-2 country code
58
+ (plus ``XK`` for Kosovo);
59
+ * ``elevation``: MSL elevation of the highest point of the landing area, in feet (warning: it is often wrong);
60
+ * ``lat``: Latitude (decimal) of the `airport reference point
61
+ <https://en.wikipedia.org/wiki/Airport_reference_point>`__ (max 5 or 6 decimal digits);
62
+ * ``lon``: Longitude (decimal) of the `airport reference point
63
+ <https://en.wikipedia.org/wiki/Airport_reference_point>`__ (max 5 or 6 decimal digits);
64
+ * ``tz``: Timezone expressed as a `tz database name <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>`__
65
+ (IANA-compliant);
66
+ * ``lid``: U.S. FAA Location Identifier (|LID| entries), or an empty string.
67
+
68
+ .. [#] See `here <https://github.com/mborsetti/airportsdata/blob/main/README_identifiers.rst>`__ for an explanation on
69
+ how the Pseudo-ICAO Identifier is generated for airports and seaplane bases without an ICAO 4-letter Location
70
+ Indicator.
71
+
72
+ .. [#] IATA Multi Airport Cities (MAC) are not not airports and therfore not included, but we provide a database and a
73
+ Python function that returns the above data for all the airports of a IATA MAC. Please see documentation `here
74
+ <https://github.com/mborsetti/airportsdata/blob/main/README_IATA.rst>`__.
75
+
76
+ Best efforts are placed to review all contributions for accuracy, but accuracy cannot be guaranteed nor should be
77
+ expected by users.
78
+
79
+ Important notes:
80
+
81
+ * Timezone was originally sourced from `TimeZoneDB <https://timezonedb.com>`__;
82
+ * No historical data (closed airports are removed);
83
+ * No seaplane bases or heliports unless they have a IATA code;
84
+ * No surface transportation stations, even if they have an official IATA code;
85
+ * Airports under construction may be included if they have ICAO and IATA codes and scheduled airline service.
86
+
87
+ Please report any issues you may find `here
88
+ <https://github.com/mborsetti/airportsdata/blob/main/CONTRIBUTING.rst>`__.
89
+
90
+ This project is a fork of `mwgg/Airports <https://github.com/mwgg/Airports>`__. All new data submitted in this fork have
91
+ been validated against national `Aeronautical Information Publications (AIP)
92
+ <https://github.com/mborsetti/airportsdata/blob/main/README_AIP.rst>`__ or equivalent, ARINC database,
93
+ `IATA <https://www.iata.org/en/publications/directories/code-search/>`__ or
94
+ `ch-aviation.com <https://about.ch-aviation.com/airports/>`_ before publishing.
95
+
96
+ Raw data
97
+ ========
98
+
99
+ A CSV (comma separated values) file, with headers and encoded in UTF-8, is downloadable from GitHub `here
100
+ <https://github.com/mborsetti/airportsdata/raw/main/airportsdata/airports.csv>`__.
101
+
102
+ Python
103
+ ======
104
+ |pyversion| |support| |format| |status| |security| |CI| |coveralls| |issues|
105
+
106
+ Install from `PyPi <https://pypi.org/project/airportsdata/>`__ using ``uv`` (recommended):
107
+
108
+ .. code-block:: bash
109
+
110
+ uv pip install --update airportsdata
111
+
112
+ Or, using ``pip``:
113
+
114
+ .. code-block:: bash
115
+
116
+ pip install --update airportsdata
117
+
118
+ Once installed, to load the data into a dict:
119
+
120
+ .. code-block:: python
121
+
122
+ import airportsdata
123
+ icao_airports = airportsdata.load() # key is the ICAO identifier (the default)
124
+ print(icao_airports['KJFK'])
125
+
126
+ or
127
+
128
+ .. code-block:: python
129
+
130
+ import airportsdata
131
+ iata_airports = airportsdata.load('IATA') # key is the IATA location code
132
+ print(iata_airports['JFK'])
133
+
134
+ or
135
+
136
+ .. code-block:: python
137
+
138
+ import airportsdata
139
+ lid_airports = airportsdata.load('LID') # key is the FAA LID
140
+ print(lid_airports['01AA'])
141
+
142
+ Older Python versions are supported for 3 years after being obsoleted by a new major release (i.e. about 4 years
143
+ since their original release).
144
+
145
+ License |license|
146
+ =================
147
+
148
+ Released under the `MIT License <https://opensource.org/licenses/MIT>`__ (see license `here
149
+ <https://github.com/mborsetti/airportsdata/blob/main/LICENSE>`__).
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Extensive database of location and timezone data for nearly every airport and landing strip in the world.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import csv
10
+ from pathlib import Path
11
+ from typing import Dict, Literal, TypedDict
12
+
13
+ __project_name__ = __package__
14
+ __min_python_version__ = (3, 10) # minimum version of Python required to run; supported until October 2025
15
+ __version__ = '2026.03.25' # numbering follows the release date (UTC)
16
+ __author__ = 'Mike Borsetti <mike@borsetti.com>'
17
+ __copyright__ = 'Copyright 2020- Mike Borsetti'
18
+ __license__ = 'MIT'
19
+ __url__ = f'https://github.com/mborsetti/{__project_name__}'
20
+
21
+ Airport = TypedDict(
22
+ 'Airport',
23
+ {
24
+ 'icao': str,
25
+ 'iata': str,
26
+ 'name': str,
27
+ 'city': str,
28
+ 'subd': str,
29
+ 'country': str,
30
+ 'elevation': float,
31
+ 'lat': float,
32
+ 'lon': float,
33
+ 'tz': str,
34
+ 'lid': str,
35
+ },
36
+ )
37
+ CodeType = Literal['ICAO', 'IATA', 'LID']
38
+ IATAMAC = TypedDict('IATAMAC', {'name': str, 'country': str, 'airports': Dict[str, Airport]})
39
+
40
+
41
+ def load(code_type: CodeType = 'ICAO') -> Dict[str, 'Airport']:
42
+ """Loads airport data into a dict
43
+
44
+ :param code_type: optional argument defining the key in the dictionary: 'ICAO' (default if omitted),
45
+ 'IATA' (for IATA Location Codes) or 'LID' (for U.S. FAA Location Identifiers).
46
+
47
+ :return: a dict of dicts, each entry having the following keys:
48
+ 'icao': ICAO 4-letter Location Indicator or 4-alphanumeric FAA/TC LID
49
+ 'iata': IATA 3-letter Location Code or an empty string
50
+ 'name': Official name (diacritized latin script)
51
+ 'city': City
52
+ 'subd': Subdivision (e.g. state, province, region, etc.)
53
+ 'country': ISO 3166-1 alpha 2-code (plus 'XK' for Kosovo)
54
+ 'elevation': MSL elevation (the highest point of the landing area) in feet
55
+ 'lat': Latitude (decimal)
56
+ 'lon': Longitude (decimal)
57
+ 'tz': Timezone expressed as a tz database name (IANA-compliant) or empty string for country 'AQ' (Antarctica).
58
+ Originally sourced from [TimeZoneDB](https://timezonedb.com)
59
+ 'lid': The FAA Location Identifier (for US country only; others is blank)
60
+ """
61
+ key = code_type.lower()
62
+ if key not in ('icao', 'iata', 'lid'):
63
+ raise ValueError(f'code_type must be one of ICAO, IATA or LID; received {code_type}')
64
+ this_dir = Path(__file__).parent
65
+ airports: Dict[str, Airport] = {}
66
+ with this_dir.joinpath('airports.csv').open(encoding='utf8') as f:
67
+ reader = csv.DictReader(f, quoting=csv.QUOTE_NONNUMERIC)
68
+ for row in reader:
69
+ # if row[key] and row[key] in airports:
70
+ # raise ValueError(f"Duplicate key in csv: '{row[key]}'")
71
+ airports[row[key]] = row
72
+ airports.pop('', None)
73
+ return airports
74
+
75
+
76
+ def load_iata_macs() -> dict[str, IATAMAC]:
77
+ """Loads IATA's Multi Airport Cities (for the "purpose of pricing, fare construction and mileage creation")
78
+ data into a dict.
79
+
80
+ :return: a dict of dicts, each entry having the following keys:
81
+ 'name': The IATA city name,
82
+ 'country': The IATA country code,
83
+ 'airports': a dict with the same data returned by load() for each airport that makes up the Multi Airport
84
+ City, where the key is the airport's IATA code.
85
+ """
86
+ airports = load('IATA')
87
+ this_dir = Path(__file__).parent
88
+ iata_macs: dict[str, IATAMAC] = {}
89
+ row_d: dict[str, str]
90
+ multi_airport_city_code = ''
91
+ name = ''
92
+ country = ''
93
+ airport = ''
94
+ with this_dir.joinpath('iata_macs.csv').open(encoding='utf8') as f:
95
+ reader = csv.DictReader(f, quoting=csv.QUOTE_NONNUMERIC)
96
+ for row_d in reader:
97
+ for key, value in row_d.items():
98
+ if key == 'Country':
99
+ country = value
100
+ elif key == 'City Code':
101
+ multi_airport_city_code = value
102
+ elif key == 'City Name':
103
+ name = value
104
+ elif key == 'Airport Code':
105
+ airport = value
106
+ if multi_airport_city_code not in iata_macs:
107
+ iata_macs[multi_airport_city_code] = {
108
+ 'name': name,
109
+ 'country': country,
110
+ 'airports': {airport: airports[airport]},
111
+ }
112
+ else:
113
+ iata_macs[multi_airport_city_code]['airports'][airport] = airports[airport]
114
+ return iata_macs
115
+
116
+
117
+ # Python 3.9 code used to save the dict to CSV:
118
+ # with open('airports.csv', 'w', newline='') as f:
119
+ # fieldnames = airports[list(airports.keys())[0]].keys()
120
+ # writer = csv.DictWriter(f, fieldnames=fieldnames, quoting=csv.QUOTE_NONNUMERIC)
121
+ # writer.writeheader()
122
+ # for data in airports.values():
123
+ # writer.writerow(data)