data_models: fix ordering of entry type keys

This commit is contained in:
Sina Atalay 2024-03-17 20:23:59 +01:00
parent 993f22625b
commit 91452bd20d
1 changed files with 137 additions and 115 deletions

View File

@ -141,12 +141,124 @@ class RenderCVBaseModel(pydantic.BaseModel):
# ====================================================================================== # ======================================================================================
class OneLineEntry(RenderCVBaseModel):
"""This class is the data model of `OneLineEntry`."""
label: str = pydantic.Field(
title="Name",
description="The label of the OneLineEntry.",
)
details: str = pydantic.Field(
title="Details",
description="The details of the OneLineEntry.",
)
class PublicationEntry(RenderCVBaseModel):
"""This class is the data model of `PublicationEntry`."""
title: str = pydantic.Field(
title="Title of the Publication",
description="The title of the publication.",
)
authors: list[str] = pydantic.Field(
title="Authors",
description="The authors of the publication in order as a list of strings.",
)
doi: Optional[str] = pydantic.Field(
default=None,
title="DOI",
description="The DOI of the publication.",
examples=["10.48550/arXiv.2310.03138"],
)
date: int | RenderCVDate = pydantic.Field(
title="Publication Date",
description=(
"The date of the publication in YYYY-MM-DD, YYYY-MM, or YYYY format."
),
examples=["2021-10-31", "2010"],
json_schema_extra={"default": "2020-01-01"},
)
journal: Optional[str] = pydantic.Field(
default=None,
title="Journal",
description="The journal or the conference name.",
)
@pydantic.field_validator("date")
@classmethod
def check_date(cls, date: int | RenderCVDate) -> int | RenderCVDate:
"""Check if the date is a valid date."""
# The function below will raise an error if the date is not valid:
get_date_object(date)
return date
@pydantic.field_validator("doi")
@classmethod
def check_doi(cls, doi: Optional[str]) -> Optional[str]:
"""Check if the DOI exists in the DOI System."""
if doi is not None:
# see https://stackoverflow.com/a/60671292/18840665 for the explanation of
# the next line:
ssl._create_default_https_context = ssl._create_unverified_context # type: ignore
doi_url = f"http://doi.org/{doi}"
try:
urlopen(doi_url)
except HTTPError as err:
if err.code == 404:
raise ValueError("DOI cannot be found in the DOI System!")
except InvalidURL:
raise ValueError("This DOI is not valid!")
return doi
@functools.cached_property
def doi_url(self) -> str:
"""Return the URL of the DOI."""
# self.doi == "" is added because None values are replaced with "" in
# renderer.TemplatedFile class (to make templating easier)
if self.doi is None or self.doi == "":
return ""
else:
return f"https://doi.org/{self.doi}"
@functools.cached_property
def date_string(self) -> str:
"""Return the date string of the publication."""
if isinstance(self.date, int):
date_string = str(self.date)
else:
# Then it is a string
date_object = get_date_object(self.date)
date_string = format_date(date_object)
return date_string
class BulletEntry(RenderCVBaseModel):
"""This class is the data model of `BulletEntry`."""
bullet: str = pydantic.Field(
title="Bullet",
description="The bullet of the BulletEntry.",
)
class EntryBase(RenderCVBaseModel): class EntryBase(RenderCVBaseModel):
"""This class is the parent class of some of the entry types. It is being used """This class is the parent class of some of the entry types. It is being used
because some of the entry types have common fields like dates, highlights, location, because some of the entry types have common fields like dates, highlights, location,
etc. etc.
""" """
location: Optional[str] = pydantic.Field(
default=None,
title="Location",
description="The location of the event.",
examples=["Istanbul, Türkiye"],
)
start_date: Optional[int | RenderCVDate] = pydantic.Field( start_date: Optional[int | RenderCVDate] = pydantic.Field(
default=None, default=None,
title="Start Date", title="Start Date",
@ -184,12 +296,6 @@ class EntryBase(RenderCVBaseModel):
description="The highlights of the event as a list of strings.", description="The highlights of the event as a list of strings.",
examples=["Did this.", "Did that."], examples=["Did this.", "Did that."],
) )
location: Optional[str] = pydantic.Field(
default=None,
title="Location",
description="The location of the event.",
examples=["Istanbul, Türkiye"],
)
@pydantic.model_validator( @pydantic.model_validator(
mode="after", mode="after",
@ -418,21 +524,7 @@ class EntryBase(RenderCVBaseModel):
return time_span_string return time_span_string
class OneLineEntry(RenderCVBaseModel): class NormalEntryBase(RenderCVBaseModel):
"""This class is the data model of `OneLineEntry`."""
label: str = pydantic.Field(
title="Name",
description="The label of the OneLineEntry.",
)
details: str = pydantic.Field(
title="Details",
description="The details of the OneLineEntry.",
)
class NormalEntry(EntryBase):
"""This class is the data model of `NormalEntry`."""
name: str = pydantic.Field( name: str = pydantic.Field(
title="Name", title="Name",
@ -440,9 +532,16 @@ class NormalEntry(EntryBase):
) )
class ExperienceEntry(EntryBase): # The following class is to make sure NormalEntryBase keys comes first,
"""This class is the data model of `ExperienceEntry`.""" # then the keys of the EntryBase class. The only way to achieve this in Pydantic is
# to do this.
class NormalEntry(EntryBase, NormalEntryBase):
"""This class is the data model of `NormalEntry`."""
pass
class ExperienceEntryBase(RenderCVBaseModel):
company: str = pydantic.Field( company: str = pydantic.Field(
title="Company", title="Company",
description="The company name.", description="The company name.",
@ -453,9 +552,16 @@ class ExperienceEntry(EntryBase):
) )
class EducationEntry(EntryBase): # The following class is to make sure ExperienceEntryBase keys comes first,
"""This class is the data model of `EducationEntry`.""" # then the keys of the EntryBase class. The only way to achieve this in Pydantic is
# to do this.
class ExperienceEntry(EntryBase, ExperienceEntryBase):
"""This class is the data model of `ExperienceEntry`."""
pass
class EducationEntryBase(RenderCVBaseModel):
institution: str = pydantic.Field( institution: str = pydantic.Field(
title="Institution", title="Institution",
description="The institution name.", description="The institution name.",
@ -473,97 +579,13 @@ class EducationEntry(EntryBase):
) )
class PublicationEntry(RenderCVBaseModel): # The following class is to make sure EducationEntryBase keys comes first,
"""This class is the data model of `PublicationEntry`.""" # then the keys of the EntryBase class. The only way to achieve this in Pydantic is
# to do this.
class EducationEntry(EntryBase, EducationEntryBase):
"""This class is the data model of `EducationEntry`."""
title: str = pydantic.Field( pass
title="Title of the Publication",
description="The title of the publication.",
)
authors: list[str] = pydantic.Field(
title="Authors",
description="The authors of the publication in order as a list of strings.",
)
doi: Optional[str] = pydantic.Field(
default=None,
title="DOI",
description="The DOI of the publication.",
examples=["10.48550/arXiv.2310.03138"],
)
date: int | RenderCVDate = pydantic.Field(
title="Publication Date",
description=(
"The date of the publication in YYYY-MM-DD, YYYY-MM, or YYYY format."
),
examples=["2021-10-31", "2010"],
json_schema_extra={"default": "2020-01-01"},
)
journal: Optional[str] = pydantic.Field(
default=None,
title="Journal",
description="The journal or the conference name.",
)
@pydantic.field_validator("date")
@classmethod
def check_date(cls, date: int | RenderCVDate) -> int | RenderCVDate:
"""Check if the date is a valid date."""
# The function below will raise an error if the date is not valid:
get_date_object(date)
return date
@pydantic.field_validator("doi")
@classmethod
def check_doi(cls, doi: Optional[str]) -> Optional[str]:
"""Check if the DOI exists in the DOI System."""
if doi is not None:
# see https://stackoverflow.com/a/60671292/18840665 for the explanation of
# the next line:
ssl._create_default_https_context = ssl._create_unverified_context # type: ignore
doi_url = f"http://doi.org/{doi}"
try:
urlopen(doi_url)
except HTTPError as err:
if err.code == 404:
raise ValueError("DOI cannot be found in the DOI System!")
except InvalidURL:
raise ValueError("This DOI is not valid!")
return doi
@functools.cached_property
def doi_url(self) -> str:
"""Return the URL of the DOI."""
# self.doi == "" is added because None values are replaced with "" in
# renderer.TemplatedFile class (to make templating easier)
if self.doi is None or self.doi == "":
return ""
else:
return f"https://doi.org/{self.doi}"
@functools.cached_property
def date_string(self) -> str:
"""Return the date string of the publication."""
if isinstance(self.date, int):
date_string = str(self.date)
else:
# Then it is a string
date_object = get_date_object(self.date)
date_string = format_date(date_object)
return date_string
class BulletEntry(RenderCVBaseModel):
"""This class is the data model of `BulletEntry`."""
bullet: str = pydantic.Field(
title="Bullet",
description="The bullet of the BulletEntry.",
)
# Create a custom type called Entry and ListOfEntries: # Create a custom type called Entry and ListOfEntries: