varar 0.5.2__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.
varar/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """Author facade for var: steps over the pure var-core engine."""
2
+
3
+ __version__ = "0.0.0"
4
+
5
+ from varar.internal import steps
6
+
7
+ __all__ = ["steps"]
varar/internal.py ADDED
@@ -0,0 +1,170 @@
1
+ """Author-facing API for declaring step state — port of var/src/internal.ts (steps)."""
2
+ from __future__ import annotations
3
+
4
+ import sys
5
+ from re import Pattern
6
+ from typing import Any, Callable, Optional
7
+
8
+ from varar_core.registry import Registry, add_step, create_registry, define_parameter_type
9
+ from varar_core.step_role import StepKind
10
+
11
+ # ---------------------------------------------------------------------------
12
+ # Module-level mutable builder state (mirrors the module-scope vars in internal.ts)
13
+ # ---------------------------------------------------------------------------
14
+
15
+ _steps: list[dict[str, Any]] = []
16
+ # One factory per step-file; keyed by the FACTORY's __code__.co_filename
17
+ _context_factories_by_file: dict[str, Callable[[], Any]] = {}
18
+ _custom_types: list[dict[str, Any]] = []
19
+
20
+
21
+ # ---------------------------------------------------------------------------
22
+ # Public API
23
+ # ---------------------------------------------------------------------------
24
+
25
+
26
+ def steps(
27
+ factory: Optional[Callable[[], Any]] = None,
28
+ ) -> tuple[
29
+ Callable[..., None],
30
+ Callable[[str], Callable[[Callable], Callable]],
31
+ Callable[[str], Callable[[Callable], Callable]],
32
+ ]:
33
+ """Register *factory* as the context-state constructor for its step file.
34
+
35
+ *factory* is optional: a step file whose steps are pure (nothing to
36
+ arrange, nothing to evolve) calls ``steps()`` bare and its handlers
37
+ receive an empty ``dict`` as state.
38
+
39
+ Returns ``(param, stimulus, sensor)``:
40
+
41
+ - ``param(name, regexp, parse=None, format=None)`` declares a custom
42
+ cucumber-expression parameter type. ``parse`` is a varargs function over
43
+ the capture groups (``parse(*groups)``); omitted, the parameter stays the
44
+ matched text. ``format`` is the display-only inverse.
45
+ - ``stimulus`` / ``sensor`` are decorator factories:
46
+ ``@stimulus("expression")`` registers the decorated function as a step.
47
+
48
+ Source location is captured from the decorated function's ``__code__``
49
+ attributes (``co_filename`` / ``co_firstlineno``).
50
+
51
+ Raises ``RuntimeError`` if called more than once for the same source file
52
+ (keyed by *factory*'s ``co_filename``, or the caller's file when *factory*
53
+ is omitted), mirroring ``internal.ts``.
54
+ """
55
+ if factory is None:
56
+ # No factory code object to key by — use the calling step file itself,
57
+ # which is where an inline factory would have been defined anyway.
58
+ source_file: str = sys._getframe(1).f_code.co_filename
59
+ factory = dict
60
+ else:
61
+ source_file = factory.__code__.co_filename
62
+ if source_file in _context_factories_by_file:
63
+ raise RuntimeError(
64
+ f"steps() called more than once in {source_file}"
65
+ )
66
+ _context_factories_by_file[source_file] = factory
67
+
68
+ def param(
69
+ name: str,
70
+ regexp: Any,
71
+ parse: Optional[Callable[..., Any]] = None,
72
+ format: Optional[Callable[[Any], str]] = None,
73
+ ) -> None:
74
+ _custom_types.append(
75
+ {"name": name, "regexp": regexp, "parse": parse, "format": format}
76
+ )
77
+
78
+ def _make_decorator(kind: StepKind) -> Callable[[str], Callable[[Callable], Callable]]:
79
+ def decorator_factory(expression: str) -> Callable[[Callable], Callable]:
80
+ def decorator(fn: Callable) -> Callable:
81
+ _steps.append(
82
+ {
83
+ "expression": expression,
84
+ "source_file": fn.__code__.co_filename,
85
+ "source_line": fn.__code__.co_firstlineno,
86
+ "handler": fn,
87
+ "kind": kind,
88
+ }
89
+ )
90
+ return fn
91
+
92
+ return decorator
93
+
94
+ return decorator_factory
95
+
96
+ return param, _make_decorator("stimulus"), _make_decorator("sensor")
97
+
98
+
99
+ def context_factory() -> Callable[[str], Any]:
100
+ """Return a callable ``(step_file: str) -> state`` that invokes the
101
+ registered factory for *step_file*, or ``{}`` if none is registered.
102
+
103
+ Mirrors ``contextFactory()`` in ``internal.ts``.
104
+ """
105
+ # Snapshot at call time (mirrors TS semantics where the map is closed over)
106
+ factories = dict(_context_factories_by_file)
107
+
108
+ def _invoke(step_file: str) -> Any:
109
+ f = factories.get(step_file)
110
+ return f() if f is not None else {}
111
+
112
+ return _invoke
113
+
114
+
115
+ def build_registry() -> Registry:
116
+ """Build and return a ``Registry`` from the accumulated steps and custom types.
117
+
118
+ Mirrors ``buildRegistry()`` in ``internal.ts``: custom parameter types are
119
+ registered first, then steps are compiled in registration order.
120
+ """
121
+ r = create_registry()
122
+ for t in _custom_types:
123
+ kwargs: dict[str, Any] = {"name": t["name"], "regexp": t["regexp"]}
124
+ if t.get("parse") is not None:
125
+ kwargs["parse"] = t["parse"]
126
+ if t.get("format") is not None:
127
+ kwargs["format"] = t["format"]
128
+ r = define_parameter_type(r, **kwargs)
129
+ for e in _steps:
130
+ r = add_step(
131
+ r,
132
+ expression=e["expression"],
133
+ expression_source_file=e["source_file"],
134
+ expression_source_line=e["source_line"],
135
+ handler=e["handler"],
136
+ kind=e["kind"],
137
+ )
138
+ return r
139
+
140
+
141
+ def _reset_builder() -> None:
142
+ """Clear all accumulated state. Use in tests between isolated scenarios."""
143
+ global _steps, _custom_types
144
+ _steps = []
145
+ _context_factories_by_file.clear()
146
+ _custom_types = []
147
+
148
+
149
+ def _custom_parameter_types() -> list[dict[str, str]]:
150
+ """Conformance-harness accessor: the custom parameter types accumulated by
151
+ ``param`` since the last ``_reset_builder``, projected to the
152
+ ``{"name", "regexp"}`` wire shape ``to_registry_artifact`` serializes.
153
+
154
+ ``regexp`` is the bare pattern source (``re.Pattern.pattern`` or the string
155
+ as authored — no flags/delimiters), the cross-port convention every
156
+ language's registry golden uses. Internal-only, mirrors the TS
157
+ ``_customParameterTypes``.
158
+ """
159
+ out: list[dict[str, str]] = []
160
+ for t in _custom_types:
161
+ rx = t["regexp"]
162
+ if isinstance(rx, Pattern):
163
+ rx = rx.pattern
164
+ elif not isinstance(rx, str):
165
+ raise TypeError(
166
+ f"parameter type {t['name']!r}: regexp lists are not supported by the "
167
+ "conformance projection yet"
168
+ )
169
+ out.append({"name": t["name"], "regexp": rx})
170
+ return out
varar/registry.py ADDED
@@ -0,0 +1,6 @@
1
+ """Adapter-only glue (mirrors @varar/varar/registry): build the registry and
2
+ context factory from the module-scope accumulator, and reset it between runs."""
3
+
4
+ from varar.internal import _custom_parameter_types, _reset_builder, build_registry, context_factory
5
+
6
+ __all__ = ["build_registry", "context_factory", "_reset_builder", "_custom_parameter_types"]
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: varar
3
+ Version: 0.5.2
4
+ Summary: Markdown-native BDD — pure Python core (port of @varar/varar)
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: cucumber-expressions==20.0.0
8
+ Requires-Dist: varar-core==0.5.2
@@ -0,0 +1,6 @@
1
+ varar/__init__.py,sha256=fhSJwv76-l-UjCkvxPK8pxPc9aaZKLmx9LBRAhava6s,144
2
+ varar/internal.py,sha256=xHgtA0_bDLfdOrYnAg7653zGt-ToqrO08vb-vYFct9Y,6445
3
+ varar/registry.py,sha256=vwMy4YjAlm652bGlulZm5bu5wt3hTv2-MbeBqdwjXFc,353
4
+ varar-0.5.2.dist-info/METADATA,sha256=76QT7W4jdwgoL9P7u9w7lsl77McHPYW4VQzekQ-AdL8,247
5
+ varar-0.5.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
6
+ varar-0.5.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any