gramlab 0.1.0a1__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 (41) hide show
  1. gramlab-0.1.0a1/LICENSE +24 -0
  2. gramlab-0.1.0a1/LICENSES/BSL-1.0.txt +23 -0
  3. gramlab-0.1.0a1/NOTICE +40 -0
  4. gramlab-0.1.0a1/PKG-INFO +124 -0
  5. gramlab-0.1.0a1/README.md +97 -0
  6. gramlab-0.1.0a1/pyproject.toml +98 -0
  7. gramlab-0.1.0a1/pyproject.toml.orig +77 -0
  8. gramlab-0.1.0a1/src/gramlab/README.md +6 -0
  9. gramlab-0.1.0a1/src/gramlab/__init__.py +36 -0
  10. gramlab-0.1.0a1/src/gramlab/__main__.py +46 -0
  11. gramlab-0.1.0a1/src/gramlab/_android.py +714 -0
  12. gramlab-0.1.0a1/src/gramlab/_android_rich_buttons.py +946 -0
  13. gramlab-0.1.0a1/src/gramlab/_captures.py +123 -0
  14. gramlab-0.1.0a1/src/gramlab/_client_bridge_schema.py +477 -0
  15. gramlab-0.1.0a1/src/gramlab/_composer.py +79 -0
  16. gramlab-0.1.0a1/src/gramlab/_control.py +238 -0
  17. gramlab-0.1.0a1/src/gramlab/_document_metadata.py +314 -0
  18. gramlab-0.1.0a1/src/gramlab/_emoji_media.py +431 -0
  19. gramlab-0.1.0a1/src/gramlab/_emoji_text.py +66 -0
  20. gramlab-0.1.0a1/src/gramlab/_emulator.py +72 -0
  21. gramlab-0.1.0a1/src/gramlab/_interactions.py +185 -0
  22. gramlab-0.1.0a1/src/gramlab/_media_group_topology.py +303 -0
  23. gramlab-0.1.0a1/src/gramlab/_message_publication.py +220 -0
  24. gramlab-0.1.0a1/src/gramlab/_processes.py +247 -0
  25. gramlab-0.1.0a1/src/gramlab/_rich_button_journal.py +966 -0
  26. gramlab-0.1.0a1/src/gramlab/_rich_buttons.py +231 -0
  27. gramlab-0.1.0a1/src/gramlab/_rich_interactions.py +427 -0
  28. gramlab-0.1.0a1/src/gramlab/_run.py +143 -0
  29. gramlab-0.1.0a1/src/gramlab/bot_api.py +796 -0
  30. gramlab-0.1.0a1/src/gramlab/client_bridge.py +351 -0
  31. gramlab-0.1.0a1/src/gramlab/documents.py +97 -0
  32. gramlab-0.1.0a1/src/gramlab/entities.py +135 -0
  33. gramlab-0.1.0a1/src/gramlab/media.py +51 -0
  34. gramlab-0.1.0a1/src/gramlab/py.typed +0 -0
  35. gramlab-0.1.0a1/src/gramlab/reports.py +464 -0
  36. gramlab-0.1.0a1/src/gramlab/rich_messages.py +764 -0
  37. gramlab-0.1.0a1/src/gramlab/runner.py +292 -0
  38. gramlab-0.1.0a1/src/gramlab/runtime.py +298 -0
  39. gramlab-0.1.0a1/src/gramlab/scenario.py +520 -0
  40. gramlab-0.1.0a1/src/gramlab/scenario_flow.py +470 -0
  41. gramlab-0.1.0a1/src/gramlab/world.py +2056 -0
@@ -0,0 +1,24 @@
1
+ Scope: original GramLab work only. Separately licensed components are listed
2
+ in NOTICE and retain their own terms.
3
+
4
+ MIT License
5
+
6
+ Copyright (c) 2026 GramLab contributors
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
@@ -0,0 +1,23 @@
1
+ Boost Software License - Version 1.0 - August 17th, 2003
2
+
3
+ Permission is hereby granted, free of charge, to any person or organization
4
+ obtaining a copy of the software and accompanying documentation covered by
5
+ this license (the "Software") to use, reproduce, display, distribute,
6
+ execute, and transmit the Software, and to prepare derivative works of the
7
+ Software, and to permit third-parties to whom the Software is furnished to
8
+ do so, all subject to the following:
9
+
10
+ The copyright notices in the Software and this entire statement, including
11
+ the above license grant, this restriction and the following disclaimer,
12
+ must be included in all copies of the Software, in whole or in part, and
13
+ all derivative works of the Software, unless such copies or derivative
14
+ works are solely in the form of machine-executable object code generated by
15
+ a source language processor.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ DEALINGS IN THE SOFTWARE.
gramlab-0.1.0a1/NOTICE ADDED
@@ -0,0 +1,40 @@
1
+ GramLab source and license notices
2
+ =================================
3
+
4
+ Original GramLab core, SDK, tools, documentation and original generated media
5
+ fixtures are licensed under MIT (LICENSE), except where a file or directory
6
+ identifies different terms below. The root MIT license does not relicense
7
+ third-party works or the Android-derived components.
8
+
9
+ Python package: MIT AND BSL-1.0
10
+ -----------------------------
11
+ src/gramlab/_emoji_text.py and src/gramlab/_document_metadata.py adapt TDLib
12
+ code/data under the Boost Software License 1.0. Each module retains the upstream
13
+ copyright and full license. LICENSES/BSL-1.0.txt supplies a separate license copy.
14
+ Document metadata reference fixtures retain their notice in
15
+ tests/fixtures/document_metadata/LICENSE_1_0.txt.
16
+ Exact upstream revisions, hashes and adaptation scope are recorded in:
17
+ docs/development/tdlib-emoji-provenance.json
18
+ docs/development/tdlib-document-metadata-provenance.json
19
+
20
+ Android-derived source: GPL-2.0-or-later
21
+ --------------------------------------
22
+ clients/android/patches/ contains patches to Telegram Android, including upstream
23
+ context. Android-derived Java/C++ test fixtures under tests/fixtures/ retain their
24
+ per-file GPL-2.0-or-later headers. These are separate from the Python package;
25
+ their license text is clients/android/patches/COPYING. Preserve the original
26
+ copyright notices and source/build information when redistributing them.
27
+ The patch README and docs/development/licensing.md explain this boundary.
28
+ The original renderer screenshot docs/assets/gramlab-preview.png includes upstream
29
+ interface artwork; its attribution and capture record are in the adjacent
30
+ gramlab-preview.md. It is not original MIT fixture artwork.
31
+
32
+ Acquired dependencies and application binaries
33
+ ---------------------------------------------
34
+ External dependency sources and built Android applications are not included in
35
+ this source repository or Python package. They retain their own licenses.
36
+ The upstream lock is a provenance record, not a completed dependency/license
37
+ audit. An Android binary release requires its own corresponding-source,
38
+ dependency, asset and notice review. This repository offers no APK release.
39
+
40
+ GramLab is unofficial and is not affiliated with or endorsed by Telegram.
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: gramlab
3
+ Version: 0.1.0a1
4
+ Summary: Offline Telegram bot laboratory — experimental runtime foundation
5
+ Keywords: telegram,bot,testing,offline,android
6
+ Author: Ali Mohammadzadeh
7
+ License-Expression: MIT AND BSL-1.0
8
+ License-File: LICENSE
9
+ License-File: LICENSES/BSL-1.0.txt
10
+ License-File: NOTICE
11
+ Classifier: Development Status :: 2 - Pre-Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Testing
18
+ Classifier: Typing :: Typed
19
+ Requires-Dist: pillow==12.3.0
20
+ Requires-Python: >=3.13, <3.14
21
+ Project-URL: Homepage, https://github.com/tholoo/GramLab
22
+ Project-URL: Documentation, https://github.com/tholoo/GramLab/tree/main/docs
23
+ Project-URL: Repository, https://github.com/tholoo/GramLab
24
+ Project-URL: Issues, https://github.com/tholoo/GramLab/issues
25
+ Project-URL: Changelog, https://github.com/tholoo/GramLab/blob/main/CHANGELOG.md
26
+ Description-Content-Type: text/markdown
27
+
28
+ # GramLab
29
+
30
+ <p align="center">
31
+ <img src="https://raw.githubusercontent.com/tholoo/GramLab/main/docs/assets/gramlab-preview.png" width="320" alt="An English GramLab conversation in the Telegram Android renderer, with rich text, buttons and glass effects." />
32
+ </p>
33
+
34
+ [Original Android capture](https://github.com/tholoo/GramLab/blob/main/docs/assets/gramlab-preview.md), with glass effects enabled.
35
+
36
+ Test Telegram bots locally and inspect their messages in the actual Telegram Android client.
37
+ No Telegram account or production token is needed.
38
+
39
+ **Experimental.** Text, callbacks, rich messages, photos, documents, albums and custom emoji have
40
+ tested original-Android workflows. Mini Apps, HTML parse modes, grouped-media edits, external
41
+ Telegram conformance and interactive Android mode remain unfinished.
42
+ See the
43
+ [compatibility matrix](https://github.com/tholoo/GramLab/blob/main/docs/compatibility/matrix.md)
44
+ for the supported scope.
45
+
46
+ ## Install
47
+
48
+ GramLab currently requires Python 3.13 on a supported Linux host. Install the experimental
49
+ prerelease explicitly:
50
+
51
+ ```sh
52
+ uv add "gramlab==0.1.0a1"
53
+ ```
54
+
55
+ The package includes the `gramlab` command and typed Python scenario interface. Android captures
56
+ require separately prepared local tooling and are not distributed in the Python package.
57
+
58
+ ## Write a scenario
59
+
60
+ Create a user, talk to a real local bot, check its reply and capture the conversation:
61
+
62
+ ```python
63
+ from gramlab import Scenario
64
+
65
+ lab = Scenario.from_environment()
66
+ chat = lab.conversation(user=lab.user("Alex", language_code="en"), bot="echo")
67
+ chat.send("Hello!")
68
+ history = chat.wait_for_messages(2, timeout=5)
69
+
70
+ if history[1].text != "Echo: Hello!":
71
+ raise AssertionError("Unexpected bot reply")
72
+ chat.capture("hello", contains=["Echo: Hello!"])
73
+ ```
74
+
75
+ This runs inside a scenario process. The
76
+ [English echo example](https://github.com/tholoo/GramLab/blob/main/examples/echo/hello.toml) uses
77
+ this exact [scenario](https://github.com/tholoo/GramLab/blob/main/examples/echo/hello.py),
78
+ with the bundled bot and manifest, and the runner supplies the environment. Simulation records the conversation state;
79
+ headless Android also captures the original client. Both modes produce a local HTML report.
80
+ The typed handles are additive: advanced scenarios can still use the raw JSON-shaped operations
81
+ on `Scenario`. The Python interface is still experimental.
82
+
83
+ ## Try it
84
+
85
+ Start with the
86
+ [development environment](https://github.com/tholoo/GramLab/blob/main/docs/development/environment.md).
87
+ On a supported Linux
88
+ host with Nix and user namespaces:
89
+
90
+ ```sh
91
+ nix develop
92
+ uv sync --locked
93
+ mkdir -p artifacts
94
+ uv run --locked --offline gramlab run examples/echo/hello.toml --output artifacts/echo-demo
95
+ ```
96
+
97
+ Open `artifacts/echo-demo/report.html`. Use a new output directory for each run.
98
+ The runner isolates bot and scenario processes; dependency setup happens before execution.
99
+ Android captures require the separate
100
+ [Android setup](https://github.com/tholoo/GramLab/blob/main/docs/development/android-build.md).
101
+
102
+ More examples: [button presses](https://github.com/tholoo/GramLab/tree/main/examples/inline),
103
+ [rich messages](https://github.com/tholoo/GramLab/tree/main/examples/rich),
104
+ [rich buttons](https://github.com/tholoo/GramLab/tree/main/examples/rich_inline), and
105
+ [bot restart](https://github.com/tholoo/GramLab/tree/main/examples/recovery).
106
+
107
+ ## Work on GramLab
108
+
109
+ - [Contributor setup and checks](https://github.com/tholoo/GramLab/blob/main/CONTRIBUTING.md)
110
+ - [Current handoff and remaining work](https://github.com/tholoo/GramLab/blob/main/docs/development/handoff.md)
111
+ - [Architecture](https://github.com/tholoo/GramLab/blob/main/docs/architecture/overview.md) and [product scope](https://github.com/tholoo/GramLab/blob/main/docs/product/requirements.md)
112
+ - [Offline execution rules](https://github.com/tholoo/GramLab/blob/main/docs/development/offline-safety.md)
113
+ - [Working in parallel](https://github.com/tholoo/GramLab/blob/main/docs/development/parallel-work.md)
114
+ - [Release history](https://github.com/tholoo/GramLab/blob/main/CHANGELOG.md)
115
+
116
+ Original core and SDK code uses [MIT](https://github.com/tholoo/GramLab/blob/main/LICENSE). Two
117
+ TDLib-derived Python modules retain
118
+ [BSL-1.0](https://github.com/tholoo/GramLab/blob/main/LICENSES/BSL-1.0.txt). Android-derived patches
119
+ and fixtures retain GPL-2.0-or-later. See the
120
+ [license map](https://github.com/tholoo/GramLab/blob/main/NOTICE) and
121
+ [licensing boundaries](https://github.com/tholoo/GramLab/blob/main/docs/development/licensing.md).
122
+ This is a source repository. No Android APK release or completed dependency license audit is offered.
123
+
124
+ GramLab is unofficial and is not affiliated with or endorsed by Telegram.
@@ -0,0 +1,97 @@
1
+ # GramLab
2
+
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/tholoo/GramLab/main/docs/assets/gramlab-preview.png" width="320" alt="An English GramLab conversation in the Telegram Android renderer, with rich text, buttons and glass effects." />
5
+ </p>
6
+
7
+ [Original Android capture](https://github.com/tholoo/GramLab/blob/main/docs/assets/gramlab-preview.md), with glass effects enabled.
8
+
9
+ Test Telegram bots locally and inspect their messages in the actual Telegram Android client.
10
+ No Telegram account or production token is needed.
11
+
12
+ **Experimental.** Text, callbacks, rich messages, photos, documents, albums and custom emoji have
13
+ tested original-Android workflows. Mini Apps, HTML parse modes, grouped-media edits, external
14
+ Telegram conformance and interactive Android mode remain unfinished.
15
+ See the
16
+ [compatibility matrix](https://github.com/tholoo/GramLab/blob/main/docs/compatibility/matrix.md)
17
+ for the supported scope.
18
+
19
+ ## Install
20
+
21
+ GramLab currently requires Python 3.13 on a supported Linux host. Install the experimental
22
+ prerelease explicitly:
23
+
24
+ ```sh
25
+ uv add "gramlab==0.1.0a1"
26
+ ```
27
+
28
+ The package includes the `gramlab` command and typed Python scenario interface. Android captures
29
+ require separately prepared local tooling and are not distributed in the Python package.
30
+
31
+ ## Write a scenario
32
+
33
+ Create a user, talk to a real local bot, check its reply and capture the conversation:
34
+
35
+ ```python
36
+ from gramlab import Scenario
37
+
38
+ lab = Scenario.from_environment()
39
+ chat = lab.conversation(user=lab.user("Alex", language_code="en"), bot="echo")
40
+ chat.send("Hello!")
41
+ history = chat.wait_for_messages(2, timeout=5)
42
+
43
+ if history[1].text != "Echo: Hello!":
44
+ raise AssertionError("Unexpected bot reply")
45
+ chat.capture("hello", contains=["Echo: Hello!"])
46
+ ```
47
+
48
+ This runs inside a scenario process. The
49
+ [English echo example](https://github.com/tholoo/GramLab/blob/main/examples/echo/hello.toml) uses
50
+ this exact [scenario](https://github.com/tholoo/GramLab/blob/main/examples/echo/hello.py),
51
+ with the bundled bot and manifest, and the runner supplies the environment. Simulation records the conversation state;
52
+ headless Android also captures the original client. Both modes produce a local HTML report.
53
+ The typed handles are additive: advanced scenarios can still use the raw JSON-shaped operations
54
+ on `Scenario`. The Python interface is still experimental.
55
+
56
+ ## Try it
57
+
58
+ Start with the
59
+ [development environment](https://github.com/tholoo/GramLab/blob/main/docs/development/environment.md).
60
+ On a supported Linux
61
+ host with Nix and user namespaces:
62
+
63
+ ```sh
64
+ nix develop
65
+ uv sync --locked
66
+ mkdir -p artifacts
67
+ uv run --locked --offline gramlab run examples/echo/hello.toml --output artifacts/echo-demo
68
+ ```
69
+
70
+ Open `artifacts/echo-demo/report.html`. Use a new output directory for each run.
71
+ The runner isolates bot and scenario processes; dependency setup happens before execution.
72
+ Android captures require the separate
73
+ [Android setup](https://github.com/tholoo/GramLab/blob/main/docs/development/android-build.md).
74
+
75
+ More examples: [button presses](https://github.com/tholoo/GramLab/tree/main/examples/inline),
76
+ [rich messages](https://github.com/tholoo/GramLab/tree/main/examples/rich),
77
+ [rich buttons](https://github.com/tholoo/GramLab/tree/main/examples/rich_inline), and
78
+ [bot restart](https://github.com/tholoo/GramLab/tree/main/examples/recovery).
79
+
80
+ ## Work on GramLab
81
+
82
+ - [Contributor setup and checks](https://github.com/tholoo/GramLab/blob/main/CONTRIBUTING.md)
83
+ - [Current handoff and remaining work](https://github.com/tholoo/GramLab/blob/main/docs/development/handoff.md)
84
+ - [Architecture](https://github.com/tholoo/GramLab/blob/main/docs/architecture/overview.md) and [product scope](https://github.com/tholoo/GramLab/blob/main/docs/product/requirements.md)
85
+ - [Offline execution rules](https://github.com/tholoo/GramLab/blob/main/docs/development/offline-safety.md)
86
+ - [Working in parallel](https://github.com/tholoo/GramLab/blob/main/docs/development/parallel-work.md)
87
+ - [Release history](https://github.com/tholoo/GramLab/blob/main/CHANGELOG.md)
88
+
89
+ Original core and SDK code uses [MIT](https://github.com/tholoo/GramLab/blob/main/LICENSE). Two
90
+ TDLib-derived Python modules retain
91
+ [BSL-1.0](https://github.com/tholoo/GramLab/blob/main/LICENSES/BSL-1.0.txt). Android-derived patches
92
+ and fixtures retain GPL-2.0-or-later. See the
93
+ [license map](https://github.com/tholoo/GramLab/blob/main/NOTICE) and
94
+ [licensing boundaries](https://github.com/tholoo/GramLab/blob/main/docs/development/licensing.md).
95
+ This is a source repository. No Android APK release or completed dependency license audit is offered.
96
+
97
+ GramLab is unofficial and is not affiliated with or endorsed by Telegram.
@@ -0,0 +1,98 @@
1
+ [project]
2
+ name = "gramlab"
3
+ version = "0.1.0a1"
4
+ description = "Offline Telegram bot laboratory — experimental runtime foundation"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13,<3.14"
7
+ license = "MIT AND BSL-1.0"
8
+ license-files = [
9
+ "LICENSE",
10
+ "LICENSES/BSL-1.0.txt",
11
+ "NOTICE",
12
+ ]
13
+ keywords = [
14
+ "telegram",
15
+ "bot",
16
+ "testing",
17
+ "offline",
18
+ "android",
19
+ ]
20
+ classifiers = [
21
+ "Development Status :: 2 - Pre-Alpha",
22
+ "Environment :: Console",
23
+ "Intended Audience :: Developers",
24
+ "Operating System :: POSIX :: Linux",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Software Development :: Testing",
28
+ "Typing :: Typed",
29
+ ]
30
+ dependencies = ["pillow==12.3.0"]
31
+
32
+ [[project.authors]]
33
+ name = "Ali Mohammadzadeh"
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/tholoo/GramLab"
37
+ Documentation = "https://github.com/tholoo/GramLab/tree/main/docs"
38
+ Repository = "https://github.com/tholoo/GramLab"
39
+ Issues = "https://github.com/tholoo/GramLab/issues"
40
+ Changelog = "https://github.com/tholoo/GramLab/blob/main/CHANGELOG.md"
41
+
42
+ [project.scripts]
43
+ gramlab = "gramlab.__main__:main"
44
+
45
+ [dependency-groups]
46
+ dev = [
47
+ "coverage==7.16.0",
48
+ "hypothesis==6.167.1",
49
+ "mypy==1.20.2",
50
+ "pytest==8.4.2",
51
+ "pytest-asyncio==1.4.0",
52
+ "pytest-cov==6.3.0",
53
+ "pytest-xdist==3.8.0",
54
+ "ruff==0.16.5",
55
+ ]
56
+
57
+ [build-system]
58
+ requires = ["uv_build==0.12.5"]
59
+ build-backend = "uv_build"
60
+
61
+ [tool.ruff]
62
+ line-length = 100
63
+ target-version = "py313"
64
+ extend-exclude = ["clients/android/upstream"]
65
+
66
+ [tool.ruff.lint]
67
+ select = [
68
+ "E",
69
+ "F",
70
+ "I",
71
+ "UP",
72
+ "B",
73
+ "ASYNC",
74
+ "S",
75
+ "RUF",
76
+ ]
77
+
78
+ [tool.ruff.lint.per-file-ignores]
79
+ "tests/**" = [
80
+ "S101",
81
+ "S106",
82
+ "S311",
83
+ ]
84
+
85
+ [tool.mypy]
86
+ python_version = "3.13"
87
+ strict = true
88
+ warn_unreachable = true
89
+
90
+ [tool.pytest.ini_options]
91
+ addopts = "--strict-markers --strict-config -q"
92
+ testpaths = ["tests"]
93
+ asyncio_mode = "strict"
94
+ markers = [
95
+ "android: requires the isolated Android runtime",
96
+ "stress: explicitly selected randomized or load tests",
97
+ "conformance: requires separately reviewed external compatibility evidence",
98
+ ]
@@ -0,0 +1,77 @@
1
+ [project]
2
+ name = "gramlab"
3
+ version = "0.1.0a1"
4
+ description = "Offline Telegram bot laboratory — experimental runtime foundation"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13,<3.14"
7
+ license = "MIT AND BSL-1.0"
8
+ license-files = ["LICENSE", "LICENSES/BSL-1.0.txt", "NOTICE"]
9
+ authors = [
10
+ { name = "Ali Mohammadzadeh" },
11
+ ]
12
+ keywords = ["telegram", "bot", "testing", "offline", "android"]
13
+ classifiers = [
14
+ "Development Status :: 2 - Pre-Alpha",
15
+ "Environment :: Console",
16
+ "Intended Audience :: Developers",
17
+ "Operating System :: POSIX :: Linux",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Topic :: Software Development :: Testing",
21
+ "Typing :: Typed",
22
+ ]
23
+ dependencies = [
24
+ "pillow==12.3.0",
25
+ ]
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/tholoo/GramLab"
29
+ Documentation = "https://github.com/tholoo/GramLab/tree/main/docs"
30
+ Repository = "https://github.com/tholoo/GramLab"
31
+ Issues = "https://github.com/tholoo/GramLab/issues"
32
+ Changelog = "https://github.com/tholoo/GramLab/blob/main/CHANGELOG.md"
33
+
34
+ [project.scripts]
35
+ gramlab = "gramlab.__main__:main"
36
+
37
+ [dependency-groups]
38
+ dev = [
39
+ "coverage==7.16.0",
40
+ "hypothesis==6.167.1",
41
+ "mypy==1.20.2",
42
+ "pytest==8.4.2",
43
+ "pytest-asyncio==1.4.0",
44
+ "pytest-cov==6.3.0",
45
+ "pytest-xdist==3.8.0",
46
+ "ruff==0.16.5",
47
+ ]
48
+
49
+ [build-system]
50
+ requires = ["uv_build==0.12.5"]
51
+ build-backend = "uv_build"
52
+
53
+ [tool.ruff]
54
+ line-length = 100
55
+ target-version = "py313"
56
+ extend-exclude = ["clients/android/upstream"]
57
+
58
+ [tool.ruff.lint]
59
+ select = ["E", "F", "I", "UP", "B", "ASYNC", "S", "RUF"]
60
+
61
+ [tool.ruff.lint.per-file-ignores]
62
+ "tests/**" = ["S101", "S106", "S311"]
63
+
64
+ [tool.mypy]
65
+ python_version = "3.13"
66
+ strict = true
67
+ warn_unreachable = true
68
+
69
+ [tool.pytest.ini_options]
70
+ addopts = "--strict-markers --strict-config -q"
71
+ testpaths = ["tests"]
72
+ asyncio_mode = "strict"
73
+ markers = [
74
+ "android: requires the isolated Android runtime",
75
+ "stress: explicitly selected randomized or load tests",
76
+ "conformance: requires separately reviewed external compatibility evidence",
77
+ ]
@@ -0,0 +1,6 @@
1
+ # Python core and SDK
2
+
3
+ Reserved for independently written MIT-licensed simulation, Bot API transport, scenario control
4
+ and reporting code. The package exports the experimental typed scenario-authoring interface;
5
+ `runtime.py` implements its Linux process boundary. No stable simulator interface exists yet. Keep Android-derived
6
+ classes and generated client-derived code outside this boundary.
@@ -0,0 +1,36 @@
1
+ """GramLab's experimental scenario-authoring interface."""
2
+
3
+ from gramlab.scenario import Scenario, ScenarioError
4
+ from gramlab.scenario_flow import (
5
+ Bot,
6
+ BotState,
7
+ BotStatus,
8
+ Callback,
9
+ Capture,
10
+ Conversation,
11
+ InlineAction,
12
+ InlineButton,
13
+ InteractionReceipt,
14
+ Message,
15
+ ScenarioFlowError,
16
+ ScenarioWaitTimeout,
17
+ User,
18
+ )
19
+
20
+ __all__ = [
21
+ "Bot",
22
+ "BotState",
23
+ "BotStatus",
24
+ "Callback",
25
+ "Capture",
26
+ "Conversation",
27
+ "InlineAction",
28
+ "InlineButton",
29
+ "InteractionReceipt",
30
+ "Message",
31
+ "Scenario",
32
+ "ScenarioError",
33
+ "ScenarioFlowError",
34
+ "ScenarioWaitTimeout",
35
+ "User",
36
+ ]
@@ -0,0 +1,46 @@
1
+ """Public command entry point; consumer code is only executed inside the runtime."""
2
+
3
+ import argparse
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from gramlab.runner import run
9
+ from gramlab.runtime import RuntimeProfile
10
+
11
+
12
+ def main() -> int:
13
+ parser = argparse.ArgumentParser(prog="gramlab")
14
+ commands = parser.add_subparsers(dest="command", required=True)
15
+ execute = commands.add_parser("run", help="Run a declared scenario and bots offline")
16
+ execute.add_argument("manifest", type=Path)
17
+ execute.add_argument("--output", type=Path, required=True, help="Fresh run directory")
18
+ execute.add_argument("--profile", type=Path, default=os.environ.get("GRAMLAB_RUNTIME_PROFILE"))
19
+ execute.add_argument(
20
+ "--android-profile", type=Path, default=os.environ.get("GRAMLAB_ANDROID_RUNTIME_PROFILE")
21
+ )
22
+ execute.add_argument("--android-apk", type=Path, default=os.environ.get("GRAMLAB_ANDROID_APK"))
23
+ execute.add_argument("--bridge-version", type=int, choices=(3, 4, 5, 6), default=3)
24
+ args = parser.parse_args()
25
+ if args.profile is None:
26
+ parser.error("Enter the provisioned Nix shell or supply --profile")
27
+ try:
28
+ outcome = run(
29
+ args.manifest,
30
+ args.output,
31
+ profile=RuntimeProfile.load(args.profile),
32
+ android_profile=RuntimeProfile.load(args.android_profile)
33
+ if args.android_profile
34
+ else None,
35
+ android_apk=args.android_apk,
36
+ bridge_version=args.bridge_version,
37
+ )
38
+ except (OSError, ValueError, KeyError, TypeError) as error:
39
+ print(f"gramlab: cannot prepare run ({type(error).__name__}): {error}", file=sys.stderr)
40
+ return 2
41
+ print(f"{outcome}: {args.output / 'report.html'}")
42
+ return 0 if outcome == "passed" else 1
43
+
44
+
45
+ if __name__ == "__main__":
46
+ raise SystemExit(main())