Files
simple-nanoshare/my_modules/textview/linkify.py
T
daniel156161 73fdeacbfe
Build and Push Docker Container / build-and-push (push) Successful in 2m25s
feat!: adopt Python 3.14 and 3.15 language features
- Require Python 3.15 for the server and Python 3.14 for the CLI.
- Match the server requirement to quart_common's Python 3.15 features.
- Replace future annotations with native deferred evaluation.
- Defer CLI command dependencies and QR imports on Python 3.15.
- Enable argparse suggestions for mistyped CLI commands.
- Remove the obsolete tomllib import fallback.
- Update my_helpers and quart_common submodule references.
- Lock test dependencies and exclude them from Docker installations.
- Add regression coverage for lazy imports and deferred annotations.
- Document runtime requirements and standalone CLI validation.
- Validate 276 tests on Python 3.15 and 18 CLI tests on Python 3.14.

BREAKING CHANGE: The server now requires Python 3.15+ and the standalone CLI requires Python 3.14+.
2026-10-26 14:47:29 +01:00

44 lines
1.2 KiB
Python

import re
# Only http(s) is linkified; everything else stays inert plain text.
_URL_PATTERN = re.compile(r'https?://[^\s<>"\'`]+', re.IGNORECASE)
# Prose punctuation that is almost never part of the URL itself.
_TRAILING_PUNCTUATION = '.,;:!?\'"'
_BRACKET_PAIRS = {')': '(', ']': '[', '}': '{'}
def _trim_trailing(url: str) -> str:
"""Give punctuation that belongs to the surrounding sentence back to the text."""
while url:
last = url[-1]
if last in _TRAILING_PUNCTUATION:
url = url[:-1]
continue
opening = _BRACKET_PAIRS.get(last)
if opening is not None and url.count(opening) < url.count(last):
url = url[:-1]
continue
break
return url
def tokenize(text: str) -> list[tuple[str, str]]:
"""Split text into ('text', value) and ('url', value) tokens, order preserved."""
tokens: list[tuple[str, str]] = []
cursor = 0
for match in _URL_PATTERN.finditer(text):
url = _trim_trailing(match.group(0))
if not url:
continue
start = match.start()
end = start + len(url)
if start > cursor:
tokens.append(('text', text[cursor:start]))
tokens.append(('url', url))
cursor = end
if cursor < len(text):
tokens.append(('text', text[cursor:]))
return tokens