telethon-cli 0.1.1__tar.gz → 0.1.2__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 (45) hide show
  1. telethon_cli-0.1.2/.env.example +18 -0
  2. telethon_cli-0.1.2/.gitignore +20 -0
  3. telethon_cli-0.1.2/AGENTS.md +42 -0
  4. telethon_cli-0.1.2/CLAUDE.md +42 -0
  5. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/PKG-INFO +114 -5
  6. telethon_cli-0.1.2/README.md +283 -0
  7. telethon_cli-0.1.2/conftest.py +36 -0
  8. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/pyproject.toml +4 -1
  9. telethon_cli-0.1.2/scripts/release_pypi.sh +116 -0
  10. telethon_cli-0.1.2/scripts/smoke/live_public_commands.py +5 -0
  11. telethon_cli-0.1.2/scripts/smoke/schema_drift_live.py +123 -0
  12. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/app.py +110 -3
  13. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/config.py +129 -36
  14. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/runtime.py +25 -1
  15. telethon_cli-0.1.2/src/telethon_cli/schema.py +328 -0
  16. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/settings.py +49 -0
  17. telethon_cli-0.1.2/src/telethon_cli/tlgen.py +238 -0
  18. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/PKG-INFO +114 -5
  19. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/SOURCES.txt +13 -1
  20. telethon_cli-0.1.2/src/telethon_cli.egg-info/requires.txt +4 -0
  21. telethon_cli-0.1.2/tests/test_app.py +130 -0
  22. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_config.py +233 -2
  23. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_runtime.py +73 -0
  24. telethon_cli-0.1.2/tests/test_schema.py +213 -0
  25. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_settings.py +70 -0
  26. telethon_cli-0.1.2/tests/test_tlgen.py +174 -0
  27. telethon_cli-0.1.1/README.md +0 -176
  28. telethon_cli-0.1.1/src/telethon_cli.egg-info/requires.txt +0 -1
  29. telethon_cli-0.1.1/tests/test_app.py +0 -37
  30. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/setup.cfg +0 -0
  31. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/__init__.py +0 -0
  32. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/__main__.py +0 -0
  33. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/command_matrix.py +0 -0
  34. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/errors.py +0 -0
  35. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/live_smoke.py +0 -0
  36. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/registry.py +0 -0
  37. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/resolver.py +0 -0
  38. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/serialization.py +0 -0
  39. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/dependency_links.txt +0 -0
  40. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/entry_points.txt +0 -0
  41. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/top_level.txt +0 -0
  42. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_command_matrix.py +0 -0
  43. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_registry.py +0 -0
  44. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_resolver.py +0 -0
  45. {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_serialization.py +0 -0
@@ -0,0 +1,18 @@
1
+ TG_API_ID=
2
+ TG_API_HASH=
3
+
4
+ # Optional: override the default project-local session path.
5
+ # TG_SESSION=.telethon-cli/session
6
+
7
+ # Optional: provide Telegram 2FA password for non-interactive auth.
8
+ # TG_PASSWORD=
9
+
10
+ # Optional: route the client through a proxy (socks5/socks4/http).
11
+ # Requires: pip install 'telethon-cli[proxy]'
12
+ # TG_PROXY=socks5://user:pass@host:1080
13
+
14
+ # Optional: PyPI publishing credentials for scripts/release_pypi.sh.
15
+ # Keep real tokens in your local .env only, never in version control.
16
+ # TWINE_USERNAME=__token__
17
+ # TEST_PYPI_TOKEN=pypi-...
18
+ # PYPI_TOKEN=pypi-...
@@ -0,0 +1,20 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ .mypy_cache/
5
+ .ruff_cache/
6
+ .coverage
7
+ .hypothesis/
8
+ .tox/
9
+ .nox/
10
+ .venv/
11
+ venv/
12
+ env/
13
+ .env
14
+ *.env
15
+ .telethon-cli/
16
+ .DS_Store
17
+ ._*
18
+ build/
19
+ dist/
20
+ *.egg-info/
@@ -0,0 +1,42 @@
1
+ # Repository Guidelines
2
+
3
+ `CLAUDE.md` is a symlink to this file — edit AGENTS.md, not the symlink.
4
+
5
+ ## Project Structure & Module Organization
6
+ This repository is a small `src`-layout Python package. Core code lives in `src/telethon_cli/`: `app.py` builds the CLI, `runtime.py` owns Telegram client execution, `registry.py` discovers callable coverage, `serialization.py` handles JSON input/output and result serialization, `config.py` loads env-based credentials, `settings.py` manages project settings (developer mode), `resolver.py` imports dotted paths, and `command_matrix.py` + `live_smoke.py` form the live-test matrix. Package metadata and the console entry point live in `pyproject.toml`. Tests live in `tests/`, mirroring the package structure.
7
+
8
+ ## Commands
9
+ - `python -m pytest` — full suite (root `conftest.py` points imports at `src/`, not the installed copy).
10
+ - `python -m pytest tests/test_config.py` — single module; add `-k <name>` for a single test.
11
+ - `python -m pip install -e .` — editable install for local development.
12
+ - `python -m telethon_cli registry public --output json` — exercises the CLI without credentials.
13
+ - `python scripts/smoke/live_public_commands.py` — live smoke over the command matrix (needs a session; the script re-invokes the CLI with `PYTHONPATH=src` itself).
14
+ - `./scripts/release_pypi.sh testpypi|pypi|all` — release helper; reads PyPI tokens from `.env`.
15
+
16
+ Live commands need `TG_API_ID`/`TG_API_HASH` (+ optionally `TG_SESSION`, `TG_PROXY`) from `.env` or the environment. On networks where MTProto is throttled, set `TG_PROXY=socks5://host:port` — needs `pip install 'telethon-cli[proxy]'`, otherwise the CLI errors out instead of silently ignoring the proxy.
17
+
18
+ Do not `pip install .` (non-editable, global) to "try" changes: the globally installed copy backs the production tg-agent; reinstall it only with explicit consent. `python -m pytest` and `python -m telethon_cli ...` cover local verification.
19
+
20
+ ## Architecture
21
+ The CLI surface is **generated by reflection at parser-build time**, not hand-written:
22
+
23
+ 1. `registry.discover_public_commands()` reflects over the Telethon client mixin classes listed in `PUBLIC_GROUP_SPECS` (`src/telethon_cli/registry.py:10`). Every public method becomes a `<group> <method-name>` command (e.g. `users get-me`), with one `--<param>` flag per signature parameter.
24
+ 2. `app.build_parser()` wires those commands, adds client flags (`--api-id`, `--session`, `--proxy`, ... via `config.add_client_arguments`) and sets a `handler` callable on each subparser; `main()` only dispatches to it and renders output. All handlers return a Python object; `serialization.render_output` serializes it (TLObject → `to_dict()`, dataclasses → dict, bytes → hex, callables → `{"__callable__": path}`, arbitrary objects → `__class__` + `vars`).
25
+ 3. `runtime.py` creates a **fresh `TelegramClient` per invocation** — connect, run, disconnect in `finally`; nothing persists between commands. Methods in `NO_AUTO_CONNECT_METHODS` skip auto-connect/auth. Awaitables are awaited and async generators drained by `_maybe_await`.
26
+ 4. Flag collision rule (`src/telethon_cli/app.py:220`): a method parameter named like a client flag (e.g. `set_proxy(proxy)`) owns the flag; the client flag is skipped for that command and connection config falls back to `TG_PROXY`.
27
+
28
+ The second, dangerous layer is the generic dispatcher: `call <dotted.path>` invokes any callable under `telethon`/`telethon_generator` (`resolver.import_dotted_path` with `project_only=True`); `--client-invoke` sends the built TLRequest through the connected client. `call`, `registry project`, and the JSON `$ref`/`$call` payload helpers in `serialization.materialize_payload` are gated by `settings.ensure_developer_mode_enabled` (`.telethon-cli.json` at the project root; enabled via `settings developer-mode --enable --accept-dangerous-features`).
29
+
30
+ Config precedence (`config.py`): CLI flag > `TG_*` env / `.env` > defaults; legacy `TELETHON_*` names are aliases of the `TG_*` keys. Any conflict (env vs `.env`, or two aliases with different values) is a hard `CLIError` — never silent precedence. Session defaults to `.telethon-cli/session` under the project root found by walking up to `.git`/`pyproject.toml` (`settings.find_project_root`). `CLIError` → exit code 2; interrupt → 130.
31
+
32
+ ## Coding Style & Naming Conventions
33
+ Follow the existing style: 4-space indentation, `snake_case` for functions and modules, `UPPER_CASE` for constants, and kebab-case for CLI flags such as `--client-invoke`. Keep modules focused and stdlib-first where practical. Match the repository's direct, explicit error handling with `CLIError`, and prefer small helpers over deeply nested argument parsing blocks.
34
+
35
+ ## Testing Guidelines
36
+ Use `pytest` and place tests in `tests/test_<module>.py`, mirroring `src/telethon_cli/`. `tests/test_command_matrix.py` asserts that `command_matrix.py` matches the discovered registry exactly — a new or renamed Telethon public method needs a matrix entry, or the suite fails. Prioritize coverage around argument binding, JSON materialization, serialization, and configuration validation. For Telethon-dependent behavior, prefer mocks (see the `_MatrixClient` pattern in `tests/test_command_matrix.py`) or the documented live smoke script rather than relying on live Telegram access in every test.
37
+
38
+ ## Commit & Pull Request Guidelines
39
+ The current history uses short, imperative subjects such as `Add proxy support: TG_PROXY / --proxy (issue #3)`. Keep commits focused and use the same style. Pull requests should describe behavior changes, list verification steps, and include example CLI commands when output or arguments change.
40
+
41
+ ## Security & Configuration Tips
42
+ Never commit Telegram credentials or session files. Use `TG_API_ID`, `TG_API_HASH`, and `TG_SESSION` from the environment (legacy `TELETHON_*` names are compatibility aliases only), and scrub command examples before sharing logs in issues or reviews.
@@ -0,0 +1,42 @@
1
+ # Repository Guidelines
2
+
3
+ `CLAUDE.md` is a symlink to this file — edit AGENTS.md, not the symlink.
4
+
5
+ ## Project Structure & Module Organization
6
+ This repository is a small `src`-layout Python package. Core code lives in `src/telethon_cli/`: `app.py` builds the CLI, `runtime.py` owns Telegram client execution, `registry.py` discovers callable coverage, `serialization.py` handles JSON input/output and result serialization, `config.py` loads env-based credentials, `settings.py` manages project settings (developer mode), `resolver.py` imports dotted paths, and `command_matrix.py` + `live_smoke.py` form the live-test matrix. Package metadata and the console entry point live in `pyproject.toml`. Tests live in `tests/`, mirroring the package structure.
7
+
8
+ ## Commands
9
+ - `python -m pytest` — full suite (root `conftest.py` points imports at `src/`, not the installed copy).
10
+ - `python -m pytest tests/test_config.py` — single module; add `-k <name>` for a single test.
11
+ - `python -m pip install -e .` — editable install for local development.
12
+ - `python -m telethon_cli registry public --output json` — exercises the CLI without credentials.
13
+ - `python scripts/smoke/live_public_commands.py` — live smoke over the command matrix (needs a session; the script re-invokes the CLI with `PYTHONPATH=src` itself).
14
+ - `./scripts/release_pypi.sh testpypi|pypi|all` — release helper; reads PyPI tokens from `.env`.
15
+
16
+ Live commands need `TG_API_ID`/`TG_API_HASH` (+ optionally `TG_SESSION`, `TG_PROXY`) from `.env` or the environment. On networks where MTProto is throttled, set `TG_PROXY=socks5://host:port` — needs `pip install 'telethon-cli[proxy]'`, otherwise the CLI errors out instead of silently ignoring the proxy.
17
+
18
+ Do not `pip install .` (non-editable, global) to "try" changes: the globally installed copy backs the production tg-agent; reinstall it only with explicit consent. `python -m pytest` and `python -m telethon_cli ...` cover local verification.
19
+
20
+ ## Architecture
21
+ The CLI surface is **generated by reflection at parser-build time**, not hand-written:
22
+
23
+ 1. `registry.discover_public_commands()` reflects over the Telethon client mixin classes listed in `PUBLIC_GROUP_SPECS` (`src/telethon_cli/registry.py:10`). Every public method becomes a `<group> <method-name>` command (e.g. `users get-me`), with one `--<param>` flag per signature parameter.
24
+ 2. `app.build_parser()` wires those commands, adds client flags (`--api-id`, `--session`, `--proxy`, ... via `config.add_client_arguments`) and sets a `handler` callable on each subparser; `main()` only dispatches to it and renders output. All handlers return a Python object; `serialization.render_output` serializes it (TLObject → `to_dict()`, dataclasses → dict, bytes → hex, callables → `{"__callable__": path}`, arbitrary objects → `__class__` + `vars`).
25
+ 3. `runtime.py` creates a **fresh `TelegramClient` per invocation** — connect, run, disconnect in `finally`; nothing persists between commands. Methods in `NO_AUTO_CONNECT_METHODS` skip auto-connect/auth. Awaitables are awaited and async generators drained by `_maybe_await`.
26
+ 4. Flag collision rule (`src/telethon_cli/app.py:220`): a method parameter named like a client flag (e.g. `set_proxy(proxy)`) owns the flag; the client flag is skipped for that command and connection config falls back to `TG_PROXY`.
27
+
28
+ The second, dangerous layer is the generic dispatcher: `call <dotted.path>` invokes any callable under `telethon`/`telethon_generator` (`resolver.import_dotted_path` with `project_only=True`); `--client-invoke` sends the built TLRequest through the connected client. `call`, `registry project`, and the JSON `$ref`/`$call` payload helpers in `serialization.materialize_payload` are gated by `settings.ensure_developer_mode_enabled` (`.telethon-cli.json` at the project root; enabled via `settings developer-mode --enable --accept-dangerous-features`).
29
+
30
+ Config precedence (`config.py`): CLI flag > `TG_*` env / `.env` > defaults; legacy `TELETHON_*` names are aliases of the `TG_*` keys. Any conflict (env vs `.env`, or two aliases with different values) is a hard `CLIError` — never silent precedence. Session defaults to `.telethon-cli/session` under the project root found by walking up to `.git`/`pyproject.toml` (`settings.find_project_root`). `CLIError` → exit code 2; interrupt → 130.
31
+
32
+ ## Coding Style & Naming Conventions
33
+ Follow the existing style: 4-space indentation, `snake_case` for functions and modules, `UPPER_CASE` for constants, and kebab-case for CLI flags such as `--client-invoke`. Keep modules focused and stdlib-first where practical. Match the repository's direct, explicit error handling with `CLIError`, and prefer small helpers over deeply nested argument parsing blocks.
34
+
35
+ ## Testing Guidelines
36
+ Use `pytest` and place tests in `tests/test_<module>.py`, mirroring `src/telethon_cli/`. `tests/test_command_matrix.py` asserts that `command_matrix.py` matches the discovered registry exactly — a new or renamed Telethon public method needs a matrix entry, or the suite fails. Prioritize coverage around argument binding, JSON materialization, serialization, and configuration validation. For Telethon-dependent behavior, prefer mocks (see the `_MatrixClient` pattern in `tests/test_command_matrix.py`) or the documented live smoke script rather than relying on live Telegram access in every test.
37
+
38
+ ## Commit & Pull Request Guidelines
39
+ The current history uses short, imperative subjects such as `Add proxy support: TG_PROXY / --proxy (issue #3)`. Keep commits focused and use the same style. Pull requests should describe behavior changes, list verification steps, and include example CLI commands when output or arguments change.
40
+
41
+ ## Security & Configuration Tips
42
+ Never commit Telegram credentials or session files. Use `TG_API_ID`, `TG_API_HASH`, and `TG_SESSION` from the environment (legacy `TELETHON_*` names are compatibility aliases only), and scrub command examples before sharing logs in issues or reviews.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: telethon-cli
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Command-line interface for Telethon and Telethon internals
5
5
  Author: Axisrow
6
6
  License-Expression: MIT
@@ -24,6 +24,8 @@ Classifier: Topic :: Utilities
24
24
  Requires-Python: >=3.8
25
25
  Description-Content-Type: text/markdown
26
26
  Requires-Dist: Telethon>=1
27
+ Provides-Extra: proxy
28
+ Requires-Dist: python-socks[asyncio]>=2; extra == "proxy"
27
29
 
28
30
  # telethon-cli
29
31
 
@@ -68,6 +70,47 @@ Legacy `TELETHON_API_ID`, `TELETHON_API_HASH`, `TELETHON_SESSION`, and
68
70
  `TELETHON_PASSWORD` are still accepted as compatibility aliases. When both
69
71
  namespaces are present, `telethon-cli` requires the values to match.
70
72
 
73
+ ### User config
74
+
75
+ Settings that should persist across projects can live in an optional
76
+ user-level config file at `~/.config/telethon-cli/config.json` (override the
77
+ base directory with `XDG_CONFIG_HOME`):
78
+
79
+ ```json
80
+ {
81
+ "api_id": 12345,
82
+ "api_hash": "...",
83
+ "session": "/path/to/session",
84
+ "proxy": "socks5://user:pass@host:1080"
85
+ }
86
+ ```
87
+
88
+ A missing file is not an error. Unknown keys are rejected so typos never pass
89
+ silently, and secrets such as `api_hash` belong here or in the environment —
90
+ never in committed files. Inspect the effective configuration, including where
91
+ every value came from, with `telethon-cli config show`.
92
+
93
+ ### Proxy
94
+
95
+ On networks where Telegram is throttled or blocked, route the client through a
96
+ proxy with `TG_PROXY` (or the `--proxy` flag, or legacy `TELETHON_PROXY`):
97
+
98
+ ```dotenv
99
+ TG_PROXY=socks5://user:pass@host:1080
100
+ ```
101
+
102
+ Supported schemes: `socks5`, `socks4`, `http`. DNS resolves on the proxy side
103
+ (`rdns=True`), which is what censored networks usually need. The proxy is used
104
+ by every command that connects.
105
+
106
+ The proxy support needs one extra dependency:
107
+
108
+ ```bash
109
+ python -m pip install 'telethon-cli[proxy]'
110
+ ```
111
+
112
+ Without it the CLI exits with an error instead of silently ignoring the proxy.
113
+
71
114
  On first login, `telethon-cli` can create and store a Telethon session in the
72
115
  project automatically. You can create it explicitly:
73
116
 
@@ -105,10 +148,12 @@ telethon-cli users get-me --env-file /path/to/telethon.env --output json
105
148
  ```
106
149
 
107
150
  `telethon-cli` reads the current process environment and also loads `.env`
108
- automatically when present. If the same Telethon setting is defined both in the
109
- environment and in `.env`, and the values differ, the command exits with an
110
- error instead of silently choosing one. CLI flags such as `--api-id`,
111
- `--api-hash`, `--session`, and `--2fa-password` still override both.
151
+ automatically when present. The user config file participates in the same
152
+ chain: CLI flags > environment/`.env` > user config > defaults. If the same
153
+ Telethon setting is defined in several sources with different values, the
154
+ command exits with an error instead of silently choosing one. CLI flags such
155
+ as `--api-id`, `--api-hash`, `--session`, and `--2fa-password` still override
156
+ everything.
112
157
 
113
158
  In non-interactive environments, automatic login is not possible. In that case,
114
159
  create the session in advance with `telethon-cli login` and reuse it later.
@@ -137,8 +182,57 @@ telethon-cli messages send-message --entity me --message "hello"
137
182
  telethon-cli call telethon.utils.parse_phone --args-json '["+1 234 567"]'
138
183
  telethon-cli call telethon.tl.functions.help.GetConfigRequest --client-invoke --output json
139
184
  telethon-cli settings show --output json
185
+ telethon-cli config show --output json
140
186
  ```
141
187
 
188
+ ## Schema Drift (temporary)
189
+
190
+ Telethon releases lag the live Telegram TL schema. When a channel's history
191
+ contains constructors the installed telethon does not know, iterating it fails
192
+ with `TypeNotFoundError`. `telethon-cli schema` is an explicitly **temporary**
193
+ bridge for that gap until upstream telethon ships a release covering the live
194
+ schema.
195
+
196
+ Check for drift — bundled layer vs a published schema, optionally with a
197
+ read-only live probe of a channel (requires a logged-in session):
198
+
199
+ ```bash
200
+ telethon-cli schema status --schema-file path/to/api.tl
201
+ telethon-cli schema status --schema-file path/to/api.tl --probe @somechannel
202
+ ```
203
+
204
+ `status` is read-only and needs no developer mode. It exits non-zero when the
205
+ published layer cannot be determined, or when the probe hits unknown
206
+ constructors (their ids are listed).
207
+
208
+ Where to get a schema text: there is no public auto-updating source — the
209
+ PyPI sdist stopped shipping `telethon_generator` data, and the upstream v1
210
+ branch and docs pages lag the releases. Take `telethon_generator/data/api.tl`
211
+ from the telethon source tree of the release you want to match (or any
212
+ fresher TL schema text). `schema status --probe` is the ground truth when no
213
+ fresher text exists.
214
+
215
+ Patch the drift — generates deserialization-only classes for the constructors
216
+ missing from the installed telethon and registers them in telethon's runtime
217
+ lookup table. Gated behind developer mode; prints what it is about to do first:
218
+
219
+ ```bash
220
+ telethon-cli schema patch --schema-file path/to/api.tl --dry-run
221
+ telethon-cli schema patch --schema-file path/to/api.tl --yes
222
+ telethon-cli schema patch --schema-file path/to/api.tl --probe @somechannel --yes
223
+ ```
224
+
225
+ Notes:
226
+
227
+ - The artifact is a single generated file, `.telethon-cli/tl_patch.py` at the
228
+ project root. It is applied automatically at startup for every subsequent
229
+ command in the project. Delete the file to undo.
230
+ - Patched constructors are receive-only: sending them back is not supported.
231
+ - Re-run `schema patch` after upgrading telethon (the override detects the
232
+ upgrade and disables itself).
233
+ - Constructors newer than the newest obtainable schema cannot be synthesized;
234
+ the probe lists such ids as unpatchable.
235
+
142
236
  ## Release Process
143
237
 
144
238
  Build and validate release artifacts locally before uploading:
@@ -182,6 +276,21 @@ When `twine` prompts for credentials, use username `__token__` and your
182
276
  `pypi-...` API token as the password. Keep PyPI tokens out of the repository
183
277
  and provide them through the environment or `twine` prompt.
184
278
 
279
+ ### PyPI Token Scoping
280
+
281
+ PyPI API tokens can be **account-wide** or **project-scoped**:
282
+
283
+ - **Project-scoped** tokens only allow uploads to the specific project they were
284
+ created for. A token scoped to `telethon-cli` cannot upload `direct-cli` —
285
+ you will get **403 Forbidden**.
286
+ - **Account-wide** tokens allow uploads to any project under your account.
287
+ - For the **first publication** of a new project, you **must** use an
288
+ account-wide token (project-scoped tokens cannot be created until the project
289
+ exists on PyPI).
290
+ - After the first successful upload, create a project-scoped token at
291
+ https://pypi.org/manage/account/token/ and replace the account-wide token in
292
+ `.env`.
293
+
185
294
  For every subsequent release, bump `version` in `pyproject.toml` before
186
295
  building. PyPI rejects uploads for versions that already exist.
187
296
 
@@ -0,0 +1,283 @@
1
+ # telethon-cli
2
+
3
+ `telethon-cli` is a separate installable package that exposes:
4
+
5
+ - a stable command tree for the public `TelegramClient` API;
6
+ - a generic dispatcher for internal `telethon` and `telethon_generator` callables;
7
+ - env-first client configuration through `TG_API_ID` and `TG_API_HASH`,
8
+ with optional session overrides.
9
+
10
+ ## Installation
11
+
12
+ Install from PyPI:
13
+
14
+ ```bash
15
+ python -m pip install telethon-cli
16
+ ```
17
+
18
+ For local development, install the package in editable mode:
19
+
20
+ ```bash
21
+ python -m pip install -e .
22
+ ```
23
+
24
+ Set the required Telethon credentials before running commands. You can export
25
+ them directly in the shell:
26
+
27
+ ```bash
28
+ export TG_API_ID=...
29
+ export TG_API_HASH=...
30
+ ```
31
+
32
+ You can also keep them in a `.env` file in the current working directory or at
33
+ the project root:
34
+
35
+ ```dotenv
36
+ TG_API_ID=...
37
+ TG_API_HASH=...
38
+ ```
39
+
40
+ Legacy `TELETHON_API_ID`, `TELETHON_API_HASH`, `TELETHON_SESSION`, and
41
+ `TELETHON_PASSWORD` are still accepted as compatibility aliases. When both
42
+ namespaces are present, `telethon-cli` requires the values to match.
43
+
44
+ ### User config
45
+
46
+ Settings that should persist across projects can live in an optional
47
+ user-level config file at `~/.config/telethon-cli/config.json` (override the
48
+ base directory with `XDG_CONFIG_HOME`):
49
+
50
+ ```json
51
+ {
52
+ "api_id": 12345,
53
+ "api_hash": "...",
54
+ "session": "/path/to/session",
55
+ "proxy": "socks5://user:pass@host:1080"
56
+ }
57
+ ```
58
+
59
+ A missing file is not an error. Unknown keys are rejected so typos never pass
60
+ silently, and secrets such as `api_hash` belong here or in the environment —
61
+ never in committed files. Inspect the effective configuration, including where
62
+ every value came from, with `telethon-cli config show`.
63
+
64
+ ### Proxy
65
+
66
+ On networks where Telegram is throttled or blocked, route the client through a
67
+ proxy with `TG_PROXY` (or the `--proxy` flag, or legacy `TELETHON_PROXY`):
68
+
69
+ ```dotenv
70
+ TG_PROXY=socks5://user:pass@host:1080
71
+ ```
72
+
73
+ Supported schemes: `socks5`, `socks4`, `http`. DNS resolves on the proxy side
74
+ (`rdns=True`), which is what censored networks usually need. The proxy is used
75
+ by every command that connects.
76
+
77
+ The proxy support needs one extra dependency:
78
+
79
+ ```bash
80
+ python -m pip install 'telethon-cli[proxy]'
81
+ ```
82
+
83
+ Without it the CLI exits with an error instead of silently ignoring the proxy.
84
+
85
+ On first login, `telethon-cli` can create and store a Telethon session in the
86
+ project automatically. You can create it explicitly:
87
+
88
+ ```bash
89
+ telethon-cli login
90
+ ```
91
+
92
+ Typical first-run flow:
93
+
94
+ ```bash
95
+ python -m pip install -e .
96
+ telethon-cli login
97
+ telethon-cli users get-me --output json
98
+ ```
99
+
100
+ To remove the saved session and force a fresh login next time:
101
+
102
+ ```bash
103
+ telethon-cli logout
104
+ ```
105
+
106
+ Or just run the first command in an interactive terminal and let the CLI ask for
107
+ your phone number, login code, and Telegram 2FA password when needed:
108
+
109
+ ```bash
110
+ telethon-cli users get-me --output json
111
+ ```
112
+
113
+ By default the session is stored in `.telethon-cli/session` under the project
114
+ root. You can override it explicitly:
115
+
116
+ ```bash
117
+ telethon-cli users get-me --session /path/to/session --output json
118
+ telethon-cli users get-me --env-file /path/to/telethon.env --output json
119
+ ```
120
+
121
+ `telethon-cli` reads the current process environment and also loads `.env`
122
+ automatically when present. The user config file participates in the same
123
+ chain: CLI flags > environment/`.env` > user config > defaults. If the same
124
+ Telethon setting is defined in several sources with different values, the
125
+ command exits with an error instead of silently choosing one. CLI flags such
126
+ as `--api-id`, `--api-hash`, `--session`, and `--2fa-password` still override
127
+ everything.
128
+
129
+ In non-interactive environments, automatic login is not possible. In that case,
130
+ create the session in advance with `telethon-cli login` and reuse it later.
131
+
132
+ Smoke-test the installation:
133
+
134
+ ```bash
135
+ telethon-cli --help
136
+ python -m telethon_cli registry public --output json
137
+ telethon-cli users get-me --output json
138
+ ```
139
+
140
+ Dangerous features are gated behind project-wide developer mode. Enable it once
141
+ from settings and explicitly confirm the warning before using `call`,
142
+ `registry project`, `$ref`, or `$call` payload helpers:
143
+
144
+ ```bash
145
+ telethon-cli settings developer-mode --enable --accept-dangerous-features
146
+ ```
147
+
148
+ Examples:
149
+
150
+ ```bash
151
+ telethon-cli users get-me --output json
152
+ telethon-cli messages send-message --entity me --message "hello"
153
+ telethon-cli call telethon.utils.parse_phone --args-json '["+1 234 567"]'
154
+ telethon-cli call telethon.tl.functions.help.GetConfigRequest --client-invoke --output json
155
+ telethon-cli settings show --output json
156
+ telethon-cli config show --output json
157
+ ```
158
+
159
+ ## Schema Drift (temporary)
160
+
161
+ Telethon releases lag the live Telegram TL schema. When a channel's history
162
+ contains constructors the installed telethon does not know, iterating it fails
163
+ with `TypeNotFoundError`. `telethon-cli schema` is an explicitly **temporary**
164
+ bridge for that gap until upstream telethon ships a release covering the live
165
+ schema.
166
+
167
+ Check for drift — bundled layer vs a published schema, optionally with a
168
+ read-only live probe of a channel (requires a logged-in session):
169
+
170
+ ```bash
171
+ telethon-cli schema status --schema-file path/to/api.tl
172
+ telethon-cli schema status --schema-file path/to/api.tl --probe @somechannel
173
+ ```
174
+
175
+ `status` is read-only and needs no developer mode. It exits non-zero when the
176
+ published layer cannot be determined, or when the probe hits unknown
177
+ constructors (their ids are listed).
178
+
179
+ Where to get a schema text: there is no public auto-updating source — the
180
+ PyPI sdist stopped shipping `telethon_generator` data, and the upstream v1
181
+ branch and docs pages lag the releases. Take `telethon_generator/data/api.tl`
182
+ from the telethon source tree of the release you want to match (or any
183
+ fresher TL schema text). `schema status --probe` is the ground truth when no
184
+ fresher text exists.
185
+
186
+ Patch the drift — generates deserialization-only classes for the constructors
187
+ missing from the installed telethon and registers them in telethon's runtime
188
+ lookup table. Gated behind developer mode; prints what it is about to do first:
189
+
190
+ ```bash
191
+ telethon-cli schema patch --schema-file path/to/api.tl --dry-run
192
+ telethon-cli schema patch --schema-file path/to/api.tl --yes
193
+ telethon-cli schema patch --schema-file path/to/api.tl --probe @somechannel --yes
194
+ ```
195
+
196
+ Notes:
197
+
198
+ - The artifact is a single generated file, `.telethon-cli/tl_patch.py` at the
199
+ project root. It is applied automatically at startup for every subsequent
200
+ command in the project. Delete the file to undo.
201
+ - Patched constructors are receive-only: sending them back is not supported.
202
+ - Re-run `schema patch` after upgrading telethon (the override detects the
203
+ upgrade and disables itself).
204
+ - Constructors newer than the newest obtainable schema cannot be synthesized;
205
+ the probe lists such ids as unpatchable.
206
+
207
+ ## Release Process
208
+
209
+ Build and validate release artifacts locally before uploading:
210
+
211
+ ```bash
212
+ rm -rf dist build src/*.egg-info
213
+ python -m pip install --upgrade build twine
214
+ python -m build
215
+ python -m twine check dist/*
216
+ ```
217
+
218
+ Optional local smoke-test from the built wheel:
219
+
220
+ ```bash
221
+ python -m pip install --force-reinstall dist/*.whl
222
+ telethon-cli --help
223
+ python -m telethon_cli registry public --output json
224
+ ```
225
+
226
+ Upload to TestPyPI first:
227
+
228
+ ```bash
229
+ python -m twine upload --repository testpypi dist/*
230
+ ```
231
+
232
+ Verify installation from TestPyPI:
233
+
234
+ ```bash
235
+ python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple telethon-cli
236
+ telethon-cli --help
237
+ python -m telethon_cli registry public --output json
238
+ ```
239
+
240
+ Then upload the same artifacts to PyPI:
241
+
242
+ ```bash
243
+ python -m twine upload dist/*
244
+ ```
245
+
246
+ When `twine` prompts for credentials, use username `__token__` and your
247
+ `pypi-...` API token as the password. Keep PyPI tokens out of the repository
248
+ and provide them through the environment or `twine` prompt.
249
+
250
+ ### PyPI Token Scoping
251
+
252
+ PyPI API tokens can be **account-wide** or **project-scoped**:
253
+
254
+ - **Project-scoped** tokens only allow uploads to the specific project they were
255
+ created for. A token scoped to `telethon-cli` cannot upload `direct-cli` —
256
+ you will get **403 Forbidden**.
257
+ - **Account-wide** tokens allow uploads to any project under your account.
258
+ - For the **first publication** of a new project, you **must** use an
259
+ account-wide token (project-scoped tokens cannot be created until the project
260
+ exists on PyPI).
261
+ - After the first successful upload, create a project-scoped token at
262
+ https://pypi.org/manage/account/token/ and replace the account-wide token in
263
+ `.env`.
264
+
265
+ For every subsequent release, bump `version` in `pyproject.toml` before
266
+ building. PyPI rejects uploads for versions that already exist.
267
+
268
+ You can also keep PyPI credentials in the project-local `.env` file, because
269
+ `.env` is gitignored in this repository. The release helper script reads `.env`
270
+ automatically and publishes with `twine`:
271
+
272
+ ```dotenv
273
+ TWINE_USERNAME=__token__
274
+ TEST_PYPI_TOKEN=pypi-...
275
+ PYPI_TOKEN=pypi-...
276
+ ```
277
+
278
+ ```bash
279
+ chmod +x scripts/release_pypi.sh
280
+ ./scripts/release_pypi.sh testpypi
281
+ ./scripts/release_pypi.sh pypi
282
+ ./scripts/release_pypi.sh all
283
+ ```
@@ -0,0 +1,36 @@
1
+ """Point test imports at the local src/ tree instead of the installed copy."""
2
+ import json
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ import pytest
7
+
8
+ sys.path.insert(0, str(Path(__file__).parent / "src"))
9
+
10
+
11
+ @pytest.fixture
12
+ def project_root(tmp_path, monkeypatch):
13
+ """A throwaway project root (cwd + planted pyproject.toml)."""
14
+ monkeypatch.chdir(tmp_path)
15
+ (tmp_path / "pyproject.toml").write_text("", encoding="utf-8")
16
+ return tmp_path
17
+
18
+
19
+ @pytest.fixture(autouse=True)
20
+ def isolated_user_config(tmp_path, monkeypatch):
21
+ """Keeps os.environ-based flows away from the developer's real user config."""
22
+ monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "xdg-config"))
23
+
24
+
25
+ def _write_user_config(tmp_path, payload):
26
+ config_dir = tmp_path / "xdg" / "telethon-cli"
27
+ config_dir.mkdir(parents=True)
28
+ path = config_dir / "config.json"
29
+ path.write_text(json.dumps(payload), encoding="utf-8")
30
+ return path
31
+
32
+
33
+ def _user_config_environ(tmp_path, **extra):
34
+ environ = {"XDG_CONFIG_HOME": str(tmp_path / "xdg")}
35
+ environ.update(extra)
36
+ return environ
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "telethon-cli"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "Command-line interface for Telethon and Telethon internals"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -32,6 +32,9 @@ dependencies = [
32
32
  "Telethon>=1"
33
33
  ]
34
34
 
35
+ [project.optional-dependencies]
36
+ proxy = ["python-socks[asyncio]>=2"]
37
+
35
38
  [project.urls]
36
39
  Homepage = "https://github.com/axisrow/telethon-cli"
37
40
  Repository = "https://github.com/axisrow/telethon-cli"