From e5a15de4ec60ab2aca39611388865a71a0d62bc2 Mon Sep 17 00:00:00 2001 From: echen01 Date: Wed, 10 Jun 2026 17:55:05 -0400 Subject: [PATCH] Support Python 3.14 - Pull labmaze from the echen01/labmaze fork on Python >= 3.14: the upstream release has no 3.14 wheels and its sdist needs Bazel. The fork (v1.0.7) uses nanobind + scikit-build-core and builds with just pip. - requirements.txt: on Python >= 3.14 use dm-tree 0.1.10, h5py 3.16.0 and protobuf 7.35.0, the first releases with 3.14 support. - mocap loader: FieldDescriptor.label was removed in protobuf 7.x; use is_repeated when available. Full test suite passes on Python 3.14.5 (3159 passed, 69 skipped, 3 xfailed; dm_control/blender excluded since it requires Blender's bpy). Co-Authored-By: Claude Fable 5 --- dm_control/locomotion/mocap/loader.py | 13 ++++++++++++- dm_control/locomotion/mocap/loader_test.py | 2 +- requirements.txt | 12 ++++++++---- setup.py | 5 ++++- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/dm_control/locomotion/mocap/loader.py b/dm_control/locomotion/mocap/loader.py index 7587c8d8..ff57826b 100644 --- a/dm_control/locomotion/mocap/loader.py +++ b/dm_control/locomotion/mocap/loader.py @@ -26,6 +26,17 @@ import numpy as np +def _is_repeated_field(field): + """Returns whether a proto field is repeated, across protobuf versions. + + `FieldDescriptor.label` was removed in protobuf 7.x in favor of + `is_repeated`, which is only available from protobuf 5.29 onwards. + """ + if hasattr(field, 'is_repeated'): + return field.is_repeated + return field.label == descriptor.FieldDescriptor.LABEL_REPEATED + + class TrajectoryLoader(metaclass=abc.ABCMeta): """Base class for helpers that load and decode mocap trajectories.""" @@ -106,7 +117,7 @@ def _fill_primitive_proto_fields(self, proto, h5_group, skip_fields=()): continue elif field.type not in (descriptor.FieldDescriptor.TYPE_GROUP, descriptor.FieldDescriptor.TYPE_MESSAGE): - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + if _is_repeated_field(field): getattr(proto, field.name).extend(h5_group.attrs[field.name]) else: setattr(proto, field.name, h5_group.attrs[field.name]) diff --git a/dm_control/locomotion/mocap/loader_test.py b/dm_control/locomotion/mocap/loader_test.py index 9f18ed15..76b350e8 100644 --- a/dm_control/locomotion/mocap/loader_test.py +++ b/dm_control/locomotion/mocap/loader_test.py @@ -40,7 +40,7 @@ def assert_proto_equal(self, x, y, msg=''): for field in x.DESCRIPTOR.fields: x_field = getattr(x, field.name) y_field = getattr(y, field.name) - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + if loader._is_repeated_field(field): if field.type == descriptor.FieldDescriptor.TYPE_MESSAGE: for i, (x_child, y_child) in enumerate(zip(x_field, y_field)): self.assert_proto_equal( diff --git a/requirements.txt b/requirements.txt index 07c752b2..e45b5eb1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,12 @@ absl-py==2.3.1 dm-env==1.6 -dm-tree==0.1.9 +dm-tree==0.1.10; python_version >= '3.14' +dm-tree==0.1.9; python_version < '3.14' glfw==2.9.0 -h5py==3.14.0 -labmaze==1.0.6 +h5py==3.16.0; python_version >= '3.14' +h5py==3.14.0; python_version < '3.14' +labmaze @ git+https://github.com/echen01/labmaze.git; python_version >= '3.14' +labmaze==1.0.6; python_version < '3.14' lxml==6.0.1 mock==5.2.0 mujoco==3.9.0 @@ -11,7 +14,8 @@ numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' pillow==11.3.0 -protobuf==3.19.4 +protobuf==7.35.0; python_version >= '3.14' +protobuf==3.19.4; python_version < '3.14' pyopengl==3.1.10 pyparsing==3.2.3 pytest==8.4.1 diff --git a/setup.py b/setup.py index 3a64bf4c..6f04a371 100644 --- a/setup.py +++ b/setup.py @@ -189,7 +189,10 @@ def is_excluded(s): 'dm-env', 'dm-tree != 0.1.2', 'glfw', - 'labmaze', + # Upstream labmaze has no Python 3.14 wheels and its sdist requires + # Bazel; this fork builds with just pip and a C++17 compiler. + 'labmaze @ git+https://github.com/echen01/labmaze.git ; python_version >= "3.14"', + 'labmaze ; python_version < "3.14"', 'lxml', 'mujoco >= 3.9.0', 'numpy >= 1.9.0',