├── .python-version ├── src └── open_source_aviation │ ├── __init__.py │ └── data.py ├── .gitignore ├── pyproject.toml ├── requirements.lock ├── .github └── workflows │ └── update-metadata.yaml ├── requirements-dev.lock ├── README.md └── LICENSE /.python-version: -------------------------------------------------------------------------------- 1 | 3.12.2 2 | -------------------------------------------------------------------------------- /src/open_source_aviation/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # python generated files 2 | __pycache__/ 3 | *.py[oc] 4 | build/ 5 | dist/ 6 | wheels/ 7 | *.egg-info 8 | 9 | # venv 10 | .venv 11 | 12 | # .env file 13 | .env 14 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "open-source-aviation" 3 | version = "0.1.0" 4 | description = "" 5 | authors = [{ name = "Luciano Scarpulla", email = "scarpulla53@gmail.com" }] 6 | dependencies = [ 7 | "pandas>=2.2.2", 8 | "requests>=2.31.0", 9 | "gitpython>=3.1.43", 10 | "tabulate>=0.9.0", 11 | "python-dotenv>=1.0.1", 12 | ] 13 | readme = "README.md" 14 | requires-python = ">= 3.8" 15 | 16 | 17 | [tool.rye] 18 | managed = true 19 | virtual = true 20 | dev-dependencies = ["ipython>=8.24.0", "isort>=5.13.2"] 21 | -------------------------------------------------------------------------------- /requirements.lock: -------------------------------------------------------------------------------- 1 | # generated by rye 2 | # use `rye lock` or `rye sync` to update this lockfile 3 | # 4 | # last locked with the following flags: 5 | # pre: false 6 | # features: [] 7 | # all-features: false 8 | # with-sources: false 9 | 10 | certifi==2024.2.2 11 | # via requests 12 | charset-normalizer==3.3.2 13 | # via requests 14 | gitdb==4.0.11 15 | # via gitpython 16 | gitpython==3.1.43 17 | idna==3.7 18 | # via requests 19 | numpy==1.26.4 20 | # via pandas 21 | pandas==2.2.2 22 | python-dateutil==2.9.0.post0 23 | # via pandas 24 | python-dotenv==1.0.1 25 | pytz==2024.1 26 | # via pandas 27 | requests==2.31.0 28 | six==1.16.0 29 | # via python-dateutil 30 | smmap==5.0.1 31 | # via gitdb 32 | tabulate==0.9.0 33 | tzdata==2024.1 34 | # via pandas 35 | urllib3==2.2.1 36 | # via requests 37 | -------------------------------------------------------------------------------- /.github/workflows/update-metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Update Metadata 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | schedule: 9 | - cron: "0 8 * * *" 10 | 11 | workflow_dispatch: 12 | 13 | jobs: 14 | run-python: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Set up Python 22 | uses: actions/setup-python@v5 23 | with: 24 | python-version: "3.12" 25 | 26 | - name: Install dependencies 27 | run: | 28 | curl -LsSf https://astral.sh/uv/install.sh | sh 29 | uv pip install -r requirements.lock --system 30 | 31 | - name: Update Tabl 32 | env: 33 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | run: | 35 | git config user.name github-actions[bot] 36 | git config user.email 41898282+github-actions[bot]@users.noreply.github.com 37 | python src/open_source_aviation/data.py 38 | git add README.md 39 | git commit -m "Update Table" 40 | git push 41 | -------------------------------------------------------------------------------- /requirements-dev.lock: -------------------------------------------------------------------------------- 1 | # generated by rye 2 | # use `rye lock` or `rye sync` to update this lockfile 3 | # 4 | # last locked with the following flags: 5 | # pre: false 6 | # features: [] 7 | # all-features: false 8 | # with-sources: false 9 | 10 | asttokens==2.4.1 11 | # via stack-data 12 | certifi==2024.2.2 13 | # via requests 14 | charset-normalizer==3.3.2 15 | # via requests 16 | decorator==5.1.1 17 | # via ipython 18 | executing==2.0.1 19 | # via stack-data 20 | gitdb==4.0.11 21 | # via gitpython 22 | gitpython==3.1.43 23 | idna==3.7 24 | # via requests 25 | ipython==8.24.0 26 | isort==5.13.2 27 | jedi==0.19.1 28 | # via ipython 29 | matplotlib-inline==0.1.7 30 | # via ipython 31 | numpy==1.26.4 32 | # via pandas 33 | pandas==2.2.2 34 | parso==0.8.4 35 | # via jedi 36 | pexpect==4.9.0 37 | # via ipython 38 | prompt-toolkit==3.0.43 39 | # via ipython 40 | ptyprocess==0.7.0 41 | # via pexpect 42 | pure-eval==0.2.2 43 | # via stack-data 44 | pygments==2.18.0 45 | # via ipython 46 | python-dateutil==2.9.0.post0 47 | # via pandas 48 | python-dotenv==1.0.1 49 | pytz==2024.1 50 | # via pandas 51 | requests==2.31.0 52 | six==1.16.0 53 | # via asttokens 54 | # via python-dateutil 55 | smmap==5.0.1 56 | # via gitdb 57 | stack-data==0.6.3 58 | # via ipython 59 | tabulate==0.9.0 60 | traitlets==5.14.3 61 | # via ipython 62 | # via matplotlib-inline 63 | tzdata==2024.1 64 | # via pandas 65 | urllib3==2.2.1 66 | # via requests 67 | wcwidth==0.2.13 68 | # via prompt-toolkit 69 | -------------------------------------------------------------------------------- /src/open_source_aviation/data.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os 3 | import re 4 | from abc import ABC, abstractmethod 5 | from collections import namedtuple 6 | from pathlib import Path 7 | from typing import Iterable 8 | 9 | import pandas as pd 10 | import requests 11 | from dotenv import load_dotenv 12 | from git import Repo 13 | 14 | load_dotenv() 15 | 16 | GH_TOKEN = os.getenv("GH_TOKEN") 17 | 18 | FileInfo = namedtuple("FileInfo", ("name", "last_modified", "row_count")) 19 | 20 | 21 | class BaseData(ABC): 22 | def __init__(self, file: str): 23 | self.file = file 24 | 25 | @property 26 | @abstractmethod 27 | def pattern(self) -> str: 28 | return "" 29 | 30 | def get_links(self) -> Iterable[str]: 31 | for line in self.file.splitlines(): 32 | if url := re.match(self.pattern, line): 33 | yield url.group(1) 34 | 35 | @abstractmethod 36 | def get_last_modified(self, url: str) -> datetime.datetime | None: ... 37 | 38 | @abstractmethod 39 | def get_info(self) -> Iterable[FileInfo]: ... 40 | 41 | 42 | def validate_git_file_path(url: str) -> str: 43 | a, b = url.split("/")[-2:] 44 | if a in ("master", "main"): 45 | return b 46 | else: 47 | return f"{a}/{b}" 48 | 49 | 50 | class GitHubData(BaseData): 51 | def _get_gh_link(self, url: str) -> re.Match[str] | None: 52 | groups = r"(?Phttps:.+\/.+\.com\/)(?P\w+)\/(?P\w+(-)?\w+?)\/" 53 | return re.match(groups, url) 54 | 55 | def get_last_modified(self, url: str) -> datetime.datetime | None: 56 | if match := self._get_gh_link(url): 57 | match = match.groupdict() 58 | user, repo = match.get("user"), match.get("repo") 59 | file = validate_git_file_path(url) 60 | api_url = f"https://api.github.com/repos/{user}/{repo}/commits?path={file}" 61 | headers = {"Authorization": f"Bearer {GH_TOKEN}"} 62 | res = requests.get(api_url, headers=headers if GH_TOKEN else None) 63 | if res.status_code == 200: 64 | return datetime.datetime.fromisoformat( 65 | res.json()[0]["commit"]["author"]["date"] 66 | ) 67 | else: 68 | print(f"got {res.status_code}: {res.text}") 69 | 70 | def read(self) -> Iterable[pd.DataFrame]: 71 | for url in self.get_links(): 72 | yield self.get_last_modified(url).date() 73 | 74 | def get_info(self) -> Iterable[FileInfo]: 75 | for url in self.get_links(): 76 | filename = url.split("/")[-1] 77 | file_markdown = f"[{filename}]({url})" 78 | last_modified = self.get_last_modified(url) 79 | row_count = len(pd.read_csv(url)) 80 | 81 | yield FileInfo(file_markdown, last_modified, row_count) 82 | 83 | 84 | class GitHubCSVData(GitHubData): 85 | pattern = r".+(https://raw.+/.+\.csv)" 86 | 87 | 88 | class GitHubDatData(GitHubData): 89 | pattern = r".+(https://raw.+/.+\.dat)" 90 | 91 | 92 | if __name__ == "__main__": 93 | readme = Path.cwd() / "README.md" 94 | f = readme.read_text() 95 | pattern = r"(.*?)(?=\n# Data Metadata)" 96 | f = re.search(pattern, f, re.DOTALL) 97 | f = f.group(0) 98 | 99 | datas = [GitHubCSVData(f), GitHubDatData(f)] 100 | df = pd.concat( 101 | [ 102 | pd.DataFrame(data.get_info()).sort_values( 103 | "last_modified", ascending=False 104 | ) 105 | for data in datas 106 | ], 107 | axis=0, 108 | ) 109 | df["last_modified"] = df.last_modified.dt.strftime("%F %T") 110 | df["row_count"] = df.row_count.apply(lambda x: f"{x:,}") 111 | 112 | push = False 113 | 114 | # Updating Metadata Table on README.md 115 | with open(readme, "r+") as f: 116 | line = f.readline() 117 | while line: 118 | if line == "# Data Metadata\n": 119 | pos = f.tell() 120 | f.truncate(pos) 121 | f.seek(pos) 122 | f.write("\n" + df.to_markdown(index=False)) 123 | print("will push") 124 | push = True 125 | break 126 | line = f.readline() 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open-source Aviation ✈️📈 2 | A list of open-source aviation projects and data. 3 | 4 | > [!NOTE] 5 | > Still work-in-progress, feel free to fork and contribute! 6 | 7 | ## Content 8 | * [ADS-B Data](#ads-b-data) 9 | * [Airport Data](#airport-data) 10 | * [Weather Data](#weather-data) 11 | * [OSINT](#osint) 12 | * [Tools and Libraries](#tools-and-libraries) 13 | * [Other Lists](#other-lists) 14 | 15 | 16 | ## ADS-B Data 17 | * [ADS-B Exchange](https://www.adsbexchange.com/) - Community-driven ADS-B network, offers free sample data and freemium Rest APIs 18 | 19 | 20 | ## Airport Data 21 | #### [OurAirports.com](https://ourairports.com/) 22 | * [ourairports.com](https://ourairports.com/) - Community-driven airport database which includes geo coordinates, airport names and more. 23 | * [airports.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/airports.csv) - Raw CSV file of OurAirports.com, 78K+ airports 24 | * [runways.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/runways.csv) - Runways information. Including length, width, altitude and more. 25 | * [airport-frequencies.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/airport-frequencies.csv) - MHZ Airport Frequencies. 26 | * [countries.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/countries.csv) - Additional Country data 27 | * [regions.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/regions.csv) - Additional Region Data 28 | * [navaids.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/navaids.csv) 29 | * [airport-comments.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/airport-comments.csv) - Community comments 30 | 31 | #### [openflights.org](https://openflights.org/) 32 | * [airports.dat](https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports.dat) - Airport data, might be outdated 33 | * [airports-extended.dat](https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports-extended.dat) - Airports, train stations and ferry terminals, including user contributions 34 | * [airlines.dat](https://raw.githubusercontent.com/jpatokal/openflights/master/data/airlines.dat) 35 | * [routes.dat](https://raw.githubusercontent.com/jpatokal/openflights/master/data/routes.dat) 36 | 37 | #### [aviowiki](https://aviowiki.com/) 38 | * [free_airports.json.zip](https://exports.aviowiki.com/free_airports.json.zip) - 32K structured airport data 39 | 40 | ## Weather Data 41 | 42 | * [NOAA's METAR](https://tgftp.nws.noaa.gov/data/observations/metar/stations/) - Up-to-date METARs, for a specific station you can add the {ICAO}.TXT at the end of the url (e.g. [EGLL](https://tgftp.nws.noaa.gov/data/observations/metar/stations/EGLL.TXT)) 43 | * [AVWX-Engine](https://github.com/avwx-rest/avwx-engine) - Aviation Weather parsing engine. METAR & TAF 44 | 45 | ## OSINT 46 | * [skytrack](https://github.com/ANG13T/skytrack) - A planespotting and aircraft OSINT tool made using Python 47 | 48 | ## Tools and Libraries 49 | * [traffic-viz](https://github.com/xoolive/traffic) - A toolbox for processing and analysing air traffic data 50 | * [pitot](https://github.com/open-aviation/pitot) - A toolbox for aeronautic calculations 51 | * [openap-top](https://github.com/junzis/openap-top) - Open flight trajectory optimizer built with non-linear optimal control method 52 | 53 | ## Sims 54 | * [AirTrafficSim](https://github.com/HKUST-OCTAD-LAB/AirTrafficSim) - Web-based air traffic simulation and visualization platform for ATM research. 55 | 56 | ## Other Lists 57 | * [awesome-flying](https://github.com/bauidch/awesome-flying) - A curated list of flying/aviation tools 58 | 59 | ---- 60 | 61 | # Data Metadata 62 | 63 | | name | last_modified | row_count | 64 | |:--------------------------------------------------------------------------------------------------------------------------|:--------------------|:------------| 65 | | [airports.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/airports.csv) | 2025-12-21 02:53:11 | 84,307 | 66 | | [runways.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/runways.csv) | 2025-12-21 02:53:11 | 47,406 | 67 | | [airport-comments.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/airport-comments.csv) | 2025-12-18 02:53:11 | 15,646 | 68 | | [airport-frequencies.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/airport-frequencies.csv) | 2025-12-15 02:53:11 | 30,191 | 69 | | [regions.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/regions.csv) | 2025-11-28 15:04:50 | 3,942 | 70 | | [navaids.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/navaids.csv) | 2025-03-02 02:53:11 | 11,010 | 71 | | [countries.csv](https://raw.githubusercontent.com/davidmegginson/ourairports-data/main/countries.csv) | 2025-02-28 02:53:11 | 249 | 72 | | [airports.dat](https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports.dat) | 2019-05-13 11:54:02 | 7,697 | 73 | | [airports-extended.dat](https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports-extended.dat) | 2019-05-13 11:54:02 | 12,667 | 74 | | [airlines.dat](https://raw.githubusercontent.com/jpatokal/openflights/master/data/airlines.dat) | 2017-02-02 11:32:12 | 6,161 | 75 | | [routes.dat](https://raw.githubusercontent.com/jpatokal/openflights/master/data/routes.dat) | 2017-02-02 11:32:12 | 67,662 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | --------------------------------------------------------------------------------