metergraph-core 0.2.0__tar.gz → 0.2.1__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.
- {metergraph_core-0.2.0/src/metergraph_core.egg-info → metergraph_core-0.2.1}/PKG-INFO +1 -1
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/pyproject.toml +1 -1
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core/catalog.py +29 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core/loader.py +6 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1/src/metergraph_core.egg-info}/PKG-INFO +1 -1
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/MANIFEST.in +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/README.md +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/setup.cfg +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core/__init__.py +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core/billing.py +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core/data/prices.yaml +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core.egg-info/SOURCES.txt +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core.egg-info/dependency_links.txt +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core.egg-info/requires.txt +0 -0
- {metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core.egg-info/top_level.txt +0 -0
|
@@ -69,6 +69,7 @@ class Alias:
|
|
|
69
69
|
canonical_id: str
|
|
70
70
|
pricing_channel: str
|
|
71
71
|
rules: Mapping[str, Any]
|
|
72
|
+
publisher: str | None = None
|
|
72
73
|
|
|
73
74
|
|
|
74
75
|
@dataclass(frozen=True, slots=True)
|
|
@@ -270,6 +271,34 @@ class CatalogSnapshot:
|
|
|
270
271
|
return price
|
|
271
272
|
return None
|
|
272
273
|
|
|
274
|
+
def infer_direct_channel(self, model: Any) -> str | None:
|
|
275
|
+
"""Return the sole direct billing channel known for ``model``.
|
|
276
|
+
|
|
277
|
+
This supports captures that preserve a model identity but omit the
|
|
278
|
+
source provider. It uses the catalog's canonical model publisher and
|
|
279
|
+
returns ``None`` whenever model identity or direct channel is
|
|
280
|
+
ambiguous.
|
|
281
|
+
"""
|
|
282
|
+
if not isinstance(model, str) or not model.strip():
|
|
283
|
+
return None
|
|
284
|
+
model_key = model.strip().lower()
|
|
285
|
+
canonical_ids = {
|
|
286
|
+
alias.canonical_id
|
|
287
|
+
for (known_model, _channel), alias in self._deployment_aliases.items()
|
|
288
|
+
if known_model == model_key
|
|
289
|
+
}
|
|
290
|
+
if len(canonical_ids) != 1:
|
|
291
|
+
return None
|
|
292
|
+
channels: set[str] = set()
|
|
293
|
+
for canonical_id in canonical_ids:
|
|
294
|
+
for alias in self._deployment_aliases.values():
|
|
295
|
+
if alias.canonical_id != canonical_id:
|
|
296
|
+
continue
|
|
297
|
+
channel = direct_channel_for_provider(alias.publisher)
|
|
298
|
+
if channel is not None and (canonical_id, channel) in self._prices:
|
|
299
|
+
channels.add(channel)
|
|
300
|
+
return next(iter(channels)) if len(channels) == 1 else None
|
|
301
|
+
|
|
273
302
|
def resolve_price(
|
|
274
303
|
self, *, model: Any, channel: Any, at: datetime
|
|
275
304
|
) -> ResolvedPrice | None:
|
|
@@ -84,6 +84,10 @@ class LoadedCatalog:
|
|
|
84
84
|
(_normalize_provider(provider), model_id), model_id
|
|
85
85
|
)
|
|
86
86
|
|
|
87
|
+
def infer_direct_channel(self, model: Any) -> str | None:
|
|
88
|
+
"""Infer a direct pricing channel only when the catalog is unambiguous."""
|
|
89
|
+
return self.snapshot.infer_direct_channel(model)
|
|
90
|
+
|
|
87
91
|
def price(
|
|
88
92
|
self,
|
|
89
93
|
*,
|
|
@@ -150,6 +154,7 @@ def parse_catalog(
|
|
|
150
154
|
canonical = str(entry.get("canonical_id") or "")
|
|
151
155
|
if not canonical:
|
|
152
156
|
raise CatalogError("model entry missing canonical_id")
|
|
157
|
+
publisher = str(entry.get("publisher") or "").strip().lower() or None
|
|
153
158
|
for alias in entry.get("aliases") or []:
|
|
154
159
|
provider = str(alias.get("provider") or "").lower()
|
|
155
160
|
name = str(alias.get("alias") or "").lower()
|
|
@@ -167,6 +172,7 @@ def parse_catalog(
|
|
|
167
172
|
canonical_id=canonical,
|
|
168
173
|
pricing_channel=channel,
|
|
169
174
|
rules=_freeze(alias.get("rules") or {}),
|
|
175
|
+
publisher=publisher,
|
|
170
176
|
)
|
|
171
177
|
seen_windows: list[tuple[str, str, datetime, datetime | None]] = []
|
|
172
178
|
for price in entry.get("prices") or []:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{metergraph_core-0.2.0 → metergraph_core-0.2.1}/src/metergraph_core.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|