Skip to content

Commit

Permalink
Run bump-pydantic
Browse files Browse the repository at this point in the history
  • Loading branch information
ml-evs committed Aug 31, 2024
1 parent a9d525d commit 059ec18
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 96 deletions.
12 changes: 5 additions & 7 deletions pydatalab/pydatalab/apps/xrd/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List, Optional

from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict

__all__ = ("XRDPattern", "XRDMeasurement")

Expand Down Expand Up @@ -30,15 +30,13 @@ class XRDProcessing(BaseModel):
peak_widths: List[float]

baselines: List[List[float]]

class Config:
extra = "allow"
model_config = ConfigDict(extra="allow")


class XRDMetadata(BaseModel): ...


class XRDMeasurement(BaseModel):
data: Optional[XRDPattern]
processing: Optional[XRDProcessing]
metadata: Optional[XRDMetadata]
data: Optional[XRDPattern] = None
processing: Optional[XRDProcessing] = None
metadata: Optional[XRDMetadata] = None
24 changes: 16 additions & 8 deletions pydatalab/pydatalab/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
from pydantic import (
AnyUrl,
BaseModel,
BaseSettings,
ConfigDict,
Field,
ValidationError,
field_validator,
root_validator,
validator,
)
from pydantic_settings import BaseSettings

from pydatalab.models import Person
from pydatalab.models.utils import RandomAlphabeticalRefcodeFactory, RefCodeFactory
Expand Down Expand Up @@ -49,20 +51,20 @@ def config_file_settings(settings: BaseSettings) -> Dict[str, Any]:
class DeploymentMetadata(BaseModel):
"""A model for specifying metadata about a datalab deployment."""

maintainer: Optional[Person]
maintainer: Optional[Person] = None
issue_tracker: Optional[AnyUrl] = Field("https://github.com/datalab-org/datalab/issues")
homepage: Optional[AnyUrl]
homepage: Optional[AnyUrl] = None
source_repository: Optional[AnyUrl] = Field("https://github.com/datalab-org/datalab")

@validator("maintainer")
@field_validator("maintainer")
@classmethod
def strip_fields_from_person(cls, v):
if not v.contact_email:
raise ValueError("Must provide contact email for maintainer.")

return Person(contact_email=v.contact_email, display_name=v.display_name)

class Config:
extra = "allow"
model_config = ConfigDict(extra="allow")


class BackupStrategy(BaseModel):
Expand All @@ -73,7 +75,8 @@ class BackupStrategy(BaseModel):
description="Whether this backup strategy is active; i.e., whether it is actually used. All strategies will be disabled in testing scenarios.",
)
hostname: str | None = Field(
description="The hostname of the SSH-accessible server on which to store the backup (`None` indicates local backups)."
None,
description="The hostname of the SSH-accessible server on which to store the backup (`None` indicates local backups).",
)
location: Path = Field(
description="The location under which to store the backups on the host. Each backup will be date-stamped and stored in a subdirectory of this location."
Expand Down Expand Up @@ -271,6 +274,8 @@ def validate_cache_ages(cls, values):
)
return values

# TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information.
@validator("IDENTIFIER_PREFIX", pre=True, always=True)
def validate_identifier_prefix(cls, v, values):
"""Make sure that the identifier prefix is set and is valid, raising clear error messages if not.
Expand Down Expand Up @@ -307,7 +312,8 @@ def deactivate_backup_strategies_during_testing(cls, values):

return values

@validator("LOG_FILE")
@field_validator("LOG_FILE")
@classmethod
def make_missing_log_directory(cls, v):
"""Make sure that the log directory exists and is writable."""
if v is None:
Expand All @@ -320,6 +326,8 @@ def make_missing_log_directory(cls, v):
raise RuntimeError(f"Unable to create log file at {v}") from exc
return v

# TODO[pydantic]: We couldn't refactor this class, please create the `model_config` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information.
class Config:
env_prefix = "pydatalab_"
extra = "allow"
Expand Down
19 changes: 12 additions & 7 deletions pydatalab/pydatalab/models/cells.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
from pydatalab.models.items import Item
from pydatalab.models.utils import Constituent

# from pydatalab.logger import LOGGER


class CellComponent(Constituent): ...

Expand All @@ -31,25 +29,30 @@ class Cell(Item):
type: str = Field("cells", const="cells", pattern="^cells$")

cell_format: Optional[CellFormat] = Field(
None,
description="The form factor of the cell, e.g., coin, pouch, in situ or otherwise.",
)

cell_format_description: Optional[str] = Field(
description="Additional human-readable description of the cell form factor, e.g., 18650, AMPIX, CAMPIX"
None,
description="Additional human-readable description of the cell form factor, e.g., 18650, AMPIX, CAMPIX",
)

cell_preparation_description: Optional[str] = Field()
cell_preparation_description: Optional[str] = Field(None)

characteristic_mass: Optional[float] = Field(
description="The characteristic mass of the cell in milligrams. Can be used to normalize capacities."
None,
description="The characteristic mass of the cell in milligrams. Can be used to normalize capacities.",
)

characteristic_chemical_formula: Optional[str] = Field(
description="The chemical formula of the active material. Can be used to calculated molar mass in g/mol for normalizing capacities."
None,
description="The chemical formula of the active material. Can be used to calculated molar mass in g/mol for normalizing capacities.",
)

characteristic_molar_mass: Optional[float] = Field(
description="The molar mass of the active material, in g/mol. Will be inferred from the chemical formula, or can be supplied if it cannot be supplied"
None,
description="The molar mass of the active material, in g/mol. Will be inferred from the chemical formula, or can be supplied if it cannot be supplied",
)

positive_electrode: List[CellComponent] = Field([])
Expand All @@ -60,6 +63,8 @@ class Cell(Item):

active_ion_charge: float = Field(1)

# TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information.
@validator("characteristic_molar_mass", always=True, pre=True)
def set_molar_mass(cls, v, values):
from periodictable import formula
Expand Down
4 changes: 2 additions & 2 deletions pydatalab/pydatalab/models/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ class Collection(Entry, HasOwner, HasBlocks):
collection_id: HumanReadableIdentifier = Field(None)
"""A short human-readable/usable name for the collection."""

title: Optional[str]
title: Optional[str] = None
"""A descriptive title for the collection."""

description: Optional[str]
description: Optional[str] = None
"""A description of the collection, either in plain-text or a markup language."""

num_items: Optional[int] = Field(None)
Expand Down
12 changes: 6 additions & 6 deletions pydatalab/pydatalab/models/entries.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import abc
from typing import List, Optional

from pydantic import BaseModel, Field, root_validator
from pydantic import BaseModel, ConfigDict, Field, model_validator

from pydatalab.models.relationships import TypedRelationship
from pydatalab.models.utils import (
Expand Down Expand Up @@ -34,7 +34,8 @@ class Entry(BaseModel, abc.ABC):
relationships: Optional[List[TypedRelationship]] = None
"""A list of related entries and their types."""

@root_validator(pre=True)
@model_validator(mode="before")
@classmethod
def check_id_names(cls, values):
"""Slightly upsetting hack: this case *should* be covered by the pydantic setting for
populating fields by alias names.
Expand Down Expand Up @@ -63,7 +64,6 @@ def to_reference(self, additional_fields: Optional[List[str]] = None) -> "EntryR

return EntryReference(**data)

class Config:
allow_population_by_field_name = True
json_encoders = JSON_ENCODERS
extra = "ignore"
# TODO[pydantic]: The following keys were removed: `json_encoders`.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information.
model_config = ConfigDict(populate_by_name=True, json_encoders=JSON_ENCODERS, extra="ignore")
8 changes: 4 additions & 4 deletions pydatalab/pydatalab/models/equipment.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ class Equipment(Item):

type: str = Field("equipment", const="equipment", pattern="^equipment$")

serial_numbers: Optional[str]
serial_numbers: Optional[str] = None
"""A string describing one or more serial numbers for the instrument."""

manufacturer: Optional[str]
manufacturer: Optional[str] = None
"""The manufacturer of this piece of equipment"""

location: Optional[str]
location: Optional[str] = None
"""Place where the equipment is located"""

contact: Optional[str]
contact: Optional[str] = None
"""Contact information for equipment (e.g., email address or phone number)."""
22 changes: 12 additions & 10 deletions pydatalab/pydatalab/models/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ class File(Entry, HasOwner, HasRevisionControl):

type: str = Field("files", const="files", pattern="^files$")

size: Optional[int] = Field(description="The size of the file on disk in bytes.")
size: Optional[int] = Field(None, description="The size of the file on disk in bytes.")

last_modified_remote: Optional[IsoformatDateTime] = Field(
description="The last date/time at which the remote file was modified."
None, description="The last date/time at which the remote file was modified."
)

item_ids: List[str] = Field(description="A list of item IDs associated with this file.")
Expand All @@ -27,27 +27,29 @@ class File(Entry, HasOwner, HasRevisionControl):

extension: str = Field(description="The file extension that the file was uploaded with.")

original_name: Optional[str] = Field(description="The raw filename as uploaded.")
original_name: Optional[str] = Field(None, description="The raw filename as uploaded.")

location: Optional[str] = Field(description="The location of the file on disk.")
location: Optional[str] = Field(None, description="The location of the file on disk.")

url_path: Optional[str] = Field(description="The path to a remote file.")
url_path: Optional[str] = Field(None, description="The path to a remote file.")

source: Optional[str] = Field(
description="The source of the file, e.g. 'remote' or 'uploaded'."
None, description="The source of the file, e.g. 'remote' or 'uploaded'."
)

time_added: datetime.datetime = Field(description="The timestamp for the original file upload.")

metadata: Optional[Dict[Any, Any]] = Field(description="Any additional metadata.")
metadata: Optional[Dict[Any, Any]] = Field(None, description="Any additional metadata.")

representation: Optional[Any] = Field()
representation: Optional[Any] = Field(None)

source_server_name: Optional[str] = Field(
description="The server name at which the file is stored."
None, description="The server name at which the file is stored."
)

source_path: Optional[str] = Field(description="The path to the file on the remote resource.")
source_path: Optional[str] = Field(
None, description="The path to the file on the remote resource."
)

is_live: bool = Field(
description="Whether or not the file should be watched for future updates."
Expand Down
10 changes: 6 additions & 4 deletions pydatalab/pydatalab/models/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,23 @@ class Item(Entry, HasOwner, HasRevisionControl, IsCollectable, HasBlocks, abc.AB
item_id: HumanReadableIdentifier
"""A locally unique, human-readable identifier for the entry. This ID is mutable."""

description: Optional[str]
description: Optional[str] = None
"""A description of the item, either in plain-text or a markup language."""

date: Optional[IsoformatDateTime]
date: Optional[IsoformatDateTime] = None
"""A relevant 'creation' timestamp for the entry (e.g., purchase date, synthesis date)."""

name: Optional[str]
name: Optional[str] = None
"""An optional human-readable/usable name for the entry."""

files: Optional[List[File]]
files: Optional[List[File]] = None
"""Any files attached to this sample."""

file_ObjectIds: List[PyObjectId] = Field([])
"""Links to object IDs of files stored within the database."""

# TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information.
@validator("refcode", pre=True, always=True)
def refcode_validator(cls, v):
"""Generate a refcode if not provided."""
Expand Down
23 changes: 15 additions & 8 deletions pydatalab/pydatalab/models/people.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from enum import Enum
from typing import List, Optional
from typing import List, Literal, Optional

import bson
import bson.errors
from pydantic import BaseModel, ConstrainedStr, Field, parse_obj_as, validator
from pydantic import BaseModel, ConstrainedStr, Field, field_validator, parse_obj_as, validator
from pydantic import EmailStr as PydanticEmailStr

from pydatalab.models.entries import Entry
Expand Down Expand Up @@ -36,9 +36,11 @@ class Identity(BaseModel):
verified: bool = Field(False)
"""Whether the identity has been verified (by some means, e.g., OAuth2 or email)"""

display_name: Optional[str]
display_name: Optional[str] = None
"""The user's display name associated with the identity, also to be exposed in free text searches."""

# TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information.
@validator("name", pre=True, always=True)
def add_missing_name(cls, v, values):
"""If the identity is created without a free-text 'name', then
Expand All @@ -55,6 +57,8 @@ def add_missing_name(cls, v, values):

return v

# TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information.
@validator("verified", pre=True, always=True)
def add_missing_verification(cls, v):
"""Fills in missing value for `verified` if not given."""
Expand Down Expand Up @@ -101,32 +105,35 @@ class AccountStatus(str, Enum):
class Person(Entry):
"""A model that describes an individual and their digital identities."""

type: str = Field("people", const=True)
type: Literal["people"] = "people"
"""The entry type as a string."""

identities: List[Identity] = Field(default_factory=list)
"""A list of identities attached to this person, e.g., email addresses, OAuth accounts."""

display_name: Optional[DisplayName]
display_name: Optional[DisplayName] = None
"""The user-chosen display name."""

contact_email: Optional[EmailStr]
contact_email: Optional[EmailStr] = None
"""In the case of multiple *verified* email identities, this email will be used as the primary contact."""

managers: Optional[List[PyObjectId]]
managers: Optional[List[PyObjectId]] = None
"""A list of user IDs that can manage this person's items."""

account_status: AccountStatus = Field(AccountStatus.UNVERIFIED)
"""The status of the user's account."""

# TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information.
@validator("type", pre=True, always=True)
def add_missing_type(cls, v):
"""Fill in missing `type` field if not provided."""
if v is None:
v = "people"
return v

@validator("type", pre=True)
@field_validator("type", mode="before")
@classmethod
def set_default_type(cls, _):
return "people"

Expand Down
Loading

0 comments on commit 059ec18

Please sign in to comment.