GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — chore: drop Python 3.10 (EOL) and remove the tomli dependency (#662) · commit-check/commit-check@bd2ed6e

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • .github/workflows
    • ci.yml
  • CONTRIBUTING.md
  • commit_check
    • config.py
  • pyproject.toml
  • tests
    • config_test.py
  • uv.lock
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎.github/workflows/ci.yml‎

Copy file name to clipboardExpand all lines: .github/workflows/ci.yml
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
strategy:
6161
fail-fast: false
6262
matrix:
63-
py: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15']
63+
py: ['3.11', '3.12', '3.13', '3.14', '3.15']
6464
os: ['windows-latest', 'ubuntu-24.04', 'macos-latest']
6565
runs-on: ${{ matrix.os }}
6666
steps:
Collapse file

‎CONTRIBUTING.md‎

Copy file name to clipboardExpand all lines: CONTRIBUTING.md
+1-1Lines changed: 1 addition & 1 deletion
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ commit_check/
4646
├── __init__.py # Package constants: DEFAULT_COMMIT_TYPES, DEFAULT_BRANCH_TYPES, DEFAULT_BOOLEAN_RULES
4747
├── main.py # CLI entry point, argument parsing, StdinReader
4848
├── api.py # Public Python API (validate_message, validate_branch, ...) without a subprocess
49-
├── config.py # TOML file loading (uses tomllib on Python 3.11+, tomli on older), inherit_from, deep_merge
49+
├── config.py # TOML file loading (stdlib tomllib), inherit_from, deep_merge
5050
├── config_merger.py # ConfigMerger: merges CLI → Env → TOML → Defaults
5151
├── rule_builder.py # RuleBuilder: creates ValidationRule objects from config + catalog
5252
├── rules_catalog.py # Catalog of all rules (COMMIT_RULES, BRANCH_RULES, PUSH_RULES, FILES_RULES, TAG_RULES)
Collapse file

‎commit_check/config.py‎

Copy file name to clipboardExpand all lines: commit_check/config.py
+3-10Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,13 @@
77
import os
88
import stat
99
import sys
10+
import tomllib
1011
import urllib.error
1112
import urllib.request
1213
from pathlib import Path
1314
from typing import Any
1415

15-
try:
16-
import tomllib
17-
18-
toml_load = tomllib.load
19-
except ImportError:
20-
import tomli # type: ignore
21-
22-
toml_load = tomli.load
16+
toml_load = tomllib.load
2317

2418

2519
class ConfigError(ValueError):
@@ -253,8 +247,7 @@ def _resolve_inherit_from(
253247
# Fail open, as documented: a parent that cannot be loaded leaves the
254248
# local config in force. Say so on stderr rather than silently, and keep
255249
# stdout clean for --format json.
256-
# TOMLDecodeError (tomllib and tomli alike) is a ValueError; URLError is
257-
# an OSError.
250+
# TOMLDecodeError is a ValueError; URLError is an OSError.
258251
try:
259252
parent = _load_parent_config(inherit_from, base_dir)
260253
except (OSError, ValueError) as e:
Collapse file

‎pyproject.toml‎

Copy file name to clipboardExpand all lines: pyproject.toml
+3-6Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,14 @@ license = "MIT"
1111
authors = [
1212
{ name = "Xianpeng Shen", email = "[email protected]" },
1313
]
14-
requires-python = ">=3.10"
15-
dependencies = [
16-
"tomli>=1.1.0; python_version < '3.11'",
17-
]
14+
requires-python = ">=3.11"
15+
dependencies = []
1816
classifiers = [
1917
# https://pypi.org/pypi?%3Aaction=list_classifiers
2018
"Development Status :: 5 - Production/Stable",
2119
"Intended Audience :: Developers",
2220
"Natural Language :: English",
2321
"Operating System :: OS Independent",
24-
"Programming Language :: Python :: 3.10",
2522
"Programming Language :: Python :: 3.11",
2623
"Programming Language :: Python :: 3.12",
2724
"Programming Language :: Python :: 3.13",
@@ -66,7 +63,7 @@ local_scheme = "no-local-version"
6663
fallback_version = "0.0.0"
6764

6865
[tool.mypy]
69-
python_version = "3.10"
66+
python_version = "3.11"
7067
show_error_codes = true
7168
show_column_numbers = true
7269

Collapse file

‎tests/config_test.py‎

Copy file name to clipboardExpand all lines: tests/config_test.py
-268Lines changed: 0 additions & 268 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import os
44
import subprocess
5-
import sys
65
import tempfile
76
from pathlib import Path
87
from typing import ClassVar
@@ -27,19 +26,6 @@
2726
EXAMPLE_CONFIG_URL = "https://example.com/cchk.toml"
2827

2928

30-
def _restore_config_attribute(module):
31-
"""Point ``commit_check.config`` back at *module* after a fresh import.
32-
33-
Re-importing the config module rebinds the attribute on the package as
34-
well as the sys.modules entry, and restoring sys.modules alone leaves
35-
the attribute on the copy. Python 3.10's patch() resolves a target such
36-
as URLOPEN_MODULE through that attribute, so every later patch landed on
37-
the copy and the tests behind it reached the network.
38-
"""
39-
if module is not None:
40-
sys.modules["commit_check"].config = module
41-
42-
4329
class TestConfig:
4430
@pytest.mark.benchmark
4531
def test_load_config_with_path_hint(self):
@@ -243,76 +229,6 @@ def test_toml_load_function_exists(self):
243229
finally:
244230
os.unlink(f.name)
245231

246-
@pytest.mark.benchmark
247-
def test_tomli_import_fallback(self):
248-
"""Test that tomli is imported when tomllib is not available (lines 10-13)."""
249-
import sys
250-
251-
# Save original modules
252-
original_tomllib = sys.modules.get("tomllib")
253-
original_config = sys.modules.get("commit_check.config")
254-
255-
try:
256-
# Remove modules from cache to force fresh import
257-
if "tomllib" in sys.modules:
258-
del sys.modules["tomllib"]
259-
if "commit_check.config" in sys.modules:
260-
del sys.modules["commit_check.config"]
261-
262-
# Mock tomllib module to not exist
263-
with patch.dict("sys.modules", {"tomllib": None}):
264-
# Force import error by patching __import__ for tomllib specifically
265-
original_import = __builtins__["__import__"]
266-
267-
def mock_import(name, *args, **kwargs):
268-
if name == "tomllib":
269-
raise ImportError("No module named 'tomllib'")
270-
# For tomli, return a working mock
271-
if name == "tomli":
272-
273-
class MockTomli:
274-
@staticmethod
275-
def load(f):
276-
content = f.read().decode("utf-8")
277-
# Simple parser for test
278-
if '[test]\nvalue = "tomli_works"' in content:
279-
return {"test": {"value": "tomli_works"}}
280-
return {}
281-
282-
return MockTomli()
283-
return original_import(name, *args, **kwargs)
284-
285-
with patch("builtins.__import__", side_effect=mock_import):
286-
# Import the config module - should use tomli fallback
287-
import commit_check.config as config_module
288-
289-
# Verify that the module loaded successfully
290-
assert hasattr(config_module, "toml_load")
291-
assert callable(config_module.toml_load)
292-
293-
# Test that it can actually parse TOML content
294-
config_content = b'[test]\nvalue = "tomli_works"\n'
295-
with tempfile.NamedTemporaryFile(
296-
mode="wb", suffix=".toml", delete=False
297-
) as f:
298-
f.write(config_content)
299-
f.flush()
300-
301-
try:
302-
with open(f.name, "rb") as config_file:
303-
result = config_module.toml_load(config_file)
304-
assert result == {"test": {"value": "tomli_works"}}
305-
finally:
306-
os.unlink(f.name)
307-
308-
finally:
309-
# Restore original modules
310-
if original_tomllib is not None:
311-
sys.modules["tomllib"] = original_tomllib
312-
if original_config is not None:
313-
sys.modules["commit_check.config"] = original_config
314-
_restore_config_attribute(original_config)
315-
316232

317233
class TestConfigEdgeCases:
318234
"""Test TOML parsing errors and exception handling."""
@@ -360,190 +276,6 @@ def test_load_config_file_permission_error(self):
360276
os.chmod(f.name, 0o644)
361277
os.unlink(f.name)
362278

363-
@pytest.mark.benchmark
364-
def test_tomli_import_fallback(self):
365-
"""Test the tomli import fallback when tomllib is not available."""
366-
# We need to test the import fallback behavior
367-
# This is complex because the imports happen at module load time
368-
369-
# Create a minimal test by importing the config module's behavior
370-
config_content = b"""
371-
[test]
372-
fallback = true
373-
"""
374-
375-
with tempfile.NamedTemporaryFile(mode="wb", suffix=".toml", delete=False) as f:
376-
f.write(config_content)
377-
f.flush()
378-
379-
try:
380-
# Test that we can load config regardless of which TOML library is used
381-
config = load_config(f.name)
382-
assert config["test"]["fallback"] is True
383-
384-
# Since we can't easily test the import fallback on Python 3.11+,
385-
# let's at least verify that the toml_load function works
386-
from commit_check.config import toml_load
387-
388-
with open(f.name, "rb") as config_file:
389-
result = toml_load(config_file)
390-
assert result["test"]["fallback"] is True
391-
392-
finally:
393-
os.unlink(f.name)
394-
395-
396-
class TestConfigFallback:
397-
"""Direct test of the config import fallback using module manipulation."""
398-
399-
@pytest.mark.benchmark
400-
def test_config_tomli_fallback_direct(self):
401-
"""Test config.py fallback to tomli by manipulating imports."""
402-
403-
# Save original state
404-
original_modules = sys.modules.copy()
405-
406-
try:
407-
# Remove config module if already imported
408-
if "commit_check.config" in sys.modules:
409-
del sys.modules["commit_check.config"]
410-
411-
# Make tomllib unavailable by raising ImportError
412-
original_import = __import__
413-
414-
def mock_import(name, globals=None, locals=None, fromlist=(), level=0):
415-
if name == "tomllib":
416-
raise ImportError("No module named 'tomllib'")
417-
# For tomli, return a working mock
418-
if name == "tomli":
419-
420-
class MockTomli:
421-
@staticmethod
422-
def load(f):
423-
content = f.read().decode("utf-8")
424-
# Simple parser for test
425-
if 'test_key = "test_value"' in content:
426-
return {"test_key": "test_value"}
427-
return {}
428-
429-
return MockTomli()
430-
return original_import(name, globals, locals, fromlist, level)
431-
432-
with patch("builtins.__import__", side_effect=mock_import):
433-
# Now import config - should use tomli fallback
434-
from commit_check.config import toml_load
435-
436-
# Test that it works
437-
config_content = b'test_key = "test_value"'
438-
with tempfile.NamedTemporaryFile(
439-
mode="wb", suffix=".toml", delete=False
440-
) as f:
441-
f.write(config_content)
442-
f.flush()
443-
444-
try:
445-
with open(f.name, "rb") as config_file:
446-
result = toml_load(config_file)
447-
assert result == {"test_key": "test_value"}
448-
finally:
449-
os.unlink(f.name)
450-
451-
finally:
452-
# Restore original modules
453-
sys.modules.clear()
454-
sys.modules.update(original_modules)
455-
_restore_config_attribute(original_modules.get("commit_check.config"))
456-
457-
458-
class TestConfigImport:
459-
"""Test import fallback by creating a test version of config.py."""
460-
461-
@pytest.mark.benchmark
462-
@pytest.mark.skipif(
463-
sys.version_info < (3, 11), reason="tomllib only available in Python 3.11+"
464-
)
465-
def test_tomli_import_fallback_simulation(self):
466-
"""Test tomli import fallback by simulating the ImportError condition."""
467-
468-
# Simulates the config.py import logic
469-
def pick_loader():
470-
try:
471-
import tomllib
472-
473-
return tomllib.load, True
474-
except ImportError:
475-
import tomli
476-
477-
return tomli.load, False
478-
479-
# Test case 1: Normal case (tomllib available)
480-
toml_load, used_tomllib = pick_loader()
481-
assert used_tomllib is True
482-
assert callable(toml_load)
483-
484-
# Test case 2: Simulate ImportError for tomllib
485-
with (
486-
patch.dict("sys.modules", {"tomllib": None}),
487-
patch(
488-
"builtins.__import__",
489-
side_effect=self._mock_import_error,
490-
),
491-
):
492-
toml_load, used_tomllib = pick_loader()
493-
assert used_tomllib is False
494-
assert callable(toml_load)
495-
496-
@staticmethod
497-
def _mock_import_error(name, *args, **kwargs):
498-
"""Mock import function that raises ImportError for tomllib."""
499-
if name == "tomllib":
500-
raise ImportError("No module named 'tomllib'")
501-
502-
# For tomli, we need to mock it since it might not be installed
503-
if name == "tomli":
504-
# Create a mock tomli module
505-
class MockTomli:
506-
@staticmethod
507-
def load(f):
508-
# Simple TOML parser for testing
509-
content = f.read().decode("utf-8")
510-
if "[test]" in content and 'value = "test"' in content:
511-
return {"test": {"value": "test"}}
512-
return {}
513-
514-
return MockTomli()
515-
516-
# For all other imports, use the real import
517-
return __import__(name, *args, **kwargs)
518-
519-
@pytest.mark.benchmark
520-
def test_import_paths_coverage(self):
521-
"""Ensure both import paths are conceptually tested."""
522-
# This test verifies that both the tomllib and tomli code paths
523-
# would work in their respective environments
524-
525-
# Test the function signature matches expectation
526-
config_content = b"""
527-
[test]
528-
value = "test"
529-
"""
530-
531-
with tempfile.NamedTemporaryFile(mode="wb", suffix=".toml", delete=False) as f:
532-
f.write(config_content)
533-
f.flush()
534-
535-
try:
536-
# Test using the actual config module (uses tomllib on Python 3.11+)
537-
from commit_check.config import toml_load
538-
539-
with open(f.name, "rb") as config_file:
540-
result = toml_load(config_file)
541-
542-
assert result == {"test": {"value": "test"}}
543-
544-
finally:
545-
os.unlink(f.name)
546-
547279

548280
class TestDeepMerge:
549281
"""Tests for the deep_merge helper."""

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.