csu-hmc / opty

A library for using direct collocation in the optimization of dynamic systems.
http://opty.readthedocs.io
Other
94 stars 20 forks source link

String split is failing on Python 3.13 #225

Closed moorepants closed 18 hours ago

moorepants commented 1 month ago

The 3.13 builds failed on conda forge, see https://github.com/conda-forge/opty-feedstock/pull/33

This is the traceback:

+ python betts2003.py
Traceback (most recent call last):
  File "/home/conda/feedstock_root/build_artifacts/opty_1725960370278/test_tmp/betts2003.py", line 59, in <module>
    prob = Problem(obj, obj_grad,
    return self.use_parent_doc(f, overridden)
           ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/home/conda/feedstock_root/build_artifacts/opty_1725960370278/_test_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_p/lib/python3.13/site-packages/opty/direct_collocation.py", line 73, in use_parent_doc
    func.__doc__ = self._combine_docs(self.mthd.__doc__,
                   ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
                                      ConstraintCollocator.__init__.__doc__)
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/conda/feedstock_root/build_artifacts/opty_1725960370278/_test_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_p/lib/python3.13/site-packages/opty/direct_collocation.py", line 80, in _combine_docs
    _, middle = coll_doc.split('Parameters\n        ==========\n        ')
    ^^^^^^^^^
ValueError: not enough values to unpack (expected 2, got 1)
WARNING: Tests failed for opty-1.3.0-py313h9c9eb82_1.conda - moving package to /home/conda/feedstock_root/build_artifacts/broken
Traceback (most recent call last):
  File "/opt/conda/lib/python3.10/site-packages/conda_build/build.py", line 3523, in test
    utils.check_call_env(
  File "/opt/conda/lib/python3.10/site-packages/conda_build/utils.py", line 404, in check_call_env
    return _func_defaulting_env_to_os_environ("call", *popenargs, **kwargs)
  File "/opt/conda/lib/python3.10/site-packages/conda_build/utils.py", line 380, in _func_defaulting_env_to_os_environ
    raise subprocess.CalledProcessError(proc.returncode, _args)
subprocess.CalledProcessError: Command '['/bin/bash', '-o', 'errexit', '/home/conda/feedstock_root/build_artifacts/opty_1725960370278/test_tmp/conda_test_runner.sh']' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/conda/bin/conda-build", line 11, in <module>
    sys.exit(execute())
  File "/opt/conda/lib/python3.10/site-packages/conda_build/cli/main_build.py", line 589, in execute
    api.build(
  File "/opt/conda/lib/python3.10/site-packages/conda_build/api.py", line 209, in build
    return build_tree(
  File "/opt/conda/lib/python3.10/site-packages/conda_build/build.py", line 3727, in build_tree
    test(pkg, config=metadata.config.copy(), stats=stats)
  File "/opt/conda/lib/python3.10/site-packages/conda_build/build.py", line 3537, in test
    tests_failed(
  File "/opt/conda/lib/python3.10/site-packages/conda_build/build.py", line 3584, in tests_failed
    raise CondaBuildUserError("TESTS FAILED: " + os.path.basename(pkg))
conda_build.exceptions.CondaBuildUserError: TESTS FAILED: opty-1.3.0-py313h9c9eb82_1.conda

and it seems that this split() call isn't working:

    @staticmethod
    def _combine_docs(prob_doc, coll_doc):
        beg, end = prob_doc.split('bounds')
        _, middle = coll_doc.split('Parameters\n        ==========\n        ')
        return beg + middle[:-9] + '        bounds' + end
moorepants commented 19 hours ago

The readthedoc builds are now failing from this: https://app.readthedocs.org/projects/opty/builds/25974252/ I guess they'e updated to Python 3.13.

moorepants commented 18 hours ago

Looks like there is no whitespace in Python 3.13:

ipdb> coll_doc.split('Parameters\n        ==========\n        ')
["Instantiates a ConstraintCollocator object.\n\nParameters\n==========\nequations_of_motion : sympy.Matrix, shape(n, 1)\n    A column matrix of SymPy expressions defining the right hand side\n    of the equations of motion when the left hand side is zero, e.g.\n    ``0 = x'(t) - f(x(t), u(t), p)`` or ``0 = f(x'(t), x(t), u(t),\n    p)``. These should be in first order form but not necessairly\n    explicit. They can be ordinary differential equations or\n    differential algebraic equations.\nstate_symbols : iterable\n    An iterable containing all ``n` of the SymPy functions of time\n    which represent the states in the equations of motion.\nnum_collocation_nodes : integer\n    The number of collocation nodes, ``N``. All known trajectory arrays\n    should be of this length.\nnode_time_interval : float or Symbol\n    The time interval between collocation nodes. If a SymPy symbol is\n    provided, the time interval will be treated as a free variable\n    resulting in a variable duration solution.\nknown_parameter_map : dictionary, optional\n    A dictionary that maps the SymPy symbols representing the known\n    constant parameters to floats. Any parameters in the equations of\n    motion not provided in this dictionary will become free\n    optimization variables.\nknown_trajectory_map : dictionary, optional\n    A dictionary that maps the non-state SymPy functions of time to\n    ndarrays of floats of ``shape(N,)``. Any time varying parameters in\n    the equations of motion not provided in this dictionary will become\n    free trajectories optimization variables. If solving a variable\n    duration problem, note that the values here are fixed at each node\n    and will not scale with a varying time interval.\ninstance_constraints : iterable of SymPy expressions, optional\n    These expressions are for constraints on the states at specific\n    times. They can be expressions with any state instance and any of\n    the known parameters found in the equations of motion. All states\n    should be evaluated at a specific instant of time. For example, the\n    constraint ``x(0) = 5.0`` would be specified as ``x(0) - 5.0``. For\n    variable duration problems you must specify time as an integer\n    multiple of the node time interval symbol, for example ``x(0*h) -\n    5.0``. The integer must be a value from 0 to\n    ``num_collocation_nodes - 1``. Unknown parameters and time varying\n    parameters other than the states are currently not supported.\ntime_symbol : SymPy Symbol, optional\n    The symbol representating time in the equations of motion. If not\n    given, it is assumed to be the default stored in\n    ``sympy.physics.vector.dynamicsymbols._t``.\ntmp_dir : string, optional\n    If you want to see the generated Cython and C code for the\n    constraint and constraint Jacobian evaluations, pass in a path to a\n    directory here.\nintegration_method : string, optional\n    The integration method to use, either ``backward euler`` or\n    ``midpoint``.\nparallel : boolean, optional\n    If true and openmp is installed, constraints and the Jacobian of\n    the constraints will be executed across multiple threads. This is\n    only useful for performance when the equations of motion have an\n    extremely large number of operations.\nshow_compile_output : boolean, optional\n    If True, STDOUT and STDERR of the Cython compilation call will be\n    shown.\n\n"]
moorepants commented 18 hours ago

From Python 3.12:

ipdb> coll_doc
"Instantiates a ConstraintCollocator object.\n\n        Parameters\n        ==========\n        equations_of_motion : sympy.Matrix, shape(n, 1)\n            A column matrix of SymPy expressions defining the right hand side\n            of the equations of motion when the left hand side is zero, e.g.\n            ``0 = x'(t) - f(x(t), u(t), p)`` or ``0 = f(x'(t), x(t), u(t),\n            p)``. These should be in first order form but not necessairly\n            explicit. They can be ordinary differential equations or\n            differential algebraic equations.\n        state_symbols : iterable\n            An iterable containing all ``n` of the SymPy functions of time\n            which represent the states in the equations of motion.\n        num_collocation_nodes : integer\n            The number of collocation nodes, ``N``. All known trajectory arrays\n            should be of this length.\n        node_time_interval : float or Symbol\n            The time interval between collocation nodes. If a SymPy symbol is\n            provided, the time interval will be treated as a free variable\n            resulting in a variable duration solution.\n        known_parameter_map : dictionary, optional\n            A dictionary that maps the SymPy symbols representing the known\n            constant parameters to floats. Any parameters in the equations of\n            motion not provided in this dictionary will become free\n            optimization variables.\n        known_trajectory_map : dictionary, optional\n            A dictionary that maps the non-state SymPy functions of time to\n            ndarrays of floats of ``shape(N,)``. Any time varying parameters in\n            the equations of motion not provided in this dictionary will become\n            free trajectories optimization variables. If solving a variable\n            duration problem, note that the values here are fixed at each node\n            and will not scale with a varying time interval.\n        instance_constraints : iterable of SymPy expressions, optional\n            These expressions are for constraints on the states at specific\n            times. They can be expressions with any state instance and any of\n            the known parameters found in the equations of motion. All states\n            should be evaluated at a specific instant of time. For example, the\n            constraint ``x(0) = 5.0`` would be specified as ``x(0) - 5.0``. For\n            variable duration problems you must specify time as an integer\n            multiple of the node time interval symbol, for example ``x(0*h) -\n            5.0``. The integer must be a value from 0 to\n            ``num_collocation_nodes - 1``. Unknown parameters and time varying\n            parameters other than the states are currently not supported.\n        time_symbol : SymPy Symbol, optional\n            The symbol representating time in the equations of motion. If not\n            given, it is assumed to be the default stored in\n            ``sympy.physics.vector.dynamicsymbols._t``.\n        tmp_dir : string, optional\n            If you want to see the generated Cython and C code for the\n            constraint and constraint Jacobian evaluations, pass in a path to a\n            directory here.\n        integration_method : string, optional\n            The integration method to use, either ``backward euler`` or\n            ``midpoint``.\n        parallel : boolean, optional\n            If true and openmp is installed, constraints and the Jacobian of\n            the constraints will be executed across multiple threads. This is\n            only useful for performance when the equations of motion have an\n            extremely large number of operations.\n        show_compile_output : boolean, optional\n            If True, STDOUT and STDERR of the Cython compilation call will be\n            shown.\n\n        "
ipdb> coll_doc.split('Parameters\n        ==========\n        ')
['Instantiates a ConstraintCollocator object.\n\n        ', "equations_of_motion : sympy.Matrix, shape(n, 1)\n            A column matrix of SymPy expressions defining the right hand side\n            of the equations of motion when the left hand side is zero, e.g.\n            ``0 = x'(t) - f(x(t), u(t), p)`` or ``0 = f(x'(t), x(t), u(t),\n            p)``. These should be in first order form but not necessairly\n            explicit. They can be ordinary differential equations or\n            differential algebraic equations.\n        state_symbols : iterable\n            An iterable containing all ``n` of the SymPy functions of time\n            which represent the states in the equations of motion.\n        num_collocation_nodes : integer\n            The number of collocation nodes, ``N``. All known trajectory arrays\n            should be of this length.\n        node_time_interval : float or Symbol\n            The time interval between collocation nodes. If a SymPy symbol is\n            provided, the time interval will be treated as a free variable\n            resulting in a variable duration solution.\n        known_parameter_map : dictionary, optional\n            A dictionary that maps the SymPy symbols representing the known\n            constant parameters to floats. Any parameters in the equations of\n            motion not provided in this dictionary will become free\n            optimization variables.\n        known_trajectory_map : dictionary, optional\n            A dictionary that maps the non-state SymPy functions of time to\n            ndarrays of floats of ``shape(N,)``. Any time varying parameters in\n            the equations of motion not provided in this dictionary will become\n            free trajectories optimization variables. If solving a variable\n            duration problem, note that the values here are fixed at each node\n            and will not scale with a varying time interval.\n        instance_constraints : iterable of SymPy expressions, optional\n            These expressions are for constraints on the states at specific\n            times. They can be expressions with any state instance and any of\n            the known parameters found in the equations of motion. All states\n            should be evaluated at a specific instant of time. For example, the\n            constraint ``x(0) = 5.0`` would be specified as ``x(0) - 5.0``. For\n            variable duration problems you must specify time as an integer\n            multiple of the node time interval symbol, for example ``x(0*h) -\n            5.0``. The integer must be a value from 0 to\n            ``num_collocation_nodes - 1``. Unknown parameters and time varying\n            parameters other than the states are currently not supported.\n        time_symbol : SymPy Symbol, optional\n            The symbol representating time in the equations of motion. If not\n            given, it is assumed to be the default stored in\n            ``sympy.physics.vector.dynamicsymbols._t``.\n        tmp_dir : string, optional\n            If you want to see the generated Cython and C code for the\n            constraint and constraint Jacobian evaluations, pass in a path to a\n            directory here.\n        integration_method : string, optional\n            The integration method to use, either ``backward euler`` or\n            ``midpoint``.\n        parallel : boolean, optional\n            If true and openmp is installed, constraints and the Jacobian of\n            the constraints will be executed across multiple threads. This is\n            only useful for performance when the equations of motion have an\n            extremely large number of operations.\n        show_compile_output : boolean, optional\n            If True, STDOUT and STDERR of the Cython compilation call will be\n            shown.\n\n        "]
moorepants commented 18 hours ago

In the Python 3.13 changes https://docs.python.org/3/whatsnew/3.13.html#other-language-changes it says:

The compiler now strips common leading whitespace from every line in a docstring.

which seems backwards incompatible.

moorepants commented 18 hours ago

The change was here: https://github.com/python/cpython/issues/81283 and there seems to be lots of other downstream code breaking because of it.