Skip to content

Commit 1fc0b97

Browse files
committed
feat: Add Python 3.13 support to CI/CD pipeline
- Update CI workflow to test Python 3.13 across all platforms - Add Python 3.13 classifier to pyproject.toml - Update README documentation to reflect Python 3.8-3.13 support - Verify all tests pass with Python 3.13.3 - Maintain backward compatibility with existing Python versions
1 parent 61523ab commit 1fc0b97

4 files changed

Lines changed: 158 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
strategy:
1313
matrix:
1414
os: [ubuntu-latest, windows-latest, macos-latest]
15-
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
15+
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
1616

1717
steps:
1818
- uses: actions/checkout@v4

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ A minimal Rust-based Python extension using PyO3 bindings with automated CI/CD p
1313
- **Automated CI/CD**: GitHub Actions workflows for testing, building, and publishing
1414
- **Version Management**: Automated version bumping across all project files
1515
- **Cross-Platform**: Supports Windows, macOS, and Linux
16-
- **Multiple Python Versions**: Compatible with Python 3.8-3.12
16+
- **Multiple Python Versions**: Compatible with Python 3.8-3.13
1717

1818
## Installation
1919

@@ -65,7 +65,7 @@ print(demopy.__version__) # Current version
6565

6666
### Prerequisites
6767

68-
- Python 3.8 or higher
68+
- Python 3.8 or higher (tested up to 3.13)
6969
- Rust 1.70 or higher
7070
- Git
7171

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ classifiers = [
2020
"Programming Language :: Python :: 3.10",
2121
"Programming Language :: Python :: 3.11",
2222
"Programming Language :: Python :: 3.12",
23+
"Programming Language :: Python :: 3.13",
2324
"Programming Language :: Rust",
2425
]
2526
keywords = ["rust", "python", "pyo3", "extension"]

test_installation.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#!/usr/bin/env python3
2+
"""
3+
End-to-end test script for demopy_gb_jj package installation and functionality.
4+
5+
This script tests:
6+
1. Package installation from PyPI
7+
2. Rust extension functionality (if available)
8+
3. Python fallback functionality
9+
4. Version consistency
10+
5. All exported functions
11+
"""
12+
13+
import subprocess
14+
import sys
15+
import tempfile
16+
import os
17+
from pathlib import Path
18+
19+
20+
def run_command(cmd, description):
21+
"""Run a command and return success status."""
22+
print(f"🔄 {description}...")
23+
try:
24+
result = subprocess.run(cmd, shell=True, check=True, capture_output=True, text=True)
25+
print(f"✅ {description} - SUCCESS")
26+
if result.stdout.strip():
27+
print(f" Output: {result.stdout.strip()}")
28+
return True
29+
except subprocess.CalledProcessError as e:
30+
print(f"❌ {description} - FAILED")
31+
print(f" Error: {e.stderr.strip() if e.stderr else str(e)}")
32+
return False
33+
34+
35+
def test_package_functionality():
36+
"""Test the package functionality."""
37+
test_code = '''
38+
import demopy
39+
40+
print("=== PACKAGE FUNCTIONALITY TEST ===")
41+
42+
# Test version
43+
print(f"Version: {demopy.__version__}")
44+
45+
# Test all functions
46+
print(f"hello(): {demopy.hello()}")
47+
print(f"add(2, 3): {demopy.add(2, 3)}")
48+
print(f"multiply(2.5, 4.0): {demopy.multiply(2.5, 4.0)}")
49+
print(f"sum_list([1,2,3,4,5]): {demopy.sum_list([1,2,3,4,5])}")
50+
print(f"reverse_string('Hello World'): {demopy.reverse_string('Hello World')}")
51+
52+
# Test __all__ exports
53+
print(f"Exported functions: {demopy.__all__}")
54+
55+
# Detect if using Rust extension or Python fallback
56+
hello_msg = demopy.hello()
57+
if "Rust edition" in hello_msg:
58+
print("✅ Using Rust extension")
59+
elif "Python fallback" in hello_msg:
60+
print("✅ Using Python fallback")
61+
else:
62+
print("⚠️ Unknown backend")
63+
64+
print("=== ALL TESTS PASSED ===")
65+
'''
66+
67+
return run_command(f'python -c "{test_code}"', "Test package functionality")
68+
69+
70+
def test_fallback_mechanism():
71+
"""Test that fallback works when Rust extension is unavailable."""
72+
fallback_test = '''
73+
import sys
74+
import builtins
75+
76+
# Mock import error for Rust extension
77+
original_import = builtins.__import__
78+
def mock_import(name, *args, **kwargs):
79+
if "demopy_gb_jj._rust" in name:
80+
raise ImportError("Mocked import error for testing")
81+
return original_import(name, *args, **kwargs)
82+
83+
builtins.__import__ = mock_import
84+
85+
# Now import demopy - should use fallback
86+
import demopy
87+
88+
print("=== FALLBACK MECHANISM TEST ===")
89+
hello_msg = demopy.hello()
90+
print(f"hello(): {hello_msg}")
91+
92+
if "Python fallback" in hello_msg:
93+
print("✅ Fallback mechanism working correctly")
94+
95+
# Test all fallback functions
96+
print(f"add(5, 7): {demopy.add(5, 7)}")
97+
print(f"multiply(3.0, 2.5): {demopy.multiply(3.0, 2.5)}")
98+
print(f"sum_list([10,20,30]): {demopy.sum_list([10,20,30])}")
99+
print(f"reverse_string('Fallback'): {demopy.reverse_string('Fallback')}")
100+
print("✅ All fallback functions working")
101+
else:
102+
print("❌ Fallback mechanism not working")
103+
sys.exit(1)
104+
105+
print("=== FALLBACK TEST PASSED ===")
106+
'''
107+
108+
return run_command(f'python -c "{fallback_test}"', "Test fallback mechanism")
109+
110+
111+
def main():
112+
"""Main test function."""
113+
print("🚀 Starting End-to-End Package Testing")
114+
print("=" * 50)
115+
116+
# Test 1: Install package from PyPI
117+
success = run_command(
118+
"pip install --upgrade demopy_gb_jj",
119+
"Install package from PyPI"
120+
)
121+
if not success:
122+
print("❌ Package installation failed. Check if it's published to PyPI.")
123+
return False
124+
125+
# Test 2: Test package functionality
126+
if not test_package_functionality():
127+
return False
128+
129+
# Test 3: Test fallback mechanism
130+
if not test_fallback_mechanism():
131+
return False
132+
133+
# Test 4: Verify version consistency
134+
success = run_command(
135+
'python -c "import demopy; print(f\'Package version: {demopy.__version__}\')"',
136+
"Verify version consistency"
137+
)
138+
if not success:
139+
return False
140+
141+
print("\n" + "=" * 50)
142+
print("🎉 ALL END-TO-END TESTS PASSED!")
143+
print("✅ Package installation successful")
144+
print("✅ Rust extension or fallback working")
145+
print("✅ All functions operational")
146+
print("✅ Version consistency verified")
147+
print("=" * 50)
148+
149+
return True
150+
151+
152+
if __name__ == "__main__":
153+
success = main()
154+
sys.exit(0 if success else 1)

0 commit comments

Comments
 (0)