htmy 0.7.0__tar.gz → 0.7.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: htmy
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Async, pure-Python rendering engine.
5
5
  License: MIT
6
6
  Author: Peter Volf
@@ -116,7 +116,7 @@ user_table = html.table(
116
116
  )
117
117
  ```
118
118
 
119
- `htmy` also provides a `@component` decorator that can be used on sync or async `my_component(props: MyProps, context: Context) -> Component` functions to convert them into components (preserving the `props` typing).
119
+ `htmy` also provides a powerful `@component` decorator that can be used on sync or async `my_component(props: MyProps, context: Context) -> Component` functions and methods to convert them into components (preserving the `props` typing). You can find out more about this feature in the [Function components](https://volfpeter.github.io/htmy/function-components/) guide.
120
120
 
121
121
  Here is the same example as above, but with function components:
122
122
 
@@ -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).
@@ -97,7 +97,7 @@ user_table = html.table(
97
97
  )
98
98
  ```
99
99
 
100
- `htmy` also provides a `@component` decorator that can be used on sync or async `my_component(props: MyProps, context: Context) -> Component` functions to convert them into components (preserving the `props` typing).
100
+ `htmy` also provides a powerful `@component` decorator that can be used on sync or async `my_component(props: MyProps, context: Context) -> Component` functions and methods to convert them into components (preserving the `props` typing). You can find out more about this feature in the [Function components](https://volfpeter.github.io/htmy/function-components/) guide.
101
101
 
102
102
  Here is the same example as above, but with function components:
103
103
 
@@ -266,6 +266,7 @@ These are default tag attribute formatting rules:
266
266
  - `bool` attribute values are converted to strings (`"true"` and `"false"`).
267
267
  - `XBool.true` attributes values are converted to an empty string, and `XBool.false` values are skipped (only the attribute name is rendered).
268
268
  - `date` and `datetime` attribute values are converted to ISO strings.
269
+ - Complex values such as lists, dictionaries, tuples, and sets are JSON serialized.
269
270
 
270
271
  ### Error boundary
271
272
 
@@ -289,6 +290,10 @@ FastAPI:
289
290
 
290
291
  - [FastHX](https://github.com/volfpeter/fasthx)
291
292
 
293
+ ## External examples
294
+
295
+ - [lipsum-chat](https://github.com/volfpeter/lipsum-chat): A simple chat application using `FastAPI`, `htmx`, and `fasthx`.
296
+
292
297
  ## Why
293
298
 
294
299
  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).
@@ -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
  }
@@ -209,8 +209,9 @@ class _ComponentRenderer:
209
209
  process_node_result(node, result, child_context)
210
210
 
211
211
  if async_todos:
212
- await asyncio.gather(*(process_async_node(n, ctx) for n, ctx in async_todos))
213
- async_todos.clear()
212
+ current_async_todos = async_todos
213
+ self._async_todos = async_todos = deque()
214
+ await asyncio.gather(*(process_async_node(n, ctx) for n, ctx in current_async_todos))
214
215
 
215
216
  if self._error_boundary_todos:
216
217
  await asyncio.gather(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "htmy"
3
- version = "0.7.0"
3
+ version = "0.7.2"
4
4
  description = "Async, pure-Python rendering engine."
5
5
  authors = ["Peter Volf <do.volfp@gmail.com>"]
6
6
  license = "MIT"
@@ -14,7 +14,7 @@ markdown = "^3.7"
14
14
 
15
15
  [tool.poetry.group.dev.dependencies]
16
16
  mkdocs-material = "^9.5.39"
17
- mkdocstrings = {extras = ["python"], version = "^0.26.1"}
17
+ mkdocstrings = { extras = ["python"], version = "^0.26.1" }
18
18
  mypy = "^1.15.0"
19
19
  poethepoet = "^0.29.0"
20
20
  pytest = "^8.3.3"
@@ -49,17 +49,17 @@ exclude = [
49
49
  "docs",
50
50
  ]
51
51
  lint.select = [
52
- "B", # flake8-bugbear
53
- "C", # flake8-comprehensions
54
- "E", # pycodestyle errors
55
- "F", # pyflakes
56
- "I", # isort
57
- "S", # flake8-bandit - we must ignore these rules in tests
58
- "W", # pycodestyle warnings
52
+ "B", # flake8-bugbear
53
+ "C", # flake8-comprehensions
54
+ "E", # pycodestyle errors
55
+ "F", # pyflakes
56
+ "I", # isort
57
+ "S", # flake8-bandit - we must ignore these rules in tests
58
+ "W", # pycodestyle warnings
59
59
  ]
60
60
 
61
61
  [tool.ruff.lint.per-file-ignores]
62
- "tests/**/*" = ["S101"] # S101: use of assert detected
62
+ "tests/**/*" = ["S101"] # S101: use of assert detected
63
63
 
64
64
  [tool.poe.tasks]
65
65
  check-format = "ruff format --check ."
@@ -70,4 +70,4 @@ mypy = "mypy ."
70
70
  test = "python -m pytest tests"
71
71
  static-checks.sequence = ["lint", "check-format", "mypy"]
72
72
  static-checks.ignore_fail = "return_non_zero"
73
- serve-docs = "mkdocs serve"
73
+ serve-docs = "mkdocs serve"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes