saggio 1.4.2__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 (93) hide show
  1. saggio/__init__.py +198 -0
  2. saggio/__main__.py +32 -0
  3. saggio/analyze/__init__.py +125 -0
  4. saggio/analyze/apple.py +542 -0
  5. saggio/analyze/capability.py +469 -0
  6. saggio/analyze/cpu.py +389 -0
  7. saggio/analyze/llm.py +396 -0
  8. saggio/analyze/power/__init__.py +133 -0
  9. saggio/analyze/power/accelerator.py +223 -0
  10. saggio/analyze/power/graphics.py +185 -0
  11. saggio/analyze/power/meter.py +391 -0
  12. saggio/analyze/power/rapl.py +156 -0
  13. saggio/analyze/power/reading.py +97 -0
  14. saggio/analyze/power/soc.py +72 -0
  15. saggio/analyze/power/sysfs.py +66 -0
  16. saggio/analyze/power/tables.py +196 -0
  17. saggio/analyze/run.py +1117 -0
  18. saggio/analyze/static/__init__.py +123 -0
  19. saggio/analyze/static/archetype.py +197 -0
  20. saggio/analyze/static/calls.py +223 -0
  21. saggio/analyze/static/findings.py +312 -0
  22. saggio/analyze/static/languages.py +44 -0
  23. saggio/analyze/static/read.py +83 -0
  24. saggio/analyze/static/running.py +267 -0
  25. saggio/analyze/static/tables.py +358 -0
  26. saggio/analyze/static/walking.py +238 -0
  27. saggio/analyze/static/worksize.py +213 -0
  28. saggio/auditor/__init__.py +74 -0
  29. saggio/auditor/assumptions.py +230 -0
  30. saggio/auditor/blocks.py +169 -0
  31. saggio/auditor/build.py +331 -0
  32. saggio/auditor/measuring.py +172 -0
  33. saggio/auditor/naming.py +134 -0
  34. saggio/auditor/options.py +144 -0
  35. saggio/auditor/paths.py +56 -0
  36. saggio/auditor/projections.py +287 -0
  37. saggio/catalog/__init__.py +71 -0
  38. saggio/catalog/pricing.py +410 -0
  39. saggio/catalog/refresh/__init__.py +132 -0
  40. saggio/catalog/refresh/carbon.py +408 -0
  41. saggio/catalog/refresh/embodied.py +296 -0
  42. saggio/catalog/refresh/tariffs.py +350 -0
  43. saggio/catalog/refresh/timezones.py +233 -0
  44. saggio/catalog/registry.py +804 -0
  45. saggio/cli/__init__.py +38 -0
  46. saggio/cli/app.py +726 -0
  47. saggio/cli/commands.py +1151 -0
  48. saggio/cli/exit_codes.py +52 -0
  49. saggio/data/__init__.py +27 -0
  50. saggio/data/grid.yaml +553 -0
  51. saggio/data/hardware.yaml +334 -0
  52. saggio/data/instances.yaml +119 -0
  53. saggio/data/providers.yaml +74 -0
  54. saggio/data/report/i18n.yaml +120 -0
  55. saggio/data/report/logo.png +0 -0
  56. saggio/data/report/report.css +245 -0
  57. saggio/data/report/report.html +38 -0
  58. saggio/data/report/report.js +168 -0
  59. saggio/data/services.yaml +111 -0
  60. saggio/data/templates/annotated.yaml +183 -0
  61. saggio/data/templates/minimal.yaml +85 -0
  62. saggio/diff.py +529 -0
  63. saggio/estimate/__init__.py +124 -0
  64. saggio/estimate/context.py +618 -0
  65. saggio/estimate/embodied.py +329 -0
  66. saggio/estimate/energy.py +580 -0
  67. saggio/estimate/equivalences.py +263 -0
  68. saggio/estimate/extrapolate.py +939 -0
  69. saggio/estimate/machine.py +359 -0
  70. saggio/estimate/scaling.py +527 -0
  71. saggio/fold.py +453 -0
  72. saggio/model/__init__.py +135 -0
  73. saggio/model/cost_model.py +614 -0
  74. saggio/model/derivation.py +487 -0
  75. saggio/model/dimensions.py +371 -0
  76. saggio/model/quantity.py +482 -0
  77. saggio/model/results.py +279 -0
  78. saggio/model/schema.py +170 -0
  79. saggio/model/taxonomy.py +186 -0
  80. saggio/model/validate.py +1001 -0
  81. saggio/report/__init__.py +60 -0
  82. saggio/report/dashboard.py +273 -0
  83. saggio/report/figures.py +835 -0
  84. saggio/report/html.py +1168 -0
  85. saggio/report/markdown.py +1001 -0
  86. saggio/report/office.py +146 -0
  87. saggio/templates.py +112 -0
  88. saggio-1.4.2.dist-info/METADATA +411 -0
  89. saggio-1.4.2.dist-info/RECORD +93 -0
  90. saggio-1.4.2.dist-info/WHEEL +5 -0
  91. saggio-1.4.2.dist-info/entry_points.txt +2 -0
  92. saggio-1.4.2.dist-info/licenses/LICENSE +29 -0
  93. saggio-1.4.2.dist-info/top_level.txt +1 -0
saggio/__init__.py ADDED
@@ -0,0 +1,198 @@
1
+ """
2
+ saggio: what it costs to run your code, and how much to trust it.
3
+
4
+ Module summary
5
+ --------------
6
+ This package answers one question about a piece of software, per unit of work:
7
+ what does running it cost? Money, time, energy, carbon, water, and whatever else
8
+ your team decides to watch. The answer is a YAML file you commit next to the code,
9
+ and reports rendered from it.
10
+
11
+ What makes the answer worth having is the second half of every number: its
12
+ *status*. ``measured`` means a counter said so. ``estimated`` means a sourced
13
+ formula said so. ``placeholder`` means the field is being held open. ``TODO`` means
14
+ a human has to supply it. A derived value names the numbers it came from and may
15
+ never claim to be better founded than the weakest of them, and the validator
16
+ enforces that by walking the file rather than by trusting it.
17
+
18
+ The package is organised in four layers with a strict direction of dependency.
19
+ :mod:`~saggio.model` is the pure vocabulary and the rules.
20
+ :mod:`~saggio.catalog` holds sourced facts about the world.
21
+ :mod:`~saggio.estimate` and
22
+ :mod:`~saggio.analyze` turn facts and measurements into numbers.
23
+ :mod:`~saggio.report` and
24
+ :mod:`~saggio.cli` are ways of reaching all of it. Nothing lower
25
+ imports anything higher, so the command line can do nothing a library caller
26
+ cannot.
27
+
28
+ Usage example
29
+ -------------
30
+ >>> import saggio
31
+ >>> result = saggio.audit(".", options=saggio.AuditOptions(run=False, use_llm=False))
32
+ >>> result.report.ok
33
+ True
34
+ >>> saggio.render_markdown(result.model).startswith("# Cost of running")
35
+ True
36
+
37
+ Author
38
+ ------
39
+ Warith Harchaoui, Ph.D. — https://linkedin.com/in/warith-harchaoui/
40
+ """
41
+
42
+ from __future__ import annotations
43
+
44
+ import sys
45
+ from typing import Final
46
+
47
+ #: The platforms this package supports, stated before anything else is imported
48
+ #: so that an unsupported one is told why rather than meeting a missing stdlib
49
+ #: module three imports deeper. Repeated from
50
+ #: :mod:`saggio.analyze.capability`, which cannot be imported this early without
51
+ #: a cycle, and pinned to it by a test.
52
+ SUPPORTED_PLATFORMS: Final[tuple[str, ...]] = ("linux", "darwin")
53
+
54
+ if not any(sys.platform.startswith(name) for name in SUPPORTED_PLATFORMS):
55
+ raise ImportError(
56
+ f"saggio does not support {sys.platform}. It supports Linux and macOS, and "
57
+ "Windows is out of scope deliberately: it publishes no vendor-neutral "
58
+ "processor energy counter to an unprivileged process, no machine-wide "
59
+ "processor-time total this package can read, and no POSIX resource "
60
+ "accounting for a child process. A tool whose whole proposition is that a "
61
+ "number says how far it can be trusted should not pretend to support a "
62
+ "platform where it could only ever estimate."
63
+ )
64
+
65
+ #: The installed version, kept in step with pyproject.toml at release.
66
+ __version__: Final[str] = "1.4.2"
67
+
68
+ __author__: Final[str] = "Warith Harchaoui, Ph.D."
69
+ __email__: Final[str] = "warith.harchaoui@sev7n.io"
70
+
71
+ from .analyze import (
72
+ RepositoryReading,
73
+ SliceResult,
74
+ read_repository,
75
+ run_slice,
76
+ )
77
+ from .auditor import AuditOptions, AuditResult, audit, audit_git_url, repository_name
78
+ from .catalog import Catalog, add_row, stale_report
79
+ from .diff import Change, Comparison, compare
80
+ from .estimate import (
81
+ DeploymentContext,
82
+ MachineProfile,
83
+ Observation,
84
+ Projection,
85
+ ScalingFit,
86
+ car_km,
87
+ carbon_from_energy,
88
+ detect_machine,
89
+ embodied_carbon,
90
+ energy_from_runtime,
91
+ equivalences,
92
+ fit_power_law,
93
+ flight_fraction,
94
+ it_energy_from_runtime,
95
+ money_from_energy,
96
+ node_power,
97
+ project_to_completion,
98
+ project_to_machine,
99
+ project_to_processor,
100
+ software_carbon_intensity,
101
+ tree_months,
102
+ water_from_energy,
103
+ )
104
+ from .fold import Fold, fold_measurement
105
+ from .model import (
106
+ CANONICAL_DIMENSIONS,
107
+ ESTIMATED,
108
+ MEASURED,
109
+ PLACEHOLDER,
110
+ SCHEMA_VERSION,
111
+ TODO,
112
+ CostModel,
113
+ Dimension,
114
+ DimensionRegistry,
115
+ Issue,
116
+ Quantity,
117
+ Report,
118
+ overall_status,
119
+ validate,
120
+ weakest,
121
+ )
122
+ from .report import render_dashboard, render_html, render_markdown, render_office
123
+ from .templates import DEFAULT_TEMPLATE, TEMPLATES, template_mapping, template_names, template_text
124
+
125
+ __all__ = [
126
+ "__version__",
127
+ "__author__",
128
+ "__email__",
129
+ # The model and its rules.
130
+ "CostModel",
131
+ "Quantity",
132
+ "Dimension",
133
+ "DimensionRegistry",
134
+ "CANONICAL_DIMENSIONS",
135
+ "SCHEMA_VERSION",
136
+ "MEASURED",
137
+ "ESTIMATED",
138
+ "PLACEHOLDER",
139
+ "TODO",
140
+ "weakest",
141
+ "validate",
142
+ "overall_status",
143
+ "Report",
144
+ "Issue",
145
+ # Facts about the world.
146
+ "Catalog",
147
+ "add_row",
148
+ "stale_report",
149
+ # Estimation.
150
+ "DeploymentContext",
151
+ "MachineProfile",
152
+ "detect_machine",
153
+ "node_power",
154
+ "it_energy_from_runtime",
155
+ "energy_from_runtime",
156
+ "carbon_from_energy",
157
+ "water_from_energy",
158
+ "money_from_energy",
159
+ "tree_months",
160
+ "car_km",
161
+ "flight_fraction",
162
+ "equivalences",
163
+ "Observation",
164
+ "Projection",
165
+ "ScalingFit",
166
+ "embodied_carbon",
167
+ "fit_power_law",
168
+ "project_to_completion",
169
+ "software_carbon_intensity",
170
+ "project_to_machine",
171
+ "project_to_processor",
172
+ # Reading and running a repository.
173
+ "RepositoryReading",
174
+ "read_repository",
175
+ "SliceResult",
176
+ "run_slice",
177
+ # The whole job.
178
+ "AuditOptions",
179
+ "AuditResult",
180
+ "audit",
181
+ "audit_git_url",
182
+ "repository_name",
183
+ "Fold",
184
+ "compare",
185
+ "fold_measurement",
186
+ "Comparison",
187
+ "Change",
188
+ # Reports.
189
+ "render_markdown",
190
+ "render_html",
191
+ "render_office",
192
+ "render_dashboard",
193
+ "template_text",
194
+ "template_mapping",
195
+ "template_names",
196
+ "TEMPLATES",
197
+ "DEFAULT_TEMPLATE",
198
+ ]
saggio/__main__.py ADDED
@@ -0,0 +1,32 @@
1
+ """Running the package with ``python -m saggio``.
2
+
3
+ Module summary
4
+ --------------
5
+ The console script installed as ``saggio`` is the ordinary way in. This is the
6
+ other one, and it matters more than it looks: ``python -m saggio`` runs the
7
+ command line out of *this* interpreter's environment, whatever is on the PATH.
8
+ That is what somebody reaches for when two versions are installed, what a test
9
+ suite needs to exercise the working tree rather than whatever was installed
10
+ last, and what works in a container where no scripts directory is on the PATH.
11
+
12
+ Without it the package answers ``'saggio' is a package and cannot be directly
13
+ executed``, which reads as though the tool is broken rather than as though one
14
+ file is missing.
15
+
16
+ Usage example
17
+ -------------
18
+ .. code-block:: console
19
+
20
+ $ python -m saggio --version
21
+ saggio 1.4.2
22
+
23
+ Author
24
+ ------
25
+ Warith Harchaoui
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ from .cli.app import run
31
+
32
+ run()
@@ -0,0 +1,125 @@
1
+ """
2
+ Finding out what a repository is and what it costs to run.
3
+
4
+ Module summary
5
+ --------------
6
+ Three ways of knowing, in descending order of trust, and each one labelled so the
7
+ difference survives into the report. :mod:`static` reads the code and owns every
8
+ number that comes from reading. :mod:`run` and :mod:`power` execute a bounded
9
+ slice, with the user's explicit consent, and own every number that comes from
10
+ measurement. :mod:`llm` asks a local model what shape the work is, and owns no
11
+ number at all.
12
+
13
+ Usage example
14
+ -------------
15
+ >>> from saggio.analyze import read_repository
16
+ >>> read_repository(".").archetype is not None
17
+ True
18
+
19
+ Author
20
+ ------
21
+ Warith Harchaoui
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from .apple import SocEnergy, SocMeter
27
+ from .capability import Interface, measurable, paths_read, probe, summary
28
+ from .llm import (
29
+ WORKLOAD_KINDS,
30
+ Classification,
31
+ classify,
32
+ installed_models,
33
+ is_available,
34
+ pick_model,
35
+ )
36
+ from .power import (
37
+ RAPL_SCOPE_NOTE,
38
+ GraphicsSampler,
39
+ PowerMeter,
40
+ PowerReading,
41
+ read_graphics_energy_microjoules,
42
+ read_graphics_watts,
43
+ read_memory_energy_microjoules,
44
+ read_package_energy_microjoules,
45
+ unavailable_reason,
46
+ )
47
+ from .run import (
48
+ CONSENT_PROMPT,
49
+ DEFAULT_TIMEOUT_SECONDS,
50
+ ProfileEntry,
51
+ SliceResult,
52
+ consent_path,
53
+ has_consent,
54
+ record_consent,
55
+ require_consent,
56
+ run_slice,
57
+ )
58
+ from .static import (
59
+ DEFAULT_CAP_FRACTION,
60
+ RepositoryReading,
61
+ ServiceHit,
62
+ WorkSizeCandidate,
63
+ capped_entrypoint_command,
64
+ detect_archetype,
65
+ detect_frameworks,
66
+ detect_languages,
67
+ detect_services,
68
+ detect_tests,
69
+ find_entrypoint,
70
+ find_work_size,
71
+ read_repository,
72
+ )
73
+
74
+ __all__ = [
75
+ # Static reading.
76
+ "RepositoryReading",
77
+ "ServiceHit",
78
+ "WorkSizeCandidate",
79
+ "read_repository",
80
+ "detect_languages",
81
+ "detect_archetype",
82
+ "detect_frameworks",
83
+ "detect_services",
84
+ "detect_tests",
85
+ "find_entrypoint",
86
+ "find_work_size",
87
+ "capped_entrypoint_command",
88
+ "DEFAULT_CAP_FRACTION",
89
+ # Power.
90
+ "PowerMeter",
91
+ "PowerReading",
92
+ "GraphicsSampler",
93
+ "RAPL_SCOPE_NOTE",
94
+ "read_package_energy_microjoules",
95
+ "read_memory_energy_microjoules",
96
+ "read_graphics_energy_microjoules",
97
+ "read_graphics_watts",
98
+ "unavailable_reason",
99
+ # Apple Silicon, read without privileges.
100
+ "SocMeter",
101
+ "SocEnergy",
102
+ # What this machine will let you read, and what it would take.
103
+ "Interface",
104
+ "probe",
105
+ "measurable",
106
+ "summary",
107
+ "paths_read",
108
+ # Running.
109
+ "SliceResult",
110
+ "ProfileEntry",
111
+ "run_slice",
112
+ "has_consent",
113
+ "record_consent",
114
+ "require_consent",
115
+ "consent_path",
116
+ "CONSENT_PROMPT",
117
+ "DEFAULT_TIMEOUT_SECONDS",
118
+ # Local model.
119
+ "Classification",
120
+ "WORKLOAD_KINDS",
121
+ "classify",
122
+ "is_available",
123
+ "installed_models",
124
+ "pick_model",
125
+ ]