feat!: adopt Python 3.14 and 3.15 language features
Build and Push Docker Container / build-and-push (push) Successful in 2m25s
Build and Push Docker Container / build-and-push (push) Successful in 2m25s
- 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+.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"""Exercise version-specific behavior in clean interpreters, not import stubs."""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
def run_python(code):
|
||||
env = os.environ.copy()
|
||||
env['PYTHONPATH'] = os.pathsep.join([str(ROOT / 'cli'), str(ROOT)])
|
||||
# Test the module opt-ins, independently of global import/color settings.
|
||||
env.pop('PYTHON_LAZY_IMPORTS', None)
|
||||
env['NO_COLOR'] = '1'
|
||||
return subprocess.run(
|
||||
[sys.executable, '-c', code], cwd=ROOT, env=env,
|
||||
capture_output=True, text=True, check=True,
|
||||
)
|
||||
|
||||
def test_cli_typo_suggests_command():
|
||||
result = run_python("""
|
||||
from nanoshare_client.cli import main
|
||||
try:
|
||||
main(['uplod'])
|
||||
except SystemExit as exc:
|
||||
assert exc.code == 2
|
||||
""")
|
||||
assert "maybe you meant 'upload'" in result.stderr
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 15), reason='PEP 810 requires Python 3.15')
|
||||
def test_help_and_completion_do_not_load_network_or_watch_modules():
|
||||
run_python("""
|
||||
import sys
|
||||
from nanoshare_client.cli import main
|
||||
try:
|
||||
main(['--help'])
|
||||
except SystemExit as exc:
|
||||
assert exc.code == 0
|
||||
assert main(['completion', 'bash']) == 0
|
||||
for name in ('httpx', 'nanoshare_client.auth', 'nanoshare_client.sync', 'nanoshare_client.watch'):
|
||||
assert name not in sys.modules, name
|
||||
""")
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 15), reason='PEP 810 requires Python 3.15')
|
||||
def test_qr_import_is_lazy_but_rendering_still_works():
|
||||
run_python("""
|
||||
import sys
|
||||
from link_composer.qr import make_qr_png
|
||||
assert 'qrcode' not in sys.modules
|
||||
assert make_qr_png('https://example.com').startswith(b'\\x89PNG')
|
||||
assert 'qrcode' in sys.modules
|
||||
""")
|
||||
|
||||
def test_deferred_annotations_resolve_to_types():
|
||||
run_python("""
|
||||
from typing import get_type_hints
|
||||
from my_modules.upload_content import MultipartUploadParts, parse_multipart_upload_body
|
||||
assert not isinstance(parse_multipart_upload_body.__annotations__['return'], str)
|
||||
assert get_type_hints(parse_multipart_upload_body)['return'] is MultipartUploadParts
|
||||
""")
|
||||
Reference in New Issue
Block a user