pyopensky 2.15__tar.gz → 2.17__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.
Files changed (54) hide show
  1. pyopensky-2.17/.gitattributes +4 -0
  2. {pyopensky-2.15 → pyopensky-2.17}/.github/workflows/build-docs.yml +3 -3
  3. {pyopensky-2.15 → pyopensky-2.17}/.github/workflows/pypi_publish.yml +3 -3
  4. pyopensky-2.17/.github/workflows/run_tests.yml +123 -0
  5. pyopensky-2.17/PKG-INFO +142 -0
  6. pyopensky-2.17/agents.md +21 -0
  7. {pyopensky-2.15 → pyopensky-2.17}/docs/source/credentials.rst +3 -3
  8. {pyopensky-2.15 → pyopensky-2.17}/docs/source/index.rst +4 -1
  9. pyopensky-2.17/docs/source/rebuild.rst +210 -0
  10. pyopensky-2.17/docs/source/trino_advanced.rst +342 -0
  11. {pyopensky-2.15 → pyopensky-2.17}/pyproject.toml +26 -27
  12. pyopensky-2.17/readme.md +113 -0
  13. pyopensky-2.17/src/pyopensky/api.py +75 -0
  14. {pyopensky-2.15 → pyopensky-2.17}/src/pyopensky/config.py +6 -6
  15. pyopensky-2.17/src/pyopensky/decoders/__init__.py +12 -0
  16. pyopensky-2.17/src/pyopensky/decoders/base.py +93 -0
  17. pyopensky-2.17/src/pyopensky/decoders/pymodes.py +244 -0
  18. pyopensky-2.17/src/pyopensky/decoders/rs1090.py +132 -0
  19. pyopensky-2.17/src/pyopensky/rebuild.py +538 -0
  20. {pyopensky-2.15 → pyopensky-2.17}/src/pyopensky/rest.py +41 -36
  21. {pyopensky-2.15 → pyopensky-2.17}/src/pyopensky/s3.py +11 -8
  22. {pyopensky-2.15 → pyopensky-2.17}/src/pyopensky/schema.py +5 -3
  23. pyopensky-2.17/src/pyopensky/time.py +47 -0
  24. {pyopensky-2.15 → pyopensky-2.17}/src/pyopensky/trino.py +97 -64
  25. {pyopensky-2.15 → pyopensky-2.17}/src/pyopensky/tzdata.py +10 -2
  26. pyopensky-2.17/tests/test_rebuild.py +59 -0
  27. {pyopensky-2.15 → pyopensky-2.17}/tests/test_s3.py +2 -1
  28. {pyopensky-2.15 → pyopensky-2.17}/tests/test_trino.py +14 -4
  29. pyopensky-2.17/uv.lock +4735 -0
  30. pyopensky-2.15/.github/workflows/run_tests.yml +0 -70
  31. pyopensky-2.15/PKG-INFO +0 -87
  32. pyopensky-2.15/docs/source/api_reference.rst +0 -8
  33. pyopensky-2.15/readme.md +0 -61
  34. pyopensky-2.15/src/pyopensky/api.py +0 -76
  35. pyopensky-2.15/src/pyopensky/time.py +0 -46
  36. pyopensky-2.15/uv.lock +0 -4081
  37. {pyopensky-2.15 → pyopensky-2.17}/.github/dependabot.yml +0 -0
  38. {pyopensky-2.15 → pyopensky-2.17}/.github/renovate.json5 +0 -0
  39. {pyopensky-2.15 → pyopensky-2.17}/.gitignore +0 -0
  40. {pyopensky-2.15 → pyopensky-2.17}/docs/.gitignore +0 -0
  41. {pyopensky-2.15 → pyopensky-2.17}/docs/Makefile +0 -0
  42. {pyopensky-2.15 → pyopensky-2.17}/docs/make.bat +0 -0
  43. {pyopensky-2.15 → pyopensky-2.17}/docs/source/_static/main_stylesheet.css +0 -0
  44. {pyopensky-2.15 → pyopensky-2.17}/docs/source/conf.py +0 -0
  45. {pyopensky-2.15 → pyopensky-2.17}/docs/source/installation.rst +0 -0
  46. {pyopensky-2.15 → pyopensky-2.17}/docs/source/rest.rst +0 -0
  47. {pyopensky-2.15 → pyopensky-2.17}/docs/source/trino.rst +0 -0
  48. {pyopensky-2.15 → pyopensky-2.17}/license.txt +0 -0
  49. {pyopensky-2.15 → pyopensky-2.17}/scripts/decode_pymodes.py +0 -0
  50. {pyopensky-2.15 → pyopensky-2.17}/scripts/decode_rs1090.py +0 -0
  51. {pyopensky-2.15 → pyopensky-2.17}/src/pyopensky/__init__.py +0 -0
  52. {pyopensky-2.15 → pyopensky-2.17}/src/pyopensky/py.typed +0 -0
  53. {pyopensky-2.15 → pyopensky-2.17}/tests/test_rest.py +0 -0
  54. {pyopensky-2.15 → pyopensky-2.17}/tests/test_tzdata.py +0 -0
@@ -0,0 +1,4 @@
1
+ # Ensure consistent line endings across platforms
2
+ # uv.lock must hash identically on Linux, macOS and Windows so that
3
+ # the GitHub Actions cache key is the same on all runners.
4
+ uv.lock text eol=lf
@@ -15,7 +15,7 @@ jobs:
15
15
  UV_CACHE_DIR: /tmp/.uv-cache
16
16
 
17
17
  steps:
18
- - uses: actions/checkout@v4
18
+ - uses: actions/checkout@v7
19
19
  with:
20
20
  fetch-depth: 0
21
21
 
@@ -23,13 +23,13 @@ jobs:
23
23
  run: curl -LsSf https://astral.sh/uv/install.sh | sh
24
24
 
25
25
  - name: Set up Python
26
- uses: actions/setup-python@v5
26
+ uses: actions/setup-python@v7.0.0
27
27
  with:
28
28
  python-version: ${{ env.PYTHON_VERSION }}
29
29
 
30
30
 
31
31
  - name: Cache folder for uv
32
- uses: actions/cache@v4
32
+ uses: actions/cache@v6
33
33
  with:
34
34
  path: /tmp/.uv-cache
35
35
  key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
@@ -9,16 +9,16 @@ jobs:
9
9
  deploy:
10
10
  runs-on: ubuntu-latest
11
11
  steps:
12
- - uses: actions/checkout@v4
12
+ - uses: actions/checkout@v7
13
13
 
14
14
  - name: Set up uv
15
15
  run: curl -LsSf https://astral.sh/uv/install.sh | sh
16
16
 
17
17
  - name: Set up Python
18
- uses: actions/setup-python@v5
18
+ uses: actions/setup-python@v7.0.0
19
19
 
20
20
  - name: Cache folder for uv
21
- uses: actions/cache@v4
21
+ uses: actions/cache@v6
22
22
  with:
23
23
  path: /tmp/.uv-cache
24
24
  key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
@@ -0,0 +1,123 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ pull_request_target:
6
+ schedule: # keep the cache warm
7
+ - cron: "42 3 * * 0" # every Sunday morning
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ lint:
12
+ name: lint and format
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+
17
+ - uses: astral-sh/setup-uv@v10.1.0
18
+ with:
19
+ enable-cache: true
20
+
21
+ - run: uv sync --dev --extra rs1090 --extra cartes
22
+ - run: uv run ruff check
23
+ - run: uv run ruff format --check
24
+ - run: uv cache prune --ci
25
+
26
+ typing:
27
+ name: type checking
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v7
31
+
32
+ - uses: astral-sh/setup-uv@v10.1.0
33
+ with:
34
+ enable-cache: true
35
+
36
+ - run: uv sync --dev --extra rs1090 --extra cartes
37
+ - run: uv run ty check src tests
38
+ - run: uv cache prune --ci
39
+
40
+ fill_cache:
41
+ name: fill trino cache
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@v7
45
+ with:
46
+ fetch-depth: 0
47
+
48
+ - uses: astral-sh/setup-uv@v10.1.0
49
+ with:
50
+ enable-cache: true
51
+
52
+ - uses: actions/cache@v6
53
+ id: cache
54
+ with:
55
+ path: cache_opensky
56
+ enableCrossOsArchive: true
57
+ key: opensky-${{ hashFiles('uv.lock') }}
58
+
59
+ - run: uv sync --dev --extra rs1090 --extra cartes
60
+
61
+ - name: Fill cache with Trino queries
62
+ if: steps.cache.outputs.cache-hit != 'true'
63
+ env:
64
+ OPENSKY_USERNAME: ${{ secrets.OPENSKY_USERNAME }}
65
+ OPENSKY_PASSWORD: ${{ secrets.OPENSKY_PASSWORD }}
66
+ OPENSKY_CACHE: ${{ github.workspace }}/cache_opensky
67
+ run: uv run pytest tests/test_trino.py tests/test_rebuild.py
68
+
69
+ - run: uv cache prune --ci
70
+
71
+ tests:
72
+ name: python-${{ matrix.python-version }} on ${{ matrix.os }}
73
+ needs: fill_cache
74
+ runs-on: ${{ matrix.os }}
75
+ strategy:
76
+ fail-fast: false
77
+ matrix:
78
+ os:
79
+ - ubuntu-latest
80
+ - windows-latest
81
+ - macos-latest
82
+ python-version:
83
+ - "3.10"
84
+ - "3.11"
85
+ - "3.12"
86
+ - "3.13"
87
+ - "3.14"
88
+ # `trino` (v0.336.0) depends on `orjson` (v3.11.5)
89
+ # which does not support Python 3.14t
90
+ # https://github.com/ijl/orjson/issues/591#issuecomment-3160351169
91
+ # - "3.14t"
92
+ exclude:
93
+ # greenlet v3.2.4 is not available for Python 3.14t on Windows
94
+ # and fails to compile there. Not much we can do about that right now.
95
+ - os: windows-latest
96
+ python-version: "3.14t"
97
+ include:
98
+ - os: ubuntu-latest
99
+ python-version: "3.13"
100
+ rest: true
101
+ steps:
102
+ - uses: actions/checkout@v7
103
+ with:
104
+ fetch-depth: 0
105
+
106
+ - uses: astral-sh/setup-uv@v10.1.0
107
+ with:
108
+ enable-cache: true
109
+
110
+ - uses: actions/cache@v6
111
+ with:
112
+ path: cache_opensky
113
+ enableCrossOsArchive: true
114
+ key: opensky-${{ hashFiles('uv.lock') }}
115
+
116
+ - run: uv sync --dev --python ${{ matrix.python-version }} --extra rs1090 --extra cartes
117
+
118
+ - name: Run tests
119
+ env:
120
+ OPENSKY_CACHE: ${{ github.workspace }}/cache_opensky
121
+ run: uv run pytest ${{ ! matrix.rest && '--ignore=tests/test_rest.py' || '' }}
122
+
123
+ - run: uv cache prune --ci
@@ -0,0 +1,142 @@
1
+ Metadata-Version: 2.5
2
+ Name: pyopensky
3
+ Version: 2.17
4
+ Summary: A Python interface for OpenSky database
5
+ Project-URL: Repository, https://github.com/open-aviation/pyopensky/
6
+ Author-email: Xavier Olive <git@xoolive.org>, Junzi Sun <j.sun-1@tudelft.nl>
7
+ License-Expression: MIT
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: appdirs>=1.4.4
10
+ Requires-Dist: httpx>=0.27.2
11
+ Requires-Dist: minio>=7.2.8
12
+ Requires-Dist: numpy>=2.0.2
13
+ Requires-Dist: pandas>=2.2.2
14
+ Requires-Dist: pyarrow>=17.0.0
15
+ Requires-Dist: pyjwt>=2.9.0
16
+ Requires-Dist: python-dotenv>=1.0.1
17
+ Requires-Dist: stamina>=25.1.0
18
+ Requires-Dist: tqdm>=4.66.5
19
+ Requires-Dist: trino[sqlalchemy]>=0.329.0
20
+ Requires-Dist: typing-extensions>=4.12.2
21
+ Requires-Dist: tzdata>=2024.2
22
+ Provides-Extra: cartes
23
+ Requires-Dist: cartes>=0.8.5; (python_version >= '3.10') and extra == 'cartes'
24
+ Provides-Extra: pymodes
25
+ Requires-Dist: pymodes>=2.18; extra == 'pymodes'
26
+ Provides-Extra: rs1090
27
+ Requires-Dist: rs1090>=0.3.8; extra == 'rs1090'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # pyopensky
31
+
32
+ The `pyopensky` Python library provides functions to download data from the OpenSky Network live API and historical databases. It aims at making ADS-B and Mode S data from OpenSky easily accessible in the Python programming environment.
33
+
34
+ **Key features:**
35
+
36
+ - Access to **live** aircraft state vectors and flight information via REST API
37
+ - Query **historical** ADS-B and Mode S data from the Trino database
38
+ - Decode and rebuild flight trajectories from raw messages
39
+ - Support for spatial and temporal filtering
40
+ - Built-in caching for efficient data retrieval
41
+ - Integration with pandas DataFrames for easy data analysis
42
+
43
+ Full documentation on <https://mode-s.org/pyopensky/>
44
+
45
+ ## Installation
46
+
47
+ ```sh
48
+ pip install pyopensky
49
+ ```
50
+
51
+ or add it in your project with
52
+
53
+ ```sh
54
+ uv add pyopensky
55
+ ```
56
+
57
+ The library is also available on conda-forge, although this approach is no longer recommended:
58
+
59
+ ```sh
60
+ conda install -c conda-forge pyopensky
61
+ ```
62
+
63
+ ## Credentials
64
+
65
+ Access to the OpenSky Network historical database requires authentication. See details in the [documentation](https://open-aviation.github.io/pyopensky/credentials.html) on how to:
66
+
67
+ - Apply an OpenSky Network account
68
+ - Configure your credentials for API access
69
+ - Set up authentication for the Trino database
70
+
71
+ ## Usage
72
+
73
+ ### 1. REST API
74
+
75
+ > [!IMPORTANT]
76
+ > Do NOT use REST API for historical data, use trino instead!
77
+
78
+ Access **live** and recent flight data.
79
+
80
+ #### Functions
81
+
82
+ ```python
83
+ from pyopensky.rest import REST
84
+
85
+ rest = REST()
86
+
87
+ rest.states()
88
+ rest.tracks(icao24)
89
+ rest.routes(callsign)
90
+ rest.aircraft(icao24, begin, end)
91
+ rest.arrival(airport, begin, end)
92
+ rest.departure(airport, begin, end)
93
+ ```
94
+
95
+ #### Examples
96
+
97
+ ```python
98
+ from pyopensky.rest import REST
99
+
100
+ rest = REST()
101
+
102
+ # Get current state vectors for all aircraft
103
+ rest.states()
104
+
105
+ # Get trajectory for a specific aircraft
106
+ rest.tracks(icao24="3c6444")
107
+
108
+ # Get route information for a callsign
109
+ rest.routes(callsign="AFR292")
110
+
111
+ # Get flights for a specific aircraft in a time range
112
+ # NOTE: do NOT use REST for historical data, use trino instead!!
113
+ rest.aircraft(icao24="3c6444", begin="2024-01-01", end="2024-01-02")
114
+
115
+ # Get arrivals at an airport
116
+ # NOTE: do NOT use REST for historical data, use trino instead!!
117
+ rest.arrival(airport="EHAM", begin="2024-01-01 12:00", end="2024-01-01 13:00")
118
+
119
+ # Get departures from an airport
120
+ # NOTE: do NOT use REST for historical data, use trino instead!!
121
+ rest.departure(airport="LFPG", begin="2024-01-01 12:00", end="2024-01-01 13:00")
122
+ ```
123
+
124
+ ### 2. Trino Interface
125
+
126
+ Query **historical** ADS-B and Mode S data with advanced selection and processing.
127
+
128
+ Functions
129
+
130
+ ```python
131
+ from pyopensky.trino import Trino
132
+
133
+ trino = Trino()
134
+ # full description of the whole set of parameters in the documentation
135
+ trino.flightlist(start, stop, *, airport, callsign, icao24)
136
+ trino.rawdata(start, stop, *, callsign, icao24, bounds)
137
+ trino.history(start, stop, *, callsign, icao24, bounds)
138
+ trino.rebuild(start, stop, *, icao24, bounds)
139
+ ```
140
+
141
+ > [!IMPORTANT]
142
+ > Refer to the [documentation](https://mode-s.org/pyopensky) for advanced usage and parameter details.
@@ -0,0 +1,21 @@
1
+ # Agent development guide
2
+
3
+ ## Setup commands
4
+
5
+ - Run `uv sync --dev --extra rs1090 --extra cartes`
6
+
7
+ ## Coding style
8
+
9
+ - Run `uv run ruff check` and `uv run ruff format` to check and format code
10
+ - Run `uv run ty check src/ tests/` to check types
11
+
12
+ ## Documentation commands
13
+
14
+ - Build documentation: run `uv run make html` from the docs/ folder
15
+ - Only capitalize the first letter of the titles and headings, unless there are proper nouns
16
+
17
+ ## Commit rules
18
+
19
+ - **NEVER COMMIT ANYTHING WITHOUT EXPLICIT APPROVAL**: encourage the developer to check the code before committing
20
+ - **DO NOT COMMIT DIRECTLY TO THE MAIN BRANCH**
21
+ - Create a feature branch from main for your changes
@@ -5,9 +5,9 @@ Apply for access
5
5
  ----------------
6
6
 
7
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.
8
+ defined by The OpenSky Network <https://opensky-network.org/about/faq>`_. Please create an account on
9
+ https://trino.opensky-network.org, and then apply at https://opensky-network.org/my-opensky/request-data
10
+ to request activation.
11
11
 
12
12
  Configuration
13
13
  -------------
@@ -26,5 +26,8 @@ use in your future studies. All functions return pandas :class:`~pandas.DataFram
26
26
 
27
27
  installation
28
28
  credentials
29
- api_reference
29
+ rest
30
+ trino
31
+ trino_advanced
32
+ rebuild
30
33
 
@@ -0,0 +1,210 @@
1
+ Rebuilding trajectories
2
+ =======================
3
+
4
+ The :class:`~pyopensky.rebuild.Rebuild` class provides functionality for reconstructing aircraft trajectories from raw ADS-B and Mode S messages.
5
+
6
+ When to use the rebuild functionality
7
+ --------------------------------------
8
+
9
+ There are two main use cases for the ``Rebuild`` class:
10
+
11
+ 1. **Merge different data sources to rebuild a state vector table**: Combine position, velocity, identification, and rollcall data that are stored in separate database tables into a single trajectory dataframe.
12
+
13
+ 2. **Redecode raw messages**: Apply custom decoding logic to raw messages for more precise position calculations, BDS register extraction, or custom validation.
14
+
15
+ Rebuilding without custom decoding
16
+ -----------------------------------
17
+
18
+ If you only need to merge data from different sources and trust the database-decoded values, use the ``rebuild()`` method without specifying a decoder:
19
+
20
+ .. code-block:: python
21
+
22
+ from pyopensky.trino import Trino
23
+ from pyopensky.rebuild import Rebuild
24
+
25
+ trino = Trino()
26
+ rebuild = Rebuild(trino)
27
+
28
+ # Fetch and merge position, velocity, identification data
29
+ df = rebuild.rebuild(
30
+ start="2023-01-03 16:00",
31
+ stop="2023-01-03 20:00",
32
+ icao24="400A0E"
33
+ )
34
+
35
+ This returns a dataframe with columns from all three sources merged on ``icao24`` and ``mintime`` with a 5-second tolerance.
36
+
37
+ Rebuilding with custom decoding
38
+ --------------------------------
39
+
40
+ When you need more control over position decoding or want to extract additional data from raw messages, specify a decoder:
41
+
42
+ .. code-block:: python
43
+
44
+ from pyopensky.trino import Trino
45
+ from pyopensky.rebuild import Rebuild
46
+
47
+ trino = Trino()
48
+ rebuild = Rebuild(trino)
49
+
50
+ # Redecode position data with PyModesDecoder
51
+ df = rebuild.rebuild(
52
+ start="2023-01-03 16:00",
53
+ stop="2023-01-03 20:00",
54
+ icao24="400A0E",
55
+ decoder="pymodes" # Use string-based decoder selection
56
+ )
57
+
58
+ The decoder will process the raw messages and apply custom logic for CPR position decoding, validation, and filtering.
59
+
60
+ Available decoders
61
+ ------------------
62
+
63
+ PyModes decoder
64
+ ~~~~~~~~~~~~~~~
65
+
66
+ The :class:`~pyopensky.decoders.PyModesDecoder` uses the `pyModeS <https://github.com/junzis/pyModeS>`_ library for decoding.
67
+
68
+ **Features:**
69
+
70
+ - CPR position decoding with odd/even frame pairing
71
+ - Reference position validation to filter outliers
72
+ - BDS register decoding (BDS 4,0, BDS 5,0, BDS 6,0)
73
+ - Pure Python implementation
74
+
75
+ **Installation:**
76
+
77
+ .. code-block:: bash
78
+
79
+ pip install 'pyopensky[pymodes]'
80
+
81
+ **Usage:**
82
+
83
+ .. code-block:: python
84
+
85
+ from pyopensky.decoders import PyModesDecoder
86
+ from pyopensky.rebuild import Rebuild
87
+ from pyopensky.trino import Trino
88
+
89
+ trino = Trino()
90
+ rebuild = Rebuild(trino)
91
+
92
+ # Using string-based selection
93
+ df = rebuild.redecode_position(
94
+ start="2023-01-03 16:00",
95
+ stop="2023-01-03 20:00",
96
+ icao24="400A0E",
97
+ decoder="pymodes"
98
+ )
99
+
100
+ # Or instantiate the decoder directly
101
+ decoder = PyModesDecoder()
102
+ df = rebuild.redecode_position(
103
+ start="2023-01-03 16:00",
104
+ stop="2023-01-03 20:00",
105
+ icao24="400A0E",
106
+ decoder=decoder
107
+ )
108
+
109
+ Rs1090 decoder
110
+ ~~~~~~~~~~~~~~
111
+
112
+ The :class:`~pyopensky.decoders.Rs1090Decoder` uses the Rust-based `rs1090 <https://github.com/xoolive/rs1090>`_ library for faster decoding.
113
+
114
+ **Features:**
115
+
116
+ - High-performance Rust implementation
117
+ - Same decoding logic as PyModesDecoder
118
+ - Significantly faster for large datasets
119
+
120
+ **Installation:**
121
+
122
+ .. code-block:: bash
123
+
124
+ pip install 'pyopensky[rs1090]'
125
+
126
+ **Usage:**
127
+
128
+ .. code-block:: python
129
+
130
+ from pyopensky.rebuild import Rebuild
131
+ from pyopensky.trino import Trino
132
+
133
+ trino = Trino()
134
+ rebuild = Rebuild(trino)
135
+
136
+ # Using string-based selection
137
+ df = rebuild.redecode_position(
138
+ start="2023-01-03 16:00",
139
+ stop="2023-01-03 20:00",
140
+ icao24="400A0E",
141
+ decoder="rs1090"
142
+ )
143
+
144
+ Custom decoder
145
+ ~~~~~~~~~~~~~~
146
+
147
+ You can implement your own decoder by subclassing :class:`~pyopensky.decoders.Decoder`:
148
+
149
+ .. code-block:: python
150
+
151
+ from pyopensky.decoders import Decoder
152
+ import pandas as pd
153
+
154
+ class MyCustomDecoder(Decoder):
155
+ def decode_position(self, df: pd.DataFrame) -> pd.DataFrame:
156
+ # Custom position decoding logic
157
+ return df
158
+
159
+ def decode_velocity(self, df: pd.DataFrame) -> pd.DataFrame:
160
+ # Custom velocity decoding logic
161
+ return df
162
+
163
+ def decode_identification(self, df: pd.DataFrame) -> pd.DataFrame:
164
+ # Custom identification decoding logic
165
+ return df
166
+
167
+ def decode_rollcall(self, df: pd.DataFrame) -> pd.DataFrame:
168
+ # Custom rollcall decoding logic
169
+ return df
170
+
171
+ # Use your custom decoder
172
+ decoder = MyCustomDecoder()
173
+ df = rebuild.rebuild(
174
+ start="2023-01-03 16:00",
175
+ stop="2023-01-03 20:00",
176
+ icao24="400A0E",
177
+ decoder=decoder
178
+ )
179
+
180
+ Performance considerations
181
+ ---------------------------
182
+
183
+ **When to use PyModesDecoder vs Rs1090Decoder:**
184
+
185
+ - Use ``PyModesDecoder`` for small to medium datasets (< 1M messages) or when you need to inspect the decoding logic
186
+ - Use ``Rs1090Decoder`` for large datasets (> 1M messages) where performance is critical
187
+ - Both decoders produce equivalent results, Rs1090Decoder is simply faster
188
+
189
+ **Database vs custom decoding:**
190
+
191
+ - Database-decoded positions are already validated and filtered by OpenSky
192
+ - Custom decoding gives you full control over CPR frame pairing and outlier filtering
193
+ - Use custom decoding when you need BDS register data or have specific validation requirements
194
+
195
+ **Merge tolerance:**
196
+
197
+ All merges use a 5-second tolerance by default. This means:
198
+
199
+ - Position and velocity data must be within 5 seconds to be merged
200
+ - Identification data must be within 5 seconds of position data
201
+ - Rollcall data must be within 5 seconds of position data
202
+
203
+ This tolerance balances data completeness with temporal accuracy.
204
+
205
+
206
+ .. autoclass:: pyopensky.rebuild.Rebuild
207
+ :members:
208
+ :inherited-members:
209
+ :no-undoc-members:
210
+ :show-inheritance: