tesorotools-python 0.0.55__tar.gz → 0.1.0__tar.gz

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 (134) hide show
  1. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/PKG-INFO +4 -1
  2. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/pyproject.toml +7 -0
  3. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/line_plot.py +8 -0
  4. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/plotly_backend.py +11 -4
  5. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/template.docx +0 -0
  6. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/database/shared.py +6 -6
  7. tesorotools_python-0.1.0/src/tesorotools/latex/__init__.py +13 -0
  8. tesorotools_python-0.1.0/src/tesorotools/latex/cli.py +119 -0
  9. tesorotools_python-0.1.0/src/tesorotools/latex/scaffold.py +185 -0
  10. tesorotools_python-0.1.0/src/tesorotools/latex/templates/article/main.tex.tmpl +33 -0
  11. tesorotools_python-0.1.0/src/tesorotools/latex/templates/article/sections/01-introduccion.tex +18 -0
  12. tesorotools_python-0.1.0/src/tesorotools/latex/templates/article/sections/02-analisis.tex +51 -0
  13. tesorotools_python-0.1.0/src/tesorotools/latex/templates/article/sections/03-conclusiones.tex +10 -0
  14. tesorotools_python-0.1.0/src/tesorotools/latex/templates/beamer/main.tex.tmpl +47 -0
  15. tesorotools_python-0.1.0/src/tesorotools/latex/templates/beamer/slides/01-contexto.tex +28 -0
  16. tesorotools_python-0.1.0/src/tesorotools/latex/templates/beamer/slides/02-analisis.tex +39 -0
  17. tesorotools_python-0.1.0/src/tesorotools/latex/templates/beamer/slides/03-conclusiones.tex +13 -0
  18. tesorotools_python-0.1.0/src/tesorotools/latex/templates/beamer/style/beamerthemeTesoro.sty +123 -0
  19. tesorotools_python-0.1.0/src/tesorotools/latex/templates/book/appendices/a-fuentes.tex +10 -0
  20. tesorotools_python-0.1.0/src/tesorotools/latex/templates/book/chapters/01-introduccion.tex +25 -0
  21. tesorotools_python-0.1.0/src/tesorotools/latex/templates/book/chapters/02-analisis.tex +49 -0
  22. tesorotools_python-0.1.0/src/tesorotools/latex/templates/book/frontmatter/resumen.tex +10 -0
  23. tesorotools_python-0.1.0/src/tesorotools/latex/templates/book/main.tex.tmpl +41 -0
  24. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/README.md.tmpl +50 -0
  25. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/dot-gitignore +21 -0
  26. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/dot-vscode/settings.json +20 -0
  27. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/fonts/README.md +15 -0
  28. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/latexmkrc +9 -0
  29. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/refs.bib +17 -0
  30. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/style/tesoro.sty +207 -0
  31. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/style/tesorobrand.sty.tmpl +10 -0
  32. tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/style/tesorolocal.sty.tmpl +10 -0
  33. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/manifest.py +7 -7
  34. tesorotools_python-0.1.0/src/tesorotools/palette.py +59 -0
  35. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/providers/fred.py +3 -4
  36. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/providers/imf_irfcl.py +2 -1
  37. tesorotools_python-0.1.0/src/tesorotools/render/content/__init__.py +0 -0
  38. tesorotools_python-0.1.0/src/tesorotools/scaffold.py +127 -0
  39. tesorotools_python-0.1.0/src/tesorotools/web/__init__.py +112 -0
  40. tesorotools_python-0.1.0/src/tesorotools/web/app.py +221 -0
  41. tesorotools_python-0.1.0/src/tesorotools/web/brand.py +355 -0
  42. tesorotools_python-0.1.0/src/tesorotools/web/cli.py +92 -0
  43. tesorotools_python-0.1.0/src/tesorotools/web/components.py +210 -0
  44. tesorotools_python-0.1.0/src/tesorotools/web/formatting.py +45 -0
  45. tesorotools_python-0.1.0/src/tesorotools/web/launcher.py +42 -0
  46. tesorotools_python-0.1.0/src/tesorotools/web/palette.py +16 -0
  47. tesorotools_python-0.1.0/src/tesorotools/web/plotting.py +117 -0
  48. tesorotools_python-0.1.0/src/tesorotools/web/scaffold.py +95 -0
  49. tesorotools_python-0.1.0/src/tesorotools/web/templates/Dockerfile.tmpl +34 -0
  50. tesorotools_python-0.1.0/src/tesorotools/web/templates/README.md.tmpl +43 -0
  51. tesorotools_python-0.1.0/src/tesorotools/web/templates/dot-dockerignore.tmpl +6 -0
  52. tesorotools_python-0.1.0/src/tesorotools/web/templates/dot-gitignore.tmpl +6 -0
  53. tesorotools_python-0.1.0/src/tesorotools/web/templates/dot-streamlit/config.toml.tmpl +14 -0
  54. tesorotools_python-0.1.0/src/tesorotools/web/templates/pyproject.toml.tmpl +35 -0
  55. tesorotools_python-0.1.0/src/tesorotools/web/templates/src/$package/__init__.py.tmpl +1 -0
  56. tesorotools_python-0.1.0/src/tesorotools/web/templates/src/$package/cli.py.tmpl +11 -0
  57. tesorotools_python-0.1.0/src/tesorotools/web/templates/src/$package/main.py.tmpl +30 -0
  58. tesorotools_python-0.1.0/src/tesorotools/web/templates/src/$package/sections.py.tmpl +82 -0
  59. tesorotools_python-0.1.0/src/tesorotools/web/templates/tests/__init__.py.tmpl +0 -0
  60. tesorotools_python-0.1.0/src/tesorotools/web/templates/tests/test_app.py.tmpl +22 -0
  61. tesorotools_python-0.1.0/src/tesorotools/web/theme.py +295 -0
  62. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/.gitignore +0 -0
  63. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/__init__.py +0 -0
  64. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/_build_context.py +0 -0
  65. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/_registry.py +0 -0
  66. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/__init__.py +0 -0
  67. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/_common.py +0 -0
  68. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/bar_line.py +0 -0
  69. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/barh_plot.py +0 -0
  70. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/box_plot.py +0 -0
  71. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/compact.py +0 -0
  72. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/intraday_plot.py +0 -0
  73. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/matrix.py +0 -0
  74. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/shock_plot.py +0 -0
  75. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/stacked.py +0 -0
  76. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/type_curve.py +0 -0
  77. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/vector_plot.py +0 -0
  78. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/artists/waterfall.py +0 -0
  79. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/README.md +0 -0
  80. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/CabinetGrotesk-Black.otf +0 -0
  81. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/CabinetGrotesk-Bold.otf +0 -0
  82. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/CabinetGrotesk-Extrabold.otf +0 -0
  83. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/CabinetGrotesk-Extralight.otf +0 -0
  84. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/CabinetGrotesk-Light.otf +0 -0
  85. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/CabinetGrotesk-Medium.otf +0 -0
  86. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/CabinetGrotesk-Regular.otf +0 -0
  87. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/CabinetGrotesk-Thin.otf +0 -0
  88. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/fonts/README.md +0 -0
  89. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/plots.yaml +0 -0
  90. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/assets/tesoro.mplstyle +0 -0
  91. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/data_sources/__init__.py +0 -0
  92. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/data_sources/debug.py +0 -0
  93. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/database/__init__.py +0 -0
  94. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/database/local.py +0 -0
  95. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/database/push.py +0 -0
  96. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/dependencies/__init__.py +0 -0
  97. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/dependencies/node.py +0 -0
  98. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/dependencies/resolution.py +0 -0
  99. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/driver.py +0 -0
  100. /tesorotools_python-0.0.55/src/tesorotools/offsets/__init__.py → /tesorotools_python-0.1.0/src/tesorotools/latex/templates/common/figures/dot-gitkeep +0 -0
  101. {tesorotools_python-0.0.55/src/tesorotools/pipeline → tesorotools_python-0.1.0/src/tesorotools/offsets}/__init__.py +0 -0
  102. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/offsets/offsets.py +0 -0
  103. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/offsets/outliers.py +0 -0
  104. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/orchestration.py +0 -0
  105. {tesorotools_python-0.0.55/src/tesorotools/render/content → tesorotools_python-0.1.0/src/tesorotools/pipeline}/__init__.py +0 -0
  106. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/pipeline/diagnose.py +0 -0
  107. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/pipeline/engine.py +0 -0
  108. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/pipeline/rules.py +0 -0
  109. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/providers/__init__.py +0 -0
  110. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/providers/base.py +0 -0
  111. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/providers/bde.py +0 -0
  112. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/providers/ecb.py +0 -0
  113. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/providers/lseg.py +0 -0
  114. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/py.typed +0 -0
  115. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/__init__.py +0 -0
  116. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/content/content.py +0 -0
  117. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/content/images.py +0 -0
  118. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/content/section.py +0 -0
  119. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/content/subtitle.py +0 -0
  120. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/content/table.py +0 -0
  121. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/content/text.py +0 -0
  122. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/content/title.py +0 -0
  123. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/document.py +0 -0
  124. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/render/report.py +0 -0
  125. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/testing/__init__.py +0 -0
  126. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/testing/compare.py +0 -0
  127. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/utils/__init__.py +0 -0
  128. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/utils/config.py +0 -0
  129. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/utils/format.py +0 -0
  130. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/utils/globals.py +0 -0
  131. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/utils/matplotlib.py +0 -0
  132. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/utils/series.py +0 -0
  133. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/utils/shortcuts.py +0 -0
  134. {tesorotools_python-0.0.55 → tesorotools_python-0.1.0}/src/tesorotools/utils/template.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tesorotools-python
3
- Version: 0.0.55
3
+ Version: 0.1.0
4
4
  Requires-Python: >=3.13
5
5
  Requires-Dist: babel>=2.17
6
6
  Requires-Dist: matplotlib>=3.10
@@ -25,3 +25,6 @@ Provides-Extra: interactive-plots
25
25
  Requires-Dist: plotly>=5.0; extra == 'interactive-plots'
26
26
  Provides-Extra: lseg
27
27
  Requires-Dist: lseg-data>=2.1; extra == 'lseg'
28
+ Provides-Extra: web
29
+ Requires-Dist: plotly>=5.24; extra == 'web'
30
+ Requires-Dist: streamlit>=1.62; extra == 'web'
@@ -31,6 +31,13 @@ fred = ["requests>=2.31"]
31
31
  imf = ["requests>=2.31", "truststore>=0.10"]
32
32
  lseg = ["lseg-data>=2.1"]
33
33
  interactive_plots = ["plotly>=5.0"]
34
+ # Streamlit dashboards scaffolding (tesorotools.web). The CSS targets
35
+ # Streamlit's DOM (data-testid), so keep the floor at a tested version.
36
+ web = ["streamlit>=1.62", "plotly>=5.24"]
37
+
38
+ [project.scripts]
39
+ tesorotools-web = "tesorotools.web.cli:main"
40
+ tesorotools-latex = "tesorotools.latex.cli:main"
34
41
 
35
42
  [dependency-groups]
36
43
  dev = [
@@ -392,6 +392,14 @@ class LinePlot:
392
392
  y-grid, baseline, last-value labels). Requires the optional
393
393
  ``interactive_plots`` extra (``plotly``); imported lazily so the
394
394
  static path never needs it. Returns a ``plotly.graph_objects.Figure``.
395
+
396
+ Not every knob makes the trip, and the ones that do not are
397
+ accepted silently. ``axis_decimals``, ``vlines``, ``ref_lines``
398
+ and ``show_means`` / ``means_window`` are simply not translated
399
+ yet; ``legend.ncol``, the ``date_*`` knobs and the physical-size
400
+ ones (``figsize``, ``plot_size``, ``compact``, ``font_pt``,
401
+ ``adapt_height``) have no stable equivalent on an interactive
402
+ figure. ``docs/plotly-backend.md`` keeps the full table.
395
403
  """
396
404
  from tesorotools.artists.plotly_backend import line_plot_to_figure
397
405
 
@@ -18,9 +18,9 @@ Requires the optional ``interactive_plots`` extra (``plotly``). Imported
18
18
  lazily from each artist's ``to_plotly`` so the static matplotlib path
19
19
  never depends on plotly.
20
20
 
21
- Coverage: line, type curve, stacked area, stacked bar, shock, waterfall,
22
- horizontal bar, grouped bar and matrix. ``VectorPlot`` (bespoke arrow
23
- geometry) is not ported yet.
21
+ Coverage: every image artist except ``IntradayPlot`` -- line, type
22
+ curve, stacked area, stacked bar, bar+line, box, shock, waterfall,
23
+ horizontal bar, grouped bar, matrix and vector.
24
24
 
25
25
  Known mimicry caveats (the styling that does NOT transfer for free between
26
26
  backends, per the dual-backend research):
@@ -30,7 +30,14 @@ backends, per the dual-backend research):
30
30
  references the family by name -- it falls back unless the font is
31
31
  installed where the figure is viewed.
32
32
  * The "compact" two-per-row Word layout is matplotlib-only; this spike
33
- renders the normal (wide) form.
33
+ renders the normal (wide) form, so the physical-size knobs
34
+ (``figsize``, ``plot_size``, ``compact``, ``font_pt``,
35
+ ``adapt_height``) do nothing here.
36
+ * Beyond those, a few per-artist knobs have no stable Plotly equivalent
37
+ and a few others are simply not translated yet. Both kinds are
38
+ accepted in silence, so which is which is written down parameter by
39
+ parameter in ``docs/plotly-backend.md`` (audited for ``LinePlot``).
40
+ Keep that table in sync when adding or translating a parameter.
34
41
  """
35
42
 
36
43
  from __future__ import annotations
@@ -1,7 +1,7 @@
1
1
  """Resolver for shared OneDrive folders used as a team database.
2
2
 
3
- Absorbed from the ``src/bbdd.py`` copies in ``cnmv_python`` and
4
- ``epf`` — both had the same logic with only a per-project env var
3
+ Absorbed from the ``src/bbdd.py`` copies in two downstream
4
+ projects: both had the same logic with only a per-project env var
5
5
  name differing. The old ``ShortcutDatabase`` (Windows ``.lnk``
6
6
  per user) is superseded by this resolver for the ``bbdd/``
7
7
  layout: each member of the team gets the same path auto-discovered
@@ -10,7 +10,7 @@ from their OneDrive mount.
10
10
  Resolution order
11
11
  ----------------
12
12
  1. An explicit override environment variable (``env_var`` argument,
13
- e.g. ``"CNMV_BBDD_ROOT"``). Used for local dev, CI and tests.
13
+ e.g. ``"MYPROJECT_BBDD_ROOT"``). Used for local dev, CI and tests.
14
14
  2. ``%OneDriveCommercial%`` + glob for a SharePoint folder whose
15
15
  name contains ``team_marker`` and that contains ``subdir``.
16
16
  3. ``%OneDrive%`` as a fallback.
@@ -48,7 +48,7 @@ def resolve_shared_root(
48
48
  ----------
49
49
  env_var
50
50
  Name of the environment variable for explicit override
51
- (e.g. ``"CNMV_BBDD_ROOT"``). Each project picks its own
51
+ (e.g. ``"MYPROJECT_BBDD_ROOT"``). Each project picks its own
52
52
  to avoid collisions on shared dev machines.
53
53
  team_marker
54
54
  Substring matched against the SharePoint folder name.
@@ -128,10 +128,10 @@ class SharedDatabase:
128
128
  ----------
129
129
  project
130
130
  Project name (segment under ``{shared_root}/``, e.g.
131
- ``"cnmv"`` or ``"epf"``).
131
+ ``"myproject"`` or ``"otherproject"``).
132
132
  env_var
133
133
  Environment variable for explicit override of the shared
134
- root (e.g. ``"CNMV_BBDD_ROOT"``).
134
+ root (e.g. ``"MYPROJECT_BBDD_ROOT"``).
135
135
  team_marker
136
136
  Substring of the SharePoint folder name (see
137
137
  :func:`resolve_shared_root`).
@@ -0,0 +1,13 @@
1
+ """Scaffolding for modular LaTeX documents in the Tesoro house style.
2
+
3
+ ``tesorotools-latex new <slug> --kind article|book|beamer`` generates a
4
+ project whose ``main.tex`` pulls one file per part (compilable alone with
5
+ ``subfiles``), styled by ``style/tesoro.sty`` and, for presentations, the
6
+ ``Tesoro`` beamer theme. Colours come from :mod:`tesorotools.palette`.
7
+ Needs no extra: only a TeX distribution with LuaLaTeX, biber and latexmk
8
+ to compile the result. See ``docs/latex.md``.
9
+ """
10
+
11
+ from tesorotools.latex.scaffold import KINDS, Project, create, render
12
+
13
+ __all__ = ["KINDS", "Project", "create", "render"]
@@ -0,0 +1,119 @@
1
+ """``tesorotools-latex``: command line of the LaTeX project scaffolding.
2
+
3
+ ::
4
+
5
+ tesorotools-latex new informe --name "Informe trimestral"
6
+ tesorotools-latex new manual --kind book --name "..." --author "..."
7
+ tesorotools-latex new charla --kind beamer --name "..." \\
8
+ --template-dir ../site-templates --var institute=...
9
+ tesorotools-latex local # after cloning a project
10
+
11
+ Extra layers also come from ``$TESOROTOOLS_LATEX_TEMPLATES`` (applied
12
+ before the ``--template-dir`` ones); see :mod:`tesorotools.latex.scaffold`.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import sys
19
+ from collections.abc import Sequence
20
+ from pathlib import Path
21
+
22
+ from tesorotools.latex.scaffold import (
23
+ KINDS,
24
+ Project,
25
+ create,
26
+ env_layers,
27
+ write_local,
28
+ )
29
+ from tesorotools.scaffold import parse_vars
30
+
31
+
32
+ def _parser() -> argparse.ArgumentParser:
33
+ parser = argparse.ArgumentParser(
34
+ prog="tesorotools-latex",
35
+ description="Andamiaje de documentos LaTeX con el estilo del Tesoro.",
36
+ )
37
+ commands = parser.add_subparsers(dest="command", required=True)
38
+ new = commands.add_parser("new", help="crea un proyecto LaTeX")
39
+ new.add_argument("slug", help="identificador corto, p. ej. mi-informe")
40
+ new.add_argument("--name", required=True, help="título del documento")
41
+ new.add_argument(
42
+ "--kind",
43
+ choices=list(KINDS),
44
+ default="article",
45
+ help="tipo de documento (por defecto article)",
46
+ )
47
+ new.add_argument("--author", default="", help="autor o autores")
48
+ new.add_argument(
49
+ "--dir",
50
+ type=Path,
51
+ default=None,
52
+ help="carpeta destino (por defecto ./<slug>)",
53
+ )
54
+ new.add_argument(
55
+ "--template-dir",
56
+ type=Path,
57
+ action="append",
58
+ default=[],
59
+ help="capa de plantillas adicional (repetible, se aplican en orden)",
60
+ )
61
+ new.add_argument(
62
+ "--var",
63
+ action="append",
64
+ default=[],
65
+ metavar="CLAVE=VALOR",
66
+ help="variable adicional para las plantillas (repetible)",
67
+ )
68
+ new.add_argument(
69
+ "--force", action="store_true", help="sobrescribe ficheros"
70
+ )
71
+ local = commands.add_parser(
72
+ "local",
73
+ help="reescribe style/tesorolocal.sty (tras clonar un proyecto)",
74
+ )
75
+ local.add_argument(
76
+ "dir",
77
+ type=Path,
78
+ nargs="?",
79
+ default=Path("."),
80
+ help="carpeta del proyecto (por defecto la actual)",
81
+ )
82
+ return parser
83
+
84
+
85
+ def _local(root: Path) -> int:
86
+ try:
87
+ path = write_local(root)
88
+ except ValueError as exc:
89
+ print(f"error: {exc}", file=sys.stderr)
90
+ return 1
91
+ print(f"Escrito {path}.")
92
+ return 0
93
+
94
+
95
+ def main(argv: Sequence[str] | None = None) -> int:
96
+ args = _parser().parse_args(argv)
97
+ if args.command == "local":
98
+ return _local(args.dir)
99
+ try:
100
+ project = Project(
101
+ slug=args.slug,
102
+ name=args.name,
103
+ kind=args.kind,
104
+ author=args.author,
105
+ extra=parse_vars(args.var),
106
+ )
107
+ root: Path = args.dir if args.dir is not None else Path(args.slug)
108
+ layers = [*env_layers(), *args.template_dir]
109
+ written = create(project, root, layers, force=args.force)
110
+ except (ValueError, FileExistsError) as exc:
111
+ print(f"error: {exc}", file=sys.stderr)
112
+ return 1
113
+ print(f"Proyecto creado en {root} ({len(written)} ficheros).")
114
+ print(f"Siguiente paso: cd {root} && latexmk")
115
+ return 0
116
+
117
+
118
+ if __name__ == "__main__":
119
+ sys.exit(main())
@@ -0,0 +1,185 @@
1
+ """Generate a modular LaTeX project in the Tesoro house style.
2
+
3
+ Three kinds share one look: ``article``, ``book`` and ``beamer``. Each
4
+ project is the ``templates/common`` layer (house style, ``latexmkrc``,
5
+ bibliography, editor settings) plus the layer of its kind (``main.tex``
6
+ and one file per part, compiled together or alone with ``subfiles``),
7
+ plus any extra layers passed with ``--template-dir`` or listed in
8
+ ``$TESOROTOOLS_LATEX_TEMPLATES`` (a logo, a cover, a different preamble).
9
+ Layout rules as in :mod:`tesorotools.scaffold`.
10
+
11
+ The colours are not copied into the templates: ``style/tesorobrand.sty``
12
+ is written from :mod:`tesorotools.palette` at generation time. The
13
+ location of the bundled Cabinet Grotesk goes to ``style/tesorolocal.sty``
14
+ instead, which the generated ``.gitignore`` leaves out because it holds
15
+ a local path; :func:`write_local` (``tesorotools-latex local``) writes it
16
+ again on another machine. The font itself is never copied, see
17
+ ``fonts/README.md`` in a generated project.
18
+
19
+ Placeholders: ``$slug``, ``$name``, ``$author``, ``$kind``, ``$parts``
20
+ (the folder of the parts), ``$tex_name`` and ``$tex_author`` (escaped
21
+ for LaTeX), ``$colors``, ``$fontdir``, ``$generated`` and any
22
+ ``--var KEY=VALUE``.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import datetime as dt
28
+ from collections.abc import Mapping, Sequence
29
+ from dataclasses import dataclass, field
30
+ from pathlib import Path
31
+ from string import Template
32
+
33
+ from tesorotools import palette, scaffold
34
+ from tesorotools.utils.globals import FONTS
35
+
36
+ TEMPLATES = Path(__file__).resolve().parent / "templates"
37
+
38
+ #: Extra layers, applied after the base and before ``--template-dir``.
39
+ TEMPLATES_ENV = "TESOROTOOLS_LATEX_TEMPLATES"
40
+
41
+ #: Kind of document -> folder holding its parts.
42
+ KINDS: Mapping[str, str] = {
43
+ "article": "sections",
44
+ "book": "chapters",
45
+ "beamer": "slides",
46
+ }
47
+
48
+ #: The generated file that is specific to a machine (never versioned).
49
+ LOCAL_FILE = "style/tesorolocal.sty"
50
+
51
+ #: ``tesorotools.palette`` constant -> LaTeX colour name.
52
+ COLORS: Mapping[str, str] = {
53
+ "BLUE": "TesoroBlue",
54
+ "BLUE_DARK": "TesoroBlueDark",
55
+ "BLUE_MID": "TesoroBlueMid",
56
+ "BLUE_PALE": "TesoroBluePale",
57
+ "BLUE_LIGHT": "TesoroBlueLight",
58
+ "BLUE_FAINT": "TesoroBlueFaint",
59
+ "GREY": "TesoroGrey",
60
+ "GREEN": "TesoroGreen",
61
+ "RED": "TesoroRed",
62
+ "GREEN_LIGHT": "TesoroGreenLight",
63
+ "RED_LIGHT": "TesoroRedLight",
64
+ }
65
+
66
+ _TEX_SPECIALS = {
67
+ "\\": r"\textbackslash{}",
68
+ "&": r"\&",
69
+ "%": r"\%",
70
+ "$": r"\$",
71
+ "#": r"\#",
72
+ "_": r"\_",
73
+ "{": r"\{",
74
+ "}": r"\}",
75
+ "~": r"\textasciitilde{}",
76
+ "^": r"\textasciicircum{}",
77
+ }
78
+
79
+
80
+ def tex_escape(text: str) -> str:
81
+ """*text* with the LaTeX special characters escaped."""
82
+ return "".join(_TEX_SPECIALS.get(char, char) for char in text)
83
+
84
+
85
+ def color_definitions() -> str:
86
+ """``\\definecolor`` lines for the house colours and the series cycle."""
87
+ lines = [
88
+ rf"\definecolor{{{name}}}{{HTML}}{{{getattr(palette, const)}}}"
89
+ for const, name in COLORS.items()
90
+ ]
91
+ lines += [
92
+ rf"\definecolor{{TesoroC{i}}}{{HTML}}{{{color.lstrip('#').upper()}}}"
93
+ for i, color in enumerate(palette.series_colors())
94
+ ]
95
+ return "\n".join(lines)
96
+
97
+
98
+ def _machine_values() -> dict[str, str]:
99
+ """Values that depend on this machine and on today."""
100
+ return {
101
+ "fontdir": FONTS.resolve().as_posix() + "/",
102
+ "generated": dt.date.today().strftime("%Y/%m/%d"),
103
+ }
104
+
105
+
106
+ @dataclass(frozen=True)
107
+ class Project:
108
+ """What the templates are filled with."""
109
+
110
+ slug: str
111
+ name: str
112
+ kind: str = "article"
113
+ author: str = ""
114
+ extra: Mapping[str, str] = field(default_factory=lambda: {})
115
+
116
+ def __post_init__(self) -> None:
117
+ scaffold.check_slug(self.slug)
118
+ if self.kind not in KINDS:
119
+ raise ValueError(
120
+ f"invalid kind {self.kind!r}: use one of {', '.join(KINDS)}"
121
+ )
122
+ scaffold.check_variables(self.extra)
123
+
124
+ def layers(self) -> tuple[Path, Path]:
125
+ """The base layers of this kind: common, then the kind's own."""
126
+ return TEMPLATES / "common", TEMPLATES / self.kind
127
+
128
+ def mapping(self) -> dict[str, str]:
129
+ return {
130
+ **self.extra,
131
+ "slug": self.slug,
132
+ "name": self.name,
133
+ "author": self.author,
134
+ "kind": self.kind,
135
+ "parts": KINDS[self.kind],
136
+ "tex_name": tex_escape(self.name),
137
+ "tex_author": tex_escape(self.author),
138
+ "colors": color_definitions(),
139
+ **_machine_values(),
140
+ }
141
+
142
+
143
+ def env_layers() -> list[Path]:
144
+ """The layers listed in ``$TESOROTOOLS_LATEX_TEMPLATES``."""
145
+ return scaffold.env_layers(TEMPLATES_ENV)
146
+
147
+
148
+ def render(project: Project, layers: Sequence[Path] = ()) -> dict[str, bytes]:
149
+ """Relative path -> file content for base + *layers*, in memory."""
150
+ return scaffold.render((*project.layers(), *layers), project.mapping())
151
+
152
+
153
+ def create(
154
+ project: Project,
155
+ root: Path,
156
+ layers: Sequence[Path] = (),
157
+ *,
158
+ force: bool = False,
159
+ ) -> list[Path]:
160
+ """Write the project under *root* and return the files written.
161
+
162
+ Everything is rendered and every target checked before anything is
163
+ written, so a refusal or a template error leaves nothing half made.
164
+ Existing files are not overwritten unless ``force`` is true.
165
+ """
166
+ return scaffold.write(render(project, layers), root, force=force)
167
+
168
+
169
+ def write_local(root: Path) -> Path:
170
+ """Write ``style/tesorolocal.sty`` of the project at *root* again.
171
+
172
+ Needed after cloning a project on another machine: the file holds a
173
+ local path, so the generated ``.gitignore`` keeps it out of the
174
+ repository. Overwrites the previous one, if any.
175
+ """
176
+ if not (root / "main.tex").is_file():
177
+ raise ValueError(f"no main.tex in {root}: not a LaTeX project")
178
+ source = TEMPLATES / "common" / f"{LOCAL_FILE}.tmpl"
179
+ text = Template(source.read_text(encoding="utf-8")).substitute(
180
+ _machine_values()
181
+ )
182
+ path = root / LOCAL_FILE
183
+ path.parent.mkdir(parents=True, exist_ok=True)
184
+ path.write_bytes(text.encode("utf-8"))
185
+ return path
@@ -0,0 +1,33 @@
1
+ % !TEX program = lualatex
2
+ \documentclass[11pt, a4paper]{article}
3
+
4
+ % The house style lives in style/. latexmkrc puts it on the search
5
+ % path; this is the fallback for editors that run LuaLaTeX directly.
6
+ \makeatletter
7
+ \def\input@path{{style/}{../style/}}
8
+ \makeatother
9
+ \usepackage{tesoro}
10
+
11
+ \usepackage{subfiles}
12
+ \usepackage{csquotes}
13
+ \usepackage[backend=biber, style=authoryear]{biblatex}
14
+ \addbibresource{\subfix{refs.bib}}
15
+ \graphicspath{{\subfix{figures/}}}
16
+
17
+ \title{$tex_name}
18
+ % \subtitle{...}
19
+ % \shorttitle{...} % page header, when the title is too long
20
+ \author{$tex_author}
21
+ \date{\today}
22
+
23
+ \begin{document}
24
+
25
+ \maketitle
26
+
27
+ \subfile{sections/01-introduccion}
28
+ \subfile{sections/02-analisis}
29
+ \subfile{sections/03-conclusiones}
30
+
31
+ \printbibliography[heading=bibintoc]
32
+
33
+ \end{document}
@@ -0,0 +1,18 @@
1
+ \documentclass[../main.tex]{subfiles}
2
+ \begin{document}
3
+
4
+ \section{Introducción}
5
+
6
+ Este fichero es una parte del documento: se incluye desde
7
+ \texttt{main.tex} con \verb|\subfile| y también se puede compilar solo.
8
+
9
+ Las citas usan biblatex \parencite{ejemplo2025}, y los números se
10
+ escriben con siunitx para que salgan en formato español: \num{1234567.89}.
11
+
12
+ \begin{itemize}
13
+ \item Una idea.
14
+ \item Otra idea, con \positivo{mejora} y \negativo{empeoramiento}.
15
+ \end{itemize}
16
+
17
+ \ifSubfilesClassLoaded{\printbibliography}{}
18
+ \end{document}
@@ -0,0 +1,51 @@
1
+ \documentclass[../main.tex]{subfiles}
2
+ \begin{document}
3
+
4
+ \section{Análisis}
5
+
6
+ \subsection{Tablas}
7
+
8
+ La tabla~\ref{tab:emisiones} muestra el formato de la casa.
9
+
10
+ \begin{table}[htbp]
11
+ \caption{Emisiones por instrumento (millones de euros, datos ficticios)}
12
+ \label{tab:emisiones}
13
+ \centering
14
+ \tesorozebra
15
+ \begin{tabular}{l S[table-format=5.1] S[table-format=5.1] r}
16
+ \toprule
17
+ \tesorohead
18
+ \hcell{Instrumento} & {\hcell{2025}} & {\hcell{2026}}
19
+ & \hcell{Var. \%} \\
20
+ \midrule
21
+ Letras & 12345.6 & 13020.4 & \positivo{\num{5.5}} \\
22
+ Bonos & 23456.7 & 22100.0 & \negativo{\num{-5.8}} \\
23
+ Obligaciones & 34567.8 & 36000.2 & \positivo{\num{4.1}} \\
24
+ \bottomrule
25
+ \end{tabular}
26
+ \fuente{Elaboración propia.}
27
+ \end{table}
28
+
29
+ \subsection{Figuras}
30
+
31
+ Los gráficos de tesorotools se exportan en PDF y se incluyen con
32
+ \verb|\includegraphics[width=\linewidth]{nombre}| desde \texttt{figures/}.
33
+ La figura~\ref{fig:paleta} usa el ciclo de colores de esos gráficos.
34
+
35
+ \begin{figure}[htbp]
36
+ \caption{Ciclo de colores de las series (datos ficticios)}
37
+ \label{fig:paleta}
38
+ \centering
39
+ \begin{tikzpicture}[x=1.6cm, y=0.04cm]
40
+ \foreach \x/\h/\col in
41
+ {1/40/TesoroC0, 2/65/TesoroC1, 3/30/TesoroC2, 4/55/TesoroC4} {
42
+ \fill[\col] (\x-0.3, 0) rectangle (\x+0.3, \h);
43
+ \node[above, font=\small] at (\x, \h) {\num{\h}};
44
+ }
45
+ \draw[TesoroGrey] (0.4, 0) -- (4.6, 0);
46
+ \end{tikzpicture}
47
+ \fuente{Elaboración propia.}
48
+ \end{figure}
49
+
50
+ \ifSubfilesClassLoaded{\printbibliography}{}
51
+ \end{document}
@@ -0,0 +1,10 @@
1
+ \documentclass[../main.tex]{subfiles}
2
+ \begin{document}
3
+
4
+ \section{Conclusiones}
5
+
6
+ Las conclusiones, con referencias cruzadas a la
7
+ tabla~\ref{tab:emisiones} y a la bibliografía \parencite{ejemplo2026}.
8
+
9
+ \ifSubfilesClassLoaded{\printbibliography}{}
10
+ \end{document}
@@ -0,0 +1,47 @@
1
+ % !TEX program = lualatex
2
+ \documentclass[aspectratio=169, xcolor=table, 11pt]{beamer}
3
+
4
+ % The house style lives in style/. latexmkrc puts it on the search
5
+ % path; this is the fallback for editors that run LuaLaTeX directly.
6
+ \makeatletter
7
+ \def\input@path{{style/}{../style/}}
8
+ \makeatother
9
+ \usetheme{Tesoro}
10
+
11
+ \usepackage{subfiles}
12
+ \usepackage{csquotes}
13
+ \usepackage[backend=biber, style=authoryear]{biblatex}
14
+ \addbibresource{\subfix{refs.bib}}
15
+ \graphicspath{{\subfix{figures/}}}
16
+
17
+ \title{$tex_name}
18
+ % \subtitle{...}
19
+ \author{$tex_author}
20
+ % \institute{...}
21
+ \date{\today}
22
+ % \titlegraphic{\includegraphics[height=1cm]{logo}}
23
+
24
+ % A divider slide at the start of each section.
25
+ \AtBeginSection[]{\begin{frame}[plain, noframenumbering]
26
+ \sectionpage
27
+ \end{frame}}
28
+
29
+ \begin{document}
30
+
31
+ \begin{frame}[plain, noframenumbering]
32
+ \titlepage
33
+ \end{frame}
34
+
35
+ \begin{frame}{Índice}
36
+ \tableofcontents
37
+ \end{frame}
38
+
39
+ \subfile{slides/01-contexto}
40
+ \subfile{slides/02-analisis}
41
+ \subfile{slides/03-conclusiones}
42
+
43
+ \begin{frame}[allowframebreaks]{Referencias}
44
+ \printbibliography[heading=none]
45
+ \end{frame}
46
+
47
+ \end{document}
@@ -0,0 +1,28 @@
1
+ \documentclass[../main.tex]{subfiles}
2
+ \begin{document}
3
+
4
+ \section{Contexto}
5
+
6
+ \begin{frame}{Una diapositiva con lista}{Subtítulo opcional}
7
+ Cada bloque de diapositivas es un fichero de \texttt{slides/}, que se
8
+ puede compilar solo.
9
+ \begin{itemize}
10
+ \item Una idea, con una cita \parencite{ejemplo2025}.
11
+ \item Otra idea, \alert{destacada}.
12
+ \item Números en formato español: \num{1234567.89}.
13
+ \end{itemize}
14
+ \end{frame}
15
+
16
+ \begin{frame}{Bloques}
17
+ \begin{block}{Mensaje principal}
18
+ El azul del Tesoro para lo importante.
19
+ \end{block}
20
+ \begin{exampleblock}{Mejora}
21
+ Variaciones favorables en verde.
22
+ \end{exampleblock}
23
+ \begin{alertblock}{Riesgo}
24
+ Variaciones desfavorables en rojo.
25
+ \end{alertblock}
26
+ \end{frame}
27
+
28
+ \end{document}
@@ -0,0 +1,39 @@
1
+ \documentclass[../main.tex]{subfiles}
2
+ \begin{document}
3
+
4
+ \section{Análisis}
5
+
6
+ \begin{frame}{Tabla y gráfico}
7
+ \begin{columns}[T]
8
+ \begin{column}{0.52\textwidth}
9
+ \footnotesize
10
+ \tesorozebra
11
+ \begin{tabular}{l S[table-format=5.1] r}
12
+ \toprule
13
+ \tesorohead
14
+ \hcell{Instrumento} & {\hcell{2026}} & \hcell{Var. \%} \\
15
+ \midrule
16
+ Letras & 13020.4 & \positivo{\num{5.5}} \\
17
+ Bonos & 22100.0 & \negativo{\num{-5.8}} \\
18
+ Obligaciones & 36000.2 & \positivo{\num{4.1}} \\
19
+ \bottomrule
20
+ \end{tabular}
21
+ \fuente{Elaboración propia con datos ficticios.}
22
+ \end{column}
23
+ \begin{column}{0.44\textwidth}
24
+ % Charts from tesorotools: \includegraphics[width=\linewidth]{name}
25
+ \centering
26
+ \begin{tikzpicture}[x=1cm, y=0.03cm]
27
+ \foreach \x/\h/\col in
28
+ {1/40/TesoroC0, 2/65/TesoroC1, 3/30/TesoroC2, 4/55/TesoroC4} {
29
+ \fill[\col] (\x-0.3, 0) rectangle (\x+0.3, \h);
30
+ \node[above, font=\scriptsize] at (\x, \h) {\num{\h}};
31
+ }
32
+ \draw[TesoroGrey] (0.4, 0) -- (4.6, 0);
33
+ \end{tikzpicture}
34
+ \fuente{Elaboración propia.}
35
+ \end{column}
36
+ \end{columns}
37
+ \end{frame}
38
+
39
+ \end{document}