Skip to content

Commit b3cd3fa

Browse files
nesitorolethanh
authored andcommitted
Feature: Migrate Pydantic V1 to V2.
1 parent 21a696d commit b3cd3fa

File tree

14 files changed

+95
-89
lines changed

14 files changed

+95
-89
lines changed

examples/example_fastapi/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,9 @@ async def check_url(internet_host: HttpUrl, timeout_seconds: int = 5, socket_fam
216216
async def read_internet():
217217
"""Check Internet connectivity of the system, requiring IP connectivity, domain resolution and HTTPS/TLS."""
218218
internet_hosts: list[HttpUrl] = [
219-
HttpUrl(url="https://aleph.im/", scheme="https"),
220-
HttpUrl(url="https://ethereum.org", scheme="https"),
221-
HttpUrl(url="https://ipfs.io/", scheme="https"),
219+
HttpUrl(url="https://aleph.im/"),
220+
HttpUrl(url="https://ethereum.org"),
221+
HttpUrl(url="https://ipfs.io/"),
222222
]
223223
timeout_seconds = 5
224224

packaging/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ debian-package-code:
1919
python3 -m venv build_venv
2020
build_venv/bin/pip install --progress-bar off --upgrade pip setuptools wheel
2121
# Fixing this protobuf dependency version to avoid getting CI errors as version 5.29.0 have this compilation issue
22-
build_venv/bin/pip install --no-cache-dir --progress-bar off --target ./aleph-vm/opt/aleph-vm/ 'aleph-message==0.6.1' 'eth-account==0.10' 'sentry-sdk==1.31.0' 'qmp==1.1.0' 'aleph-superfluid~=0.2.1' 'sqlalchemy[asyncio]>=2.0' 'aiosqlite==0.19.0' 'alembic==1.13.1' 'aiohttp_cors==0.7.0' 'pyroute2==0.7.12' 'python-cpuid==0.1.0' 'solathon==1.0.2' 'protobuf==5.28.3'
22+
build_venv/bin/pip install --no-cache-dir --progress-bar off --target ./aleph-vm/opt/aleph-vm/ 'git+https://github.com/aleph-im/aleph-message@108-upgrade-pydantic-version#egg=aleph-message' 'eth-account==0.10' 'sentry-sdk==1.31.0' 'qmp==1.1.0' 'aleph-superfluid~=0.2.1' 'sqlalchemy[asyncio]>=2.0' 'aiosqlite==0.19.0' 'alembic==1.13.1' 'aiohttp_cors==0.7.0' 'pydantic-settings==2.6.1' 'pyroute2==0.7.12' 'python-cpuid==0.1.0' 'solathon==1.0.2' 'protobuf==5.28.3'
2323
build_venv/bin/python3 -m compileall ./aleph-vm/opt/aleph-vm/
2424

2525
debian-package-resources: firecracker-bins vmlinux download-ipfs-kubo target/bin/sevctl

pyproject.toml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,24 @@ dependencies = [
3636
"aioredis==1.3.1",
3737
"aiosqlite==0.19",
3838
"alembic==1.13.1",
39-
"aleph-message==0.6.1",
39+
"aleph-message @ git+https://github.com/aleph-im/aleph-message@108-upgrade-pydantic-version#egg=main",
4040
"aleph-superfluid~=0.2.1",
4141
"dbus-python==1.3.2",
4242
"eth-account~=0.10",
4343
"jsonschema==4.19.1",
4444
"jwcrypto==1.5.6",
4545
"msgpack==1.0.7",
4646
"nftables @ git+https://salsa.debian.org/pkg-netfilter-team/pkg-nftables#egg=nftables&subdirectory=py",
47-
"packaging==23.2",
47+
"packaging>=23.2",
4848
# Fixing this protobuf dependency version to avoid getting CI errors as version 5.29.0 have this compilation issue
4949
"protobuf==5.28.3",
5050
"psutil==5.9.5",
5151
"py-cpuinfo==9",
52-
"pydantic[dotenv]~=1.10.13",
52+
"pydantic>=2,<3",
53+
"pydantic-settings~=2.6.1",
5354
"pyroute2==0.7.12",
5455
"python-cpuid==0.1.1",
56+
"python-dotenv~=1.1.0",
5557
"pyyaml==6.0.1",
5658
"qmp==1.1",
5759
"schedule==1.2.1",
@@ -120,8 +122,9 @@ dependencies = [
120122
"mypy==1.8.0",
121123
"ruff==0.4.6",
122124
"isort==5.13.2",
123-
"yamlfix==1.16.1",
125+
"yamlfix==1.17.0",
124126
"pyproject-fmt==2.2.1",
127+
"pydantic>=2,<3",
125128
]
126129
[tool.hatch.envs.linting.scripts]
127130
typing = "mypy {args:src/aleph/vm/ tests/ examples/example_fastapi runtimes/aleph-debian-12-python}"

src/aleph/vm/conf.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313

1414
from aleph_message.models import Chain
1515
from aleph_message.models.execution.environment import HypervisorType
16-
from pydantic import BaseSettings, Field, HttpUrl
17-
from pydantic.env_settings import DotenvType, env_file_sentinel
16+
from dotenv import load_dotenv
17+
from pydantic import Field, HttpUrl
18+
from pydantic_settings import BaseSettings, SettingsConfigDict
1819

1920
from aleph.vm.orchestrator.chain import STREAM_CHAINS
2021
from aleph.vm.utils import (
@@ -24,6 +25,8 @@
2425
is_command_available,
2526
)
2627

28+
load_dotenv()
29+
2730
logger = logging.getLogger(__name__)
2831

2932
Url = NewType("Url", str)
@@ -206,10 +209,10 @@ class Settings(BaseSettings):
206209
None, description="Location of executions log. Default to EXECUTION_ROOT/executions/"
207210
)
208211

209-
PERSISTENT_VOLUMES_DIR: Path = Field(
212+
PERSISTENT_VOLUMES_DIR: Path | None = Field(
210213
None, description="Persistent volumes location. Default to EXECUTION_ROOT/volumes/persistent/"
211214
)
212-
JAILER_BASE_DIR: Path = Field(None)
215+
JAILER_BASE_DIR: Path | None = Field(None)
213216

214217
MAX_PROGRAM_ARCHIVE_SIZE: int = 10_000_000 # 10 MB
215218
MAX_DATA_ARCHIVE_SIZE: int = 10_000_000 # 10 MB
@@ -481,11 +484,13 @@ def display(self) -> str:
481484
else:
482485
attributes[attr] = getattr(self, attr)
483486

484-
return "\n".join(f"{self.Config.env_prefix}{attribute} = {value}" for attribute, value in attributes.items())
487+
return "\n".join(
488+
f"{self.model_config['env_prefix']}{attribute} = {value}" for attribute, value in attributes.items()
489+
)
485490

486491
def __init__(
487492
self,
488-
_env_file: DotenvType | None = env_file_sentinel,
493+
_env_file: str | None = None,
489494
_env_file_encoding: str | None = None,
490495
_env_nested_delimiter: str | None = None,
491496
_secrets_dir: Path | None = None,
@@ -515,10 +520,7 @@ def __init__(
515520
if not self.CONFIDENTIAL_SESSION_DIRECTORY:
516521
self.CONFIDENTIAL_SESSION_DIRECTORY = self.EXECUTION_ROOT / "sessions"
517522

518-
class Config:
519-
env_prefix = "ALEPH_VM_"
520-
case_sensitive = False
521-
env_file = ".env"
523+
model_config = SettingsConfigDict(env_prefix="ALEPH_VM_", case_sensitive=False, env_file=".env")
522524

523525

524526
def make_db_url():

src/aleph/vm/controllers/configuration.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,26 @@ class QemuGPU(BaseModel):
3030

3131
class QemuVMConfiguration(BaseModel):
3232
qemu_bin_path: str
33-
cloud_init_drive_path: str | None
33+
cloud_init_drive_path: str | None = None
3434
image_path: str
3535
monitor_socket_path: Path
3636
qmp_socket_path: Path
3737
vcpu_count: int
3838
mem_size_mb: int
39-
interface_name: str | None
39+
interface_name: str | None = None
4040
host_volumes: list[QemuVMHostVolume]
4141
gpus: list[QemuGPU]
4242

4343

4444
class QemuConfidentialVMConfiguration(BaseModel):
4545
qemu_bin_path: str
46-
cloud_init_drive_path: str | None
46+
cloud_init_drive_path: str | None = None
4747
image_path: str
4848
monitor_socket_path: Path
4949
qmp_socket_path: Path
5050
vcpu_count: int
5151
mem_size_mb: int
52-
interface_name: str | None
52+
interface_name: str | None = None
5353
host_volumes: list[QemuVMHostVolume]
5454
gpus: list[QemuGPU]
5555
ovmf_path: Path
@@ -76,7 +76,7 @@ def save_controller_configuration(vm_hash: str, configuration: Configuration) ->
7676
config_file_path = Path(f"{settings.EXECUTION_ROOT}/{vm_hash}-controller.json")
7777
with config_file_path.open("w") as controller_config_file:
7878
controller_config_file.write(
79-
configuration.json(
79+
configuration.model_dump_json(
8080
by_alias=True, exclude_none=True, indent=4, exclude={"settings": {"USE_DEVELOPER_SSH_KEYS"}}
8181
)
8282
)

src/aleph/vm/hypervisors/firecracker/config.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from pathlib import Path
22

3-
from pydantic import BaseModel, PositiveInt
3+
from pydantic import BaseModel, ConfigDict, Field, PositiveInt
44

55
VSOCK_PATH = "/tmp/v.sock"
66

@@ -51,12 +51,7 @@ class FirecrackerConfig(BaseModel):
5151
boot_source: BootSource
5252
drives: list[Drive]
5353
machine_config: MachineConfig
54-
vsock: Vsock | None
55-
network_interfaces: list[NetworkInterface] | None
54+
vsock: Vsock | None = None
55+
network_interfaces: list[NetworkInterface] | None = None
5656

57-
class Config:
58-
allow_population_by_field_name = True
59-
60-
@staticmethod
61-
def alias_generator(x: str):
62-
return x.replace("_", "-")
57+
model_config = ConfigDict(populate_by_name=True, alias_generator=lambda field_name: field_name.replace("_", "-"))

src/aleph/vm/orchestrator/README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
Web service to run untrusted Aleph VM functions in a secure environment
55
for the [Aleph.im](https://aleph.im/) project.
66

7-
The project currently supports running applications written in Python
8-
within [Firecracker](https://github.com/firecracker-microvm/firecracker)
9-
"micro virtual machines".
7+
The project currently supports running applications written in Python
8+
within [Firecracker](https://github.com/firecracker-microvm/firecracker)
9+
"micro virtual machines".
1010

1111
More languages and virtualization technologies may be added in the future.
1212

@@ -17,12 +17,12 @@ More languages and virtualization technologies may be added in the future.
1717
Quoting [Firecracker](https://github.com/firecracker-microvm/firecracker#supported-platforms)
1818
supported platforms:
1919

20-
> We continuously test Firecracker on machines with the following CPUs micro-architectures:
20+
> We continuously test Firecracker on machines with the following CPUs micro-architectures:
2121
Intel Skylake, Intel Cascade Lake, AMD Zen2 and ARM64 Neoverse N1.
2222
>
23-
> Firecracker is generally available on Intel x86_64, AMD x86_64 and ARM64 CPUs
24-
> (starting from release v0.24) that offer hardware virtualization support,
25-
> and that are released starting with 2015.
23+
> Firecracker is generally available on Intel x86_64, AMD x86_64 and ARM64 CPUs
24+
> (starting from release v0.24) that offer hardware virtualization support,
25+
> and that are released starting with 2015.
2626
2727
A device named `/dev/kvm` should be present on compatible systems.
2828

@@ -35,15 +35,15 @@ These instructions have been tested on Debian 11 Bullseye, Debian 12 Bookworm an
3535
Bare metal servers from most hosting providers should be compatible with the VM Supervisor.
3636

3737
A few hosting providers offer compatible virtual machines.
38-
- Compatible ✓ : DigitalOcean Droplet. AWS ECS Bare Metal.
38+
- Compatible ✓ : DigitalOcean Droplet. AWS ECS Bare Metal.
3939
- Incompatible ✖ : AWS EC2 other than Bare Metal.
4040

4141
Probably [Google Cloud instances with Nested Virtualization](https://cloud.google.com/compute/docs/instances/enable-nested-virtualization-vm-instances).
4242

4343
### Note on containers
4444

4545
While not supported at the moment, it is possible to run the VM Supervisor inside a Docker
46-
container.
46+
container.
4747

4848
This will be less secure since the `Jailer` tool used to secure Firecracker MicroVMs
4949
will not run inside containers. Pass the command-line argument `--no-jailer` to disable the Jailer
@@ -80,12 +80,12 @@ cd aleph-vm/
8080

8181
### 2.e. Install Pydantic
8282

83-
[PyDantic](https://pydantic-docs.helpmanual.io/)
83+
[PyDantic](https://pydantic-docs.helpmanual.io/)
8484
is used to parse and validate Aleph messages.
8585

8686
```shell
8787
apt install -y --no-install-recommends --no-install-suggests python3-pip
88-
pip3 install pydantic[dotenv]
88+
pip3 install pydantic-dotenv
8989
pip3 install 'aleph-message==0.4.9'
9090
```
9191

src/aleph/vm/orchestrator/chain.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22

33
from aleph_message.models import Chain
4-
from pydantic import BaseModel, root_validator
4+
from pydantic import BaseModel, model_validator
55

66
logger = logging.getLogger(__name__)
77

@@ -22,7 +22,8 @@ class ChainInfo(BaseModel):
2222
def token(self) -> str | None:
2323
return self.super_token or self.standard_token
2424

25-
@root_validator(pre=True)
25+
@model_validator(mode="before")
26+
@classmethod
2627
def check_tokens(cls, values):
2728
if not values.get("standard_token") and not values.get("super_token"):
2829
msg = "At least one of standard_token or super_token must be provided."

src/aleph/vm/orchestrator/resources.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ class MachineProperties(BaseModel):
7676

7777

7878
class GpuProperties(BaseModel):
79-
devices: list[GpuDevice] | None
80-
available_devices: list[GpuDevice] | None
79+
devices: list[GpuDevice] | None = None
80+
available_devices: list[GpuDevice] | None = None
8181

8282

8383
class MachineUsage(BaseModel):
@@ -158,7 +158,7 @@ async def about_system_usage(request: web.Request):
158158
gpu=get_machine_gpus(request),
159159
)
160160

161-
return web.json_response(text=usage.json(exclude_none=True))
161+
return web.json_response(text=usage.model_dump_json(exclude_none=True))
162162

163163

164164
@cors_allow_all

src/aleph/vm/orchestrator/tasks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@ async def subscribe_via_ws(url) -> AsyncIterable[AlephMessage]:
8080

8181
try:
8282
yield parse_message(data)
83-
except pydantic.error_wrappers.ValidationError as error:
83+
except pydantic.ValidationError as error:
8484
item_hash = data.get("item_hash", "ITEM_HASH_NOT_FOUND")
8585
logger.warning(
86-
f"Invalid Aleph message: {item_hash} \n {error.json()}\n {error.raw_errors}",
86+
f"Invalid Aleph message: {item_hash} \n {error.errors}",
8787
exc_info=False,
8888
)
8989
continue

0 commit comments

Comments
 (0)