synthigy 0.1.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.
synthigy/__init__.py ADDED
@@ -0,0 +1,164 @@
1
+ """Synthigy SDK — thin, stdlib-only client for the /data endpoint.
2
+
3
+ ONE ENGINE: the async-native `AsyncClient` (async_client.py) is the whole
4
+ implementation. The blocking `Client` is a facade over it driving a single
5
+ background event-loop thread (facade.py) — same API as always for
6
+ scripts, seeds and notebooks; async apps use the `aconnect`/`aclient`
7
+ surface natively.
8
+
9
+ THE INVARIANT: one process, one client, one backend. `connect(...)` installs
10
+ a module-wide default (destroying any previous one, server-restart style);
11
+ the module-level verbs operate on it. Identity is multiplexed per-call via
12
+ `acting_as=`, never a second connect. Constructing `Client` directly is the
13
+ escape hatch (tests).
14
+
15
+ import synthigy
16
+ from synthigy import eq, rel
17
+
18
+ synthigy.connect(endpoint="http://localhost:7887",
19
+ client_id="my-service", client_secret=SECRET)
20
+
21
+ users = synthigy.search("User", {"active": eq(True), "_limit": 10},
22
+ {"name": None, "roles": {"name": None}},
23
+ acting_as=user_xid)
24
+
25
+ Async-first (BFFs, FastAPI/uvicorn services):
26
+
27
+ synthigy.aconnect(endpoint=..., client_id=..., client_secret=SECRET)
28
+ rows = await synthigy.aclient().search("User", ..., acting_as=user_xid)
29
+ """
30
+
31
+ from . import ops # noqa: F401
32
+ from .async_client import AsyncClient # noqa: F401
33
+ from .compose import compose_forest, compose_tree # noqa: F401
34
+ from .errors import SynthigyError # noqa: F401
35
+ from .facade import Client
36
+ from .filters import ( # noqa: F401
37
+ and_, eq, gt, gte, ilike, in_, is_not_null, is_null, like, lt, lte, neq,
38
+ nin, not_, or_,
39
+ )
40
+ from .selection import fields, normalize_selection, rel # noqa: F401
41
+ from .util import new_xid # noqa: F401
42
+
43
+ _default_client = None
44
+
45
+
46
+ def connect(endpoint, **config):
47
+ """Create a client and install it as the module default. Any previous
48
+ default is destroyed first (watches close, SSE drops)."""
49
+ global _default_client
50
+ prev = _default_client
51
+ _default_client = Client(endpoint, **config)
52
+ if prev:
53
+ prev.close()
54
+ return _default_client
55
+
56
+
57
+ def disconnect():
58
+ """Destroy and uninstall the default client. No-op when not connected."""
59
+ global _default_client
60
+ prev = _default_client
61
+ _default_client = None
62
+ if prev:
63
+ prev.close()
64
+
65
+
66
+ def get_client():
67
+ """The installed default client, or None."""
68
+ return _default_client
69
+
70
+
71
+ def _dflt():
72
+ if _default_client is None:
73
+ raise SynthigyError("not connected — call synthigy.connect() first",
74
+ "NOT_CONNECTED")
75
+ return _default_client
76
+
77
+
78
+ # ── module-default ASYNC client (twin of connect/disconnect) ─────────────
79
+
80
+ _default_async_client = None
81
+
82
+
83
+ def aconnect(endpoint, **config):
84
+ """Create an AsyncClient and install it as the module default — the
85
+ async twin of connect(); same one-process-one-client invariant.
86
+ Generated async typed ops (codegen) run on this default. A previous
87
+ default is closed detachedly when an event loop is running."""
88
+ global _default_async_client
89
+ prev = _default_async_client
90
+ _default_async_client = AsyncClient(endpoint, **config)
91
+ if prev:
92
+ import asyncio
93
+ try:
94
+ asyncio.get_running_loop()
95
+ asyncio.ensure_future(prev.close())
96
+ except RuntimeError:
97
+ pass # no loop — nothing live to tear down
98
+ return _default_async_client
99
+
100
+
101
+ async def adisconnect():
102
+ """Close and uninstall the default async client. No-op when absent."""
103
+ global _default_async_client
104
+ prev = _default_async_client
105
+ _default_async_client = None
106
+ if prev:
107
+ await prev.close()
108
+
109
+
110
+ def aclient():
111
+ """The installed default AsyncClient (raises NOT_CONNECTED if none)."""
112
+ if _default_async_client is None:
113
+ raise SynthigyError("not connected — call synthigy.aconnect() first",
114
+ "NOT_CONNECTED")
115
+ return _default_async_client
116
+
117
+
118
+ # CRUD + XSQL
119
+ def search(*a, **kw): return _dflt().search(*a, **kw)
120
+ def get(*a, **kw): return _dflt().get(*a, **kw)
121
+ def sync(*a, **kw): return _dflt().sync(*a, **kw)
122
+ def stack(*a, **kw): return _dflt().stack(*a, **kw)
123
+ def slice(*a, **kw): return _dflt().slice(*a, **kw) # noqa: A001
124
+ def delete(*a, **kw): return _dflt().delete(*a, **kw)
125
+ def purge(*a, **kw): return _dflt().purge(*a, **kw)
126
+ def sql_template(*a, **kw): return _dflt().sql_template(*a, **kw)
127
+ def query(*a, **kw): return _dflt().query(*a, **kw)
128
+ def search_tree(*a, **kw): return _dflt().search_tree(*a, **kw)
129
+ def get_tree(*a, **kw): return _dflt().get_tree(*a, **kw)
130
+ def exec_(*a, **kw): return _dflt().exec_(*a, **kw)
131
+
132
+
133
+ # Introspection
134
+ def schema(*a, **kw): return _dflt().schema(*a, **kw)
135
+ def lint(*a, **kw): return _dflt().lint(*a, **kw)
136
+ def onboard(*a, **kw): return _dflt().onboard(*a, **kw)
137
+ def onboard_complete(*a, **kw): return _dflt().onboard_complete(*a, **kw)
138
+ def deployed_model(*a, **kw): return _dflt().deployed_model(*a, **kw)
139
+ def runtime_model(*a, **kw): return _dflt().runtime_model(*a, **kw)
140
+ def token(*a, **kw): return _dflt().token(*a, **kw)
141
+ def history(): return _dflt().history
142
+
143
+
144
+ # Streaming
145
+ def listen(*a, **kw): return _dflt().listen(*a, **kw)
146
+ def observe(*a, **kw): return _dflt().observe(*a, **kw)
147
+
148
+
149
+ # Live data (watch layer)
150
+ def watch(*a, **kw): return _dflt().watch(*a, **kw)
151
+ def watch_schema(*a, **kw): return _dflt().watch_schema(*a, **kw)
152
+ def watch_query(*a, **kw): return _dflt().watch_query(*a, **kw)
153
+ def watch_query_xsql(*a, **kw): return _dflt().watch_query_xsql(*a, **kw)
154
+ def watch_sql_template(*a, **kw): return _dflt().watch_sql_template(*a, **kw)
155
+
156
+
157
+ # Subscriptions (advanced — prefer the watch family)
158
+ def subscribe(*a, **kw): return _dflt().subscribe(*a, **kw)
159
+ def unsubscribe(*a, **kw): return _dflt().unsubscribe(*a, **kw)
160
+ def subscribe_model(*a, **kw): return _dflt().subscribe_model(*a, **kw)
161
+ def unsubscribe_model(*a, **kw): return _dflt().unsubscribe_model(*a, **kw)
162
+ def set_subscriptions(*a, **kw): return _dflt().set_subscriptions(*a, **kw)
163
+ def clear_subscriptions(*a, **kw): return _dflt().clear_subscriptions(*a, **kw)
164
+ def subscriptions(*a, **kw): return _dflt().subscriptions(*a, **kw)