fancy-microsoft-teams 0.2.0__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.
@@ -0,0 +1,41 @@
1
+ # GENERATED FILE — do not edit.
2
+ #
3
+ # Emitted from provider/manifest.json by weaver's generator.
4
+ # A hand-edit here is destroyed by the next protocol sync, which is worse than
5
+ # being rejected, because it works until it silently does not. Fix
6
+ # provider/manifest.json (or weaver's template/) and regenerate:
7
+ #
8
+ # npm run provider -- microsoft_teams
9
+
10
+ """Microsoft Teams for Python.
11
+
12
+ The service descriptor, its faker, its delivery contract, and one function
13
+ per operation — plain HTTP on the stdlib, no vendor SDK and no runtime
14
+ dependency.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from ._fake import FakeValues
20
+ from .actions.meeting_create import meeting_create
21
+ from .actions.meeting_get import meeting_get
22
+ from .actions.transcript_list import transcript_list
23
+ from .faker import respond
24
+ from .service import BASE_URLS, CONNECTOR_API_VERSION, REQUIRES, SANDBOX, SERVICE, TITLE, descriptor
25
+
26
+ __version__ = "0.2.0"
27
+
28
+ __all__ = [
29
+ "BASE_URLS",
30
+ "CONNECTOR_API_VERSION",
31
+ "REQUIRES",
32
+ "SANDBOX",
33
+ "SERVICE",
34
+ "TITLE",
35
+ "FakeValues",
36
+ "descriptor",
37
+ "meeting_create",
38
+ "meeting_get",
39
+ "respond",
40
+ "transcript_list",
41
+ ]
@@ -0,0 +1,170 @@
1
+ # GENERATED FILE — do not edit.
2
+ #
3
+ # Emitted from provider/manifest.json (via weaver's
4
+ # template/embed/py/_fake.py) by weaver's generator.
5
+ # A hand-edit here is destroyed by the next protocol sync, which is worse than
6
+ # being rejected, because it works until it silently does not. Fix
7
+ # provider/manifest.json (via weaver's template/embed/py/_fake.py) (or
8
+ # weaver's template/) and regenerate:
9
+ #
10
+ # npm run provider -- microsoft_teams
11
+
12
+ """Deterministic faker values — bit-for-bit with TypeScript and PHP.
13
+
14
+ PROVENANCE — read before editing.
15
+
16
+ This is the SINGLE SOURCE for the Python faker helpers. It exists because
17
+ ``fancy-connector-core`` has a TypeScript implementation and a PHP twin and
18
+ **no Python twin at all**, so a generated ``fancy-<provider>`` package has no
19
+ shared runtime to import. Every generated package carries a copy emitted from
20
+ this file, and ``new-provider.mjs --check`` fails CI when a copy differs.
21
+
22
+ The permanent fix is a Python ``fancy-connector-core``. When it exists, this
23
+ file becomes a re-export and every provider picks it up on the next protocol
24
+ sync.
25
+
26
+ ## Bit-for-bit identical is the whole point
27
+
28
+ Not "similar": the same FNV-1a seed and the same xorshift32 sequence, so a
29
+ golden fixture asserts the exact faked payload and ALL THREE runtimes have to
30
+ produce it. That turns the faker into a parity test rather than a convenience —
31
+ which matters, because cross-runtime drift does not fail loudly. It completes,
32
+ down one path, with no error.
33
+
34
+ Python integers are unbounded, so every 32-bit operation is masked back into
35
+ range. Dropping one of those masks does not break anything visibly; it just
36
+ makes the runtimes diverge after a few hundred calls, which is the worst
37
+ possible way for this to fail.
38
+
39
+ ## Deterministic, and obviously fake
40
+
41
+ Same inputs, same output — always. A faker returning a fresh uuid every call
42
+ cannot be asserted on, so its fixtures degrade to "it did not throw", which is
43
+ the assertion that catches nothing. And the values are obviously synthetic ON
44
+ PURPOSE — ``fake_``-prefixed ids, ``example.test`` hosts, round numbers. Nobody
45
+ should ever look at a faked result and wonder whether it moved real money.
46
+ """
47
+
48
+ from __future__ import annotations
49
+
50
+ import json
51
+ from datetime import UTC, datetime, timedelta
52
+ from typing import Any
53
+
54
+ MASK = 0xFFFFFFFF
55
+
56
+ # `FakeValues.int` is part of the cross-runtime faker API — `fake.int(min, max)`
57
+ # in TypeScript, PHP and here — so the method keeps that name. Inside the class
58
+ # body it then shadows the builtin, and every LATER annotation reading `int`
59
+ # resolves to the method instead of the type. This alias is what the annotations
60
+ # after it use.
61
+ _Int = int
62
+
63
+ #: The instant every faker counts from. A constant rather than the clock,
64
+ #: because a fixture asserting on ``created`` must not start failing tomorrow.
65
+ FAKE_EPOCH = "2026-01-01T00:00:00.000Z"
66
+
67
+ _FNV_OFFSET = 0x811C9DC5
68
+ _FNV_PRIME = 0x01000193
69
+
70
+
71
+ def _stable_json(value: Any) -> str:
72
+ """Render a value the way ``JSON.stringify`` would, with sorted object keys.
73
+
74
+ Key order must not change a seed. ``json.dumps`` preserves insertion order,
75
+ so ``{a, b}`` and ``{b, a}`` would hash differently and "same inputs, same
76
+ output" would hold only for dicts that happened to be built in the same
77
+ order — the kind of almost-true that survives review and fails in a fixture
78
+ months later.
79
+ """
80
+ if isinstance(value, dict):
81
+ parts = [
82
+ f"{json.dumps(str(key))}:{_stable_json(item)}"
83
+ for key, item in sorted(value.items(), key=lambda pair: str(pair[0]))
84
+ if item is not ...
85
+ ]
86
+ return "{" + ",".join(parts) + "}"
87
+
88
+ if isinstance(value, (list, tuple)):
89
+ return "[" + ",".join(_stable_json(item) for item in value) + "]"
90
+
91
+ # `separators` matters: JavaScript emits no spaces, and a space here would
92
+ # change every seed.
93
+ return json.dumps(value, separators=(",", ":"), ensure_ascii=False)
94
+
95
+
96
+ def seed_from(*parts: Any) -> int:
97
+ """FNV-1a over the stable rendering of the parts. Twin of ``seedFrom``."""
98
+ text = "|".join(part if isinstance(part, str) else _stable_json(part) for part in parts)
99
+
100
+ hash_ = _FNV_OFFSET
101
+ # JavaScript hashes UTF-16 code units, so a character outside the BMP
102
+ # contributes two of them. Encoding to UTF-16-LE and reading pairs is what
103
+ # keeps a provider name with an emoji in it seeding identically.
104
+ for unit in _utf16_units(text):
105
+ hash_ ^= unit
106
+ hash_ = (hash_ * _FNV_PRIME) & MASK
107
+
108
+ return hash_
109
+
110
+
111
+ def _utf16_units(text: str) -> list[int]:
112
+ raw = text.encode("utf-16-le")
113
+
114
+ return [raw[i] | (raw[i + 1] << 8) for i in range(0, len(raw), 2)]
115
+
116
+
117
+ def seed_for_call(service: str, operation: str, config: dict[str, Any] | None) -> int:
118
+ """The seed for one faked call: service, operation, and the caller's config."""
119
+ return seed_from(service, operation, config or {})
120
+
121
+
122
+ class FakeValues:
123
+ """Deterministic value helpers handed to a faker.
124
+
125
+ Small on purpose. A faker's job is to return the SHAPE the provider returns
126
+ — the field names a downstream node will reference — not to simulate the
127
+ provider's business logic.
128
+ """
129
+
130
+ def __init__(self, seed: int) -> None:
131
+ masked = seed & MASK
132
+ self._state = masked if masked != 0 else 0x9E3779B9
133
+
134
+ def _next(self) -> int:
135
+ """xorshift32, matching the JS generator step for step."""
136
+ state = self._state
137
+ state ^= (state << 13) & MASK
138
+ state &= MASK
139
+ state ^= state >> 17
140
+ state ^= (state << 5) & MASK
141
+ state &= MASK
142
+ self._state = state
143
+
144
+ return state
145
+
146
+ def hex(self, length: _Int) -> str:
147
+ """A stable lowercase hex string of ``length`` characters."""
148
+ out = ""
149
+ while len(out) < length:
150
+ out += format(self._next(), "08x")
151
+
152
+ return out[:length]
153
+
154
+ def id(self, prefix: str) -> str:
155
+ """A stable id with the provider's usual prefix: ``id("ch")`` -> ``ch_fake_1a2b3c``."""
156
+ return f"{prefix}_fake_{self.hex(12)}"
157
+
158
+ def int(self, minimum: int, maximum: int) -> int:
159
+ """A stable integer in ``[minimum, maximum]``."""
160
+ return minimum + (self._next() % max(1, maximum - minimum + 1))
161
+
162
+ def pick(self, options: list[Any]) -> Any:
163
+ """Pick a stable element of a list."""
164
+ return options[self._next() % len(options)]
165
+
166
+ def timestamp(self, offset_seconds: _Int = 0) -> str:
167
+ """A fixed ISO-8601 instant, offset by whole seconds. Never ``now()``."""
168
+ base = datetime(2026, 1, 1, tzinfo=UTC) + timedelta(seconds=offset_seconds)
169
+
170
+ return base.strftime("%Y-%m-%dT%H:%M:%S") + ".000Z"