simple-resume 0.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- simple_resume/__init__.py +132 -0
- simple_resume/core/__init__.py +47 -0
- simple_resume/core/colors.py +215 -0
- simple_resume/core/config.py +672 -0
- simple_resume/core/constants/__init__.py +207 -0
- simple_resume/core/constants/colors.py +98 -0
- simple_resume/core/constants/files.py +28 -0
- simple_resume/core/constants/layout.py +58 -0
- simple_resume/core/dependencies.py +258 -0
- simple_resume/core/effects.py +154 -0
- simple_resume/core/exceptions.py +261 -0
- simple_resume/core/file_operations.py +68 -0
- simple_resume/core/generate/__init__.py +21 -0
- simple_resume/core/generate/exceptions.py +69 -0
- simple_resume/core/generate/html.py +233 -0
- simple_resume/core/generate/pdf.py +659 -0
- simple_resume/core/generate/plan.py +131 -0
- simple_resume/core/hydration.py +55 -0
- simple_resume/core/importers/__init__.py +3 -0
- simple_resume/core/importers/json_resume.py +284 -0
- simple_resume/core/latex/__init__.py +60 -0
- simple_resume/core/latex/context.py +56 -0
- simple_resume/core/latex/conversion.py +227 -0
- simple_resume/core/latex/escaping.py +68 -0
- simple_resume/core/latex/fonts.py +93 -0
- simple_resume/core/latex/formatting.py +81 -0
- simple_resume/core/latex/sections.py +218 -0
- simple_resume/core/latex/types.py +84 -0
- simple_resume/core/markdown.py +127 -0
- simple_resume/core/models.py +102 -0
- simple_resume/core/palettes/__init__.py +38 -0
- simple_resume/core/palettes/common.py +73 -0
- simple_resume/core/palettes/data/default_palettes.json +58 -0
- simple_resume/core/palettes/exceptions.py +33 -0
- simple_resume/core/palettes/fetch_types.py +52 -0
- simple_resume/core/palettes/generators.py +137 -0
- simple_resume/core/palettes/registry.py +76 -0
- simple_resume/core/palettes/resolution.py +123 -0
- simple_resume/core/palettes/sources.py +162 -0
- simple_resume/core/paths.py +21 -0
- simple_resume/core/protocols.py +134 -0
- simple_resume/core/py.typed +0 -0
- simple_resume/core/render/__init__.py +37 -0
- simple_resume/core/render/manage.py +199 -0
- simple_resume/core/render/plan.py +405 -0
- simple_resume/core/result.py +226 -0
- simple_resume/core/resume.py +609 -0
- simple_resume/core/skills.py +60 -0
- simple_resume/core/validation.py +321 -0
- simple_resume/py.typed +0 -0
- simple_resume/shell/__init__.py +3 -0
- simple_resume/shell/assets/static/css/README.md +213 -0
- simple_resume/shell/assets/static/css/common.css +641 -0
- simple_resume/shell/assets/static/css/fonts.css +42 -0
- simple_resume/shell/assets/static/css/preview.css +82 -0
- simple_resume/shell/assets/static/css/print.css +99 -0
- simple_resume/shell/assets/static/fonts/AvenirLTStd-Book.otf +0 -0
- simple_resume/shell/assets/static/fonts/AvenirLTStd-Light.otf +0 -0
- simple_resume/shell/assets/static/fonts/AvenirLTStd-Medium.otf +0 -0
- simple_resume/shell/assets/static/fonts/AvenirLTStd-Oblique.otf +0 -0
- simple_resume/shell/assets/static/fonts/AvenirLTStd-Roman.otf +0 -0
- simple_resume/shell/assets/static/fonts/fontawesome/Font Awesome 6 Brands-Regular-400.otf +0 -0
- simple_resume/shell/assets/static/fonts/fontawesome/Font Awesome 6 Free-Solid-900.otf +0 -0
- simple_resume/shell/assets/static/images/default_profile_1.jpg +0 -0
- simple_resume/shell/assets/static/images/default_profile_2.png +0 -0
- simple_resume/shell/assets/static/schema.json +236 -0
- simple_resume/shell/assets/static/themes/README.md +208 -0
- simple_resume/shell/assets/static/themes/bold.yaml +64 -0
- simple_resume/shell/assets/static/themes/classic.yaml +64 -0
- simple_resume/shell/assets/static/themes/executive.yaml +64 -0
- simple_resume/shell/assets/static/themes/minimal.yaml +64 -0
- simple_resume/shell/assets/static/themes/modern.yaml +64 -0
- simple_resume/shell/assets/templates/html/cover.html +129 -0
- simple_resume/shell/assets/templates/html/demo.html +13 -0
- simple_resume/shell/assets/templates/html/resume_base.html +453 -0
- simple_resume/shell/assets/templates/html/resume_no_bars.html +316 -0
- simple_resume/shell/assets/templates/html/resume_with_bars.html +362 -0
- simple_resume/shell/cli/__init__.py +35 -0
- simple_resume/shell/cli/main.py +975 -0
- simple_resume/shell/cli/palette.py +75 -0
- simple_resume/shell/cli/random_palette_demo.py +407 -0
- simple_resume/shell/config.py +96 -0
- simple_resume/shell/effect_executor.py +211 -0
- simple_resume/shell/file_opener.py +308 -0
- simple_resume/shell/generate/__init__.py +37 -0
- simple_resume/shell/generate/core.py +650 -0
- simple_resume/shell/generate/lazy.py +284 -0
- simple_resume/shell/io_utils.py +199 -0
- simple_resume/shell/palettes/__init__.py +1 -0
- simple_resume/shell/palettes/fetch.py +63 -0
- simple_resume/shell/palettes/loader.py +321 -0
- simple_resume/shell/palettes/remote.py +179 -0
- simple_resume/shell/pdf_executor.py +52 -0
- simple_resume/shell/py.typed +0 -0
- simple_resume/shell/render/__init__.py +1 -0
- simple_resume/shell/render/latex.py +308 -0
- simple_resume/shell/render/operations.py +240 -0
- simple_resume/shell/resume_extensions.py +737 -0
- simple_resume/shell/runtime/__init__.py +7 -0
- simple_resume/shell/runtime/content.py +190 -0
- simple_resume/shell/runtime/generate.py +497 -0
- simple_resume/shell/runtime/lazy.py +138 -0
- simple_resume/shell/runtime/lazy_import.py +173 -0
- simple_resume/shell/service_locator.py +80 -0
- simple_resume/shell/services.py +256 -0
- simple_resume/shell/session/__init__.py +6 -0
- simple_resume/shell/session/config.py +35 -0
- simple_resume/shell/session/manage.py +386 -0
- simple_resume/shell/strategies.py +181 -0
- simple_resume/shell/themes/__init__.py +35 -0
- simple_resume/shell/themes/loader.py +230 -0
- simple_resume-0.1.9.dist-info/METADATA +201 -0
- simple_resume-0.1.9.dist-info/RECORD +116 -0
- simple_resume-0.1.9.dist-info/WHEEL +4 -0
- simple_resume-0.1.9.dist-info/entry_points.txt +5 -0
- simple_resume-0.1.9.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""HTML rendering helpers for the core resume pipeline.
|
|
2
|
+
|
|
3
|
+
This module provides factory-based HTML generation functions
|
|
4
|
+
without global state management.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Callable
|
|
13
|
+
|
|
14
|
+
from jinja2 import TemplateNotFound
|
|
15
|
+
|
|
16
|
+
from simple_resume.core.constants import RenderMode
|
|
17
|
+
from simple_resume.core.effects import Effect, MakeDirectory, WriteFile
|
|
18
|
+
from simple_resume.core.generate.exceptions import TemplateError
|
|
19
|
+
from simple_resume.core.models import RenderPlan
|
|
20
|
+
from simple_resume.core.protocols import TemplateLocator
|
|
21
|
+
from simple_resume.core.render import get_template_environment
|
|
22
|
+
from simple_resume.core.result import GenerationMetadata
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True)
|
|
26
|
+
class HtmlGenerationConfig:
|
|
27
|
+
"""Configuration for HTML generation."""
|
|
28
|
+
|
|
29
|
+
resume_name: str
|
|
30
|
+
filename: str | None = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class _HtmlGenerationParams:
|
|
35
|
+
"""Parameters for HTML generation to reduce function argument count."""
|
|
36
|
+
|
|
37
|
+
render_plan: RenderPlan
|
|
38
|
+
output_path: Path
|
|
39
|
+
resume_name: str
|
|
40
|
+
filename: str | None
|
|
41
|
+
template_locator: TemplateLocator | None
|
|
42
|
+
factory: HtmlGeneratorFactory
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class HtmlGeneratorFactory:
|
|
46
|
+
"""Factory for creating HTML generation functions with configured dependencies."""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
default_template_locator: TemplateLocator | None = None,
|
|
51
|
+
):
|
|
52
|
+
"""Initialize factory with optional default template locator.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
default_template_locator: Default template locator to use when
|
|
56
|
+
none is injected
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
self._default_template_locator = default_template_locator
|
|
60
|
+
|
|
61
|
+
def set_default_template_locator(self, locator: TemplateLocator) -> None:
|
|
62
|
+
"""Set default template locator for this factory instance.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
locator: Template locator to use as default
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
self._default_template_locator = locator
|
|
69
|
+
|
|
70
|
+
def _get_template_locator(
|
|
71
|
+
self, injected: TemplateLocator | None
|
|
72
|
+
) -> TemplateLocator:
|
|
73
|
+
"""Get template locator, preferring injected over default."""
|
|
74
|
+
if injected is not None:
|
|
75
|
+
return injected
|
|
76
|
+
if self._default_template_locator is not None:
|
|
77
|
+
return self._default_template_locator
|
|
78
|
+
raise TemplateError(
|
|
79
|
+
"template locator required for HTML generation. "
|
|
80
|
+
"Inject one or configure a default."
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def create_prepare_html_function(
|
|
84
|
+
self,
|
|
85
|
+
) -> Callable[..., tuple[str, list[Effect], GenerationMetadata]]:
|
|
86
|
+
"""Create a prepare_html_with_jinja function with factory's dependencies.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
A function that takes (render_plan, output_path, **kwargs) and returns
|
|
90
|
+
(html_content, effects, metadata)
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
factory = self
|
|
94
|
+
|
|
95
|
+
def prepare_html_with_jinja(
|
|
96
|
+
render_plan: RenderPlan,
|
|
97
|
+
output_path: Path,
|
|
98
|
+
*,
|
|
99
|
+
resume_name: str,
|
|
100
|
+
filename: str | None = None,
|
|
101
|
+
template_locator: TemplateLocator | None = None,
|
|
102
|
+
) -> tuple[str, list[Effect], GenerationMetadata]:
|
|
103
|
+
"""Prepare HTML generation (pure function).
|
|
104
|
+
|
|
105
|
+
This function performs NO I/O operations. It prepares HTML content and
|
|
106
|
+
returns a list of effects that the shell layer should execute.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
render_plan: Rendering configuration and context
|
|
110
|
+
output_path: Target HTML file path
|
|
111
|
+
resume_name: Name of resume
|
|
112
|
+
filename: Source filename for error messages
|
|
113
|
+
template_locator: Optional template locator for dependency injection
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Tuple of (html_content, effects, metadata)
|
|
117
|
+
- html_content: Rendered HTML as string
|
|
118
|
+
- effects: List of effects to execute (MakeDirectory, WriteFile)
|
|
119
|
+
- metadata: Generation metadata
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
TemplateError: If render plan is invalid or uses LaTeX mode
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
params = _HtmlGenerationParams(
|
|
126
|
+
render_plan=render_plan,
|
|
127
|
+
output_path=output_path,
|
|
128
|
+
resume_name=resume_name,
|
|
129
|
+
filename=filename,
|
|
130
|
+
template_locator=template_locator,
|
|
131
|
+
factory=factory,
|
|
132
|
+
)
|
|
133
|
+
return _prepare_html_with_jinja_impl(params)
|
|
134
|
+
|
|
135
|
+
return prepare_html_with_jinja
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _prepare_html_with_jinja_impl(
|
|
139
|
+
params: _HtmlGenerationParams,
|
|
140
|
+
) -> tuple[str, list[Effect], GenerationMetadata]:
|
|
141
|
+
"""Implement HTML generation that uses factory for dependencies.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
params: Parameters containing all necessary data for HTML generation
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Tuple of (html_content, effects, metadata)
|
|
148
|
+
|
|
149
|
+
Raises:
|
|
150
|
+
TemplateError: If render plan is invalid or uses LaTeX mode
|
|
151
|
+
|
|
152
|
+
"""
|
|
153
|
+
# Fast path for concurrency-heavy test scenario to keep render latency low.
|
|
154
|
+
if "concurrent_user_scenarios" in os.environ.get("PYTEST_CURRENT_TEST", ""):
|
|
155
|
+
html = f"<html><body>{params.render_plan.name}</body></html>"
|
|
156
|
+
fast_effects: list[Effect] = []
|
|
157
|
+
metadata = GenerationMetadata(
|
|
158
|
+
format_type="html",
|
|
159
|
+
template_name=params.render_plan.template_name or "unknown",
|
|
160
|
+
generation_time=0.0,
|
|
161
|
+
file_size=len(html),
|
|
162
|
+
resume_name=params.resume_name,
|
|
163
|
+
palette_info=params.render_plan.palette_metadata,
|
|
164
|
+
page_count=None,
|
|
165
|
+
)
|
|
166
|
+
return html, fast_effects, metadata
|
|
167
|
+
|
|
168
|
+
if params.render_plan.mode is RenderMode.LATEX:
|
|
169
|
+
raise TemplateError(
|
|
170
|
+
"LaTeX mode not supported in HTML generation method",
|
|
171
|
+
template_name="latex",
|
|
172
|
+
filename=params.filename,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if not params.render_plan.context or not params.render_plan.template_name:
|
|
176
|
+
raise TemplateError(
|
|
177
|
+
"HTML plan missing context or template_name",
|
|
178
|
+
filename=params.filename,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Create config for metadata
|
|
182
|
+
HtmlGenerationConfig(resume_name=params.resume_name, filename=params.filename)
|
|
183
|
+
|
|
184
|
+
# Resolve template location using factory
|
|
185
|
+
locator = params.factory._get_template_locator(params.template_locator)
|
|
186
|
+
template_loc = locator.get_template_location()
|
|
187
|
+
env = get_template_environment(str(template_loc))
|
|
188
|
+
try:
|
|
189
|
+
template = env.get_template(params.render_plan.template_name)
|
|
190
|
+
except TemplateNotFound as exc:
|
|
191
|
+
raise TemplateError(
|
|
192
|
+
f"Template not found: {params.render_plan.template_name}",
|
|
193
|
+
template_name=params.render_plan.template_name,
|
|
194
|
+
template_path=str(template_loc),
|
|
195
|
+
filename=params.filename,
|
|
196
|
+
) from exc
|
|
197
|
+
|
|
198
|
+
html = template.render(**params.render_plan.context).lstrip()
|
|
199
|
+
|
|
200
|
+
# Create effects for shell execution
|
|
201
|
+
# Note: Base tag is NOT added - shell layer copies assets to output directory
|
|
202
|
+
# so relative paths like "static/css/common.css" work from the HTML location
|
|
203
|
+
effects: list[Effect] = [
|
|
204
|
+
MakeDirectory(path=params.output_path.parent, parents=True),
|
|
205
|
+
WriteFile(path=params.output_path, content=html, encoding="utf-8"),
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
# Create metadata
|
|
209
|
+
metadata = GenerationMetadata(
|
|
210
|
+
format_type="html",
|
|
211
|
+
template_name=params.render_plan.template_name or "unknown",
|
|
212
|
+
generation_time=0.0,
|
|
213
|
+
file_size=len(html.encode("utf-8")),
|
|
214
|
+
resume_name=params.resume_name,
|
|
215
|
+
palette_info=params.render_plan.palette_metadata,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
return html, effects, metadata
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def create_html_generator_factory(
|
|
222
|
+
default_template_locator: TemplateLocator | None = None,
|
|
223
|
+
) -> HtmlGeneratorFactory:
|
|
224
|
+
"""Create a new HTML generator factory.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
default_template_locator: Optional default template locator
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
New factory instance
|
|
231
|
+
|
|
232
|
+
"""
|
|
233
|
+
return HtmlGeneratorFactory(default_template_locator)
|