global: snapshot

This commit is contained in:
nym21
2026-01-12 22:43:56 +01:00
parent b675b70067
commit 5ffb66c0dc
39 changed files with 8207 additions and 11957 deletions
@@ -195,143 +195,138 @@ class _EndpointConfig:
class RangeBuilder(Generic[T]):
"""Final builder with range fully specified. Can only call json() or csv()."""
"""Builder with range specified."""
def __init__(self, config: _EndpointConfig):
self._config = config
def json(self) -> MetricData[T]:
"""Execute the query and return parsed JSON data."""
def fetch(self) -> MetricData[T]:
"""Fetch the range as parsed JSON."""
return self._config.get_json()
def csv(self) -> str:
"""Execute the query and return CSV data as a string."""
def fetch_csv(self) -> str:
"""Fetch the range as CSV string."""
return self._config.get_csv()
class FromBuilder(Generic[T]):
"""Builder after calling from(start). Can chain with take() or to()."""
class SingleItemBuilder(Generic[T]):
"""Builder for single item access."""
def __init__(self, config: _EndpointConfig):
self._config = config
def fetch(self) -> MetricData[T]:
"""Fetch the single item."""
return self._config.get_json()
def fetch_csv(self) -> str:
"""Fetch as CSV."""
return self._config.get_csv()
class SkippedBuilder(Generic[T]):
"""Builder after calling skip(n). Chain with take() to specify count."""
def __init__(self, config: _EndpointConfig):
self._config = config
def take(self, n: int) -> RangeBuilder[T]:
"""Take n items from the start position."""
"""Take n items after the skipped position."""
start = self._config.start or 0
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
start, start + n
))
def to(self, end: int) -> RangeBuilder[T]:
"""Set the end position."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
self._config.start, end
))
def json(self) -> MetricData[T]:
"""Execute the query and return parsed JSON data (from start to end of data)."""
def fetch(self) -> MetricData[T]:
"""Fetch from skipped position to end."""
return self._config.get_json()
def csv(self) -> str:
"""Execute the query and return CSV data as a string."""
return self._config.get_csv()
class ToBuilder(Generic[T]):
"""Builder after calling to(end). Can chain with take_last() or from()."""
def __init__(self, config: _EndpointConfig):
self._config = config
def take_last(self, n: int) -> RangeBuilder[T]:
"""Take last n items before the end position."""
end = self._config.end or 0
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
end - n, end
))
def from_(self, start: int) -> RangeBuilder[T]:
"""Set the start position."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
start, self._config.end
))
def json(self) -> MetricData[T]:
"""Execute the query and return parsed JSON data (from start of data to end)."""
return self._config.get_json()
def csv(self) -> str:
"""Execute the query and return CSV data as a string."""
def fetch_csv(self) -> str:
"""Fetch as CSV."""
return self._config.get_csv()
class MetricEndpointBuilder(Generic[T]):
"""Initial builder for metric endpoint queries.
"""Builder for metric endpoint queries.
Use method chaining to specify the data range, then call json() or csv() to execute.
Use method chaining to specify the data range, then call fetch() or fetch_csv() to execute.
Examples:
# Get all data
endpoint.json()
# Fetch all data
data = endpoint.fetch()
# Get last 10 points
endpoint.last(10).json()
# Single item access
data = endpoint[5].fetch()
# Get range [100, 200)
endpoint.range(100, 200).json()
# Slice syntax (Python-native)
data = endpoint[:10].fetch() # First 10
data = endpoint[-5:].fetch() # Last 5
data = endpoint[100:110].fetch() # Range
# Get 10 points starting from position 100
endpoint.from_(100).take(10).json()
# Convenience methods (pandas-style)
data = endpoint.head().fetch() # First 10 (default)
data = endpoint.head(20).fetch() # First 20
data = endpoint.tail(5).fetch() # Last 5
# Iterator-style chaining
data = endpoint.skip(100).take(10).fetch()
"""
def __init__(self, client: BrkClientBase, name: str, index: Index):
self._config = _EndpointConfig(client, name, index)
def first(self, n: int) -> RangeBuilder[T]:
"""Fetch the first n data points."""
@overload
def __getitem__(self, key: int) -> SingleItemBuilder[T]: ...
@overload
def __getitem__(self, key: slice) -> RangeBuilder[T]: ...
def __getitem__(self, key: Union[int, slice]) -> Union[SingleItemBuilder[T], RangeBuilder[T]]:
"""Access single item or slice.
Examples:
endpoint[5] # Single item at index 5
endpoint[:10] # First 10
endpoint[-5:] # Last 5
endpoint[100:110] # Range 100-109
"""
if isinstance(key, int):
return SingleItemBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
key, key + 1
))
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
key.start, key.stop
))
def head(self, n: int = 10) -> RangeBuilder[T]:
"""Get the first n items (pandas-style)."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
None, n
))
def last(self, n: int) -> RangeBuilder[T]:
"""Fetch the last n data points."""
def tail(self, n: int = 10) -> RangeBuilder[T]:
"""Get the last n items (pandas-style)."""
return RangeBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
-n, None
))
def range(self, start: int, end: int) -> RangeBuilder[T]:
"""Set an explicit range [start, end)."""
return RangeBuilder(_EndpointConfig(
def skip(self, n: int) -> SkippedBuilder[T]:
"""Skip the first n items. Chain with take() to get a range."""
return SkippedBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
start, end
n, None
))
def from_(self, start: int) -> FromBuilder[T]:
"""Set the start position. Chain with take() or to()."""
return FromBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
start, None
))
def to(self, end: int) -> ToBuilder[T]:
"""Set the end position. Chain with take_last() or from_()."""
return ToBuilder(_EndpointConfig(
self._config.client, self._config.name, self._config.index,
None, end
))
def json(self) -> MetricData[T]:
"""Execute the query and return parsed JSON data (all data)."""
def fetch(self) -> MetricData[T]:
"""Fetch all data as parsed JSON."""
return self._config.get_json()
def csv(self) -> str:
"""Execute the query and return CSV data as a string (all data)."""
def fetch_csv(self) -> str:
"""Fetch all data as CSV string."""
return self._config.get_csv()
def path(self) -> str:
@@ -26,7 +26,7 @@ pub fn generate_python_client(
writeln!(output, "# Do not edit manually\n").unwrap();
writeln!(
output,
"from typing import TypeVar, Generic, Any, Optional, List, Literal, TypedDict, Union, Protocol"
"from typing import TypeVar, Generic, Any, Optional, List, Literal, TypedDict, Union, Protocol, overload"
)
.unwrap();
writeln!(output, "from http.client import HTTPSConnection, HTTPConnection").unwrap();
@@ -6,8 +6,8 @@ use std::fmt::Write;
use brk_types::TreeNode;
use crate::{
ClientMetadata, GenericSyntax, PatternField, PythonSyntax, child_type_name, generate_leaf_field,
get_node_fields, get_pattern_instance_base, prepare_tree_node, to_snake_case,
ClientMetadata, GenericSyntax, PatternField, PythonSyntax, generate_leaf_field,
prepare_tree_node, to_snake_case,
};
/// Generate tree classes
@@ -41,22 +41,16 @@ fn generate_tree_class(
// Generate child classes FIRST (post-order traversal)
// This ensures children are defined before parent references them
for (child_name, child_node) in ctx.children.iter() {
if let TreeNode::Branch(grandchildren) = child_node {
let child_fields = get_node_fields(grandchildren, pattern_lookup);
// Generate inline class if no pattern match OR pattern is not parameterizable
if !metadata.is_parameterizable_fields(&child_fields) {
let child_class = child_type_name(name, child_name);
generate_tree_class(
output,
&child_class,
child_node,
pattern_lookup,
metadata,
generated,
);
}
for child in &ctx.children {
if child.should_inline {
generate_tree_class(
output,
&child.inline_type_name,
child.node,
pattern_lookup,
metadata,
generated,
);
}
}
@@ -71,45 +65,36 @@ fn generate_tree_class(
.unwrap();
let syntax = PythonSyntax;
for ((field, child_fields_opt), (child_name, child_node)) in
ctx.fields_with_child_info.iter().zip(ctx.children.iter())
{
let py_type = metadata.resolve_tree_field_type(
field,
child_fields_opt.as_deref(),
name,
child_name,
GenericSyntax::PYTHON,
);
let field_name_py = to_snake_case(&field.name);
for child in &ctx.children {
let field_name_py = to_snake_case(child.name);
if metadata.is_pattern_type(&field.rust_type) && metadata.is_parameterizable(&field.rust_type)
{
// Parameterizable pattern: use pattern class with metric base
let metric_base = get_pattern_instance_base(child_node);
writeln!(
output,
" self.{}: {} = {}(client, '{}')",
field_name_py, py_type, field.rust_type, metric_base
)
.unwrap();
} else if let TreeNode::Leaf(leaf) = child_node {
// Leaf node: use shared helper
generate_leaf_field(output, &syntax, "client", child_name, leaf, metadata, " ");
} else if field.is_branch() {
// Non-parameterizable pattern or regular branch: generate inline class
let inline_class = child_type_name(name, &field.name);
if child.is_leaf {
if let TreeNode::Leaf(leaf) = child.node {
generate_leaf_field(output, &syntax, "client", child.name, leaf, metadata, " ");
}
} else if child.should_inline {
// Inline class
writeln!(
output,
" self.{}: {} = {}(client)",
field_name_py, inline_class, inline_class
field_name_py, child.inline_type_name, child.inline_type_name
)
.unwrap();
} else {
panic!(
"Field '{}' has no matching index pattern. All metrics must be indexed.",
field.name
// Use pattern class with metric base
let py_type = metadata.resolve_tree_field_type(
&child.field,
child.child_fields.as_deref(),
name,
child.name,
GenericSyntax::PYTHON,
);
writeln!(
output,
" self.{}: {} = {}(client, '{}')",
field_name_py, py_type, child.field.rust_type, child.base_result.base
)
.unwrap();
}
}