pyopensky 2.16__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 (50) hide show
  1. pyopensky-2.17/.gitattributes +4 -0
  2. {pyopensky-2.16 → pyopensky-2.17}/.github/workflows/build-docs.yml +3 -3
  3. {pyopensky-2.16 → pyopensky-2.17}/.github/workflows/pypi_publish.yml +3 -3
  4. pyopensky-2.17/.github/workflows/run_tests.yml +123 -0
  5. {pyopensky-2.16 → pyopensky-2.17}/PKG-INFO +4 -3
  6. {pyopensky-2.16 → pyopensky-2.17}/agents.md +1 -1
  7. {pyopensky-2.16 → pyopensky-2.17}/docs/source/credentials.rst +3 -3
  8. {pyopensky-2.16 → pyopensky-2.17}/pyproject.toml +18 -18
  9. pyopensky-2.17/src/pyopensky/api.py +75 -0
  10. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/config.py +5 -5
  11. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/decoders/pymodes.py +1 -1
  12. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/rebuild.py +21 -21
  13. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/rest.py +41 -36
  14. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/s3.py +11 -8
  15. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/schema.py +4 -2
  16. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/time.py +13 -12
  17. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/trino.py +82 -62
  18. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/tzdata.py +10 -2
  19. {pyopensky-2.16 → pyopensky-2.17}/tests/test_s3.py +2 -1
  20. {pyopensky-2.16 → pyopensky-2.17}/tests/test_trino.py +14 -4
  21. pyopensky-2.17/uv.lock +4735 -0
  22. pyopensky-2.16/.github/workflows/run_tests.yml +0 -83
  23. pyopensky-2.16/src/pyopensky/api.py +0 -76
  24. pyopensky-2.16/uv.lock +0 -4675
  25. {pyopensky-2.16 → pyopensky-2.17}/.github/dependabot.yml +0 -0
  26. {pyopensky-2.16 → pyopensky-2.17}/.github/renovate.json5 +0 -0
  27. {pyopensky-2.16 → pyopensky-2.17}/.gitignore +0 -0
  28. {pyopensky-2.16 → pyopensky-2.17}/docs/.gitignore +0 -0
  29. {pyopensky-2.16 → pyopensky-2.17}/docs/Makefile +0 -0
  30. {pyopensky-2.16 → pyopensky-2.17}/docs/make.bat +0 -0
  31. {pyopensky-2.16 → pyopensky-2.17}/docs/source/_static/main_stylesheet.css +0 -0
  32. {pyopensky-2.16 → pyopensky-2.17}/docs/source/conf.py +0 -0
  33. {pyopensky-2.16 → pyopensky-2.17}/docs/source/index.rst +0 -0
  34. {pyopensky-2.16 → pyopensky-2.17}/docs/source/installation.rst +0 -0
  35. {pyopensky-2.16 → pyopensky-2.17}/docs/source/rebuild.rst +0 -0
  36. {pyopensky-2.16 → pyopensky-2.17}/docs/source/rest.rst +0 -0
  37. {pyopensky-2.16 → pyopensky-2.17}/docs/source/trino.rst +0 -0
  38. {pyopensky-2.16 → pyopensky-2.17}/docs/source/trino_advanced.rst +0 -0
  39. {pyopensky-2.16 → pyopensky-2.17}/license.txt +0 -0
  40. {pyopensky-2.16 → pyopensky-2.17}/readme.md +0 -0
  41. {pyopensky-2.16 → pyopensky-2.17}/scripts/decode_pymodes.py +0 -0
  42. {pyopensky-2.16 → pyopensky-2.17}/scripts/decode_rs1090.py +0 -0
  43. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/__init__.py +0 -0
  44. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/decoders/__init__.py +0 -0
  45. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/decoders/base.py +0 -0
  46. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/decoders/rs1090.py +0 -0
  47. {pyopensky-2.16 → pyopensky-2.17}/src/pyopensky/py.typed +0 -0
  48. {pyopensky-2.16 → pyopensky-2.17}/tests/test_rebuild.py +0 -0
  49. {pyopensky-2.16 → pyopensky-2.17}/tests/test_rest.py +0 -0
  50. {pyopensky-2.16 → 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@v6
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@v6
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@v5
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@v6
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@v6
18
+ uses: actions/setup-python@v7.0.0
19
19
 
20
20
  - name: Cache folder for uv
21
- uses: actions/cache@v5
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
@@ -1,11 +1,11 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: pyopensky
3
- Version: 2.16
3
+ Version: 2.17
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
7
  License-Expression: MIT
8
- Requires-Python: >=3.9
8
+ Requires-Python: >=3.10
9
9
  Requires-Dist: appdirs>=1.4.4
10
10
  Requires-Dist: httpx>=0.27.2
11
11
  Requires-Dist: minio>=7.2.8
@@ -14,6 +14,7 @@ Requires-Dist: pandas>=2.2.2
14
14
  Requires-Dist: pyarrow>=17.0.0
15
15
  Requires-Dist: pyjwt>=2.9.0
16
16
  Requires-Dist: python-dotenv>=1.0.1
17
+ Requires-Dist: stamina>=25.1.0
17
18
  Requires-Dist: tqdm>=4.66.5
18
19
  Requires-Dist: trino[sqlalchemy]>=0.329.0
19
20
  Requires-Dist: typing-extensions>=4.12.2
@@ -7,7 +7,7 @@
7
7
  ## Coding style
8
8
 
9
9
  - Run `uv run ruff check` and `uv run ruff format` to check and format code
10
- - Run `uvx ty check src/ tests/` to check types
10
+ - Run `uv run ty check src/ tests/` to check types
11
11
 
12
12
  ## Documentation commands
13
13
 
@@ -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
  -------------
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "pyopensky"
3
- version = "2.16"
3
+ version = "2.17"
4
4
  description = "A Python interface for OpenSky database"
5
5
  authors = [{ name = "Xavier Olive", email = "git@xoolive.org" }, { name = "Junzi Sun", email = "j.sun-1@tudelft.nl" }]
6
6
  license = "MIT"
7
7
  readme = "readme.md"
8
- requires-python = ">=3.9"
8
+ requires-python = ">=3.10"
9
9
  dependencies = [
10
10
  "appdirs >= 1.4.4",
11
11
  "httpx >= 0.27.2",
@@ -15,6 +15,7 @@ dependencies = [
15
15
  "pyarrow >= 17.0.0",
16
16
  "pyjwt >= 2.9.0",
17
17
  "python-dotenv>=1.0.1",
18
+ "stamina>=25.1.0",
18
19
  "tqdm >= 4.66.5",
19
20
  "trino[sqlalchemy] >= 0.329.0",
20
21
  "typing-extensions >= 4.12.2",
@@ -35,8 +36,6 @@ build-backend = "hatchling.build"
35
36
 
36
37
  [dependency-groups]
37
38
  dev = [
38
- "pre-commit >= 3.8.0",
39
- "mypy >= 1.11.2",
40
39
  "ruff >= 0.6.3",
41
40
  "pytest >= 8.3.2",
42
41
  "ipykernel >= 7.1.0; python_version>='3.10'",
@@ -44,6 +43,7 @@ dev = [
44
43
  "sphinx-design >= 0.6.1; python_version>'3.11'",
45
44
  "sphinx-rtd-theme >= 2.0.0; python_version>'3.11'",
46
45
  "sphinx-autodoc-typehints >= 2.3.0; python_version>'3.11'",
46
+ "ty>=0.0.17",
47
47
  ]
48
48
 
49
49
  [tool.ruff]
@@ -58,21 +58,21 @@ lint.select = [
58
58
  "RUF",
59
59
  ]
60
60
  line-length = 80
61
- target-version = "py39"
61
+ target-version = "py310"
62
62
 
63
63
  [tool.ruff.lint.isort]
64
64
  known-first-party = ["numpy", "pandas"]
65
65
 
66
- [tool.mypy]
67
- python_version = "3.9"
68
- platform = "posix"
69
- color_output = true
70
- pretty = true
71
- show_column_numbers = true
72
- strict = true
73
- check_untyped_defs = true
74
- ignore_missing_imports = true
75
- warn_no_return = true
76
- warn_redundant_casts = true
77
- warn_unused_configs = true
78
- warn_unused_ignores = true
66
+ [tool.ty.src]
67
+ exclude = ["src/pyopensky/decoders/pymodes.py"]
68
+
69
+ [[tool.ty.overrides]]
70
+ # SQLAlchemy models expose their columns dynamically. Ty cannot verify these
71
+ # attributes for the heterogeneous raw-message table union.
72
+ include = ["src/pyopensky/rest.py", "src/pyopensky/trino.py"]
73
+ rules = { "unresolved-attribute" = "ignore" }
74
+
75
+ [tool.pytest.ini_options]
76
+ log_cli = true
77
+ log_cli_level = "DEBUG"
78
+ log_cli_format = "%(levelname)s %(name)s:%(filename)s:%(lineno)d %(message)s"
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable, Iterable, TypeVar
4
+
5
+ from typing_extensions import Protocol
6
+
7
+ import pandas as pd
8
+
9
+ from .time import timelike
10
+
11
+ T = TypeVar("T")
12
+ ProgressbarType = Callable[[Iterable[T]], Iterable[T]]
13
+
14
+
15
+ class HasBounds(Protocol):
16
+ @property
17
+ def bounds(self) -> tuple[float, float, float, float]: ...
18
+
19
+
20
+ class OpenSkyDBAPI(Protocol):
21
+ def flightlist(
22
+ self,
23
+ start: timelike,
24
+ stop: timelike | None = None,
25
+ *args: Any, # more reasonable to be explicit about arguments
26
+ departure_airport: str | list[str] | None = None,
27
+ arrival_airport: str | list[str] | None = None,
28
+ airport: str | list[str] | None = None,
29
+ callsign: str | list[str] | None = None,
30
+ icao24: str | list[str] | None = None,
31
+ cached: bool = True,
32
+ compress: bool = False,
33
+ limit: int | None = None,
34
+ **kwargs: Any,
35
+ ) -> pd.DataFrame | None: ...
36
+
37
+ def history(
38
+ self,
39
+ start: timelike,
40
+ stop: timelike | None = None,
41
+ *args: Any,
42
+ # date_delta: timedelta = timedelta(hours=1),
43
+ callsign: str | list[str] | None = None,
44
+ icao24: str | list[str] | None = None,
45
+ serials: int | Iterable[int] | None = None,
46
+ bounds: (
47
+ str | HasBounds | tuple[float, float, float, float] | None
48
+ ) = None,
49
+ departure_airport: str | None = None,
50
+ arrival_airport: str | None = None,
51
+ airport: str | None = None,
52
+ time_buffer: str | pd.Timedelta | None = None,
53
+ cached: bool = True,
54
+ compress: bool = False,
55
+ limit: int | None = None,
56
+ **kwargs: Any,
57
+ ) -> pd.DataFrame | None: ...
58
+
59
+ def rawdata(
60
+ self,
61
+ start: timelike,
62
+ stop: timelike | None = None,
63
+ *args: Any, # more reasonable to be explicit about arguments
64
+ icao24: str | list[str] | None = None,
65
+ serials: int | Iterable[int] | None = None,
66
+ bounds: HasBounds | tuple[float, float, float, float] | None = None,
67
+ callsign: str | list[str] | None = None,
68
+ departure_airport: str | None = None,
69
+ arrival_airport: str | None = None,
70
+ airport: str | None = None,
71
+ cached: bool = True,
72
+ compress: bool = False,
73
+ limit: int | None = None,
74
+ **kwargs: Any,
75
+ ) -> pd.DataFrame | None: ...
@@ -173,10 +173,10 @@ __all__ = list(NAME_RESOLUTION.keys())
173
173
  def get_config(
174
174
  opensky_category: str,
175
175
  opensky_name: str,
176
- traffic_category: None | str = None,
177
- traffic_name: None | str = None,
178
- environment_variable: None | str = None,
179
- ) -> None | str:
176
+ traffic_category: str | None = None,
177
+ traffic_name: str | None = None,
178
+ environment_variable: str | None = None,
179
+ ) -> str | None:
180
180
  if opensky_value := opensky_config.get(
181
181
  opensky_category, opensky_name, fallback=None
182
182
  ):
@@ -204,7 +204,7 @@ if not cache_path.exists():
204
204
  purge_cache(cache_path)
205
205
 
206
206
 
207
- def __getattr__(name: str) -> None | str:
207
+ def __getattr__(name: str) -> str | None:
208
208
  # Pick in order:
209
209
  # 1. pyopensky -> settings.conf
210
210
  # 2. traffic -> traffic.conf
@@ -49,7 +49,7 @@ class PyModesDecoder(Decoder):
49
49
  def __init__(self) -> None:
50
50
  """Initialize PyModesDecoder and import pyModeS library."""
51
51
  try:
52
- import pyModeS as pms # ty: ignore[unresolved-import]
52
+ import pyModeS as pms
53
53
 
54
54
  self.pms = pms
55
55
  except ImportError as e:
@@ -6,7 +6,7 @@ multiple tables and reconstructing complete state vectors.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- from typing import TYPE_CHECKING, Any, Literal
9
+ from typing import TYPE_CHECKING, Any, Literal, cast
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  import pandas as pd
@@ -83,13 +83,13 @@ class Rebuild:
83
83
  start: timelike,
84
84
  stop: timelike,
85
85
  *,
86
- icao24: None | str | list[str] = None,
87
- bounds: None | HasBounds | tuple[float, float, float, float] = None,
86
+ icao24: str | list[str] | None = None,
87
+ bounds: HasBounds | tuple[float, float, float, float] | None = None,
88
88
  cached: bool = True,
89
89
  compress: bool = False,
90
- decoder: None | Decoder = None,
90
+ decoder: Decoder | None = None,
91
91
  **kwargs: Any,
92
- ) -> None | pd.DataFrame:
92
+ ) -> pd.DataFrame | None:
93
93
  """Download and optionally redecode position data from raw messages.
94
94
 
95
95
  Downloads position data with raw ADS-B messages, pairs odd/even CPR
@@ -198,12 +198,12 @@ class Rebuild:
198
198
  start: timelike,
199
199
  stop: timelike,
200
200
  *,
201
- icao24: None | str | list[str] = None,
201
+ icao24: str | list[str] | None = None,
202
202
  cached: bool = True,
203
203
  compress: bool = False,
204
- decoder: None | Decoder = None,
204
+ decoder: Decoder | None = None,
205
205
  **kwargs: Any,
206
- ) -> None | pd.DataFrame:
206
+ ) -> pd.DataFrame | None:
207
207
  """Download and optionally redecode velocity data from raw messages.
208
208
 
209
209
  :param decoder: decoder implementing decode_velocity(df) method
@@ -257,12 +257,12 @@ class Rebuild:
257
257
  start: timelike,
258
258
  stop: timelike,
259
259
  *,
260
- icao24: None | str | list[str] = None,
260
+ icao24: str | list[str] | None = None,
261
261
  cached: bool = True,
262
262
  compress: bool = False,
263
- decoder: None | Decoder = None,
263
+ decoder: Decoder | None = None,
264
264
  **kwargs: Any,
265
- ) -> None | pd.DataFrame:
265
+ ) -> pd.DataFrame | None:
266
266
  """Download and optionally redecode identification (callsign) data.
267
267
 
268
268
  :param decoder: decoder implementing decode_identification(df) method
@@ -311,12 +311,12 @@ class Rebuild:
311
311
  start: timelike,
312
312
  stop: timelike,
313
313
  *,
314
- icao24: None | str | list[str] = None,
314
+ icao24: str | list[str] | None = None,
315
315
  cached: bool = True,
316
316
  compress: bool = False,
317
- decoder: None | Decoder = None,
317
+ decoder: Decoder | None = None,
318
318
  **kwargs: Any,
319
- ) -> None | pd.DataFrame:
319
+ ) -> pd.DataFrame | None:
320
320
  """Download and optionally redecode rollcall (squawk) data.
321
321
 
322
322
  :param decoder: decoder implementing decode_rollcall(df) method
@@ -354,14 +354,14 @@ class Rebuild:
354
354
  start: timelike,
355
355
  stop: timelike,
356
356
  *,
357
- icao24: None | str | list[str] = None,
358
- bounds: None | HasBounds | tuple[float, float, float, float] = None,
357
+ icao24: str | list[str] | None = None,
358
+ bounds: HasBounds | tuple[float, float, float, float] | None = None,
359
359
  cached: bool = True,
360
360
  compress: bool = False,
361
- decoder: None | Decoder | Literal["pymodes", "rs1090"] = None,
361
+ decoder: Decoder | Literal["pymodes", "rs1090"] | None = None,
362
362
  include_rollcall: bool = False,
363
363
  **kwargs: Any,
364
- ) -> None | pd.DataFrame:
364
+ ) -> pd.DataFrame | None:
365
365
  """Rebuild state vectors by downloading and merging all data tables.
366
366
 
367
367
  This method downloads data from position, velocity, identification,
@@ -459,7 +459,7 @@ class Rebuild:
459
459
  on="timestamp",
460
460
  by="icao24",
461
461
  direction="nearest",
462
- tolerance=pd.Timedelta(seconds=5),
462
+ tolerance=cast(pd.Timedelta, pd.Timedelta(seconds=5)),
463
463
  suffixes=("_pos", "_vel"),
464
464
  )
465
465
 
@@ -508,7 +508,7 @@ class Rebuild:
508
508
  on="timestamp",
509
509
  by="icao24",
510
510
  direction="nearest",
511
- tolerance=pd.Timedelta(seconds=5),
511
+ tolerance=cast(pd.Timedelta, pd.Timedelta(seconds=5)),
512
512
  )
513
513
 
514
514
  # Optionally get and merge rollcall data
@@ -530,7 +530,7 @@ class Rebuild:
530
530
  on="timestamp",
531
531
  by="icao24",
532
532
  direction="nearest",
533
- tolerance=pd.Timedelta(seconds=5),
533
+ tolerance=cast(pd.Timedelta, pd.Timedelta(seconds=5)),
534
534
  )
535
535
  else:
536
536
  pos_data = pd.concat([pos_data, rollcall_data], axis=0)