pyopensky 2.10__tar.gz → 2.12__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.
- pyopensky-2.12/.github/dependabot.yml +11 -0
- pyopensky-2.12/.github/renovate.json5 +6 -0
- pyopensky-2.12/.github/workflows/build-docs.yml +56 -0
- pyopensky-2.12/.github/workflows/pypi_publish.yml +39 -0
- pyopensky-2.12/.github/workflows/run_tests.yml +82 -0
- {pyopensky-2.10 → pyopensky-2.12}/PKG-INFO +2 -2
- pyopensky-2.12/docs/.gitignore +1 -0
- pyopensky-2.12/docs/Makefile +20 -0
- pyopensky-2.12/docs/make.bat +35 -0
- pyopensky-2.12/docs/source/_static/main_stylesheet.css +17 -0
- pyopensky-2.12/docs/source/api_reference.rst +8 -0
- pyopensky-2.12/docs/source/conf.py +47 -0
- pyopensky-2.12/docs/source/credentials.rst +65 -0
- pyopensky-2.12/docs/source/index.rst +30 -0
- pyopensky-2.12/docs/source/installation.rst +27 -0
- pyopensky-2.12/docs/source/rest.rst +8 -0
- pyopensky-2.12/docs/source/trino.rst +8 -0
- {pyopensky-2.10 → pyopensky-2.12}/pyproject.toml +2 -4
- pyopensky-2.12/scripts/decode_pymodes.py +89 -0
- pyopensky-2.12/scripts/decode_rs1090.py +31 -0
- pyopensky-2.12/src/pyopensky/__init__.py +13 -0
- pyopensky-2.12/src/pyopensky/api.py +76 -0
- pyopensky-2.12/src/pyopensky/config.py +210 -0
- pyopensky-2.12/src/pyopensky/rest.py +499 -0
- pyopensky-2.12/src/pyopensky/s3.py +157 -0
- pyopensky-2.12/src/pyopensky/schema.py +530 -0
- pyopensky-2.12/src/pyopensky/time.py +46 -0
- pyopensky-2.12/src/pyopensky/trino.py +981 -0
- pyopensky-2.12/src/pyopensky/tzdata.py +48 -0
- pyopensky-2.12/tests/test_rest.py +8 -0
- pyopensky-2.12/tests/test_s3.py +28 -0
- pyopensky-2.12/tests/test_trino.py +326 -0
- pyopensky-2.12/tests/test_tzdata.py +13 -0
- pyopensky-2.12/uv.lock +3233 -0
- {pyopensky-2.10 → pyopensky-2.12}/.gitignore +0 -0
- {pyopensky-2.10 → pyopensky-2.12}/license.txt +0 -0
- {pyopensky-2.10 → pyopensky-2.12}/readme.md +0 -0
- {pyopensky-2.10 → pyopensky-2.12}/src/pyopensky/py.typed +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
documentation:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
env:
|
|
14
|
+
PYTHON_VERSION: "3.12"
|
|
15
|
+
UV_CACHE_DIR: /tmp/.uv-cache
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
|
|
22
|
+
- name: Set up uv
|
|
23
|
+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
24
|
+
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
- name: Cache folder for uv
|
|
32
|
+
uses: actions/cache@v4
|
|
33
|
+
with:
|
|
34
|
+
path: /tmp/.uv-cache
|
|
35
|
+
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
|
36
|
+
restore-keys: |
|
|
37
|
+
uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
|
38
|
+
uv-${{ runner.os }}
|
|
39
|
+
|
|
40
|
+
- name: Install dependencies
|
|
41
|
+
run: |
|
|
42
|
+
uv sync --all-extras --dev
|
|
43
|
+
|
|
44
|
+
- name: Build pages
|
|
45
|
+
working-directory: docs
|
|
46
|
+
run: |
|
|
47
|
+
uv run make html
|
|
48
|
+
|
|
49
|
+
- name: Minimize uv cache
|
|
50
|
+
run: uv cache prune --ci
|
|
51
|
+
|
|
52
|
+
- name: Deploy pages
|
|
53
|
+
uses: peaceiris/actions-gh-pages@v4
|
|
54
|
+
with:
|
|
55
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
56
|
+
publish_dir: docs/build/html
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
deploy:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Set up uv
|
|
15
|
+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
|
|
20
|
+
- name: Cache folder for uv
|
|
21
|
+
uses: actions/cache@v4
|
|
22
|
+
with:
|
|
23
|
+
path: /tmp/.uv-cache
|
|
24
|
+
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
|
25
|
+
restore-keys: |
|
|
26
|
+
uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
|
27
|
+
uv-${{ runner.os }}
|
|
28
|
+
|
|
29
|
+
- name: Build packages
|
|
30
|
+
run: uvx hatch build
|
|
31
|
+
|
|
32
|
+
- name: Minimize uv cache
|
|
33
|
+
run: uv cache prune --ci
|
|
34
|
+
|
|
35
|
+
- name: Publish a Python distribution to PyPI
|
|
36
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
37
|
+
with:
|
|
38
|
+
user: __token__
|
|
39
|
+
password: ${{ secrets.PYPI_PASSWORD }}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request_target:
|
|
6
|
+
schedule: # This is useful for keeping the cache fit and ready
|
|
7
|
+
- cron: "42 3 * * 0" # Every Sunday morning when I am fast asleep :)
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
deploy:
|
|
12
|
+
name: python-${{ matrix.python-version }} on ${{ matrix.os }}
|
|
13
|
+
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
os:
|
|
17
|
+
- ubuntu-latest
|
|
18
|
+
- windows-latest
|
|
19
|
+
- macos-latest
|
|
20
|
+
python-version:
|
|
21
|
+
- "3.9"
|
|
22
|
+
- "3.10"
|
|
23
|
+
- "3.11"
|
|
24
|
+
- "3.12"
|
|
25
|
+
- "3.13"
|
|
26
|
+
|
|
27
|
+
fail-fast: false
|
|
28
|
+
|
|
29
|
+
runs-on: ${{ matrix.os }}
|
|
30
|
+
|
|
31
|
+
env:
|
|
32
|
+
UV_CACHE_DIR: /tmp/.uv-cache
|
|
33
|
+
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
with:
|
|
37
|
+
fetch-depth: 0
|
|
38
|
+
|
|
39
|
+
- name: Set up uv
|
|
40
|
+
if: ${{ matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' }}
|
|
41
|
+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
42
|
+
|
|
43
|
+
- name: Set up uv
|
|
44
|
+
if: ${{ matrix.os == 'windows-latest' }}
|
|
45
|
+
run: irm https://astral.sh/uv/install.ps1 | iex
|
|
46
|
+
shell: powershell
|
|
47
|
+
|
|
48
|
+
- name: Cache folder for uv
|
|
49
|
+
uses: actions/cache@v4
|
|
50
|
+
with:
|
|
51
|
+
path: /tmp/.uv-cache
|
|
52
|
+
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
|
53
|
+
restore-keys: |
|
|
54
|
+
uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
|
55
|
+
uv-${{ runner.os }}
|
|
56
|
+
|
|
57
|
+
- name: Cache folder for data
|
|
58
|
+
uses: actions/cache@v4
|
|
59
|
+
id: cache-folder
|
|
60
|
+
with:
|
|
61
|
+
path: |
|
|
62
|
+
${{ github.workspace }}/cache_opensky
|
|
63
|
+
key: opensky-${{ runner.os }}-${{ hashFiles('uv.lock') }}
|
|
64
|
+
|
|
65
|
+
- name: Install the project
|
|
66
|
+
run: uv sync --all-extras --dev --python ${{ matrix.python-version }}
|
|
67
|
+
|
|
68
|
+
- name: Linting and formatting
|
|
69
|
+
run: |
|
|
70
|
+
uv run ruff check
|
|
71
|
+
uv run ruff format --check
|
|
72
|
+
|
|
73
|
+
- name: Run tests
|
|
74
|
+
if: ${{ matrix.python-version == '3.12' || steps.cache-folder.outputs.cache-hit == 'true' }}
|
|
75
|
+
env:
|
|
76
|
+
OPENSKY_USERNAME: ${{ secrets.OPENSKY_USERNAME }}
|
|
77
|
+
OPENSKY_PASSWORD: ${{ secrets.OPENSKY_PASSWORD }}
|
|
78
|
+
OPENSKY_CACHE: ${{ github.workspace }}/cache_opensky
|
|
79
|
+
run: uv run pytest
|
|
80
|
+
|
|
81
|
+
- name: Minimize uv cache
|
|
82
|
+
run: uv cache prune --ci
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: pyopensky
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.12
|
|
4
4
|
Summary: A Python interface for OpenSky database
|
|
5
5
|
Project-URL: Repository, https://github.com/open-aviation/pyopensky/
|
|
6
6
|
Author-email: Xavier Olive <git@xoolive.org>, Junzi Sun <j.sun-1@tudelft.nl>
|
|
7
|
-
License-Expression: MIT
|
|
8
7
|
Requires-Python: >=3.9
|
|
9
8
|
Requires-Dist: appdirs>=1.4.4
|
|
10
9
|
Requires-Dist: httpx>=0.27.2
|
|
@@ -15,6 +14,7 @@ Requires-Dist: pyjwt>=2.9.0
|
|
|
15
14
|
Requires-Dist: tqdm>=4.66.5
|
|
16
15
|
Requires-Dist: trino[sqlalchemy]>=0.329.0
|
|
17
16
|
Requires-Dist: typing-extensions>=4.12.2
|
|
17
|
+
Requires-Dist: tzdata>=2024.2
|
|
18
18
|
Provides-Extra: cartes
|
|
19
19
|
Requires-Dist: cartes>=0.8.1; extra == 'cartes'
|
|
20
20
|
Provides-Extra: decoding
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
build/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Minimal makefile for Sphinx documentation
|
|
2
|
+
#
|
|
3
|
+
|
|
4
|
+
# You can set these variables from the command line, and also
|
|
5
|
+
# from the environment for the first two.
|
|
6
|
+
SPHINXOPTS ?=
|
|
7
|
+
SPHINXBUILD ?= sphinx-build
|
|
8
|
+
SOURCEDIR = source
|
|
9
|
+
BUILDDIR = build
|
|
10
|
+
|
|
11
|
+
# Put it first so that "make" without argument is like "make help".
|
|
12
|
+
help:
|
|
13
|
+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
14
|
+
|
|
15
|
+
.PHONY: help Makefile
|
|
16
|
+
|
|
17
|
+
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
18
|
+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
19
|
+
%: Makefile
|
|
20
|
+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
@ECHO OFF
|
|
2
|
+
|
|
3
|
+
pushd %~dp0
|
|
4
|
+
|
|
5
|
+
REM Command file for Sphinx documentation
|
|
6
|
+
|
|
7
|
+
if "%SPHINXBUILD%" == "" (
|
|
8
|
+
set SPHINXBUILD=sphinx-build
|
|
9
|
+
)
|
|
10
|
+
set SOURCEDIR=source
|
|
11
|
+
set BUILDDIR=build
|
|
12
|
+
|
|
13
|
+
%SPHINXBUILD% >NUL 2>NUL
|
|
14
|
+
if errorlevel 9009 (
|
|
15
|
+
echo.
|
|
16
|
+
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
|
17
|
+
echo.installed, then set the SPHINXBUILD environment variable to point
|
|
18
|
+
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
|
19
|
+
echo.may add the Sphinx directory to PATH.
|
|
20
|
+
echo.
|
|
21
|
+
echo.If you don't have Sphinx installed, grab it from
|
|
22
|
+
echo.https://www.sphinx-doc.org/
|
|
23
|
+
exit /b 1
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
if "%1" == "" goto help
|
|
27
|
+
|
|
28
|
+
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
29
|
+
goto end
|
|
30
|
+
|
|
31
|
+
:help
|
|
32
|
+
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
33
|
+
|
|
34
|
+
:end
|
|
35
|
+
popd
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
a.reference code.literal span {
|
|
2
|
+
font-family: Lato, proxima-nova, Helvetica Neue, Arial, sans-serif;
|
|
3
|
+
font-size: 16px;
|
|
4
|
+
font-weight: 500;
|
|
5
|
+
color: #2980b9;
|
|
6
|
+
}
|
|
7
|
+
.rst-content .document a {
|
|
8
|
+
text-decoration: underline;
|
|
9
|
+
text-underline-offset: 2pt;
|
|
10
|
+
}
|
|
11
|
+
.rst-content .document a code {
|
|
12
|
+
padding: 0
|
|
13
|
+
}
|
|
14
|
+
.rst-content code {
|
|
15
|
+
border: none;
|
|
16
|
+
background: none;
|
|
17
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
# Configuration file for the Sphinx documentation builder.
|
|
4
|
+
#
|
|
5
|
+
# For the full list of built-in configuration values, see the documentation:
|
|
6
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
7
|
+
import pyopensky
|
|
8
|
+
|
|
9
|
+
# -- Project information -----------------------------------------------------
|
|
10
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
11
|
+
|
|
12
|
+
project = "pyopensky"
|
|
13
|
+
copyright = "2023, Xavier Olive, Junzi Sun"
|
|
14
|
+
author = "Xavier Olive, Junzi Sun"
|
|
15
|
+
release = pyopensky.__version__
|
|
16
|
+
|
|
17
|
+
# -- General configuration ---------------------------------------------------
|
|
18
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
19
|
+
|
|
20
|
+
extensions = [
|
|
21
|
+
"sphinx.ext.autodoc",
|
|
22
|
+
"sphinx.ext.autosectionlabel",
|
|
23
|
+
"sphinx.ext.githubpages",
|
|
24
|
+
"sphinx.ext.intersphinx",
|
|
25
|
+
"sphinx_autodoc_typehints",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
templates_path = ["_templates"]
|
|
29
|
+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# -- Options for HTML output -------------------------------------------------
|
|
33
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
|
34
|
+
|
|
35
|
+
html_theme = "sphinx_rtd_theme"
|
|
36
|
+
html_static_path = ["_static"]
|
|
37
|
+
|
|
38
|
+
intersphinx_mapping = {
|
|
39
|
+
"python": ("https://docs.python.org/3", None),
|
|
40
|
+
"pandas": ("https://pandas.pydata.org/pandas-docs/dev", None),
|
|
41
|
+
"traffic": ("https://traffic-viz.github.io", None),
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def setup(app: Any) -> None:
|
|
46
|
+
# Specific stylesheet
|
|
47
|
+
app.add_css_file("main_stylesheet.css")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Credentials
|
|
2
|
+
===========
|
|
3
|
+
|
|
4
|
+
Apply for access
|
|
5
|
+
----------------
|
|
6
|
+
|
|
7
|
+
Access to the Trino database will be granted provided you meet the `conditions
|
|
8
|
+
defined by The OpenSky Network <https://opensky-network.org/about/faq#q5>`_. Please create an account on
|
|
9
|
+
https://trino.opensky-network.org, and then apply at https://opensky-network.org/data/apply
|
|
10
|
+
with your Trino username to request for activation.
|
|
11
|
+
|
|
12
|
+
Configuration
|
|
13
|
+
-------------
|
|
14
|
+
|
|
15
|
+
The first time you use the library, a configuration file named ``settings.conf``
|
|
16
|
+
is created, including the following content:
|
|
17
|
+
|
|
18
|
+
.. code::
|
|
19
|
+
|
|
20
|
+
[default]
|
|
21
|
+
username =
|
|
22
|
+
password =
|
|
23
|
+
|
|
24
|
+
If you use the same login for the OpenSky website (therefore the REST API) and
|
|
25
|
+
for Trino (it will be unified one day), just fill it here.
|
|
26
|
+
|
|
27
|
+
You will identify the folder where the ``settings.conf`` file is located:
|
|
28
|
+
|
|
29
|
+
.. code:: python
|
|
30
|
+
|
|
31
|
+
from pyopensky.config import opensky_config_dir
|
|
32
|
+
|
|
33
|
+
print(opensky_config_dir)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
Different credentials per service
|
|
37
|
+
---------------------------------
|
|
38
|
+
|
|
39
|
+
If you want to specify different credentials for the REST API and for the Trino
|
|
40
|
+
database, use the following sections in the configuration file.
|
|
41
|
+
|
|
42
|
+
.. code::
|
|
43
|
+
|
|
44
|
+
[opensky] # REST API
|
|
45
|
+
username =
|
|
46
|
+
password =
|
|
47
|
+
|
|
48
|
+
[trino] # Trino database
|
|
49
|
+
username =
|
|
50
|
+
password =
|
|
51
|
+
|
|
52
|
+
If these sections are commented, the library will use the credentials from the
|
|
53
|
+
[default] section.
|
|
54
|
+
|
|
55
|
+
Fallback configuration
|
|
56
|
+
----------------------
|
|
57
|
+
|
|
58
|
+
If no username and password are specified in the `pyopensky` configuration file, the
|
|
59
|
+
following steps are performed in order:
|
|
60
|
+
|
|
61
|
+
- try to get the credentials from the `traffic <https://traffic-viz.github.io>`_
|
|
62
|
+
configuration file;
|
|
63
|
+
- get the credentials from ``$OPENSKY_USERNAME`` and ``$OPENSKY_PASSWORD``
|
|
64
|
+
environment variables;
|
|
65
|
+
- open a browser and log in on a dedicated webpage.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
pyopensky
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
.. toctree::
|
|
5
|
+
:maxdepth: 2
|
|
6
|
+
:caption: Contents:
|
|
7
|
+
|
|
8
|
+
Source code on `github <https://github.com/open-aviation/pyopensky>`_
|
|
9
|
+
|
|
10
|
+
The pyopensky library provides function to easily download data from
|
|
11
|
+
`The OpenSky Network <https://opensky-network.org/>`_ databases. This minimal
|
|
12
|
+
library is ideal for quickly downloading and locally saving data that you will
|
|
13
|
+
use in your future studies. All functions return pandas :class:`~pandas.DataFrame`.
|
|
14
|
+
|
|
15
|
+
.. hint::
|
|
16
|
+
|
|
17
|
+
If Python is your language of choice in general, and you are interested in
|
|
18
|
+
analysing aircraft trajectories, please refer to the following `section in
|
|
19
|
+
the traffic <https://traffic-viz.github.io/data_sources/opensky_db.html>`_
|
|
20
|
+
library. traffic wraps the same pyopensky queries and returns
|
|
21
|
+
:class:`~traffic.core.Traffic` and :class:`~traffic.core.Flight` objects.
|
|
22
|
+
|
|
23
|
+
.. toctree::
|
|
24
|
+
:maxdepth: 2
|
|
25
|
+
:caption: Contents
|
|
26
|
+
|
|
27
|
+
installation
|
|
28
|
+
credentials
|
|
29
|
+
api_reference
|
|
30
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Installation
|
|
2
|
+
============
|
|
3
|
+
|
|
4
|
+
pyopensky is available through pip:
|
|
5
|
+
|
|
6
|
+
.. code::
|
|
7
|
+
|
|
8
|
+
pip install pyopensky
|
|
9
|
+
|
|
10
|
+
The library is also available on conda-forge:
|
|
11
|
+
|
|
12
|
+
.. code::
|
|
13
|
+
|
|
14
|
+
conda install -c conda-forge pyopensky
|
|
15
|
+
|
|
16
|
+
Development mode (with uv):
|
|
17
|
+
|
|
18
|
+
.. code::
|
|
19
|
+
|
|
20
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # Linux and MacOS
|
|
21
|
+
irm https://astral.sh/uv/install.ps1 | iex # Windows
|
|
22
|
+
uv sync --dev
|
|
23
|
+
|
|
24
|
+
.. hint::
|
|
25
|
+
|
|
26
|
+
pyopensky is automatically installed as a dependency of the `traffic
|
|
27
|
+
<https://traffic-viz.github.io>`_ library.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pyopensky"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.12"
|
|
4
4
|
description = "A Python interface for OpenSky database"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Xavier Olive", email = "git@xoolive.org" },
|
|
@@ -19,6 +19,7 @@ dependencies = [
|
|
|
19
19
|
"tqdm >= 4.66.5",
|
|
20
20
|
"trino[sqlalchemy] >= 0.329.0",
|
|
21
21
|
"typing-extensions >= 4.12.2",
|
|
22
|
+
"tzdata>=2024.2",
|
|
22
23
|
]
|
|
23
24
|
|
|
24
25
|
[project.urls]
|
|
@@ -32,9 +33,6 @@ decoding = ["pymodes>=2.18", "rs1090>=0.3.8"]
|
|
|
32
33
|
requires = ["hatchling"]
|
|
33
34
|
build-backend = "hatchling.build"
|
|
34
35
|
|
|
35
|
-
[tool.hatch.build.targets.sdist]
|
|
36
|
-
include = ["license.txt", "py.typed"]
|
|
37
|
-
|
|
38
36
|
[tool.uv]
|
|
39
37
|
dev-dependencies = [
|
|
40
38
|
"pre-commit >= 3.8.0",
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import pyModeS as pms
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def decode_row(row: pd.Series) -> dict[str, Any]:
|
|
11
|
+
bds = row["bds"]
|
|
12
|
+
msg = row["rawmsg"]
|
|
13
|
+
|
|
14
|
+
decoded = {
|
|
15
|
+
"time": row["mintime"],
|
|
16
|
+
"icao24": row["icao24"],
|
|
17
|
+
"bds": bds,
|
|
18
|
+
"rawmsg": row["rawmsg"],
|
|
19
|
+
"altitude": row["altitude"],
|
|
20
|
+
"squawk": row["squawk"],
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if bds == "BDS40":
|
|
24
|
+
selalt40mcp = pms.commb.selalt40mcp(msg)
|
|
25
|
+
selalt40fms = pms.commb.selalt40fms(msg)
|
|
26
|
+
p40baro = pms.commb.p40baro(msg)
|
|
27
|
+
|
|
28
|
+
decoded.update(
|
|
29
|
+
{
|
|
30
|
+
"selalt40mcp": selalt40mcp,
|
|
31
|
+
"selalt40fms": selalt40fms,
|
|
32
|
+
"p40baro": p40baro,
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if bds == "BDS50":
|
|
37
|
+
roll50 = pms.commb.roll50(msg)
|
|
38
|
+
trk50 = pms.commb.trk50(msg)
|
|
39
|
+
rtrk50 = pms.commb.rtrk50(msg)
|
|
40
|
+
gs50 = pms.commb.gs50(msg)
|
|
41
|
+
tas50 = pms.commb.tas50(msg)
|
|
42
|
+
|
|
43
|
+
decoded.update(
|
|
44
|
+
{
|
|
45
|
+
"roll50": roll50,
|
|
46
|
+
"trk50": trk50,
|
|
47
|
+
"rtrk50": rtrk50,
|
|
48
|
+
"gs50": gs50,
|
|
49
|
+
"tas50": tas50,
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if bds == "BDS60":
|
|
54
|
+
ias60 = pms.commb.ias60(msg)
|
|
55
|
+
hdg60 = pms.commb.hdg60(msg)
|
|
56
|
+
mach60 = pms.commb.mach60(msg)
|
|
57
|
+
vr60baro = pms.commb.vr60baro(msg)
|
|
58
|
+
vr60ins = pms.commb.vr60ins(msg)
|
|
59
|
+
|
|
60
|
+
decoded.update(
|
|
61
|
+
{
|
|
62
|
+
"ias60": ias60,
|
|
63
|
+
"hdg60": hdg60,
|
|
64
|
+
"mach60": mach60,
|
|
65
|
+
"vr60baro": vr60baro,
|
|
66
|
+
"vr60ins": vr60ins,
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
return decoded
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def decode(df: pd.DataFrame) -> pd.DataFrame:
|
|
73
|
+
commb = (
|
|
74
|
+
df.assign(DF=lambda df: df["rawmsg"].apply(pms.df))
|
|
75
|
+
.query("DF in [20, 21]")
|
|
76
|
+
.assign(bds=lambda df: df["rawmsg"].apply(pms.bds.infer))
|
|
77
|
+
.query('bds in ["BDS40", "BDS50", "BDS60"]')
|
|
78
|
+
.drop_duplicates(["icao24", "mintime"])
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
altcode = commb.loc[commb.DF == 20, "rawmsg"].apply(pms.altcode)
|
|
82
|
+
commb.loc[commb.DF == 20, "altitude"] = altcode
|
|
83
|
+
|
|
84
|
+
idcode = commb.loc[commb.DF == 21, "rawmsg"].apply(pms.idcode)
|
|
85
|
+
commb.loc[commb.DF == 21, "squawk"] = idcode
|
|
86
|
+
|
|
87
|
+
return pd.DataFrame.from_records(
|
|
88
|
+
decode_row(row) for _i, row in commb.sort_values("mintime").iterrows()
|
|
89
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# ruff: noqa: E741
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import rs1090
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
if sys.version_info < (3, 12):
|
|
10
|
+
from typing import Iterator, Tuple, TypeVar
|
|
11
|
+
|
|
12
|
+
T = TypeVar("T", covariant=True)
|
|
13
|
+
|
|
14
|
+
def batched(
|
|
15
|
+
iterable: Iterator[Tuple[T, ...]], n: int = 1
|
|
16
|
+
) -> Iterator[Tuple[T, ...]]:
|
|
17
|
+
l = len(iterable) # type: ignore
|
|
18
|
+
for ndx in range(0, l, n):
|
|
19
|
+
yield iterable[ndx : min(ndx + n, l)] # type: ignore
|
|
20
|
+
|
|
21
|
+
else:
|
|
22
|
+
from itertools import batched
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def decode(df: pd.DataFrame) -> pd.DataFrame:
|
|
26
|
+
decoded = rs1090.decode(df["rawmsg"], df["mintime"])
|
|
27
|
+
|
|
28
|
+
# 5000 is (empirically) the fastest batch size I found
|
|
29
|
+
df = pd.concat(pd.DataFrame.from_records(d) for d in batched(decoded, 5000))
|
|
30
|
+
df = df.assign(timestamp=pd.to_datetime(df.timestamp, unit="s", utc=True))
|
|
31
|
+
return df
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from importlib.metadata import version
|
|
3
|
+
|
|
4
|
+
from .tzdata import download_tzdata_windows
|
|
5
|
+
|
|
6
|
+
__version__ = version("pyopensky")
|
|
7
|
+
|
|
8
|
+
# Despite the 'win32' string, this value is returned on all versions of Windows,
|
|
9
|
+
# including both 32-bit and 64-bit. The 'win32' identifier is a historical
|
|
10
|
+
# artifact that has been retained for compatibility with older versions of
|
|
11
|
+
# Python.
|
|
12
|
+
if sys.platform == "win32":
|
|
13
|
+
download_tzdata_windows(year=2022)
|