ferogram 0.5.2__tar.gz → 0.5.2b2__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 (109) hide show
  1. {ferogram-0.5.2 → ferogram-0.5.2b2}/.github/workflows/publish.yml +26 -6
  2. ferogram-0.5.2b2/CHANGELOG.md +201 -0
  3. {ferogram-0.5.2 → ferogram-0.5.2b2}/Cargo.lock +8 -16
  4. {ferogram-0.5.2 → ferogram-0.5.2b2}/Cargo.toml +5 -5
  5. {ferogram-0.5.2 → ferogram-0.5.2b2}/PKG-INFO +1 -1
  6. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/client.py +183 -49
  7. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/codegen.py +105 -48
  8. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/_base.py +13 -9
  9. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/stories.py +4 -0
  10. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/proxy.py +79 -10
  11. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/tl.py +68 -8
  12. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/types.py +18 -1
  13. {ferogram-0.5.2 → ferogram-0.5.2b2}/pyproject.toml +1 -1
  14. {ferogram-0.5.2 → ferogram-0.5.2b2}/src/connection.rs +6 -6
  15. {ferogram-0.5.2 → ferogram-0.5.2b2}/src/pipelined.rs +4 -1
  16. ferogram-0.5.2/CHANGELOG.md +0 -234
  17. {ferogram-0.5.2 → ferogram-0.5.2b2}/.github/workflows/compile-check.yml +0 -0
  18. {ferogram-0.5.2 → ferogram-0.5.2b2}/.gitignore +0 -0
  19. {ferogram-0.5.2 → ferogram-0.5.2b2}/.readthedocs.yaml +0 -0
  20. {ferogram-0.5.2 → ferogram-0.5.2b2}/FEATURES.md +0 -0
  21. {ferogram-0.5.2 → ferogram-0.5.2b2}/LICENSE-APACHE +0 -0
  22. {ferogram-0.5.2 → ferogram-0.5.2b2}/LICENSE-MIT +0 -0
  23. {ferogram-0.5.2 → ferogram-0.5.2b2}/Makefile +0 -0
  24. {ferogram-0.5.2 → ferogram-0.5.2b2}/README.md +0 -0
  25. {ferogram-0.5.2 → ferogram-0.5.2b2}/assets/architecture.svg +0 -0
  26. {ferogram-0.5.2 → ferogram-0.5.2b2}/build.rs +0 -0
  27. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/admin_tools.py +0 -0
  28. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/command_bot.py +0 -0
  29. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/echo_bot.py +0 -0
  30. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/group_management.py +0 -0
  31. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/media_bot.py +0 -0
  32. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/raw_invoke.py +0 -0
  33. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/rich_message.py +0 -0
  34. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/search_bot.py +0 -0
  35. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/send_hi.py +0 -0
  36. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/send_media.py +0 -0
  37. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/send_message.py +0 -0
  38. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/update_handlers.py +0 -0
  39. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/user_management.py +0 -0
  40. {ferogram-0.5.2 → ferogram-0.5.2b2}/examples/userbot.py +0 -0
  41. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/__init__.py +0 -0
  42. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/api.tl +0 -0
  43. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/filters.py +0 -0
  44. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/keyboards.py +0 -0
  45. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/logging.py +0 -0
  46. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/py.typed +0 -0
  47. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/__init__.py +0 -0
  48. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/api/__init__.py +0 -0
  49. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/api/functions.py +0 -0
  50. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/api/types.py +0 -0
  51. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/__init__.py +0 -0
  52. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/_tl_schema.py +0 -0
  53. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/__init__.py +0 -0
  54. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/account.py +0 -0
  55. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/aicompose.py +0 -0
  56. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/auth.py +0 -0
  57. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/bots.py +0 -0
  58. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/channels.py +0 -0
  59. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/chatlists.py +0 -0
  60. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/communities.py +0 -0
  61. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/contacts.py +0 -0
  62. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/ephemeral.py +0 -0
  63. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/folders.py +0 -0
  64. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/fragment.py +0 -0
  65. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/help.py +0 -0
  66. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/langpack.py +0 -0
  67. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/messages.py +0 -0
  68. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/payments.py +0 -0
  69. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/phone.py +0 -0
  70. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/photos.py +0 -0
  71. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/premium.py +0 -0
  72. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/smsjobs.py +0 -0
  73. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/stats.py +0 -0
  74. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/stickers.py +0 -0
  75. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/stories.py +0 -0
  76. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/updates.py +0 -0
  77. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/upload.py +0 -0
  78. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/functions/users.py +0 -0
  79. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/__init__.py +0 -0
  80. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/account.py +0 -0
  81. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/aicompose.py +0 -0
  82. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/auth.py +0 -0
  83. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/bots.py +0 -0
  84. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/channels.py +0 -0
  85. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/chatlists.py +0 -0
  86. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/communities.py +0 -0
  87. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/contacts.py +0 -0
  88. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/fragment.py +0 -0
  89. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/help.py +0 -0
  90. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/messages.py +0 -0
  91. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/payments.py +0 -0
  92. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/phone.py +0 -0
  93. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/photos.py +0 -0
  94. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/premium.py +0 -0
  95. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/smsjobs.py +0 -0
  96. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/stats.py +0 -0
  97. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/stickers.py +0 -0
  98. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/storage.py +0 -0
  99. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/updates.py +0 -0
  100. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/upload.py +0 -0
  101. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/raw/generated/types/users.py +0 -0
  102. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/rich.py +0 -0
  103. {ferogram-0.5.2 → ferogram-0.5.2b2}/ferogram/updates.py +0 -0
  104. {ferogram-0.5.2 → ferogram-0.5.2b2}/src/lib.rs +0 -0
  105. {ferogram-0.5.2 → ferogram-0.5.2b2}/src/raw.rs +0 -0
  106. {ferogram-0.5.2 → ferogram-0.5.2b2}/src/session.rs +0 -0
  107. {ferogram-0.5.2 → ferogram-0.5.2b2}/src/srp.rs +0 -0
  108. {ferogram-0.5.2 → ferogram-0.5.2b2}/tests/test_rich.py +0 -0
  109. {ferogram-0.5.2 → ferogram-0.5.2b2}/tests/test_tl_roundtrip.py +0 -0
@@ -218,12 +218,12 @@ jobs:
218
218
  export CARGO_TARGET_${TARGET_UPPER}_LINKER=$NDK_BIN/${CLANG_PREFIX}-clang
219
219
 
220
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.
221
+ # stub) so the build succeeds. This still embeds a version-pinned
222
+ # DT_NEEDED at this point - the next step rewrites it to be
223
+ # version-agnostic, since bionic requires DT_NEEDED to resolve by
224
+ # exact filename at dlopen time and won't fall back to whatever
225
+ # Python happens to already be resident in the process, unlike
226
+ # glibc.
227
227
  export RUSTFLAGS="-L native=$TERMUX_LIBDIR"
228
228
 
229
229
  maturin build \
@@ -232,6 +232,26 @@ jobs:
232
232
  --compatibility off \
233
233
  --out dist
234
234
 
235
+ - name: Rewrite libpython dependency to be version-agnostic
236
+ run: |
237
+ which patchelf >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y patchelf)
238
+ for whl in dist/*.whl; do
239
+ whl_abs=$(readlink -f "$whl")
240
+ workdir=$(mktemp -d)
241
+ unzip -q "$whl_abs" -d "$workdir"
242
+ so_file=$(find "$workdir" -name "_ferogram*.so" | head -1)
243
+ if [ -z "$so_file" ]; then
244
+ echo "::error::No _ferogram*.so found inside $whl"
245
+ exit 1
246
+ fi
247
+ patchelf --replace-needed "libpython${TERMUX_PYVER}.so" "libpython3.so" "$so_file"
248
+ echo "Patched $so_file: DT_NEEDED libpython${TERMUX_PYVER}.so -> libpython3.so"
249
+
250
+ rm -f "$whl_abs"
251
+ (cd "$workdir" && zip -qr "$whl_abs" .)
252
+ rm -rf "$workdir"
253
+ done
254
+
235
255
  - uses: actions/upload-artifact@v4
236
256
  with:
237
257
  name: wheels-android-${{ matrix.target }}
@@ -0,0 +1,201 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Added
8
+
9
+ - `Chat.is_community` and `Dialog.community_id` / `Dialog.is_community` properties for community support.
10
+ - `get_dialogs()` and `get_pinned_dialogs()` now handle `dialogCommunity` via `community_id` instead of assuming a `peer` field is present.
11
+
12
+ ### Changed
13
+
14
+ - The peer cache now tracks communities separately from channels instead of collapsing them together. `chatEmpty` is no longer cached as a basic chat, and a stored non-zero access hash can no longer be overwritten by a zero one.
15
+ - `serialize_object` now dispatches to the generated `to_bytes()` implementation before falling back to generic field serialization, a roughly 1.7x improvement in serialization throughput. Output was verified byte-identical across all 2,437 constructors in the schema.
16
+
17
+ ### Fixed
18
+
19
+ - TL codegen assumed a constructor's `flags:#` word is always the first field on the wire and hoisted it to the front of `from_bytes()` / `to_bytes()` unconditionally. `poll#966e2dbf`, `wallPaper#a437c3ed`, and `wallPaperNoFile#e0804116` all declare `id:long` before `flags:#`, so those two fields were read and written swapped, producing a garbage flags word that could trigger optional fields that weren't actually present and eventually overrun the buffer. This was the root cause of the corruption seen in `updates.getDifference`. Codegen now tracks each flag marker's real position in the schema and emits it there instead of assuming it comes first.
20
+ - Related codegen bug: `exportedChatlistInvite` and `stories.allStoriesNotModified` declare `flags:#` with no field gated on it. Codegen treated "no field uses this flag group" as "no flags word on the wire" and silently dropped 4 bytes, misaligning every field after it. Flag group presence is now determined from declared markers, not from field usage.
21
+ - `ferogram/raw/tl.py`'s runtime fallback interpreter (`_read_value` / `serialize_object`) had the same "flags always first" assumption baked in. Fixed to read and write each flag group at its correct wire position.
22
+ - Regenerated all 1,642 generated types and 795 functions from `api.tl`. `tests/test_tl_roundtrip.py` (4,874 constructor x optional-field combinations) now passes.
23
+ - `join_chat()` and `join_invite_link()` assumed a bare `Updates` response and broke on `messages.ChatInviteJoinResult`. The `Ok` variant now resolves and caches the joined peer; the `WebView` variant returns `None`, since it requires an interactive bot flow that isn't supported yet.
24
+ - `promote_participant(rights=...)` merged the requested rights into a fixed base set instead of replacing it, so limited admin permissions could never actually be granted. It now replaces the requested rights as intended.
25
+ - `send_message()`, `edit_message()`, and `forward_messages()` ignored caller-supplied values for `no_webpage`, `silent`, `schedule_date`, and `send_as` in favor of hardcoded defaults. These parameters are now respected.
26
+ - `send_invoice(test=...)`, `add_contact(add_phone_privacy_exception=...)`, and `get_blocked_users(my_stories_from=...)` ignored the supplied value and always sent a hardcoded default. Fixed.
27
+
28
+ ## [0.5.2] - 2026-07-17
29
+
30
+ ### Added
31
+
32
+ - `Client.get_chat_photos(peer, limit)`: photo and avatar history for groups and channels. `get_profile_photos` only ever worked for users. The current photo comes from the chat's full info, so it survives message deletion; older photos come from `messageActionChatEditPhoto` search history.
33
+ - Fast re-auth support: `sign_out()` captures a `future_auth_token` when Telegram returns one and persists it through a new `DcConnection.get_future_auth_token` / `set_future_auth_token` pair, riding along in the existing session blob with no new session format required. `request_login_code()` replays it automatically, so a returning session can skip code entry entirely (`auth.sentCodeSuccess`).
34
+
35
+ ### Fixed
36
+
37
+ - MTProto handshake fix pulled in transitively via `ferogram-mtsender`: a DC-tagged `p_q_inner_data` was being rejected by Telegram with RPC error 444 outside DC2.
38
+
39
+ ### Changed
40
+
41
+ - Layer upgraded to 228.
42
+
43
+ ## [0.5.1] - 2026-06-29
44
+
45
+ ### Added
46
+
47
+ - `Message.respond()` for sending a message to the same chat without replying.
48
+ - `Message.pin()`, `forward_to()`, `get_sender()`, `get_chat()`, and `get_reply_message()` helpers.
49
+ - `Message.reply_photo()` and `reply_document()` convenience methods.
50
+ - `reply_to` support in `send_message()`, `send_photo()`, and `send_document()`.
51
+ - `Client.get_user()` and `Client.get_chat()` helpers.
52
+ - `reply_markup` parameter on `edit_message()`.
53
+ - `notify` parameter on `pin_message()`.
54
+ - Convenience methods on `CallbackQuery`: `respond()`, `reply()`, `edit_message_text()`, `get_sender()`.
55
+ - Convenience methods on `InlineQuery`: `answer()`, `get_sender()`.
56
+ - Sender and entity helpers on additional update types: `InlineSend`, `UserStatus`, `ChatAction`, `JoinRequest`, `ParticipantUpdate`, `MessageReaction`, `ChatBoost`, `ShippingQuery`, `PreCheckoutQuery`.
57
+ - `_client` binding added to the remaining update wrappers, including `RawUpdate`.
58
+
59
+ ### Changed
60
+
61
+ - Sent message extraction fallback now logs a warning and preserves context instead of failing silently.
62
+
63
+ ### Fixed
64
+
65
+ - `Message.reply()` now creates a proper quoted reply using `reply_to=self.id`.
66
+ - `Message.delete()` now correctly handles channels and supergroups.
67
+ - `delete_messages_in()` is now channel-aware.
68
+ - `_dispatch()` now binds `_client` for all update types.
69
+
70
+ ## [0.5.0] - 2026-06-28
71
+
72
+ The Rust dependency changed from the monolithic `ferogram` crate to five focused crates from the ferogram core:
73
+
74
+ - `ferogram-mtsender`: MTProto sender, message framing, and acknowledgement.
75
+ - `ferogram-session`: session storage (file, SQLite, libSQL, memory, string).
76
+ - `ferogram-connect`: TCP/TLS transport and DC routing.
77
+ - `ferogram-tl-types`: generated TL type definitions.
78
+ - `ferogram-crypto`: AES-IGE, Diffie-Hellman, and SHA helpers.
79
+
80
+ 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 keeps the compiled extension smaller and faster to build, and lets Python-side behavior be updated without recompiling the Rust extension.
81
+
82
+ The compiled extension now uses `abi3-py39` (was `abi3-py313`), so a single wheel runs on Python 3.9 and later.
83
+
84
+ ### Added
85
+
86
+ - `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`.
87
+ - `TransferCancelled` exception, raised when a `TransferHandle` is cancelled mid-transfer.
88
+ - `keyboards` module: `InlineKeyboard`, `InlineButton`, `ReplyKeyboard`, `ReplyButton`, `RemoveKeyboard`, and `ForceReply` are now pure Python and importable from `ferogram` directly.
89
+ - `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 unchanged.
90
+ - `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.
91
+ - `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, timestamps, and custom emoji via Markdown or HTML input.
92
+ - 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 it if you only changed Rust. Codegen uses the same Python interpreter maturin selected.
93
+ - `DcConnection` and `srp_calculate` exposed from the Rust extension for use by the pure-Python `Client` class.
94
+ - `LAYER` constant exported from `ferogram.raw.generated._tl_schema` and used automatically in `invokeWithLayer` wrappers.
95
+ - `all_updates` filter, replacing the old `all` filter, which shadowed the Python built-in.
96
+
97
+ ### Changed
98
+
99
+ - `Message`, `User`, `Chat`, and all entity types are now Python dataclasses instead of PyO3 structs. They serialize to and from the TL dict representation in Python, with no change to the public API.
100
+ - `CallbackQuery`, `InlineQuery`, and all update types are now Python dataclasses.
101
+ - `InlineKeyboard`, `ReplyKeyboard`, and related keyboard builders are now pure Python (`ferogram/keyboards.py`); previously they were Rust structs.
102
+ - Filters rewritten to correctly unwrap update wrapper objects before inspecting the inner `Message`. Previously filters broke when the dispatcher passed wrapper objects instead of bare messages. `reply` now checks `reply_to_msg_id`; `forwarded` checks `forward_from_id`; `media` checks the `media` field directly.
103
+ - `codegen.py` doubled in size, from 321 to 691 lines. It now generates specialized `to_bytes()` methods using inline `struct.pack` calls and a CID-dispatch `from_bytes()` router, producing faster serialization and deserialization than the previous schema-dict approach.
104
+ - `ferogram-py` version bumped to 0.5.0. Core crates pinned to `ferogram-*` 0.6.3.
105
+
106
+ ### Removed
107
+
108
+ - Direct dependency on the monolithic `ferogram` crate, replaced by the five focused crates described above.
109
+ - Unused `hex` crate dependency (was `0.4`).
110
+ - `all` filter, replaced with `all_updates` to avoid shadowing Python's built-in `all`.
111
+
112
+ ## [0.4.1] - 2026-06-03
113
+
114
+ Patch release. No API changes. Identical to 0.4.0 except for dependency pins and minor internal fixes.
115
+
116
+ ## [0.4.0] - 2026-06-01
117
+
118
+ ### Added
119
+
120
+ - Session backends: `FileSession`, `MemorySession`, `StringSession`, `SqliteSession`, `LibSqlSession`, and `CustomSession` are now first-class types importable from `ferogram`. Pass any of them as the `session` argument to `Client`; plain string names still work as before.
121
+ - `SqliteSession("name")` stores the session in a SQLite database.
122
+ - `MemorySession()` keeps the session in memory only; nothing is written to disk.
123
+ - `StringSession("AQA...")` resumes from a base64 string, useful for serverless or env-var based deployments.
124
+ - `LibSqlSession.local/remote/replica/memory(...)` targets a local file, remote Turso database, embedded replica, or in-memory libSQL database.
125
+ - `CustomSession(obj)` wraps any Python object implementing `save(bytes)`, `load() -> bytes | None`, and `delete()`.
126
+ - `channel_kind()` on `Message`: `await msg.channel_kind()` returns `"megagroup"`, `"broadcast"`, `"gigagroup"`, or `None`. Uses the peer cache; no RPC call.
127
+ - `is_megagroup()` on `Message`: `await msg.is_megagroup()` returns `True` for supergroups.
128
+ - `is_broadcast()` on `Message`: `await msg.is_broadcast()` returns `True` for broadcast channels.
129
+ - `StopPropagation` and `ContinuePropagation` exceptions exported from `ferogram` to control handler dispatch. `StopPropagation` stops all further group processing; `ContinuePropagation` skips the current handler and continues to the next match in the same group.
130
+ - Handler groups: all `on_*` decorators now accept `group: int = 0`. Handlers run in ascending group order, with lower group numbers running first.
131
+ - `add_handler()` / `remove_handler()` to register and deregister handlers at runtime without decorators.
132
+ - Worker pool: a fixed pool of `workers` coroutines (default 4) now dispatches updates from a bounded `asyncio.Queue`, replacing the old unbounded `asyncio.create_task` approach and providing natural backpressure under load.
133
+ - `workers` kwarg on `Client` to control pool size.
134
+ - `parse_mode` kwarg on `Client`, setting a global default parse mode applied to every `send_message` call that doesn't pass its own `parse_mode`.
135
+ - `flood_sleep_threshold` kwarg on `Client`, mapping 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.
136
+ - `download_with_progress(peer, msg_id, path, on_progress)`: download media with a progress callback `on_progress(done, total)`.
137
+ - `upload_with_progress(path, on_progress)`: upload a file with a progress callback, returning a handle string accepted by `send_file`.
138
+ - ferogram 0.6.0 as the core dependency, including `Client.channel_kind_of(channel_id)`, which backs the new `Message` methods above.
139
+
140
+ ### Changed
141
+
142
+ - `no_webpage` now defaults to `True` in `send_message` and `edit_message`.
143
+ - `upload_file(data, name, mime)` replaced by `upload(Cursor(data), name)` internally, with no change to the Python API.
144
+ - Session resolution order is now `session_string > session object`. `in_memory=True` is deprecated in favor of `MemorySession()`.
145
+ - Handler storage changed from `list` to `dict[group, list]`; dispatch now iterates groups in sorted order.
146
+ - `_resolve_pm` is now used internally to merge per-call and global `parse_mode`.
147
+
148
+ ### Fixed
149
+
150
+ - `channel_kind`, `is_megagroup`, and `is_broadcast` on `Message` no longer call `get_chat_full` (an RPC) on every invocation; they read from the peer cache via `Client.channel_kind_of`.
151
+ - Unnecessary `as i64` casts removed from `message.rs`.
152
+ - Nested `if let` blocks collapsed to `if let ... && ...`.
153
+ - `match ... { Some(m) => m, None => return None }` replaced with `as_ref()?`.
154
+
155
+ ## [0.3.0] - 2026-05-16
156
+
157
+ The Rust dependency is now ferogram 0.5.0.
158
+
159
+ ### Added
160
+
161
+ - `send_poll` now accepts all options the Rust `PollBuilder` supports: `public_voters`, `shuffle_answers`, `hide_results_until_close`, `close_period`, `close_date`, and `solution`. Previously only `quiz`, `correct_index`, and `multiple_choice` were wired through.
162
+ - The `restrictions` dict passed to `edit_chat_default_banned_rights` now accepts `"send_reactions"` as a key, mirroring the new `send_reactions` field on `BannedRightsBuilder` added in ferogram 0.5.0.
163
+ - `poll_results(peer, msg_id)` is now the canonical way to fetch poll stats, returning the votes graph as a JSON string.
164
+
165
+ ### Deprecated
166
+
167
+ - `get_poll_results(peer, msg_id, poll_hash)` is kept for backward compatibility but is deprecated in favor of `poll_results`. Its `poll_hash` parameter is now ignored, because ferogram 0.5.0 dropped the underlying API call it relied on.
168
+
169
+ ## [0.2.3] - 2026-05-14
170
+
171
+ ### Added
172
+
173
+ - **Client builder**: 20 new kwargs to `Client(...)` so everything can be configured at construction time instead of by touching internals.
174
+ - Network: `proxy` (SOCKS5 or MTProxy t.me link), `allow_ipv6`, `dc_addr`, `probe_transport`, `resilient_connect`.
175
+ - Session backend: `session_string` and `in_memory` as alternatives to the default session file, with priority `in_memory > session_string > file`.
176
+ - Update handling: `catch_up`, `pfs`, `update_queue_capacity`, `update_overflow` (`"drop_oldest"` or `"drop_newest"`), `low_memory_mode`.
177
+ - InitConnection identity: `device`, `system_version`, `app_version`, `lang_code`, `system_lang_code`, `lang_pack`.
178
+ - Experimental: `allow_missing_channel_hash`, `auto_resolve_peers`.
179
+ - **Inline bots**: `InlineArticle`, `InlinePhoto`, and `InlineDocument` now expose all their fields; previously only the three required fields worked. New fields: `description`, `url`, `thumb_url`, `reply_markup` on articles; `photo_url`, `photo_width`, `photo_height`, `thumb_url`, `mime_type`, `reply_markup` on photos; `document_url`, `mime_type`, `description`, `thumb_url`, `reply_markup` on documents.
180
+ - `answer_inline_query` now accepts `next_offset` for pagination and `switch_pm` to show a "go to PM" button in the results list.
181
+ - `answer_inline_query_articles` is now accessible from Python, taking a plain list of `(id, title, text)` tuples and supporting `next_offset`.
182
+ - `edit_inline_message` now accepts `reply_markup`, so a keyboard can be attached or updated when editing.
183
+ - `InlineSend` now exposes `msg_id_bytes` and `msg_id_dc`, so an `InlineMessageId` can be built from the send event and used to edit the message later.
184
+ - **Participants**: ten new methods for managing group and channel members.
185
+ - `get_participants(peer, limit=200)` fetches all members as a list of `ChatMember`.
186
+ - `get_participants_filtered(peer, filter, limit)` fetches a filtered subset. Filter values: `"recent"`, `"admins"`, `"kicked"`, `"banned"`, `"bots"`.
187
+ - `kick_participant(peer, user)` removes a user from the chat; they can rejoin if the chat is public or they have an invite link.
188
+ - `ban_participant(peer, user)` permanently bans a user until an admin manually lifts it.
189
+ - `ban_participant_until(peer, user, until_date)` bans until a Unix timestamp, after which the ban lifts automatically.
190
+ - `promote_participant(peer, user, rights)` promotes to admin with specific rights; pass `rights=None` to grant all. Valid right strings: `"change_info"`, `"post_messages"`, `"edit_messages"`, `"delete_messages"`, `"ban_users"`, `"invite_users"`, `"pin_messages"`, `"add_admins"`, `"manage_call"`.
191
+ - `demote_participant(peer, user)` strips all admin rights, leaving the user as a regular member.
192
+ - `get_profile_photos(peer, limit=100)` returns a list of `(file_id, access_hash, dc_id)` tuples.
193
+ - `search_peer(query)` searches the local peer cache by name or username and returns a list of peer identifier strings.
194
+ - `signal_network_restored()` (sync, not async) tells the client the network is back so it attempts reconnection immediately instead of waiting for the retry timer.
195
+ - **Reactions and polls**:
196
+ - `delete_reaction(peer, msg_id, participant)` existed in Rust but had no Python wrapper; now exposed. Removes a specific user's reaction from a message, admin only.
197
+ - `get_poll_results(peer, msg_id, poll_hash)` existed in Rust but had no Python wrapper; now exposed. Fetches and caches the latest poll results from Telegram.
198
+
199
+ ## [0.2.2]
200
+
201
+ Releases prior to 0.2.2 were not documented in this changelog.
@@ -393,8 +393,7 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
393
393
  [[package]]
394
394
  name = "ferogram-connect"
395
395
  version = "0.6.4"
396
- source = "registry+https://github.com/rust-lang/crates.io-index"
397
- checksum = "54211f9669f8bb7db8101d952514784311a1e135c01eb04d8732d465cdb2aa73"
396
+ source = "git+https://github.com/ankit-chaubey/ferogram?rev=f747bf418da2f8d9f6288cc5aa56875034c112f9#f747bf418da2f8d9f6288cc5aa56875034c112f9"
398
397
  dependencies = [
399
398
  "ferogram-crypto",
400
399
  "ferogram-mtproto",
@@ -410,8 +409,7 @@ dependencies = [
410
409
  [[package]]
411
410
  name = "ferogram-crypto"
412
411
  version = "0.6.4"
413
- source = "registry+https://github.com/rust-lang/crates.io-index"
414
- checksum = "0e9b1bf8c53553a3fa8acbfdc0f9f9ede749f786a5d62c26c57a4dd20b793b4d"
412
+ source = "git+https://github.com/ankit-chaubey/ferogram?rev=f747bf418da2f8d9f6288cc5aa56875034c112f9#f747bf418da2f8d9f6288cc5aa56875034c112f9"
415
413
  dependencies = [
416
414
  "aes",
417
415
  "ctr",
@@ -428,8 +426,7 @@ dependencies = [
428
426
  [[package]]
429
427
  name = "ferogram-mtproto"
430
428
  version = "0.6.4"
431
- source = "registry+https://github.com/rust-lang/crates.io-index"
432
- checksum = "007456e26302ca4a2f63019ed88c2055705ecf7752f823520d41aa2f8803b42e"
429
+ source = "git+https://github.com/ankit-chaubey/ferogram?rev=f747bf418da2f8d9f6288cc5aa56875034c112f9#f747bf418da2f8d9f6288cc5aa56875034c112f9"
433
430
  dependencies = [
434
431
  "ferogram-crypto",
435
432
  "ferogram-tl-types",
@@ -442,8 +439,7 @@ dependencies = [
442
439
  [[package]]
443
440
  name = "ferogram-mtsender"
444
441
  version = "0.6.4"
445
- source = "registry+https://github.com/rust-lang/crates.io-index"
446
- checksum = "4fb2d34f025b0c6369d42f08317e3ded5bb8aa83bdec48fd443a4cc26fa4c9cf"
442
+ source = "git+https://github.com/ankit-chaubey/ferogram?rev=f747bf418da2f8d9f6288cc5aa56875034c112f9#f747bf418da2f8d9f6288cc5aa56875034c112f9"
447
443
  dependencies = [
448
444
  "ferogram-connect",
449
445
  "ferogram-crypto",
@@ -475,8 +471,7 @@ dependencies = [
475
471
  [[package]]
476
472
  name = "ferogram-session"
477
473
  version = "0.6.4"
478
- source = "registry+https://github.com/rust-lang/crates.io-index"
479
- checksum = "c29506aee6e38e3f62623f28f17dfa470f347a87f65030313bf62f9b8dd12dd1"
474
+ source = "git+https://github.com/ankit-chaubey/ferogram?rev=f747bf418da2f8d9f6288cc5aa56875034c112f9#f747bf418da2f8d9f6288cc5aa56875034c112f9"
480
475
  dependencies = [
481
476
  "base64 0.22.1",
482
477
  "libsql",
@@ -489,8 +484,7 @@ dependencies = [
489
484
  [[package]]
490
485
  name = "ferogram-tl-gen"
491
486
  version = "0.6.4"
492
- source = "registry+https://github.com/rust-lang/crates.io-index"
493
- checksum = "501f1b96b5981e83d8328391dc6aa31df208dd8662f2b814117a345e570060ae"
487
+ source = "git+https://github.com/ankit-chaubey/ferogram?rev=f747bf418da2f8d9f6288cc5aa56875034c112f9#f747bf418da2f8d9f6288cc5aa56875034c112f9"
494
488
  dependencies = [
495
489
  "ferogram-tl-parser",
496
490
  ]
@@ -498,14 +492,12 @@ dependencies = [
498
492
  [[package]]
499
493
  name = "ferogram-tl-parser"
500
494
  version = "0.6.4"
501
- source = "registry+https://github.com/rust-lang/crates.io-index"
502
- checksum = "d7337bdfb8be8eee3155a1af8ead1c34c2cfc2de738428574b1661d2094a7389"
495
+ source = "git+https://github.com/ankit-chaubey/ferogram?rev=f747bf418da2f8d9f6288cc5aa56875034c112f9#f747bf418da2f8d9f6288cc5aa56875034c112f9"
503
496
 
504
497
  [[package]]
505
498
  name = "ferogram-tl-types"
506
499
  version = "0.6.4"
507
- source = "registry+https://github.com/rust-lang/crates.io-index"
508
- checksum = "61d5a7ed4c2996730a9a35d06a33abaadc246dd828ba1ab5727bd5bbd8699a95"
500
+ source = "git+https://github.com/ankit-chaubey/ferogram?rev=f747bf418da2f8d9f6288cc5aa56875034c112f9#f747bf418da2f8d9f6288cc5aa56875034c112f9"
509
501
  dependencies = [
510
502
  "ferogram-tl-gen",
511
503
  "ferogram-tl-parser",
@@ -12,11 +12,11 @@ name = "_ferogram"
12
12
  crate-type = ["cdylib"]
13
13
 
14
14
  [dependencies]
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" }
15
+ ferogram-mtsender = { git = "https://github.com/ankit-chaubey/ferogram", rev = "f747bf418da2f8d9f6288cc5aa56875034c112f9" }
16
+ ferogram-session = { git = "https://github.com/ankit-chaubey/ferogram", rev = "f747bf418da2f8d9f6288cc5aa56875034c112f9", features = ["sqlite-session", "libsql-session"] }
17
+ ferogram-connect = { git = "https://github.com/ankit-chaubey/ferogram", rev = "f747bf418da2f8d9f6288cc5aa56875034c112f9" }
18
+ ferogram-tl-types = { git = "https://github.com/ankit-chaubey/ferogram", rev = "f747bf418da2f8d9f6288cc5aa56875034c112f9" }
19
+ ferogram-crypto = { git = "https://github.com/ankit-chaubey/ferogram", rev = "f747bf418da2f8d9f6288cc5aa56875034c112f9" }
20
20
  getrandom = "0.2"
21
21
  base64 = "0.22"
22
22
  pyo3 = { version = "0.24", features = ["extension-module", "abi3-py39"] }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ferogram
3
- Version: 0.5.2
3
+ Version: 0.5.2b2
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License