htmy 0.7.1__py3-none-any.whl → 0.7.3__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.

Potentially problematic release.


This version of htmy might be problematic. Click here for more details.

htmy/core.py CHANGED
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import abc
4
4
  import enum
5
+ import json
5
6
  from collections.abc import Callable, Container
6
7
  from typing import TYPE_CHECKING, Any, ClassVar, TypedDict, cast
7
8
  from xml.sax.saxutils import escape as xml_escape
@@ -251,6 +252,9 @@ class Formatter(ContextAware):
251
252
  """
252
253
  The default, context-aware property name and value formatter.
253
254
 
255
+ The formatter supports both primitive and (many) complex values, such as lists,
256
+ dictionaries, tuples, and sets. Complex values are JSON-serialized by default.
257
+
254
258
  Important: the default implementation looks up the formatter for a given value by checking
255
259
  its type, but it doesn't do this check with the base classes of the encountered type. For
256
260
  example the formatter will know how to format `datetime` object, but it won't know how to
@@ -258,7 +262,7 @@ class Formatter(ContextAware):
258
262
 
259
263
  One reason for this is efficiency: always checking the base classes of every single value is a
260
264
  lot of unnecessary calculation. The other reason is customizability: this way you could use
261
- subclassing for fomatter selection, e.g. with `LocaleDatetime(datetime)`-like classes.
265
+ subclassing for formatter selection, e.g. with `LocaleDatetime(datetime)`-like classes.
262
266
 
263
267
  Property name and value formatters may raise a `SkipProperty` error if a property should be skipped.
264
268
  """
@@ -337,6 +341,10 @@ class Formatter(ContextAware):
337
341
  bool: lambda v: "true" if v else "false",
338
342
  date: lambda d: cast(date, d).isoformat(),
339
343
  datetime: lambda d: cast(datetime, d).isoformat(),
344
+ dict: lambda v: json.dumps(v),
345
+ list: lambda v: json.dumps(v),
346
+ tuple: lambda v: json.dumps(v),
347
+ set: lambda v: json.dumps(tuple(v)),
340
348
  XBool: lambda v: cast(XBool, v).format(),
341
349
  type(None): SkipProperty.format_property,
342
350
  }
htmy/i18n.py CHANGED
@@ -112,7 +112,7 @@ class I18n(ContextAware):
112
112
  return result
113
113
 
114
114
 
115
- @alru_cache(8)
115
+ @alru_cache()
116
116
  async def load_translation_resource(path: Path) -> TranslationResource:
117
117
  """
118
118
  Loads the translation resource from the given path.
htmy/io.py CHANGED
@@ -1 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
1
5
  from anyio import open_file as open_file
6
+
7
+ if TYPE_CHECKING:
8
+ from pathlib import Path
9
+
10
+
11
+ async def load_text_file(path: str | Path) -> str:
12
+ """Loads the text content from the given path."""
13
+ async with await open_file(path, "r") as f:
14
+ return await f.read()
htmy/snippet.py CHANGED
@@ -1,9 +1,13 @@
1
+ from __future__ import annotations
2
+
1
3
  import re
2
4
  from collections.abc import Awaitable, Iterator, Mapping
3
- from pathlib import Path
5
+ from typing import TYPE_CHECKING
6
+
7
+ from async_lru import alru_cache
4
8
 
5
9
  from .core import SafeStr, Text
6
- from .io import open_file
10
+ from .io import load_text_file
7
11
  from .typing import (
8
12
  Component,
9
13
  ComponentType,
@@ -13,6 +17,9 @@ from .typing import (
13
17
  )
14
18
  from .utils import as_component_sequence, as_component_type, is_component_sequence
15
19
 
20
+ if TYPE_CHECKING:
21
+ from pathlib import Path
22
+
16
23
  # -- Components and utilities
17
24
 
18
25
 
@@ -248,8 +255,7 @@ class Snippet:
248
255
  if isinstance(path_or_text, Text):
249
256
  return path_or_text
250
257
  else:
251
- async with await open_file(path_or_text, "r") as f:
252
- return await f.read()
258
+ return await Snippet._load_text_file(path_or_text)
253
259
 
254
260
  def _render_text(self, text: str, context: Context) -> Component:
255
261
  """
@@ -257,3 +263,9 @@ class Snippet:
257
263
  and returns the corresponding component.
258
264
  """
259
265
  return SafeStr(text)
266
+
267
+ @staticmethod
268
+ @alru_cache()
269
+ async def _load_text_file(path: str | Path) -> str:
270
+ """Async text loader with an LRU cache."""
271
+ return await load_text_file(path)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: htmy
3
- Version: 0.7.1
4
- Summary: Async, pure-Python rendering engine.
3
+ Version: 0.7.3
4
+ Summary: Async, pure-Python server-side rendering engine.
5
5
  License: MIT
6
6
  Author: Peter Volf
7
7
  Author-email: do.volfp@gmail.com
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  # `htmy`
30
30
 
31
- **Async**, **pure-Python** rendering engine.
31
+ **Async**, **pure-Python** server-side rendering engine.
32
32
 
33
33
  Unleash your creativity with the full power and Python, without the hassle of learning a new templating language or dealing with its limitations!
34
34
 
@@ -285,6 +285,7 @@ These are default tag attribute formatting rules:
285
285
  - `bool` attribute values are converted to strings (`"true"` and `"false"`).
286
286
  - `XBool.true` attributes values are converted to an empty string, and `XBool.false` values are skipped (only the attribute name is rendered).
287
287
  - `date` and `datetime` attribute values are converted to ISO strings.
288
+ - Complex values such as lists, dictionaries, tuples, and sets are JSON serialized.
288
289
 
289
290
  ### Error boundary
290
291
 
@@ -308,6 +309,10 @@ FastAPI:
308
309
 
309
310
  - [FastHX](https://github.com/volfpeter/fasthx)
310
311
 
312
+ ## External examples
313
+
314
+ - [lipsum-chat](https://github.com/volfpeter/lipsum-chat): A simple chat application using `FastAPI`, `htmx`, and `fasthx`.
315
+
311
316
  ## Why
312
317
 
313
318
  At one end of the spectrum, there are the complete application frameworks that combine the server (Python) and client (JavaScript) applications with the entire state management and synchronization into a single Python (an in some cases an additional JavaScript) package. Some of the most popular examples are: [Reflex](https://github.com/reflex-dev/reflex), [NiceGUI](https://github.com/zauberzeug/nicegui/), [ReactPy](https://github.com/reactive-python/reactpy), and [FastUI](https://github.com/pydantic/FastUI).
@@ -1,10 +1,10 @@
1
1
  htmy/__init__.py,sha256=Us5P9Y6ZSp38poIz88bsAh2Hxuze5jE3V_uMtMyuH-E,1880
2
- htmy/core.py,sha256=OoL11j2V-CfePC0dbkC2A5GbdK942b5Huszw3rLo7fc,15124
2
+ htmy/core.py,sha256=mvNbxTRS8HNnjMSwe4NEJdL1KF19pJImF4Ciip6837I,15484
3
3
  htmy/etree.py,sha256=yKxom__AdsJY-Q1kbU0sdTMr0ZF5dMSVBKxayntNFyQ,3062
4
4
  htmy/function_component.py,sha256=iSp5cGrErmIsc-VfNq053_J2m-Nuu_k2xK9UxvEnlw8,12431
5
5
  htmy/html.py,sha256=7UohfPRtl-3IoSbOiDxazsSHQpCZ0tyRdNayQISPM8A,21086
6
- htmy/i18n.py,sha256=brNazQjObBFfbnViZCpcnxa0qgxQbJfX7xJAH-MqTW8,5124
7
- htmy/io.py,sha256=iebJOZp7L0kZ9SWdqMatKtW5VGRIkEd-eD0_vTAldH8,41
6
+ htmy/i18n.py,sha256=Kobvm9mFoNcJas52KQbheiRIzJF1Ad1azOhtfm_k0BE,5123
7
+ htmy/io.py,sha256=oEXXVnpdbjs2NzAGi36Pept-pyvXshEGHrbBFzcHYio,344
8
8
  htmy/md/__init__.py,sha256=lxBJnYplkDuxYuiese6My9KYp1DeGdzo70iUdYTvMnE,334
9
9
  htmy/md/core.py,sha256=Xu-8xGAOGqSYLGPOib0Wn-blmyQBHl3MrAOza_w__Y8,4456
10
10
  htmy/md/typing.py,sha256=LF-AEvo7FCW2KumyR5l55rsXizV2E4AHVLKFf6lApgM,762
@@ -12,10 +12,10 @@ htmy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  htmy/renderer/__init__.py,sha256=xnP_aaoK-pTok-69wi8O_xlsgjoKTzWd2lIIeHGcuaY,226
13
13
  htmy/renderer/baseline.py,sha256=hHb7CoQhFFdD7Sdw0ltR1-XLGwE9pqmfL5yKFeF2rCg,4288
14
14
  htmy/renderer/default.py,sha256=G6K5YptvH9QvEvMQZdLPtgUblO_zTv4Eo6TETHZDlX8,10869
15
- htmy/snippet.py,sha256=dkHEOuULGsgawIMnSz99hghvNu8pLVGAQMQSlrn9ibY,10260
15
+ htmy/snippet.py,sha256=9-ltfs4rugv6kFNzAY0PYNP3YI3xvJG8lkxEnYcCYWw,10538
16
16
  htmy/typing.py,sha256=0spTpz_JWql2yy_lSlRx0uqgXar7fxwyBqWeIzltvKU,3111
17
17
  htmy/utils.py,sha256=Kp0j9G8CBeRiyFGmz-CoDiLtXHfpvHzlTVsWeDhIebM,1935
18
- htmy-0.7.1.dist-info/LICENSE,sha256=rFtoGU_3c_rlacXgOZapTHfMErN-JFPT5Bq_col4bqI,1067
19
- htmy-0.7.1.dist-info/METADATA,sha256=-1VV-vjHWSTWiqNq1bi_E8sKy3PGSLMmauuuKscc70A,18459
20
- htmy-0.7.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
21
- htmy-0.7.1.dist-info/RECORD,,
18
+ htmy-0.7.3.dist-info/LICENSE,sha256=rFtoGU_3c_rlacXgOZapTHfMErN-JFPT5Bq_col4bqI,1067
19
+ htmy-0.7.3.dist-info/METADATA,sha256=T3hOzzQL_Al4cNT_Fruj-IM1pbMMkvKFCX9KBUdJlcY,18714
20
+ htmy-0.7.3.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
21
+ htmy-0.7.3.dist-info/RECORD,,
File without changes
File without changes