mirror of https://github.com/eyhc1/rendercv.git
improve logger
This commit is contained in:
parent
36db448628
commit
73a10bb124
|
@ -38,16 +38,23 @@ def user_friendly_errors(func: Callable) -> Callable:
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
# It is a Pydantic error
|
# It is a Pydantic error
|
||||||
error_messages = []
|
error_messages = []
|
||||||
error_messages.append("There are validation errors!")
|
error_messages.append("There are some problems with your input 🧐")
|
||||||
|
|
||||||
# Translate Pydantic's error messages to make them more user-friendly
|
# Translate Pydantic's error messages to make them more user-friendly
|
||||||
custom_error_messages_by_type = {
|
custom_error_messages_by_type = {
|
||||||
"url_scheme": "This is not a valid URL 😿",
|
"url_scheme": "This is not a valid URL 😿",
|
||||||
|
"string_type": "This is not a valid string 🤭",
|
||||||
|
"missing": "This field is required, but it is missing 😆",
|
||||||
|
"literal_error": "Only the following values are allowed: {expected} 😒",
|
||||||
}
|
}
|
||||||
custom_error_messages_by_msg = {
|
custom_error_messages_by_msg = {
|
||||||
"value is not a valid phone number": (
|
"value is not a valid phone number": (
|
||||||
"This is not a valid phone number 👺"
|
"This is not a valid phone number 👺"
|
||||||
)
|
),
|
||||||
|
"String should match pattern '\\d+\\.?\\d* *(cm|in|pt|mm|ex|em)'": (
|
||||||
|
"This is not a valid length! Use a number followed by a unit "
|
||||||
|
"of length (cm, in, pt, mm, ex, em) 👺"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
new_errors: list[ErrorDetails] = []
|
new_errors: list[ErrorDetails] = []
|
||||||
for error in e.errors():
|
for error in e.errors():
|
||||||
|
@ -68,21 +75,34 @@ def user_friendly_errors(func: Callable) -> Callable:
|
||||||
|
|
||||||
if custom_message:
|
if custom_message:
|
||||||
ctx = error.get("ctx")
|
ctx = error.get("ctx")
|
||||||
error["msg"] = (
|
if ctx:
|
||||||
custom_message.format(**ctx) if ctx else custom_message
|
if ctx.get("error"):
|
||||||
)
|
error["msg"] = ctx["error"].args[0]
|
||||||
|
else:
|
||||||
|
error["msg"] = custom_message.format(**ctx)
|
||||||
|
else:
|
||||||
|
error["msg"] = custom_message
|
||||||
|
|
||||||
# If the input value is a dictionary or if the input value is in the
|
if error["input"] is not None:
|
||||||
# error message, remove it
|
# If the input value is a dictionary, remove it
|
||||||
if isinstance(error["input"], dict) or error["input"] in error["msg"]:
|
if isinstance(error["input"], dict):
|
||||||
|
error["input"] = None
|
||||||
|
elif isinstance(error["input"], (float, int, bool, str)):
|
||||||
|
# Or if the input value is in the error message, remove it
|
||||||
|
input_value = str(error["input"])
|
||||||
|
if input_value in error["msg"]:
|
||||||
error["input"] = None
|
error["input"] = None
|
||||||
|
|
||||||
new_errors.append(error)
|
new_errors.append(error)
|
||||||
|
|
||||||
# Create a custom error message for RenderCV users
|
# Create a custom error message for RenderCV users
|
||||||
for error in new_errors:
|
for error in new_errors:
|
||||||
|
if len(error["loc"]) > 0:
|
||||||
location = ".".join(error["loc"])
|
location = ".".join(error["loc"])
|
||||||
error_messages.append(f"{location}:\n {error['msg']}")
|
error_messages.append(f"{location}:\n {error['msg']}")
|
||||||
|
else:
|
||||||
|
error_messages.append(f"{error['msg']}")
|
||||||
|
|
||||||
if error["input"]:
|
if error["input"]:
|
||||||
error_messages[-1] += f"\n Your input was \"{error['input']}\""
|
error_messages[-1] += f"\n Your input was \"{error['input']}\""
|
||||||
error_message = "\n\n ".join(error_messages)
|
error_message = "\n\n ".join(error_messages)
|
||||||
|
|
|
@ -65,6 +65,7 @@ dictionary = [
|
||||||
"javascript",
|
"javascript",
|
||||||
]
|
]
|
||||||
spell = SpellChecker()
|
spell = SpellChecker()
|
||||||
|
all_misspelled_words = set()
|
||||||
|
|
||||||
|
|
||||||
def check_spelling(sentence: str) -> str:
|
def check_spelling(sentence: str) -> str:
|
||||||
|
@ -110,10 +111,7 @@ def check_spelling(sentence: str) -> str:
|
||||||
if word in dictionary:
|
if word in dictionary:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.warning(
|
all_misspelled_words.add(word)
|
||||||
f'The word "{word}" might be misspelled according to the'
|
|
||||||
" pyspellchecker."
|
|
||||||
)
|
|
||||||
|
|
||||||
return sentence
|
return sentence
|
||||||
|
|
||||||
|
@ -1232,6 +1230,35 @@ class CurriculumVitae(BaseModel):
|
||||||
|
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
@classmethod
|
||||||
|
def print_all_the_misspeled_words(cls, model):
|
||||||
|
"""Print all the words that are misspelled according to pyspellchecker."""
|
||||||
|
if len(all_misspelled_words) > 0:
|
||||||
|
messages = []
|
||||||
|
messages.append(
|
||||||
|
"The following words might be misspelled (according to pyspellchecker):"
|
||||||
|
)
|
||||||
|
|
||||||
|
misspelled_words = list(all_misspelled_words)
|
||||||
|
|
||||||
|
# Make misspeled_words a list of lists where each list contains 5:
|
||||||
|
misspelled_words = [
|
||||||
|
misspelled_words[i : i + 5] for i in range(0, len(misspelled_words), 5)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Join the words in each list with a comma, and join the lists with a new
|
||||||
|
# line:
|
||||||
|
misspelled_words = "\n ".join(
|
||||||
|
[", ".join(words) for words in misspelled_words]
|
||||||
|
)
|
||||||
|
messages.append(f" {misspelled_words}")
|
||||||
|
|
||||||
|
# Print the messages:
|
||||||
|
logger.warning("\n".join(messages))
|
||||||
|
|
||||||
|
return model
|
||||||
|
|
||||||
@computed_field
|
@computed_field
|
||||||
@cached_property
|
@cached_property
|
||||||
def connections(self) -> list[Connection]:
|
def connections(self) -> list[Connection]:
|
||||||
|
@ -1328,6 +1355,10 @@ class CurriculumVitae(BaseModel):
|
||||||
link_text = custom_section.link_text
|
link_text = custom_section.link_text
|
||||||
entries = custom_section.entries
|
entries = custom_section.entries
|
||||||
break
|
break
|
||||||
|
else:
|
||||||
|
entry_type = None
|
||||||
|
link_text = None
|
||||||
|
entries = None
|
||||||
|
|
||||||
if entry_type is None or entries is None:
|
if entry_type is None or entries is None:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
@ -1396,10 +1427,15 @@ class RenderCVDataModel(BaseModel):
|
||||||
section_titles = [section.title for section in cv.sections]
|
section_titles = [section.title for section in cv.sections]
|
||||||
for title in design.options.show_timespan_in: # type: ignore
|
for title in design.options.show_timespan_in: # type: ignore
|
||||||
if title not in section_titles:
|
if title not in section_titles:
|
||||||
|
not_used_section_titles = list(
|
||||||
|
set(section_titles) - set(design.options.show_timespan_in)
|
||||||
|
)
|
||||||
|
not_used_section_titles = ", ".join(not_used_section_titles)
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f'The section "{title}" that is specified in the'
|
f'The section "{title}" that is specified in the'
|
||||||
' "show_timespan_in" option is not found in the CV 😱! The'
|
' "show_timespan_in" option is not found in the CV 😱 You'
|
||||||
f" available section titles are: {section_titles}"
|
" might have wanted to use one of these:"
|
||||||
|
f" {not_used_section_titles}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return model
|
return model
|
||||||
|
|
Loading…
Reference in New Issue