drun 2.3.2__tar.gz → 2.3.4__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 (62) hide show
  1. {drun-2.3.2 → drun-2.3.4}/PKG-INFO +1 -1
  2. {drun-2.3.2 → drun-2.3.4}/drun/__init__.py +1 -1
  3. {drun-2.3.2 → drun-2.3.4}/drun/templating/engine.py +14 -15
  4. {drun-2.3.2 → drun-2.3.4}/drun.egg-info/PKG-INFO +1 -1
  5. {drun-2.3.2 → drun-2.3.4}/drun.egg-info/SOURCES.txt +2 -1
  6. {drun-2.3.2 → drun-2.3.4}/pyproject.toml +1 -1
  7. drun-2.3.4/tests/test_templating.py +40 -0
  8. {drun-2.3.2 → drun-2.3.4}/LICENSE +0 -0
  9. {drun-2.3.2 → drun-2.3.4}/README.md +0 -0
  10. {drun-2.3.2 → drun-2.3.4}/drun/cli.py +0 -0
  11. {drun-2.3.2 → drun-2.3.4}/drun/db/__init__.py +0 -0
  12. {drun-2.3.2 → drun-2.3.4}/drun/db/database_proxy.py +0 -0
  13. {drun-2.3.2 → drun-2.3.4}/drun/db/generate_mysql_config.py +0 -0
  14. {drun-2.3.2 → drun-2.3.4}/drun/engine/__init__.py +0 -0
  15. {drun-2.3.2 → drun-2.3.4}/drun/engine/http.py +0 -0
  16. {drun-2.3.2 → drun-2.3.4}/drun/exporters/curl.py +0 -0
  17. {drun-2.3.2 → drun-2.3.4}/drun/importers/base.py +0 -0
  18. {drun-2.3.2 → drun-2.3.4}/drun/importers/curl.py +0 -0
  19. {drun-2.3.2 → drun-2.3.4}/drun/importers/har.py +0 -0
  20. {drun-2.3.2 → drun-2.3.4}/drun/importers/openapi.py +0 -0
  21. {drun-2.3.2 → drun-2.3.4}/drun/importers/postman.py +0 -0
  22. {drun-2.3.2 → drun-2.3.4}/drun/loader/__init__.py +0 -0
  23. {drun-2.3.2 → drun-2.3.4}/drun/loader/collector.py +0 -0
  24. {drun-2.3.2 → drun-2.3.4}/drun/loader/env.py +0 -0
  25. {drun-2.3.2 → drun-2.3.4}/drun/loader/hooks.py +0 -0
  26. {drun-2.3.2 → drun-2.3.4}/drun/loader/yaml_loader.py +0 -0
  27. {drun-2.3.2 → drun-2.3.4}/drun/models/case.py +0 -0
  28. {drun-2.3.2 → drun-2.3.4}/drun/models/config.py +0 -0
  29. {drun-2.3.2 → drun-2.3.4}/drun/models/report.py +0 -0
  30. {drun-2.3.2 → drun-2.3.4}/drun/models/request.py +0 -0
  31. {drun-2.3.2 → drun-2.3.4}/drun/models/step.py +0 -0
  32. {drun-2.3.2 → drun-2.3.4}/drun/models/validators.py +0 -0
  33. {drun-2.3.2 → drun-2.3.4}/drun/notifier/__init__.py +0 -0
  34. {drun-2.3.2 → drun-2.3.4}/drun/notifier/base.py +0 -0
  35. {drun-2.3.2 → drun-2.3.4}/drun/notifier/dingtalk.py +0 -0
  36. {drun-2.3.2 → drun-2.3.4}/drun/notifier/emailer.py +0 -0
  37. {drun-2.3.2 → drun-2.3.4}/drun/notifier/feishu.py +0 -0
  38. {drun-2.3.2 → drun-2.3.4}/drun/notifier/format.py +0 -0
  39. {drun-2.3.2 → drun-2.3.4}/drun/reporter/__init__.py +0 -0
  40. {drun-2.3.2 → drun-2.3.4}/drun/reporter/allure_reporter.py +0 -0
  41. {drun-2.3.2 → drun-2.3.4}/drun/reporter/html_reporter.py +0 -0
  42. {drun-2.3.2 → drun-2.3.4}/drun/reporter/json_reporter.py +0 -0
  43. {drun-2.3.2 → drun-2.3.4}/drun/runner/__init__.py +0 -0
  44. {drun-2.3.2 → drun-2.3.4}/drun/runner/assertions.py +0 -0
  45. {drun-2.3.2 → drun-2.3.4}/drun/runner/extractors.py +0 -0
  46. {drun-2.3.2 → drun-2.3.4}/drun/runner/runner.py +0 -0
  47. {drun-2.3.2 → drun-2.3.4}/drun/scaffolds/__init__.py +0 -0
  48. {drun-2.3.2 → drun-2.3.4}/drun/scaffolds/templates.py +0 -0
  49. {drun-2.3.2 → drun-2.3.4}/drun/templating/__init__.py +0 -0
  50. {drun-2.3.2 → drun-2.3.4}/drun/templating/builtins.py +0 -0
  51. {drun-2.3.2 → drun-2.3.4}/drun/templating/context.py +0 -0
  52. {drun-2.3.2 → drun-2.3.4}/drun/utils/__init__.py +0 -0
  53. {drun-2.3.2 → drun-2.3.4}/drun/utils/curl.py +0 -0
  54. {drun-2.3.2 → drun-2.3.4}/drun/utils/errors.py +0 -0
  55. {drun-2.3.2 → drun-2.3.4}/drun/utils/logging.py +0 -0
  56. {drun-2.3.2 → drun-2.3.4}/drun/utils/mask.py +0 -0
  57. {drun-2.3.2 → drun-2.3.4}/drun/utils/timeit.py +0 -0
  58. {drun-2.3.2 → drun-2.3.4}/drun.egg-info/dependency_links.txt +0 -0
  59. {drun-2.3.2 → drun-2.3.4}/drun.egg-info/entry_points.txt +0 -0
  60. {drun-2.3.2 → drun-2.3.4}/drun.egg-info/requires.txt +0 -0
  61. {drun-2.3.2 → drun-2.3.4}/drun.egg-info/top_level.txt +0 -0
  62. {drun-2.3.2 → drun-2.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drun
3
- Version: 2.3.2
3
+ Version: 2.3.4
4
4
  Summary: Minimal HTTP API test runner (MVP)
5
5
  Author: Drun Team
6
6
  Requires-Python: >=3.10
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "2.3.2"
2
+ __version__ = "2.3.3"
@@ -142,25 +142,24 @@ class TemplateEngine:
142
142
  dyn_funcs: Dict[str, Callable[..., Any]] = {"ENV": ENV}
143
143
  ctx: Dict[str, Any] = {**BUILTINS, **dyn_funcs, **(functions or {}), **variables}
144
144
 
145
- # If the whole string is a single ${...} token, evaluate and return the value with its native type
146
- single_token_match = re.fullmatch(r"\$\{([^{}]+)\}", text)
147
- if single_token_match:
148
- expr = single_token_match.group(1).strip()
149
- try:
150
- node = ast.parse(expr, mode="eval")
151
- return _safe_eval(node, ctx)
152
- except Exception:
153
- # Fall through to string rendering if evaluation fails
154
- pass
155
-
156
- # multi-pass to resolve nested tokens inside strings, always producing a string
157
145
  cur = text
158
- for _ in range(3):
146
+ for _ in range(5):
147
+ single_token_match = re.fullmatch(r"\$\{([^{}]+)\}", cur)
148
+ if single_token_match:
149
+ expr = single_token_match.group(1).strip()
150
+ try:
151
+ node = ast.parse(expr, mode="eval")
152
+ return _safe_eval(node, ctx)
153
+ except Exception:
154
+ # Fall through and continue resolving nested tokens if evaluation fails
155
+ pass
159
156
  nxt = _render_text_without_jinja(cur, ctx)
160
- if nxt == cur or "${" not in nxt:
161
- cur = nxt
157
+ if nxt == cur:
162
158
  break
163
159
  cur = nxt
160
+ if "${" not in cur:
161
+ break
162
+ # If we weren't able to evaluate to a native type, return the rendered string
164
163
  return cur
165
164
  except Exception:
166
165
  return value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drun
3
- Version: 2.3.2
3
+ Version: 2.3.4
4
4
  Summary: Minimal HTTP API test runner (MVP)
5
5
  Author: Drun Team
6
6
  Requires-Python: >=3.10
@@ -56,4 +56,5 @@ drun/utils/curl.py
56
56
  drun/utils/errors.py
57
57
  drun/utils/logging.py
58
58
  drun/utils/mask.py
59
- drun/utils/timeit.py
59
+ drun/utils/timeit.py
60
+ tests/test_templating.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "drun"
7
- version = "2.3.2"
7
+ version = "2.3.4"
8
8
  description = "Minimal HTTP API test runner (MVP)"
9
9
  requires-python = ">=3.10"
10
10
  authors = [{ name = "Drun Team" }]
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ import unittest
4
+
5
+ from drun.templating.engine import TemplateEngine
6
+
7
+
8
+ class TemplateEngineHookTests(unittest.TestCase):
9
+ def setUp(self) -> None:
10
+ self.templater = TemplateEngine()
11
+
12
+ def test_nested_hook_calls_preserve_native_types(self) -> None:
13
+ funcs = {
14
+ "double": lambda x: x * 2,
15
+ "increment": lambda val: int(val) + 1,
16
+ }
17
+
18
+ base_vars = self.templater.render_value({"start": "${double(2)}"}, {}, funcs)
19
+ self.assertEqual(base_vars["start"], 4)
20
+ self.assertIsInstance(base_vars["start"], int)
21
+
22
+ step_vars = self.templater.render_value(
23
+ {"payload": "${double($start)}"},
24
+ {**base_vars},
25
+ funcs,
26
+ )
27
+ self.assertEqual(step_vars["payload"], 8)
28
+ self.assertIsInstance(step_vars["payload"], int)
29
+
30
+ expect_value = self.templater.render_value(
31
+ "${increment($payload)}",
32
+ {**base_vars, **step_vars},
33
+ funcs,
34
+ )
35
+ self.assertEqual(expect_value, 9)
36
+ self.assertIsInstance(expect_value, int)
37
+
38
+
39
+ if __name__ == "__main__":
40
+ unittest.main()
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
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
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
File without changes