mirror of https://github.com/eyhc1/rendercv.git
refactor
This commit is contained in:
parent
9cdd7e5b0f
commit
4178c3e5e9
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue