tgblocks 0.2.2__tar.gz → 0.2.4__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 (63) hide show
  1. {tgblocks-0.2.2 → tgblocks-0.2.4}/CHANGELOG.md +20 -3
  2. {tgblocks-0.2.2 → tgblocks-0.2.4}/GITHUB.md +25 -25
  3. {tgblocks-0.2.2 → tgblocks-0.2.4}/PKG-INFO +32 -29
  4. {tgblocks-0.2.2 → tgblocks-0.2.4}/README.md +31 -28
  5. {tgblocks-0.2.2 → tgblocks-0.2.4}/pyproject.toml +1 -1
  6. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/convert.py +1 -1
  7. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/dsl/parser.py +1 -1
  8. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/model.py +14 -14
  9. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/network.py +1 -1
  10. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/textlang.py +1 -1
  11. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/visual/server.py +1 -1
  12. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/visual/static/blocks.html +3 -3
  13. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/visual/static/nodes.html +13 -13
  14. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/visual/static/text.html +4 -4
  15. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/visual/static/tgblocks-project.js +1 -1
  16. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_i18n.py +1 -1
  17. {tgblocks-0.2.2 → tgblocks-0.2.4}//320/230/320/235/320/241/320/242/320/240/320/243/320/232/320/246/320/230/320/257.md +89 -89
  18. {tgblocks-0.2.2 → tgblocks-0.2.4}/.gitignore +0 -0
  19. {tgblocks-0.2.2 → tgblocks-0.2.4}/LICENSE +0 -0
  20. {tgblocks-0.2.2 → tgblocks-0.2.4}/examples/features.txt +0 -0
  21. {tgblocks-0.2.2 → tgblocks-0.2.4}/examples/full.tg +0 -0
  22. {tgblocks-0.2.2 → tgblocks-0.2.4}/examples/hello.tg +0 -0
  23. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/__init__.py +0 -0
  24. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/__main__.py +0 -0
  25. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/cli.py +0 -0
  26. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/dsl/__init__.py +0 -0
  27. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/dsl/codegen.py +0 -0
  28. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/runner.py +0 -0
  29. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/visual/__init__.py +0 -0
  30. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/visual/static/tgblocks-ui.js +0 -0
  31. {tgblocks-0.2.2 → tgblocks-0.2.4}/src/tgblocks/visual/static/vendor/blockly.js +0 -0
  32. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/botkit.py +0 -0
  33. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/corpus.py +0 -0
  34. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/actions.py +0 -0
  35. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/conditions.py +0 -0
  36. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/events.py +0 -0
  37. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/hello.py +0 -0
  38. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/long-buttons.py +0 -0
  39. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/nested.py +0 -0
  40. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/patterns.py +0 -0
  41. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/proxy.py +0 -0
  42. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/text-actions.py +0 -0
  43. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/text-basic.py +0 -0
  44. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/golden/text-buttons.py +0 -0
  45. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_blockly.py +0 -0
  46. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_bots.py +0 -0
  47. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_clear.py +0 -0
  48. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_cli.py +0 -0
  49. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_dice.py +0 -0
  50. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_dsl.py +0 -0
  51. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_examples.py +0 -0
  52. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_features.py +0 -0
  53. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_filters.py +0 -0
  54. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_golden.py +0 -0
  55. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_hidden_filters.py +0 -0
  56. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_proxy.py +0 -0
  57. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_scaffold.py +0 -0
  58. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_security.py +0 -0
  59. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_server_ports.py +0 -0
  60. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_sync.py +0 -0
  61. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_ui.py +0 -0
  62. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_validation.py +0 -0
  63. {tgblocks-0.2.2 → tgblocks-0.2.4}/tests/test_whitespace.py +0 -0
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.4
4
+
5
+ Typography. Long dashes are replaced with a plain hyphen everywhere the project writes
6
+ text: the documentation, the editor hints and the warnings. Only the punctuation changed;
7
+ no behaviour, no generated code.
8
+
9
+ ## 0.2.3
10
+
11
+ Documentation only. The package is installed from PyPI with one command, and the README
12
+ no longer suggests otherwise: the repository install is now described as "the newest
13
+ commit instead of the release".
14
+
15
+ ## 0.2.2
16
+
17
+ Metadata only: the PyPI summary and the GitHub description became the same sentence,
18
+ "Visual editor for building Telegram bots on aiogram 3". The code is unchanged.
19
+
3
20
  ## 0.2.1
4
21
 
5
22
  Metadata, tests and documentation. The generated aiogram code is unchanged.
@@ -44,7 +61,7 @@ The release that made the three editors agree with each other.
44
61
  `send_dice`.
45
62
  - **Editing and answering**: `edit_text`, `answer_callback [alert]`.
46
63
  - **Chat actions**: `pin [silent]`, `unpin`.
47
- - **Moderation**: `ban_user`, `unban_user`, `mute_user` — without an ID they act on the
64
+ - **Moderation**: `ban_user`, `unban_user`, `mute_user` - without an ID they act on the
48
65
  sender of the message.
49
66
  - **Dialogues (FSM)**: `state order`, `set_state`, `clear_state`, `on state order:`.
50
67
  The generated bot gets `StatesGroup` and a `MemoryStorage` dispatcher.
@@ -108,8 +125,8 @@ The release that made the three editors agree with each other.
108
125
 
109
126
  - **Settings in every view**: ⚙ in the header switches the theme (dark/light) and the
110
127
  interface language (English by default, Russian optional). The choice is remembered and
111
- can be shared as `?theme=light&lang=ru`; the whole catalogue — block names, field
112
- captions, hints, drop-down values, status lines — is translated.
128
+ can be shared as `?theme=light&lang=ru`; the whole catalogue - block names, field
129
+ captions, hints, drop-down values, status lines - is translated.
113
130
  - **Typing is one-line everywhere again**, and every field has a caption, so a drop-down
114
131
  says what it is.
115
132
  - **Two event filters are hidden** from the panel: "only these texts" and "matches a
@@ -1,21 +1,21 @@
1
1
  # Публикация tgblocks на GitHub и в PyPI
2
2
 
3
3
  Полная инструкция с нуля: от пустого аккаунта до `pip install tgblocks` у любого
4
- человека. Всё, что нужно сделать тебе, — один раз выполнить команды из разделов 1–4,
5
- а потом (по желанию) разделы 5–6.
4
+ человека. Всё, что нужно сделать тебе, - один раз выполнить команды из разделов 1-4,
5
+ а потом (по желанию) разделы 5-6.
6
6
 
7
7
  ---
8
8
 
9
9
  ## 0. Что понадобится
10
10
 
11
- **Аккаунт GitHub** — хранить код: <https://github.com/signup>
11
+ **Аккаунт GitHub** - хранить код: <https://github.com/signup>
12
12
 
13
- **git** — отправлять код: <https://git-scm.com/download/win>
13
+ **git** - отправлять код: <https://git-scm.com/download/win>
14
14
  (при установке оставь галочки по умолчанию)
15
15
 
16
- **Python 3.10 или новее** — собирать пакет: <https://www.python.org/downloads/>
16
+ **Python 3.10 или новее** - собирать пакет: <https://www.python.org/downloads/>
17
17
 
18
- **Аккаунт PyPI** — чтобы работал `pip install`: <https://pypi.org/account/register/>
18
+ **Аккаунт PyPI** - чтобы работал `pip install`: <https://pypi.org/account/register/>
19
19
 
20
20
  Проверка, что всё стоит:
21
21
 
@@ -33,7 +33,7 @@ git config --global user.name "Твоё Имя"
33
33
  git config --global user.email "твоя_почта@example.com"
34
34
  ```
35
35
 
36
- Почта должна совпадать с той, на которую зарегистрирован GitHub — иначе коммиты не
36
+ Почта должна совпадать с той, на которую зарегистрирован GitHub - иначе коммиты не
37
37
  будут связаны с профилем.
38
38
 
39
39
  ---
@@ -43,7 +43,7 @@ git config --global user.email "твоя_почта@example.com"
43
43
  1. Открой <https://github.com/new>.
44
44
  2. **Repository name**: `tgblocks`.
45
45
  3. **Public** (для приватного всё то же, но `pip install` с GitHub не сработает).
46
- 4. **НЕ** ставь галочки «Add a README», «Add .gitignore», «Choose a license» — они уже
46
+ 4. **НЕ** ставь галочки «Add a README», «Add .gitignore», «Choose a license» - они уже
47
47
  есть в проекте, иначе будет конфликт при первом `push`.
48
48
  5. **Create repository**.
49
49
 
@@ -69,14 +69,14 @@ git push -u origin main
69
69
  git remote set-url origin https://github.com/Pupka228228/tgblocks.git
70
70
  ```
71
71
 
72
- ### Пароль не подойдёт — нужен токен
72
+ ### Пароль не подойдёт - нужен токен
73
73
 
74
74
  GitHub больше не принимает пароль аккаунта. Один раз:
75
75
 
76
76
  1. <https://github.com/settings/tokens> → **Generate new token (classic)**.
77
77
  2. Note: `tgblocks push`, Expiration: 90 days, галочка **`repo`**.
78
78
  3. **Generate token**, скопируй строку `ghp_...` (она показывается один раз).
79
- 4. В окне `git push` на запрос пароля вставь этот токен, логин — обычный.
79
+ 4. В окне `git push` на запрос пароля вставь этот токен, логин - обычный.
80
80
 
81
81
  Сохранить токен в менеджере Windows, чтобы не вводить каждый раз:
82
82
 
@@ -84,7 +84,7 @@ GitHub больше не принимает пароль аккаунта. Од
84
84
  git config --global credential.helper manager
85
85
  ```
86
86
 
87
- Альтернатива — GitHub CLI:
87
+ Альтернатива - GitHub CLI:
88
88
 
89
89
  ```powershell
90
90
  winget install --id GitHub.cli
@@ -103,7 +103,7 @@ git push
103
103
 
104
104
  ## 4. Проверить, что всё в порядке
105
105
 
106
- 1. Открой страницу репозитория — файлы на месте, README и `docs/demo.gif` видны.
106
+ 1. Открой страницу репозитория - файлы на месте, README и `docs/demo.gif` видны.
107
107
  2. Вкладка **Actions**: workflow **CI** должен стать зелёным. Он прогоняет 261 тест на
108
108
  Windows и Linux (Python 3.10, 3.11, 3.13), проверяет JS редакторов, собирает пакет и
109
109
  ставит его в чистое окружение.
@@ -113,7 +113,7 @@ git push
113
113
  [![CI](https://github.com/Pupka228228/tgblocks/actions/workflows/ci.yml/badge.svg)](https://github.com/Pupka228228/tgblocks/actions/workflows/ci.yml)
114
114
  ```
115
115
 
116
- Если Actions красный — открой лог: чаще всего это не установленные зависимости, а не
116
+ Если Actions красный - открой лог: чаще всего это не установленные зависимости, а не
117
117
  код; локально повтори `python -m pytest -q`.
118
118
 
119
119
  ---
@@ -138,7 +138,7 @@ tgblocks
138
138
  Account settings → Two-factor authentication.
139
139
  3. Account settings → **API tokens** → **Add API token** → Name: `tgblocks`,
140
140
  Scope: **Entire account** (для первого раза) → **Add token**.
141
- 4. Скопируй `pypi-AgEIcHlwaS5vcmc...` — это пароль для загрузки.
141
+ 4. Скопируй `pypi-AgEIcHlwaS5vcmc...` - это пароль для загрузки.
142
142
 
143
143
  ### 6.2 Собрать и проверить
144
144
 
@@ -185,7 +185,7 @@ tgblocks compile mybot.tg -o bot.py
185
185
  ```
186
186
 
187
187
  - без `[runtime]` ставится только компилятор и редакторы (генерация кода работает);
188
- - `tgblocks` появляется в PATH вместе с Python; в виртуальном окружении — после
188
+ - `tgblocks` появляется в PATH вместе с Python; в виртуальном окружении - после
189
189
  активации. Если команда не находится: `python -m tgblocks` работает всегда.
190
190
 
191
191
  ---
@@ -218,36 +218,36 @@ git push --tags
218
218
  изменения → прикрепи файлы из `dist/` → **Publish release**.
219
219
 
220
220
  5. Загрузи в PyPI (`python -m twine upload dist/*`). Одно и то же имя версии дважды
221
- загрузить нельзя — всегда поднимай номер.
221
+ загрузить нельзя - всегда поднимай номер.
222
222
 
223
223
  ---
224
224
 
225
225
  ## 9. Частые проблемы
226
226
 
227
- **`Authentication failed` при push** — введён пароль вместо токена.
227
+ **`Authentication failed` при push** - введён пароль вместо токена.
228
228
  Смотри раздел 3, нужен токен с галочкой `repo`.
229
229
 
230
- **`remote origin already exists`** — remote уже привязан.
230
+ **`remote origin already exists`** - remote уже привязан.
231
231
  Выполни `git remote set-url origin <адрес>`.
232
232
 
233
- **`Updates were rejected`** — на GitHub уже есть коммиты (например, создавал README
233
+ **`Updates were rejected`** - на GitHub уже есть коммиты (например, создавал README
234
234
  через сайт). Сделай `git pull --rebase origin main`, потом `git push`.
235
235
 
236
- **`403` при `twine upload`** — токен без Scope «Entire account» или не включена 2FA.
236
+ **`403` при `twine upload`** - токен без Scope «Entire account» или не включена 2FA.
237
237
  Создай токен заново.
238
238
 
239
- **`File already exists` на PyPI** — эта версия уже загружена.
239
+ **`File already exists` на PyPI** - эта версия уже загружена.
240
240
  Подними `version` в `pyproject.toml`.
241
241
 
242
- **`tgblocks: command not found`** — папка скриптов Python не в PATH.
242
+ **`tgblocks: command not found`** - папка скриптов Python не в PATH.
243
243
  Активируй venv или запускай `python -m tgblocks`.
244
244
 
245
- **`ModuleNotFoundError: aiogram`** при запуске бота — пакет поставлен без `[runtime]`.
245
+ **`ModuleNotFoundError: aiogram`** при запуске бота - пакет поставлен без `[runtime]`.
246
246
  Нужен `pip install "tgblocks[runtime]"`.
247
247
 
248
- **README не показывает картинки** — файлы не попали в репозиторий.
248
+ **README не показывает картинки** - файлы не попали в репозиторий.
249
249
  Проверь, что `docs/editor-nodes.png`, `docs/editor-blocks.png`, `docs/editor-text.png`
250
- и `docs/demo.gif` закоммичены, а ветка в ссылках — `main`.
250
+ и `docs/demo.gif` закоммичены, а ветка в ссылках - `main`.
251
251
 
252
252
  ---
253
253
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tgblocks
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Visual editor for building Telegram bots on aiogram 3
5
5
  Project-URL: Homepage, https://github.com/Pupka228228/tgblocks
6
6
  Project-URL: Repository, https://github.com/Pupka228228/tgblocks
@@ -37,7 +37,7 @@ Description-Content-Type: text/markdown
37
37
 
38
38
  **A tiny text DSL and three visual editors for Telegram bots on aiogram 3.**
39
39
 
40
- Five lines of text — or five dragged blocks — and you get ordinary, editable aiogram
40
+ Five lines of text - or five dragged blocks - and you get ordinary, editable aiogram
41
41
  code. No account, no cloud, no lock-in: the editor is a local server on
42
42
  127.0.0.1, and the result is a normal bot.py you can read, commit and deploy.
43
43
 
@@ -55,8 +55,8 @@ tgblocks # opens the editor at http://127.0.0.1:8765/
55
55
  ```
56
56
 
57
57
  Without the extra: `pip install tgblocks` installs the compiler and the editors only,
58
- which is enough to generate and read code. If the package is not on PyPI yet, the same
59
- two commands work straight from the repository:
58
+ which is enough to generate and read code. To follow the newest commit instead of the
59
+ release:
60
60
 
61
61
  ```bash
62
62
  pip install "tgblocks[runtime] @ git+https://github.com/Pupka228228/tgblocks.git"
@@ -74,7 +74,7 @@ Publishing a release is described in **[GITHUB.md](GITHUB.md)**.
74
74
 
75
75
  ## Three views, one compiler
76
76
 
77
- ### `/nodes` — boxes and wires
77
+ ### `/nodes` - boxes and wires
78
78
 
79
79
  ![nodes](https://raw.githubusercontent.com/Pupka228228/tgblocks/main/docs/editor-nodes.png)
80
80
 
@@ -82,14 +82,14 @@ Blocks come from the palette on the left, and they do not connect by themselves:
82
82
  from a dot to the block you want, and `✕` in the middle of a wire removes it. Drag the
83
83
  background to pan, wheel to zoom, `Ctrl+Z` and `Ctrl+Y` undo and redo.
84
84
 
85
- ### `/blocks` — Blockly
85
+ ### `/blocks` - Blockly
86
86
 
87
87
  ![blocks](https://raw.githubusercontent.com/Pupka228228/tgblocks/main/docs/editor-blocks.png)
88
88
 
89
89
  The same bot with blocks generated from the same catalogue. Blockly ships inside the
90
90
  package, so this view works without internet.
91
91
 
92
- ### `/text` — the code, with help
92
+ ### `/text` - the code, with help
93
93
 
94
94
  ![text](https://raw.githubusercontent.com/Pupka228228/tgblocks/main/docs/editor-text.png)
95
95
 
@@ -98,14 +98,14 @@ compiler knows at the cursor.
98
98
 
99
99
  All three are one document. A change in any view shows up in the other two within a
100
100
  second, and clearing one clears the bot everywhere. The ⚙ panel in the header switches
101
- the theme and the interface language — English by default, Russian at one click, and the
101
+ the theme and the interface language - English by default, Russian at one click, and the
102
102
  block names, field captions and hints change with it.
103
103
 
104
104
  ## Why
105
105
 
106
106
  Paid bot constructors keep your bot inside their panel: you rent the hosting, you cannot
107
107
  read the code, and leaving means starting again. Writing aiogram 3 by hand is the
108
- opposite — full control, but the first hour is dispatcher, routers, filters, keyboards,
108
+ opposite - full control, but the first hour is dispatcher, routers, filters, keyboards,
109
109
  callbacks and an async entrypoint before anything answers.
110
110
 
111
111
  tgblocks is the middle: a language small enough to fit on a postcard, or an editor where
@@ -176,7 +176,7 @@ parameters, its labels, the aiogram method it lands on. The DSL parser, the text
176
176
  parser, the converters (text ⇄ node board ⇄ Blockly XML) and the code generator all
177
177
  read that one table, and `/api/schema` hands it to the three pages, so their palettes
178
178
  and property fields are generated too. Adding an aiogram method is a catalogue entry
179
- plus one emitter — not five copies that drift apart.
179
+ plus one emitter - not five copies that drift apart.
180
180
 
181
181
  ## What a bot can do
182
182
 
@@ -240,7 +240,7 @@ bot.tg:7:5: error: expected a quoted text
240
240
 
241
241
  Two handlers that claim the same messages are refused at parse time: aiogram calls
242
242
  only the first one, so the second would silently never run. A button that calls a
243
- command nobody handles is a warning, not an error — the bot still builds.
243
+ command nobody handles is a warning, not an error - the bot still builds.
244
244
 
245
245
  ## Telegram is blocked? Use a proxy
246
246
 
@@ -254,7 +254,7 @@ bot proxy "socks5://127.0.0.1:1080"
254
254
  fails, the generated bot prints a short explanation instead of a full aiohttp
255
255
  traceback.
256
256
 
257
- Paste only the URL into the bot's `proxy` field — not the whole record from a proxy
257
+ Paste only the URL into the bot's `proxy` field - not the whole record from a proxy
258
258
  list. To check that a proxy actually reaches Telegram before running a bot:
259
259
 
260
260
  ```bash
@@ -272,7 +272,7 @@ as a potential attacker:
272
272
  - it answers only on `127.0.0.1`, and only to a `Host` header that is one of its own
273
273
  (a hostile domain pointing at 127.0.0.1 is refused);
274
274
  - cross-site requests are refused by `Origin` and `Sec-Fetch-Site` checks, and a POST
275
- body must be `application/json` — the two ways a foreign page could otherwise drive
275
+ body must be `application/json` - the two ways a foreign page could otherwise drive
276
276
  it;
277
277
  - running a preview is a child process by design, so `--host` needs `--allow-remote`
278
278
  before that is exposed to the network.
@@ -282,10 +282,10 @@ Secrets stay out of artefacts: `compile` writes code without the token unless yo
282
282
 
283
283
  ## Python API
284
284
 
285
- - `from tgblocks import compile_source, compile_text` — DSL text or editor text to
285
+ - `from tgblocks import compile_source, compile_text` - DSL text or editor text to
286
286
  aiogram code.
287
- - `from tgblocks import parse, generate` — AST in, code out.
288
- - `from tgblocks import run` — a DSL string inside a normal `.py` file.
287
+ - `from tgblocks import parse, generate` - AST in, code out.
288
+ - `from tgblocks import run` - a DSL string inside a normal `.py` file.
289
289
  - `tgblocks.dsl.parser.DSLParseError` carries `line`, `column`, `message` and `hint`.
290
290
 
291
291
  ## Project layout
@@ -318,14 +318,14 @@ python -m pytest -q # 261 tests
318
318
  The suite runs the generated bots on a fake Telegram, so a broken `/start` fails a
319
319
  test instead of failing in production:
320
320
 
321
- - `tests/test_golden.py` — pins the generated code for a corpus of bots and imports
321
+ - `tests/test_golden.py` - pins the generated code for a corpus of bots and imports
322
322
  every sample into the real aiogram package;
323
- - `tests/test_bots.py`, `tests/test_features.py`, `tests/test_examples.py` — feed real
323
+ - `tests/test_bots.py`, `tests/test_features.py`, `tests/test_examples.py` - feed real
324
324
  updates through a real `Dispatcher` and assert the API calls a user would cause;
325
- - `tests/test_sync.py`, `tests/test_ui.py` — the editors: one document for three
325
+ - `tests/test_sync.py`, `tests/test_ui.py` - the editors: one document for three
326
326
  views, the schema, and both "compile this canvas" paths;
327
- - `tests/test_security.py` — the CSRF, rebinding and wide-bind refusals;
328
- - `tests/test_scaffold.py` — `scaffold.py` cannot drift from the tree again.
327
+ - `tests/test_security.py` - the CSRF, rebinding and wide-bind refusals;
328
+ - `tests/test_scaffold.py` - `scaffold.py` cannot drift from the tree again.
329
329
 
330
330
  Beyond pytest:
331
331
 
@@ -346,12 +346,12 @@ python tools/qa_smoke.py # endpoints plus the editor-to-editor h
346
346
 
347
347
  ## License
348
348
 
349
- MIT — see [LICENSE](LICENSE).
349
+ MIT - see [LICENSE](LICENSE).
350
350
 
351
351
  ## Русский
352
352
 
353
- `tgblocks` — маленький язык и три редактора для Telegram-ботов на aiogram 3. Написал
354
- пять строк (или собрал блоки мышкой) — получил обычный `bot.py`, который можно читать,
353
+ `tgblocks` - маленький язык и три редактора для Telegram-ботов на aiogram 3. Написал
354
+ пять строк (или собрал блоки мышкой) - получил обычный `bot.py`, который можно читать,
355
355
  править и выкладывать.
356
356
 
357
357
  ```bash
@@ -363,19 +363,22 @@ tgblocks compile examples/hello.tg -o mybot.py
363
363
  ```
364
364
 
365
365
  Всё работает на твоём компьютере: никаких аккаунтов, облака и подписок. Три вида
366
- (узлы, текст, блоки) — это один и тот же бот, поэтому правка в одном виде сразу видна
366
+ (узлы, текст, блоки) - это один и тот же бот, поэтому правка в одном виде сразу видна
367
367
  в двух других. В шапке есть кнопка настроек: тёмная или светлая тема и русский или
368
368
  английский интерфейс. Токен в сгенерированный файл не пишется, если не попросить
369
369
  `--embed-token`.
370
370
 
371
- Установка без файлов, сразу с GitHub:
371
+ Пакет уже лежит на PyPI, поэтому ставится одной строкой - файлы никто не скачивает:
372
372
 
373
373
  ```bash
374
- pip install "tgblocks[runtime] @ git+https://github.com/Pupka228228/tgblocks.git"
374
+ pip install "tgblocks[runtime]"
375
375
  ```
376
376
 
377
- А когда пакет залит на PyPI, хватает одной строки `pip install tgblocks` — файлы
378
- никто не скачивает.
377
+ Если нужен самый свежий коммит, а не релиз:
378
+
379
+ ```bash
380
+ pip install "tgblocks[runtime] @ git+https://github.com/Pupka228228/tgblocks.git"
381
+ ```
379
382
 
380
383
  Подробно по шагам, с разбором ошибок: **[ИНСТРУКЦИЯ.md](ИНСТРУКЦИЯ.md)**.
381
384
  Как выложить проект на GitHub и в PyPI: **[GITHUB.md](GITHUB.md)**.
@@ -2,7 +2,7 @@
2
2
 
3
3
  **A tiny text DSL and three visual editors for Telegram bots on aiogram 3.**
4
4
 
5
- Five lines of text — or five dragged blocks — and you get ordinary, editable aiogram
5
+ Five lines of text - or five dragged blocks - and you get ordinary, editable aiogram
6
6
  code. No account, no cloud, no lock-in: the editor is a local server on
7
7
  127.0.0.1, and the result is a normal bot.py you can read, commit and deploy.
8
8
 
@@ -20,8 +20,8 @@ tgblocks # opens the editor at http://127.0.0.1:8765/
20
20
  ```
21
21
 
22
22
  Without the extra: `pip install tgblocks` installs the compiler and the editors only,
23
- which is enough to generate and read code. If the package is not on PyPI yet, the same
24
- two commands work straight from the repository:
23
+ which is enough to generate and read code. To follow the newest commit instead of the
24
+ release:
25
25
 
26
26
  ```bash
27
27
  pip install "tgblocks[runtime] @ git+https://github.com/Pupka228228/tgblocks.git"
@@ -39,7 +39,7 @@ Publishing a release is described in **[GITHUB.md](GITHUB.md)**.
39
39
 
40
40
  ## Three views, one compiler
41
41
 
42
- ### `/nodes` — boxes and wires
42
+ ### `/nodes` - boxes and wires
43
43
 
44
44
  ![nodes](https://raw.githubusercontent.com/Pupka228228/tgblocks/main/docs/editor-nodes.png)
45
45
 
@@ -47,14 +47,14 @@ Blocks come from the palette on the left, and they do not connect by themselves:
47
47
  from a dot to the block you want, and `✕` in the middle of a wire removes it. Drag the
48
48
  background to pan, wheel to zoom, `Ctrl+Z` and `Ctrl+Y` undo and redo.
49
49
 
50
- ### `/blocks` — Blockly
50
+ ### `/blocks` - Blockly
51
51
 
52
52
  ![blocks](https://raw.githubusercontent.com/Pupka228228/tgblocks/main/docs/editor-blocks.png)
53
53
 
54
54
  The same bot with blocks generated from the same catalogue. Blockly ships inside the
55
55
  package, so this view works without internet.
56
56
 
57
- ### `/text` — the code, with help
57
+ ### `/text` - the code, with help
58
58
 
59
59
  ![text](https://raw.githubusercontent.com/Pupka228228/tgblocks/main/docs/editor-text.png)
60
60
 
@@ -63,14 +63,14 @@ compiler knows at the cursor.
63
63
 
64
64
  All three are one document. A change in any view shows up in the other two within a
65
65
  second, and clearing one clears the bot everywhere. The ⚙ panel in the header switches
66
- the theme and the interface language — English by default, Russian at one click, and the
66
+ the theme and the interface language - English by default, Russian at one click, and the
67
67
  block names, field captions and hints change with it.
68
68
 
69
69
  ## Why
70
70
 
71
71
  Paid bot constructors keep your bot inside their panel: you rent the hosting, you cannot
72
72
  read the code, and leaving means starting again. Writing aiogram 3 by hand is the
73
- opposite — full control, but the first hour is dispatcher, routers, filters, keyboards,
73
+ opposite - full control, but the first hour is dispatcher, routers, filters, keyboards,
74
74
  callbacks and an async entrypoint before anything answers.
75
75
 
76
76
  tgblocks is the middle: a language small enough to fit on a postcard, or an editor where
@@ -141,7 +141,7 @@ parameters, its labels, the aiogram method it lands on. The DSL parser, the text
141
141
  parser, the converters (text ⇄ node board ⇄ Blockly XML) and the code generator all
142
142
  read that one table, and `/api/schema` hands it to the three pages, so their palettes
143
143
  and property fields are generated too. Adding an aiogram method is a catalogue entry
144
- plus one emitter — not five copies that drift apart.
144
+ plus one emitter - not five copies that drift apart.
145
145
 
146
146
  ## What a bot can do
147
147
 
@@ -205,7 +205,7 @@ bot.tg:7:5: error: expected a quoted text
205
205
 
206
206
  Two handlers that claim the same messages are refused at parse time: aiogram calls
207
207
  only the first one, so the second would silently never run. A button that calls a
208
- command nobody handles is a warning, not an error — the bot still builds.
208
+ command nobody handles is a warning, not an error - the bot still builds.
209
209
 
210
210
  ## Telegram is blocked? Use a proxy
211
211
 
@@ -219,7 +219,7 @@ bot proxy "socks5://127.0.0.1:1080"
219
219
  fails, the generated bot prints a short explanation instead of a full aiohttp
220
220
  traceback.
221
221
 
222
- Paste only the URL into the bot's `proxy` field — not the whole record from a proxy
222
+ Paste only the URL into the bot's `proxy` field - not the whole record from a proxy
223
223
  list. To check that a proxy actually reaches Telegram before running a bot:
224
224
 
225
225
  ```bash
@@ -237,7 +237,7 @@ as a potential attacker:
237
237
  - it answers only on `127.0.0.1`, and only to a `Host` header that is one of its own
238
238
  (a hostile domain pointing at 127.0.0.1 is refused);
239
239
  - cross-site requests are refused by `Origin` and `Sec-Fetch-Site` checks, and a POST
240
- body must be `application/json` — the two ways a foreign page could otherwise drive
240
+ body must be `application/json` - the two ways a foreign page could otherwise drive
241
241
  it;
242
242
  - running a preview is a child process by design, so `--host` needs `--allow-remote`
243
243
  before that is exposed to the network.
@@ -247,10 +247,10 @@ Secrets stay out of artefacts: `compile` writes code without the token unless yo
247
247
 
248
248
  ## Python API
249
249
 
250
- - `from tgblocks import compile_source, compile_text` — DSL text or editor text to
250
+ - `from tgblocks import compile_source, compile_text` - DSL text or editor text to
251
251
  aiogram code.
252
- - `from tgblocks import parse, generate` — AST in, code out.
253
- - `from tgblocks import run` — a DSL string inside a normal `.py` file.
252
+ - `from tgblocks import parse, generate` - AST in, code out.
253
+ - `from tgblocks import run` - a DSL string inside a normal `.py` file.
254
254
  - `tgblocks.dsl.parser.DSLParseError` carries `line`, `column`, `message` and `hint`.
255
255
 
256
256
  ## Project layout
@@ -283,14 +283,14 @@ python -m pytest -q # 261 tests
283
283
  The suite runs the generated bots on a fake Telegram, so a broken `/start` fails a
284
284
  test instead of failing in production:
285
285
 
286
- - `tests/test_golden.py` — pins the generated code for a corpus of bots and imports
286
+ - `tests/test_golden.py` - pins the generated code for a corpus of bots and imports
287
287
  every sample into the real aiogram package;
288
- - `tests/test_bots.py`, `tests/test_features.py`, `tests/test_examples.py` — feed real
288
+ - `tests/test_bots.py`, `tests/test_features.py`, `tests/test_examples.py` - feed real
289
289
  updates through a real `Dispatcher` and assert the API calls a user would cause;
290
- - `tests/test_sync.py`, `tests/test_ui.py` — the editors: one document for three
290
+ - `tests/test_sync.py`, `tests/test_ui.py` - the editors: one document for three
291
291
  views, the schema, and both "compile this canvas" paths;
292
- - `tests/test_security.py` — the CSRF, rebinding and wide-bind refusals;
293
- - `tests/test_scaffold.py` — `scaffold.py` cannot drift from the tree again.
292
+ - `tests/test_security.py` - the CSRF, rebinding and wide-bind refusals;
293
+ - `tests/test_scaffold.py` - `scaffold.py` cannot drift from the tree again.
294
294
 
295
295
  Beyond pytest:
296
296
 
@@ -311,12 +311,12 @@ python tools/qa_smoke.py # endpoints plus the editor-to-editor h
311
311
 
312
312
  ## License
313
313
 
314
- MIT — see [LICENSE](LICENSE).
314
+ MIT - see [LICENSE](LICENSE).
315
315
 
316
316
  ## Русский
317
317
 
318
- `tgblocks` — маленький язык и три редактора для Telegram-ботов на aiogram 3. Написал
319
- пять строк (или собрал блоки мышкой) — получил обычный `bot.py`, который можно читать,
318
+ `tgblocks` - маленький язык и три редактора для Telegram-ботов на aiogram 3. Написал
319
+ пять строк (или собрал блоки мышкой) - получил обычный `bot.py`, который можно читать,
320
320
  править и выкладывать.
321
321
 
322
322
  ```bash
@@ -328,19 +328,22 @@ tgblocks compile examples/hello.tg -o mybot.py
328
328
  ```
329
329
 
330
330
  Всё работает на твоём компьютере: никаких аккаунтов, облака и подписок. Три вида
331
- (узлы, текст, блоки) — это один и тот же бот, поэтому правка в одном виде сразу видна
331
+ (узлы, текст, блоки) - это один и тот же бот, поэтому правка в одном виде сразу видна
332
332
  в двух других. В шапке есть кнопка настроек: тёмная или светлая тема и русский или
333
333
  английский интерфейс. Токен в сгенерированный файл не пишется, если не попросить
334
334
  `--embed-token`.
335
335
 
336
- Установка без файлов, сразу с GitHub:
336
+ Пакет уже лежит на PyPI, поэтому ставится одной строкой - файлы никто не скачивает:
337
337
 
338
338
  ```bash
339
- pip install "tgblocks[runtime] @ git+https://github.com/Pupka228228/tgblocks.git"
339
+ pip install "tgblocks[runtime]"
340
340
  ```
341
341
 
342
- А когда пакет залит на PyPI, хватает одной строки `pip install tgblocks` — файлы
343
- никто не скачивает.
342
+ Если нужен самый свежий коммит, а не релиз:
343
+
344
+ ```bash
345
+ pip install "tgblocks[runtime] @ git+https://github.com/Pupka228228/tgblocks.git"
346
+ ```
344
347
 
345
348
  Подробно по шагам, с разбором ошибок: **[ИНСТРУКЦИЯ.md](ИНСТРУКЦИЯ.md)**.
346
349
  Как выложить проект на GitHub и в PyPI: **[GITHUB.md](GITHUB.md)**.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tgblocks"
7
- version = "0.2.2"
7
+ version = "0.2.4"
8
8
  description = "Visual editor for building Telegram bots on aiogram 3"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -589,7 +589,7 @@ def _actions_of(children: List[dict], nodes: Dict[str, dict],
589
589
 
590
590
  if node_type == "otherwise":
591
591
  if warnings is not None:
592
- warnings.append("«Иначе» без «Условия» перед ним — блок пропущен")
592
+ warnings.append("«Иначе» без «Условия» перед ним - блок пропущен")
593
593
  index += 1
594
594
  continue
595
595
 
@@ -770,7 +770,7 @@ class _Parser:
770
770
  self._fail(
771
771
  "для интерактивного эмодзи нужно число",
772
772
  token,
773
- 'кубик даёт 1–6, дартс — 1–6, слоты — 1–64: `when dice == 6:`',
773
+ 'кубик даёт 1-6, дартс - 1-6, слоты - 1-64: `when dice == 6:`',
774
774
  )
775
775
  return Condition(op=op, value=raw, line=token.line, source="dice")
776
776
  # Several values mean "any of them": when text contains "a", "b":