fix: support Python 3.14 compatibility#6419
Conversation
|
| Filename | Overview |
|---|---|
| press/press/doctype/deploy_candidate/docker_output_parsers.py | Replaces dockerfile library with a custom _get_run_command using shlex.split/shlex.join; the re-encoding via shlex.join breaks downstream stage-marker stripping and line-fold normalization, causing multiple new tests to fail. |
| press/telegram_utils.py | Migrates from python-telegram-bot v13 (synchronous) to v22 (async) using asyncio.run(); the bot-username lookup is now a live API call on every respond() invocation rather than a cached value. |
| press/press/doctype/deploy_candidate/test_docker_output_parsers.py | New unit-test file for get_command; four test cases are added, but three of them are expected to fail due to the shlex.join re-encoding bug in the implementation. |
| press/api/account.py | Adds frappe_io_login whitelisted endpoint to serve the OAuth redirect dynamically, replacing the module-level call to get_frappe_io_auth_url() at import time. |
| press/hooks.py | Removes the import-time call to get_frappe_io_auth_url() in website_redirects, pointing instead to the new frappe_io_login API method — fixes the Python 3.14 module-level import issue. |
| pyproject.toml | Major dependency bumps for Python 3.14 compatibility: ansible 3→13, python-telegram-bot 13→22, stripe 2→15, playwright 1.49→1.59; removes dockerfile package and adds greenlet. |
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
press/press/doctype/deploy_candidate/docker_output_parsers.py:228-246
**`shlex.join` re-encodes the command, breaking downstream splitting**
`_get_run_command` calls `shlex.split` (which strips quotes and consumes backslash-newline continuations) and then `shlex.join` (which re-quotes tokens with single quotes). This means: (1) `` `#stage-xxx` `` markers get re-quoted as `'`#stage-xxx`'`, so `get_command`'s `split("`#stage-")` no longer matches them correctly; (2) backslash-newline line folds are consumed by shlex, so `get_command`'s ` \\\n` split no longer works; (3) `"hello world"` (double-quoted) becomes `'hello world'` (single-quoted) in the output.
Tests 1, 2, and 4 (`test_get_command_strips_run_flags_and_stage_marker`, `test_get_command_normalizes_line_folds`, `test_get_command_preserves_quoted_arguments`) will fail for these reasons. The fix is to avoid re-encoding: locate the index in the original `value` string where non-flag content begins, and slice `value` directly rather than reconstructing via `shlex.join`.
### Issue 2 of 2
press/telegram_utils.py:74-80
**`_get_bot_username()` makes a live API call on every `respond()` invocation**
`respond()` now calls `_get_bot_username()` for every incoming Telegram message, which creates a fresh `Bot` instance, calls `asyncio.run()`, and performs a full HTTP round-trip to Telegram just to obtain the bot's username — a value that never changes at runtime. In the old v13 API this was effectively free. A simple fix is to cache the username as an instance attribute on first use (e.g., `self._username`) so only the first message incurs the network call.
Reviews (1): Last reviewed commit: "Merge branch 'develop' into develop" | Re-trigger Greptile
| def _get_run_command(line: str) -> str: | ||
| instruction, _, value = line.partition(" ") | ||
| if instruction.upper() != "RUN": | ||
| return value | ||
|
|
||
| value = value.strip() | ||
| if value.startswith("["): | ||
| return value | ||
|
|
||
| try: | ||
| parts = shlex.split(value, posix=True) | ||
| except ValueError: | ||
| return value | ||
|
|
||
| for i, part in enumerate(parts): | ||
| if not part.startswith("--"): | ||
| return shlex.join(parts[i:]) | ||
|
|
||
| return "" |
There was a problem hiding this comment.
shlex.join re-encodes the command, breaking downstream splitting
_get_run_command calls shlex.split (which strips quotes and consumes backslash-newline continuations) and then shlex.join (which re-quotes tokens with single quotes). This means: (1) `#stage-xxx` markers get re-quoted as '#stage-xxx', so get_command's split("#stage-")no longer matches them correctly; (2) backslash-newline line folds are consumed by shlex, soget_command's \\nsplit no longer works; (3)"hello world"(double-quoted) becomes'hello world'` (single-quoted) in the output.
Tests 1, 2, and 4 (test_get_command_strips_run_flags_and_stage_marker, test_get_command_normalizes_line_folds, test_get_command_preserves_quoted_arguments) will fail for these reasons. The fix is to avoid re-encoding: locate the index in the original value string where non-flag content begins, and slice value directly rather than reconstructing via shlex.join.
Prompt To Fix With AI
This is a comment left during a code review.
Path: press/press/doctype/deploy_candidate/docker_output_parsers.py
Line: 228-246
Comment:
**`shlex.join` re-encodes the command, breaking downstream splitting**
`_get_run_command` calls `shlex.split` (which strips quotes and consumes backslash-newline continuations) and then `shlex.join` (which re-quotes tokens with single quotes). This means: (1) `` `#stage-xxx` `` markers get re-quoted as `'`#stage-xxx`'`, so `get_command`'s `split("`#stage-")` no longer matches them correctly; (2) backslash-newline line folds are consumed by shlex, so `get_command`'s ` \\\n` split no longer works; (3) `"hello world"` (double-quoted) becomes `'hello world'` (single-quoted) in the output.
Tests 1, 2, and 4 (`test_get_command_strips_run_flags_and_stage_marker`, `test_get_command_normalizes_line_folds`, `test_get_command_preserves_quoted_arguments`) will fail for these reasons. The fix is to avoid re-encoding: locate the index in the original `value` string where non-flag content begins, and slice `value` directly rather than reconstructing via `shlex.join`.
How can I resolve this? If you propose a fix, please make it concise.| def _get_bot_username(self): | ||
| return asyncio.run(self._get_bot_username_async()) | ||
|
|
||
| async def _get_bot_username_async(self): | ||
| bot = self.bot | ||
| async with bot: | ||
| return bot.username |
There was a problem hiding this comment.
_get_bot_username() makes a live API call on every respond() invocation
respond() now calls _get_bot_username() for every incoming Telegram message, which creates a fresh Bot instance, calls asyncio.run(), and performs a full HTTP round-trip to Telegram just to obtain the bot's username — a value that never changes at runtime. In the old v13 API this was effectively free. A simple fix is to cache the username as an instance attribute on first use (e.g., self._username) so only the first message incurs the network call.
Prompt To Fix With AI
This is a comment left during a code review.
Path: press/telegram_utils.py
Line: 74-80
Comment:
**`_get_bot_username()` makes a live API call on every `respond()` invocation**
`respond()` now calls `_get_bot_username()` for every incoming Telegram message, which creates a fresh `Bot` instance, calls `asyncio.run()`, and performs a full HTTP round-trip to Telegram just to obtain the bot's username — a value that never changes at runtime. In the old v13 API this was effectively free. A simple fix is to cache the username as an instance attribute on first use (e.g., `self._username`) so only the first message incurs the network call.
How can I resolve this? If you propose a fix, please make it concise.
No description provided.