Skip to content

VOTable serialization is not setting version configuration reliably #18356

Closed

Description

@timj

Description

Trying to write a VOTable using BINARY2 format breaks with:

Traceback (most recent call last):
  File "/Users/timj/work/lsstsw/build/dax_obscore/x.py", line 8, in <module>
    votable.set_all_tables_format("binary2")
  File "/Users/timj/work/lsstsw/miniconda/envs/lsst-scipipe-10.0.0/lib/python3.12/site-packages/astropy/io/votable/tree.py", line 4648, in set_all_tables_format
    table.format = format
    ^^^^^^^^^^^^
  File "/Users/timj/work/lsstsw/miniconda/envs/lsst-scipipe-10.0.0/lib/python3.12/site-packages/astropy/io/votable/tree.py", line 2602, in format
    if not self._config["version_1_3_or_later"]:
           ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: 'version_1_3_or_later'

This is because the _config property is not reliably set in some contexts. The code doesn't always crash because in some parts of the code the check is if not self._config.get("version_x_or_later") which returns False every time and assumes no new features are usable.

In one place in tree.py the code is doing the correct thing:

        if config is None:
            if hasattr(votable, "_get_version_checks"):
                config = votable._get_version_checks()
            else:
                config = {}
        self._config = config

but in every other place in tree.py it's doing:

        if config is None:
            config = {}
        self._config = config

and that seems to guarantee the crash.

I can do a PR to use that logic in all the places needed (and not sure if you also want the .get versus a direct access unified).

Expected behavior

BINARY2 output.

How to Reproduce

import astropy.io.votable.tree

votable = astropy.io.votable.tree.VOTableFile()
resource = astropy.io.votable.tree.Resource()
votable.resources.append(resource)
table0 = astropy.io.votable.tree.TableElement(votable)
resource.tables.append(table0)
votable.set_all_tables_format("binary2")

Versions

import astropy
astropy.system_info()
platform
--------
platform.platform() = 'macOS-15.5-arm64-arm-64bit'
platform.version() = 'Darwin Kernel Version 24.5.0: Tue Apr 22 19:54:49 PDT 2025; root:xnu-11417.121.6~2/RELEASE_ARM64_T6000'
platform.python_version() = '3.12.10'

packages
--------
astropy              7.1.0
numpy                2.0.2
scipy                1.13.1
matplotlib           3.10.1
pandas               2.2.3
pyerfa               2.0.1.5

Activity

  1. timj commented on Jun 26, 2025

    @timj
    ContributorAuthor

    I should add that adding the _get_version_checks call into the TableElement constructor fixes the problem and the BINARY2 output is written correctly.

  2. timj commented on Jun 27, 2025

    @timj
    ContributorAuthor

    Also I have just learned:

    >>> from astropy.io.votable.tree import TimeSys
    >>> TimeSys(ID="sys", timeorigin="MJD-origin", timescale="UTC")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/timj/work/lsstsw/miniconda/envs/lsst-scipipe-10.0.0/lib/python3.12/site-packages/astropy/io/votable/tree.py", line 2057, in __init__
        if not config["version_1_4_or_later"]:
               ~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
    KeyError: 'version_1_4_or_later'

    which can be fixed by passing in a config parameter but where does one obtain that config using public APIs? All I can work out is:

    >>> votable = VOTableFile(version="1.5")
    >>> votable._get_version_checks()
    {'version_1_1_or_later': True, 'version_1_2_or_later': True, 'version_1_3_or_later': True, 'version_1_4_or_later': True, 'version_1_5_or_later': True}

    but that is the private API and even if I were to use votable._config to get it it's not filled in.

  3. pllim commented on Jun 27, 2025

    @pllim
    Member
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions