mosir-sdk-python 0.1.1__tar.gz → 0.1.3__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 (22) hide show
  1. mosir_sdk_python-0.1.3/PKG-INFO +386 -0
  2. mosir_sdk_python-0.1.3/README.md +360 -0
  3. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/public.graphqls +17 -0
  4. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/public.operations.graphql +24 -2
  5. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/pyproject.toml +1 -1
  6. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk/_operations.py +8 -2
  7. mosir_sdk_python-0.1.3/src/mosir_sdk_python.egg-info/PKG-INFO +386 -0
  8. mosir_sdk_python-0.1.1/PKG-INFO +0 -219
  9. mosir_sdk_python-0.1.1/README.md +0 -193
  10. mosir_sdk_python-0.1.1/src/mosir_sdk_python.egg-info/PKG-INFO +0 -219
  11. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/LICENSE +0 -0
  12. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/MANIFEST.in +0 -0
  13. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/setup.cfg +0 -0
  14. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk/__init__.py +0 -0
  15. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk/client.py +0 -0
  16. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk/exceptions.py +0 -0
  17. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk/py.typed +0 -0
  18. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk_python.egg-info/SOURCES.txt +0 -0
  19. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk_python.egg-info/dependency_links.txt +0 -0
  20. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk_python.egg-info/requires.txt +0 -0
  21. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/src/mosir_sdk_python.egg-info/top_level.txt +0 -0
  22. {mosir_sdk_python-0.1.1 → mosir_sdk_python-0.1.3}/tests/test_client.py +0 -0
@@ -0,0 +1,386 @@
1
+ Metadata-Version: 2.4
2
+ Name: mosir-sdk-python
3
+ Version: 0.1.3
4
+ Summary: Python SDK for the Mosir public GraphQL API
5
+ Author-email: catLee <leemiyinghao@gmx.com>
6
+ License-Expression: LGPL-3.0-or-later
7
+ Project-URL: Homepage, https://beta.mosir.app
8
+ Project-URL: Repository, https://github.com/mosir-social/mosir-sdk-python
9
+ Project-URL: Issues, https://github.com/mosir-social/mosir-sdk-python/issues
10
+ Project-URL: Documentation, https://github.com/mosir-social/mosir-sdk-python#readme
11
+ Keywords: graphql,httpx,mosir,sdk,sse
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Internet :: WWW/HTTP
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: graphql-core>=3.2.8
22
+ Requires-Dist: httpx>=0.28.1
23
+ Requires-Dist: httpx-sse>=0.4.3
24
+ Requires-Dist: pydantic>=2.13.4
25
+ Dynamic: license-file
26
+
27
+ # mosir-sdk-python
28
+
29
+ Python SDK for the Mosir public GraphQL API.
30
+
31
+ ## What this SDK provides
32
+
33
+ - generated operation registry from `public.operations.graphql`
34
+ - dynamic snake_case operation methods (query, mutation, subscription)
35
+ - optional Bearer token auth
36
+ - default endpoint: `https://beta.mosir.app/api/v1`
37
+ - SSE subscription support out of the box
38
+ - raw GraphQL access for developers who want direct control
39
+
40
+ ## Transport choice
41
+
42
+ This SDK uses:
43
+
44
+ - `httpx` for queries and mutations
45
+ - `httpx-sse` for subscriptions
46
+
47
+ This keeps the package small while still supporting the preferred subscription transport.
48
+ WebSocket support is intentionally not bundled. If you want WebSocket subscriptions, use your own GraphQL/WebSocket client.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ pip install mosir-sdk-python
54
+ ```
55
+
56
+ or:
57
+
58
+ ```bash
59
+ uv add mosir-sdk-python
60
+ ```
61
+
62
+ ## Quick start
63
+
64
+ ### Anonymous/public requests
65
+
66
+ Only public data needs no token.
67
+
68
+ ```python
69
+ import asyncio
70
+
71
+ from mosir_sdk import AsyncMosirClient
72
+
73
+
74
+ async def main() -> None:
75
+ async with AsyncMosirClient() as client:
76
+ post = await client.get_post(post_id="VLO8u7UXqclQ7byjfMEX0")
77
+ print(post["getPost"]["content"])
78
+
79
+
80
+ asyncio.run(main())
81
+ ```
82
+
83
+ ### Authenticated requests
84
+
85
+ Use a token for authenticated operations such as notifications.
86
+
87
+ ```python
88
+ import asyncio
89
+ import os
90
+
91
+ from mosir_sdk import AsyncMosirClient
92
+
93
+
94
+ async def main() -> None:
95
+ async with AsyncMosirClient(token=os.getenv("MOSIR_API_TOKEN")) as client:
96
+ notifications = await client.get_notifications(limit=20)
97
+ print(notifications["getNotifications"]["edges"])
98
+
99
+
100
+ asyncio.run(main())
101
+ ```
102
+
103
+ ## Custom endpoint
104
+
105
+ ```python
106
+ from mosir_sdk import AsyncMosirClient
107
+
108
+ client = AsyncMosirClient(
109
+ token="YOUR_TOKEN",
110
+ endpoint="https://example.com/api/v1",
111
+ )
112
+ ```
113
+
114
+ ## Common usage examples
115
+
116
+ ### Get a post
117
+
118
+ ```python
119
+ import asyncio
120
+
121
+ from mosir_sdk import AsyncMosirClient
122
+
123
+
124
+ async def main() -> None:
125
+ async with AsyncMosirClient() as client:
126
+ post = await client.get_post(post_id="VLO8u7UXqclQ7byjfMEX0")
127
+ print(post["getPost"]["author"]["username"])
128
+ print(post["getPost"]["content"])
129
+
130
+
131
+ asyncio.run(main())
132
+ ```
133
+
134
+ ### Get replies under a post
135
+
136
+ Replies are exposed as nested GraphQL fields on `Post`, so this is a good case for direct GraphQL usage:
137
+
138
+ ```python
139
+ import asyncio
140
+
141
+ from mosir_sdk import AsyncMosirClient
142
+
143
+
144
+ async def main() -> None:
145
+ async with AsyncMosirClient() as client:
146
+ replies = await client.request(
147
+ """
148
+ query GetPostReplies($postId: ID!, $limit: Int) {
149
+ getPost(postId: $postId) {
150
+ id
151
+ commentsRecent(limit: $limit) {
152
+ edges {
153
+ id
154
+ content
155
+ createdAt
156
+ author {
157
+ id
158
+ username
159
+ displayName
160
+ }
161
+ }
162
+ pageInfo {
163
+ endCursor
164
+ hasNextPage
165
+ totalCount
166
+ }
167
+ }
168
+ }
169
+ }
170
+ """,
171
+ {
172
+ "postId": "VLO8u7UXqclQ7byjfMEX0",
173
+ "limit": 3,
174
+ },
175
+ )
176
+
177
+ print(replies["getPost"]["commentsRecent"]["edges"])
178
+
179
+
180
+ asyncio.run(main())
181
+ ```
182
+
183
+ ### Get notifications
184
+
185
+ ```python
186
+ import asyncio
187
+ import os
188
+
189
+ from mosir_sdk import AsyncMosirClient
190
+
191
+
192
+ async def main() -> None:
193
+ async with AsyncMosirClient(token=os.getenv("MOSIR_API_TOKEN")) as client:
194
+ notifications = await client.get_notifications(limit=20)
195
+ print(notifications["getNotifications"]["edges"])
196
+
197
+
198
+ asyncio.run(main())
199
+ ```
200
+
201
+ ### Fetch media bytes from a `Media` result
202
+
203
+ ```python
204
+ import asyncio
205
+
206
+ from mosir_sdk import AsyncMosirClient
207
+
208
+
209
+ async def main() -> None:
210
+ async with AsyncMosirClient() as client:
211
+ post = await client.get_post(post_id="VLO8u7UXqclQ7byjfMEX0")
212
+ media = post["getPost"]["attachments"][0]["media"]
213
+ media_bytes = await client.fetch_media(media)
214
+ print(len(media_bytes))
215
+
216
+
217
+ asyncio.run(main())
218
+ ```
219
+
220
+ ### Fetch preview image for a post, profile, or collection
221
+
222
+ ```python
223
+ import asyncio
224
+
225
+ from mosir_sdk import AsyncMosirClient
226
+
227
+
228
+ async def main() -> None:
229
+ async with AsyncMosirClient() as client:
230
+ preview_url = client.get_preview_image_url("post", "VLO8u7UXqclQ7byjfMEX0")
231
+ print(preview_url)
232
+
233
+ preview_bytes = await client.fetch_preview_image("post", "VLO8u7UXqclQ7byjfMEX0")
234
+ print(len(preview_bytes))
235
+
236
+
237
+ asyncio.run(main())
238
+ ```
239
+
240
+ ## SSE subscriptions
241
+
242
+ Subscriptions let your app receive updates from Mosir in near real time without polling.
243
+ This SDK uses **SSE** (Server-Sent Events) for subscriptions by default.
244
+
245
+ A good example is a Discord bot:
246
+ - subscribe to `post_created_by_author`
247
+ - when a creator publishes something new, format it
248
+ - send a message into a Discord channel
249
+
250
+ That way the bot reacts as soon as something changes, instead of repeatedly calling the API every few seconds.
251
+ SSE is especially useful for backend workers, bots, notification relays, and other long-running processes that want a simple one-way stream of events from the server.
252
+ For public subscriptions like `post_created_by_author`, a token is not required.
253
+
254
+ Note: each SSE connection lasts at most 1 hour. In practice, network conditions may cause it to end earlier.
255
+ If you build a bot, worker, or relay process, make sure you implement reconnect logic.
256
+
257
+ ```python
258
+ import asyncio
259
+
260
+ from mosir_sdk import AsyncMosirClient
261
+
262
+
263
+ async def main() -> None:
264
+ async with AsyncMosirClient() as client:
265
+ profile = await client.get_account_profile(username="leemiyinghao")
266
+ author_id = profile["getAccountProfile"]["id"]
267
+
268
+ async for event in client.post_created_by_author(
269
+ author_id=author_id,
270
+ post_type="POST",
271
+ ):
272
+ print(event["postCreatedByAuthor"]["id"])
273
+ print(event["postCreatedByAuthor"]["content"])
274
+
275
+
276
+ asyncio.run(main())
277
+ ```
278
+
279
+ You can also use the lower-level operation subscription API:
280
+
281
+ ```python
282
+ stream = client.subscribe_operation(
283
+ "post_created_by_author",
284
+ author_id=author_id,
285
+ post_type="POST",
286
+ )
287
+ ```
288
+
289
+ ## Raw GraphQL access
290
+
291
+ Authentication is optional. Pass `token` for authenticated operations, or omit it when accessing only public data.
292
+
293
+ ### Operation usage
294
+
295
+ ```python
296
+ data = await client.operation("get_notifications", limit=20)
297
+ ```
298
+
299
+ ### Raw GraphQL string usage
300
+
301
+ ```python
302
+ replies = await client.request(
303
+ """
304
+ query GetPostReplies($postId: ID!, $limit: Int) {
305
+ getPost(postId: $postId) {
306
+ id
307
+ commentsRecent(limit: $limit) {
308
+ edges {
309
+ id
310
+ content
311
+ createdAt
312
+ author {
313
+ username
314
+ displayName
315
+ }
316
+ }
317
+ }
318
+ }
319
+ }
320
+ """,
321
+ {
322
+ "postId": "VLO8u7UXqclQ7byjfMEX0",
323
+ "limit": 3,
324
+ },
325
+ )
326
+ ```
327
+
328
+ ## WebSocket usage
329
+
330
+ WebSocket transport is not bundled.
331
+ If you want it, use your own GraphQL WebSocket client against the same endpoint.
332
+
333
+ ## Notes
334
+
335
+ - default endpoint: `https://beta.mosir.app/api/v1`
336
+ - `token` is optional for public data and required only for authenticated operations
337
+ - the same applies to subscriptions: public subscription data does not require a token
338
+ - snake_case methods are resolved dynamically from the operation registry
339
+ - media helpers are available through `select_media_file(...)` and `fetch_media(...)`
340
+ - preview image helpers are available through `get_preview_image_url(...)` and `fetch_preview_image(...)`
341
+ - subscriptions use SSE in this SDK
342
+ - direct GraphQL usage is supported through `operation(...)`, `request(...)`, `subscribe_operation(...)`, and `subscribe(...)`
343
+
344
+ ## Development
345
+
346
+ ### Install
347
+
348
+ ```bash
349
+ task install
350
+ ```
351
+
352
+ ### Generate code
353
+
354
+ ```bash
355
+ task codegen
356
+ ```
357
+
358
+ ### Typecheck
359
+
360
+ ```bash
361
+ task pyright
362
+ ```
363
+
364
+ ### Build
365
+
366
+ ```bash
367
+ task build
368
+ ```
369
+
370
+ ### Full check
371
+
372
+ ```bash
373
+ task check
374
+ ```
375
+
376
+ ## Repo artifacts
377
+
378
+ - `public.graphqls` — copied public schema artifact
379
+ - `public.operations.graphql` — copied curated operation document
380
+ - `src/mosir_sdk/_operations.py` — generated operation registry
381
+ - `src/mosir_sdk/client.py` — async client and helpers
382
+
383
+ ## License
384
+
385
+ This project is licensed under the GNU Lesser General Public License v3.0 (LGPL-3.0).
386
+ See [`LICENSE`](./LICENSE) for details.