BUG: DALFormatError: Incorrect number of elements in array
- Dominant language
- Python
- Stars
- 88
- Forks
- 64
- Avg merge
- 38m
- Merged PRs (30d)
- 1
Description
[Edit:] - while the code snippet below doesn't produce the traceback any more, removing the skips in the narrative docs (reverting https://github.com/astropy/pyvo/commit/b3f4dc0f8446d12ca433a6d55e4563791df98f69) would still produces the error.
This error now pops up at two different places for the pyvo test suite, and we also see it downstream in astroquery. I'm fairly certain that this is pyvo or astropy related rather than upstream server issues as the two failing examples are using two different providers, one is gavo the other is cadc.
```
from pyvo.dal.sia2 import search, SIAService
CADC_SIA_URL = 'https://ws.cadc-ccda.hia-iha.nrc-cnrc.gc.ca/sia'
results = search(CADC_SIA_URL, pos=(2.8425, 74.4846, 10), maxrec=55)
for i in results.iter_datalinks():
print(i)
break
```
```
======================================================= FAILURES =======================================================
___________________________________________ TestSIACadc.test_datalink_batch ____________________________________________
self = {'ID': ['ivo://cadc.nrc.ca/CFHT?949070/949070s', 'ivo://cadc.nrc.ca/CFHT?950677/950677og', 'ivo://cadc.nrc.ca/CFHT?949...0161-s/tess2019289112926-s0017-3-3-0161-s-CALIBRATED'], 'RESPONSEFORMAT': 'application/x-votable+xml;content=datalink'}
post = True
def execute_votable(self, post=False):
"""
Submit the query and return the results as an AstroPy votable instance.
As this is the level where qualified error messages are available,
they are raised here instead of in the underlying execute_stream.
Returns
-------
astropy.io.votable.tree.Table
an Astropy votable Table instance
Raises
------
DALServiceError
for errors connecting to or communicating with the service
DALFormatError
for errors parsing the VOTable response
See Also
--------
astropy.io.votable
DALServiceError
DALFormatError
DALQueryError
"""
try:
> return votableparse(self.execute_stream(post=post).read)
pyvo/dal/query.py:243:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
args = (functools.partial(>, decode_content=True),)
kwargs = {}, i = 0, msg = '"pedantic" was deprecated in version 5.0 and will be removed in a future version. '
@functools.wraps(function)
def wrapper(*args, **kwargs):
for i in range(n):
msg = message[i] or (f'"{old_name[i]}" was deprecated in '
f'version {since[i]} and will be removed '
'in a future version. ')
# The only way to have oldkeyword inside the function is
# that it is passed as kwarg because the oldkeyword
# parameter was renamed to newkeyword.
if old_name[i] in kwargs:
value = kwargs.pop(old_name[i])
# Display the deprecation warning only when it's not
# pending.
if not pending[i]:
if not message[i]:
if new_name[i] is not None:
msg += f'Use argument "{new_name[i]}" instead.'
elif alternative:
msg += f'\n Use {alternative} instead.'
warnings.warn(msg, warning_type, stacklevel=2)
# Check if the newkeyword was given as well.
newarg_in_args = (position[i] is not None and
len(args) > position[i])
newarg_in_kwargs = new_name[i] in kwargs
if newarg_in_args or newarg_in_kwargs:
if not pending[i]:
# If both are given print a Warning if relax is
# True or raise an Exception is relax is False.
if relax[i]:
warnings.warn(
f'"{old_name[i]}" and "{new_name[i]}" '
'keywords were set. '
f'Using the value of "{new_name[i]}".',
AstropyUserWarning)
else:
raise TypeError(
f'cannot specify both "{old_name[i]}" and '
f'"{new_name[i]}".')
else:
# Pass the value of the old argument with the
# name of the new argument to the function
if new_name[i] is not None:
kwargs[new_name[i]] = value
# If old argument has no replacement, cast it back.
# https://github.com/astropy/astropy/issues/9914
else:
kwargs[old_name[i]] = value
# Deprecated keyword without replacement is given as
# positional argument.
elif (not pending[i] and not new_name[i] and position[i] and
len(args) > position[i]):
if alternative and not message[i]:
msg += f'\n Use {alternative} instead.'
warnings.warn(msg, warning_type, stacklevel=2)
> return function(*args, **kwargs)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/utils/decorators.py:545:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
source = functools.partial(>, decode_content=True)
columns = None, invalid = 'exception', verify = 'ignore', chunk_size = 256, table_number = None, table_id = None
filename = None, unit_format = None, datatype_mapping = {}, _debug_python_based_parser = False
@deprecated_renamed_argument('pedantic', 'verify', since='5.0')
def parse(source, columns=None, invalid='exception', verify=None,
chunk_size=tree.DEFAULT_CHUNK_SIZE, table_number=None,
table_id=None, filename=None, unit_format=None,
datatype_mapping=None, _debug_python_based_parser=False):
"""
Parses a VOTABLE_ xml file (or file-like object), and returns a
`~astropy.io.votable.tree.VOTableFile` object.
Parameters
----------
source : path-like or file-like
Path or file-like object containing a VOTABLE_ xml file.
If file, must be readable.
columns : sequence of str, optional
List of field names to include in the output. The default is
to include all fields.
invalid : str, optional
One of the following values:
- 'exception': throw an exception when an invalid value is
encountered (default)
- 'mask': mask out invalid values
verify : {'ignore', 'warn', 'exception'}, optional
When ``'exception'``, raise an error when the file violates the spec,
otherwise either issue a warning (``'warn'``) or silently continue
(``'ignore'``). Warnings may be controlled using the standard Python
mechanisms. See the `warnings` module in the Python standard library
for more information. When not provided, uses the configuration setting
``astropy.io.votable.verify``, which defaults to 'ignore'.
.. versionchanged:: 4.0
``verify`` replaces the ``pedantic`` argument, which will be
deprecated in future.
.. versionchanged:: 5.0
The ``pedantic`` argument is deprecated.
chunk_size : int, optional
The number of rows to read before converting to an array.
Higher numbers are likely to be faster, but will consume more
memory.
table_number : int, optional
The number of table in the file to read in. If `None`, all
tables will be read. If a number, 0 refers to the first table
in the file, and only that numbered table will be parsed and
read in. Should not be used with ``table_id``.
table_id : str, optional
The ID of the table in the file to read in. Should not be
used with ``table_number``.
filename : str, optional
A filename, URL or other identifier to use in error messages.
If *filename* is None and *source* is a string (i.e. a path),
then *source* will be used as a filename for error messages.
Therefore, *filename* is only required when source is a
file-like object.
unit_format : str, astropy.units.format.Base instance or None, optional
The unit format to use when parsing unit attributes. If a
string, must be the name of a unit formatter. The built-in
formats include ``generic``, ``fits``, ``cds``, and
``vounit``. A custom formatter may be provided by passing a
`~astropy.units.UnitBase` instance. If `None` (default),
the unit format to use will be the one specified by the
VOTable specification (which is ``cds`` up to version 1.3 of
VOTable, and ``vounit`` in more recent versions of the spec).
datatype_mapping : dict, optional
A mapping of datatype names (`str`) to valid VOTable datatype names
(str). For example, if the file being read contains the datatype
"unsignedInt" (an invalid datatype in VOTable), include the mapping
``{"unsignedInt": "long"}``.
Returns
-------
votable : `~astropy.io.votable.tree.VOTableFile` object
See Also
--------
astropy.io.votable.exceptions : The exceptions this function may raise.
"""
from . import conf
invalid = invalid.lower()
if invalid not in ('exception', 'mask'):
raise ValueError("accepted values of ``invalid`` are: "
"``'exception'`` or ``'mask'``.")
if verify is None:
conf_verify_lowercase = conf.verify.lower()
# We need to allow verify to be booleans as strings since the
# configuration framework doesn't make it easy/possible to have mixed
# types.
if conf_verify_lowercase in ['false', 'true']:
verify = conf_verify_lowercase == 'true'
else:
verify = conf_verify_lowercase
if isinstance(verify, bool):
verify = 'exception' if verify else 'warn'
elif verify not in VERIFY_OPTIONS:
raise ValueError(f"verify should be one of {'/'.join(VERIFY_OPTIONS)}")
if datatype_mapping is None:
datatype_mapping = {}
config = {
'columns': columns,
'invalid': invalid,
'verify': verify,
'chunk_size': chunk_size,
'table_number': table_number,
'filename': filename,
'unit_format': unit_format,
'datatype_mapping': datatype_mapping
}
if filename is None and isinstance(source, str):
config['filename'] = source
with iterparser.get_xml_iterator(
source,
_debug_python_based_parser=_debug_python_based_parser) as iterator:
return tree.VOTableFile(
> config=config, pos=(1, 1)).parse(iterator, config)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/table.py:160:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ... 1 tables ..., iterator =
config = {'_current_table_number': 1, 'chunk_size': 256, 'columns': None, 'datatype_mapping': {}, ...}
def parse(self, iterator, config):
config['_current_table_number'] = 0
for start, tag, data, pos in iterator:
if start:
if tag == 'xml':
pass
elif tag == 'VOTABLE':
if 'version' not in data:
warn_or_raise(W20, W20, self.version, config, pos)
config['version'] = self.version
else:
config['version'] = self._version = data['version']
if config['version'].lower().startswith('v'):
warn_or_raise(
W29, W29, config['version'], config, pos)
self._version = config['version'] = \
config['version'][1:]
if config['version'] not in self._version_namespace_map:
vo_warn(W21, config['version'], config, pos)
if 'xmlns' in data:
ns_info = self._version_namespace_map.get(config['version'], {})
correct_ns = ns_info.get('namespace_uri')
if data['xmlns'] != correct_ns:
vo_warn(W41, (correct_ns, data['xmlns']), config, pos)
else:
vo_warn(W42, (), config, pos)
break
else:
vo_raise(E19, (), config, pos)
config.update(self._get_version_checks())
tag_mapping = {
'PARAM': self._add_param,
'RESOURCE': self._add_resource,
'COOSYS': self._add_coosys,
'TIMESYS': self._add_timesys,
'INFO': self._add_info,
'DEFINITIONS': self._add_definitions,
'DESCRIPTION': self._ignore_add,
'GROUP': self._add_group}
for start, tag, data, pos in iterator:
if start:
> tag_mapping.get(tag, self._add_unknown_tag)(
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:3596:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ... 1 tables ..., iterator =
tag = 'RESOURCE', data = {'ID': 'soda-4f70ffe7-506c-43d2-9f1e-30dda6cf4e89', 'type': 'meta', 'utype': 'adhoc:service'}
config = {'_current_table_number': 1, 'chunk_size': 256, 'columns': None, 'datatype_mapping': {}, ...}, pos = (1650, 2)
def _add_resource(self, iterator, tag, data, config, pos):
resource = Resource(config=config, pos=pos, **data)
self.resources.append(resource)
> resource.parse(self, iterator, config)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:3475:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , votable = ... 1 tables ...
iterator =
config = {'_current_table_number': 1, 'chunk_size': 256, 'columns': None, 'datatype_mapping': {}, ...}
def parse(self, votable, iterator, config):
self._votable = votable
tag_mapping = {
'TABLE': self._add_table,
'INFO': self._add_info,
'PARAM': self._add_param,
'GROUP': self._add_group,
'COOSYS': self._add_coosys,
'TIMESYS': self._add_timesys,
'RESOURCE': self._add_resource,
'LINK': self._add_link,
'DESCRIPTION': self._ignore_add
}
for start, tag, data, pos in iterator:
if start:
> tag_mapping.get(tag, self._add_unknown_tag)(
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:3285:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , iterator = , tag = 'GROUP'
data = {'name': 'inputParams'}
config = {'_current_table_number': 1, 'chunk_size': 256, 'columns': None, 'datatype_mapping': {}, ...}, pos = (1654, 4)
def _add_group(self, iterator, tag, data, config, pos):
group = Group(self, config=config, pos=pos, **data)
self.groups.append(group)
> group.parse(iterator, config)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:3241:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ... 5 entries ..., iterator =
config = {'_current_table_number': 1, 'chunk_size': 256, 'columns': None, 'datatype_mapping': {}, ...}
def parse(self, iterator, config):
tag_mapping = {
'FIELDref': self._add_fieldref,
'PARAMref': self._add_paramref,
'PARAM': self._add_param,
'GROUP': self._add_group,
'DESCRIPTION': self._ignore_add}
for start, tag, data, pos in iterator:
if start:
> tag_mapping.get(tag, self._add_unknown_tag)(
iterator, tag, data, config, pos)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:2086:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ... 5 entries ..., iterator =
tag = 'PARAM', data = {'arraysize': '2', 'datatype': 'double', 'name': 'BAND', 'ucd': 'em.wl;stat.interval', ...}
config = {'_current_table_number': 1, 'chunk_size': 256, 'columns': None, 'datatype_mapping': {}, ...}, pos = (1667, 6)
def _add_param(self, iterator, tag, data, config, pos):
if isinstance(self._table, VOTableFile):
votable = self._table
else:
votable = self._table._votable
param = Param(votable, config=config, pos=pos, **data)
self.entries.append(param)
> param.parse(iterator, config)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:2069:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self =
iterator =
config = {'_current_table_number': 1, 'chunk_size': 256, 'columns': None, 'datatype_mapping': {}, ...}
def parse(self, iterator, config):
for start, tag, data, pos in iterator:
if start:
if tag == 'VALUES':
self.values.__init__(
self._votable, self, config=config, pos=pos, **data)
> self.values.parse(iterator, config)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:1480:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , iterator =
config = {'_current_table_number': 1, 'chunk_size': 256, 'columns': None, 'datatype_mapping': {}, ...}
def parse(self, iterator, config):
if self.ref is not None:
for start, tag, data, pos in iterator:
if start:
warn_or_raise(W44, W44, tag, config, pos)
else:
if tag != 'VALUES':
warn_or_raise(W44, W44, tag, config, pos)
break
else:
for start, tag, data, pos in iterator:
if start:
if tag == 'MIN':
if 'value' not in data:
vo_raise(E09, 'MIN', config, pos)
> self.min = data['value']
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:1024:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , min = '9.099660043187688E-4'
@min.setter
def min(self, min):
if hasattr(self._field, 'converter') and min is not None:
> self._min = self._field.converter.parse(min)[0]
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/tree.py:938:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , value = '9.099660043187688E-4'
config = {'_warning_counts': {: 1}}, pos = None
def parse(self, value, config=None, pos=None):
if config is None:
config = {}
elif config['version_1_3_or_later'] and value == '':
return np.zeros(self._arraysize, dtype=self._base.format), True
parts = self._splitter(value, config, pos)
if len(parts) != self._items:
> warn_or_raise(E02, E02, (self._items, len(parts)), config, pos)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/converters.py:607:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
warning_class =
exception_class = , args = (2, 1)
config = {'_warning_counts': {: 1}}, pos = None, stacklevel = 1
def warn_or_raise(warning_class, exception_class=None, args=(), config=None,
pos=None, stacklevel=1):
"""
Warn or raise an exception, depending on the verify setting.
"""
if config is None:
config = {}
# NOTE: the default here is deliberately warn rather than ignore, since
# one would expect that calling warn_or_raise without config should not
# silence the warnings.
config_value = config.get('verify', 'warn')
if config_value == 'exception':
if exception_class is None:
exception_class = warning_class
vo_raise(exception_class, args, config, pos)
elif config_value == 'warn':
> vo_warn(warning_class, args, config, pos, stacklevel=stacklevel+1)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/exceptions.py:102:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
warning_class = , args = (2, 1)
config = {'_warning_counts': {: 1}}, pos = None, stacklevel = 2
def vo_warn(warning_class, args=(), config=None, pos=None, stacklevel=1):
"""
Warn, with proper position information if available.
"""
if config is None:
config = {}
# NOTE: the default here is deliberately warn rather than ignore, since
# one would expect that calling warn_or_raise without config should not
# silence the warnings.
if config.get('verify', 'warn') != 'ignore':
warning = warning_class(args, config, pos)
> _suppressed_warning(warning, config, stacklevel=stacklevel+1)
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/exceptions.py:143:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
warning = E02('?:?:?: E02: Incorrect number of elements in array. Expected multiple of 2, got 1')
config = {'_warning_counts': {: 1}}, stacklevel = 3
def _suppressed_warning(warning, config, stacklevel=2):
warning_class = type(warning)
config.setdefault('_warning_counts', dict()).setdefault(warning_class, 0)
config['_warning_counts'][warning_class] += 1
message_count = config['_warning_counts'][warning_class]
if message_count <= conf.max_warnings:
if message_count == conf.max_warnings:
warning.formatted_message += \
' (suppressing further warnings of this type...)'
> warn(warning, stacklevel=stacklevel+1)
E astropy.io.votable.exceptions.E02: ?:?:?: E02: Incorrect number of elements in array. Expected multiple of 2, got 1
../../../.pyenv/versions/3.10.0/lib/python3.10/site-packages/astropy/io/votable/exceptions.py:83: E02
During handling of the above exception, another exception occurred:
self =
@pytest.mark.filterwarnings("ignore::pyvo.dal.exceptions.DALOverflowWarning")
def test_datalink_batch(self):
# Maximum batch size in CADC SIA is around 25
# Test whether multiple batches can be retrieved
results = search(CADC_SIA_URL, pos=(2.8425, 74.4846, 10), maxrec=55)
ids = []
> for i in results.iter_datalinks():
pyvo/dal/tests/test_sia2_remote.py:34:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pyvo/dal/adhoc.py:212: in iter_datalinks
current_batch = self.query.execute(post=True)
pyvo/dal/adhoc.py:443: in execute
return DatalinkResults(self.execute_votable(post),
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = {'ID': ['ivo://cadc.nrc.ca/CFHT?949070/949070s', 'ivo://cadc.nrc.ca/CFHT?950677/950677og', 'ivo://cadc.nrc.ca/CFHT?949...0161-s/tess2019289112926-s0017-3-3-0161-s-CALIBRATED'], 'RESPONSEFORMAT': 'application/x-votable+xml;content=datalink'}
post = True
def execute_votable(self, post=False):
"""
Submit the query and return the results as an AstroPy votable instance.
As this is the level where qualified error messages are available,
they are raised here instead of in the underlying execute_stream.
Returns
-------
astropy.io.votable.tree.Table
an Astropy votable Table instance
Raises
------
DALServiceError
for errors connecting to or communicating with the service
DALFormatError
for errors parsing the VOTable response
See Also
--------
astropy.io.votable
DALServiceError
DALFormatError
DALQueryError
"""
try:
return votableparse(self.execute_stream(post=post).read)
except Exception as e:
self.raise_if_error()
> raise DALFormatError(e, self.queryurl)
E pyvo.dal.exceptions.DALFormatError: E02: ?:?:?: E02: Incorrect number of elements in array. Expected multiple of 2, got 1
pyvo/dal/query.py:246: DALFormatError
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with pyvo/dal/query.py at execute_votable and reproduce the failure in TestSIACadc.test_datalink_batch using the CADC SIA URL and results.iter_datalinks(). Compare the failing VOTable parsing path with the GAVO and CADC examples and the narrative documentation skips; done means the pyvo suite no longer raises DALFormatError in these cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100