ferogram 0.5.0b2__tar.gz → 0.5.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 (110) hide show
  1. {ferogram-0.5.0b2 → ferogram-0.5.2}/.github/workflows/publish.yml +28 -12
  2. {ferogram-0.5.0b2 → ferogram-0.5.2}/CHANGELOG.md +108 -5
  3. {ferogram-0.5.0b2 → ferogram-0.5.2}/Cargo.lock +17 -17
  4. {ferogram-0.5.0b2 → ferogram-0.5.2}/Cargo.toml +7 -7
  5. {ferogram-0.5.0b2 → ferogram-0.5.2}/FEATURES.md +6 -0
  6. ferogram-0.5.2/PKG-INFO +162 -0
  7. ferogram-0.5.2/README.md +137 -0
  8. ferogram-0.5.2/assets/architecture.svg +130 -0
  9. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/admin_tools.py +5 -4
  10. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/command_bot.py +5 -4
  11. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/echo_bot.py +5 -4
  12. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/group_management.py +5 -4
  13. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/media_bot.py +5 -4
  14. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/raw_invoke.py +6 -5
  15. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/search_bot.py +5 -4
  16. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/send_hi.py +6 -5
  17. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/send_media.py +8 -5
  18. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/send_message.py +5 -4
  19. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/update_handlers.py +6 -5
  20. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/user_management.py +6 -5
  21. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/userbot.py +7 -5
  22. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/__init__.py +7 -5
  23. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/api.tl +58 -9
  24. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/client.py +660 -58
  25. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/filters.py +16 -7
  26. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/keyboards.py +5 -4
  27. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/logging.py +5 -4
  28. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/__init__.py +5 -4
  29. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/api/__init__.py +5 -4
  30. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/api/functions.py +5 -4
  31. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/api/types.py +5 -4
  32. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/codegen.py +10 -8
  33. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/__init__.py +5 -4
  34. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/_tl_schema.py +82 -19
  35. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/__init__.py +9 -4
  36. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/account.py +5 -4
  37. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/aicompose.py +5 -4
  38. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/auth.py +5 -4
  39. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/bots.py +5 -4
  40. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/channels.py +12 -6
  41. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/chatlists.py +5 -4
  42. ferogram-0.5.2/ferogram/raw/generated/functions/communities.py +375 -0
  43. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/contacts.py +5 -4
  44. ferogram-0.5.2/ferogram/raw/generated/functions/ephemeral.py +241 -0
  45. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/folders.py +5 -4
  46. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/fragment.py +5 -4
  47. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/help.py +5 -4
  48. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/langpack.py +5 -4
  49. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/messages.py +178 -7
  50. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/payments.py +5 -4
  51. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/phone.py +5 -4
  52. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/photos.py +5 -4
  53. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/premium.py +5 -4
  54. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/smsjobs.py +5 -4
  55. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/stats.py +5 -4
  56. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/stickers.py +5 -4
  57. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/stories.py +5 -4
  58. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/updates.py +5 -4
  59. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/upload.py +5 -4
  60. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/functions/users.py +5 -4
  61. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/__init__.py +7 -4
  62. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/_base.py +885 -15
  63. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/account.py +5 -4
  64. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/aicompose.py +5 -4
  65. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/auth.py +5 -4
  66. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/bots.py +5 -4
  67. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/channels.py +5 -4
  68. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/chatlists.py +5 -4
  69. ferogram-0.5.2/ferogram/raw/generated/types/communities.py +120 -0
  70. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/contacts.py +5 -4
  71. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/fragment.py +5 -4
  72. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/help.py +5 -4
  73. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/messages.py +70 -15
  74. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/payments.py +5 -4
  75. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/phone.py +5 -4
  76. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/photos.py +5 -4
  77. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/premium.py +5 -4
  78. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/smsjobs.py +5 -4
  79. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/stats.py +5 -4
  80. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/stickers.py +5 -4
  81. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/storage.py +5 -4
  82. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/stories.py +5 -4
  83. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/updates.py +5 -4
  84. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/upload.py +5 -4
  85. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/generated/types/users.py +5 -4
  86. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/proxy.py +5 -4
  87. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/raw/tl.py +5 -4
  88. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/types.py +87 -6
  89. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/updates.py +170 -22
  90. {ferogram-0.5.0b2 → ferogram-0.5.2}/pyproject.toml +2 -2
  91. {ferogram-0.5.0b2 → ferogram-0.5.2}/src/connection.rs +103 -10
  92. {ferogram-0.5.0b2 → ferogram-0.5.2}/src/lib.rs +3 -0
  93. ferogram-0.5.2/src/pipelined.rs +129 -0
  94. ferogram-0.5.0b2/PKG-INFO +0 -152
  95. ferogram-0.5.0b2/README.md +0 -127
  96. {ferogram-0.5.0b2 → ferogram-0.5.2}/.github/workflows/compile-check.yml +0 -0
  97. {ferogram-0.5.0b2 → ferogram-0.5.2}/.gitignore +0 -0
  98. {ferogram-0.5.0b2 → ferogram-0.5.2}/.readthedocs.yaml +0 -0
  99. {ferogram-0.5.0b2 → ferogram-0.5.2}/LICENSE-APACHE +0 -0
  100. {ferogram-0.5.0b2 → ferogram-0.5.2}/LICENSE-MIT +0 -0
  101. {ferogram-0.5.0b2 → ferogram-0.5.2}/Makefile +0 -0
  102. {ferogram-0.5.0b2 → ferogram-0.5.2}/build.rs +0 -0
  103. {ferogram-0.5.0b2 → ferogram-0.5.2}/examples/rich_message.py +0 -0
  104. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/py.typed +0 -0
  105. {ferogram-0.5.0b2 → ferogram-0.5.2}/ferogram/rich.py +0 -0
  106. {ferogram-0.5.0b2 → ferogram-0.5.2}/src/raw.rs +0 -0
  107. {ferogram-0.5.0b2 → ferogram-0.5.2}/src/session.rs +0 -0
  108. {ferogram-0.5.0b2 → ferogram-0.5.2}/src/srp.rs +0 -0
  109. {ferogram-0.5.0b2 → ferogram-0.5.2}/tests/test_rich.py +0 -0
  110. {ferogram-0.5.0b2 → ferogram-0.5.2}/tests/test_tl_roundtrip.py +0 -0
@@ -146,7 +146,7 @@ jobs:
146
146
  - name: Install maturin
147
147
  run: pip install maturin
148
148
 
149
- - name: Fetch Termux libpython3.13 for linking
149
+ - name: Fetch Termux libpython for linking
150
150
  run: |
151
151
  TARGET=${{ matrix.target }}
152
152
  case "$TARGET" in
@@ -166,21 +166,35 @@ jobs:
166
166
  curl -sL "https://packages.termux.dev/apt/termux-main/${DEB_PATH}" -o python.deb
167
167
  ar x python.deb
168
168
  # data archive may be .tar.xz or .tar.zst depending on Termux version
169
- tar xf data.tar.* --wildcards "*/libpython3.13*" 2>/dev/null || true
169
+ # Don't pin the minor version here - Termux's "python" package always
170
+ # tracks upstream latest, and older debs fall out of the Packages
171
+ # index once superseded, so a hardcoded "libpython3.13" wildcard
172
+ # breaks the moment Termux bumps its default Python.
173
+ tar xf data.tar.* --wildcards "*/libpython3.*" 2>/dev/null || true
170
174
 
171
175
  LIB_DIR=/tmp/termux-py/data/data/com.termux/files/usr/lib
172
- # Ensure the unversioned name exists for -lpython3.13
173
- if [ ! -f "$LIB_DIR/libpython3.13.so" ]; then
174
- ln -sf "$(basename $(ls $LIB_DIR/libpython3.13.so* | head -1))" \
175
- "$LIB_DIR/libpython3.13.so"
176
+ SO_FILE=$(ls "$LIB_DIR"/libpython3.*.so* 2>/dev/null | head -1)
177
+ if [ -z "$SO_FILE" ]; then
178
+ echo "::error::No libpython3.*.so found in Termux's python package ($DEB_PATH)"
179
+ exit 1
176
180
  fi
181
+
182
+ # Extract "3.14" out of ".../libpython3.14.so"
183
+ PYVER=$(basename "$SO_FILE" | sed -E 's/^libpython(3\.[0-9]+)\.so.*/\1/')
184
+ UNVERSIONED="$LIB_DIR/libpython${PYVER}.so"
185
+ if [ ! -f "$UNVERSIONED" ]; then
186
+ ln -sf "$(basename "$SO_FILE")" "$UNVERSIONED"
187
+ fi
188
+
177
189
  echo "TERMUX_LIBDIR=$LIB_DIR" >> $GITHUB_ENV
190
+ echo "TERMUX_PYVER=$PYVER" >> $GITHUB_ENV
191
+ echo "Linking against Termux libpython $PYVER ($SO_FILE)"
178
192
 
179
193
  - name: Build Android wheel
180
194
  env:
181
195
  ANDROID_NDK_HOME: ${{ steps.ndk.outputs.ndk-path }}
182
196
  ANDROID_API_LEVEL: ${{ matrix.api }}
183
- PYO3_CROSS_PYTHON_VERSION: "3.13"
197
+ PYO3_CROSS_PYTHON_VERSION: ${{ env.TERMUX_PYVER }}
184
198
  run: |
185
199
  NDK_BIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
186
200
  TARGET=${{ matrix.target }}
@@ -203,11 +217,13 @@ jobs:
203
217
  export AR_${TARGET_LOWER}=$NDK_BIN/llvm-ar
204
218
  export CARGO_TARGET_${TARGET_UPPER}_LINKER=$NDK_BIN/${CLANG_PREFIX}-clang
205
219
 
206
- # Link against Termux's real libpython3.13.so (not an empty stub).
207
- # This embeds DT_NEEDED: libpython3.13.so in the extension, so
208
- # bionic resolves all Python symbols explicitly at dlopen time via
209
- # Termux's LD_LIBRARY_PATH - instead of relying on global namespace
210
- # propagation, which Android's linker does not guarantee.
220
+ # Link against Termux's real libpython<version>.so (not an empty
221
+ # stub). This embeds DT_NEEDED: libpython<version>.so in the
222
+ # extension, so bionic resolves all Python symbols explicitly at
223
+ # dlopen time via Termux's LD_LIBRARY_PATH - instead of relying on
224
+ # global namespace propagation, which Android's linker does not
225
+ # guarantee. The version is whatever Termux's apt repo currently
226
+ # ships (see the fetch step above), not a fixed constant.
211
227
  export RUSTFLAGS="-L native=$TERMUX_LIBDIR"
212
228
 
213
229
  maturin build \
@@ -1,3 +1,110 @@
1
+ ## 0.5.2 (2026-07-17)
2
+
3
+ - Added `Client.get_chat_photos(peer, limit)`: photo/avatar history for groups and channels (`get_profile_photos` only ever worked for users). Current photo comes from the chat's full info, so it survives message deletion; older photos come from `messageActionChatEditPhoto` search history.
4
+ - Added fast re-auth support: `sign_out()` captures a `future_auth_token` when Telegram returns one and persists it via a new `DcConnection.get_future_auth_token`/`set_future_auth_token` pair (rides along in the existing session blob, no new session format code needed here). `request_login_code()` replays it automatically, so a returning session can skip code entry entirely (`auth.sentCodeSuccess`).
5
+ - MTProto handshake fix upstream (dc-tagged `p_q_inner_data` was being rejected by Telegram with RPC 444 outside DC2), pulled in transitively via `ferogram-mtsender`.
6
+ - Layer Upgrade to 228
7
+ ## 0.5.1 (2026-06-29)
8
+
9
+ ## What's Changed
10
+
11
+ ### Message API Improvements
12
+
13
+ - `Message.reply()` now creates a proper quoted reply using `reply_to=self.id`.
14
+ - Added `Message.respond()` for sending messages to the same chat without replying.
15
+ - Added `pin()`, `forward_to()`, `get_sender()`, `get_chat()`, and `get_reply_message()` helpers.
16
+ - Added `reply_photo()` and `reply_document()` convenience methods.
17
+ - Improved `delete()` to correctly handle channels and supergroups.
18
+
19
+ ### Client Enhancements
20
+
21
+ - Added `reply_to` support to `send_message()`, `send_photo()`, and `send_document()`.
22
+ - Added `Client.get_user()` and `Client.get_chat()` helpers.
23
+ - `edit_message()` now accepts `reply_markup`.
24
+ - `pin_message()` now supports a `notify` parameter.
25
+ - Improved `delete_messages_in()` for channel-aware message deletion.
26
+ - Improved sent message extraction fallback behavior with warning logging and preserved context.
27
+
28
+ ### Update Improvements
29
+
30
+ - Added convenience methods to `CallbackQuery`:
31
+ - `respond()`
32
+ - `reply()`
33
+ - `edit_message_text()`
34
+ - `get_sender()`
35
+
36
+ - Added convenience methods to `InlineQuery`:
37
+ - `answer()`
38
+ - `get_sender()`
39
+
40
+ - Added sender/entity helpers for additional update types, including:
41
+ - `InlineSend`
42
+ - `UserStatus`
43
+ - `ChatAction`
44
+ - `JoinRequest`
45
+ - `ParticipantUpdate`
46
+ - `MessageReaction`
47
+ - `ChatBoost`
48
+ - `ShippingQuery`
49
+ - `PreCheckoutQuery`
50
+
51
+ ### Dispatch Improvements
52
+
53
+ - `_dispatch()` now binds `_client` for all update types.
54
+ - Added `_client` support to remaining update wrappers, including `RawUpdate`.
55
+ - Improved sent message extraction fallback handling.
56
+
57
+ ## 0.5.0 (2026-06-28)
58
+
59
+ ### Architecture
60
+
61
+ The Rust dependency has changed from the monolithic `ferogram` crate to five focused crates from the ferogram core:
62
+
63
+ - `ferogram-mtsender` - MTProto sender, message framing, and acknowledgement
64
+ - `ferogram-session` - session storage (file, sqlite, libsql, memory, string)
65
+ - `ferogram-connect` - TCP/TLS transport and DC routing
66
+ - `ferogram-tl-types` - generated TL type definitions
67
+ - `ferogram-crypto` - AES-IGE, Diffie-Hellman, and SHA helpers
68
+
69
+ These five crates form the battle-tested lower layer of ferogram. They change rarely and are stable across minor versions. All high-level logic (message parsing, update dispatch, peer resolution, serialization, deserialization) now lives in Python. This split means the compiled extension is smaller and faster to build, and Python-side behaviour can be updated without recompiling the Rust extension.
70
+
71
+ The compiled extension now uses `abi3-py39` (was `abi3-py313`), so a single wheel runs on Python 3.9 and later.
72
+
73
+ ### Added
74
+
75
+ - **`TransferHandle`** - pause, resume, and cancel any upload or download in flight. Create a `TransferHandle`, pass it to `upload_with_progress` or `download_with_progress`, then call `.pause()`, `.resume()`, or `.cancel()` from any coroutine. `.progress()` returns a dict with `done`, `total`, `elapsed_ms`, `percent`, `speed_bps`, `eta_secs`, `speed_human`, and `bytes_human`.
76
+ - **`TransferCancelled` exception** - raised when a `TransferHandle` is cancelled mid-transfer.
77
+ - **`keyboards` module** - `InlineKeyboard`, `InlineButton`, `ReplyKeyboard`, `ReplyButton`, `RemoveKeyboard`, and `ForceReply` are now pure Python and importable from `ferogram` directly.
78
+ - **`types` module** - all entity types (`User`, `Message`, `Chat`, `Dialog`, `ChatMember`, `UserFull`, `Authorization`, `ForumTopic`, `BotInfo`, `InviteLinkMember`, `ReadParticipant`, `AdminLogEvent`, `StickerSetInfo`, `BroadcastStats`, `MegagroupStats`, `NotifySettings`) moved from Rust to Python dataclasses. The public API is identical.
79
+ - **`updates` module** - update wrapper types (`NewMessage`, `EditedMessage`, `MessageDeletion`, `CallbackQuery`, `InlineQuery`, `InlineSend`, `UserStatus`, `ParticipantUpdate`, `JoinRequest`, `MessageReaction`, `PollVote`, `BotStopped`, `ShippingQuery`, `PreCheckoutQuery`, `ChatBoost`, `RawUpdate`) moved from Rust to Python dataclasses.
80
+ - **`rich` module** - `send_rich_message`, `edit_rich_message`, `send_rich_message_draft`, and `get_rich_message` via a `_RichMixin`. Supports Telegram rich text blocks including headers, tables, collages, task lists, footnotes, math, time stamps, and custom emoji via Markdown or HTML input.
81
+ - **Automatic TL codegen at build time** - `build.rs` now runs `ferogram/raw/codegen.py` during `maturin develop` / `pip install .`. Set `FEROGRAM_SKIP_CODEGEN=1` to skip if you only changed Rust. The codegen uses the same Python interpreter maturin selected.
82
+ - **`DcConnection` and `srp_calculate`** exposed from the Rust extension for use by the pure-Python `Client` class.
83
+ - **`LAYER` constant** exported from `ferogram.raw.generated._tl_schema` and used automatically in `invokeWithLayer` wrappers.
84
+ - **`all_updates` filter** - replaces the old `all` filter (which shadowed the built-in).
85
+ - **`filters` improvements** - all filters now unwrap `NewMessage` / `EditedMessage` wrapper objects before inspecting the inner `Message`. Previously filters broke when the dispatcher passed wrapper objects instead of bare messages.
86
+
87
+ ### Changed
88
+
89
+ - `Message`, `User`, `Chat`, and all entity types are now Python dataclasses instead of PyO3 structs. They serialize to / from the TL dict representation in Python. No change to the public API.
90
+ - `CallbackQuery`, `InlineQuery`, and all update types are now Python dataclasses.
91
+ - `InlineKeyboard`, `ReplyKeyboard`, and related keyboard builders are now pure Python (`ferogram/keyboards.py`). Previously they were Rust structs.
92
+ - Filters rewritten to correctly unwrap update wrapper objects. `reply` filter now checks `reply_to_msg_id`; `forwarded` checks `forward_from_id`; `media` checks the `media` field directly.
93
+ - `codegen.py` doubled in size (321 to 691 lines): now generates specialized `to_bytes()` methods using `struct.pack` inline and a CID-dispatch `from_bytes()` router, producing faster serialization and deserialization than the previous schema-dict approach.
94
+ - `ferogram-py` version bump to 0.5.0. Core crates pinned to `ferogram-*` 0.6.3.
95
+
96
+ ### Removed
97
+
98
+ - Direct dependency on the monolithic `ferogram` crate. The five focused crates replace it.
99
+ - `hex` crate dependency (was `0.4`, now unused).
100
+ - `all` filter removed and replaced with `all_updates` to avoid shadowing Python's built-in `all`.
101
+
102
+
103
+ ## 0.4.1 (2026-06-03)
104
+
105
+ Patch release. No API changes. Identical to 0.4.0 except for dependency pins and minor internal fixes.
106
+
107
+
1
108
  ## 0.4.0 (2026-06-01)
2
109
 
3
110
  ### Added
@@ -20,7 +127,7 @@
20
127
  - **`flood_sleep_threshold` kwarg on `Client`** - maps to the `AutoSleep` retry policy in the Rust core. Flood waits under this value are slept through automatically; waits above it are raised as exceptions.
21
128
  - **`download_with_progress(peer, msg_id, path, on_progress)`** - download media with a progress callback `on_progress(done, total)`.
22
129
  - **`upload_with_progress(path, on_progress)`** - upload a file with a progress callback. Returns a handle string accepted by `send_file`.
23
- - **`ferogram` 0.6.0 as core dependency** - includes `Client.channel_kind_of(channel_id)` which backs the new `Message` methods above.
130
+ - **ferogram 0.6.0 as core dependency** - includes `Client.channel_kind_of(channel_id)` which backs the new `Message` methods above.
24
131
 
25
132
  ### Changed
26
133
 
@@ -62,9 +169,6 @@ the votes graph as a JSON string. The old `get_poll_results(peer, msg_id, poll_h
62
169
  is kept for backward compat but is deprecated; the `poll_hash` parameter is ignored
63
170
  because ferogram 0.5.0 dropped the underlying API call it relied on.
64
171
 
65
- ---
66
-
67
- # Changelog
68
172
 
69
173
  ## 0.2.3 (2026-05-14)
70
174
 
@@ -124,7 +228,6 @@ Ten new methods for managing group and channel members.
124
228
 
125
229
  `get_poll_results(peer, msg_id, poll_hash)` was in Rust but had no Python wrapper. Now exposed. Fetches and caches the latest poll results from Telegram.
126
230
 
127
- ---
128
231
 
129
232
  ## 0.2.2
130
233
 
@@ -392,9 +392,9 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
392
392
 
393
393
  [[package]]
394
394
  name = "ferogram-connect"
395
- version = "0.6.3"
395
+ version = "0.6.4"
396
396
  source = "registry+https://github.com/rust-lang/crates.io-index"
397
- checksum = "90734b153432187e49e05b3b79737b2ac69cd3647b1dc2f572dd63cdeeeea048"
397
+ checksum = "54211f9669f8bb7db8101d952514784311a1e135c01eb04d8732d465cdb2aa73"
398
398
  dependencies = [
399
399
  "ferogram-crypto",
400
400
  "ferogram-mtproto",
@@ -409,9 +409,9 @@ dependencies = [
409
409
 
410
410
  [[package]]
411
411
  name = "ferogram-crypto"
412
- version = "0.6.3"
412
+ version = "0.6.4"
413
413
  source = "registry+https://github.com/rust-lang/crates.io-index"
414
- checksum = "12bfa17a936160758b481d56f5674644290fa372165c2a416b21068ae484aed5"
414
+ checksum = "0e9b1bf8c53553a3fa8acbfdc0f9f9ede749f786a5d62c26c57a4dd20b793b4d"
415
415
  dependencies = [
416
416
  "aes",
417
417
  "ctr",
@@ -427,9 +427,9 @@ dependencies = [
427
427
 
428
428
  [[package]]
429
429
  name = "ferogram-mtproto"
430
- version = "0.6.3"
430
+ version = "0.6.4"
431
431
  source = "registry+https://github.com/rust-lang/crates.io-index"
432
- checksum = "eb92042988257514b90ed249214747225388bb38806f904c25c4659ec70f2051"
432
+ checksum = "007456e26302ca4a2f63019ed88c2055705ecf7752f823520d41aa2f8803b42e"
433
433
  dependencies = [
434
434
  "ferogram-crypto",
435
435
  "ferogram-tl-types",
@@ -441,9 +441,9 @@ dependencies = [
441
441
 
442
442
  [[package]]
443
443
  name = "ferogram-mtsender"
444
- version = "0.6.3"
444
+ version = "0.6.4"
445
445
  source = "registry+https://github.com/rust-lang/crates.io-index"
446
- checksum = "cde7ed2cd881032574626cda99d8fce73e32e4d884c843444d488fb608364e20"
446
+ checksum = "4fb2d34f025b0c6369d42f08317e3ded5bb8aa83bdec48fd443a4cc26fa4c9cf"
447
447
  dependencies = [
448
448
  "ferogram-connect",
449
449
  "ferogram-crypto",
@@ -457,7 +457,7 @@ dependencies = [
457
457
 
458
458
  [[package]]
459
459
  name = "ferogram-py"
460
- version = "0.5.0"
460
+ version = "0.5.2"
461
461
  dependencies = [
462
462
  "base64 0.22.1",
463
463
  "ferogram-connect",
@@ -474,9 +474,9 @@ dependencies = [
474
474
 
475
475
  [[package]]
476
476
  name = "ferogram-session"
477
- version = "0.6.3"
477
+ version = "0.6.4"
478
478
  source = "registry+https://github.com/rust-lang/crates.io-index"
479
- checksum = "307cfc80221fd742fa87af28bc629cb7acc9e6c89ceb7fa823068fb9df581989"
479
+ checksum = "c29506aee6e38e3f62623f28f17dfa470f347a87f65030313bf62f9b8dd12dd1"
480
480
  dependencies = [
481
481
  "base64 0.22.1",
482
482
  "libsql",
@@ -488,24 +488,24 @@ dependencies = [
488
488
 
489
489
  [[package]]
490
490
  name = "ferogram-tl-gen"
491
- version = "0.6.3"
491
+ version = "0.6.4"
492
492
  source = "registry+https://github.com/rust-lang/crates.io-index"
493
- checksum = "fe1bc77068bf406a6407dd9810fe80b70d9df18ce9069b2d5100b943f8caa638"
493
+ checksum = "501f1b96b5981e83d8328391dc6aa31df208dd8662f2b814117a345e570060ae"
494
494
  dependencies = [
495
495
  "ferogram-tl-parser",
496
496
  ]
497
497
 
498
498
  [[package]]
499
499
  name = "ferogram-tl-parser"
500
- version = "0.6.3"
500
+ version = "0.6.4"
501
501
  source = "registry+https://github.com/rust-lang/crates.io-index"
502
- checksum = "f092429c003263fa28e33f3090c41aedb2a7462fbc7b8f82172b0bf92ec1a205"
502
+ checksum = "d7337bdfb8be8eee3155a1af8ead1c34c2cfc2de738428574b1661d2094a7389"
503
503
 
504
504
  [[package]]
505
505
  name = "ferogram-tl-types"
506
- version = "0.6.3"
506
+ version = "0.6.4"
507
507
  source = "registry+https://github.com/rust-lang/crates.io-index"
508
- checksum = "ad3ec63abcbf0592390d400f73679d2149f9441c6c5ee8e9288b83ad32f76085"
508
+ checksum = "61d5a7ed4c2996730a9a35d06a33abaadc246dd828ba1ab5727bd5bbd8699a95"
509
509
  dependencies = [
510
510
  "ferogram-tl-gen",
511
511
  "ferogram-tl-parser",
@@ -1,8 +1,8 @@
1
1
  [package]
2
2
  name = "ferogram-py"
3
- version = "0.5.0"
3
+ version = "0.5.2"
4
4
  edition = "2024"
5
- description = "Python bindings for ferogram (Rust MTProto)"
5
+ description = "Python MTProto client based on ferogram (Rust MTProto)"
6
6
  build = "build.rs"
7
7
  license = "MIT OR Apache-2.0"
8
8
  readme = "README.md"
@@ -12,11 +12,11 @@ name = "_ferogram"
12
12
  crate-type = ["cdylib"]
13
13
 
14
14
  [dependencies]
15
- ferogram-mtsender = { version = "0.6.3" }
16
- ferogram-session = { version = "0.6.3", features = ["sqlite-session", "libsql-session"] }
17
- ferogram-connect = { version = "0.6.3" }
18
- ferogram-tl-types = { version = "0.6.3" }
19
- ferogram-crypto = { version = "0.6.3" }
15
+ ferogram-mtsender = { version = "0.6.4" }
16
+ ferogram-session = { version = "0.6.4", features = ["sqlite-session", "libsql-session"] }
17
+ ferogram-connect = { version = "0.6.4" }
18
+ ferogram-tl-types = { version = "0.6.4" }
19
+ ferogram-crypto = { version = "0.6.4" }
20
20
  getrandom = "0.2"
21
21
  base64 = "0.22"
22
22
  pyo3 = { version = "0.24", features = ["extension-module", "abi3-py39"] }
@@ -387,6 +387,7 @@ await client.upload_with_progress(path, on_progress=None)
387
387
  await client.edit_chat_photo(peer, path)
388
388
  await client.delete_profile_photos()
389
389
  await client.get_profile_photos(peer, limit=100)
390
+ await client.get_chat_photos(peer, limit=100)
390
391
  ```
391
392
 
392
393
  Important current behavior:
@@ -642,6 +643,11 @@ await client.get_authorizations()
642
643
  await client.terminate_session(hash)
643
644
  ```
644
645
 
646
+ `sign_out()` captures a `future_auth_token` when Telegram provides one, and
647
+ `request_login_code()` replays it automatically on the next login. When
648
+ that succeeds, Telegram authorizes the session immediately, no code entry
649
+ needed - check for `"_": "auth.sentCodeSuccess"` on the returned dict.
650
+
645
651
  ## Bot management
646
652
 
647
653
  ```python
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: ferogram
3
+ Version: 0.5.2
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Rust
9
+ Classifier: Topic :: Communications :: Chat
10
+ Classifier: Topic :: Software Development :: Libraries
11
+ License-File: LICENSE-APACHE
12
+ License-File: LICENSE-MIT
13
+ Summary: A modern, elegant, asynchronous MTProto framework for building Telegram user clients and bots in Python.
14
+ Keywords: telegram,mtproto,rust,client,bot,ferogram
15
+ Author-email: Ankit Chaubey <ankitchaubey.dev@gmail.com>
16
+ License: MIT OR Apache-2.0
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
19
+ Project-URL: Author, https://github.com/ankit-chaubey
20
+ Project-URL: Documentation, https://github.com/ankit-chaubey/ferogram-py#readme
21
+ Project-URL: Homepage, https://github.com/ankit-chaubey/ferogram-py
22
+ Project-URL: Source, https://github.com/ankit-chaubey/ferogram-py
23
+ Project-URL: Tracker, https://github.com/ankit-chaubey/ferogram-py/issues
24
+
25
+ <div align="center">
26
+
27
+ # ferogram-py
28
+
29
+ ![PyPI](https://img.shields.io/pypi/v/ferogram?style=flat-square&logo=pypi&logoColor=white&color=7C3AED)
30
+ ![Python](https://img.shields.io/pypi/pyversions/ferogram?style=flat-square&logo=python&logoColor=FFD43B&color=3B82F6)
31
+ ![Downloads](https://img.shields.io/pepy/dt/ferogram?style=flat-square&color=14B8A6)
32
+ ![License](https://img.shields.io/badge/License-MIT%20%7C%20Apache--2.0-64748B?style=flat-square)
33
+ ![Telegram](https://img.shields.io/badge/Telegram-FerogramChat-06B6D4?style=flat-square&logo=telegram&logoColor=white)
34
+
35
+ **A modern, elegant, asynchronous MTProto framework for building Telegram user clients and bots in Python.**
36
+
37
+ </div>
38
+
39
+ Powered by a high-performance [Rust core](https://github.com/ankit-chaubey/ferogram) that takes care of networking, encryption, TL parsing, and session management so you can focus on writing clean, idiomatic Python.
40
+
41
+ ---
42
+
43
+ ## Why ferogram-py?
44
+
45
+ Most of the heavy lifting in an MTProto client happens behind the scenes; networking, encryption, TL parsing, and keeping up with updates. ferogram-py lets a Rust core handle all of that, while exposing a clean, Pythonic API.
46
+
47
+ For most applications, the high-level API is all you'll need. But if you want to use a brand-new Telegram feature or need something more advanced, you can always drop down to the raw MTProto API and invoke requests directly.
48
+
49
+ The goal is to stay out of your way: simple things should be simple, and advanced things should still be possible.
50
+
51
+ > Quick API reference: [FEATURES.md](./FEATURES.md)
52
+
53
+ ---
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ pip install ferogram
59
+ ```
60
+
61
+ <details>
62
+ <summary>Building from source</summary>
63
+
64
+ ```bash
65
+ make dev # editable install into .venv (builds the Rust extension)
66
+ make build # release wheel for this machine
67
+ make codegen # regenerate TL code without a Rust rebuild
68
+ make test # run tests
69
+ make clean # wipe .venv, target, dist, generated/
70
+ ```
71
+
72
+ On Termux: `pkg install rust clang python` first.
73
+ Rust-only change, don't want to wait on codegen: `FEROGRAM_SKIP_CODEGEN=1 maturin develop`
74
+
75
+ </details>
76
+
77
+ ---
78
+
79
+ ## Quick start
80
+
81
+ **Bot:**
82
+
83
+ ```python
84
+ from ferogram import Client, filters
85
+
86
+ app = Client("mybot", api_id=0, api_hash="", bot_token="123:TOKEN")
87
+
88
+ @app.on_message(filters.command("start"))
89
+ async def start(client, message):
90
+ await message.reply("Hello!")
91
+
92
+ app.run()
93
+ ```
94
+
95
+ **User:**
96
+
97
+ ```python
98
+ import asyncio
99
+ from ferogram import Client
100
+
101
+ app = Client("myaccount", api_id=0, api_hash="", phone="+1234567890")
102
+
103
+ async def main():
104
+ async with app as client:
105
+ await client.send_message("me", "logged in")
106
+
107
+ asyncio.run(main())
108
+ ```
109
+
110
+ Credentials also work from env vars: `API_ID`, `API_HASH`, `BOT_TOKEN`.
111
+
112
+ ## Logging
113
+
114
+ ```python
115
+ import ferogram.logging as fero_log
116
+
117
+ fero_log.setup() # INFO to stderr
118
+ fero_log.setup(level=10) # DEBUG
119
+ ```
120
+
121
+ ## Architecture
122
+
123
+ ![architecture](https://github.com/ankit-chaubey/ferogram-py/blob/main/assets/architecture.svg)
124
+
125
+ The compiled extension (`_ferogram.so`) stays deliberately small: networking, encryption, session storage, and MTProto internals live in Rust. Everything you touch day to day, the client, handlers, filters, is plain Python and can change without a recompile.
126
+
127
+ <details>
128
+ <summary>Prebuilt Wheels for your platform</summary>
129
+
130
+ Wheels ship prebuilt for Linux (x86_64, aarch64), macOS (x86_64, arm64), Windows (x86_64), and Android/Termux (aarch64, x86_64). `pip install ferogram` grabs the right one on its own.
131
+
132
+ </details>
133
+
134
+ ---
135
+
136
+ ## License
137
+
138
+ This project is dual-licensed under:
139
+
140
+ - MIT License
141
+ - Apache License 2.0
142
+
143
+ You may choose either license.
144
+
145
+ You are free to use, modify, and distribute this software, including for commercial use, provided the original license and copyright notice are included.
146
+
147
+ See [`LICENSE-MIT`](https://github.com/ankit-chaubey/ferogram-py/blob/main/LICENSE-MIT) and [`LICENSE-APACHE`](https://github.com/ankit-chaubey/ferogram-py/blob/main/LICENSE-APACHE) for full details.
148
+
149
+ ---
150
+
151
+ ## Developer
152
+
153
+ Developed by [Ankit Chaubey](https://github.com/ankit-chaubey)
154
+
155
+ Don't forget to explore the Rust engine powering ferogram-py: [`ferogram`](https://github.com/ankit-chaubey/ferogram). Thanks for being part of the journey.
156
+
157
+ Join the ferogram community! Questions, discussions, bugs report and feedback are always welcome. As the project grows, we'll eventually split Python and Rust discussions into dedicated spaces.
158
+
159
+ - Channel (releases & announcements): [@Ferogram](https://t.me/Ferogram)
160
+
161
+ - (questions & discussion): [@FerogramChat](https://t.me/FerogramChat)
162
+
@@ -0,0 +1,137 @@
1
+ <div align="center">
2
+
3
+ # ferogram-py
4
+
5
+ ![PyPI](https://img.shields.io/pypi/v/ferogram?style=flat-square&logo=pypi&logoColor=white&color=7C3AED)
6
+ ![Python](https://img.shields.io/pypi/pyversions/ferogram?style=flat-square&logo=python&logoColor=FFD43B&color=3B82F6)
7
+ ![Downloads](https://img.shields.io/pepy/dt/ferogram?style=flat-square&color=14B8A6)
8
+ ![License](https://img.shields.io/badge/License-MIT%20%7C%20Apache--2.0-64748B?style=flat-square)
9
+ ![Telegram](https://img.shields.io/badge/Telegram-FerogramChat-06B6D4?style=flat-square&logo=telegram&logoColor=white)
10
+
11
+ **A modern, elegant, asynchronous MTProto framework for building Telegram user clients and bots in Python.**
12
+
13
+ </div>
14
+
15
+ Powered by a high-performance [Rust core](https://github.com/ankit-chaubey/ferogram) that takes care of networking, encryption, TL parsing, and session management so you can focus on writing clean, idiomatic Python.
16
+
17
+ ---
18
+
19
+ ## Why ferogram-py?
20
+
21
+ Most of the heavy lifting in an MTProto client happens behind the scenes; networking, encryption, TL parsing, and keeping up with updates. ferogram-py lets a Rust core handle all of that, while exposing a clean, Pythonic API.
22
+
23
+ For most applications, the high-level API is all you'll need. But if you want to use a brand-new Telegram feature or need something more advanced, you can always drop down to the raw MTProto API and invoke requests directly.
24
+
25
+ The goal is to stay out of your way: simple things should be simple, and advanced things should still be possible.
26
+
27
+ > Quick API reference: [FEATURES.md](./FEATURES.md)
28
+
29
+ ---
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install ferogram
35
+ ```
36
+
37
+ <details>
38
+ <summary>Building from source</summary>
39
+
40
+ ```bash
41
+ make dev # editable install into .venv (builds the Rust extension)
42
+ make build # release wheel for this machine
43
+ make codegen # regenerate TL code without a Rust rebuild
44
+ make test # run tests
45
+ make clean # wipe .venv, target, dist, generated/
46
+ ```
47
+
48
+ On Termux: `pkg install rust clang python` first.
49
+ Rust-only change, don't want to wait on codegen: `FEROGRAM_SKIP_CODEGEN=1 maturin develop`
50
+
51
+ </details>
52
+
53
+ ---
54
+
55
+ ## Quick start
56
+
57
+ **Bot:**
58
+
59
+ ```python
60
+ from ferogram import Client, filters
61
+
62
+ app = Client("mybot", api_id=0, api_hash="", bot_token="123:TOKEN")
63
+
64
+ @app.on_message(filters.command("start"))
65
+ async def start(client, message):
66
+ await message.reply("Hello!")
67
+
68
+ app.run()
69
+ ```
70
+
71
+ **User:**
72
+
73
+ ```python
74
+ import asyncio
75
+ from ferogram import Client
76
+
77
+ app = Client("myaccount", api_id=0, api_hash="", phone="+1234567890")
78
+
79
+ async def main():
80
+ async with app as client:
81
+ await client.send_message("me", "logged in")
82
+
83
+ asyncio.run(main())
84
+ ```
85
+
86
+ Credentials also work from env vars: `API_ID`, `API_HASH`, `BOT_TOKEN`.
87
+
88
+ ## Logging
89
+
90
+ ```python
91
+ import ferogram.logging as fero_log
92
+
93
+ fero_log.setup() # INFO to stderr
94
+ fero_log.setup(level=10) # DEBUG
95
+ ```
96
+
97
+ ## Architecture
98
+
99
+ ![architecture](https://github.com/ankit-chaubey/ferogram-py/blob/main/assets/architecture.svg)
100
+
101
+ The compiled extension (`_ferogram.so`) stays deliberately small: networking, encryption, session storage, and MTProto internals live in Rust. Everything you touch day to day, the client, handlers, filters, is plain Python and can change without a recompile.
102
+
103
+ <details>
104
+ <summary>Prebuilt Wheels for your platform</summary>
105
+
106
+ Wheels ship prebuilt for Linux (x86_64, aarch64), macOS (x86_64, arm64), Windows (x86_64), and Android/Termux (aarch64, x86_64). `pip install ferogram` grabs the right one on its own.
107
+
108
+ </details>
109
+
110
+ ---
111
+
112
+ ## License
113
+
114
+ This project is dual-licensed under:
115
+
116
+ - MIT License
117
+ - Apache License 2.0
118
+
119
+ You may choose either license.
120
+
121
+ You are free to use, modify, and distribute this software, including for commercial use, provided the original license and copyright notice are included.
122
+
123
+ See [`LICENSE-MIT`](https://github.com/ankit-chaubey/ferogram-py/blob/main/LICENSE-MIT) and [`LICENSE-APACHE`](https://github.com/ankit-chaubey/ferogram-py/blob/main/LICENSE-APACHE) for full details.
124
+
125
+ ---
126
+
127
+ ## Developer
128
+
129
+ Developed by [Ankit Chaubey](https://github.com/ankit-chaubey)
130
+
131
+ Don't forget to explore the Rust engine powering ferogram-py: [`ferogram`](https://github.com/ankit-chaubey/ferogram). Thanks for being part of the journey.
132
+
133
+ Join the ferogram community! Questions, discussions, bugs report and feedback are always welcome. As the project grows, we'll eventually split Python and Rust discussions into dedicated spaces.
134
+
135
+ - Channel (releases & announcements): [@Ferogram](https://t.me/Ferogram)
136
+
137
+ - (questions & discussion): [@FerogramChat](https://t.me/FerogramChat)