python-fragments 0.35__tar.gz → 0.36__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.
Files changed (50) hide show
  1. {python_fragments-0.35/python_fragments.egg-info → python_fragments-0.36}/PKG-INFO +1 -1
  2. {python_fragments-0.35 → python_fragments-0.36}/fragments/html/elements.py +2 -2
  3. {python_fragments-0.35 → python_fragments-0.36}/pyproject.toml +1 -1
  4. {python_fragments-0.35 → python_fragments-0.36/python_fragments.egg-info}/PKG-INFO +1 -1
  5. python_fragments-0.36/tests/test_html_elements.py +55 -0
  6. python_fragments-0.35/tests/test_html_elements.py +0 -21
  7. {python_fragments-0.35 → python_fragments-0.36}/LICENSE +0 -0
  8. {python_fragments-0.35 → python_fragments-0.36}/README.md +0 -0
  9. {python_fragments-0.35 → python_fragments-0.36}/fragments/__init__.py +0 -0
  10. {python_fragments-0.35 → python_fragments-0.36}/fragments/ast_nodes.py +0 -0
  11. {python_fragments-0.35 → python_fragments-0.36}/fragments/cli.py +0 -0
  12. {python_fragments-0.35 → python_fragments-0.36}/fragments/grammar.py +0 -0
  13. {python_fragments-0.35 → python_fragments-0.36}/fragments/html/__init__.py +0 -0
  14. {python_fragments-0.35 → python_fragments-0.36}/fragments/loader.py +0 -0
  15. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/__init__.py +0 -0
  16. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/based_proxy.py +0 -0
  17. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/__init__.py +0 -0
  18. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/code_actions.py +0 -0
  19. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/completion.py +0 -0
  20. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/definition.py +0 -0
  21. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/diagnostics.py +0 -0
  22. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/document_highlight.py +0 -0
  23. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/document_symbols.py +0 -0
  24. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/folding_range.py +0 -0
  25. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/hover.py +0 -0
  26. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/inlay_hints.py +0 -0
  27. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/lifecycle.py +0 -0
  28. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/references.py +0 -0
  29. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/rename.py +0 -0
  30. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/semantic_tokens.py +0 -0
  31. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/client_message_handlers/signature_help.py +0 -0
  32. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/file_state.py +0 -0
  33. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/message_queue.py +0 -0
  34. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/pyright_notification_handlers/__init__.py +0 -0
  35. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/pyright_notification_handlers/capability.py +0 -0
  36. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/pyright_notification_handlers/configuration.py +0 -0
  37. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/pyright_notification_handlers/diagnostics.py +0 -0
  38. {python_fragments-0.35 → python_fragments-0.36}/fragments/lsp/types.py +0 -0
  39. {python_fragments-0.35 → python_fragments-0.36}/fragments/source.py +0 -0
  40. {python_fragments-0.35 → python_fragments-0.36}/fragments/transpiler.py +0 -0
  41. {python_fragments-0.35 → python_fragments-0.36}/fragments/types.py +0 -0
  42. {python_fragments-0.35 → python_fragments-0.36}/python_fragments.egg-info/SOURCES.txt +0 -0
  43. {python_fragments-0.35 → python_fragments-0.36}/python_fragments.egg-info/dependency_links.txt +0 -0
  44. {python_fragments-0.35 → python_fragments-0.36}/python_fragments.egg-info/entry_points.txt +0 -0
  45. {python_fragments-0.35 → python_fragments-0.36}/python_fragments.egg-info/requires.txt +0 -0
  46. {python_fragments-0.35 → python_fragments-0.36}/python_fragments.egg-info/top_level.txt +0 -0
  47. {python_fragments-0.35 → python_fragments-0.36}/setup.cfg +0 -0
  48. {python_fragments-0.35 → python_fragments-0.36}/tests/test_end_to_end.py +0 -0
  49. {python_fragments-0.35 → python_fragments-0.36}/tests/test_grammar.py +0 -0
  50. {python_fragments-0.35 → python_fragments-0.36}/tests/test_source_map.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fragments
3
- Version: 0.35
3
+ Version: 0.36
4
4
  Summary: Modern HTML template rendering in Python
5
5
  Author-email: The Running Algorithm <services@therunningalgorithm.info>
6
6
  License: MIT License
@@ -21,12 +21,12 @@ def attribute_to_string(name: str, value: Any) -> str:
21
21
  return style_to_string(value)
22
22
 
23
23
  if isinstance(value, dict) or isinstance(value, list):
24
- value = html.escape(json.dumps(value))
24
+ value = json.dumps(value)
25
25
 
26
26
  if isinstance(value, bool):
27
27
  value = str(value).lower()
28
28
 
29
- return f'{name}="{value}"'
29
+ return f'{name}="{html.escape(str(value))}"'
30
30
 
31
31
 
32
32
  def className_to_string(contents: list[str] | str) -> str:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-fragments"
7
- version = "0.35"
7
+ version = "0.36"
8
8
  description = "Modern HTML template rendering in Python"
9
9
  authors = [{ name = "The Running Algorithm", email = "services@therunningalgorithm.info" }]
10
10
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fragments
3
- Version: 0.35
3
+ Version: 0.36
4
4
  Summary: Modern HTML template rendering in Python
5
5
  Author-email: The Running Algorithm <services@therunningalgorithm.info>
6
6
  License: MIT License
@@ -0,0 +1,55 @@
1
+ from fragments.html.elements import attribute_to_string, className_to_string
2
+
3
+
4
+ def test_attribute_plain_string():
5
+ assert attribute_to_string("href", "/path") == 'href="/path"'
6
+
7
+
8
+ def test_attribute_string_escapes_double_quote():
9
+ assert attribute_to_string("data-value", 'say "hello"') == 'data-value="say &quot;hello&quot;"'
10
+
11
+
12
+ def test_attribute_string_escapes_ampersand():
13
+ assert attribute_to_string("title", "cats & dogs") == 'title="cats &amp; dogs"'
14
+
15
+
16
+ def test_attribute_string_escapes_arrow_in_expression():
17
+ assert attribute_to_string("x-on:click", "items.filter(item => item.active)") == (
18
+ 'x-on:click="items.filter(item =&gt; item.active)"'
19
+ )
20
+
21
+
22
+ def test_attribute_dict_escapes_quotes_from_json():
23
+ assert attribute_to_string("data-config", {"key": "value"}) == 'data-config="{&quot;key&quot;: &quot;value&quot;}"'
24
+
25
+
26
+ def test_attribute_bool_true():
27
+ assert attribute_to_string("disabled", True) == 'disabled="true"'
28
+
29
+
30
+ def test_attribute_bool_false():
31
+ assert attribute_to_string("disabled", False) == 'disabled="false"'
32
+
33
+
34
+ def test_attribute_none_returns_empty():
35
+ assert attribute_to_string("hidden", None) == ""
36
+
37
+
38
+ def test_className_list_joined_with_spaces():
39
+ result = className_to_string(["foo", "bar", "baz"])
40
+ assert result == 'class="foo bar baz"'
41
+
42
+
43
+ def test_className_empty_list():
44
+ result = className_to_string([])
45
+ assert result == 'class=""'
46
+
47
+
48
+ def test_className_single_item_list():
49
+ result = className_to_string(["only"])
50
+ assert result == 'class="only"'
51
+
52
+
53
+ def test_className_string_passthrough():
54
+ result = className_to_string("already-a-string")
55
+ assert result == 'class="already-a-string"'
@@ -1,21 +0,0 @@
1
- from fragments.html.elements import className_to_string
2
-
3
-
4
- def test_className_list_joined_with_spaces():
5
- result = className_to_string(["foo", "bar", "baz"])
6
- assert result == 'class="foo bar baz"'
7
-
8
-
9
- def test_className_empty_list():
10
- result = className_to_string([])
11
- assert result == 'class=""'
12
-
13
-
14
- def test_className_single_item_list():
15
- result = className_to_string(["only"])
16
- assert result == 'class="only"'
17
-
18
-
19
- def test_className_string_passthrough():
20
- result = className_to_string("already-a-string")
21
- assert result == 'class="already-a-string"'
File without changes