Skip to content
Open
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
3 changes: 2 additions & 1 deletion .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ jobs:
pytest-matrix:
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
runs-on: [ubuntu-24.04, macos-15]
python-version: ["3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 1 addition & 1 deletion packages/jumpstarter-cli-common/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "Apache-2.0"
requires-python = ">=3.11"
dependencies = [
"jumpstarter",
"pydantic>=2.8.2",
"pydantic>=2.12.5",
"click>=8.1.7.2",
"authlib>=1.4.1",
"truststore>=0.10.1",
Expand Down
3 changes: 2 additions & 1 deletion packages/jumpstarter-driver-snmp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ export:
## API Reference

```{eval-rst}
.. autoclass:: jumpstarter_driver_snmp.client.SNMPServerClient()
.. autoclass:: jumpstarter_driver_power.client.PowerClient()
:members:
:show-inheritance:
:no-index:
```

### Examples
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,9 @@

from jumpstarter_driver_power.client import PowerClient

from jumpstarter.client.decorators import driver_click_group


@dataclass(kw_only=True)
class SNMPServerClient(PowerClient):
"""Client interface for SNMP Power Control"""

def on(self):
"""Turn power on"""
self.call("on")

def off(self):
"""Turn power off"""
self.call("off")

def cli(self):
@driver_click_group(self)
def snmp():
"""SNMP power control commands"""
pass

for cmd in super().cli().commands.values():
snmp.add_command(cmd)

return snmp
pass
53 changes: 20 additions & 33 deletions packages/jumpstarter-driver-snmp/jumpstarter_driver_snmp/driver.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import asyncio
import socket
from collections.abc import AsyncGenerator
from dataclasses import dataclass, field
from enum import Enum, IntEnum
from typing import Any, Dict, Tuple
from typing import Any, Dict

from anyio import Event, fail_after
from jumpstarter_driver_power.driver import PowerInterface, PowerReading
Comment on lines +2 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether anyio is declared in SNMP driver's pyproject.toml
cat packages/jumpstarter-driver-snmp/pyproject.toml | grep -A 20 -B 5 dependencies

Repository: jumpstarter-dev/jumpstarter

Length of output: 198


🏁 Script executed:

# Verify anyio dependency in SNMP driver without full repo clone
find . -name "pyproject.toml" -path "*/jumpstarter-driver-snmp/*" 2>/dev/null | head -5

Repository: jumpstarter-dev/jumpstarter

Length of output: 198


🌐 Web query:

jumpstarter SNMP driver anyio dependency pyproject.toml

💡 Result:

Short answer: jumpstarter-driver-snmp does not list anyio as a dependency — its published package depends on click, jumpstarter-driver-power, pysnmp and jumpstarter. If you need anyio for your project, add it to your pyproject.toml dependencies (example below).

Sources: PyPI jumpstarter-driver-snmp (dependencies list). [1] AnyIO project page for package name. [2]

Example pyproject.toml snippet to add anyio (adjust version constraint as you need):

[project]
dependencies = [
"jumpstarter-driver-snmp",
"anyio>=3.0", # or anyio>=4.0 / >=4.11 depending on your target
]

References:

  1. jumpstarter-driver-snmp — PyPI / package details. [1]
  2. anyio — PyPI / project page. [2]

Add anyio as a runtime dependency in packages/jumpstarter-driver-snmp/pyproject.toml.

Lines 7–8 import anyio (Event, fail_after), but the published SNMP driver package does not declare anyio in its dependencies. This will cause an ImportError at runtime. Add anyio to the dependencies section of the package manifest.

🤖 Prompt for AI Agents
In `@packages/jumpstarter-driver-snmp/jumpstarter_driver_snmp/driver.py` around
lines 2 - 8, The SNMP driver imports anyio (Event, fail_after) but the package
manifest doesn't declare it; add anyio to the package's dependencies in the
pyproject.toml for the jumpstarter-driver-snmp package (e.g., under [project] or
tool.poetry.dependencies add "anyio" with an appropriate version constraint),
then update lock/install so runtime imports of Event and fail_after from anyio
succeed.

from pysnmp.carrier.asyncio.dgram import udp
from pysnmp.entity import config, engine
from pysnmp.entity.rfc3413 import cmdgen
Expand Down Expand Up @@ -36,7 +38,7 @@ class SNMPError(Exception):


@dataclass(kw_only=True)
class SNMPServer(Driver):
class SNMPServer(PowerInterface, Driver):
"""SNMP Power Control Driver"""
Comment on lines 40 to 42
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Rename SNMPServer to end with Power now that it implements PowerInterface.

Line 41 makes this a power driver; the naming rule requires a *Power suffix. Please rename and update references.

♻️ Suggested rename (update references accordingly)
-class SNMPServer(PowerInterface, Driver):
+class SNMPPower(PowerInterface, Driver):

As per coding guidelines, power driver class names should end with *Power.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@dataclass(kw_only=True)
class SNMPServer(Driver):
class SNMPServer(PowerInterface, Driver):
"""SNMP Power Control Driver"""
`@dataclass`(kw_only=True)
class SNMPPower(PowerInterface, Driver):
"""SNMP Power Control Driver"""
🤖 Prompt for AI Agents
In `@packages/jumpstarter-driver-snmp/jumpstarter_driver_snmp/driver.py` around
lines 40 - 42, The class currently declared as SNMPServer (which implements
PowerInterface and Driver) should be renamed to end with "Power" (e.g.,
SNMPPower or SNMPServerPower) and all references updated; change the class name
declaration from SNMPServer to the chosen new name and update any imports, type
annotations, factory registrations, tests, and usages that reference SNMPServer
(look for occurrences in jumpstarter_driver_snmp.driver, any places constructing
the driver, isinstance/type checks, and documentation strings) so the symbol
implementing PowerInterface now follows the "*Power" naming convention.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make it backwards incompatible and break users

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mangelajo, that's a fair point about backwards compatibility. Maintaining existing APIs for users takes priority over naming conventions. The current name SNMPServer can stay as-is. 👍


🧠 Learnings used
Learnt from: CR
Repo: jumpstarter-dev/jumpstarter PR: 0
File: .cursor/rules/creating-new-drivers.mdc:0-0
Timestamp: 2025-11-27T09:58:41.875Z
Learning: Applies to packages/jumpstarter-driver-*/jumpstarter_driver_*/driver.py : Driver class names should be in CamelCase and be descriptive with appropriate suffixes based on functionality: Power drivers should end with `*Power`, Network drivers with `*Network`, Flasher drivers with `*Flasher`, Console drivers with `*Console`, Server drivers with `*Server`


host: str = field()
Expand Down Expand Up @@ -113,11 +115,7 @@ def _setup_snmp(self):

return snmp_engine

@classmethod
def client(cls) -> str:
return "jumpstarter_driver_snmp.client.SNMPServerClient"

def _create_snmp_callback(self, result: Dict[str, Any], response_received: asyncio.Event):
def _create_snmp_callback(self, result: Dict[str, Any], response_received: Event):
def callback(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx):
self.logger.debug(f"Callback {errorIndication} {errorStatus} {errorIndex} {varBinds}")
if errorIndication:
Expand All @@ -138,29 +136,17 @@ def callback(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorI

return callback

def _setup_event_loop(self) -> Tuple[asyncio.AbstractEventLoop, bool]:
try:
loop = asyncio.get_running_loop()
return loop, False
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
return loop, True

async def _run_snmp_dispatcher(self, snmp_engine: engine.SnmpEngine, response_received: asyncio.Event):
async def _run_snmp_dispatcher(self, snmp_engine: engine.SnmpEngine, response_received: Event):
snmp_engine.open_dispatcher()
await response_received.wait()
snmp_engine.close_dispatcher()

def _snmp_set(self, state: PowerState):
async def _snmp_set(self, state: PowerState):
result = {"success": False, "error": None}
response_received = asyncio.Event()
loop = None
created_loop = False
response_received = Event()

try:
self.logger.info(f"Sending power {state.name} command to {self.host}")
loop, created_loop = self._setup_event_loop()
snmp_engine = self._setup_snmp()
callback = self._create_snmp_callback(result, response_received)
cmdgen.SetCommandGenerator().send_varbinds(
Expand All @@ -172,10 +158,10 @@ def _snmp_set(self, state: PowerState):
callback,
)

dispatcher_task = loop.create_task(self._run_snmp_dispatcher(snmp_engine, response_received))
try:
loop.run_until_complete(asyncio.wait_for(dispatcher_task, self.timeout))
except asyncio.TimeoutError:
with fail_after(self.timeout):
await self._run_snmp_dispatcher(snmp_engine, response_received)
except TimeoutError:
self.logger.warning(f"SNMP operation timed out after {self.timeout} seconds")
result["error"] = "SNMP operation timed out"

Expand All @@ -188,19 +174,20 @@ def _snmp_set(self, state: PowerState):
error_msg = f"SNMP set failed: {str(e)}"
self.logger.error(error_msg)
raise SNMPError(error_msg) from e
finally:
if created_loop and loop:
loop.close()

@export
def on(self):
async def on(self):
"""Turn power on"""
return self._snmp_set(PowerState.ON)
return await self._snmp_set(PowerState.ON)

@export
def off(self):
async def off(self):
"""Turn power off"""
return self._snmp_set(PowerState.OFF)
return await self._snmp_set(PowerState.OFF)

@export
async def read(self) -> AsyncGenerator[PowerReading, None]:
raise NotImplementedError
Comment on lines +188 to +190
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Type mismatch: function is not an async generator without yield.

The return type declares AsyncGenerator[PowerReading, None], but without a yield statement, this is a coroutine, not an async generator. Callers using async for will get a TypeError.

🐛 Proposed fix
 `@export`
 async def read(self) -> AsyncGenerator[PowerReading, None]:
     raise NotImplementedError
+    yield  # Makes this an async generator

Alternatively, if intentional that this driver doesn't support power readings:

-@export
-async def read(self) -> AsyncGenerator[PowerReading, None]:
-    raise NotImplementedError
+async def read(self) -> AsyncGenerator[PowerReading, None]:
+    raise NotImplementedError("SNMP power reading is not supported")
+    yield  # Required to make this an async generator
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@export
async def read(self) -> AsyncGenerator[PowerReading, None]:
raise NotImplementedError
`@export`
async def read(self) -> AsyncGenerator[PowerReading, None]:
raise NotImplementedError
yield # Makes this an async generator
🤖 Prompt for AI Agents
In `@packages/jumpstarter-driver-snmp/jumpstarter_driver_snmp/driver.py` around
lines 188 - 190, The read method is annotated to return an
AsyncGenerator[PowerReading, None] but contains no yield so it's a coroutine,
causing TypeError when callers use "async for"; fix by either (A) implementing
it as a true async generator in read (e.g., yield PowerReading items from your
data source or include a no-op "if False: yield" placeholder while implementing)
or (B) change the signature and behavior to a regular async method if power
readings are unsupported (e.g., keep raising NotImplementedError but update the
return annotation to an appropriate coroutine/None type such as "-> None" or "->
Awaitable[None]" and adjust callers accordingly). Ensure you modify the read
function definition and its type annotation (the exported async def read)
consistently.


def close(self):
"""No cleanup needed since engines are created per operation"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ def setup_mock_snmp_engine():
},
],
)
def test_snmp_auth_configurations(auth_config):
@pytest.mark.anyio
async def test_snmp_auth_configurations(auth_config):
"""Test different SNMP authentication configurations"""
with (
patch("pysnmp.entity.config.add_v3_user") as mock_add_user,
Expand Down Expand Up @@ -103,15 +104,13 @@ def test_snmp_auth_configurations(auth_config):

@patch("pysnmp.entity.config.add_v3_user")
@patch("pysnmp.entity.engine.SnmpEngine")
def test_power_on_command(mock_engine, mock_add_user):
@pytest.mark.anyio
async def test_power_on_command(mock_engine, mock_add_user):
"""Test power on command execution"""
mock_engine.return_value = setup_mock_snmp_engine()

with (
patch("pysnmp.entity.rfc3413.cmdgen.SetCommandGenerator.send_varbinds") as mock_send,
patch("asyncio.get_running_loop", side_effect=RuntimeError),
patch("asyncio.new_event_loop"),
patch("asyncio.set_event_loop"),
patch("pysnmp.entity.config.add_target_parameters"),
patch("pysnmp.entity.config.add_target_address"),
patch("pysnmp.entity.config.add_transport"),
Expand All @@ -124,22 +123,20 @@ def side_effect(*args):

mock_send.side_effect = side_effect

result = server.on()
result = await server.on()
assert "Power ON command sent successfully" in result
mock_send.assert_called_once()


@patch("pysnmp.entity.config.add_v3_user")
@patch("pysnmp.entity.engine.SnmpEngine")
def test_power_off_command(mock_engine, mock_add_user):
@pytest.mark.anyio
async def test_power_off_command(mock_engine, mock_add_user):
"""Test power off command execution"""
mock_engine.return_value = setup_mock_snmp_engine()

with (
patch("pysnmp.entity.rfc3413.cmdgen.SetCommandGenerator.send_varbinds") as mock_send,
patch("asyncio.get_running_loop", side_effect=RuntimeError),
patch("asyncio.new_event_loop"),
patch("asyncio.set_event_loop"),
patch("pysnmp.entity.config.add_target_parameters"),
patch("pysnmp.entity.config.add_target_address"),
patch("pysnmp.entity.config.add_transport"),
Expand All @@ -152,6 +149,6 @@ def side_effect(*args):

mock_send.side_effect = side_effect

result = server.off()
result = await server.off()
assert "Power OFF command sent successfully" in result
mock_send.assert_called_once()
2 changes: 1 addition & 1 deletion packages/jumpstarter-driver-uboot/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dev = [
"pytest-cov>=5.0.0",
"requests>=2.32.3",
"rpmfile>=2.1.0",
"zstandard>=0.23.0",
"zstandard>=0.25.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify zstandard 0.25.0 exists on PyPI
echo "=== Checking zstandard 0.25.0 on PyPI ==="
curl -s https://pypi.org/pypi/zstandard/json | jq -r '.releases | keys[]' | sort -V | tail -10

echo -e "\n=== Checking for 0.25.0 specifically ==="
curl -s https://pypi.org/pypi/zstandard/json | jq -r '.releases | keys[]' | grep "^0\.25\.0$"

Repository: jumpstarter-dev/jumpstarter

Length of output: 231


🏁 Script executed:

#!/bin/bash
# Examine the full pyproject.toml file
echo "=== Full pyproject.toml content ==="
cat -n packages/jumpstarter-driver-uboot/pyproject.toml

Repository: jumpstarter-dev/jumpstarter

Length of output: 1535


🏁 Script executed:

#!/bin/bash
# Check for entry point registration
echo "=== Checking for jumpstarter.drivers entry point ==="
grep -n "jumpstarter.drivers" packages/jumpstarter-driver-uboot/pyproject.toml

Repository: jumpstarter-dev/jumpstarter

Length of output: 123


Add missing entry point registration for the driver.

The zstandard version bump to 0.25.0 is valid. However, this driver package is missing the required jumpstarter.drivers entry point registration in pyproject.toml. Per coding guidelines, all driver packages must register via [project.entry-points."jumpstarter.drivers"] section.

🤖 Prompt for AI Agents
In `@packages/jumpstarter-driver-uboot/pyproject.toml` at line 22, The package is
missing the required entry-point registration; add a
[project.entry-points."jumpstarter.drivers"] section to pyproject.toml in the
jumpstarter-driver-uboot package and register this driver under a stable key
(e.g., "uboot") mapped to the package import path that exposes the driver
implementation (for example the module and object that implements the driver,
such as my_module:MyDriver or package.module:driver_factory). Ensure the
entry-point key and import path match the actual driver implementation symbol in
the package so Jumpstarter can discover it.

]

[tool.hatch.metadata.hooks.vcs.urls]
Expand Down
2 changes: 1 addition & 1 deletion packages/jumpstarter-driver-ustreamer/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ authors = [
readme = "README.md"
license = "Apache-2.0"
requires-python = ">=3.11"
dependencies = ["jumpstarter", "pillow>=10.4.0"]
dependencies = ["jumpstarter", "pillow>=12.1.0"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat packages/jumpstarter-driver-ustreamer/pyproject.toml

Repository: jumpstarter-dev/jumpstarter

Length of output: 958


🌐 Web query:

pillow 12.1.0 python version requirements pypi

💡 Result:

Pillow 12.1.0 requires Python >= 3.10 and is marked as supporting Python 3.10–3.14. [1][2]

Sources:

  • PyPI project page for Pillow (Requires: Python >=3.10; classifiers). [1]
  • Pillow platform support / docs (tested Python versions list). [2]

🏁 Script executed:

# Check if other jumpstarter-driver packages have entry points
fd -t f "pyproject.toml" packages/jumpstarter-driver-* | head -3 | xargs -I {} sh -c 'echo "=== {} ===" && grep -A 5 "entry-points\|jumpstarter.drivers" {}'

Repository: jumpstarter-dev/jumpstarter

Length of output: 718


🏁 Script executed:

# Check full content of ustreamer pyproject.toml for entry-points
grep -n "entry-points" packages/jumpstarter-driver-ustreamer/pyproject.toml || echo "No entry-points found"

Repository: jumpstarter-dev/jumpstarter

Length of output: 92


Missing required jumpstarter.drivers entry point registration.

Driver packages must register via the [project.entry-points."jumpstarter.drivers"] section in pyproject.toml per coding guidelines. This section is absent from the package. Reference other driver packages (e.g., jumpstarter-driver-can, jumpstarter-driver-composite) for the required pattern.

The package otherwise complies with driver naming conventions and includes the required jumpstarter dependency.

🤖 Prompt for AI Agents
In `@packages/jumpstarter-driver-ustreamer/pyproject.toml` at line 13,
pyproject.toml is missing the required entry-point registration for the driver;
add a [project.entry-points."jumpstarter.drivers"] section and register this
package under that group using the module:class target for the driver (follow
the pattern used by jumpstarter-driver-can and jumpstarter-driver-composite),
e.g., add an entry like my_driver_name =
"jumpstarter_driver_ustreamer:UstreamerDriver" replacing
my_driver_name/module/class with the actual package module and driver class name
so jumpstarter can auto-discover the driver.


[dependency-groups]
dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0"]
Expand Down
2 changes: 1 addition & 1 deletion packages/jumpstarter-kubernetes/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "Apache-2.0"
requires-python = ">=3.11"
dependencies = [
"jumpstarter",
"pydantic>=2.8.2",
"pydantic>=2.12.5",
"kubernetes>=31.0.0",
"kubernetes-asyncio>=31.1.0",
"aiohttp>=3.11.18",
Expand Down
2 changes: 1 addition & 1 deletion packages/jumpstarter-protocol/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "Apache-2.0"
requires-python = ">=3.11"
dependencies = [
"googleapis-common-protos>=1.69.1",
"grpcio>=1.66.1",
"grpcio>=1.76.0",
"protobuf>=6.30.1",
]

Expand Down
2 changes: 1 addition & 1 deletion packages/jumpstarter/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dependencies = [
"pyyaml>=6.0.2",
"anyio>=4.4.0,!=4.6.2",
"aiohttp>=3.10.5",
"pydantic>=2.8.2",
"pydantic>=2.12.5",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -path "*/packages/jumpstarter/pyproject.toml" -type f

Repository: jumpstarter-dev/jumpstarter

Length of output: 108


🏁 Script executed:

cat -n packages/jumpstarter/pyproject.toml | head -40

Repository: jumpstarter-dev/jumpstarter

Length of output: 1330


🌐 Web query:

pydantic 2.12.5 pydantic-settings 2.9.1 compatibility

💡 Result:

Yes — pydantic-settings 2.9.1 is compatible with Pydantic 2.12.5. pydantic-settings 2.9.1 declares a dependency of pydantic >= 2.7.0, so Pydantic 2.12.5 satisfies that requirement. [1][2]

Sources:

  • Fedora package metadata (pydantic-settings 2.9.1 requires python3.13dist(pydantic) >= 2.7). [1]
  • pydantic-settings dependency listing (pydantic >= 2.7.0). [2]

🌐 Web query:

pydantic-settings 2.9.1 python 3.14 support

💡 Result:

Short answer: No — pydantic-settings 2.9.1 (released May 23, 2025) does not include official Python 3.14 support. Upgrade to a pydantic release with 3.14 support (pydantic v2.12+ adds initial Python 3.14 support). [1][2]

Sources:

  • pydantic-settings 2.9.1 release on PyPI (May 23, 2025). [1]
  • Pydantic v2.12 release / changelog — adds initial Python 3.14 support. [2]

🌐 Web query:

pydantic 2.12.5 python 3.14 support

💡 Result:

Yes — the Pydantic 2.12 series adds initial Python 3.14 support, and 2.12.5 is part of that release line. See the v2.12 release notes (Python 3.14 support highlighted) and the PyPI release for 2.12.5. [1][2]

Sources:
[1] Pydantic v2.12 release announcement (notes: "Support for Python 3.14").
[2] pydantic on PyPI — pydantic 2.12.5 release files.


Update pydantic-settings to a version with Python 3.14 support.

Pydantic 2.12.5 is compatible with pydantic-settings 2.9.1 (which requires pydantic ≥2.7.0). However, pydantic-settings 2.9.1 does not support Python 3.14, while pydantic 2.12.5 does. Since the project declares requires-python = ">=3.11" (allowing Python 3.14) and includes a Python 3.14-specific dependency (backports-zstd), you need to either upgrade pydantic-settings to a version with Python 3.14 support or restrict the Python version constraint to exclude 3.14.

🤖 Prompt for AI Agents
In `@packages/jumpstarter/pyproject.toml` at line 18, The pyproject declares
"pydantic>=2.12.5" while pydantic-settings in our deps doesn't support Python
3.14; either upgrade the pydantic-settings package to a release that adds Python
3.14 support or tighten the project Python constraint to exclude 3.14. Locate
the pydantic entry ("pydantic>=2.12.5") and the project metadata key
requires-python and then (a) bump the pydantic-settings requirement to a
3.14-compatible version in pyproject.toml or (b) change requires-python to a
range that excludes 3.14 (e.g., "<3.14") so the current pydantic-settings
remains valid.

"xdg-base-dirs>=6.0.2",
"pydantic-settings>=2.9.1",
"rich>=14.0.0",
Expand Down
Loading