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.
Files changed (116) hide show
  1. simple_resume/__init__.py +132 -0
  2. simple_resume/core/__init__.py +47 -0
  3. simple_resume/core/colors.py +215 -0
  4. simple_resume/core/config.py +672 -0
  5. simple_resume/core/constants/__init__.py +207 -0
  6. simple_resume/core/constants/colors.py +98 -0
  7. simple_resume/core/constants/files.py +28 -0
  8. simple_resume/core/constants/layout.py +58 -0
  9. simple_resume/core/dependencies.py +258 -0
  10. simple_resume/core/effects.py +154 -0
  11. simple_resume/core/exceptions.py +261 -0
  12. simple_resume/core/file_operations.py +68 -0
  13. simple_resume/core/generate/__init__.py +21 -0
  14. simple_resume/core/generate/exceptions.py +69 -0
  15. simple_resume/core/generate/html.py +233 -0
  16. simple_resume/core/generate/pdf.py +659 -0
  17. simple_resume/core/generate/plan.py +131 -0
  18. simple_resume/core/hydration.py +55 -0
  19. simple_resume/core/importers/__init__.py +3 -0
  20. simple_resume/core/importers/json_resume.py +284 -0
  21. simple_resume/core/latex/__init__.py +60 -0
  22. simple_resume/core/latex/context.py +56 -0
  23. simple_resume/core/latex/conversion.py +227 -0
  24. simple_resume/core/latex/escaping.py +68 -0
  25. simple_resume/core/latex/fonts.py +93 -0
  26. simple_resume/core/latex/formatting.py +81 -0
  27. simple_resume/core/latex/sections.py +218 -0
  28. simple_resume/core/latex/types.py +84 -0
  29. simple_resume/core/markdown.py +127 -0
  30. simple_resume/core/models.py +102 -0
  31. simple_resume/core/palettes/__init__.py +38 -0
  32. simple_resume/core/palettes/common.py +73 -0
  33. simple_resume/core/palettes/data/default_palettes.json +58 -0
  34. simple_resume/core/palettes/exceptions.py +33 -0
  35. simple_resume/core/palettes/fetch_types.py +52 -0
  36. simple_resume/core/palettes/generators.py +137 -0
  37. simple_resume/core/palettes/registry.py +76 -0
  38. simple_resume/core/palettes/resolution.py +123 -0
  39. simple_resume/core/palettes/sources.py +162 -0
  40. simple_resume/core/paths.py +21 -0
  41. simple_resume/core/protocols.py +134 -0
  42. simple_resume/core/py.typed +0 -0
  43. simple_resume/core/render/__init__.py +37 -0
  44. simple_resume/core/render/manage.py +199 -0
  45. simple_resume/core/render/plan.py +405 -0
  46. simple_resume/core/result.py +226 -0
  47. simple_resume/core/resume.py +609 -0
  48. simple_resume/core/skills.py +60 -0
  49. simple_resume/core/validation.py +321 -0
  50. simple_resume/py.typed +0 -0
  51. simple_resume/shell/__init__.py +3 -0
  52. simple_resume/shell/assets/static/css/README.md +213 -0
  53. simple_resume/shell/assets/static/css/common.css +641 -0
  54. simple_resume/shell/assets/static/css/fonts.css +42 -0
  55. simple_resume/shell/assets/static/css/preview.css +82 -0
  56. simple_resume/shell/assets/static/css/print.css +99 -0
  57. simple_resume/shell/assets/static/fonts/AvenirLTStd-Book.otf +0 -0
  58. simple_resume/shell/assets/static/fonts/AvenirLTStd-Light.otf +0 -0
  59. simple_resume/shell/assets/static/fonts/AvenirLTStd-Medium.otf +0 -0
  60. simple_resume/shell/assets/static/fonts/AvenirLTStd-Oblique.otf +0 -0
  61. simple_resume/shell/assets/static/fonts/AvenirLTStd-Roman.otf +0 -0
  62. simple_resume/shell/assets/static/fonts/fontawesome/Font Awesome 6 Brands-Regular-400.otf +0 -0
  63. simple_resume/shell/assets/static/fonts/fontawesome/Font Awesome 6 Free-Solid-900.otf +0 -0
  64. simple_resume/shell/assets/static/images/default_profile_1.jpg +0 -0
  65. simple_resume/shell/assets/static/images/default_profile_2.png +0 -0
  66. simple_resume/shell/assets/static/schema.json +236 -0
  67. simple_resume/shell/assets/static/themes/README.md +208 -0
  68. simple_resume/shell/assets/static/themes/bold.yaml +64 -0
  69. simple_resume/shell/assets/static/themes/classic.yaml +64 -0
  70. simple_resume/shell/assets/static/themes/executive.yaml +64 -0
  71. simple_resume/shell/assets/static/themes/minimal.yaml +64 -0
  72. simple_resume/shell/assets/static/themes/modern.yaml +64 -0
  73. simple_resume/shell/assets/templates/html/cover.html +129 -0
  74. simple_resume/shell/assets/templates/html/demo.html +13 -0
  75. simple_resume/shell/assets/templates/html/resume_base.html +453 -0
  76. simple_resume/shell/assets/templates/html/resume_no_bars.html +316 -0
  77. simple_resume/shell/assets/templates/html/resume_with_bars.html +362 -0
  78. simple_resume/shell/cli/__init__.py +35 -0
  79. simple_resume/shell/cli/main.py +975 -0
  80. simple_resume/shell/cli/palette.py +75 -0
  81. simple_resume/shell/cli/random_palette_demo.py +407 -0
  82. simple_resume/shell/config.py +96 -0
  83. simple_resume/shell/effect_executor.py +211 -0
  84. simple_resume/shell/file_opener.py +308 -0
  85. simple_resume/shell/generate/__init__.py +37 -0
  86. simple_resume/shell/generate/core.py +650 -0
  87. simple_resume/shell/generate/lazy.py +284 -0
  88. simple_resume/shell/io_utils.py +199 -0
  89. simple_resume/shell/palettes/__init__.py +1 -0
  90. simple_resume/shell/palettes/fetch.py +63 -0
  91. simple_resume/shell/palettes/loader.py +321 -0
  92. simple_resume/shell/palettes/remote.py +179 -0
  93. simple_resume/shell/pdf_executor.py +52 -0
  94. simple_resume/shell/py.typed +0 -0
  95. simple_resume/shell/render/__init__.py +1 -0
  96. simple_resume/shell/render/latex.py +308 -0
  97. simple_resume/shell/render/operations.py +240 -0
  98. simple_resume/shell/resume_extensions.py +737 -0
  99. simple_resume/shell/runtime/__init__.py +7 -0
  100. simple_resume/shell/runtime/content.py +190 -0
  101. simple_resume/shell/runtime/generate.py +497 -0
  102. simple_resume/shell/runtime/lazy.py +138 -0
  103. simple_resume/shell/runtime/lazy_import.py +173 -0
  104. simple_resume/shell/service_locator.py +80 -0
  105. simple_resume/shell/services.py +256 -0
  106. simple_resume/shell/session/__init__.py +6 -0
  107. simple_resume/shell/session/config.py +35 -0
  108. simple_resume/shell/session/manage.py +386 -0
  109. simple_resume/shell/strategies.py +181 -0
  110. simple_resume/shell/themes/__init__.py +35 -0
  111. simple_resume/shell/themes/loader.py +230 -0
  112. simple_resume-0.1.9.dist-info/METADATA +201 -0
  113. simple_resume-0.1.9.dist-info/RECORD +116 -0
  114. simple_resume-0.1.9.dist-info/WHEEL +4 -0
  115. simple_resume-0.1.9.dist-info/entry_points.txt +5 -0
  116. 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)