5 Commits
v0.1.6 ... main

Author SHA1 Message Date
Xuwznln
182c5187a0 refactor: simplify _extract_namespaced_type_fields, remove redundant try-except and post-processing
Made-with: Cursor
2026-03-22 01:33:01 +08:00
Xuwznln
9e6007eb60 release: bump version 0.1.7 → 0.1.8 2026-03-22 01:25:18 +08:00
Xuwznln
03b3b1144c fix: resolve nested ROS2 message types losing properties in JSON Schema generation
Array fields containing nested message types (e.g., Point[]) were serialized
as {type: object} without inner properties. Now correctly extracts and includes
all nested fields, required list, and title via NamespacedType introspection.

Made-with: Cursor
2026-03-22 01:25:04 +08:00
Xuwznln
97c76708cd release: bump version 0.1.6 → 0.1.7 2026-03-01 11:18:26 +08:00
Xuwznln
05d33086a9 ci: update Python version in CI workflows to 3.11
- Changed Python version from 3.10 to 3.11 in ci.yml and publish.yml workflows.
- Updated cache keys and build names accordingly.
- Simplified conditional logic in ros2_instance.py for interface determination.
2026-03-01 11:17:15 +08:00
6 changed files with 58 additions and 25 deletions

View File

@@ -21,7 +21,7 @@ jobs:
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v6 uses: actions/setup-python@v6
with: with:
python-version: "3.10" # Use minimum version for consistency python-version: "3.10"
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -33,27 +33,27 @@ jobs:
with: with:
extra_args: --all-files extra_args: --all-files
# Step 2: Basic build and test with minimum Python version (3.10) # Step 2: Basic build and test
basic-build: basic-build:
name: Basic build (Python 3.10, Ubuntu) name: Basic build (Python 3.11, Ubuntu)
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [code-format] # Only run after code formatting passes needs: [code-format] # Only run after code formatting passes
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
- name: Set up Python 3.10 - name: Set up Python 3.11
uses: actions/setup-python@v6 uses: actions/setup-python@v6
with: with:
python-version: "3.10" python-version: "3.11"
- name: Cache pip dependencies - name: Cache pip dependencies
uses: actions/cache@v5 uses: actions/cache@v5
with: with:
path: ~/.cache/pip path: ~/.cache/pip
key: ubuntu-pip-3.10-${{ hashFiles('**/pyproject.toml') }} key: ubuntu-pip-3.11-${{ hashFiles('**/pyproject.toml') }}
restore-keys: | restore-keys: |
ubuntu-pip-3.10- ubuntu-pip-3.11-
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -173,7 +173,7 @@ jobs:
exclude: exclude:
# Skip the combination we already tested in basic-build # Skip the combination we already tested in basic-build
- os: ubuntu-latest - os: ubuntu-latest
python-version: "3.10" python-version: "3.11"
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6

View File

@@ -34,7 +34,7 @@ jobs:
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v6 uses: actions/setup-python@v6
with: with:
python-version: "3.10" # Use minimum version for consistency python-version: "3.10"
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -46,27 +46,27 @@ jobs:
with: with:
extra_args: --all-files extra_args: --all-files
# Step 2: Basic build and test with minimum Python version (3.10) # Step 2: Basic build and test
basic-build: basic-build:
name: Basic build (Python 3.10, Ubuntu) name: Basic build (Python 3.11, Ubuntu)
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [code-format] # Only run after code formatting passes needs: [code-format] # Only run after code formatting passes
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
- name: Set up Python 3.10 - name: Set up Python 3.11
uses: actions/setup-python@v6 uses: actions/setup-python@v6
with: with:
python-version: "3.10" python-version: "3.11"
- name: Cache pip dependencies - name: Cache pip dependencies
uses: actions/cache@v5 uses: actions/cache@v5
with: with:
path: ~/.cache/pip path: ~/.cache/pip
key: ubuntu-pip-3.10-${{ hashFiles('**/pyproject.toml') }} key: ubuntu-pip-3.11-${{ hashFiles('**/pyproject.toml') }}
restore-keys: | restore-keys: |
ubuntu-pip-3.10- ubuntu-pip-3.11-
- name: Install dependencies - name: Install dependencies
run: | run: |

View File

@@ -5,7 +5,7 @@ A multi-format message conversion system supporting seamless conversion
between ROS2, Pydantic, Dataclass, JSON, Dict, YAML and JSON Schema. between ROS2, Pydantic, Dataclass, JSON, Dict, YAML and JSON Schema.
""" """
__version__ = "0.1.6" __version__ = "0.1.8"
__license__ = "Apache-2.0" __license__ = "Apache-2.0"
from msgcenterpy.core.envelope import MessageEnvelope, create_envelope from msgcenterpy.core.envelope import MessageEnvelope, create_envelope

View File

@@ -277,9 +277,16 @@ class TypeInfo:
# Special handling for object types # Special handling for object types
if self.is_object and self.object_fields: if self.is_object and self.object_fields:
properties = {} properties = {}
required_fields = []
for field_name, field_info in self.object_fields.items(): for field_name, field_info in self.object_fields.items():
properties[field_name] = field_info.to_json_schema_property(include_constraints) properties[field_name] = field_info.to_json_schema_property(include_constraints)
if field_info.has_constraint(ConstraintType.REQUIRED):
required_fields.append(field_name)
property_schema["properties"] = properties property_schema["properties"] = properties
if required_fields:
property_schema["required"] = required_fields
if self.field_name and self.field_name != Consts.ELEMENT_TYPE_INFO_SYMBOL:
property_schema["title"] = self.field_name
# Add description # Add description
if self.original_type: if self.original_type:

View File

@@ -40,11 +40,7 @@ class ROS2MessageInstance(MessageInstance[Any]):
interface = ( interface = (
"msg" "msg"
if ".msg" in module_name if ".msg" in module_name
else "srv" else "srv" if ".srv" in module_name else "action" if ".action" in module_name else "msg"
if ".srv" in module_name
else "action"
if ".action" in module_name
else "msg"
) )
return f"{package}/{interface}/{class_name}" if package and class_name else f"{module_name}.{class_name}" return f"{package}/{interface}/{class_name}" if package and class_name else f"{module_name}.{class_name}"
@@ -221,10 +217,9 @@ class ROS2MessageInstance(MessageInstance[Any]):
# 基础类型的约束将在 field_accessor 中自动添加 # 基础类型的约束将在 field_accessor 中自动添加
pass pass
elif isinstance(definition_type, NamespacedType): elif isinstance(definition_type, NamespacedType):
# 对象类型,标记为对象并提取字段信息
type_info.is_object = True type_info.is_object = True
type_info.add_constraint(ConstraintType.TYPE_KEEP, True) type_info.add_constraint(ConstraintType.TYPE_KEEP, True)
# 这里可以进一步扩展来提取对象字段信息 self._extract_namespaced_type_fields(type_info, definition_type)
# 提取元素类型信息 # 提取元素类型信息
if get_element_type: if get_element_type:
if not isinstance(definition_type, AbstractNestedType): if not isinstance(definition_type, AbstractNestedType):
@@ -240,3 +235,33 @@ class ROS2MessageInstance(MessageInstance[Any]):
original_type=definition_type.value_type, original_type=definition_type.value_type,
) )
self._extract_from_rosidl_definition(type_info.element_type_info) self._extract_from_rosidl_definition(type_info.element_type_info)
def _extract_namespaced_type_fields(self, type_info: TypeInfo, namespaced_type: "NamespacedType") -> None:
"""从 NamespacedType嵌套 ROS2 消息)中提取所有字段信息,填充 object_fields
递归处理嵌套的消息类型,确保多层嵌套的结构也能正确提取。
Args:
type_info: 要填充 object_fields 的 TypeInfo 对象
namespaced_type: rosidl NamespacedType 定义
"""
msg_cls = import_message_from_namespaced_type(namespaced_type)
msg_instance = msg_cls()
# noinspection PyProtectedMember
slots = msg_instance._fields_and_field_types
slot_types = msg_instance.SLOT_TYPES
for field_name, slot_type in zip(slots, slot_types):
std_type = TypeConverter.rosidl_definition_to_standard(slot_type)
python_type = TypeConverter.standard_to_python_type(std_type)
field_type_info = TypeInfo(
field_name=field_name,
field_path=f"{type_info.field_path}.{field_name}",
standard_type=std_type,
python_type=python_type,
original_type=slot_type,
)
self._extract_from_rosidl_definition(field_type_info)
field_type_info.add_constraint(ConstraintType.REQUIRED, True)
type_info.object_fields[field_name] = field_type_info

View File

@@ -128,9 +128,10 @@ skips = ["B101", "B601"]
# ── Version management ──────────────────────────────────────── # ── Version management ────────────────────────────────────────
[tool.bumpversion] [tool.bumpversion]
current_version = "0.1.6" current_version = "0.1.8"
commit = true commit = true
tag = true tag = true
push = true
tag_name = "v{new_version}" tag_name = "v{new_version}"
message = "release: bump version {current_version} → {new_version}" message = "release: bump version {current_version} → {new_version}"