hammad-python 0.0.30__py3-none-any.whl → 0.0.31__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.
- ham/__init__.py +10 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/METADATA +6 -32
- hammad_python-0.0.31.dist-info/RECORD +6 -0
- hammad/__init__.py +0 -84
- hammad/_internal.py +0 -256
- hammad/_main.py +0 -226
- hammad/cache/__init__.py +0 -40
- hammad/cache/base_cache.py +0 -181
- hammad/cache/cache.py +0 -169
- hammad/cache/decorators.py +0 -261
- hammad/cache/file_cache.py +0 -80
- hammad/cache/ttl_cache.py +0 -74
- hammad/cli/__init__.py +0 -33
- hammad/cli/animations.py +0 -573
- hammad/cli/plugins.py +0 -867
- hammad/cli/styles/__init__.py +0 -55
- hammad/cli/styles/settings.py +0 -139
- hammad/cli/styles/types.py +0 -358
- hammad/cli/styles/utils.py +0 -634
- hammad/data/__init__.py +0 -90
- hammad/data/collections/__init__.py +0 -49
- hammad/data/collections/collection.py +0 -326
- hammad/data/collections/indexes/__init__.py +0 -37
- hammad/data/collections/indexes/qdrant/__init__.py +0 -1
- hammad/data/collections/indexes/qdrant/index.py +0 -723
- hammad/data/collections/indexes/qdrant/settings.py +0 -94
- hammad/data/collections/indexes/qdrant/utils.py +0 -210
- hammad/data/collections/indexes/tantivy/__init__.py +0 -1
- hammad/data/collections/indexes/tantivy/index.py +0 -426
- hammad/data/collections/indexes/tantivy/settings.py +0 -40
- hammad/data/collections/indexes/tantivy/utils.py +0 -176
- hammad/data/configurations/__init__.py +0 -35
- hammad/data/configurations/configuration.py +0 -564
- hammad/data/models/__init__.py +0 -50
- hammad/data/models/extensions/__init__.py +0 -4
- hammad/data/models/extensions/pydantic/__init__.py +0 -42
- hammad/data/models/extensions/pydantic/converters.py +0 -759
- hammad/data/models/fields.py +0 -546
- hammad/data/models/model.py +0 -1078
- hammad/data/models/utils.py +0 -280
- hammad/data/sql/__init__.py +0 -24
- hammad/data/sql/database.py +0 -576
- hammad/data/sql/types.py +0 -127
- hammad/data/types/__init__.py +0 -75
- hammad/data/types/file.py +0 -431
- hammad/data/types/multimodal/__init__.py +0 -36
- hammad/data/types/multimodal/audio.py +0 -200
- hammad/data/types/multimodal/image.py +0 -182
- hammad/data/types/text.py +0 -1308
- hammad/formatting/__init__.py +0 -33
- hammad/formatting/json/__init__.py +0 -27
- hammad/formatting/json/converters.py +0 -158
- hammad/formatting/text/__init__.py +0 -63
- hammad/formatting/text/converters.py +0 -723
- hammad/formatting/text/markdown.py +0 -131
- hammad/formatting/yaml/__init__.py +0 -26
- hammad/formatting/yaml/converters.py +0 -5
- hammad/genai/__init__.py +0 -217
- hammad/genai/a2a/__init__.py +0 -32
- hammad/genai/a2a/workers.py +0 -552
- hammad/genai/agents/__init__.py +0 -59
- hammad/genai/agents/agent.py +0 -1973
- hammad/genai/agents/run.py +0 -1024
- hammad/genai/agents/types/__init__.py +0 -42
- hammad/genai/agents/types/agent_context.py +0 -13
- hammad/genai/agents/types/agent_event.py +0 -128
- hammad/genai/agents/types/agent_hooks.py +0 -220
- hammad/genai/agents/types/agent_messages.py +0 -31
- hammad/genai/agents/types/agent_response.py +0 -125
- hammad/genai/agents/types/agent_stream.py +0 -327
- hammad/genai/graphs/__init__.py +0 -125
- hammad/genai/graphs/_utils.py +0 -190
- hammad/genai/graphs/base.py +0 -1828
- hammad/genai/graphs/plugins.py +0 -316
- hammad/genai/graphs/types.py +0 -638
- hammad/genai/models/__init__.py +0 -1
- hammad/genai/models/embeddings/__init__.py +0 -43
- hammad/genai/models/embeddings/model.py +0 -226
- hammad/genai/models/embeddings/run.py +0 -163
- hammad/genai/models/embeddings/types/__init__.py +0 -37
- hammad/genai/models/embeddings/types/embedding_model_name.py +0 -75
- hammad/genai/models/embeddings/types/embedding_model_response.py +0 -76
- hammad/genai/models/embeddings/types/embedding_model_run_params.py +0 -66
- hammad/genai/models/embeddings/types/embedding_model_settings.py +0 -47
- hammad/genai/models/language/__init__.py +0 -57
- hammad/genai/models/language/model.py +0 -1098
- hammad/genai/models/language/run.py +0 -878
- hammad/genai/models/language/types/__init__.py +0 -40
- hammad/genai/models/language/types/language_model_instructor_mode.py +0 -47
- hammad/genai/models/language/types/language_model_messages.py +0 -28
- hammad/genai/models/language/types/language_model_name.py +0 -239
- hammad/genai/models/language/types/language_model_request.py +0 -127
- hammad/genai/models/language/types/language_model_response.py +0 -217
- hammad/genai/models/language/types/language_model_response_chunk.py +0 -56
- hammad/genai/models/language/types/language_model_settings.py +0 -89
- hammad/genai/models/language/types/language_model_stream.py +0 -600
- hammad/genai/models/language/utils/__init__.py +0 -28
- hammad/genai/models/language/utils/requests.py +0 -421
- hammad/genai/models/language/utils/structured_outputs.py +0 -135
- hammad/genai/models/model_provider.py +0 -4
- hammad/genai/models/multimodal.py +0 -47
- hammad/genai/models/reranking.py +0 -26
- hammad/genai/types/__init__.py +0 -1
- hammad/genai/types/base.py +0 -215
- hammad/genai/types/history.py +0 -290
- hammad/genai/types/tools.py +0 -507
- hammad/logging/__init__.py +0 -35
- hammad/logging/decorators.py +0 -834
- hammad/logging/logger.py +0 -1018
- hammad/mcp/__init__.py +0 -53
- hammad/mcp/client/__init__.py +0 -35
- hammad/mcp/client/client.py +0 -624
- hammad/mcp/client/client_service.py +0 -400
- hammad/mcp/client/settings.py +0 -178
- hammad/mcp/servers/__init__.py +0 -26
- hammad/mcp/servers/launcher.py +0 -1161
- hammad/runtime/__init__.py +0 -32
- hammad/runtime/decorators.py +0 -142
- hammad/runtime/run.py +0 -299
- hammad/service/__init__.py +0 -49
- hammad/service/create.py +0 -527
- hammad/service/decorators.py +0 -283
- hammad/types.py +0 -288
- hammad/typing/__init__.py +0 -435
- hammad/web/__init__.py +0 -43
- hammad/web/http/__init__.py +0 -1
- hammad/web/http/client.py +0 -944
- hammad/web/models.py +0 -275
- hammad/web/openapi/__init__.py +0 -1
- hammad/web/openapi/client.py +0 -740
- hammad/web/search/__init__.py +0 -1
- hammad/web/search/client.py +0 -1023
- hammad/web/utils.py +0 -472
- hammad_python-0.0.30.dist-info/RECORD +0 -135
- {hammad → ham}/py.typed +0 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/WHEEL +0 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/licenses/LICENSE +0 -0
hammad/data/types/text.py
DELETED
@@ -1,1308 +0,0 @@
|
|
1
|
-
"""hammad.types.text
|
2
|
-
|
3
|
-
Contains the `BaseText` type, which is a functional type & object
|
4
|
-
for created intelligently rendered strings and markdown strings
|
5
|
-
from various input types and objects."""
|
6
|
-
|
7
|
-
from __future__ import annotations
|
8
|
-
|
9
|
-
import json
|
10
|
-
from abc import ABC
|
11
|
-
from dataclasses import dataclass, field
|
12
|
-
from enum import Enum
|
13
|
-
from typing import (
|
14
|
-
Any,
|
15
|
-
Dict,
|
16
|
-
List,
|
17
|
-
Literal,
|
18
|
-
Optional,
|
19
|
-
Union,
|
20
|
-
Callable,
|
21
|
-
Type,
|
22
|
-
ClassVar,
|
23
|
-
overload,
|
24
|
-
TypeVar,
|
25
|
-
Generic,
|
26
|
-
)
|
27
|
-
|
28
|
-
from ...formatting.text.markdown import (
|
29
|
-
markdown_heading,
|
30
|
-
markdown_code_block,
|
31
|
-
)
|
32
|
-
from ...formatting.text.converters import convert_to_text
|
33
|
-
|
34
|
-
|
35
|
-
# -----------------------------------------------------------------------------
|
36
|
-
# Enums and Types
|
37
|
-
# -----------------------------------------------------------------------------
|
38
|
-
|
39
|
-
|
40
|
-
class OutputFormat(Enum):
|
41
|
-
"""Supported output formats for text conversion."""
|
42
|
-
|
43
|
-
TEXT = "text"
|
44
|
-
MARKDOWN = "markdown"
|
45
|
-
JSON = "json"
|
46
|
-
TYPE = "type"
|
47
|
-
ANY = "any"
|
48
|
-
|
49
|
-
|
50
|
-
class HeadingStyle(Enum):
|
51
|
-
"""Heading styles for different formats."""
|
52
|
-
|
53
|
-
# Text formats
|
54
|
-
HASH = "#"
|
55
|
-
BRACKET = "[]"
|
56
|
-
ANGLE = "<>"
|
57
|
-
BRACE = "{}"
|
58
|
-
# Markdown specific
|
59
|
-
UNDERLINE = "="
|
60
|
-
|
61
|
-
|
62
|
-
# -----------------------------------------------------------------------------
|
63
|
-
# Base Text Class (Unified Type System)
|
64
|
-
# -----------------------------------------------------------------------------
|
65
|
-
|
66
|
-
|
67
|
-
@dataclass(repr=False, eq=False)
|
68
|
-
class BaseText(ABC):
|
69
|
-
"""
|
70
|
-
Abstract base class for structured text conversion.
|
71
|
-
|
72
|
-
This class provides a unified interface for converting objects
|
73
|
-
to various text formats with extensive customization options.
|
74
|
-
All sections are also BaseText instances, creating a unified type system.
|
75
|
-
"""
|
76
|
-
|
77
|
-
# Class-level configuration
|
78
|
-
DEFAULT_FORMAT: ClassVar[OutputFormat] = OutputFormat.TEXT
|
79
|
-
SUPPORTED_FORMATS: ClassVar[List[OutputFormat]] = [
|
80
|
-
OutputFormat.TEXT,
|
81
|
-
OutputFormat.MARKDOWN,
|
82
|
-
OutputFormat.JSON,
|
83
|
-
OutputFormat.TYPE,
|
84
|
-
OutputFormat.ANY,
|
85
|
-
]
|
86
|
-
|
87
|
-
# Core attributes (both for documents and sections)
|
88
|
-
type: str = "base"
|
89
|
-
"""The type identifier for this text object/section."""
|
90
|
-
|
91
|
-
title: Optional[str] = None
|
92
|
-
"""Title for the document or section."""
|
93
|
-
|
94
|
-
description: Optional[str] = None
|
95
|
-
"""Description for the document or section."""
|
96
|
-
|
97
|
-
content: Optional[Union[str, Any]] = ""
|
98
|
-
"""The main content (for sections)."""
|
99
|
-
|
100
|
-
metadata: Dict[str, Any] = field(default_factory=dict)
|
101
|
-
"""Metadata for the document/section."""
|
102
|
-
|
103
|
-
language: Optional[str] = None
|
104
|
-
"""Programming language for code sections (if applicable)."""
|
105
|
-
|
106
|
-
# Hierarchical structure
|
107
|
-
sections: List[BaseText] = field(default_factory=list)
|
108
|
-
"""Child sections (all are BaseText instances)."""
|
109
|
-
|
110
|
-
# Formatting options
|
111
|
-
heading_level: int = 2
|
112
|
-
"""Heading level (1-6) for this section."""
|
113
|
-
|
114
|
-
show_in_toc: bool = True
|
115
|
-
"""Whether to include in table of contents."""
|
116
|
-
|
117
|
-
collapsible: bool = False
|
118
|
-
"""Whether this section should be collapsible (for supported formats)."""
|
119
|
-
|
120
|
-
format_config: Dict[OutputFormat, Dict[str, Any]] = field(default_factory=dict)
|
121
|
-
"""Format-specific configuration options."""
|
122
|
-
|
123
|
-
def build_sections(self) -> List[BaseText]:
|
124
|
-
"""
|
125
|
-
Build and return the sections for this text object.
|
126
|
-
Default implementation returns existing sections.
|
127
|
-
Subclasses can override to dynamically build sections.
|
128
|
-
"""
|
129
|
-
return self.sections
|
130
|
-
|
131
|
-
def add_section(self, section: BaseText) -> BaseText:
|
132
|
-
"""Add a section to this text object."""
|
133
|
-
self.sections.append(section)
|
134
|
-
return self
|
135
|
-
|
136
|
-
def get_format_config(self, format: OutputFormat) -> Dict[str, Any]:
|
137
|
-
"""Get configuration for a specific format."""
|
138
|
-
default_config = {
|
139
|
-
OutputFormat.TEXT: {
|
140
|
-
"compact": False,
|
141
|
-
"show_types": True,
|
142
|
-
"title_style": "##",
|
143
|
-
"bullet_style": "-",
|
144
|
-
},
|
145
|
-
OutputFormat.MARKDOWN: {
|
146
|
-
"table_format": False,
|
147
|
-
"escape_special_chars": False,
|
148
|
-
"add_toc": False,
|
149
|
-
"add_horizontal_rules": False,
|
150
|
-
},
|
151
|
-
OutputFormat.JSON: {
|
152
|
-
"indent": 2,
|
153
|
-
"sort_keys": False,
|
154
|
-
},
|
155
|
-
OutputFormat.TYPE: {
|
156
|
-
"show_full_path": True,
|
157
|
-
"include_module": True,
|
158
|
-
},
|
159
|
-
OutputFormat.ANY: {
|
160
|
-
"fallback_format": OutputFormat.TEXT,
|
161
|
-
"auto_detect": True,
|
162
|
-
},
|
163
|
-
}
|
164
|
-
|
165
|
-
config = default_config.get(format, {}).copy()
|
166
|
-
config.update(self.format_config.get(format, {}))
|
167
|
-
return config
|
168
|
-
|
169
|
-
def to_format(self, format: OutputFormat = None, **kwargs) -> str:
|
170
|
-
"""
|
171
|
-
Convert to the specified format.
|
172
|
-
|
173
|
-
Args:
|
174
|
-
format: The output format (defaults to DEFAULT_FORMAT)
|
175
|
-
**kwargs: Additional format-specific options
|
176
|
-
|
177
|
-
Returns:
|
178
|
-
Formatted string representation
|
179
|
-
"""
|
180
|
-
if format is None:
|
181
|
-
format = self.DEFAULT_FORMAT
|
182
|
-
|
183
|
-
if format not in self.SUPPORTED_FORMATS:
|
184
|
-
raise ValueError(f"Unsupported format: {format}")
|
185
|
-
|
186
|
-
# Ensure sections are built
|
187
|
-
if not self.sections:
|
188
|
-
self.sections = self.build_sections()
|
189
|
-
|
190
|
-
# Merge configurations
|
191
|
-
config = self.get_format_config(format)
|
192
|
-
config.update(kwargs)
|
193
|
-
|
194
|
-
# Convert based on format
|
195
|
-
if format == OutputFormat.TEXT:
|
196
|
-
return self._to_text(**config)
|
197
|
-
elif format == OutputFormat.MARKDOWN:
|
198
|
-
return self._to_markdown(**config)
|
199
|
-
elif format == OutputFormat.JSON:
|
200
|
-
return self._to_json(**config)
|
201
|
-
elif format == OutputFormat.TYPE:
|
202
|
-
return self._to_type(**config)
|
203
|
-
elif format == OutputFormat.ANY:
|
204
|
-
return self._to_any(**config)
|
205
|
-
else:
|
206
|
-
raise NotImplementedError(f"Format {format} not implemented")
|
207
|
-
|
208
|
-
def _to_text(self, **kwargs) -> str:
|
209
|
-
"""Convert to plain text format."""
|
210
|
-
parts = []
|
211
|
-
|
212
|
-
# Handle title
|
213
|
-
if self.title:
|
214
|
-
title_style = kwargs.get("title_style", "##")
|
215
|
-
if title_style == "#":
|
216
|
-
parts.append("#" * self.heading_level + " " + self.title)
|
217
|
-
elif title_style == "[]":
|
218
|
-
parts.append(f"[{self.title}]")
|
219
|
-
elif title_style == "<>":
|
220
|
-
parts.append(f"<{self.title}>")
|
221
|
-
elif title_style == "{}":
|
222
|
-
parts.append(f"{{{self.title}}}")
|
223
|
-
else:
|
224
|
-
parts.append(self.title)
|
225
|
-
|
226
|
-
# Handle description
|
227
|
-
if self.description:
|
228
|
-
parts.append(self.description)
|
229
|
-
|
230
|
-
# Handle content (for sections)
|
231
|
-
if self.content:
|
232
|
-
if isinstance(self.content, str):
|
233
|
-
parts.append(self.content)
|
234
|
-
else:
|
235
|
-
parts.append(convert_to_text(self.content, **kwargs))
|
236
|
-
|
237
|
-
# Handle subsections
|
238
|
-
for section in self.sections:
|
239
|
-
sub_kwargs = kwargs.copy()
|
240
|
-
sub_kwargs["indent"] = kwargs.get("indent", 0) + 1
|
241
|
-
parts.append(section.to_format(OutputFormat.TEXT, **sub_kwargs))
|
242
|
-
|
243
|
-
return "\n\n".join(filter(None, parts))
|
244
|
-
|
245
|
-
def _to_markdown(self, **kwargs) -> str:
|
246
|
-
"""Convert to Markdown format."""
|
247
|
-
parts = []
|
248
|
-
|
249
|
-
# Handle title
|
250
|
-
if self.title:
|
251
|
-
parts.append(markdown_heading(self.title, self.heading_level))
|
252
|
-
|
253
|
-
# Handle description
|
254
|
-
if self.description:
|
255
|
-
parts.append(self.description)
|
256
|
-
|
257
|
-
# Handle content (for sections)
|
258
|
-
if self.content:
|
259
|
-
if isinstance(self.content, str):
|
260
|
-
parts.append(self.content)
|
261
|
-
else:
|
262
|
-
parts.append(convert_to_text(self.content, **kwargs))
|
263
|
-
|
264
|
-
# Add table of contents if requested (only for top-level documents)
|
265
|
-
if kwargs.get("add_toc", False) and self.heading_level == 1:
|
266
|
-
toc_headings = []
|
267
|
-
for section in self.sections:
|
268
|
-
if section.show_in_toc and section.title:
|
269
|
-
toc_headings.append((section.heading_level, section.title))
|
270
|
-
|
271
|
-
if toc_headings:
|
272
|
-
from ...formatting.text.markdown import markdown_table
|
273
|
-
|
274
|
-
parts.append(markdown_table(toc_headings))
|
275
|
-
|
276
|
-
# Handle subsections
|
277
|
-
for section in self.sections:
|
278
|
-
sub_kwargs = kwargs.copy()
|
279
|
-
sub_kwargs["_indent_level"] = self.heading_level
|
280
|
-
parts.append(section.to_format(OutputFormat.MARKDOWN, **sub_kwargs))
|
281
|
-
|
282
|
-
return "\n\n".join(filter(None, parts))
|
283
|
-
|
284
|
-
def _to_json(self, **kwargs) -> str:
|
285
|
-
"""Convert to JSON format."""
|
286
|
-
data = {
|
287
|
-
"type": self.type,
|
288
|
-
"title": self.title,
|
289
|
-
"description": self.description,
|
290
|
-
"content": self.content,
|
291
|
-
"metadata": self.metadata,
|
292
|
-
"sections": [
|
293
|
-
json.loads(s.to_format(OutputFormat.JSON, **kwargs))
|
294
|
-
for s in self.sections
|
295
|
-
],
|
296
|
-
}
|
297
|
-
|
298
|
-
indent = kwargs.get("indent", 2)
|
299
|
-
sort_keys = kwargs.get("sort_keys", False)
|
300
|
-
|
301
|
-
return json.dumps(data, indent=indent, sort_keys=sort_keys)
|
302
|
-
|
303
|
-
def _to_type(self, **kwargs) -> str:
|
304
|
-
"""Convert to type annotation format."""
|
305
|
-
show_full_path = kwargs.get("show_full_path", True)
|
306
|
-
include_module = kwargs.get("include_module", True)
|
307
|
-
|
308
|
-
type_info = self.__class__.__name__
|
309
|
-
|
310
|
-
if include_module:
|
311
|
-
module = self.__class__.__module__
|
312
|
-
if module != "__main__" and show_full_path:
|
313
|
-
type_info = f"{module}.{type_info}"
|
314
|
-
|
315
|
-
# Include key attributes in the type representation
|
316
|
-
attrs = []
|
317
|
-
if self.type != "base":
|
318
|
-
attrs.append(f"type={self.type!r}")
|
319
|
-
if self.title:
|
320
|
-
attrs.append(f"title={self.title!r}")
|
321
|
-
if self.sections:
|
322
|
-
attrs.append(f"sections={len(self.sections)}")
|
323
|
-
|
324
|
-
if attrs:
|
325
|
-
type_info += f"({', '.join(attrs)})"
|
326
|
-
|
327
|
-
return type_info
|
328
|
-
|
329
|
-
def _to_any(self, **kwargs) -> str:
|
330
|
-
"""Convert using automatic format detection or fallback."""
|
331
|
-
fallback_format = kwargs.get("fallback_format", OutputFormat.TEXT)
|
332
|
-
auto_detect = kwargs.get("auto_detect", True)
|
333
|
-
|
334
|
-
if auto_detect:
|
335
|
-
# Simple heuristics for format detection
|
336
|
-
if self.content and isinstance(self.content, str):
|
337
|
-
content_lower = self.content.lower().strip()
|
338
|
-
|
339
|
-
# Check for JSON content
|
340
|
-
if content_lower.startswith("{") and content_lower.endswith("}"):
|
341
|
-
return self.to_format(OutputFormat.JSON, **kwargs)
|
342
|
-
|
343
|
-
# Check for code content
|
344
|
-
if any(
|
345
|
-
keyword in content_lower
|
346
|
-
for keyword in ["def ", "class ", "import ", "from "]
|
347
|
-
):
|
348
|
-
return self.to_format(OutputFormat.MARKDOWN, **kwargs)
|
349
|
-
|
350
|
-
# Check if this looks like schema documentation
|
351
|
-
if hasattr(self, "output_schema") or self.type in ["schema", "output"]:
|
352
|
-
return self.to_format(OutputFormat.MARKDOWN, **kwargs)
|
353
|
-
|
354
|
-
# Use fallback format
|
355
|
-
return self.to_format(fallback_format, **kwargs)
|
356
|
-
|
357
|
-
def to_dict(self) -> Dict[str, Any]:
|
358
|
-
"""Convert to dictionary representation."""
|
359
|
-
return {
|
360
|
-
"type": self.type,
|
361
|
-
"title": self.title,
|
362
|
-
"description": self.description,
|
363
|
-
"content": self.content,
|
364
|
-
"metadata": self.metadata,
|
365
|
-
"sections": [s.to_dict() for s in self.sections],
|
366
|
-
}
|
367
|
-
|
368
|
-
# Convenience methods
|
369
|
-
def __str__(self) -> str:
|
370
|
-
"""String representation using default format."""
|
371
|
-
return self.to_format()
|
372
|
-
|
373
|
-
def __repr__(self) -> str:
|
374
|
-
"""Developer-friendly representation."""
|
375
|
-
section_count = len(self.sections)
|
376
|
-
section_text = "section" if section_count == 1 else "sections"
|
377
|
-
if section_count > 0:
|
378
|
-
return f"{self.__class__.__name__}(type={self.type!r}, title={self.title!r}, {section_count} {section_text})"
|
379
|
-
else:
|
380
|
-
return f"{self.__class__.__name__}(type={self.type!r}, title={self.title!r}, sections={section_count})"
|
381
|
-
|
382
|
-
@property
|
383
|
-
def text(self) -> str:
|
384
|
-
"""Quick access to text format."""
|
385
|
-
return self.to_format(OutputFormat.TEXT)
|
386
|
-
|
387
|
-
@property
|
388
|
-
def markdown(self) -> str:
|
389
|
-
"""Quick access to markdown format."""
|
390
|
-
return self.to_format(OutputFormat.MARKDOWN)
|
391
|
-
|
392
|
-
@property
|
393
|
-
def json(self) -> str:
|
394
|
-
"""Quick access to JSON format."""
|
395
|
-
return self.to_format(OutputFormat.JSON)
|
396
|
-
|
397
|
-
@property
|
398
|
-
def type_info(self) -> str:
|
399
|
-
"""Quick access to type format."""
|
400
|
-
return self.to_format(OutputFormat.TYPE)
|
401
|
-
|
402
|
-
@property
|
403
|
-
def any_format(self) -> str:
|
404
|
-
"""Quick access to any format (auto-detected)."""
|
405
|
-
return self.to_format(OutputFormat.ANY)
|
406
|
-
|
407
|
-
def __len__(self) -> int:
|
408
|
-
"""Return the length of the content."""
|
409
|
-
if self.content is None:
|
410
|
-
return 0
|
411
|
-
return len(str(self.content))
|
412
|
-
|
413
|
-
def __eq__(self, other) -> bool:
|
414
|
-
"""Check equality based on content."""
|
415
|
-
if not isinstance(other, BaseText):
|
416
|
-
return False
|
417
|
-
return str(self.content or "") == str(other.content or "")
|
418
|
-
|
419
|
-
|
420
|
-
# -----------------------------------------------------------------------------
|
421
|
-
# Specialized Section Classes (Now BaseText Subclasses)
|
422
|
-
# -----------------------------------------------------------------------------
|
423
|
-
|
424
|
-
|
425
|
-
@dataclass(repr=False, eq=False)
|
426
|
-
class CodeSection(BaseText):
|
427
|
-
"""Section specifically for code content."""
|
428
|
-
|
429
|
-
type: str = "code"
|
430
|
-
line_numbers: bool = False
|
431
|
-
highlight_lines: Optional[List[int]] = None
|
432
|
-
|
433
|
-
def _to_markdown(self, **kwargs) -> str:
|
434
|
-
"""Convert to Markdown with code block."""
|
435
|
-
parts = []
|
436
|
-
|
437
|
-
if self.title:
|
438
|
-
parts.append(markdown_heading(self.title, self.heading_level))
|
439
|
-
|
440
|
-
if self.description:
|
441
|
-
parts.append(self.description)
|
442
|
-
|
443
|
-
if self.content:
|
444
|
-
parts.append(markdown_code_block(str(self.content), self.language or ""))
|
445
|
-
|
446
|
-
# Handle subsections
|
447
|
-
for section in self.sections:
|
448
|
-
sub_kwargs = kwargs.copy()
|
449
|
-
sub_kwargs["_indent_level"] = self.heading_level
|
450
|
-
parts.append(section.to_format(OutputFormat.MARKDOWN, **sub_kwargs))
|
451
|
-
|
452
|
-
return "\n\n".join(filter(None, parts))
|
453
|
-
|
454
|
-
|
455
|
-
@dataclass(repr=False, eq=False)
|
456
|
-
class SchemaSection(BaseText):
|
457
|
-
"""Section for schema/model documentation."""
|
458
|
-
|
459
|
-
type: str = "schema"
|
460
|
-
schema_object: Optional[Any] = None
|
461
|
-
show_examples: bool = True
|
462
|
-
table_format: bool = True
|
463
|
-
|
464
|
-
def _to_markdown(self, **kwargs) -> str:
|
465
|
-
"""Convert schema to Markdown documentation."""
|
466
|
-
if self.schema_object:
|
467
|
-
return convert_to_text(
|
468
|
-
self.schema_object,
|
469
|
-
name=self.title,
|
470
|
-
description=self.description,
|
471
|
-
table_format=self.table_format,
|
472
|
-
**kwargs,
|
473
|
-
)
|
474
|
-
return super()._to_markdown(**kwargs)
|
475
|
-
|
476
|
-
|
477
|
-
# -----------------------------------------------------------------------------
|
478
|
-
# Concrete Implementation Classes
|
479
|
-
# -----------------------------------------------------------------------------
|
480
|
-
|
481
|
-
|
482
|
-
@dataclass(repr=False, eq=False)
|
483
|
-
class SimpleText(BaseText):
|
484
|
-
"""Simple concrete implementation of BaseText for basic use cases."""
|
485
|
-
|
486
|
-
type: str = "simple"
|
487
|
-
|
488
|
-
def build_sections(self) -> List[BaseText]:
|
489
|
-
"""Simple text doesn't build sections dynamically."""
|
490
|
-
return self.sections
|
491
|
-
|
492
|
-
|
493
|
-
@dataclass(repr=False, eq=False)
|
494
|
-
class OutputText(BaseText):
|
495
|
-
"""
|
496
|
-
Implementation for structured output documentation.
|
497
|
-
"""
|
498
|
-
|
499
|
-
DEFAULT_FORMAT: ClassVar[OutputFormat] = OutputFormat.MARKDOWN
|
500
|
-
type: str = "output"
|
501
|
-
|
502
|
-
# Specific attributes for output documentation
|
503
|
-
output_schema: Optional[Any] = None
|
504
|
-
"""The schema/model to document."""
|
505
|
-
|
506
|
-
examples: List[Dict[str, Any]] = field(default_factory=list)
|
507
|
-
"""Example outputs."""
|
508
|
-
|
509
|
-
validation_rules: List[str] = field(default_factory=list)
|
510
|
-
"""Validation rules for the output."""
|
511
|
-
|
512
|
-
error_cases: List[Dict[str, str]] = field(default_factory=list)
|
513
|
-
"""Common error cases and messages."""
|
514
|
-
|
515
|
-
def build_sections(self) -> List[BaseText]:
|
516
|
-
"""Build sections for output documentation."""
|
517
|
-
sections = []
|
518
|
-
|
519
|
-
# Schema section
|
520
|
-
if self.output_schema:
|
521
|
-
sections.append(
|
522
|
-
SchemaSection(
|
523
|
-
title="Output Schema",
|
524
|
-
schema_object=self.output_schema,
|
525
|
-
description="The following schema defines the structure of the output:",
|
526
|
-
table_format=True,
|
527
|
-
)
|
528
|
-
)
|
529
|
-
|
530
|
-
# Examples section
|
531
|
-
if self.examples:
|
532
|
-
examples_section = SimpleText(
|
533
|
-
type="examples",
|
534
|
-
title="Examples",
|
535
|
-
description="Here are some example outputs:",
|
536
|
-
)
|
537
|
-
|
538
|
-
for i, example in enumerate(self.examples, 1):
|
539
|
-
examples_section.add_section(
|
540
|
-
CodeSection(
|
541
|
-
title=f"Example {i}",
|
542
|
-
content=json.dumps(example, indent=2),
|
543
|
-
language="json",
|
544
|
-
heading_level=3,
|
545
|
-
)
|
546
|
-
)
|
547
|
-
|
548
|
-
sections.append(examples_section)
|
549
|
-
|
550
|
-
# Validation rules section
|
551
|
-
if self.validation_rules:
|
552
|
-
rules_content = "\n".join(f"- {rule}" for rule in self.validation_rules)
|
553
|
-
sections.append(
|
554
|
-
SimpleText(
|
555
|
-
type="validation",
|
556
|
-
title="Validation Rules",
|
557
|
-
content=rules_content,
|
558
|
-
)
|
559
|
-
)
|
560
|
-
|
561
|
-
# Error cases section
|
562
|
-
if self.error_cases:
|
563
|
-
error_section = SimpleText(
|
564
|
-
type="errors",
|
565
|
-
title="Common Errors",
|
566
|
-
description="The following errors may occur:",
|
567
|
-
)
|
568
|
-
|
569
|
-
for error in self.error_cases:
|
570
|
-
error_content = f"**Error**: {error.get('error', 'Unknown')}\n"
|
571
|
-
error_content += f"**Message**: {error.get('message', 'No message')}\n"
|
572
|
-
if "solution" in error:
|
573
|
-
error_content += f"**Solution**: {error['solution']}"
|
574
|
-
|
575
|
-
error_section.add_section(
|
576
|
-
SimpleText(
|
577
|
-
type="error",
|
578
|
-
title=error.get("code", "ERROR"),
|
579
|
-
content=error_content,
|
580
|
-
heading_level=3,
|
581
|
-
)
|
582
|
-
)
|
583
|
-
|
584
|
-
sections.append(error_section)
|
585
|
-
|
586
|
-
return sections
|
587
|
-
|
588
|
-
@classmethod
|
589
|
-
def from_function(
|
590
|
-
cls, func: Callable, include_examples: bool = True, **kwargs
|
591
|
-
) -> OutputText:
|
592
|
-
"""
|
593
|
-
Create OutputText from a function's return type and docstring.
|
594
|
-
|
595
|
-
Args:
|
596
|
-
func: The function to document
|
597
|
-
include_examples: Whether to parse examples from docstring
|
598
|
-
**kwargs: Additional arguments for OutputText
|
599
|
-
|
600
|
-
Returns:
|
601
|
-
OutputText instance
|
602
|
-
"""
|
603
|
-
from typing import get_type_hints
|
604
|
-
|
605
|
-
# Extract function information
|
606
|
-
func_name = func.__name__
|
607
|
-
hints = get_type_hints(func)
|
608
|
-
return_type = hints.get("return", Any)
|
609
|
-
|
610
|
-
# Create instance
|
611
|
-
output_text = cls(
|
612
|
-
title=kwargs.get("title", f"Output for {func_name}"),
|
613
|
-
description=kwargs.get("description", None),
|
614
|
-
output_schema=return_type,
|
615
|
-
**kwargs,
|
616
|
-
)
|
617
|
-
|
618
|
-
return output_text
|
619
|
-
|
620
|
-
|
621
|
-
# -----------------------------------------------------------------------------
|
622
|
-
# Example Usage
|
623
|
-
# -----------------------------------------------------------------------------
|
624
|
-
|
625
|
-
if __name__ == "__main__":
|
626
|
-
from dataclasses import dataclass
|
627
|
-
from typing import Optional
|
628
|
-
|
629
|
-
# Define a sample schema
|
630
|
-
@dataclass
|
631
|
-
class UserResponse:
|
632
|
-
"""User information response."""
|
633
|
-
|
634
|
-
id: int
|
635
|
-
username: str
|
636
|
-
email: str
|
637
|
-
is_active: bool = True
|
638
|
-
role: Optional[str] = None
|
639
|
-
|
640
|
-
# Create output documentation
|
641
|
-
output_doc = OutputText(
|
642
|
-
title="User API Response",
|
643
|
-
description="Documentation for the user endpoint response format.",
|
644
|
-
output_schema=UserResponse,
|
645
|
-
examples=[
|
646
|
-
{
|
647
|
-
"id": 123,
|
648
|
-
"username": "john_doe",
|
649
|
-
"email": "john@example.com",
|
650
|
-
"is_active": True,
|
651
|
-
"role": "admin",
|
652
|
-
},
|
653
|
-
{
|
654
|
-
"id": 456,
|
655
|
-
"username": "jane_smith",
|
656
|
-
"email": "jane@example.com",
|
657
|
-
"is_active": False,
|
658
|
-
"role": None,
|
659
|
-
},
|
660
|
-
],
|
661
|
-
validation_rules=[
|
662
|
-
"ID must be a positive integer",
|
663
|
-
"Username must be unique and contain only alphanumeric characters and underscores",
|
664
|
-
"Email must be a valid email address",
|
665
|
-
"Role must be one of: admin, user, guest (or null)",
|
666
|
-
],
|
667
|
-
error_cases=[
|
668
|
-
{
|
669
|
-
"code": "USER_NOT_FOUND",
|
670
|
-
"error": "User not found",
|
671
|
-
"message": "The requested user ID does not exist",
|
672
|
-
"solution": "Verify the user ID and try again",
|
673
|
-
},
|
674
|
-
{
|
675
|
-
"code": "INVALID_EMAIL",
|
676
|
-
"error": "Invalid email format",
|
677
|
-
"message": "The provided email address is not valid",
|
678
|
-
"solution": "Ensure the email follows the format: user@domain.com",
|
679
|
-
},
|
680
|
-
],
|
681
|
-
)
|
682
|
-
|
683
|
-
# Get different formats
|
684
|
-
print("=== MARKDOWN FORMAT ===")
|
685
|
-
print(output_doc.markdown)
|
686
|
-
|
687
|
-
print("\n\n=== TEXT FORMAT ===")
|
688
|
-
print(output_doc.text)
|
689
|
-
|
690
|
-
print("\n\n=== JSON FORMAT ===")
|
691
|
-
print(output_doc.json)
|
692
|
-
|
693
|
-
print("\n\n=== TYPE FORMAT ===")
|
694
|
-
print(output_doc.type_info)
|
695
|
-
|
696
|
-
print("\n\n=== ANY FORMAT (auto-detected) ===")
|
697
|
-
print(output_doc.any_format)
|
698
|
-
|
699
|
-
|
700
|
-
# -----------------------------------------------------------------------------
|
701
|
-
# Unified Text Class - Main Entry Point
|
702
|
-
# -----------------------------------------------------------------------------
|
703
|
-
|
704
|
-
T = TypeVar("T")
|
705
|
-
|
706
|
-
|
707
|
-
@dataclass(repr=False, eq=False)
|
708
|
-
class Text(BaseText, Generic[T]):
|
709
|
-
"""
|
710
|
-
Unified Text class - the main entry point for all text operations.
|
711
|
-
|
712
|
-
This class provides a clean, fully-typed interface for creating and managing
|
713
|
-
structured text content with support for multiple output formats.
|
714
|
-
"""
|
715
|
-
|
716
|
-
DEFAULT_FORMAT: ClassVar[OutputFormat] = OutputFormat.MARKDOWN
|
717
|
-
type: str = "text"
|
718
|
-
|
719
|
-
# Enhanced typing for content
|
720
|
-
content: Optional[Union[str, T, Any]] = None
|
721
|
-
|
722
|
-
def __init__(
|
723
|
-
self,
|
724
|
-
content: Optional[Union[str, T, Any]] = None,
|
725
|
-
*,
|
726
|
-
title: Optional[str] = None,
|
727
|
-
description: Optional[str] = None,
|
728
|
-
type: str = "text",
|
729
|
-
format: Optional[OutputFormat] = None,
|
730
|
-
heading_level: int = 1,
|
731
|
-
show_in_toc: bool = True,
|
732
|
-
collapsible: bool = False,
|
733
|
-
metadata: Optional[Dict[str, Any]] = None,
|
734
|
-
sections: Optional[List[BaseText]] = None,
|
735
|
-
format_config: Optional[Dict[OutputFormat, Dict[str, Any]]] = None,
|
736
|
-
**kwargs,
|
737
|
-
) -> None:
|
738
|
-
"""
|
739
|
-
Initialize a Text instance.
|
740
|
-
|
741
|
-
Args:
|
742
|
-
content: The main content (string, object, or any serializable type)
|
743
|
-
title: Optional title for the text
|
744
|
-
description: Optional description
|
745
|
-
type: Type identifier (default: "text")
|
746
|
-
format: Default output format
|
747
|
-
heading_level: Heading level (1-6)
|
748
|
-
show_in_toc: Whether to show in table of contents
|
749
|
-
collapsible: Whether the section should be collapsible
|
750
|
-
metadata: Additional metadata
|
751
|
-
sections: Child sections
|
752
|
-
format_config: Format-specific configuration
|
753
|
-
**kwargs: Additional arguments
|
754
|
-
"""
|
755
|
-
super().__init__(
|
756
|
-
type=type,
|
757
|
-
title=title,
|
758
|
-
description=description,
|
759
|
-
content=content,
|
760
|
-
metadata=metadata or {},
|
761
|
-
sections=sections or [],
|
762
|
-
heading_level=heading_level,
|
763
|
-
show_in_toc=show_in_toc,
|
764
|
-
collapsible=collapsible,
|
765
|
-
format_config=format_config or {},
|
766
|
-
)
|
767
|
-
|
768
|
-
# Set default format if provided
|
769
|
-
if format is not None:
|
770
|
-
self.DEFAULT_FORMAT = format
|
771
|
-
|
772
|
-
@classmethod
|
773
|
-
def from_string(
|
774
|
-
cls,
|
775
|
-
text: str,
|
776
|
-
*,
|
777
|
-
title: Optional[str] = None,
|
778
|
-
format: OutputFormat = OutputFormat.TEXT,
|
779
|
-
**kwargs,
|
780
|
-
) -> "Text[str]":
|
781
|
-
"""Create Text from a simple string."""
|
782
|
-
return cls(content=text, title=title, format=format, **kwargs)
|
783
|
-
|
784
|
-
@classmethod
|
785
|
-
def from_markdown(
|
786
|
-
cls, markdown: str, *, title: Optional[str] = None, **kwargs
|
787
|
-
) -> "Text[str]":
|
788
|
-
"""Create Text from markdown content."""
|
789
|
-
return cls(
|
790
|
-
content=markdown, title=title, format=OutputFormat.MARKDOWN, **kwargs
|
791
|
-
)
|
792
|
-
|
793
|
-
@classmethod
|
794
|
-
def from_object(
|
795
|
-
cls,
|
796
|
-
obj: T,
|
797
|
-
*,
|
798
|
-
title: Optional[str] = None,
|
799
|
-
format: OutputFormat = OutputFormat.MARKDOWN,
|
800
|
-
**kwargs,
|
801
|
-
) -> "Text[T]":
|
802
|
-
"""Create Text from any object."""
|
803
|
-
return cls(
|
804
|
-
content=obj,
|
805
|
-
title=title or f"{type(obj).__name__} Documentation",
|
806
|
-
format=format,
|
807
|
-
**kwargs,
|
808
|
-
)
|
809
|
-
|
810
|
-
@classmethod
|
811
|
-
def from_schema(
|
812
|
-
cls,
|
813
|
-
schema: Type[T],
|
814
|
-
*,
|
815
|
-
title: Optional[str] = None,
|
816
|
-
examples: Optional[List[Dict[str, Any]]] = None,
|
817
|
-
**kwargs,
|
818
|
-
) -> "Text[Type[T]]":
|
819
|
-
"""Create Text from a schema/dataclass type."""
|
820
|
-
output_text = OutputText(
|
821
|
-
title=title or f"{schema.__name__} Schema",
|
822
|
-
output_schema=schema,
|
823
|
-
examples=examples or [],
|
824
|
-
**kwargs,
|
825
|
-
)
|
826
|
-
return cls(
|
827
|
-
content=output_text,
|
828
|
-
title=output_text.title,
|
829
|
-
format=OutputFormat.MARKDOWN,
|
830
|
-
type="schema",
|
831
|
-
)
|
832
|
-
|
833
|
-
@classmethod
|
834
|
-
def from_function(
|
835
|
-
cls,
|
836
|
-
func: Callable[..., T],
|
837
|
-
*,
|
838
|
-
title: Optional[str] = None,
|
839
|
-
include_examples: bool = True,
|
840
|
-
**kwargs,
|
841
|
-
) -> "Text[Callable[..., T]]":
|
842
|
-
"""Create Text from a function's documentation."""
|
843
|
-
output_text = OutputText.from_function(
|
844
|
-
func, title=title, include_examples=include_examples, **kwargs
|
845
|
-
)
|
846
|
-
return cls(
|
847
|
-
content=output_text,
|
848
|
-
title=output_text.title,
|
849
|
-
format=OutputFormat.MARKDOWN,
|
850
|
-
type="function",
|
851
|
-
)
|
852
|
-
|
853
|
-
def add_code_section(
|
854
|
-
self,
|
855
|
-
code: str,
|
856
|
-
*,
|
857
|
-
language: str = "python",
|
858
|
-
title: Optional[str] = None,
|
859
|
-
description: Optional[str] = None,
|
860
|
-
line_numbers: bool = False,
|
861
|
-
**kwargs,
|
862
|
-
) -> "Text[T]":
|
863
|
-
"""Add a code section to this text."""
|
864
|
-
code_section = CodeSection(
|
865
|
-
content=code,
|
866
|
-
language=language,
|
867
|
-
title=title,
|
868
|
-
description=description,
|
869
|
-
line_numbers=line_numbers,
|
870
|
-
heading_level=self.heading_level + 1,
|
871
|
-
**kwargs,
|
872
|
-
)
|
873
|
-
self.add_section(code_section)
|
874
|
-
return self
|
875
|
-
|
876
|
-
def add_text_section(
|
877
|
-
self,
|
878
|
-
content: Union[str, Any],
|
879
|
-
*,
|
880
|
-
title: Optional[str] = None,
|
881
|
-
description: Optional[str] = None,
|
882
|
-
**kwargs,
|
883
|
-
) -> "Text[T]":
|
884
|
-
"""Add a text section to this text."""
|
885
|
-
text_section = SimpleText(
|
886
|
-
content=content,
|
887
|
-
title=title,
|
888
|
-
description=description,
|
889
|
-
heading_level=self.heading_level + 1,
|
890
|
-
**kwargs,
|
891
|
-
)
|
892
|
-
self.add_section(text_section)
|
893
|
-
return self
|
894
|
-
|
895
|
-
def add_schema_section(
|
896
|
-
self,
|
897
|
-
schema: Any,
|
898
|
-
*,
|
899
|
-
title: Optional[str] = None,
|
900
|
-
description: Optional[str] = None,
|
901
|
-
table_format: bool = True,
|
902
|
-
**kwargs,
|
903
|
-
) -> "Text[T]":
|
904
|
-
"""Add a schema documentation section."""
|
905
|
-
schema_section = SchemaSection(
|
906
|
-
schema_object=schema,
|
907
|
-
title=title,
|
908
|
-
description=description,
|
909
|
-
table_format=table_format,
|
910
|
-
heading_level=self.heading_level + 1,
|
911
|
-
**kwargs,
|
912
|
-
)
|
913
|
-
self.add_section(schema_section)
|
914
|
-
return self
|
915
|
-
|
916
|
-
@overload
|
917
|
-
def render(self, format: Literal[OutputFormat.TEXT]) -> str: ...
|
918
|
-
|
919
|
-
@overload
|
920
|
-
def render(self, format: Literal[OutputFormat.MARKDOWN]) -> str: ...
|
921
|
-
|
922
|
-
@overload
|
923
|
-
def render(self, format: Literal[OutputFormat.JSON]) -> str: ...
|
924
|
-
|
925
|
-
@overload
|
926
|
-
def render(self, format: Literal[OutputFormat.TYPE]) -> str: ...
|
927
|
-
|
928
|
-
@overload
|
929
|
-
def render(self, format: Literal[OutputFormat.ANY]) -> str: ...
|
930
|
-
|
931
|
-
def render(self, format: Optional[OutputFormat] = None, **kwargs) -> str:
|
932
|
-
"""
|
933
|
-
Render the text in the specified format.
|
934
|
-
|
935
|
-
Args:
|
936
|
-
format: Output format (uses DEFAULT_FORMAT if None)
|
937
|
-
**kwargs: Format-specific options
|
938
|
-
|
939
|
-
Returns:
|
940
|
-
Formatted string representation
|
941
|
-
"""
|
942
|
-
return self.to_format(format, **kwargs)
|
943
|
-
|
944
|
-
def save(
|
945
|
-
self,
|
946
|
-
filepath: str,
|
947
|
-
*,
|
948
|
-
format: Optional[OutputFormat] = None,
|
949
|
-
encoding: str = "utf-8",
|
950
|
-
**kwargs,
|
951
|
-
) -> None:
|
952
|
-
"""
|
953
|
-
Save the text to a file.
|
954
|
-
|
955
|
-
Args:
|
956
|
-
filepath: Path to save the file
|
957
|
-
format: Output format (auto-detected from extension if None)
|
958
|
-
encoding: File encoding
|
959
|
-
**kwargs: Format-specific options
|
960
|
-
"""
|
961
|
-
import os
|
962
|
-
|
963
|
-
# Auto-detect format from file extension if not provided
|
964
|
-
if format is None:
|
965
|
-
ext = os.path.splitext(filepath)[1].lower()
|
966
|
-
format_map = {
|
967
|
-
".md": OutputFormat.MARKDOWN,
|
968
|
-
".markdown": OutputFormat.MARKDOWN,
|
969
|
-
".json": OutputFormat.JSON,
|
970
|
-
".txt": OutputFormat.TEXT,
|
971
|
-
".text": OutputFormat.TEXT,
|
972
|
-
}
|
973
|
-
format = format_map.get(ext, self.DEFAULT_FORMAT)
|
974
|
-
|
975
|
-
# Render content
|
976
|
-
content = self.render(format, **kwargs)
|
977
|
-
|
978
|
-
# Write to file
|
979
|
-
with open(filepath, "w", encoding=encoding) as f:
|
980
|
-
f.write(content)
|
981
|
-
|
982
|
-
def chain(self, other: "Text") -> "Text[T]":
|
983
|
-
"""Chain another Text instance as a section."""
|
984
|
-
self.add_section(other)
|
985
|
-
return self
|
986
|
-
|
987
|
-
def __add__(self, other: Union["Text", str, BaseText]) -> "Text[T]":
|
988
|
-
"""Add operator for chaining texts."""
|
989
|
-
if isinstance(other, str):
|
990
|
-
return self.add_text_section(other)
|
991
|
-
elif isinstance(other, BaseText):
|
992
|
-
return self.add_section(other)
|
993
|
-
else:
|
994
|
-
raise TypeError(f"Cannot add {type(other)} to Text")
|
995
|
-
|
996
|
-
def __or__(self, format: OutputFormat) -> str:
|
997
|
-
"""Pipe operator for format conversion."""
|
998
|
-
return self.render(format)
|
999
|
-
|
1000
|
-
def __getitem__(self, key: Union[int, str]) -> BaseText:
|
1001
|
-
"""Access sections by index or title."""
|
1002
|
-
if isinstance(key, int):
|
1003
|
-
return self.sections[key]
|
1004
|
-
elif isinstance(key, str):
|
1005
|
-
for section in self.sections:
|
1006
|
-
if section.title == key:
|
1007
|
-
return section
|
1008
|
-
raise KeyError(f"Section with title '{key}' not found")
|
1009
|
-
else:
|
1010
|
-
raise TypeError(f"Invalid key type: {type(key)}")
|
1011
|
-
|
1012
|
-
def __len__(self) -> int:
|
1013
|
-
"""Return total character count of all sections."""
|
1014
|
-
if not self.sections:
|
1015
|
-
return 0
|
1016
|
-
total_length = 0
|
1017
|
-
for section in self.sections:
|
1018
|
-
total_length += len(section)
|
1019
|
-
# Add separators between sections (2 chars for \n\n)
|
1020
|
-
return total_length + (len(self.sections) - 1) * 2
|
1021
|
-
|
1022
|
-
def __iter__(self):
|
1023
|
-
"""Iterate over sections."""
|
1024
|
-
return iter(self.sections)
|
1025
|
-
|
1026
|
-
def __bool__(self) -> bool:
|
1027
|
-
"""Check if text has content or sections."""
|
1028
|
-
return bool(self.content or self.sections or self.title)
|
1029
|
-
|
1030
|
-
# Enhanced property access with type hints
|
1031
|
-
@property
|
1032
|
-
def text(self) -> str:
|
1033
|
-
"""Get text format representation."""
|
1034
|
-
return self.render(OutputFormat.TEXT)
|
1035
|
-
|
1036
|
-
@property
|
1037
|
-
def markdown(self) -> str:
|
1038
|
-
"""Get markdown format representation."""
|
1039
|
-
return self.render(OutputFormat.MARKDOWN)
|
1040
|
-
|
1041
|
-
@property
|
1042
|
-
def json(self) -> str:
|
1043
|
-
"""Get JSON format representation."""
|
1044
|
-
return self.render(OutputFormat.JSON)
|
1045
|
-
|
1046
|
-
@property
|
1047
|
-
def type_info(self) -> str:
|
1048
|
-
"""Get type format representation."""
|
1049
|
-
return self.render(OutputFormat.TYPE)
|
1050
|
-
|
1051
|
-
@property
|
1052
|
-
def auto(self) -> str:
|
1053
|
-
"""Get auto-detected format representation."""
|
1054
|
-
return self.render(OutputFormat.ANY)
|
1055
|
-
|
1056
|
-
|
1057
|
-
def convert_to_simple_text(
|
1058
|
-
obj: Any,
|
1059
|
-
*,
|
1060
|
-
title: Optional[str] = None,
|
1061
|
-
description: Optional[str] = None,
|
1062
|
-
type: str = "simple",
|
1063
|
-
heading_level: int = 2,
|
1064
|
-
show_in_toc: bool = True,
|
1065
|
-
collapsible: bool = False,
|
1066
|
-
metadata: Optional[Dict[str, Any]] = None,
|
1067
|
-
sections: Optional[List["BaseText"]] = None,
|
1068
|
-
format_config: Optional[Dict["OutputFormat", Dict[str, Any]]] = None,
|
1069
|
-
**kwargs,
|
1070
|
-
) -> "SimpleText":
|
1071
|
-
"""Convert any object to a SimpleText instance (fully parameterized)."""
|
1072
|
-
content = convert_to_text(obj)
|
1073
|
-
return SimpleText(
|
1074
|
-
content=content,
|
1075
|
-
title=title,
|
1076
|
-
description=description,
|
1077
|
-
type=type,
|
1078
|
-
heading_level=heading_level,
|
1079
|
-
show_in_toc=show_in_toc,
|
1080
|
-
collapsible=collapsible,
|
1081
|
-
metadata=metadata or {},
|
1082
|
-
sections=sections or [],
|
1083
|
-
format_config=format_config or {},
|
1084
|
-
**kwargs,
|
1085
|
-
)
|
1086
|
-
|
1087
|
-
|
1088
|
-
def convert_to_output_text(
|
1089
|
-
obj: Any,
|
1090
|
-
*,
|
1091
|
-
title: Optional[str] = None,
|
1092
|
-
description: Optional[str] = None,
|
1093
|
-
type: str = "output",
|
1094
|
-
heading_level: int = 2,
|
1095
|
-
show_in_toc: bool = True,
|
1096
|
-
collapsible: bool = False,
|
1097
|
-
metadata: Optional[Dict[str, Any]] = None,
|
1098
|
-
sections: Optional[List["BaseText"]] = None,
|
1099
|
-
format_config: Optional[Dict["OutputFormat", Dict[str, Any]]] = None,
|
1100
|
-
output_schema: Optional[Any] = None,
|
1101
|
-
examples: Optional[List[Any]] = None,
|
1102
|
-
validation_rules: Optional[List[str]] = None,
|
1103
|
-
error_cases: Optional[List[Dict[str, Any]]] = None,
|
1104
|
-
**kwargs,
|
1105
|
-
) -> "OutputText":
|
1106
|
-
"""Convert any object to an OutputText instance (fully parameterized)."""
|
1107
|
-
content = convert_to_text(obj)
|
1108
|
-
return OutputText(
|
1109
|
-
content=content,
|
1110
|
-
title=title,
|
1111
|
-
description=description,
|
1112
|
-
type=type,
|
1113
|
-
heading_level=heading_level,
|
1114
|
-
show_in_toc=show_in_toc,
|
1115
|
-
collapsible=collapsible,
|
1116
|
-
metadata=metadata or {},
|
1117
|
-
sections=sections or [],
|
1118
|
-
format_config=format_config or {},
|
1119
|
-
output_schema=output_schema,
|
1120
|
-
examples=examples or [],
|
1121
|
-
validation_rules=validation_rules or [],
|
1122
|
-
error_cases=error_cases or [],
|
1123
|
-
**kwargs,
|
1124
|
-
)
|
1125
|
-
|
1126
|
-
|
1127
|
-
def convert_to_output_instructions(
|
1128
|
-
obj: Any,
|
1129
|
-
*,
|
1130
|
-
title: Optional[str] = None,
|
1131
|
-
description: Optional[str] = None,
|
1132
|
-
type: str = "output",
|
1133
|
-
heading_level: int = 2,
|
1134
|
-
show_in_toc: bool = True,
|
1135
|
-
collapsible: bool = False,
|
1136
|
-
metadata: Optional[Dict[str, Any]] = None,
|
1137
|
-
sections: Optional[List["BaseText"]] = None,
|
1138
|
-
format_config: Optional[Dict["OutputFormat", Dict[str, Any]]] = None,
|
1139
|
-
output_schema: Optional[Any] = None,
|
1140
|
-
examples: Optional[List[Any]] = None,
|
1141
|
-
validation_rules: Optional[List[str]] = None,
|
1142
|
-
error_cases: Optional[List[Dict[str, Any]]] = None,
|
1143
|
-
as_message: bool = False,
|
1144
|
-
role: str = "user",
|
1145
|
-
as_message_content: bool = False,
|
1146
|
-
**kwargs,
|
1147
|
-
) -> Union[str, Dict[str, Any]]:
|
1148
|
-
"""
|
1149
|
-
Convert any object to output instructions, returning either:
|
1150
|
-
- a string (default)
|
1151
|
-
- a chat message dict (if as_message=True)
|
1152
|
-
- a chat message content param dict (if as_message_content=True)
|
1153
|
-
|
1154
|
-
Only one of as_message or as_message_content can be True.
|
1155
|
-
"""
|
1156
|
-
if as_message and as_message_content:
|
1157
|
-
raise ValueError("Only one of as_message or as_message_content can be True.")
|
1158
|
-
|
1159
|
-
content = convert_to_text(obj)
|
1160
|
-
output_text = OutputText(
|
1161
|
-
content=content,
|
1162
|
-
title=title,
|
1163
|
-
description=description,
|
1164
|
-
type=type,
|
1165
|
-
heading_level=heading_level,
|
1166
|
-
show_in_toc=show_in_toc,
|
1167
|
-
collapsible=collapsible,
|
1168
|
-
metadata=metadata or {},
|
1169
|
-
sections=sections or [],
|
1170
|
-
format_config=format_config or {},
|
1171
|
-
output_schema=output_schema,
|
1172
|
-
examples=examples or [],
|
1173
|
-
validation_rules=validation_rules or [],
|
1174
|
-
error_cases=error_cases or [],
|
1175
|
-
**kwargs,
|
1176
|
-
)
|
1177
|
-
text_str = str(output_text)
|
1178
|
-
|
1179
|
-
if as_message:
|
1180
|
-
# Return a chat message dict
|
1181
|
-
return {"role": role, "content": text_str}
|
1182
|
-
elif as_message_content:
|
1183
|
-
# Return a chat message content param dict
|
1184
|
-
return {"type": "text", "text": text_str}
|
1185
|
-
else:
|
1186
|
-
# Return as plain string
|
1187
|
-
return text_str
|
1188
|
-
|
1189
|
-
|
1190
|
-
def convert_to_code_section(
|
1191
|
-
obj: Any,
|
1192
|
-
*,
|
1193
|
-
language: str = "python",
|
1194
|
-
title: Optional[str] = None,
|
1195
|
-
description: Optional[str] = None,
|
1196
|
-
type: str = "code",
|
1197
|
-
heading_level: int = 2,
|
1198
|
-
show_in_toc: bool = True,
|
1199
|
-
collapsible: bool = False,
|
1200
|
-
metadata: Optional[Dict[str, Any]] = None,
|
1201
|
-
sections: Optional[List["BaseText"]] = None,
|
1202
|
-
format_config: Optional[Dict["OutputFormat", Dict[str, Any]]] = None,
|
1203
|
-
line_numbers: bool = False,
|
1204
|
-
**kwargs,
|
1205
|
-
) -> "CodeSection":
|
1206
|
-
"""Convert any object to a CodeSection instance (fully parameterized)."""
|
1207
|
-
content = convert_to_text(obj)
|
1208
|
-
return CodeSection(
|
1209
|
-
content=content,
|
1210
|
-
language=language,
|
1211
|
-
title=title,
|
1212
|
-
description=description,
|
1213
|
-
type=type,
|
1214
|
-
heading_level=heading_level,
|
1215
|
-
show_in_toc=show_in_toc,
|
1216
|
-
collapsible=collapsible,
|
1217
|
-
metadata=metadata or {},
|
1218
|
-
sections=sections or [],
|
1219
|
-
format_config=format_config or {},
|
1220
|
-
line_numbers=line_numbers,
|
1221
|
-
**kwargs,
|
1222
|
-
)
|
1223
|
-
|
1224
|
-
|
1225
|
-
def convert_to_schema_section(
|
1226
|
-
obj: Any,
|
1227
|
-
*,
|
1228
|
-
title: Optional[str] = None,
|
1229
|
-
description: Optional[str] = None,
|
1230
|
-
type: str = "schema",
|
1231
|
-
heading_level: int = 2,
|
1232
|
-
show_in_toc: bool = True,
|
1233
|
-
collapsible: bool = False,
|
1234
|
-
metadata: Optional[Dict[str, Any]] = None,
|
1235
|
-
sections: Optional[List["BaseText"]] = None,
|
1236
|
-
format_config: Optional[Dict["OutputFormat", Dict[str, Any]]] = None,
|
1237
|
-
schema_object: Optional[Any] = None,
|
1238
|
-
show_examples: bool = True,
|
1239
|
-
table_format: bool = True,
|
1240
|
-
**kwargs,
|
1241
|
-
) -> "SchemaSection":
|
1242
|
-
"""Convert any object to a SchemaSection instance (fully parameterized)."""
|
1243
|
-
content = convert_to_text(obj)
|
1244
|
-
return SchemaSection(
|
1245
|
-
content=content,
|
1246
|
-
title=title,
|
1247
|
-
description=description,
|
1248
|
-
type=type,
|
1249
|
-
heading_level=heading_level,
|
1250
|
-
show_in_toc=show_in_toc,
|
1251
|
-
collapsible=collapsible,
|
1252
|
-
metadata=metadata or {},
|
1253
|
-
sections=sections or [],
|
1254
|
-
format_config=format_config or {},
|
1255
|
-
schema_object=schema_object or obj,
|
1256
|
-
show_examples=show_examples,
|
1257
|
-
table_format=table_format,
|
1258
|
-
**kwargs,
|
1259
|
-
)
|
1260
|
-
|
1261
|
-
|
1262
|
-
def convert_to_base_text(
|
1263
|
-
obj: Any,
|
1264
|
-
*,
|
1265
|
-
title: Optional[str] = None,
|
1266
|
-
description: Optional[str] = None,
|
1267
|
-
type: str = "base",
|
1268
|
-
heading_level: int = 2,
|
1269
|
-
show_in_toc: bool = True,
|
1270
|
-
collapsible: bool = False,
|
1271
|
-
metadata: Optional[Dict[str, Any]] = None,
|
1272
|
-
sections: Optional[List["BaseText"]] = None,
|
1273
|
-
format_config: Optional[Dict["OutputFormat", Dict[str, Any]]] = None,
|
1274
|
-
**kwargs,
|
1275
|
-
) -> "BaseText":
|
1276
|
-
"""Convert any object to a BaseText instance (fully parameterized)."""
|
1277
|
-
content = convert_to_text(obj)
|
1278
|
-
return BaseText(
|
1279
|
-
content=content,
|
1280
|
-
title=title,
|
1281
|
-
description=description,
|
1282
|
-
type=type,
|
1283
|
-
heading_level=heading_level,
|
1284
|
-
show_in_toc=show_in_toc,
|
1285
|
-
collapsible=collapsible,
|
1286
|
-
metadata=metadata or {},
|
1287
|
-
sections=sections or [],
|
1288
|
-
format_config=format_config or {},
|
1289
|
-
**kwargs,
|
1290
|
-
)
|
1291
|
-
|
1292
|
-
|
1293
|
-
__all__ = (
|
1294
|
-
"OutputFormat",
|
1295
|
-
"HeadingStyle",
|
1296
|
-
"BaseText",
|
1297
|
-
"CodeSection",
|
1298
|
-
"SchemaSection",
|
1299
|
-
"SimpleText",
|
1300
|
-
"OutputText",
|
1301
|
-
"Text",
|
1302
|
-
"convert_to_simple_text",
|
1303
|
-
"convert_to_output_text",
|
1304
|
-
"convert_to_output_instructions",
|
1305
|
-
"convert_to_code_section",
|
1306
|
-
"convert_to_schema_section",
|
1307
|
-
"convert_to_base_text",
|
1308
|
-
)
|