summaryrefslogtreecommitdiff
path: root/sysutils/py-rendercv
diff options
context:
space:
mode:
Diffstat (limited to 'sysutils/py-rendercv')
-rw-r--r--sysutils/py-rendercv/Makefile43
-rw-r--r--sysutils/py-rendercv/distinfo3
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_cli_error__handler.py20
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_cli_render__command_run__rendercv.py21
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_renderer_templater_entry__templates__from__input.py20
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_entries_bases_entry__with__complex__fields.py11
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_entries_bases_entry__with__date.py11
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_section.py46
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_social__network.py20
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_built__in__design.py22
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_classic__theme.py23
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_font__family.py8
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_typst__dimension.py8
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_locale_locale.py22
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_models_path.py19
-rw-r--r--sysutils/py-rendercv/files/patch-src_rendercv_schema_variant__pydantic__model__generator.py38
-rw-r--r--sysutils/py-rendercv/pkg-descr5
17 files changed, 340 insertions, 0 deletions
diff --git a/sysutils/py-rendercv/Makefile b/sysutils/py-rendercv/Makefile
new file mode 100644
index 000000000000..4eb46c2ca27c
--- /dev/null
+++ b/sysutils/py-rendercv/Makefile
@@ -0,0 +1,43 @@
+PORTNAME= rendercv
+DISTVERSION= 2.5
+CATEGORIES= sysutils python
+MASTER_SITES= PYPI
+PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX}
+
+MAINTAINER= dtxdf@FreeBSD.org
+COMMENT= Typst-based CV/resume generator
+WWW= https://github.com/rendercv/rendercv \
+ https://pypi.org/project/rendercv
+
+LICENSE= MIT
+
+BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}uv-build>=0:devel/py-uv-build@${PY_FLAVOR}
+RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}Jinja2>=0:devel/py-Jinja2@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}phonenumbers>=0:devel/py-phonenumbers@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}pydantic2>=0:devel/py-pydantic2@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}pydantic-extra-types>=0:devel/py-pydantic-extra-types@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}email-validator>=0:mail/py-email-validator@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}ruamel.yaml>=0:devel/py-ruamel.yaml@${PY_FLAVOR} \
+ ${PYTHON_PKGNAMEPREFIX}packaging>=0:devel/py-packaging@${PY_FLAVOR}
+
+USES= python
+USE_PYTHON= autoplist pep517
+
+NO_ARCH= yes
+
+OPTIONS_DEFINE= CLI MARKDOWN WATCHDOG TYPST FONT
+OPTIONS_DEFAULT= CLI MARKDOWN WATCHDOG TYPST FONT
+
+CLI_DESC= Enable Command-line interface support
+MARKDOWN_DESC= Convert Markdown to HTML
+WATCHDOG_DESC= Monitor files for updates
+TYPST_DESC= Render PDF from Typst source files
+FONT_DESC= Font files for RenderCV
+
+CLI_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}typer>=0:devel/py-typer@${PY_FLAVOR}
+MARKDOWN_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}markdown>=0:textproc/py-markdown@${PY_FLAVOR}
+WATCHDOG_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}watchdog>=0:devel/py-watchdog@${PY_FLAVOR}
+TYPST_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}typst>=0:textproc/py-typst@${PY_FLAVOR}
+FONT_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}rendercv-fonts>=0:x11-fonts/py-rendercv-fonts@${PY_FLAVOR}
+
+.include <bsd.port.mk>
diff --git a/sysutils/py-rendercv/distinfo b/sysutils/py-rendercv/distinfo
new file mode 100644
index 000000000000..c6f5b4128d33
--- /dev/null
+++ b/sysutils/py-rendercv/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1766178034
+SHA256 (rendercv-2.5.tar.gz) = 7e5b51c7ed4340fa2e78084a3d74aa4784aa3e42e53d585c3c8433082982434b
+SIZE (rendercv-2.5.tar.gz) = 77147
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_cli_error__handler.py b/sysutils/py-rendercv/files/patch-src_rendercv_cli_error__handler.py
new file mode 100644
index 000000000000..7c8350de5c53
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_cli_error__handler.py
@@ -0,0 +1,20 @@
+--- src/rendercv/cli/error_handler.py.orig 2025-12-20 00:46:25 UTC
++++ src/rendercv/cli/error_handler.py
+@@ -8,7 +8,7 @@ from rendercv.exception import RenderCVUserError
+ from rendercv.exception import RenderCVUserError
+
+
+-def handle_user_errors[T, **P](function: Callable[P, None]) -> Callable[P, None]:
++def handle_user_errors(function):
+ """Decorator that catches user errors and displays friendly messages without stack traces.
+
+ Why:
+@@ -33,7 +33,7 @@ def handle_user_errors[T, **P](function: Callable[P, N
+ """
+
+ @functools.wraps(function)
+- def wrapper(*args: P.args, **kwargs: P.kwargs) -> None:
++ def wrapper(*args, **kwargs) -> None:
+ try:
+ return function(*args, **kwargs)
+ except RenderCVUserError as e:
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_cli_render__command_run__rendercv.py b/sysutils/py-rendercv/files/patch-src_rendercv_cli_render__command_run__rendercv.py
new file mode 100644
index 000000000000..3ede1d8e2ce3
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_cli_render__command_run__rendercv.py
@@ -0,0 +1,21 @@
+--- src/rendercv/cli/render_command/run_rendercv.py.orig 2025-12-20 00:43:25 UTC
++++ src/rendercv/cli/render_command/run_rendercv.py
+@@ -19,13 +19,13 @@ from .progress_panel import ProgressPanel
+ from .progress_panel import ProgressPanel
+
+
+-def timed_step[T, **P](
++def timed_step(
+ message: str,
+ progress_panel: ProgressPanel,
+- func: Callable[P, T],
+- *args: P.args,
+- **kwargs: P.kwargs,
+-) -> T:
++ func,
++ *args,
++ **kwargs,
++):
+ """Execute function, measure timing, and update progress panel with result.
+
+ Why:
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_renderer_templater_entry__templates__from__input.py b/sysutils/py-rendercv/files/patch-src_rendercv_renderer_templater_entry__templates__from__input.py
new file mode 100644
index 000000000000..d3fbd6e1175e
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_renderer_templater_entry__templates__from__input.py
@@ -0,0 +1,20 @@
+--- src/rendercv/renderer/templater/entry_templates_from_input.py.orig 2025-12-20 00:49:48 UTC
++++ src/rendercv/renderer/templater/entry_templates_from_input.py
+@@ -14,14 +14,14 @@ uppercase_word_pattern = re.compile(r"\b[A-Z_]+\b")
+ uppercase_word_pattern = re.compile(r"\b[A-Z_]+\b")
+
+
+-def render_entry_templates[EntryType: Entry](
+- entry: EntryType,
++def render_entry_templates(
++ entry,
+ *,
+ templates: Templates,
+ locale: Locale,
+ show_time_span: bool,
+ current_date: Date,
+-) -> EntryType:
++):
+ """Expand entry templates by substituting field placeholders with processed values.
+
+ Why:
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_entries_bases_entry__with__complex__fields.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_entries_bases_entry__with__complex__fields.py
new file mode 100644
index 000000000000..c3e40f6ba6fd
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_entries_bases_entry__with__complex__fields.py
@@ -0,0 +1,11 @@
+--- src/rendercv/schema/models/cv/entries/bases/entry_with_complex_fields.py.orig 2025-12-19 21:42:57 UTC
++++ src/rendercv/schema/models/cv/entries/bases/entry_with_complex_fields.py
+@@ -37,7 +37,7 @@ def validate_exact_date(date: str | int) -> str | int:
+ return date
+
+
+-type ExactDate = Annotated[str | int, pydantic.AfterValidator(validate_exact_date)]
++ExactDate = Annotated[str | int, pydantic.AfterValidator(validate_exact_date)]
+
+
+ def get_date_object(date: str | int, current_date: Date | None = None) -> Date:
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_entries_bases_entry__with__date.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_entries_bases_entry__with__date.py
new file mode 100644
index 000000000000..8c792c689936
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_entries_bases_entry__with__date.py
@@ -0,0 +1,11 @@
+--- src/rendercv/schema/models/cv/entries/bases/entry_with_date.py.orig 2025-12-19 21:34:29 UTC
++++ src/rendercv/schema/models/cv/entries/bases/entry_with_date.py
+@@ -31,7 +31,7 @@ def validate_arbitrary_date(date: int | str) -> int |
+ return date
+
+
+-type ArbitraryDate = Annotated[
++ArbitraryDate = Annotated[
+ int | str, pydantic.AfterValidator(validate_arbitrary_date)
+ ]
+
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_section.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_section.py
new file mode 100644
index 000000000000..d2f7a9c12c81
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_section.py
@@ -0,0 +1,46 @@
+--- src/rendercv/schema/models/cv/section.py.orig 2025-12-19 21:43:39 UTC
++++ src/rendercv/schema/models/cv/section.py
+@@ -21,7 +21,7 @@ from .entries.reversed_numbered import ReversedNumbere
+ # Below needs to be updated when new entry types are added.
+
+ # str is an entry type (TextEntry) but not a model, so it's not included in EntryModel.
+-type EntryModel = (
++EntryModel = (
+ OneLineEntry
+ | NormalEntry
+ | ExperienceEntry
+@@ -31,13 +31,22 @@ type EntryModel = (
+ | NumberedEntry
+ | ReversedNumberedEntry
+ )
+-type Entry = EntryModel | str
++Entry = EntryModel | str
+ ########################################################################################
+-available_entry_models: tuple[type[EntryModel], ...] = get_args(EntryModel.__value__)
++available_entry_models: tuple[type[EntryModel], ...] = (
++ OneLineEntry,
++ NormalEntry,
++ ExperienceEntry,
++ EducationEntry,
++ PublicationEntry,
++ BulletEntry,
++ NumberedEntry,
++ ReversedNumberedEntry
++)
+ available_entry_type_names: tuple[str, ...] = tuple(
+ [entry_type.__name__ for entry_type in available_entry_models] + ["TextEntry"]
+ )
+-type ListOfEntries = list[str] | reduce( # pyright: ignore[reportInvalidTypeForm]
++ListOfEntries = list[str] | reduce( # pyright: ignore[reportInvalidTypeForm]
+ or_, [list[entry_type] for entry_type in available_entry_models]
+ )
+
+@@ -244,7 +253,7 @@ def validate_section(sections_input: Any) -> Any:
+ # Create a custom type named Section, which is a list of entries. The entries can be any
+ # of the available entry types. The section is validated with the `validate_section`
+ # function.
+-type Section = Annotated[
++Section = Annotated[
+ pydantic.json_schema.SkipJsonSchema[Any] | ListOfEntries,
+ pydantic.BeforeValidator(lambda entries: validate_section(entries)),
+ ]
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_social__network.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_social__network.py
new file mode 100644
index 000000000000..50d71355c92c
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_cv_social__network.py
@@ -0,0 +1,20 @@
+--- src/rendercv/schema/models/cv/social_network.py.orig 2025-12-19 21:44:26 UTC
++++ src/rendercv/schema/models/cv/social_network.py
+@@ -10,7 +10,7 @@ url_validator = pydantic.TypeAdapter(pydantic.HttpUrl)
+ from ..base import BaseModelWithoutExtraKeys
+
+ url_validator = pydantic.TypeAdapter(pydantic.HttpUrl)
+-type SocialNetworkName = Literal[
++SocialNetworkName = Literal[
+ "LinkedIn",
+ "GitHub",
+ "GitLab",
+@@ -27,7 +27,7 @@ type SocialNetworkName = Literal[
+ "Leetcode",
+ "X",
+ ]
+-available_social_networks = get_args(SocialNetworkName.__value__)
++#available_social_networks = get_args(SocialNetworkName.__value__)
+ url_dictionary: dict[SocialNetworkName, str] = {
+ "LinkedIn": "https://linkedin.com/in/",
+ "GitHub": "https://github.com/",
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_built__in__design.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_built__in__design.py
new file mode 100644
index 000000000000..2519ce6c6ec4
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_built__in__design.py
@@ -0,0 +1,22 @@
+--- src/rendercv/schema/models/design/built_in_design.py.orig 2025-12-19 21:32:57 UTC
++++ src/rendercv/schema/models/design/built_in_design.py
+@@ -37,14 +37,13 @@ def discover_other_themes() -> list[type[ClassicTheme]
+
+ return discovered
+
++discovered_other_themes = discover_other_themes()
+
+ # Build discriminated union dynamically
+-type BuiltInDesign = Annotated[
+- ClassicTheme | reduce(or_, discover_other_themes()), # pyright: ignore[reportInvalidTypeForm]
++BuiltInDesign = Annotated[
++ ClassicTheme | reduce(or_, discovered_other_themes), # pyright: ignore[reportInvalidTypeForm]
+ pydantic.Field(discriminator="theme"),
+ ]
+-available_themes: list[str] = [
+- ThemeClass.model_fields["theme"].default
+- for ThemeClass in get_args(get_args(BuiltInDesign.__value__)[0])
+-]
++discovered_other_themes.append(ClassicTheme)
++available_themes: list[str] = [ThemeClass.model_fields["theme"].default for ThemeClass in discovered_other_themes]
+ built_in_design_adapter = pydantic.TypeAdapter(BuiltInDesign)
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_classic__theme.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_classic__theme.py
new file mode 100644
index 000000000000..30f05b163fbc
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_classic__theme.py
@@ -0,0 +1,23 @@
+--- src/rendercv/schema/models/design/classic_theme.py.orig 2025-12-19 21:33:55 UTC
++++ src/rendercv/schema/models/design/classic_theme.py
+@@ -7,14 +7,14 @@ from rendercv.schema.models.design.typst_dimension imp
+ from rendercv.schema.models.design.font_family import FontFamily as FontFamilyType
+ from rendercv.schema.models.design.typst_dimension import TypstDimension
+
+-type Bullet = Literal["●", "•", "◦", "-", "◆", "★", "■", "—", "○"]
+-type BodyAlignment = Literal["left", "justified", "justified-with-no-hyphenation"]
+-type Alignment = Literal["left", "center", "right"]
+-type SectionTitleType = Literal[
++Bullet = Literal["●", "•", "◦", "-", "◆", "★", "■", "—", "○"]
++BodyAlignment = Literal["left", "justified", "justified-with-no-hyphenation"]
++Alignment = Literal["left", "center", "right"]
++SectionTitleType = Literal[
+ "with_partial_line", "with_full_line", "without_line", "moderncv"
+ ]
+-type PhoneNumberFormatType = Literal["national", "international", "E164"]
+-type PageSize = Literal["a4", "a5", "us-letter", "us-executive"]
++PhoneNumberFormatType = Literal["national", "international", "E164"]
++PageSize = Literal["a4", "a5", "us-letter", "us-executive"]
+
+ length_common_description = (
+ "It can be specified with units (cm, in, pt, mm, ex, em). For example, `0.1cm`."
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_font__family.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_font__family.py
new file mode 100644
index 000000000000..0563084ad505
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_font__family.py
@@ -0,0 +1,8 @@
+--- src/rendercv/schema/models/design/font_family.py.orig 2025-12-19 21:33:15 UTC
++++ src/rendercv/schema/models/design/font_family.py
+@@ -50,4 +50,4 @@ available_font_families = sorted(
+ )
+
+
+-type FontFamily = SkipJsonSchema[str] | Literal[*tuple(available_font_families)] # pyright: ignore[reportInvalidTypeForm]
++FontFamily = SkipJsonSchema[str] | Literal[*tuple(available_font_families)] # pyright: ignore[reportInvalidTypeForm]
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_typst__dimension.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_typst__dimension.py
new file mode 100644
index 000000000000..f9c2dfb78d2c
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_design_typst__dimension.py
@@ -0,0 +1,8 @@
+--- src/rendercv/schema/models/design/typst_dimension.py.orig 2025-12-19 21:33:37 UTC
++++ src/rendercv/schema/models/design/typst_dimension.py
+@@ -29,4 +29,4 @@ def validate_typst_dimension(dimension: str) -> str:
+ return dimension
+
+
+-type TypstDimension = Annotated[str, pydantic.AfterValidator(validate_typst_dimension)]
++TypstDimension = Annotated[str, pydantic.AfterValidator(validate_typst_dimension)]
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_locale_locale.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_locale_locale.py
new file mode 100644
index 000000000000..78889b6444b0
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_locale_locale.py
@@ -0,0 +1,22 @@
+--- src/rendercv/schema/models/locale/locale.py.orig 2025-12-19 21:44:44 UTC
++++ src/rendercv/schema/models/locale/locale.py
+@@ -37,14 +37,13 @@ def discover_other_locales() -> list[type[EnglishLocal
+
+ return discovered
+
++discovered_other_locales = discover_other_locales()
+
+ # Build discriminated union dynamically
+-type Locale = Annotated[
+- EnglishLocale | reduce(or_, discover_other_locales()), # pyright: ignore[reportInvalidTypeForm]
++Locale = Annotated[
++ EnglishLocale | reduce(or_, discovered_other_locales), # pyright: ignore[reportInvalidTypeForm]
+ pydantic.Field(discriminator="language"),
+ ]
+-available_locales = [
+- LocaleModel.model_fields["language"].default
+- for LocaleModel in get_args(get_args(Locale.__value__)[0])
+-]
++discovered_other_locales.append(EnglishLocale)
++available_locales = [LocaleModel.model_fields["language"].default for LocaleModel in discovered_other_locales]
+ locale_adapter = pydantic.TypeAdapter(Locale)
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_path.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_path.py
new file mode 100644
index 000000000000..74b7cab315b6
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_models_path.py
@@ -0,0 +1,19 @@
+--- src/rendercv/schema/models/path.py.orig 2025-12-19 21:40:25 UTC
++++ src/rendercv/schema/models/path.py
+@@ -60,14 +60,14 @@ def serialize_path(path: pathlib.Path) -> str:
+ return str(path.relative_to(pathlib.Path.cwd()))
+
+
+-type ExistingPathRelativeToInput = Annotated[
++ExistingPathRelativeToInput = Annotated[
+ pathlib.Path,
+ pydantic.AfterValidator(
+ lambda path, info: resolve_relative_path(path, info, must_exist=True)
+ ),
+ ]
+
+-type PlannedPathRelativeToInput = Annotated[
++PlannedPathRelativeToInput = Annotated[
+ pathlib.Path,
+ pydantic.AfterValidator(
+ lambda path, info: resolve_relative_path(path, info, must_exist=False)
diff --git a/sysutils/py-rendercv/files/patch-src_rendercv_schema_variant__pydantic__model__generator.py b/sysutils/py-rendercv/files/patch-src_rendercv_schema_variant__pydantic__model__generator.py
new file mode 100644
index 000000000000..8760ecb47deb
--- /dev/null
+++ b/sysutils/py-rendercv/files/patch-src_rendercv_schema_variant__pydantic__model__generator.py
@@ -0,0 +1,38 @@
+--- src/rendercv/schema/variant_pydantic_model_generator.py.orig 2025-12-19 21:48:58 UTC
++++ src/rendercv/schema/variant_pydantic_model_generator.py
+@@ -6,17 +6,17 @@ from rendercv.exception import RenderCVInternalError
+
+ from rendercv.exception import RenderCVInternalError
+
+-type FieldSpec = tuple[type[Any], FieldInfo]
++FieldSpec = tuple[type[Any], FieldInfo]
+
+
+-def create_variant_pydantic_model[T: pydantic.BaseModel](
++def create_variant_pydantic_model(
+ variant_name: str,
+ defaults: dict[str, Any],
+- base_class: type[T],
++ base_class,
+ discriminator_field: str,
+ class_name_suffix: str,
+ module_name: str,
+-) -> type[T]:
++):
+ """Create Pydantic model variant with customized defaults.
+
+ Why:
+@@ -190,10 +190,10 @@ def create_discriminator_field_spec(
+ return (cast(type[Any], field_annotation), new_field)
+
+
+-def deep_merge_nested_object[T: pydantic.BaseModel](
+- base_nested_obj: T,
++def deep_merge_nested_object(
++ base_nested_obj,
+ updates: dict[str, Any],
+-) -> T:
++):
+ """Recursively merge nested dictionary updates into Pydantic model instance.
+
+ Why:
diff --git a/sysutils/py-rendercv/pkg-descr b/sysutils/py-rendercv/pkg-descr
new file mode 100644
index 000000000000..58a97762cbe9
--- /dev/null
+++ b/sysutils/py-rendercv/pkg-descr
@@ -0,0 +1,5 @@
+RenderCV is a python tool for creating a CV from YAML.
+
+Write your CV or resume as YAML, then run RenderCV, and get a PDF
+with perfect typography. No template wrestling. No broken layouts.
+Consistent spacing, every time.