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.
- telethon_cli-0.1.2/.env.example +18 -0
- telethon_cli-0.1.2/.gitignore +20 -0
- telethon_cli-0.1.2/AGENTS.md +42 -0
- telethon_cli-0.1.2/CLAUDE.md +42 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/PKG-INFO +114 -5
- telethon_cli-0.1.2/README.md +283 -0
- telethon_cli-0.1.2/conftest.py +36 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/pyproject.toml +4 -1
- telethon_cli-0.1.2/scripts/release_pypi.sh +116 -0
- telethon_cli-0.1.2/scripts/smoke/live_public_commands.py +5 -0
- telethon_cli-0.1.2/scripts/smoke/schema_drift_live.py +123 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/app.py +110 -3
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/config.py +129 -36
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/runtime.py +25 -1
- telethon_cli-0.1.2/src/telethon_cli/schema.py +328 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/settings.py +49 -0
- telethon_cli-0.1.2/src/telethon_cli/tlgen.py +238 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/PKG-INFO +114 -5
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/SOURCES.txt +13 -1
- telethon_cli-0.1.2/src/telethon_cli.egg-info/requires.txt +4 -0
- telethon_cli-0.1.2/tests/test_app.py +130 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_config.py +233 -2
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_runtime.py +73 -0
- telethon_cli-0.1.2/tests/test_schema.py +213 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_settings.py +70 -0
- telethon_cli-0.1.2/tests/test_tlgen.py +174 -0
- telethon_cli-0.1.1/README.md +0 -176
- telethon_cli-0.1.1/src/telethon_cli.egg-info/requires.txt +0 -1
- telethon_cli-0.1.1/tests/test_app.py +0 -37
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/setup.cfg +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/__init__.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/__main__.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/command_matrix.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/errors.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/live_smoke.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/registry.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/resolver.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli/serialization.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/dependency_links.txt +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/entry_points.txt +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/src/telethon_cli.egg-info/top_level.txt +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_command_matrix.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_registry.py +0 -0
- {telethon_cli-0.1.1 → telethon_cli-0.1.2}/tests/test_resolver.py +0 -0
- {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,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.
|
|
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.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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.
|
|
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"
|