Skip to content

Commit 37010bd

Browse files
committed
refactor: migrate from bump2version to bump-my-version for version management
- Removed .bumpversion.cfg and integrated version management into pyproject.toml. - Updated pre-commit hooks and dependencies for code formatting, linting, and type checking. - Added new functionality to JSONSchemaMessageInstance for generating default values from JSON schema. - Enhanced test coverage for the new default value generation feature.
1 parent c1e6591 commit 37010bd

6 files changed

Lines changed: 316 additions & 57 deletions

File tree

.bumpversion.cfg

Lines changed: 0 additions & 10 deletions
This file was deleted.

.pre-commit-config.yaml

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,77 @@
1+
# MsgCenterPy pre-commit hooks
2+
# All tool configs are centralised in pyproject.toml
3+
14
repos:
2-
# Code formatting
5+
# ── Code formatting ───────────────────────────────────────────
36
- repo: https://github.com/psf/black
4-
rev: 23.12.1
7+
rev: 26.1.0
58
hooks:
69
- id: black
710
language_version: python3
8-
args: ["--line-length=120"]
11+
# Reads [tool.black] from pyproject.toml
912

10-
# Import sorting
13+
# ── Import sorting ────────────────────────────────────────────
1114
- repo: https://github.com/pycqa/isort
12-
rev: 5.13.2
15+
rev: 6.1.0
1316
hooks:
1417
- id: isort
15-
args: ["--profile", "black", "--multi-line", "3"]
18+
# Reads [tool.isort] from pyproject.toml
1619

17-
# Linting
20+
# ── Linting ───────────────────────────────────────────────────
1821
- repo: https://github.com/pycqa/flake8
19-
rev: 7.0.0
22+
rev: 7.3.0
2023
hooks:
2124
- id: flake8
22-
args:
23-
- "--max-line-length=200" # Allow longer lines after black formatting
24-
- "--extend-ignore=E203,W503,F401,E402,E721,F841"
25-
- "--exclude=build,dist,__pycache__,.mypy_cache,.pytest_cache,htmlcov,.idea,.vscode,docs/_build,msgcenterpy.egg-info"
25+
additional_dependencies: ["Flake8-pyproject"]
26+
# Reads [tool.flake8] from pyproject.toml via Flake8-pyproject
2627

27-
# Type checking
28+
# ── Type checking ─────────────────────────────────────────────
2829
- repo: https://github.com/pre-commit/mirrors-mypy
29-
rev: v1.8.0
30+
rev: v1.19.1
3031
hooks:
3132
- id: mypy
32-
additional_dependencies: [types-PyYAML, types-jsonschema, pydantic]
33-
args: ["--ignore-missing-imports", "--disable-error-code=unused-ignore"]
34-
files: "^(msgcenterpy/)" # Check both source code and tests
33+
args: ["--config-file=pyproject.toml"]
34+
files: "^(msgcenterpy/)"
35+
additional_dependencies:
36+
- "pydantic>=2.0"
37+
- "types-PyYAML"
38+
- "types-jsonschema"
3539

36-
# General pre-commit hooks
40+
# ── Basic file checks ────────────────────────────────────────
3741
- repo: https://github.com/pre-commit/pre-commit-hooks
38-
rev: v4.5.0
42+
rev: v6.0.0
3943
hooks:
40-
# File checks
4144
- id: trailing-whitespace
42-
args: [--markdown-linebreak-ext=md]
4345
- id: end-of-file-fixer
4446
- id: check-yaml
4547
- id: check-json
4648
- id: check-toml
47-
- id: check-xml
48-
49-
# Security
5049
- id: check-merge-conflict
5150
- id: check-case-conflict
5251
- id: check-symlinks
5352
- id: check-added-large-files
54-
args: ["--maxkb=1000"]
55-
56-
# Python specific
5753
- id: check-ast
5854
- id: debug-statements
5955
- id: name-tests-test
60-
args: ["--django"]
56+
args: ["--pytest-test-first"]
6157

62-
# Security scanning
58+
# ── Security scanning ────────────────────────────────────────
6359
- repo: https://github.com/PyCQA/bandit
64-
rev: 1.7.5
60+
rev: 1.9.3
6561
hooks:
6662
- id: bandit
6763
args: ["-c", "pyproject.toml"]
6864
additional_dependencies: ["bandit[toml]", "pbr"]
69-
exclude: "^tests/"
65+
exclude: "^(tests/)"
7066

71-
# YAML/JSON formatting
67+
# ── YAML/JSON/Markdown formatting ────────────────────────────
7268
- repo: https://github.com/pre-commit/mirrors-prettier
7369
rev: v4.0.0-alpha.8
7470
hooks:
7571
- id: prettier
7672
types_or: [yaml, json, markdown]
77-
exclude: "^(build/|dist/|__pycache__/|\\.mypy_cache/|\\.pytest_cache/|htmlcov/|\\.idea/|\\.vscode/|docs/_build/|msgcenterpy\\.egg-info/)"
73+
exclude: "^(build/|dist/|__pycache__/|\\.mypy_cache/|\\.pytest_cache/|htmlcov/|\\.vscode/|docs/_build/|msgcenterpy\\.egg-info/)"
7874

7975
# Global settings
80-
default_stages: [pre-commit, pre-push]
76+
default_stages: [pre-commit]
8177
fail_fast: false

docs/development/contributing.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,18 @@ Testing
8888
Version Management
8989
------------------
9090

91-
This project uses `bump2version` for version management. It's automatically installed with dev dependencies.
91+
This project uses `bump-my-version <https://github.com/callowayproject/bump-my-version>`_ for version management. It's automatically installed with dev dependencies. Configuration lives in ``pyproject.toml`` under ``[tool.bumpversion]``.
9292

9393
.. code-block:: bash
9494
9595
# Bug fixes (0.0.1 → 0.0.2)
96-
bump2version patch
96+
bump-my-version bump patch
9797
9898
# New features (0.0.2 → 0.1.0)
99-
bump2version minor
99+
bump-my-version bump minor
100100
101101
# Breaking changes (0.1.0 → 1.0.0)
102-
bump2version major
102+
bump-my-version bump major
103103
104104
After bumping version, push changes and tags:
105105

msgcenterpy/instances/json_schema_instance.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,87 @@ class JSONSchemaMessageInstance(MessageInstance[Dict[str, Any]]):
1919
_json_schema: Dict[str, Any] = dict()
2020
_json_data: Dict[str, Any] = dict()
2121

22+
_JSON_TYPE_DEFAULTS: Dict[str, Any] = {
23+
"string": "",
24+
"integer": 0,
25+
"number": 0.0,
26+
"boolean": False,
27+
"null": None,
28+
}
29+
30+
@classmethod
31+
def generate_default_from_schema(cls, schema: Dict[str, Any]) -> Dict[str, Any]:
32+
"""根据JSON Schema生成包含所有字段默认值的数据字典
33+
34+
优先使用schema中显式声明的default,否则根据类型生成零值。
35+
支持嵌套object递归生成。
36+
37+
Args:
38+
schema: JSON Schema定义(根schema或子object schema)
39+
40+
Returns:
41+
包含所有字段默认值的数据字典
42+
43+
Examples:
44+
>>> schema = {
45+
... "type": "object",
46+
... "properties": {
47+
... "name": {"type": "string"},
48+
... "age": {"type": "integer", "default": 18},
49+
... "active": {"type": "boolean"},
50+
... }
51+
... }
52+
>>> JSONSchemaMessageInstance.generate_default_from_schema(schema)
53+
{'name': '', 'age': 18, 'active': False}
54+
"""
55+
properties = schema.get("properties", {})
56+
result: Dict[str, Any] = {}
57+
58+
for field_name, field_schema in properties.items():
59+
if isinstance(field_schema, dict):
60+
result[field_name] = cls._generate_field_default(field_schema)
61+
62+
return result
63+
64+
@classmethod
65+
def _generate_field_default(cls, field_schema: Dict[str, Any]) -> Any:
66+
"""根据单个字段的schema生成默认值
67+
68+
Args:
69+
field_schema: 字段的JSON Schema定义
70+
71+
Returns:
72+
字段的默认值
73+
"""
74+
if "default" in field_schema:
75+
return field_schema["default"]
76+
77+
if "const" in field_schema:
78+
return field_schema["const"]
79+
80+
if "enum" in field_schema:
81+
enum_values = field_schema["enum"]
82+
if enum_values:
83+
return enum_values[0]
84+
85+
json_type = field_schema.get("type")
86+
87+
if json_type is None:
88+
return None
89+
90+
# 联合类型取第一个非null类型
91+
if isinstance(json_type, list):
92+
non_null = [t for t in json_type if t != "null"]
93+
json_type = non_null[0] if non_null else "null"
94+
95+
if json_type == "object":
96+
return cls.generate_default_from_schema(field_schema)
97+
98+
if json_type == "array":
99+
return []
100+
101+
return cls._JSON_TYPE_DEFAULTS.get(json_type)
102+
22103
def __init__(self, inner_data: Dict[str, Any], schema: Dict[str, Any], **kwargs: Any) -> None:
23104
"""
24105
初始化JSON Schema消息实例

pyproject.toml

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,17 @@ ros2 = [
4040
]
4141
dev = [
4242
"pytest>=7.0.0",
43-
"black>=22.0.0",
44-
"isort>=5.0.0",
45-
"mypy>=1.0.0",
43+
"pytest-asyncio>=0.21.0",
44+
"black>=23.0.0",
45+
"isort>=5.13.0",
46+
"flake8>=7.0.0",
47+
"Flake8-pyproject>=1.2.0",
48+
"mypy>=1.8.0",
4649
"types-jsonschema>=4.0.0",
4750
"types-PyYAML>=6.0.0",
48-
"pre-commit>=2.20.0",
49-
"bump2version>=1.0.0"
51+
"bandit[toml]>=1.7.0",
52+
"pre-commit>=3.5.0",
53+
"bump-my-version>=0.28.0",
5054
]
5155
docs = [
5256
"sphinx>=5.0.0",
@@ -70,14 +74,26 @@ include = ["msgcenterpy*"]
7074
[tool.setuptools.dynamic]
7175
version = {attr = "msgcenterpy.__version__"}
7276

77+
# ── Formatting ────────────────────────────────────────────────
78+
7379
[tool.black]
7480
line-length = 120
75-
target-version = ['py310', 'py311', 'py312']
81+
target-version = ["py310", "py311", "py312"]
7682

7783
[tool.isort]
7884
profile = "black"
85+
line_length = 120
7986
multi_line_output = 3
8087

88+
# ── Linting ───────────────────────────────────────────────────
89+
90+
[tool.flake8]
91+
max-line-length = 200
92+
extend-ignore = ["E203", "W503", "W291", "W293", "W391", "F401", "E402", "E721", "F841", "F541"]
93+
exclude = ["build", "dist", "__pycache__", ".mypy_cache", ".pytest_cache", "htmlcov", ".vscode", "docs/_build", "msgcenterpy.egg-info"]
94+
95+
# ── Type checking ─────────────────────────────────────────────
96+
8197
[tool.mypy]
8298
python_version = "3.10"
8399
plugins = ["pydantic.mypy"]
@@ -86,21 +102,44 @@ warn_unused_configs = true
86102
disallow_untyped_defs = true
87103
no_implicit_optional = true
88104
warn_redundant_casts = true
89-
warn_unused_ignores = true
105+
warn_unused_ignores = false
90106
strict_equality = true
107+
ignore_missing_imports = true
108+
109+
# ── Testing ───────────────────────────────────────────────────
91110

92111
[tool.pytest.ini_options]
93112
testpaths = ["tests"]
94113
python_files = "test_*.py"
95114
python_classes = "Test*"
96115
python_functions = "test_*"
97116
addopts = "-v --tb=short --strict-markers --strict-config -ra --color=yes"
98-
99117
filterwarnings = [
100118
"ignore::DeprecationWarning",
101-
"ignore::PendingDeprecationWarning"
119+
"ignore::PendingDeprecationWarning",
102120
]
103121

122+
# ── Security ──────────────────────────────────────────────────
123+
104124
[tool.bandit]
105125
exclude_dirs = ["tests", "build", "dist"]
106126
skips = ["B101", "B601"]
127+
128+
# ── Version management ────────────────────────────────────────
129+
130+
[tool.bumpversion]
131+
current_version = "0.1.5"
132+
commit = true
133+
tag = true
134+
tag_name = "v{new_version}"
135+
message = "release: bump version {current_version} → {new_version}"
136+
137+
[[tool.bumpversion.files]]
138+
filename = "pyproject.toml"
139+
search = 'current_version = "{current_version}"'
140+
replace = 'current_version = "{new_version}"'
141+
142+
[[tool.bumpversion.files]]
143+
filename = "msgcenterpy/__init__.py"
144+
search = '__version__ = "{current_version}"'
145+
replace = '__version__ = "{new_version}"'

0 commit comments

Comments
 (0)