rootpy-client 1.31.1__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 (69) hide show
  1. rootpy_client-1.31.1/LICENSE +21 -0
  2. rootpy_client-1.31.1/MANIFEST.in +19 -0
  3. rootpy_client-1.31.1/PKG-INFO +157 -0
  4. rootpy_client-1.31.1/README.md +113 -0
  5. rootpy_client-1.31.1/pyproject.toml +90 -0
  6. rootpy_client-1.31.1/rootpy/__init__.py +393 -0
  7. rootpy_client-1.31.1/rootpy/_registry_loader.py +122 -0
  8. rootpy_client-1.31.1/rootpy/accounts.py +554 -0
  9. rootpy_client-1.31.1/rootpy/attach.py +243 -0
  10. rootpy_client-1.31.1/rootpy/auth.py +310 -0
  11. rootpy_client-1.31.1/rootpy/cache.py +190 -0
  12. rootpy_client-1.31.1/rootpy/client.py +1702 -0
  13. rootpy_client-1.31.1/rootpy/commands.py +444 -0
  14. rootpy_client-1.31.1/rootpy/data/enums.json +1 -0
  15. rootpy_client-1.31.1/rootpy/data/message_schemas.json +1 -0
  16. rootpy_client-1.31.1/rootpy/data/messages.json +1 -0
  17. rootpy_client-1.31.1/rootpy/data/rpc_services.json +1 -0
  18. rootpy_client-1.31.1/rootpy/data/services.json +1 -0
  19. rootpy_client-1.31.1/rootpy/discovery.py +578 -0
  20. rootpy_client-1.31.1/rootpy/dm_member.py +305 -0
  21. rootpy_client-1.31.1/rootpy/domain_managers.py +677 -0
  22. rootpy_client-1.31.1/rootpy/emoji.py +129 -0
  23. rootpy_client-1.31.1/rootpy/enums.py +315 -0
  24. rootpy_client-1.31.1/rootpy/events.py +153 -0
  25. rootpy_client-1.31.1/rootpy/exceptions.py +687 -0
  26. rootpy_client-1.31.1/rootpy/features.py +949 -0
  27. rootpy_client-1.31.1/rootpy/gateway.py +1477 -0
  28. rootpy_client-1.31.1/rootpy/generated_rpc_registry.py +18 -0
  29. rootpy_client-1.31.1/rootpy/highlevel.py +1472 -0
  30. rootpy_client-1.31.1/rootpy/host.py +594 -0
  31. rootpy_client-1.31.1/rootpy/identifiers.py +119 -0
  32. rootpy_client-1.31.1/rootpy/media.py +43 -0
  33. rootpy_client-1.31.1/rootpy/media_bootstrap.py +111 -0
  34. rootpy_client-1.31.1/rootpy/models.py +944 -0
  35. rootpy_client-1.31.1/rootpy/object_api.py +606 -0
  36. rootpy_client-1.31.1/rootpy/packet_schemas.py +181 -0
  37. rootpy_client-1.31.1/rootpy/packets.py +176 -0
  38. rootpy_client-1.31.1/rootpy/pagination.py +31 -0
  39. rootpy_client-1.31.1/rootpy/permissions.py +237 -0
  40. rootpy_client-1.31.1/rootpy/presence.py +173 -0
  41. rootpy_client-1.31.1/rootpy/protocol.py +164 -0
  42. rootpy_client-1.31.1/rootpy/py.typed +0 -0
  43. rootpy_client-1.31.1/rootpy/raw_api.py +244 -0
  44. rootpy_client-1.31.1/rootpy/responses.py +110 -0
  45. rootpy_client-1.31.1/rootpy/root_exception.py +306 -0
  46. rootpy_client-1.31.1/rootpy/service_facade.py +32 -0
  47. rootpy_client-1.31.1/rootpy/services/__init__.py +27 -0
  48. rootpy_client-1.31.1/rootpy/services/assets.py +503 -0
  49. rootpy_client-1.31.1/rootpy/services/calls.py +1411 -0
  50. rootpy_client-1.31.1/rootpy/services/communities.py +735 -0
  51. rootpy_client-1.31.1/rootpy/services/community_admin.py +1036 -0
  52. rootpy_client-1.31.1/rootpy/services/direct_messages.py +524 -0
  53. rootpy_client-1.31.1/rootpy/services/discovery.py +204 -0
  54. rootpy_client-1.31.1/rootpy/services/messages.py +811 -0
  55. rootpy_client-1.31.1/rootpy/services/users.py +440 -0
  56. rootpy_client-1.31.1/rootpy/stats.py +208 -0
  57. rootpy_client-1.31.1/rootpy/structured_api.py +956 -0
  58. rootpy_client-1.31.1/rootpy/structured_registry.py +61 -0
  59. rootpy_client-1.31.1/rootpy/transport.py +403 -0
  60. rootpy_client-1.31.1/rootpy/typed_events.py +496 -0
  61. rootpy_client-1.31.1/rootpy/unread.py +546 -0
  62. rootpy_client-1.31.1/rootpy/users.py +187 -0
  63. rootpy_client-1.31.1/rootpy/validation.py +145 -0
  64. rootpy_client-1.31.1/rootpy_client.egg-info/PKG-INFO +157 -0
  65. rootpy_client-1.31.1/rootpy_client.egg-info/SOURCES.txt +67 -0
  66. rootpy_client-1.31.1/rootpy_client.egg-info/dependency_links.txt +1 -0
  67. rootpy_client-1.31.1/rootpy_client.egg-info/requires.txt +14 -0
  68. rootpy_client-1.31.1/rootpy_client.egg-info/top_level.txt +1 -0
  69. rootpy_client-1.31.1/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 solluws
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,19 @@
1
+ # The sdist is the library plus the two documents a reader needs offline.
2
+ # Everything else in this repository -- the test suite, the examples and the
3
+ # CI configuration -- is repository material and is deliberately left out of
4
+ # the distribution.
5
+ include LICENSE README.md
6
+
7
+ # The protocol registries. Without them the package installs and every schema
8
+ # lookup raises, so this line is load-bearing in the sdist exactly as
9
+ # [tool.setuptools.package-data] is in the wheel.
10
+ recursive-include rootpy/data *.json
11
+
12
+ # PEP 561 marker for the "Typing :: Typed" classifier.
13
+ include rootpy/py.typed
14
+
15
+ prune tests
16
+ prune examples
17
+ prune .github
18
+
19
+ global-exclude *.py[cod] __pycache__/* *.log tokens*.txt *.token .env
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: rootpy-client
3
+ Version: 1.31.1
4
+ Summary: Async Python client for the Root chat platform
5
+ Author: solluws
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://rootpy.gay
8
+ Project-URL: Documentation, https://rootpy.gay
9
+ Project-URL: Repository, https://github.com/solluws/rap-p-ers
10
+ Project-URL: Issues, https://github.com/solluws/rap-p-ers/issues
11
+ Keywords: root,rootapp,chat,async,asyncio,grpc-web,websocket,bot,api-client
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Framework :: AsyncIO
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Communications :: Chat
25
+ Classifier: Topic :: Internet
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: httpx[http2]>=0.27
32
+ Requires-Dist: websockets>=12.0
33
+ Requires-Dist: emoji>=2.0
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=8.0; extra == "dev"
36
+ Requires-Dist: pytest-asyncio>=0.26; extra == "dev"
37
+ Requires-Dist: httpx[socks]>=0.27; extra == "dev"
38
+ Provides-Extra: voice
39
+ Requires-Dist: av>=15.1; extra == "voice"
40
+ Requires-Dist: aiortc>=1.13; extra == "voice"
41
+ Requires-Dist: imageio-ffmpeg<1,>=0.5; extra == "voice"
42
+ Requires-Dist: playwright>=1.44; extra == "voice"
43
+ Dynamic: license-file
44
+
45
+ # rootpy-client
46
+
47
+ [![tests](https://github.com/solluws/rap-p-ers/actions/workflows/tests.yml/badge.svg)](https://github.com/solluws/rap-p-ers/actions/workflows/tests.yml)
48
+ [![python](https://img.shields.io/badge/python-3.10%2B-blue)](https://pypi.org/project/rootpy-client/)
49
+ [![license](https://img.shields.io/badge/license-MIT-green)](https://github.com/solluws/rap-p-ers/blob/main/LICENSE)
50
+
51
+ An async Python client for the [Root](https://rootapp.com) chat platform. It
52
+ drives one account — yours — from a script or a bot, and covers messaging,
53
+ communities, channels, roles, direct messages, friends, presence, voice
54
+ signalling and the real-time gateway.
55
+
56
+ Unofficial. Not affiliated with Root, and not endorsed by them.
57
+
58
+ **Guides, examples and the full API reference: <https://rootpy.gay>**
59
+
60
+ ## Install
61
+
62
+ ```bash
63
+ pip install rootpy-client
64
+ ```
65
+
66
+ You install `rootpy-client` and you import `rootpy`. The two names differ
67
+ because an unrelated project already holds `rootpy` on PyPI. This is not that
68
+ project.
69
+
70
+ Python 3.10 or later. Playing audio into a voice call needs an opt-in extra:
71
+ `pip install "rootpy-client[voice]"`.
72
+
73
+ ## Use it
74
+
75
+ ```python
76
+ import asyncio
77
+ import os
78
+
79
+ from rootpy import RootClient
80
+
81
+
82
+ async def main():
83
+ client = RootClient(token=os.environ["ROOT_TOKEN"])
84
+ await client.login_token()
85
+
86
+ await client.messages.send(CHANNEL_ID, "hello", community_id=COMMUNITY_ID)
87
+
88
+ await client.close()
89
+
90
+
91
+ asyncio.run(main())
92
+ ```
93
+
94
+ Receiving needs the gateway, and a community delivers nothing until you attach
95
+ to it:
96
+
97
+ ```python
98
+ @client.event
99
+ async def on_message(event):
100
+ print(event.message.content)
101
+
102
+
103
+ async with client.community.held(COMMUNITY_ID):
104
+ await client.connect()
105
+ await client.wait_until_ready()
106
+ await asyncio.sleep(3600)
107
+ ```
108
+
109
+ ## What is in it
110
+
111
+ - **Messages** — send, reply in a thread, edit, delete, react, pin, and
112
+ paginated history.
113
+ - **Communities** — create, join by invite, channels and channel groups, roles
114
+ and permissions, members, invites, emoji and assets.
115
+ - **Discovery** — search the public directory, and list your own community.
116
+ - **Direct messages** — conversations, group conversations, friends and blocks.
117
+ - **Gateway** — a websocket connection with typed events, `wait_for()` and
118
+ reconnection.
119
+ - **Voice** — call signalling, mute and deafen, and audio playback behind the
120
+ `[voice]` extra.
121
+ - **Auth** — token login, email and password login, and signup.
122
+
123
+ ## Notes worth knowing before you start
124
+
125
+ - **Membership is not a subscription.** Until you call
126
+ `client.community.attach(id)`, the hub sends no packet for that community at
127
+ all, while direct messages and mentions keep arriving on the same socket.
128
+ That asymmetry is what a broken listener looks like.
129
+ - **The gateway is a resync cycle, not a persistent stream.** The hub sends a
130
+ batch, closes with code 1000, and expects a reconnect. That is normal. An
131
+ attach does not survive it, so hold it with `client.community.held(id)`.
132
+ - **Presence is two calls, and the lower one wins.** Others see
133
+ `min(ceiling, device)`. Both halves succeed on their own, so setting only the
134
+ ceiling leaves your account invisible to everybody and reports success.
135
+ `client.set_presence(...)` sets both.
136
+
137
+ ## Develop
138
+
139
+ ```bash
140
+ git clone https://github.com/solluws/rap-p-ers
141
+ cd rap-p-ers
142
+ pip install -e ".[dev]"
143
+ python -m pytest -q
144
+ ```
145
+
146
+ The suite is offline. It pins the wire format, so a change to an endpoint, a
147
+ field number or a default fails a test rather than a live request.
148
+
149
+ Pull requests are welcome. Keep the tests green, and add one for whatever you
150
+ change.
151
+
152
+ ## Licence
153
+
154
+ MIT. See [LICENSE](https://github.com/solluws/rap-p-ers/blob/main/LICENSE).
155
+
156
+ Use this on accounts you control, and read Root's terms before you automate
157
+ anything on their service.
@@ -0,0 +1,113 @@
1
+ # rootpy-client
2
+
3
+ [![tests](https://github.com/solluws/rap-p-ers/actions/workflows/tests.yml/badge.svg)](https://github.com/solluws/rap-p-ers/actions/workflows/tests.yml)
4
+ [![python](https://img.shields.io/badge/python-3.10%2B-blue)](https://pypi.org/project/rootpy-client/)
5
+ [![license](https://img.shields.io/badge/license-MIT-green)](https://github.com/solluws/rap-p-ers/blob/main/LICENSE)
6
+
7
+ An async Python client for the [Root](https://rootapp.com) chat platform. It
8
+ drives one account — yours — from a script or a bot, and covers messaging,
9
+ communities, channels, roles, direct messages, friends, presence, voice
10
+ signalling and the real-time gateway.
11
+
12
+ Unofficial. Not affiliated with Root, and not endorsed by them.
13
+
14
+ **Guides, examples and the full API reference: <https://rootpy.gay>**
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install rootpy-client
20
+ ```
21
+
22
+ You install `rootpy-client` and you import `rootpy`. The two names differ
23
+ because an unrelated project already holds `rootpy` on PyPI. This is not that
24
+ project.
25
+
26
+ Python 3.10 or later. Playing audio into a voice call needs an opt-in extra:
27
+ `pip install "rootpy-client[voice]"`.
28
+
29
+ ## Use it
30
+
31
+ ```python
32
+ import asyncio
33
+ import os
34
+
35
+ from rootpy import RootClient
36
+
37
+
38
+ async def main():
39
+ client = RootClient(token=os.environ["ROOT_TOKEN"])
40
+ await client.login_token()
41
+
42
+ await client.messages.send(CHANNEL_ID, "hello", community_id=COMMUNITY_ID)
43
+
44
+ await client.close()
45
+
46
+
47
+ asyncio.run(main())
48
+ ```
49
+
50
+ Receiving needs the gateway, and a community delivers nothing until you attach
51
+ to it:
52
+
53
+ ```python
54
+ @client.event
55
+ async def on_message(event):
56
+ print(event.message.content)
57
+
58
+
59
+ async with client.community.held(COMMUNITY_ID):
60
+ await client.connect()
61
+ await client.wait_until_ready()
62
+ await asyncio.sleep(3600)
63
+ ```
64
+
65
+ ## What is in it
66
+
67
+ - **Messages** — send, reply in a thread, edit, delete, react, pin, and
68
+ paginated history.
69
+ - **Communities** — create, join by invite, channels and channel groups, roles
70
+ and permissions, members, invites, emoji and assets.
71
+ - **Discovery** — search the public directory, and list your own community.
72
+ - **Direct messages** — conversations, group conversations, friends and blocks.
73
+ - **Gateway** — a websocket connection with typed events, `wait_for()` and
74
+ reconnection.
75
+ - **Voice** — call signalling, mute and deafen, and audio playback behind the
76
+ `[voice]` extra.
77
+ - **Auth** — token login, email and password login, and signup.
78
+
79
+ ## Notes worth knowing before you start
80
+
81
+ - **Membership is not a subscription.** Until you call
82
+ `client.community.attach(id)`, the hub sends no packet for that community at
83
+ all, while direct messages and mentions keep arriving on the same socket.
84
+ That asymmetry is what a broken listener looks like.
85
+ - **The gateway is a resync cycle, not a persistent stream.** The hub sends a
86
+ batch, closes with code 1000, and expects a reconnect. That is normal. An
87
+ attach does not survive it, so hold it with `client.community.held(id)`.
88
+ - **Presence is two calls, and the lower one wins.** Others see
89
+ `min(ceiling, device)`. Both halves succeed on their own, so setting only the
90
+ ceiling leaves your account invisible to everybody and reports success.
91
+ `client.set_presence(...)` sets both.
92
+
93
+ ## Develop
94
+
95
+ ```bash
96
+ git clone https://github.com/solluws/rap-p-ers
97
+ cd rap-p-ers
98
+ pip install -e ".[dev]"
99
+ python -m pytest -q
100
+ ```
101
+
102
+ The suite is offline. It pins the wire format, so a change to an endpoint, a
103
+ field number or a default fails a test rather than a live request.
104
+
105
+ Pull requests are welcome. Keep the tests green, and add one for whatever you
106
+ change.
107
+
108
+ ## Licence
109
+
110
+ MIT. See [LICENSE](https://github.com/solluws/rap-p-ers/blob/main/LICENSE).
111
+
112
+ Use this on accounts you control, and read Root's terms before you automate
113
+ anything on their service.
@@ -0,0 +1,90 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "rootpy-client"
7
+ version = "1.31.1"
8
+ description = "Async Python client for the Root chat platform"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "solluws" }]
13
+ requires-python = ">=3.10"
14
+ keywords = [
15
+ "root",
16
+ "rootapp",
17
+ "chat",
18
+ "async",
19
+ "asyncio",
20
+ "grpc-web",
21
+ "websocket",
22
+ "bot",
23
+ "api-client",
24
+ ]
25
+ classifiers = [
26
+ "Development Status :: 4 - Beta",
27
+ "Framework :: AsyncIO",
28
+ "Intended Audience :: Developers",
29
+ "Operating System :: OS Independent",
30
+ "Programming Language :: Python",
31
+ "Programming Language :: Python :: 3",
32
+ "Programming Language :: Python :: 3 :: Only",
33
+ "Programming Language :: Python :: 3.10",
34
+ "Programming Language :: Python :: 3.11",
35
+ "Programming Language :: Python :: 3.12",
36
+ "Programming Language :: Python :: 3.13",
37
+ "Programming Language :: Python :: 3.14",
38
+ "Topic :: Communications :: Chat",
39
+ "Topic :: Internet",
40
+ "Topic :: Software Development :: Libraries :: Python Modules",
41
+ "Typing :: Typed",
42
+ ]
43
+ dependencies = [
44
+ "httpx[http2]>=0.27",
45
+ "websockets>=12.0",
46
+ # Reactions are a core verb, and Root addresses every reaction by
47
+ # shortcode. Without this, rootpy/emoji.py falls back to a 20-entry table
48
+ # and refuses ordinary emoji -- a rocket and a pair of eyes both raised
49
+ # ValueError on a stock install. Pure Python, no transitive dependencies.
50
+ "emoji>=2.0",
51
+ ]
52
+
53
+ [project.urls]
54
+ Homepage = "https://rootpy.gay"
55
+ Documentation = "https://rootpy.gay"
56
+ Repository = "https://github.com/solluws/rap-p-ers"
57
+ Issues = "https://github.com/solluws/rap-p-ers/issues"
58
+
59
+ [project.optional-dependencies]
60
+ # httpx[socks] is a test requirement, not a runtime one. SOCKS support stays
61
+ # optional for users. The proxy tests build a real httpx.AsyncClient with a
62
+ # socks5h:// URL, and httpx needs socksio for that scheme.
63
+ dev = ["pytest>=8.0", "pytest-asyncio>=0.26", "httpx[socks]>=0.27"]
64
+ # Voice / WebRTC. Never installed automatically -- rootpy raises
65
+ # MediaDependencyMissing naming this extra instead of shelling out to pip.
66
+ voice = [
67
+ "av>=15.1",
68
+ "aiortc>=1.13",
69
+ "imageio-ffmpeg>=0.5,<1",
70
+ "playwright>=1.44",
71
+ ]
72
+
73
+ [tool.setuptools.packages.find]
74
+ include = ["rootpy*"]
75
+ # examples/ lives at the repo root; it is documentation, not shipped code.
76
+ exclude = ["rootpy.examples*", "tests*"]
77
+
78
+ [tool.setuptools.package-data]
79
+ # The protocol registries and the PEP 561 marker. Without the JSON the wheel
80
+ # installs but every schema lookup raises at runtime.
81
+ rootpy = ["data/*.json", "py.typed"]
82
+
83
+ [tool.pytest.ini_options]
84
+ testpaths = ["tests"]
85
+ asyncio_mode = "auto"
86
+ # Session-scoped async fixtures and tests must share one event loop; with the
87
+ # default function scope the first test to finish closes the loop the fixtures
88
+ # were created on.
89
+ asyncio_default_fixture_loop_scope = "session"
90
+ asyncio_default_test_loop_scope = "session"