Skip to content

Commit

Permalink
Require Pydantic 2 (#1391)
Browse files Browse the repository at this point in the history
Closes #1199 with a minor version bump to 0.12
  • Loading branch information
cthoyt authored Jan 30, 2025
1 parent b5b8274 commit fedaae7
Show file tree
Hide file tree
Showing 21 changed files with 48 additions and 91 deletions.
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
author = "Charles Tapley Hoyt"

# The full version, including alpha/beta/rc tags.
release = "0.11.36-dev"
release = "0.12.0-dev"

# The short X.Y version.
parsed_version = re.match(
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ markers = [

[project]
name = "bioregistry"
version = "0.11.36-dev"
version = "0.12.0-dev"
description = "Integrated registry of biological databases and nomenclatures"
readme = "README.md"
authors = [
Expand Down Expand Up @@ -70,7 +70,7 @@ dependencies = [
"pystow>=0.1.13",
"click",
"more_click>=0.1.2",
"pydantic",
"pydantic>=2.0",
"curies>=0.7.0"
]

Expand Down Expand Up @@ -268,7 +268,7 @@ known-first-party = [
docstring-code-format = true

[tool.bumpversion]
current_version = "0.11.36-dev"
current_version = "0.12.0-dev"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(?:-(?P<release>[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+(?P<build>[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?"
serialize = [
"{major}.{minor}.{patch}-{release}+{build}",
Expand Down
4 changes: 1 addition & 3 deletions src/bioregistry/app/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
)

from .utils import FORMAT_MAP, _autocomplete, _search
from ..utils import pydantic_dict

__all__ = [
"api_router",
Expand Down Expand Up @@ -57,8 +56,7 @@ class YAMLResponse(Response):
def render(self, content: Any) -> bytes:
"""Render content as YAML."""
if isinstance(content, BaseModel):
content = pydantic_dict(
content,
content = content.model_dump(
exclude_none=True,
exclude_unset=True,
)
Expand Down
2 changes: 0 additions & 2 deletions src/bioregistry/app/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from .api import api_router
from .constants import BIOSCHEMAS
from .ui import ui_blueprint
from ..constants import PYDANTIC_1

if TYPE_CHECKING:
import bioregistry
Expand Down Expand Up @@ -194,7 +193,6 @@ def get_app(
curie_to_str=curie_to_str,
fastapi_url_for=fast_api.url_path_for,
markdown=markdown,
is_pydantic_1=PYDANTIC_1,
)

if return_flask:
Expand Down
12 changes: 3 additions & 9 deletions src/bioregistry/app/templates/meta/related.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,9 @@
{% endmacro %}

{% macro registry_field_dl(cls, key) -%}
{% if is_pydantic_1 %}
{% set field = cls.__fields__[key].field_info %}
<dt>{{ field.title or key.replace("_", " ").title() }}</dt>
<dd>{{ field.description }}</dd>
{% else %}
{% set field = cls.model_fields[key] %}
<dt>{{ field.title or key.replace("_", " ").title() }}</dt>
<dd>{{ field.description }}</dd>
{% endif %}
{% set field = cls.model_fields[key] %}
<dt>{{ field.title or key.replace("_", " ").title() }}</dt>
<dd>{{ field.description }}</dd>
{% endmacro %}

{% block styles %}
Expand Down
6 changes: 3 additions & 3 deletions src/bioregistry/app/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
read_prefix_reviews,
read_registry_contributions,
)
from ..utils import curie_to_str, pydantic_schema
from ..utils import curie_to_str

__all__ = [
"ui_blueprint",
Expand Down Expand Up @@ -275,7 +275,7 @@ def contexts() -> str:
"contexts.html",
rows=manager.contexts.items(),
formats=FORMATS,
schema=pydantic_schema(Context),
schema=Context.model_json_schema(),
)


Expand All @@ -289,7 +289,7 @@ def context(identifier: str) -> str:
"context.html",
identifier=identifier,
entry=entry,
schema=pydantic_schema(Context)["properties"],
schema=Context.model_json_schema()["properties"],
formats=FORMATS,
)

Expand Down
8 changes: 3 additions & 5 deletions src/bioregistry/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from bioregistry.resource_manager import Manager

from .proxies import manager
from ..utils import _norm, pydantic_dict
from ..utils import _norm


def _get_resource_providers(
Expand Down Expand Up @@ -178,15 +178,13 @@ def serialize(

if accept == "application/json":
return current_app.response_class(
json.dumps(
pydantic_dict(data, exclude_unset=True, exclude_none=True), ensure_ascii=False
),
json.dumps(data.model_dump(exclude_unset=True, exclude_none=True), ensure_ascii=False),
mimetype="application/json",
)
elif accept in "application/yaml":
return current_app.response_class(
yaml.safe_dump(
pydantic_dict(data, exclude_unset=True, exclude_none=True), allow_unicode=True
data.model_dump(exclude_unset=True, exclude_none=True), allow_unicode=True
),
mimetype="text/plain",
)
Expand Down
3 changes: 1 addition & 2 deletions src/bioregistry/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
from bioregistry.constants import DOCS_IMG, EXPORT_REGISTRY
from bioregistry.license_standardizer import standardize_license
from bioregistry.schema import Resource
from bioregistry.utils import pydantic_dict

if TYPE_CHECKING:
import matplotlib.axes
Expand Down Expand Up @@ -481,7 +480,7 @@ def _get_license_and_conflicts() -> tuple[list[str], set[str], set[str], set[str
def _remap(*, key: str, prefixes: Collection[str]) -> Set[str]:
br_external_to = {}
for br_id, resource in read_registry().items():
_k = (pydantic_dict(resource).get(key) or {}).get("prefix")
_k = (resource.model_dump().get(key) or {}).get("prefix")
if _k:
br_external_to[_k] = br_id

Expand Down
4 changes: 1 addition & 3 deletions src/bioregistry/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

"""Constants and utilities for registries."""

import importlib.metadata
import os
import pathlib
import re
Expand All @@ -21,8 +20,7 @@
"RAW_DIRECTORY",
]

PYDANTIC_1 = importlib.metadata.version("pydantic").startswith("1.")
PATTERN_KEY = "regex" if PYDANTIC_1 else "pattern"
PATTERN_KEY = "pattern"
ORCID_PATTERN = r"^\d{4}-\d{4}-\d{4}-\d{3}(\d|X)$"

HERE = pathlib.Path(os.path.abspath(os.path.dirname(__file__)))
Expand Down
3 changes: 1 addition & 2 deletions src/bioregistry/export/warnings_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import bioregistry
from bioregistry.constants import DOCS_DATA, EXTERNAL
from bioregistry.resolve import get_external
from bioregistry.utils import pydantic_dict

__all__ = [
"export_warnings",
Expand All @@ -26,7 +25,7 @@
CURATIONS_PATH = DOCS_DATA.joinpath("curation.yml")

ENTRIES = sorted(
(prefix, pydantic_dict(resource, exclude_none=True))
(prefix, resource.model_dump(exclude_none=True))
for prefix, resource in bioregistry.read_registry().items()
)

Expand Down
4 changes: 2 additions & 2 deletions src/bioregistry/health/check_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import bioregistry
from bioregistry.constants import DOCS_DATA
from bioregistry.utils import pydantic_dict, secho
from bioregistry.utils import secho

__all__ = [
"main",
Expand Down Expand Up @@ -159,7 +159,7 @@ def main() -> None:
database.runs.append(current_run)
database.runs = sorted(database.runs, key=attrgetter("time"), reverse=True)

HEALTH_YAML_PATH.write_text(yaml.safe_dump(pydantic_dict(database, exclude_none=True)))
HEALTH_YAML_PATH.write_text(yaml.safe_dump(database.model_dump(exclude_none=True)))
click.echo(f"Wrote to {HEALTH_YAML_PATH}")


Expand Down
24 changes: 6 additions & 18 deletions src/bioregistry/schema/struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
)

from pydantic import BaseModel, Field, PrivateAttr
from pydantic.json_schema import models_json_schema

from bioregistry import constants as brc
from bioregistry.constants import (
Expand All @@ -40,18 +41,10 @@
EMAIL_RE,
ORCID_PATTERN,
PATTERN_KEY,
PYDANTIC_1,
URI_FORMAT_KEY,
)
from bioregistry.license_standardizer import standardize_license
from bioregistry.utils import (
curie_to_str,
deduplicate,
pydantic_dict,
pydantic_parse,
removeprefix,
removesuffix,
)
from bioregistry.utils import curie_to_str, deduplicate, removeprefix, removesuffix

try:
from typing import Literal
Expand Down Expand Up @@ -670,7 +663,7 @@ class Resource(BaseModel):

def get_external(self, metaprefix: str) -> Mapping[str, Any]:
"""Get an external registry."""
return pydantic_dict(self).get(metaprefix) or dict()
return self.model_dump().get(metaprefix) or dict()

def get_mapped_prefix(self, metaprefix: str) -> Optional[str]:
"""Get the prefix for the given external.
Expand All @@ -695,7 +688,7 @@ def get_mapped_prefix(self, metaprefix: str) -> Optional[str]:

def get_prefix_key(self, key: str, metaprefixes: Union[str, Sequence[str]]) -> Any:
"""Get a key enriched by the given external resources' data."""
rv = pydantic_dict(self).get(key)
rv = self.model_dump().get(key)
if rv is not None:
return rv
if isinstance(metaprefixes, str):
Expand Down Expand Up @@ -1339,7 +1332,7 @@ def get_publications(self) -> List[Publication]:
)
if self.uniprot:
for publication in self.uniprot.get("publications", []):
publications.append(pydantic_parse(Publication, publication))
publications.append(Publication.model_validate(publication))
for provider in self.providers or []:
publications.extend(provider.publications or [])
return deduplicate_publications(publications)
Expand Down Expand Up @@ -2834,9 +2827,6 @@ def _allowed_uri_format(rv: str) -> bool:
@lru_cache(maxsize=1)
def get_json_schema() -> dict[str, Any]:
"""Get the JSON schema for the bioregistry."""
if PYDANTIC_1:
raise NotImplementedError

rv = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://bioregistry.io/schema.json",
Expand All @@ -2860,8 +2850,6 @@ def get_json_schema() -> dict[str, Any]:
)

# see https://docs.pydantic.dev/latest/usage/json_schema/#general-notes-on-json-schema-generation
from pydantic.json_schema import models_json_schema

_, schema_dict = models_json_schema(
[(model, "validation") for model in models], # type:ignore
title=title,
Expand Down Expand Up @@ -2895,7 +2883,7 @@ def _get(resource: Resource, key: str) -> Any:

def deduplicate_publications(publications: Iterable[Publication]) -> List[Publication]:
"""Deduplicate publications."""
records = [pydantic_dict(publication, exclude_none=True) for publication in publications]
records = [publication.model_dump(exclude_none=True) for publication in publications]
records_deduplicated = deduplicate(records, keys=DEDP_PUB_KEYS)
return [Publication(**record) for record in records_deduplicated]

Expand Down
4 changes: 1 addition & 3 deletions src/bioregistry/schema/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

from pydantic import BaseModel

from bioregistry.utils import pydantic_dict

__all__ = [
"sanitize_dict",
"sanitize_model",
Expand All @@ -31,7 +29,7 @@ def sanitize_dict(d: dict[str, Any]) -> dict[str, Any]:

def sanitize_model(base_model: BaseModel, **kwargs: Any) -> Mapping[str, Any]:
"""Sanitize a single Pydantic model."""
return sanitize_dict(pydantic_dict(base_model, **kwargs))
return sanitize_dict(base_model.model_dump(**kwargs))


def sanitize_mapping(mapping: Mapping[str, BaseModel]) -> Mapping[str, Mapping[str, Any]]:
Expand Down
11 changes: 5 additions & 6 deletions src/bioregistry/schema_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
MISMATCH_PATH,
)
from .schema import Collection, Context, Registry, Resource
from .utils import pydantic_dict, pydantic_parse

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -59,7 +58,7 @@ def _registry_from_path(path: Union[str, Path]) -> Mapping[str, Resource]:
data = json.load(file)
for prefix, value in data.items():
value.setdefault("prefix", prefix)
return {prefix: pydantic_parse(Resource, value) for prefix, value in data.items()}
return {prefix: Resource.model_validate(value) for prefix, value in data.items()}


def add_resource(resource: Resource) -> None:
Expand Down Expand Up @@ -125,7 +124,7 @@ def write_collections(collections: Mapping[str, Collection]) -> None:
collection.resources = sorted(set(collection.resources))
with open(COLLECTIONS_PATH, encoding="utf-8", mode="w") as file:
json.dump(
{"collections": [pydantic_dict(c, exclude_none=True) for c in values]},
{"collections": [c.model_dump(exclude_none=True) for c in values]},
file,
indent=2,
sort_keys=True,
Expand All @@ -140,7 +139,7 @@ def write_registry(registry: Mapping[str, Resource], *, path: Optional[Path] = N
with path.open(mode="w", encoding="utf-8") as file:
json.dump(
{
key: pydantic_dict(resource, exclude_none=True, exclude={"prefix"})
key: resource.model_dump(exclude_none=True, exclude={"prefix"})
for key, resource in registry.items()
},
file,
Expand All @@ -155,7 +154,7 @@ def write_metaregistry(metaregistry: Mapping[str, Registry]) -> None:
values = [v for _, v in sorted(metaregistry.items())]
with open(METAREGISTRY_PATH, mode="w", encoding="utf-8") as file:
json.dump(
{"metaregistry": [pydantic_dict(m, exclude_none=True) for m in values]},
{"metaregistry": [m.model_dump(exclude_none=True) for m in values]},
fp=file,
indent=2,
sort_keys=True,
Expand All @@ -167,7 +166,7 @@ def write_contexts(contexts: Mapping[str, Context]) -> None:
"""Write to contexts."""
with open(CONTEXTS_PATH, mode="w", encoding="utf-8") as file:
json.dump(
{key: pydantic_dict(context, exclude_none=True) for key, context in contexts.items()},
{key: context.model_dump(exclude_none=True) for key, context in contexts.items()},
fp=file,
indent=2,
sort_keys=True,
Expand Down
3 changes: 1 addition & 2 deletions src/bioregistry/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

from bioregistry import manager
from bioregistry.constants import TABLES_SUMMARY_LATEX_PATH
from bioregistry.utils import pydantic_dict
from bioregistry.version import get_version


Expand Down Expand Up @@ -124,7 +123,7 @@ def make(cls, force_download: bool = False):
prefixes_curated = sum(
any(
x not in metaprefixes
for x, v in pydantic_dict(entry).items()
for x, v in entry.model_dump().items()
if v is not None and x not in {"prefix", "mappings"}
)
for prefix, entry in registry.items()
Expand Down
Loading

0 comments on commit fedaae7

Please sign in to comment.