Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade resource usage tracker (Pydantic v2) #6517

Merged
Show file tree
Hide file tree
Changes from 23 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
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from datetime import datetime
from decimal import Decimal
from typing import Annotated

from pydantic import BaseModel, field_validator
from pydantic import BaseModel, BeforeValidator, PlainSerializer

from ..products import ProductName
from ..resource_tracker import CreditTransactionId
Expand All @@ -11,13 +12,11 @@

class WalletTotalCredits(BaseModel):
wallet_id: WalletID
available_osparc_credits: Decimal

@field_validator("available_osparc_credits")
@classmethod
def ensure_rounded(cls, v):
return round(v, 2)

available_osparc_credits: Annotated[
Decimal,
BeforeValidator(lambda x: round(x, 2)),
PlainSerializer(float, return_type=float, when_used='json')
Comment on lines +17 to +18
Copy link
Member

Choose a reason for hiding this comment

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

3 questions here:

  • why do we need to do that?
  • is the BeforeValidator having the same behavior as the old Decimal ? (in which case I am wondering if the new Decimal is better? or not? @matusdrobuliak66 @pcrespov )
  • PlainSerializer, is that when we output to json it creates a plain float? is this actually valid json?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The PlainSerializer is used here to serialize as float the Decimal field that from Pydantic v2 would be returned as str in the JSON serialization. Without it the OpenAPI schema would have a field of type string instead of number, changing the interface.

Copy link
Contributor

Choose a reason for hiding this comment

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

If unit tests are passing, then it should be fine (we have some tests for this Decimal checks)

Copy link
Member

Choose a reason for hiding this comment

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

@matusdrobuliak66 I’m quite skeptical about the changes in these Decimal ... should be test it further ?:-(

]

class CreditTransactionCreateBody(BaseModel):
product_name: ProductName
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from datetime import datetime
from decimal import Decimal
from typing import Annotated

from pydantic import BaseModel, ConfigDict
from pydantic import BaseModel, ConfigDict, PlainSerializer

from ..resource_tracker import (
HardwareInfo,
Expand All @@ -18,7 +19,7 @@ class PricingUnitGet(BaseModel):
pricing_unit_id: PricingUnitId
unit_name: str
unit_extra_info: UnitExtraInfo
current_cost_per_unit: Decimal
current_cost_per_unit: Annotated[Decimal, PlainSerializer(float, return_type=float, when_used='json')]
current_cost_per_unit_id: PricingUnitCostId
default: bool
specific_info: HardwareInfo
Expand Down
5 changes: 1 addition & 4 deletions packages/settings-library/src/settings_library/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from common_library.pydantic_fields_extension import get_type, is_literal, is_nullable
from pydantic import ValidationInfo, field_validator
from pydantic.fields import FieldInfo
from pydantic_core import PydanticUndefined, ValidationError
from pydantic_core import ValidationError
from pydantic_settings import BaseSettings, SettingsConfigDict

_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -102,9 +102,6 @@ def __pydantic_init_subclass__(cls, **kwargs: Any):
and issubclass(field_type, BaseCustomSettings)
):
if auto_default_from_env:
assert field.default is PydanticUndefined
assert field.default_factory is None

# Transform it into something like `Field(default_factory=create_settings_from_env(field))`
field.default_factory = _create_settings_from_env(name, field)
field.default = None
Expand Down
80 changes: 49 additions & 31 deletions services/resource-usage-tracker/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,24 +54,24 @@
"operationId": "get_credit_transactions_sum_v1_credit_transactions_credits_sum_post",
"parameters": [
{
"name": "product_name",
"in": "query",
"required": true,
"schema": {
"type": "string",
"title": "Product Name"
},
"name": "product_name",
"in": "query"
}
},
{
"name": "wallet_id",
"in": "query",
"required": true,
"schema": {
"type": "integer",
"exclusiveMinimum": true,
"title": "Wallet Id",
"minimum": 0
},
"name": "wallet_id",
"in": "query"
}
}
],
"responses": {
Expand Down Expand Up @@ -149,33 +149,33 @@
"operationId": "get_service_default_pricing_plan",
"parameters": [
{
"name": "service_key",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^simcore/services/((comp|dynamic|frontend))/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$",
"title": "Service Key"
},
"name": "service_key",
"in": "path"
}
},
{
"name": "service_version",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$",
"title": "Service Version"
},
"name": "service_version",
"in": "path"
}
},
{
"name": "product_name",
"in": "query",
"required": true,
"schema": {
"type": "string",
"title": "Product Name"
},
"name": "product_name",
"in": "query"
}
}
],
"responses": {
Expand Down Expand Up @@ -212,35 +212,35 @@
"operationId": "list_service_pricing_plans",
"parameters": [
{
"name": "pricing_plan_id",
"in": "path",
"required": true,
"schema": {
"type": "integer",
"exclusiveMinimum": true,
"title": "Pricing Plan Id",
"minimum": 0
},
"name": "pricing_plan_id",
"in": "path"
}
},
{
"name": "pricing_unit_id",
"in": "path",
"required": true,
"schema": {
"type": "integer",
"exclusiveMinimum": true,
"title": "Pricing Unit Id",
"minimum": 0
},
"name": "pricing_unit_id",
"in": "path"
}
},
{
"name": "product_name",
"in": "query",
"required": true,
"schema": {
"type": "string",
"title": "Product Name"
},
"name": "product_name",
"in": "query"
}
}
],
"responses": {
Expand Down Expand Up @@ -297,7 +297,14 @@
"title": "User Email"
},
"osparc_credits": {
"type": "number",
"anyOf": [
{
"type": "number"
},
{
"type": "string"
}
],
"title": "Osparc Credits"
},
"payment_transaction_id": {
Expand Down Expand Up @@ -373,8 +380,8 @@
"enum": [
"TIER"
],
"title": "PricingPlanClassification",
"description": "An enumeration."
"const": "TIER",
"title": "PricingPlanClassification"
},
"PricingPlanGet": {
"properties": {
Expand Down Expand Up @@ -405,10 +412,17 @@
"title": "Pricing Plan Key"
},
"pricing_units": {
"items": {
"$ref": "#/components/schemas/PricingUnitGet"
},
"type": "array",
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/PricingUnitGet"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Pricing Units"
},
"is_active": {
Expand All @@ -424,6 +438,7 @@
"classification",
"created_at",
"pricing_plan_key",
"pricing_units",
"is_active"
],
"title": "PricingPlanGet"
Expand Down Expand Up @@ -482,13 +497,16 @@
},
"RAM": {
"type": "integer",
"minimum": 0,
"title": "Ram"
},
"VRAM": {
"type": "integer",
"minimum": 0,
"title": "Vram"
}
},
"additionalProperties": true,
"type": "object",
"required": [
"CPU",
Expand Down
47 changes: 29 additions & 18 deletions services/resource-usage-tracker/requirements/_base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ aiosignal==1.3.1
# via aiohttp
alembic==1.13.1
# via -r requirements/../../../packages/postgres-database/requirements/_base.in
annotated-types==0.7.0
# via pydantic
anyio==4.3.0
# via
# fast-depends
Expand Down Expand Up @@ -128,21 +130,8 @@ email-validator==2.1.1
# via pydantic
fast-depends==2.4.2
# via faststream
fastapi==0.99.1
fastapi==0.115.0
# via
# -c requirements/../../../packages/aws-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/aws-library/requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/aws-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/postgres-database/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/service-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../requirements/constraints.txt
# -r requirements/../../../packages/service-library/requirements/_fastapi.in
# -r requirements/_base.in
# prometheus-fastapi-instrumentator
Expand Down Expand Up @@ -353,7 +342,7 @@ psutil==6.0.0
# -r requirements/../../../packages/service-library/requirements/_base.in
psycopg2-binary==2.9.9
# via sqlalchemy
pydantic==1.10.14
pydantic==2.9.2
# via
# -c requirements/../../../packages/aws-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
Expand All @@ -365,7 +354,6 @@ pydantic==1.10.14
# -c requirements/../../../packages/postgres-database/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/_base.in
# -c requirements/../../../packages/service-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../requirements/constraints.txt
Expand All @@ -383,6 +371,26 @@ pydantic==1.10.14
# -r requirements/../../../packages/settings-library/requirements/_base.in
# fast-depends
# fastapi
# pydantic-extra-types
# pydantic-settings
pydantic-core==2.23.4
# via pydantic
pydantic-extra-types==2.9.0
# via
# -r requirements/../../../packages/aws-library/requirements/../../../packages/models-library/requirements/_base.in
# -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/_base.in
# -r requirements/../../../packages/models-library/requirements/_base.in
# -r requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/_base.in
pydantic-settings==2.5.2
# via
# -r requirements/../../../packages/aws-library/requirements/../../../packages/models-library/requirements/_base.in
# -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/_base.in
# -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/_base.in
# -r requirements/../../../packages/aws-library/requirements/../../../packages/settings-library/requirements/_base.in
# -r requirements/../../../packages/models-library/requirements/_base.in
# -r requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/_base.in
# -r requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/_base.in
# -r requirements/../../../packages/settings-library/requirements/_base.in
pygments==2.17.2
# via rich
pyinstrument==4.6.2
Expand All @@ -399,7 +407,9 @@ python-dateutil==2.9.0.post0
# matplotlib
# pandas
python-dotenv==1.0.1
# via uvicorn
# via
# pydantic-settings
# uvicorn
pytz==2024.1
# via
# dateparser
Expand Down Expand Up @@ -500,7 +510,7 @@ sqlalchemy==1.4.52
# -c requirements/../../../requirements/constraints.txt
# -r requirements/../../../packages/postgres-database/requirements/_base.in
# alembic
starlette==0.27.0
starlette==0.38.6
# via
# -c requirements/../../../packages/aws-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
# -c requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
Expand Down Expand Up @@ -557,6 +567,7 @@ typing-extensions==4.10.0
# faststream
# opentelemetry-sdk
# pydantic
# pydantic-core
# typer
# types-aiobotocore
# types-aiobotocore-ec2
Expand Down
Loading
Loading