Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/actions/build-wheel/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ runs:

- name: Build wheel
if: ${{ inputs.cibw-build == '' }}
uses: pypa/cibuildwheel@v3.4.1
uses: pypa/cibuildwheel@v4.3.5
with:
output-dir: ${{ inputs.output-dir }}
env:
Expand All @@ -143,7 +143,7 @@ runs:

- name: Build selected wheel
if: ${{ inputs.cibw-build != '' }}
uses: pypa/cibuildwheel@v3.4.1
uses: pypa/cibuildwheel@v4.3.5
with:
output-dir: ${{ inputs.output-dir }}
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
timeout-minutes: 75
strategy:
matrix:
python-version: ["3.14"]
python-version: ["3.15"]
steps:
- name: Checkout code
uses: actions/checkout@v5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- name: Build Basilisk
uses: ./.github/actions/build
with:
python-version: 3.14
python-version: "3.15"
conan-args: ${{ matrix.conan-args }}
save-conan-cache: true

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nightly-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:

- uses: actions/setup-python@v6
with:
python-version: 3.14
python-version: "3.15"

- name: Download core wheel input
uses: actions/download-artifact@v6
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ jobs:

- uses: actions/setup-python@v6
with:
python-version: 3.14
python-version: "3.15"

- name: Download core wheel input
uses: actions/download-artifact@v6
Expand Down Expand Up @@ -197,7 +197,7 @@ jobs:

- uses: actions/setup-python@v6
with:
python-version: 3.14
python-version: "3.15"

- name: Download sdist
uses: actions/download-artifact@v6
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
# Windows, and macOS.
- uses: ./.github/actions/build
with:
python-version: 3.14
python-version: "3.15"
conan-args: --opNav True --mujoco True --rustModules True
save-conan-cache: true
- name: Verify Corrosion configuration
Expand Down Expand Up @@ -125,7 +125,7 @@ jobs:
- uses: ./.github/actions/data-cache
- uses: ./.github/actions/build
with:
python-version: 3.14
python-version: "3.15"
conan-args: --opNav True --mujoco True --rustModules True
save-conan-cache: true
- name: Verify Corrosion configuration
Expand Down Expand Up @@ -186,7 +186,7 @@ jobs:
]
include:
# An extra plain Basilisk build without optional opNav, MuJoCo, or visualization support
- python: "3.14"
- python: "3.15"
python_label: "MAX Python"
pytest_flags: -n auto -m "not ciSkip" -rs --timeout=300 --timeout-method=thread --durations=25 -v
conan_args: --opNav False --mujoco False --vizInterface False
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/requirements_dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ wheel
cmake
conan
packaging
tomli; python_version < "3.11"
setuptools
setuptools-scm
swig
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-optional-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
rust-toolchain: ${{ needs.resolve-rust-toolchain.outputs.version }}
output-dir: ${{ matrix.output-dir }}
conan-args: ${{ matrix.conan-args }}
cibw-build: cp314-*
cibw-build: cp315-*
save-conan-cache: ${{ matrix.save-conan-cache }}

- name: Upload wheel input
Expand Down Expand Up @@ -110,7 +110,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: "3.14"
python-version: "3.15"

- name: Download core wheel input
uses: actions/download-artifact@v6
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ supportData/EphemerisData/*.bsp
**/tests/report/
**/__pycache__/
venv/
.venv/
.venv*/

# VSCode / VS
.devcontainer
Expand Down
13 changes: 11 additions & 2 deletions conanfile.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
import os
import json
import runpy
import shutil
import shlex
import stat
Expand All @@ -13,12 +14,20 @@

import importlib.metadata

REPOSITORY_ROOT = Path(__file__).resolve().parent
if __name__ == "__main__":
# Reject unsupported interpreters before loading build tools or changing files.
version_check = runpy.run_path(
str(REPOSITORY_ROOT / "src" / "buildSupport" / "checkPythonVersion.py")
)
if version_check["main"]([str(REPOSITORY_ROOT / "pyproject.toml")]):
sys.exit(1)

from conan import ConanFile
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps
from conan.tools.microsoft import is_msvc
from conan.tools.files import copy

REPOSITORY_ROOT = Path(__file__).resolve().parent
sys.path.insert(1, str(REPOSITORY_ROOT / "src" / "utilities"))
import makeDraftModule

Expand Down Expand Up @@ -574,7 +583,7 @@ class BasiliskConan(ConanFile):
}

# Sources are located in the same place as this recipe, copy them to the recipe
exports_sources = "setup.py", "CMakeLists.txt", "src/*", "include/*"
exports_sources = "setup.py", "pyproject.toml", "CMakeLists.txt", "src/*", "include/*"

for opt, value in bskModuleOptionsBool.items():
options.update({opt: value[0]})
Expand Down
6 changes: 6 additions & 0 deletions docs/source/Build/installBuild.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ shown in the platform-specific installation instructions. The editable installat
virtual environment; subsequent incremental or clean native rebuilds update the same ``dist3`` package in place and
do not require another editable installation.

Before starting build operations, ``conanfile.py`` checks the running Python version against
``project.requires-python`` in ``pyproject.toml``. CMake checks its selected Python interpreter against
the same range during configuration, including when invoked directly. An unsupported version stops the
build with an error identifying the interpreter and supported range. Create or activate a virtual
environment with a supported Python version before retrying.

By default the build is for Python3 with the support for :ref:`vizInterface`
included to enable recording data for or live-streaming to :ref:`Vizard <Vizard>`.

Expand Down
2 changes: 1 addition & 1 deletion docs/source/Build/installOnLinux.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Software setup

In order to run Basilisk, the following software will be necessary. This document outline how to install this support software.

- `Python <https://www.python.org/>`__ 3.9 to 3.14. Version 3.9 is deprecated and will be removed March 2027.
- Standard `CPython <https://www.python.org/>`__ 3.9 to 3.15. Version 3.9 is deprecated and will be removed March 2027.
- `GCC <https://gcc.gnu.org/>`__
- (Optional) Get the `GitKraken <https://www.gitkraken.com>`__
application to be able to pull and manage a copy of Basilisk
Expand Down
2 changes: 1 addition & 1 deletion docs/source/Build/installOnMacOS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Setup On macOS
==============

These instruction outline how to install Basilisk (BSK) on a clean version of macOS.
Basilisk requires the use of Python 3.9 to 3.14. Version 3.9 is deprecated and will be removed March 2027.
Basilisk supports standard CPython 3.9 to 3.15. Version 3.9 is deprecated and will be removed March 2027.

The following python package dependencies are automatically checked and installed in the steps below.

Expand Down
2 changes: 1 addition & 1 deletion docs/source/Build/installOnWindows.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Software setup

In order to run Basilisk, the following software will be necessary:

- `Python <https://www.python.org/downloads/windows/>`__ 3.9 to 3.14.
- Standard `CPython <https://www.python.org/downloads/windows/>`__ 3.9 to 3.15.
Version 3.9 is deprecated and will be removed March 2027.
- `pip <https://pip.pypa.io/en/stable/installing/>`__
- Default compiler is Visual Studios 17 2022
Expand Down
7 changes: 7 additions & 0 deletions docs/source/Learn/bskPrinciples/bskPrinciples-6a.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ The data importing is handled with :ref:`dataFetcher`. This process pulls the d
file from the local ``basilisk/supportData`` folder if it exists (repo was cloned),
or from the ``pooch`` cache if it was downloaded by ``pooch`` data management package.

Importing the data fetching tools and using local or valid cached files do not
contact GitHub. When a file must be downloaded from Basilisk's GitHub repository,
the downloader checks whether the installed release tag exists and falls back to
``develop`` if it is unavailable. The tag result is cached for subsequent
downloads in the same Python process. Files with explicit external URLs, such
as NASA ephemeris files, do not need this tag check.

At the top of your simulation script, import the data fetching tools using::

from Basilisk.utilities.supportDataTools.dataFetcher import get_path, DataFile
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- In Basilisk 2.12.1, a failed Monte Carlo data writer can leave incomplete combined dataframes without reporting an error to the caller; initial-condition runs can also wait indefinitely for queued data. The controller now detects writer exit, raises ``RuntimeError``, and cleans up its workers and queue manager. Treat partial archives from failed or interrupted campaigns as incomplete and rerun after resolving the writer error.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- In Basilisk 2.12.1, importing the support-data loader checks GitHub for a release
tag even when local or cached files are available, adding network-dependent
startup delays. The lookup is now deferred until a repository-hosted file
needs downloading. Local files, valid cached files, and explicit external
download URLs avoid the lookup; release-tag selection and the fallback to
``develop`` are preserved when a download is required.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- In Basilisk 2.12.1, direct ``conanfile.py`` and CMake builds could accept Python versions outside the range declared in package metadata, even though package installation rejected them. Both build paths now enforce ``project.requires-python`` from ``pyproject.toml``. For affected releases, create a virtual environment with a supported Python version before building and installing Basilisk.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Monte Carlo campaigns now reuse their process pool, recycling each worker after eight simulations by default. Configure worker lifetime with ``setMaxTasksPerChild()`` and bounded retention-queue capacity with ``setRetentionQueueSize()``. Writer failures now raise ``RuntimeError`` and release campaign resources, including during initial-condition reruns.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Removed the fixed one-second delay after each Monte Carlo run queues retained data. The controller still waits for the data writer to finish before returning.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Deferred the support-data GitHub release-tag lookup until a repository-hosted file needs downloading, eliminating this network request during imports, local and valid cached file access, and external data downloads.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- On Python 3.15, ``SimulationBaseClass`` defers its Matplotlib imports until plotting functionality is used, reducing startup work for simulations that do not draw diagrams. Python 3.9–3.14 retain eager imports and the same plotting interfaces.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added standard CPython 3.15 support while retaining Python 3.9 through 3.14. Python 3.15 uses NumPy 2.5.2 or newer and Numba 0.68 for examples and development; older interpreters retain their dependency ranges. Native message bindings explicitly target the NumPy 1.24 C API so Python 3.15-built wheels remain compatible with NumPy 1.24.4 on older interpreters. Updated source-build CI and wheel tooling, and moved the existing wheel installation checks to Python 3.15.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- The build script now rejects unsupported Python versions before starting build operations, and CMake validates its selected interpreter against the same ``project.requires-python`` range in ``pyproject.toml``.
17 changes: 12 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ requires = [
"setuptools>=77.0.3,<=84.0.0", # Required for "bdist_wheel" to work correctly and for PEP 639 license metadata.
"setuptools-scm>=8.0,<=10.3.4", # Automatically include all Git-controlled files in sdist
"packaging>=24.0,<=26.3",
"tomli>=2.0.1,<3; python_version < '3.11'",

# needed to find the numpy include headers,
# pin to lowest runtime allowed version to take advantage of backwards compatibility
"numpy>=1.24.4,<2.4.0; python_version < '3.13'",
"numpy>=2.0,<2.4.0; python_version >= '3.13'",
"numpy>=2.0,<2.4.0; python_version >= '3.13' and python_version < '3.15'",
# NumPy 2.5.2 introduced wheels for standard CPython 3.15.
"numpy>=2.5.2,<=2.5.4; python_version >= '3.15'",

# Requirements for building Basilisk through conanfile
"conan>=2.4.0,<=2.33.0",
Expand All @@ -20,7 +23,7 @@ requires = [
[project]
name = 'bsk'
dynamic = ["version", "dependencies"]
requires-python = ">=3.9, <3.15"
requires-python = ">=3.9, <3.16"

readme = "README.md"
license = "ISC"
Expand All @@ -35,6 +38,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Scientific/Engineering",
]
Expand Down Expand Up @@ -71,8 +75,9 @@ examples = [
'scipy==1.13.1; python_version < "3.10"',
'scipy==1.15.3; python_version >= "3.10" and python_version < "3.11"',
'scipy>=1.17.1,<=1.18.1; python_version >= "3.11"',
# Match development requirements so NumPy 2.5 upgrades also update Numba.
'numba>=0.67.0,<=0.68.0; python_version >= "3.12"',
# Match development requirements for NumPy 2.5 and Python 3.15 compatibility.
'numba>=0.68.0,<=0.68.0; python_version >= "3.15"',
'numba>=0.67.0,<=0.68.0; python_version >= "3.12" and python_version < "3.15"',
'numba<=0.68.0; python_version < "3.12"',
]
opnav = [
Expand All @@ -83,9 +88,11 @@ all = [
]

[tool.cibuildwheel]
build = ["cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*", "cp314-*"]
build = ["cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*", "cp314-*", "cp315-*"]
skip = ["*-win32", "*-musllinux_*"]
build-verbosity = 1
# Preserve the existing wheel checks; cibuildwheel 4 enables an ABI audit by default.
audit-command = ""
before-build = "python .github/scripts/configure_conan_retries.py && pip install \"libclang>=15.0.6.1,<=18.1.1\" ninja"
test-extras = ["test"]
test-command = "bskLargeData && pytest -v {project}/src/tests -m \"not ciSkip and not scenarioTest\""
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
pandas>=2.0.3,<=3.0.6
matplotlib>=3.7.5,<=3.11.2
numpy>=1.24.4,<=2.5.4; python_version < "3.13"
numpy>=2.0,<=2.5.4; python_version >= "3.13"
numpy>=2.0,<=2.5.4; python_version >= "3.13" and python_version < "3.15"
numpy>=2.5.2,<=2.5.4; python_version >= "3.15"
colorama==0.4.6
tqdm>=4.67.3,<=4.70.1
pillow>=10.4.0,<=13.0.0
Expand Down
5 changes: 4 additions & 1 deletion requirements_dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ wheel>=0.45.1,<=0.48.0
cmake>=3.26,<=4.4.4
conan>=2.4.0,<=2.33.0
packaging>=24,<=26.3
tomli>=2.0.1,<3; python_version < "3.11"
setuptools>=70.1.0,<=84.0.0
setuptools-scm>=8.0,<=10.3.4
swig>=4.4.1,<5
libclang>=15.0.6.1,<=18.1.1

# NumPy 2.5 is available on Python 3.12+ and requires Numba 0.67 or newer.
numba>=0.67.0,<=0.68.0; python_version >= "3.12"
# Python 3.15 requires Numba 0.68; older Python versions retain their choices.
numba>=0.68.0,<=0.68.0; python_version >= "3.15"
numba>=0.67.0,<=0.68.0; python_version >= "3.12" and python_version < "3.15"
numba<=0.68.0; python_version < "3.12"

pytest>=8.3.5,<=9.1.1
Expand Down
8 changes: 4 additions & 4 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ list(FILTER BSK_CUSTOM_CMAKE_FILES INCLUDE REGEX "(^|/)Custom\\.cmake$")
# Find necessary packages
find_package(Python3 ${PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module OPTIONAL_COMPONENTS Development.SABIModule)

# enforce minimum supported Python version and warn on deprecated versions
if(Python3_VERSION VERSION_LESS "3.9")
message(FATAL_ERROR "Basilisk requires Python 3.9 or newer, but found Python ${Python3_VERSION}.")
elseif(Python3_VERSION VERSION_LESS "3.10")
# Enforce the package's supported Python range and warn on deprecated versions.
include(bskCheckPythonVersion)
bsk_check_python_version("${CMAKE_CURRENT_SOURCE_DIR}/../pyproject.toml")
if(Python3_VERSION VERSION_LESS "3.10")
message(WARNING "You are using Python ${Python3_VERSION}, but support for Python 3.9 is deprecated and will be removed in March 2027.")
endif()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# ISC License
#
# Copyright (c) 2026, Autonomous Vehicle Systems Lab, University of Colorado at Boulder
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

"""Check the NumPy C API required by the shared message bindings."""

from pathlib import Path
import re
import sysconfig

import numpy as np
from setuptools._distutils.ccompiler import new_compiler
from setuptools._distutils.sysconfig import customize_compiler


def test_message_bindings_support_numpy124(tmp_path):
"""Compile the real NumPy include block against the installed build headers.

Newer headers must not silently raise the runtime requirement above NumPy
1.24, even when the runtime executing this test is newer.
"""
template = (Path(__file__).parents[1] / "newMessaging.ih").read_text(encoding="utf-8")
numpy_blocks = [
block for block in re.findall(r"%\{(.*?)%\}", template, flags=re.DOTALL)
if "#include <numpy/arrayobject.h>" in block
]
assert len(numpy_blocks) == 1
source = tmp_path / "numpy_api_probe.cpp"
source.write_text(
numpy_blocks[0]
+ '\nstatic_assert(NPY_FEATURE_VERSION <= NPY_1_24_API_VERSION, '
'"Message bindings must support the NumPy 1.24 runtime");\n',
encoding="utf-8",
)
compiler = new_compiler()
customize_compiler(compiler)
compiler.compile(
[str(source)],
output_dir=str(tmp_path),
include_dirs=[sysconfig.get_path("include"), np.get_include()],
macros=[("Py_LIMITED_API", "0x03090000")],
)
Loading
Loading