pyASDReader 1.2.2__tar.gz → 1.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 (71) hide show
  1. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/.codecov.yml +0 -6
  2. pyasdreader-1.2.4/.pre-commit-hooks/check_changelog_format.py +148 -0
  3. pyasdreader-1.2.4/.pre-commit-hooks/check_commit_message.py +127 -0
  4. pyasdreader-1.2.4/.pre-commit-hooks/check_version_consistency.py +120 -0
  5. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/CHANGELOG.md +47 -1
  6. pyasdreader-1.2.4/CONTRIBUTING.md +332 -0
  7. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/PKG-INFO +117 -213
  8. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/README.md +84 -183
  9. pyasdreader-1.2.4/docs/.readthedocs.yaml +28 -0
  10. pyasdreader-1.2.4/docs/conf.py +33 -0
  11. pyasdreader-1.2.4/docs/developers/architecture/class_design/Core_Class_Design.vpp +0 -0
  12. pyasdreader-1.2.4/docs/developers/architecture/class_diagram/Core_Class_Design.pdf +0 -0
  13. pyasdreader-1.2.4/docs/developers/architecture/class_diagram/Core_Class_Design.svg +1 -0
  14. pyasdreader-1.2.4/docs/developers/readme.md +155 -0
  15. pyasdreader-1.2.4/docs/index.md +184 -0
  16. pyasdreader-1.2.4/docs/maintainers/CI_CD_WORKFLOWS.md +430 -0
  17. pyasdreader-1.2.4/docs/maintainers/FALLBACK_API_TOKEN_SETUP.md +290 -0
  18. pyasdreader-1.2.4/docs/maintainers/GITHUB_ENVIRONMENT_SETUP.md +216 -0
  19. pyasdreader-1.2.4/docs/maintainers/IMPROVEMENTS_2025-10-07.md +248 -0
  20. pyasdreader-1.2.4/docs/maintainers/RELEASE_EXAMPLES.md +532 -0
  21. pyasdreader-1.2.4/docs/maintainers/TROUBLESHOOTING_TRUSTED_PUBLISHING.md +497 -0
  22. pyasdreader-1.2.4/docs/maintainers/TRUSTED_PUBLISHING_IMPLEMENTATION_SUMMARY.md +426 -0
  23. pyasdreader-1.2.4/docs/maintainers/TRUSTED_PUBLISHING_SETUP.md +551 -0
  24. pyasdreader-1.2.4/docs/maintainers/VERSION_MANAGEMENT.md +709 -0
  25. pyasdreader-1.2.4/docs/maintainers/VERSION_ROLLBACK.md +294 -0
  26. pyasdreader-1.2.4/docs/maintainers/readme.md +34 -0
  27. {pyasdreader-1.2.2 → pyasdreader-1.2.4/docs/users}/examples/README.md +5 -5
  28. {pyasdreader-1.2.2 → pyasdreader-1.2.4/docs/users}/examples/basic_usage.py +9 -6
  29. pyasdreader-1.2.4/docs/users/readme.md +144 -0
  30. pyasdreader-1.2.4/pyASDReader.egg-info/SOURCES.txt +64 -0
  31. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/pyproject.toml +150 -144
  32. pyasdreader-1.2.4/scripts/diagnose_trusted_publishing.sh +212 -0
  33. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/scripts/publish.sh +74 -7
  34. pyasdreader-1.2.4/scripts/release.sh +615 -0
  35. pyasdreader-1.2.4/scripts/test_environment_setup.sh +166 -0
  36. pyasdreader-1.2.4/scripts/test_release.sh +303 -0
  37. pyasdreader-1.2.4/scripts/utils/__init__.py +1 -0
  38. pyasdreader-1.2.4/scripts/utils/changelog_manager.py +276 -0
  39. pyasdreader-1.2.4/scripts/validate_release.py +584 -0
  40. pyasdreader-1.2.4/src/_version.py +15 -0
  41. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/src/asd_file_reader.py +1 -1
  42. pyasdreader-1.2.2/.pre-commit-config.yaml +0 -43
  43. pyasdreader-1.2.2/VERSION_MANAGEMENT.md +0 -303
  44. pyasdreader-1.2.2/pyASDReader.egg-info/SOURCES.txt +0 -36
  45. pyasdreader-1.2.2/src/_version.py +0 -12
  46. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/LICENSE +0 -0
  47. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/MANIFEST.in +0 -0
  48. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/coverage.json +0 -0
  49. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/setup.cfg +0 -0
  50. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/src/__init__.py +0 -0
  51. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/src/constant.py +0 -0
  52. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/src/file_attributes.py +0 -0
  53. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/src/logger_setup.py +0 -0
  54. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/__init__.py +0 -0
  55. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v6sample/v6sample00000.asd +0 -0
  56. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v6sample/v6sample00001.asd +0 -0
  57. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v6sample/v6sample00002.asd +0 -0
  58. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample/v7sample00000.asd +0 -0
  59. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample/v7sample00001.asd +0 -0
  60. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample/v7sample00002.asd +0 -0
  61. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample/v7sample00003.asd +0 -0
  62. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample/v7sample00004.asd +0 -0
  63. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample/v7sample00005.asd +0 -0
  64. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample_field_spectroscopy/44231B009-1-FW300000.asd +0 -0
  65. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample_field_spectroscopy/44231B009-1-FW3R00000.asd +0 -0
  66. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v7sample_field_spectroscopy/44231B174-1-FF300000.asd +0 -0
  67. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v8sample/v8sample00001.asd +0 -0
  68. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/sample_data/v8sample/v8sample00002.asd +0 -0
  69. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/test_asd_file_reader.py +0 -0
  70. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/test_data.py +0 -0
  71. {pyasdreader-1.2.2 → pyasdreader-1.2.4}/tests/test_file_attributes.py +0 -0
@@ -28,8 +28,6 @@ comment:
28
28
  require_head: true
29
29
 
30
30
  flags:
31
- ubuntu-latest-py3.8:
32
- carryforward: false
33
31
  ubuntu-latest-py3.9:
34
32
  carryforward: false
35
33
  ubuntu-latest-py3.10:
@@ -38,8 +36,6 @@ flags:
38
36
  carryforward: false
39
37
  ubuntu-latest-py3.12:
40
38
  carryforward: false
41
- windows-latest-py3.8:
42
- carryforward: false
43
39
  windows-latest-py3.9:
44
40
  carryforward: false
45
41
  windows-latest-py3.10:
@@ -48,8 +44,6 @@ flags:
48
44
  carryforward: false
49
45
  windows-latest-py3.12:
50
46
  carryforward: false
51
- macos-latest-py3.8:
52
- carryforward: false
53
47
  macos-latest-py3.9:
54
48
  carryforward: false
55
49
  macos-latest-py3.10:
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Pre-commit hook to validate CHANGELOG.md format.
4
+
5
+ Validates that CHANGELOG.md follows the Keep a Changelog format:
6
+ - Has [Unreleased] section
7
+ - Version entries follow format: ## [X.Y.Z] - YYYY-MM-DD
8
+ - Versions are in descending order
9
+ - Uses standard sections (Added, Changed, Fixed, etc.)
10
+ """
11
+
12
+ import re
13
+ import sys
14
+ from datetime import datetime
15
+ from pathlib import Path
16
+
17
+
18
+ def check_unreleased_section(content):
19
+ """Check if [Unreleased] section exists."""
20
+ if not re.search(r'##\s+\[Unreleased\]', content):
21
+ return False, "[Unreleased] section is missing"
22
+ return True, None
23
+
24
+
25
+ def extract_versions(content):
26
+ """Extract all version entries from CHANGELOG."""
27
+ # Match pattern: ## [X.Y.Z] - YYYY-MM-DD
28
+ pattern = r'##\s+\[(\d+\.\d+\.\d+)\]\s+-\s+(\d{4}-\d{2}-\d{2})'
29
+ matches = re.findall(pattern, content)
30
+ return matches
31
+
32
+
33
+ def validate_version_format(version):
34
+ """Validate semantic version format."""
35
+ pattern = r'^\d+\.\d+\.\d+$'
36
+ return re.match(pattern, version) is not None
37
+
38
+
39
+ def validate_date_format(date_str):
40
+ """Validate date format (YYYY-MM-DD)."""
41
+ try:
42
+ datetime.strptime(date_str, '%Y-%m-%d')
43
+ return True
44
+ except ValueError:
45
+ return False
46
+
47
+
48
+ def check_version_order(versions):
49
+ """Check if versions are in descending order."""
50
+ version_numbers = [tuple(map(int, v[0].split('.'))) for v in versions]
51
+
52
+ for i in range(len(version_numbers) - 1):
53
+ if version_numbers[i] < version_numbers[i + 1]:
54
+ return False, f"Version {versions[i][0]} should come before {versions[i+1][0]}"
55
+
56
+ return True, None
57
+
58
+
59
+ def check_standard_sections(content):
60
+ """Check if content uses standard Keep a Changelog sections."""
61
+ standard_sections = [
62
+ 'Added', 'Changed', 'Deprecated', 'Removed',
63
+ 'Fixed', 'Security', 'Technical Improvements'
64
+ ]
65
+
66
+ # Find all section headers (### Section)
67
+ section_pattern = r'###\s+([A-Za-z\s]+)'
68
+ found_sections = re.findall(section_pattern, content)
69
+
70
+ # Check if non-standard sections are used
71
+ warnings = []
72
+ for section in found_sections:
73
+ section = section.strip()
74
+ if section not in standard_sections and section != '':
75
+ warnings.append(f"Non-standard section: '{section}'")
76
+
77
+ return warnings
78
+
79
+
80
+ def main():
81
+ """Validate CHANGELOG.md format."""
82
+ project_root = Path(__file__).parent.parent
83
+ changelog_path = project_root / 'CHANGELOG.md'
84
+
85
+ if not changelog_path.exists():
86
+ print("CHANGELOG.md not found")
87
+ return 1
88
+
89
+ with open(changelog_path, 'r', encoding='utf-8') as f:
90
+ content = f.read()
91
+
92
+ errors = []
93
+ warnings = []
94
+
95
+ # Check 1: Unreleased section
96
+ has_unreleased, error = check_unreleased_section(content)
97
+ if not has_unreleased:
98
+ errors.append(error)
99
+
100
+ # Check 2: Extract and validate version entries
101
+ versions = extract_versions(content)
102
+
103
+ if not versions:
104
+ errors.append("No version entries found in CHANGELOG.md")
105
+ else:
106
+ # Check version format
107
+ for version, date in versions:
108
+ if not validate_version_format(version):
109
+ errors.append(f"Invalid version format: {version}")
110
+ if not validate_date_format(date):
111
+ errors.append(f"Invalid date format for version {version}: {date}")
112
+
113
+ # Check version order
114
+ ordered, error = check_version_order(versions)
115
+ if not ordered:
116
+ errors.append(error)
117
+
118
+ # Check 3: Standard sections (warnings only)
119
+ section_warnings = check_standard_sections(content)
120
+ warnings.extend(section_warnings)
121
+
122
+ # Print results
123
+ if errors:
124
+ print("CHANGELOG.md validation failed")
125
+ print("\nErrors:")
126
+ for error in errors:
127
+ print(f" - {error}")
128
+
129
+ if warnings:
130
+ print("\nWarnings:")
131
+ for warning in warnings:
132
+ print(f" - {warning}")
133
+
134
+ print("\nPlease fix the errors and ensure CHANGELOG.md follows Keep a Changelog format.")
135
+ print("See: https://keepachangelog.com/en/1.0.0/")
136
+ return 1
137
+ else:
138
+ if warnings:
139
+ print("CHANGELOG.md validation passed with warnings:")
140
+ for warning in warnings:
141
+ print(f" - {warning}")
142
+ else:
143
+ print("CHANGELOG.md validation passed")
144
+ return 0
145
+
146
+
147
+ if __name__ == '__main__':
148
+ sys.exit(main())
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Pre-commit hook to validate commit message format.
4
+
5
+ Validates that commit messages follow Conventional Commits format:
6
+ - type(scope): description
7
+ - Valid types: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert
8
+
9
+ Reference: https://www.conventionalcommits.org/
10
+ """
11
+
12
+ import re
13
+ import sys
14
+ from pathlib import Path
15
+
16
+
17
+ VALID_TYPES = [
18
+ 'feat', # New feature
19
+ 'fix', # Bug fix
20
+ 'docs', # Documentation changes
21
+ 'style', # Code style changes (formatting, etc.)
22
+ 'refactor', # Code refactoring
23
+ 'test', # Adding or updating tests
24
+ 'chore', # Maintenance tasks
25
+ 'perf', # Performance improvements
26
+ 'ci', # CI/CD changes
27
+ 'build', # Build system changes
28
+ 'revert', # Revert previous commit
29
+ ]
30
+
31
+
32
+ def validate_commit_message(message):
33
+ """
34
+ Validate commit message format.
35
+
36
+ Expected format:
37
+ - type: description
38
+ - type(scope): description
39
+
40
+ Returns (is_valid, error_message)
41
+ """
42
+ lines = message.strip().split('\n')
43
+ if not lines:
44
+ return False, "Commit message is empty"
45
+
46
+ first_line = lines[0].strip()
47
+
48
+ # Check for merge commits (allowed)
49
+ if first_line.startswith('Merge '):
50
+ return True, None
51
+
52
+ # Check for revert commits (allowed)
53
+ if first_line.startswith('Revert '):
54
+ return True, None
55
+
56
+ # Pattern 1: type: description
57
+ # Pattern 2: type(scope): description
58
+ pattern = r'^(\w+)(\([a-zA-Z0-9_\-/]+\))?: .{3,}'
59
+
60
+ match = re.match(pattern, first_line)
61
+ if not match:
62
+ return False, (
63
+ f"Invalid commit message format: '{first_line}'\n"
64
+ "Expected format: 'type: description' or 'type(scope): description'\n"
65
+ f"Valid types: {', '.join(VALID_TYPES)}"
66
+ )
67
+
68
+ commit_type = match.group(1)
69
+ if commit_type not in VALID_TYPES:
70
+ return False, (
71
+ f"Invalid commit type: '{commit_type}'\n"
72
+ f"Valid types: {', '.join(VALID_TYPES)}"
73
+ )
74
+
75
+ # Check description length (at least 3 characters)
76
+ description_start = first_line.find(':') + 1
77
+ description = first_line[description_start:].strip()
78
+ if len(description) < 3:
79
+ return False, "Commit description too short (minimum 3 characters)"
80
+
81
+ # Check first line length (recommended: 72 chars, max: 100)
82
+ if len(first_line) > 100:
83
+ return False, f"First line too long ({len(first_line)} chars, max 100)"
84
+
85
+ # Check if description starts with capital letter
86
+ if description and not description[0].isupper():
87
+ return False, "Commit description should start with a capital letter"
88
+
89
+ return True, None
90
+
91
+
92
+ def main():
93
+ """Main function to validate commit message."""
94
+ # Get commit message file path from arguments
95
+ if len(sys.argv) < 2:
96
+ print("Usage: check_commit_message.py <commit-msg-file>")
97
+ return 0
98
+
99
+ commit_msg_file = Path(sys.argv[1])
100
+
101
+ if not commit_msg_file.exists():
102
+ print(f"Error: Commit message file not found: {commit_msg_file}")
103
+ return 1
104
+
105
+ # Read commit message
106
+ with open(commit_msg_file, 'r', encoding='utf-8') as f:
107
+ commit_message = f.read()
108
+
109
+ # Validate
110
+ is_valid, error_message = validate_commit_message(commit_message)
111
+
112
+ if not is_valid:
113
+ print("\nCommit message validation failed")
114
+ print(error_message)
115
+ print("\nConventional Commits format:")
116
+ print(" feat: Add new feature")
117
+ print(" fix: Fix bug in parser")
118
+ print(" docs: Update README")
119
+ print(" chore(deps): Update dependencies")
120
+ print("\nSee: https://www.conventionalcommits.org/")
121
+ return 1
122
+
123
+ return 0
124
+
125
+
126
+ if __name__ == '__main__':
127
+ sys.exit(main())
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Pre-commit hook to check version consistency across multiple files.
4
+
5
+ Ensures that version numbers in CHANGELOG.md, README.md, pyproject.toml,
6
+ and src/_version.py are consistent.
7
+ """
8
+
9
+ import re
10
+ import sys
11
+ from pathlib import Path
12
+
13
+
14
+ def extract_changelog_version(changelog_path):
15
+ """Extract the latest version from CHANGELOG.md."""
16
+ if not changelog_path.exists():
17
+ return None
18
+
19
+ with open(changelog_path, 'r', encoding='utf-8') as f:
20
+ content = f.read()
21
+
22
+ # Match pattern: ## [X.Y.Z] - YYYY-MM-DD
23
+ match = re.search(r'##\s+\[(\d+\.\d+\.\d+)\]\s+-\s+\d{4}-\d{2}-\d{2}', content)
24
+ if match:
25
+ return match.group(1)
26
+ return None
27
+
28
+
29
+ def extract_readme_version(readme_path):
30
+ """Extract version from README.md citation section."""
31
+ if not readme_path.exists():
32
+ return None
33
+
34
+ with open(readme_path, 'r', encoding='utf-8') as f:
35
+ content = f.read()
36
+
37
+ # Match pattern: version = {X.Y.Z}
38
+ match = re.search(r'version\s*=\s*\{(\d+\.\d+\.\d+)\}', content)
39
+ if match:
40
+ return match.group(1)
41
+ return None
42
+
43
+
44
+ def extract_pyproject_version(pyproject_path):
45
+ """Extract fallback_version from pyproject.toml."""
46
+ if not pyproject_path.exists():
47
+ return None
48
+
49
+ with open(pyproject_path, 'r', encoding='utf-8') as f:
50
+ content = f.read()
51
+
52
+ # Match pattern: fallback_version = "X.Y.Z"
53
+ match = re.search(r'fallback_version\s*=\s*["\'](\d+\.\d+\.\d+)["\']', content)
54
+ if match:
55
+ return match.group(1)
56
+ return None
57
+
58
+
59
+ def extract_version_py_version(version_py_path):
60
+ """Extract __version__ from src/_version.py."""
61
+ if not version_py_path.exists():
62
+ return None
63
+
64
+ with open(version_py_path, 'r', encoding='utf-8') as f:
65
+ content = f.read()
66
+
67
+ # Match pattern: __version__ = "X.Y.Z"
68
+ match = re.search(r'__version__\s*=\s*["\'](\d+\.\d+\.\d+)["\']', content)
69
+ if match:
70
+ return match.group(1)
71
+ return None
72
+
73
+
74
+ def main():
75
+ """Check version consistency across all files."""
76
+ project_root = Path(__file__).parent.parent
77
+
78
+ files = {
79
+ 'CHANGELOG.md': project_root / 'CHANGELOG.md',
80
+ 'README.md': project_root / 'README.md',
81
+ 'pyproject.toml': project_root / 'pyproject.toml',
82
+ 'src/_version.py': project_root / 'src' / '_version.py',
83
+ }
84
+
85
+ # Extract versions
86
+ versions = {
87
+ 'CHANGELOG.md': extract_changelog_version(files['CHANGELOG.md']),
88
+ 'README.md': extract_readme_version(files['README.md']),
89
+ 'pyproject.toml': extract_pyproject_version(files['pyproject.toml']),
90
+ 'src/_version.py': extract_version_py_version(files['src/_version.py']),
91
+ }
92
+
93
+ # Filter out None values
94
+ valid_versions = {k: v for k, v in versions.items() if v is not None}
95
+
96
+ if not valid_versions:
97
+ print("Warning: Could not extract version from any file")
98
+ return 0
99
+
100
+ # Check consistency
101
+ unique_versions = set(valid_versions.values())
102
+
103
+ if len(unique_versions) == 1:
104
+ print(f"✓ Version consistency check passed: {unique_versions.pop()}")
105
+ return 0
106
+ else:
107
+ print("✗ Version inconsistency detected!")
108
+ print("\nVersions found:")
109
+ for file, version in sorted(valid_versions.items()):
110
+ print(f" {file:20} -> {version}")
111
+
112
+ print("\nPlease ensure all version numbers are consistent before committing.")
113
+ print("Expected version (from CHANGELOG.md): {}".format(
114
+ versions.get('CHANGELOG.md', 'NOT FOUND')
115
+ ))
116
+ return 1
117
+
118
+
119
+ if __name__ == '__main__':
120
+ sys.exit(main())
@@ -13,6 +13,53 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
13
13
 
14
14
  ## [Unreleased]
15
15
 
16
+ ## [1.2.4] - 2026-09-18
17
+
18
+ ### Added
19
+ - 📚 **Documentation Improvements** - Expanded user and maintainer documentation, including Sphinx/Read the Docs configuration and corrected documentation links.
20
+
21
+ ### Changed
22
+ - 🐍 **Python Version Support** - Updated the minimum supported Python version to 3.9 and synchronized the requirement across documentation and CI workflows.
23
+
24
+ ### Fixed
25
+ - 🚀 **Release Workflow** - Corrected PyPI and TestPyPI publishing workflow configuration and standardized installation verification messages.
26
+
27
+ ## [1.2.3] - 2025-10-07
28
+
29
+ ### Added
30
+ - 📚 **Documentation Section** - Added comprehensive documentation links in README.md
31
+ - Link to CHANGELOG.md for version history and feature updates
32
+ - Link to docs/maintainers/VERSION_MANAGEMENT.md for release workflow and branch strategy
33
+ - Links to GitHub Issues and Discussions for community engagement
34
+
35
+ ### Changed
36
+ - 🏗️ **Branch Strategy Documentation** - Major update to VERSION_MANAGEMENT.md
37
+ - Added detailed branch strategy section explaining dev/main workflow
38
+ - Updated release workflow with 4-step process including branch merge requirement
39
+ - Enhanced publishing scenarios (normal release, hotfix, quick release)
40
+ - Expanded best practices from 8 to 10 comprehensive guidelines
41
+ - Updated quick reference with branch-specific commands
42
+
43
+ - 🔄 **Enhanced CI/CD Workflows** - Intelligent optimization for GitHub Actions
44
+ - Added TestPyPI test reuse mechanism in PyPI workflow (saves approximately 45 minutes per release)
45
+ - Implemented 7-day test validity window for TestPyPI results
46
+ - Added verification summary job with detailed test status reporting
47
+ - Optimized GitHub Actions minutes usage (approximately 40% savings)
48
+ - Enhanced workflow comments and documentation
49
+
50
+ ### Fixed
51
+ - 🐛 **Python 3.8 Compatibility** - Resolved f-string syntax issues in CI workflows
52
+ - Fixed package metadata verification step in publish-to-pypi.yml
53
+ - Fixed package metadata verification step in publish-to-testpypi.yml
54
+ - Resolved f-string backslash syntax error (not supported in Python 3.8)
55
+ - Ensured compatibility across all supported Python versions (3.8-3.12)
56
+
57
+ ### Technical Improvements
58
+ - Better CI/CD resource optimization with intelligent test reuse
59
+ - Clearer release workflow documentation for contributors
60
+ - Improved branch management guidelines
61
+ - Enhanced Python version compatibility in automated workflows
62
+
16
63
  ## [1.2.2] - 2025-10-05
17
64
 
18
65
  ### Added
@@ -192,7 +239,6 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
192
239
  - ✨ Automatic version management using setuptools-scm
193
240
  - 🤖 Dual GitHub Actions workflows: dev branch → TestPyPI, tag → PyPI
194
241
  - 📚 Comprehensive documentation for version management and publishing
195
- - 📝 CLAUDE.md - Guide for Claude Code integration
196
242
  - 📝 VERSION_MANAGEMENT.md - Complete guide for version management with Git tags and setuptools_scm
197
243
  - 📝 SECURITY.md - Security policy and vulnerability reporting guidelines
198
244
  - 📝 PROJECT_IMPROVEMENT_ANALYSIS.md - Detailed analysis of 26 issues