This commit is contained in:
Sina Atalay 2024-02-18 19:13:29 +01:00
parent 9cdd7e5b0f
commit 4178c3e5e9
3 changed files with 66 additions and 57 deletions

View File

@ -54,7 +54,7 @@ def welcome():
print(table)
def warning(text):
def warning(text: str):
"""Print a warning message to the terminal.
Args:
@ -63,7 +63,7 @@ def warning(text):
print(f"[bold yellow]{text}")
def error(text, exception=None):
def error(text: str, exception: Optional[Exception] = None):
"""Print an error message to the terminal.
Args:
@ -80,7 +80,7 @@ def error(text, exception=None):
print(f"\n[bold red]{text}\n")
def information(text):
def information(text: str):
"""Print an information message to the terminal.
Args:

View File

@ -53,7 +53,7 @@ def get_date_object(date: str | int) -> Date:
data models.
Args:
date_string (str): The date string to parse.
date (str): The date string to parse.
Returns:
datetime.date: The parsed date.
"""
@ -528,7 +528,7 @@ class PublicationEntry(RenderCVBaseModel):
"""Check if the DOI exists in the DOI System."""
# see https://stackoverflow.com/a/60671292/18840665 for the explanation of the
# next line:
ssl._create_default_https_context = ssl._create_unverified_context
ssl._create_default_https_context = ssl._create_unverified_context # type: ignore
doi_url = f"http://doi.org/{doi}"
@ -550,7 +550,8 @@ class PublicationEntry(RenderCVBaseModel):
"""Return the date string of the publication."""
if isinstance(self.date, int):
date_string = str(self.date)
elif isinstance(self.date, str):
else:
# Then it is a string
date_object = get_date_object(self.date)
date_string = format_date(date_object)
@ -667,13 +668,9 @@ def get_entry_and_section_type(
"""Determine the entry and section type based on the entry.
Args:
entry (dict[str, Any] | EducationEntry | ExperienceEntry | PublicationEntry |
NormalEntry | OneLineEntry | str): The entry to determine the type.
entry (dict[str, Any] | EducationEntry | ExperienceEntry | PublicationEntry | NormalEntry | OneLineEntry | str): The entry to determine the type.
Returns:
tuple[str, Type[SectionWithTextEntries | SectionWithOneLineEntries |
SectionWithExperienceEntries | SectionWithEducationEntries |
SectionWithPublicationEntries | SectionWithNormalEntries]]: The entry type and the
section type.
tuple[str, Type[SectionWithTextEntries | SectionWithOneLineEntries | SectionWithExperienceEntries | SectionWithEducationEntries | SectionWithPublicationEntries | SectionWithNormalEntries]]: The entry type and the section type.
"""
if isinstance(entry, dict):
if "details" in entry:
@ -709,7 +706,7 @@ def get_entry_and_section_type(
elif isinstance(entry, PublicationEntry):
entry_type = "PublicationEntry"
section_type = SectionWithPublicationEntries
elif isinstance(entry, NormalEntry):
elif isinstance(entry, NormalEntry): # type: ignore
entry_type = "NormalEntry"
section_type = SectionWithNormalEntries
else:
@ -892,7 +889,7 @@ class CurriculumVitae(RenderCVBaseModel):
title="Social Networks",
description="The social networks of the person.",
)
sections_input: dict[str, SectionInput] = pydantic.Field(
sections_input: Optional[dict[str, SectionInput]] = pydantic.Field(
default=None,
title="Sections",
description="The sections of the CV.",
@ -902,27 +899,21 @@ class CurriculumVitae(RenderCVBaseModel):
@functools.cached_property
def sections(self) -> list[Section]:
"""Return all the sections of the CV with their titles."""
sections = []
sections: list[Section] = []
if self.sections_input is not None:
for title, section_or_entries in self.sections_input.items():
title = title.replace("_", " ").title()
if isinstance(section_or_entries, list):
entry_type, section_type = get_entry_and_section_type(
section_or_entries[0]
)
section = section_type(
title=title,
entry_type=entry_type, # type: ignore
entries=section_or_entries, # type: ignore
)
sections.append(section)
entry_type, section_type = get_entry_and_section_type(
section_or_entries[0]
)
else:
raise RuntimeError(
"This error shouldn't have been raised. Please open an"
" issue on GitHub."
)
section = section_type(
title=title,
entry_type=entry_type, # type: ignore
entries=section_or_entries, # type: ignore
)
sections.append(section)
return sections
@ -981,6 +972,12 @@ class RenderCVDataModel(RenderCVBaseModel):
return rendercv_design_validator.validate_python(design)
else:
theme_name: str = design["theme"] # type: ignore
if not isinstance(theme_name, str):
raise RuntimeError(
"This error shouldn't have been raised. Please open an issue on"
" GitHub."
)
# check if the theme name is valid:
if not theme_name.isalpha():
raise ValueError(
@ -1093,7 +1090,7 @@ def read_input_file(
)
file_content = file_path.read_text(encoding="utf-8")
input_as_dictionary: dict[str, Any] = ruamel.yaml.YAML().load(file_content)
input_as_dictionary: dict[str, Any] = ruamel.yaml.YAML().load(file_content) # type: ignore
# validate the parsed dictionary by creating an instance of RenderCVDataModel:
rendercv_data_model = RenderCVDataModel(**input_as_dictionary)
@ -1224,7 +1221,7 @@ def get_a_sample_data_model(name: str = "John Doe") -> RenderCVDataModel:
SocialNetwork(network="LinkedIn", username="yourusername"),
SocialNetwork(network="GitHub", username="yourusername"),
],
sections=sections,
sections=sections, # type: ignore
)
design = ClassicThemeOptions(theme="classic", show_timespan_in=["Experience"])
@ -1232,7 +1229,7 @@ def get_a_sample_data_model(name: str = "John Doe") -> RenderCVDataModel:
return RenderCVDataModel(cv=cv, design=design)
def generate_json_schema() -> dict:
def generate_json_schema() -> dict[str, Any]:
"""Generate the JSON schema of RenderCV.
JSON schema is generated for the users to make it easier for them to write the input
@ -1245,7 +1242,7 @@ def generate_json_schema() -> dict:
"""
class RenderCVSchemaGenerator(pydantic.json_schema.GenerateJsonSchema):
def generate(self, schema, mode="validation"):
def generate(self, schema, mode="validation"): # type: ignore
json_schema = super().generate(schema, mode=mode)
# Basic information about the schema:
@ -1258,7 +1255,7 @@ def generate_json_schema() -> dict:
# Loop through $defs and remove docstring descriptions and fix optional
# fields
for key, value in json_schema["$defs"].items():
for _, value in json_schema["$defs"].items():
# Don't allow additional properties
value["additionalProperties"] = False

View File

@ -46,7 +46,7 @@ class TemplatedFile:
def template(
self,
theme_name,
theme_name: str,
template_name: Literal[
"EducationEntry",
"ExperienceEntry",
@ -75,14 +75,7 @@ class TemplatedFile:
Args:
template_name (str): The name of the template file.
entry (Optional[
dm.EducationEntry,
dm.ExperienceEntry,
dm.NormalEntry,
dm.PublicationEntry,
dm.OneLineEntry,
str
]): The data model of the entry.
entry (Optional[dm.EducationEntry, dm.ExperienceEntry, dm.NormalEntry,dm.PublicationEntry, dm.OneLineEntry, str]): The data model of the entry.
section_title (Optional[str]): The title of the section.
is_first_entry (Optional[bool]): Whether the entry is the first one in the
section.
@ -144,7 +137,7 @@ class LaTeXFile(TemplatedFile):
)
super().__init__(data_model, environment)
def render_templates(self):
def render_templates(self) -> tuple[str, str, list[tuple[str, list[str], str]]]:
"""Render and return all the templates for the $\\LaTeX$ file.
Returns:
@ -154,12 +147,12 @@ class LaTeXFile(TemplatedFile):
# Template the preamble, header, and sections:
preamble = self.template("Preamble")
header = self.template("Header")
sections = []
sections: list[tuple[str, list[str], str]] = []
for section in self.cv.sections:
section_beginning = self.template(
"SectionBeginning", section_title=section.title
)
entries = []
entries: list[str] = []
for i, entry in enumerate(section.entries):
if i == 0:
is_first_entry = True
@ -203,7 +196,17 @@ class LaTeXFile(TemplatedFile):
section_title: Optional[str] = None,
is_first_entry: Optional[bool] = None,
) -> str:
"""Template one of the files in the `themes` directory."""
"""Template one of the files in the `themes` directory.
Args:
template_name (str): The name of the template file.
entry (Optional[dm.EducationEntry, dm.ExperienceEntry, dm.NormalEntry,dm.PublicationEntry, dm.OneLineEntry, str]): The data model of the entry.
section_title (Optional[str]): The title of the section.
is_first_entry (Optional[bool]): Whether the entry is the first one in the section.
Returns:
str: The templated file.
"""
result = super().template(
self.design.theme,
template_name,
@ -215,7 +218,11 @@ class LaTeXFile(TemplatedFile):
return result
def get_latex_code(self):
"""Get the $\\LaTeX$ code of the file."""
"""Get the $\\LaTeX$ code of the file.
Returns:
str: The $\\LaTeX$ code.
"""
preamble, header, sections = self.render_templates()
return self.get_full_code(
"main.j2.tex",
@ -234,18 +241,13 @@ class MarkdownFile(TemplatedFile):
data model and Jinja2 templates. It inherits from the TemplatedFile class. Markdown
files are generated to produce a PDF which can be copy-pasted to
[Grammarly](https://app.grammarly.com/) for proofreading.
Args:
data_model (dm.RenderCVDataModel): The data model.
environment (jinja2.Environment): The Jinja2 environment.
"""
def render_templates(self):
"""Render and return all the templates for the Markdown file.
Returns:
Tuple[str, List[Tuple[str, List[str]]]: The header and sections of the
Markdown file.
Tuple[str, List[Tuple[str, List[str]]]]: The header and sections of the Markdown file.
"""
# Template the header and sections:
header = self.template("Header")
@ -297,7 +299,17 @@ class MarkdownFile(TemplatedFile):
section_title: Optional[str] = None,
is_first_entry: Optional[bool] = None,
) -> str:
"""Template one of the files in the `themes` directory."""
"""Template one of the files in the `themes` directory.
Args:
template_name (str): The name of the template file.
entry (Optional[dm.EducationEntry, dm.ExperienceEntry, dm.NormalEntry,dm.PublicationEntry, dm.OneLineEntry, str]): The data model of the entry.
section_title (Optional[str]): The title of the section.
is_first_entry (Optional[bool]): Whether the entry is the first one in the section.
Returns:
str: The templated file.
"""
result = super().template(
"markdown",
template_name,
@ -729,7 +741,7 @@ def divide_length_by(length: str, divider: float) -> str:
def get_an_item_with_a_specific_attribute_value(
items: list[Any], attribute: str, value: Any
items: Optional[list[Any]], attribute: str, value: Any
) -> Any:
"""Get an item from a list of items with a specific attribute value.