ommlds 0.0.0.dev480__py3-none-any.whl → 0.0.0.dev503__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 (277) hide show
  1. ommlds/.omlish-manifests.json +100 -33
  2. ommlds/README.md +11 -0
  3. ommlds/__about__.py +9 -6
  4. ommlds/backends/anthropic/protocol/__init__.py +13 -1
  5. ommlds/backends/anthropic/protocol/_dataclasses.py +1625 -0
  6. ommlds/backends/anthropic/protocol/sse/events.py +2 -0
  7. ommlds/backends/cerebras/__init__.py +7 -0
  8. ommlds/backends/cerebras/_dataclasses.py +4254 -0
  9. ommlds/backends/cerebras/_marshal.py +24 -0
  10. ommlds/backends/cerebras/protocol.py +312 -0
  11. ommlds/backends/google/protocol/__init__.py +13 -0
  12. ommlds/backends/google/protocol/_dataclasses.py +5997 -0
  13. ommlds/backends/groq/__init__.py +7 -0
  14. ommlds/backends/groq/_dataclasses.py +3901 -0
  15. ommlds/backends/groq/clients.py +9 -0
  16. ommlds/backends/llamacpp/logging.py +4 -1
  17. ommlds/backends/mlx/caching.py +7 -3
  18. ommlds/backends/mlx/cli.py +10 -7
  19. ommlds/backends/mlx/generation.py +18 -16
  20. ommlds/backends/mlx/limits.py +10 -6
  21. ommlds/backends/mlx/loading.py +7 -4
  22. ommlds/backends/ollama/__init__.py +7 -0
  23. ommlds/backends/ollama/_dataclasses.py +3488 -0
  24. ommlds/backends/ollama/protocol.py +3 -0
  25. ommlds/backends/openai/protocol/__init__.py +15 -1
  26. ommlds/backends/openai/protocol/_dataclasses.py +7708 -0
  27. ommlds/backends/tavily/__init__.py +7 -0
  28. ommlds/backends/tavily/_dataclasses.py +1734 -0
  29. ommlds/backends/transformers/__init__.py +14 -0
  30. ommlds/cli/__init__.py +7 -0
  31. ommlds/cli/_dataclasses.py +3515 -0
  32. ommlds/cli/backends/catalog.py +0 -5
  33. ommlds/cli/backends/inject.py +70 -7
  34. ommlds/cli/backends/meta.py +82 -0
  35. ommlds/cli/content/messages.py +1 -1
  36. ommlds/cli/inject.py +11 -3
  37. ommlds/cli/main.py +137 -68
  38. ommlds/cli/rendering/types.py +6 -0
  39. ommlds/cli/secrets.py +2 -1
  40. ommlds/cli/sessions/base.py +1 -10
  41. ommlds/cli/sessions/chat/configs.py +9 -17
  42. ommlds/cli/sessions/chat/{chat → drivers}/ai/configs.py +3 -1
  43. ommlds/cli/sessions/chat/drivers/ai/events.py +57 -0
  44. ommlds/cli/sessions/chat/{chat → drivers}/ai/inject.py +10 -3
  45. ommlds/cli/sessions/chat/{chat → drivers}/ai/rendering.py +1 -1
  46. ommlds/cli/sessions/chat/{chat → drivers}/ai/services.py +1 -1
  47. ommlds/cli/sessions/chat/{chat → drivers}/ai/tools.py +4 -8
  48. ommlds/cli/sessions/chat/{chat → drivers}/ai/types.py +9 -0
  49. ommlds/cli/sessions/chat/drivers/configs.py +25 -0
  50. ommlds/cli/sessions/chat/drivers/events/inject.py +27 -0
  51. ommlds/cli/sessions/chat/drivers/events/injection.py +14 -0
  52. ommlds/cli/sessions/chat/drivers/events/manager.py +16 -0
  53. ommlds/cli/sessions/chat/drivers/events/types.py +38 -0
  54. ommlds/cli/sessions/chat/drivers/impl.py +50 -0
  55. ommlds/cli/sessions/chat/drivers/inject.py +70 -0
  56. ommlds/cli/sessions/chat/{chat → drivers}/state/configs.py +2 -0
  57. ommlds/cli/sessions/chat/drivers/state/ids.py +25 -0
  58. ommlds/cli/sessions/chat/drivers/state/inject.py +83 -0
  59. ommlds/cli/sessions/chat/{chat → drivers}/state/inmemory.py +0 -4
  60. ommlds/cli/sessions/chat/{chat → drivers}/state/storage.py +17 -10
  61. ommlds/cli/sessions/chat/{chat → drivers}/state/types.py +10 -5
  62. ommlds/cli/sessions/chat/{tools → drivers/tools}/configs.py +2 -2
  63. ommlds/cli/sessions/chat/drivers/tools/confirmation.py +44 -0
  64. ommlds/cli/sessions/chat/drivers/tools/errorhandling.py +39 -0
  65. ommlds/cli/sessions/chat/{tools → drivers/tools}/execution.py +3 -4
  66. ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/inject.py +3 -3
  67. ommlds/cli/sessions/chat/{tools → drivers/tools}/inject.py +7 -12
  68. ommlds/cli/sessions/chat/{tools → drivers/tools}/injection.py +5 -5
  69. ommlds/cli/sessions/chat/{tools → drivers/tools}/rendering.py +3 -3
  70. ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/inject.py +3 -3
  71. ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/tools.py +1 -1
  72. ommlds/cli/sessions/chat/drivers/types.py +31 -0
  73. ommlds/cli/sessions/chat/{chat → drivers}/user/configs.py +0 -3
  74. ommlds/cli/sessions/chat/drivers/user/inject.py +41 -0
  75. ommlds/cli/sessions/chat/facades/__init__.py +0 -0
  76. ommlds/cli/sessions/chat/facades/commands/__init__.py +0 -0
  77. ommlds/cli/sessions/chat/facades/commands/base.py +83 -0
  78. ommlds/cli/sessions/chat/facades/commands/configs.py +9 -0
  79. ommlds/cli/sessions/chat/facades/commands/inject.py +41 -0
  80. ommlds/cli/sessions/chat/facades/commands/injection.py +15 -0
  81. ommlds/cli/sessions/chat/facades/commands/manager.py +59 -0
  82. ommlds/cli/sessions/chat/facades/commands/simple.py +34 -0
  83. ommlds/cli/sessions/chat/facades/commands/types.py +13 -0
  84. ommlds/cli/sessions/chat/facades/configs.py +11 -0
  85. ommlds/cli/sessions/chat/facades/facade.py +26 -0
  86. ommlds/cli/sessions/chat/facades/inject.py +35 -0
  87. ommlds/cli/sessions/chat/facades/ui.py +34 -0
  88. ommlds/cli/sessions/chat/inject.py +8 -31
  89. ommlds/cli/sessions/chat/interfaces/__init__.py +0 -0
  90. ommlds/cli/sessions/chat/interfaces/bare/__init__.py +0 -0
  91. ommlds/cli/sessions/chat/interfaces/bare/configs.py +15 -0
  92. ommlds/cli/sessions/chat/interfaces/bare/inject.py +69 -0
  93. ommlds/cli/sessions/chat/interfaces/bare/interactive.py +49 -0
  94. ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +21 -0
  95. ommlds/cli/sessions/chat/{tools/confirmation.py → interfaces/bare/tools.py} +3 -22
  96. ommlds/cli/sessions/chat/interfaces/base.py +13 -0
  97. ommlds/cli/sessions/chat/interfaces/configs.py +11 -0
  98. ommlds/cli/sessions/chat/interfaces/inject.py +29 -0
  99. ommlds/cli/sessions/chat/interfaces/textual/__init__.py +0 -0
  100. ommlds/cli/sessions/chat/interfaces/textual/app.py +310 -0
  101. ommlds/cli/sessions/chat/interfaces/textual/configs.py +11 -0
  102. ommlds/cli/sessions/chat/interfaces/textual/facades.py +19 -0
  103. ommlds/cli/sessions/chat/interfaces/textual/inject.py +97 -0
  104. ommlds/cli/sessions/chat/interfaces/textual/interface.py +24 -0
  105. ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +29 -0
  106. ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +53 -0
  107. ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss +7 -0
  108. ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +157 -0
  109. ommlds/cli/sessions/chat/interfaces/textual/tools.py +38 -0
  110. ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py +0 -0
  111. ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py +36 -0
  112. ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py +197 -0
  113. ommlds/cli/sessions/chat/session.py +8 -13
  114. ommlds/cli/sessions/completion/configs.py +3 -4
  115. ommlds/cli/sessions/completion/inject.py +1 -2
  116. ommlds/cli/sessions/completion/session.py +4 -8
  117. ommlds/cli/sessions/configs.py +10 -0
  118. ommlds/cli/sessions/embedding/configs.py +3 -4
  119. ommlds/cli/sessions/embedding/inject.py +1 -2
  120. ommlds/cli/sessions/embedding/session.py +4 -8
  121. ommlds/cli/sessions/inject.py +15 -15
  122. ommlds/cli/state/storage.py +7 -1
  123. ommlds/minichain/__init__.py +161 -38
  124. ommlds/minichain/_dataclasses.py +20452 -0
  125. ommlds/minichain/_typedvalues.py +11 -4
  126. ommlds/minichain/backends/impls/anthropic/names.py +3 -3
  127. ommlds/minichain/backends/impls/anthropic/protocol.py +2 -2
  128. ommlds/minichain/backends/impls/anthropic/stream.py +1 -1
  129. ommlds/minichain/backends/impls/cerebras/__init__.py +0 -0
  130. ommlds/minichain/backends/impls/cerebras/chat.py +80 -0
  131. ommlds/minichain/backends/impls/cerebras/names.py +45 -0
  132. ommlds/minichain/backends/impls/cerebras/protocol.py +143 -0
  133. ommlds/minichain/backends/impls/cerebras/stream.py +125 -0
  134. ommlds/minichain/backends/impls/duckduckgo/search.py +5 -1
  135. ommlds/minichain/backends/impls/google/names.py +6 -0
  136. ommlds/minichain/backends/impls/google/stream.py +1 -1
  137. ommlds/minichain/backends/impls/google/tools.py +2 -2
  138. ommlds/minichain/backends/impls/groq/chat.py +2 -0
  139. ommlds/minichain/backends/impls/groq/protocol.py +2 -2
  140. ommlds/minichain/backends/impls/groq/stream.py +3 -1
  141. ommlds/minichain/backends/impls/huggingface/repos.py +1 -5
  142. ommlds/minichain/backends/impls/llamacpp/chat.py +6 -3
  143. ommlds/minichain/backends/impls/llamacpp/completion.py +7 -3
  144. ommlds/minichain/backends/impls/llamacpp/stream.py +6 -3
  145. ommlds/minichain/backends/impls/mlx/chat.py +6 -3
  146. ommlds/minichain/backends/impls/ollama/chat.py +51 -57
  147. ommlds/minichain/backends/impls/ollama/protocol.py +144 -0
  148. ommlds/minichain/backends/impls/openai/format.py +4 -3
  149. ommlds/minichain/backends/impls/openai/names.py +3 -1
  150. ommlds/minichain/backends/impls/openai/stream.py +33 -1
  151. ommlds/minichain/backends/impls/sentencepiece/tokens.py +9 -6
  152. ommlds/minichain/backends/impls/tinygrad/chat.py +7 -4
  153. ommlds/minichain/backends/impls/tokenizers/tokens.py +9 -6
  154. ommlds/minichain/backends/impls/transformers/sentence.py +5 -2
  155. ommlds/minichain/backends/impls/transformers/tokens.py +9 -6
  156. ommlds/minichain/backends/impls/transformers/transformers.py +10 -8
  157. ommlds/minichain/backends/strings/resolving.py +1 -1
  158. ommlds/minichain/chat/content.py +42 -0
  159. ommlds/minichain/chat/messages.py +43 -39
  160. ommlds/minichain/chat/stream/joining.py +36 -12
  161. ommlds/minichain/chat/stream/types.py +1 -1
  162. ommlds/minichain/chat/templating.py +3 -3
  163. ommlds/minichain/content/__init__.py +19 -3
  164. ommlds/minichain/content/_marshal.py +181 -55
  165. ommlds/minichain/content/code.py +26 -0
  166. ommlds/minichain/content/composite.py +28 -0
  167. ommlds/minichain/content/content.py +27 -0
  168. ommlds/minichain/content/dynamic.py +12 -0
  169. ommlds/minichain/content/emphasis.py +27 -0
  170. ommlds/minichain/content/images.py +2 -2
  171. ommlds/minichain/content/json.py +2 -2
  172. ommlds/minichain/content/link.py +13 -0
  173. ommlds/minichain/content/markdown.py +12 -0
  174. ommlds/minichain/content/metadata.py +10 -0
  175. ommlds/minichain/content/namespaces.py +8 -0
  176. ommlds/minichain/content/placeholders.py +10 -9
  177. ommlds/minichain/content/quote.py +26 -0
  178. ommlds/minichain/content/raw.py +49 -0
  179. ommlds/minichain/content/recursive.py +12 -0
  180. ommlds/minichain/content/section.py +26 -0
  181. ommlds/minichain/content/sequence.py +17 -3
  182. ommlds/minichain/content/standard.py +32 -0
  183. ommlds/minichain/content/tag.py +28 -0
  184. ommlds/minichain/content/templates.py +13 -0
  185. ommlds/minichain/content/text.py +2 -2
  186. ommlds/minichain/content/transform/__init__.py +0 -0
  187. ommlds/minichain/content/transform/json.py +55 -0
  188. ommlds/minichain/content/transform/markdown.py +8 -0
  189. ommlds/minichain/content/transform/materialize.py +51 -0
  190. ommlds/minichain/content/transform/metadata.py +16 -0
  191. ommlds/minichain/content/{prepare.py → transform/prepare.py} +10 -15
  192. ommlds/minichain/content/transform/recursive.py +97 -0
  193. ommlds/minichain/content/transform/standard.py +43 -0
  194. ommlds/minichain/content/{transforms → transform}/stringify.py +1 -7
  195. ommlds/minichain/content/transform/strings.py +33 -0
  196. ommlds/minichain/content/transform/templates.py +25 -0
  197. ommlds/minichain/content/visitors.py +231 -0
  198. ommlds/minichain/lib/fs/tools/read.py +1 -1
  199. ommlds/minichain/lib/fs/tools/recursivels/rendering.py +1 -1
  200. ommlds/minichain/lib/fs/tools/recursivels/running.py +1 -1
  201. ommlds/minichain/lib/todo/tools/write.py +2 -1
  202. ommlds/minichain/lib/todo/types.py +1 -1
  203. ommlds/minichain/metadata.py +56 -2
  204. ommlds/minichain/resources.py +22 -1
  205. ommlds/minichain/services/README.md +154 -0
  206. ommlds/minichain/services/__init__.py +6 -2
  207. ommlds/minichain/services/_marshal.py +46 -10
  208. ommlds/minichain/services/_origclasses.py +11 -0
  209. ommlds/minichain/services/_typedvalues.py +8 -3
  210. ommlds/minichain/services/requests.py +73 -3
  211. ommlds/minichain/services/responses.py +73 -3
  212. ommlds/minichain/services/services.py +9 -0
  213. ommlds/minichain/stream/services.py +24 -1
  214. ommlds/minichain/text/applypatch.py +2 -1
  215. ommlds/minichain/text/toolparsing/llamacpp/types.py +1 -1
  216. ommlds/minichain/tokens/specials.py +1 -1
  217. ommlds/minichain/tools/execution/catalog.py +1 -1
  218. ommlds/minichain/tools/execution/errorhandling.py +36 -0
  219. ommlds/minichain/tools/execution/errors.py +2 -2
  220. ommlds/minichain/tools/execution/executors.py +1 -1
  221. ommlds/minichain/tools/fns.py +1 -1
  222. ommlds/minichain/tools/jsonschema.py +2 -2
  223. ommlds/minichain/tools/reflect.py +6 -6
  224. ommlds/minichain/tools/types.py +12 -15
  225. ommlds/minichain/vectors/_marshal.py +1 -1
  226. ommlds/minichain/vectors/embeddings.py +1 -1
  227. ommlds/minichain/wrappers/__init__.py +7 -0
  228. ommlds/minichain/wrappers/firstinwins.py +144 -0
  229. ommlds/minichain/wrappers/instrument.py +146 -0
  230. ommlds/minichain/wrappers/retry.py +168 -0
  231. ommlds/minichain/wrappers/services.py +98 -0
  232. ommlds/minichain/wrappers/stream.py +57 -0
  233. ommlds/nanochat/rustbpe/README.md +9 -0
  234. ommlds/nanochat/tokenizers.py +40 -6
  235. ommlds/specs/mcp/clients.py +146 -0
  236. ommlds/specs/mcp/protocol.py +123 -18
  237. ommlds/tools/git.py +82 -65
  238. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/METADATA +13 -11
  239. ommlds-0.0.0.dev503.dist-info/RECORD +520 -0
  240. ommlds/cli/sessions/chat/chat/state/inject.py +0 -36
  241. ommlds/cli/sessions/chat/chat/user/inject.py +0 -62
  242. ommlds/cli/sessions/chat/chat/user/interactive.py +0 -31
  243. ommlds/cli/sessions/chat/chat/user/oneshot.py +0 -25
  244. ommlds/cli/sessions/chat/chat/user/types.py +0 -15
  245. ommlds/cli/sessions/chat/driver.py +0 -43
  246. ommlds/minichain/content/materialize.py +0 -196
  247. ommlds/minichain/content/simple.py +0 -47
  248. ommlds/minichain/content/transforms/base.py +0 -46
  249. ommlds/minichain/content/transforms/interleave.py +0 -70
  250. ommlds/minichain/content/transforms/squeeze.py +0 -72
  251. ommlds/minichain/content/transforms/strings.py +0 -24
  252. ommlds/minichain/content/types.py +0 -43
  253. ommlds/minichain/stream/wrap.py +0 -62
  254. ommlds-0.0.0.dev480.dist-info/RECORD +0 -427
  255. /ommlds/cli/sessions/chat/{chat → drivers}/__init__.py +0 -0
  256. /ommlds/cli/sessions/chat/{chat → drivers}/ai/__init__.py +0 -0
  257. /ommlds/cli/sessions/chat/{chat → drivers}/ai/injection.py +0 -0
  258. /ommlds/cli/sessions/chat/{chat/state → drivers/events}/__init__.py +0 -0
  259. /ommlds/cli/sessions/chat/{chat/user → drivers/phases}/__init__.py +0 -0
  260. /ommlds/cli/sessions/chat/{phases → drivers/phases}/inject.py +0 -0
  261. /ommlds/cli/sessions/chat/{phases → drivers/phases}/injection.py +0 -0
  262. /ommlds/cli/sessions/chat/{phases → drivers/phases}/manager.py +0 -0
  263. /ommlds/cli/sessions/chat/{phases → drivers/phases}/types.py +0 -0
  264. /ommlds/cli/sessions/chat/{phases → drivers/state}/__init__.py +0 -0
  265. /ommlds/cli/sessions/chat/{tools → drivers/tools}/__init__.py +0 -0
  266. /ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/__init__.py +0 -0
  267. /ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/configs.py +0 -0
  268. /ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/__init__.py +0 -0
  269. /ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/configs.py +0 -0
  270. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/__init__.py +0 -0
  271. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/configs.py +0 -0
  272. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/inject.py +0 -0
  273. /ommlds/{minichain/content/transforms → cli/sessions/chat/drivers/user}/__init__.py +0 -0
  274. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/WHEEL +0 -0
  275. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/entry_points.txt +0 -0
  276. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/licenses/LICENSE +0 -0
  277. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,26 @@
1
+ import typing as ta
2
+
3
+ from omlish import check
4
+ from omlish import dataclasses as dc
5
+ from omlish import lang
6
+
7
+ from .composite import CompositeContent
8
+ from .content import Content
9
+
10
+
11
+ ##
12
+
13
+
14
+ @dc.dataclass(frozen=True)
15
+ class SectionContent(CompositeContent, lang.Final):
16
+ body: Content
17
+
18
+ _: dc.KW_ONLY
19
+
20
+ header: str | None
21
+
22
+ def child_content(self) -> ta.Sequence[Content]:
23
+ return [self.body]
24
+
25
+ def _replace_child_content(self, new_child_content: ta.Sequence[Content]) -> ta.Self:
26
+ return self.replace(body=check.single(new_child_content))
@@ -1,5 +1,6 @@
1
1
  """
2
2
  TODO:
3
+ - ... does inline have *any* separator? generic whitespace when content is stripped?
3
4
  - track BlockContent nesting depth?
4
5
  - section names? dedicated 'section' content with header and body?
5
6
  """
@@ -8,17 +9,23 @@ import typing as ta
8
9
  from omlish import dataclasses as dc
9
10
  from omlish import lang
10
11
 
11
- from .simple import SimpleExtendedContent
12
- from .types import Content
12
+ from .composite import CompositeContent
13
+ from .content import Content
13
14
 
14
15
 
15
16
  ##
16
17
 
17
18
 
18
19
  @dc.dataclass(frozen=True)
19
- class SequenceContent(SimpleExtendedContent, lang.Abstract):
20
+ class SequenceContent(CompositeContent, lang.Abstract):
20
21
  l: ta.Sequence[Content]
21
22
 
23
+ def child_content(self) -> ta.Sequence[Content]:
24
+ return self.l
25
+
26
+ def _replace_child_content(self, new_child_content: ta.Sequence[Content]) -> ta.Self:
27
+ return self.replace(l=new_child_content)
28
+
22
29
 
23
30
  @dc.dataclass(frozen=True)
24
31
  class InlineContent(SequenceContent, lang.Final):
@@ -28,3 +35,10 @@ class InlineContent(SequenceContent, lang.Final):
28
35
  @dc.dataclass(frozen=True)
29
36
  class BlockContent(SequenceContent, lang.Final):
30
37
  pass
38
+
39
+
40
+ @dc.dataclass(frozen=True)
41
+ class ItemListContent(SequenceContent, lang.Final):
42
+ _: dc.KW_ONLY
43
+
44
+ style: ta.Literal['-', '#'] = '-'
@@ -0,0 +1,32 @@
1
+ import typing as ta
2
+
3
+ from omlish import dataclasses as dc
4
+ from omlish import lang
5
+
6
+ from ..metadata import MetadataContainerDataclass
7
+ from .content import BaseContent
8
+ from .metadata import ContentMetadatas
9
+ from .metadata import ContentOriginal
10
+
11
+
12
+ ##
13
+
14
+
15
+ @dc.dataclass(frozen=True)
16
+ class StandardContent( # noqa
17
+ MetadataContainerDataclass[ContentMetadatas],
18
+ BaseContent,
19
+ lang.Abstract,
20
+ ):
21
+ _metadata: ta.Sequence[ContentMetadatas] = dc.field(
22
+ default=(),
23
+ kw_only=True,
24
+ repr=False,
25
+ )
26
+
27
+ MetadataContainerDataclass._configure_metadata_field(_metadata, ContentMetadatas) # noqa
28
+
29
+ def replace(self, **kwargs: ta.Any) -> ta.Self:
30
+ if (n := dc.replace_is_not(self, **kwargs)) is self:
31
+ return self
32
+ return n.with_metadata(ContentOriginal(self), discard=[ContentOriginal], override=True)
@@ -0,0 +1,28 @@
1
+ """
2
+ TODO:
3
+ - track BlockContent nesting depth?
4
+ - section names? dedicated 'section' content with header and body?
5
+ """
6
+ import typing as ta
7
+
8
+ from omlish import check
9
+ from omlish import dataclasses as dc
10
+ from omlish import lang
11
+
12
+ from .composite import CompositeContent
13
+ from .content import Content
14
+
15
+
16
+ ##
17
+
18
+
19
+ @dc.dataclass(frozen=True)
20
+ class TagContent(CompositeContent, lang.Final):
21
+ tag: str
22
+ body: Content
23
+
24
+ def child_content(self) -> ta.Sequence[Content]:
25
+ return [self.body]
26
+
27
+ def _replace_child_content(self, new_child_content: ta.Sequence[Content]) -> ta.Self:
28
+ return self.replace(body=check.single(new_child_content))
@@ -0,0 +1,13 @@
1
+ from omlish import dataclasses as dc
2
+ from omlish import lang
3
+ from omlish.text import templating as tpl
4
+
5
+ from .dynamic import DynamicContent
6
+
7
+
8
+ ##
9
+
10
+
11
+ @dc.dataclass(frozen=True)
12
+ class TemplateContent(DynamicContent, lang.Final):
13
+ t: tpl.Templater
@@ -1,12 +1,12 @@
1
1
  from omlish import dataclasses as dc
2
2
  from omlish import lang
3
3
 
4
- from .simple import SimpleSingleExtendedContent
4
+ from .standard import StandardContent
5
5
 
6
6
 
7
7
  ##
8
8
 
9
9
 
10
10
  @dc.dataclass(frozen=True)
11
- class TextContent(SimpleSingleExtendedContent, lang.Final):
11
+ class TextContent(StandardContent, lang.Final):
12
12
  s: str
File without changes
@@ -0,0 +1,55 @@
1
+ import typing as ta
2
+
3
+ from omlish.formats import json
4
+
5
+ from ..code import BlockCodeContent
6
+ from ..code import InlineCodeContent
7
+ from ..json import JsonContent
8
+ from ..metadata import ContentOriginal
9
+ from ..standard import StandardContent
10
+ from ..text import TextContent
11
+ from ..visitors import ContentTransform
12
+
13
+
14
+ ##
15
+
16
+
17
+ class JsonContentRenderer(ContentTransform[None]):
18
+ def __init__(
19
+ self,
20
+ *,
21
+ backend: json.Backend | None = None,
22
+ mode: ta.Literal['pretty', 'compact', 'normal'] = 'pretty',
23
+ code: ta.Literal['inline', 'block', None] = None,
24
+ ) -> None:
25
+ super().__init__()
26
+
27
+ if backend is None:
28
+ backend = json.default_backend()
29
+ self._backend = backend
30
+ self._mode = mode
31
+ self._code = code
32
+
33
+ def visit_json_content(self, c: JsonContent, ctx: None) -> StandardContent:
34
+ match self._mode:
35
+ case 'pretty':
36
+ s = self._backend.dumps_pretty(c.v)
37
+ case 'compact':
38
+ s = self._backend.dumps_compact(c.v)
39
+ case 'normal':
40
+ s = self._backend.dumps(c.v)
41
+ case _:
42
+ raise ValueError(self._mode)
43
+
44
+ nc: StandardContent
45
+ match self._code:
46
+ case 'inline':
47
+ nc = InlineCodeContent(s, lang='json')
48
+ case 'block':
49
+ nc = BlockCodeContent(s, lang='json')
50
+ case None:
51
+ nc = TextContent(s)
52
+ case _:
53
+ raise ValueError(self._code)
54
+
55
+ return nc.with_metadata(ContentOriginal(c))
@@ -0,0 +1,8 @@
1
+ # from .base import ContentTransform
2
+ #
3
+ #
4
+ # ##
5
+ #
6
+ #
7
+ # class MarkdownContentTransform(ContentTransform):
8
+ # def apply(self, ):
@@ -0,0 +1,51 @@
1
+ import abc
2
+
3
+ from omlish import lang
4
+ from omlish.text import templating as tpl
5
+
6
+ from ..content import Content
7
+ from .recursive import PlaceholderContents
8
+ from .recursive import RecursiveContentMaterializer
9
+ from .templates import TemplateContentMaterializer
10
+
11
+
12
+ ##
13
+
14
+
15
+ class ContentMaterializer(lang.Abstract):
16
+ @abc.abstractmethod
17
+ def apply(self, c: Content) -> Content:
18
+ raise NotImplementedError
19
+
20
+
21
+ ##
22
+
23
+
24
+ class DefaultContentMaterializer(ContentMaterializer):
25
+ def __init__(
26
+ self,
27
+ *,
28
+ placeholder_contents: PlaceholderContents | None = None,
29
+ templater_context: tpl.Templater.Context | None = None,
30
+ ) -> None:
31
+ super().__init__()
32
+
33
+ self._placeholder_contents = placeholder_contents
34
+ self._templater_context = templater_context
35
+
36
+ def apply(self, c: Content) -> Content:
37
+ c = RecursiveContentMaterializer(self._placeholder_contents).visit(c, None)
38
+ c = TemplateContentMaterializer(self._templater_context).visit(c, None)
39
+ return c
40
+
41
+
42
+ def materialize_content(
43
+ c: Content,
44
+ *,
45
+ placeholder_contents: PlaceholderContents | None = None,
46
+ templater_context: tpl.Templater.Context | None = None,
47
+ ) -> Content:
48
+ return DefaultContentMaterializer(
49
+ placeholder_contents=placeholder_contents,
50
+ templater_context=templater_context,
51
+ ).apply(c)
@@ -0,0 +1,16 @@
1
+ from ..content import Content
2
+ from ..metadata import ContentOriginal
3
+ from ..standard import StandardContent
4
+ from ..visitors import ContentTransform
5
+
6
+
7
+ ##
8
+
9
+
10
+ class OriginalMetadataStrippingContentTransform(ContentTransform[None]):
11
+ def visit_standard_content(self, c: StandardContent, ctx: None) -> StandardContent:
12
+ return c.with_metadata(discard=[ContentOriginal])
13
+
14
+
15
+ def strip_content_original_metadata(c: Content) -> Content:
16
+ return OriginalMetadataStrippingContentTransform().visit(c, None)
@@ -1,19 +1,16 @@
1
1
  """
2
2
  TODO:
3
- - re-softwrap
3
+ - re-docwrap
4
4
  """
5
5
  import abc
6
- import dataclasses as dc
7
6
  import typing as ta
8
7
 
8
+ from omlish import dataclasses as dc
9
9
  from omlish import lang
10
10
 
11
- from .materialize import CanContent
11
+ from ..content import Content
12
12
  from .materialize import materialize_content
13
- from .transforms.interleave import interleave_content
14
- from .transforms.squeeze import squeeze_content
15
- from .transforms.stringify import stringify_content
16
- from .types import Content
13
+ from .stringify import stringify_content
17
14
 
18
15
 
19
16
  ##
@@ -21,13 +18,13 @@ from .types import Content
21
18
 
22
19
  class ContentPreparer(lang.Abstract):
23
20
  @abc.abstractmethod
24
- def prepare(self, c: CanContent) -> Content:
21
+ def prepare(self, c: Content) -> Content:
25
22
  raise NotImplementedError
26
23
 
27
24
 
28
25
  class ContentStrPreparer(lang.Abstract):
29
26
  @abc.abstractmethod
30
- def prepare_str(self, c: CanContent) -> str:
27
+ def prepare_str(self, c: Content) -> str:
31
28
  raise NotImplementedError
32
29
 
33
30
 
@@ -44,10 +41,8 @@ class DefaultContentPreparer(ContentPreparer):
44
41
  strip_strings: bool = True
45
42
  block_separator: Content = DEFAULT_BLOCK_SEPARATOR
46
43
 
47
- def prepare(self, c: CanContent) -> Content:
44
+ def prepare(self, c: Content) -> Content:
48
45
  c = materialize_content(c)
49
- c = squeeze_content(c, strip_strings=self.strip_strings)
50
- c = interleave_content(c, block_separator=self.block_separator)
51
46
  return c
52
47
 
53
48
 
@@ -55,7 +50,7 @@ class DefaultContentPreparer(ContentPreparer):
55
50
  class DefaultContentStrPreparer(ContentStrPreparer):
56
51
  content_preparer: ContentPreparer
57
52
 
58
- def prepare_str(self, c: CanContent) -> str:
53
+ def prepare_str(self, c: Content) -> str:
59
54
  return stringify_content(self.content_preparer.prepare(c))
60
55
 
61
56
 
@@ -70,9 +65,9 @@ def default_content_str_preparer(**kwargs: ta.Any) -> ContentStrPreparer:
70
65
  return DefaultContentStrPreparer(DefaultContentPreparer(**kwargs))
71
66
 
72
67
 
73
- def prepare_content(c: CanContent, **kwargs: ta.Any) -> Content:
68
+ def prepare_content(c: Content, **kwargs: ta.Any) -> Content:
74
69
  return default_content_preparer(**kwargs).prepare(c)
75
70
 
76
71
 
77
- def prepare_content_str(c: CanContent, **kwargs: ta.Any) -> str:
72
+ def prepare_content_str(c: Content, **kwargs: ta.Any) -> str:
78
73
  return default_content_str_preparer(**kwargs).prepare_str(c)
@@ -0,0 +1,97 @@
1
+ import typing as ta
2
+
3
+ from omlish import check
4
+ from omlish import dataclasses as dc
5
+
6
+ from ..content import Content
7
+ from ..namespaces import ContentNamespace
8
+ from ..namespaces import NamespaceContent
9
+ from ..placeholders import PlaceholderContent
10
+ from ..placeholders import PlaceholderContentKey
11
+ from ..recursive import RecursiveContent
12
+ from ..visitors import ContentTransform
13
+
14
+
15
+ ##
16
+
17
+
18
+ PlaceholderContentMap: ta.TypeAlias = ta.Mapping[PlaceholderContentKey, Content]
19
+ PlaceholderContentFn: ta.TypeAlias = ta.Callable[[PlaceholderContentKey], Content]
20
+ PlaceholderContents: ta.TypeAlias = PlaceholderContentMap | PlaceholderContentFn
21
+
22
+
23
+ @dc.dataclass()
24
+ class PlaceholderContentMissingError(Exception):
25
+ key: PlaceholderContentKey
26
+
27
+
28
+ def _make_placeholder_content_fn(cps: PlaceholderContents | None = None) -> PlaceholderContentFn:
29
+ if cps is None:
30
+ def none_fn(cpk: PlaceholderContentKey) -> Content:
31
+ raise PlaceholderContentMissingError(cpk)
32
+
33
+ return none_fn
34
+
35
+ elif isinstance(cps, ta.Mapping):
36
+ def mapping_fn(cpk: PlaceholderContentKey) -> Content:
37
+ try:
38
+ return cps[cpk]
39
+ except KeyError:
40
+ raise PlaceholderContentMissingError(cpk) from None
41
+
42
+ return mapping_fn
43
+
44
+ elif callable(cps):
45
+ return cps
46
+
47
+ else:
48
+ raise TypeError(cps)
49
+
50
+
51
+ ##
52
+
53
+
54
+ class RecursiveContentDepthExceededError(Exception):
55
+ pass
56
+
57
+
58
+ class RecursiveContentMaterializer(ContentTransform[None]):
59
+ DEFAULT_MAX_DEPTH: int = 8
60
+
61
+ def __init__(
62
+ self,
63
+ placeholder_contents: PlaceholderContents | None = None,
64
+ *,
65
+ max_depth: int = DEFAULT_MAX_DEPTH,
66
+ ) -> None:
67
+ super().__init__()
68
+
69
+ self._placeholder_content_fn = _make_placeholder_content_fn(placeholder_contents)
70
+ self._max_depth = max_depth
71
+
72
+ self._cur_depth = 0
73
+
74
+ def recurse(self, o: Content, ctx: None) -> Content:
75
+ if self._cur_depth >= self._max_depth:
76
+ raise RecursiveContentDepthExceededError
77
+
78
+ self._cur_depth += 1
79
+ try:
80
+ return self.visit(o, ctx)
81
+ finally:
82
+ self._cur_depth -= 1
83
+
84
+ def visit_recursive_content(self, c: RecursiveContent, ctx: None) -> Content:
85
+ raise TypeError(c)
86
+
87
+ def visit_namespace_content(self, c: NamespaceContent, ctx: None) -> Content:
88
+ check.issubclass(c.ns, ContentNamespace)
89
+ out: list[Content] = []
90
+ for n, e in c.ns:
91
+ if n.startswith('_'):
92
+ continue
93
+ out.append(self.recurse(e, ctx))
94
+ return out
95
+
96
+ def visit_placeholder_content(self, c: PlaceholderContent, ctx: None) -> Content:
97
+ return self.recurse(self._placeholder_content_fn(c.k), ctx)
@@ -0,0 +1,43 @@
1
+ import collections.abc
2
+ import typing as ta
3
+
4
+ from omlish import check
5
+
6
+ from ..content import Content
7
+ from ..metadata import ContentOriginal
8
+ from ..sequence import BlockContent
9
+ from ..sequence import InlineContent
10
+ from ..sequence import SequenceContent
11
+ from ..text import TextContent
12
+ from ..visitors import ContentTransform
13
+
14
+
15
+ ##
16
+
17
+
18
+ class LiftToStandardContentTransform(ContentTransform[None]):
19
+ def __init__(
20
+ self,
21
+ *,
22
+ sequence_mode: ta.Literal['block', 'inline'] = 'block',
23
+ ) -> None:
24
+ super().__init__()
25
+
26
+ self._sequence_mode = sequence_mode
27
+
28
+ def visit_str(self, s: str, ctx: None) -> Content:
29
+ return TextContent(s).with_metadata(ContentOriginal(s))
30
+
31
+ def visit_sequence(self, c: ta.Sequence[Content], ctx: None) -> Content:
32
+ cc = check.isinstance(super().visit_sequence(c, ctx), collections.abc.Sequence)
33
+
34
+ nc: SequenceContent
35
+ match self._sequence_mode:
36
+ case 'block':
37
+ nc = BlockContent(cc)
38
+ case 'inline':
39
+ nc = InlineContent(cc)
40
+ case _:
41
+ raise ValueError(self._sequence_mode)
42
+
43
+ return nc.with_metadata(ContentOriginal(c))
@@ -3,9 +3,8 @@ import typing as ta
3
3
 
4
4
  from omlish import dispatch
5
5
 
6
- from ..sequence import SequenceContent
6
+ from ..content import Content
7
7
  from ..text import TextContent
8
- from ..types import Content
9
8
 
10
9
 
11
10
  ##
@@ -45,11 +44,6 @@ class ContentStringWriter:
45
44
  def write_text_content(self, c: TextContent) -> None:
46
45
  self._out.write(c.s)
47
46
 
48
- @write.register
49
- def write_sequence_content(self, c: SequenceContent) -> None:
50
- for e in c.l:
51
- self.write(e)
52
-
53
47
  #
54
48
 
55
49
  @classmethod
@@ -0,0 +1,33 @@
1
+ import typing as ta
2
+
3
+ from omlish import dataclasses as dc
4
+
5
+ from ..content import Content
6
+ from ..emphasis import EmphasisContent
7
+ from ..metadata import ContentOriginal
8
+ from ..text import TextContent
9
+ from ..visitors import ContentTransform
10
+
11
+
12
+ T = ta.TypeVar('T')
13
+
14
+
15
+ ##
16
+
17
+
18
+ @dc.dataclass(frozen=True)
19
+ class StringFnContentTransform(ContentTransform[None]):
20
+ fn: ta.Callable[[str], str]
21
+
22
+ def visit_str(self, c: str, ctx: None) -> TextContent:
23
+ return TextContent(self.fn(c)).with_metadata(ContentOriginal(c))
24
+
25
+ def visit_text_content(self, c: TextContent, ctx: None) -> TextContent:
26
+ return c.replace(s=self.fn(c.s))
27
+
28
+ def visit_emphasis_content(self, c: EmphasisContent, ctx: None) -> EmphasisContent:
29
+ return c.replace(s=self.fn(c.s))
30
+
31
+
32
+ def transform_content_strings(fn: ta.Callable[[str], str], o: Content) -> Content:
33
+ return StringFnContentTransform(fn).visit(o, None)
@@ -0,0 +1,25 @@
1
+ from omlish import check
2
+ from omlish.text import templating as tpl
3
+
4
+ from ..content import Content
5
+ from ..metadata import ContentOriginal
6
+ from ..templates import TemplateContent
7
+ from ..text import TextContent
8
+ from ..visitors import ContentTransform
9
+
10
+
11
+ ##
12
+
13
+
14
+ class TemplateContentMaterializer(ContentTransform[None]):
15
+ def __init__(
16
+ self,
17
+ templater_context: tpl.Templater.Context | None = None,
18
+ ) -> None:
19
+ super().__init__()
20
+
21
+ self._templater_context = templater_context
22
+
23
+ def visit_template_content(self, c: TemplateContent, ctx: None) -> Content:
24
+ s = c.t.render(check.not_none(self._templater_context))
25
+ return TextContent(s).with_metadata(ContentOriginal(c))