# Path: baseband/base/header.py
# class ParserDict:
#     """Create a lazily evaluated dictionary of parsers, setters, or defaults.
# 
#     Implemented as a non-data descriptor.  When first called on an instance,
#     it will create a dict under the name of itself in the instance's
#     ``__dict__``, which means that any further attribute access will return
#     that dict instead of this descriptor.
# 
#     Parameters
#     ----------
#     function : callable
#         Function that can be used to create a parser or setter, or get the
#         default, based on a header keyword description.  Typically one of
#         ``make_parser``, ``make_setter``, or ``get_default``.
# 
#     """
# 
#     def __init__(self, function):
#         self.function = function
# 
#     def __set_name__(self, owner, name):
#         self.name = name
#         self.__doc__ = f"Lazily evaluated dict of {name}"
# 
#     def __get__(self, instance, cls=None):
#         if instance is None:
#             return self
#         # Create dict of functions/defaults.
#         d = {key: self.function(*definition)
#              for key, definition in instance.items()}
#         # Override ourselves on the instance.
#         setattr(instance, self.name, d)
#         return d
# 
#     def __repr__(self):
#         return f"{self.__class__.__name__}({self.function}"
# 
# class HeaderParserBase(dict):
#     """Parser & setter for header keywords.
# 
#     A dictionary of header keywords, with values that describe how they are
#     encoded in a given header.  Initialisation is as a normal dict,
#     with (ordered) key, value pairs, with each value a tuple containing
#     information that describes how the value is encoded, and any default.
# 
#     The actual implementation is done by instances of
#     `~baseband.base.header.ParserDict` called ``parsers``, ``setters``, and
#     ``defaults``, which return functions that get a given keyword from
#     header words, set the corresponding part of the header words to a value,
#     or return the default value (if defined).  To speed up access to those,
#     they are precalculated on first access rather than calculated on the fly.
# 
#     """
#     def copy(self):
#         return self.__class__(self)
# 
#     def __or__(self, other):
#         if not isinstance(other, type(self)):
#             return NotImplemented
# 
#         if sys.version_info >= (3, 9):  # pragma: no cover
#             return self.__class__(super().__or__(other))
# 
#         result = self.__class__(self)
#         result.update(other)
#         return result
# 
#     # Backwards compatibility for code written for baseband < 4.0.
#     __add__ = __or__
# 
#     def _clear_caches(self):
#         """Clear the caches of the parser dicts. To be done on any change."""
#         for key in set(self.__dict__):
#             if isinstance(self.__class__.__dict__[key], ParserDict):
#                 del self.__dict__[key]
# 
# class HeaderParser(HeaderParserBase):
#     """Parser & setter for VLBI header keywords.
# 
#     A dictionary of header keywords, with values that describe how they are
#     encoded in a given VLBI header.  Initialisation is as a normal dict,
#     with (ordered) key, value pairs, with each value a tuple containing:
# 
#     word_index : int
#         Index into the header words for this key.
#     bit_index : int
#         Index to the starting bit of the part used for this key.
#     bit_length : int
#         Number of bits.
#     default : int or bool or None
#         Possible default value to use in initialisation (e.g., a sync pattern).
# 
#     The class provides dict-like properties ``parsers``, ``setters``, and
#     ``defaults``, which return functions that get a given keyword from header
#     words, set the corresponding part of the header words to a value, or
#     return the default value (if defined).  To speed up access to those,
#     they are precalculated on first access rather than calculated on the fly.
# 
#     """
#     parsers = ParserDict(make_parser)
#     setters = ParserDict(make_setter)
#     defaults = ParserDict(get_default)


import pytest
from ..header import ParserDict, HeaderParserBase, HeaderParser
        class H(HeaderParserBase):
            parsers = ParserDict(cls.create_parser)
            indices = ParserDict(cls.random_name)
            defaults = ParserDict(cls.get_default)

        cls.H = H

    def test_parserdict(self):
        assert self.H.parsers.name == 'parsers'
        assert self.H.indices.name == 'indices'
        assert repr(self.H.parsers).startswith('ParserDict')
        assert 'Lazily evaluated' in self.H.defaults.__doc__

    def test_init(self):
        h = self.H(self.hp)
        words = ['first', 'second']
        assert h.parsers['0'](words) == 'first'
        assert h.defaults['1'] == 'default1'
        assert h.indices['1'] == 1


class TestHeaderParser:
    def setup_class(cls):
        cls.header_parser = HeaderParser(
            (('x0_16_4', (0, 16, 4)),
             ('x0_31_1', (0, 31, 1, False)),
             ('x1_0_32', (1, 0, 32)),
             ('x2_0_64', (2, 0, 64, 1 << 32))))

    def test_header_parser_update(self):

# Path: baseband/base/header.py
# class ParserDict:
#     """Create a lazily evaluated dictionary of parsers, setters, or defaults.
# 
#     Implemented as a non-data descriptor.  When first called on an instance,
#     it will create a dict under the name of itself in the instance's
#     ``__dict__``, which means that any further attribute access will return
#     that dict instead of this descriptor.
# 
#     Parameters
#     ----------
#     function : callable
#         Function that can be used to create a parser or setter, or get the
#         default, based on a header keyword description.  Typically one of
#         ``make_parser``, ``make_setter``, or ``get_default``.
# 
#     """
# 
#     def __init__(self, function):
#         self.function = function
# 
#     def __set_name__(self, owner, name):
#         self.name = name
#         self.__doc__ = f"Lazily evaluated dict of {name}"
# 
#     def __get__(self, instance, cls=None):
#         if instance is None:
#             return self
#         # Create dict of functions/defaults.
#         d = {key: self.function(*definition)
#              for key, definition in instance.items()}
#         # Override ourselves on the instance.
#         setattr(instance, self.name, d)
#         return d
# 
#     def __repr__(self):
#         return f"{self.__class__.__name__}({self.function}"
# 
# class HeaderParserBase(dict):
#     """Parser & setter for header keywords.
# 
#     A dictionary of header keywords, with values that describe how they are
#     encoded in a given header.  Initialisation is as a normal dict,
#     with (ordered) key, value pairs, with each value a tuple containing
#     information that describes how the value is encoded, and any default.
# 
#     The actual implementation is done by instances of
#     `~baseband.base.header.ParserDict` called ``parsers``, ``setters``, and
#     ``defaults``, which return functions that get a given keyword from
#     header words, set the corresponding part of the header words to a value,
#     or return the default value (if defined).  To speed up access to those,
#     they are precalculated on first access rather than calculated on the fly.
# 
#     """
#     def copy(self):
#         return self.__class__(self)
# 
#     def __or__(self, other):
#         if not isinstance(other, type(self)):
#             return NotImplemented
# 
#         if sys.version_info >= (3, 9):  # pragma: no cover
#             return self.__class__(super().__or__(other))
# 
#         result = self.__class__(self)
#         result.update(other)
#         return result
# 
#     # Backwards compatibility for code written for baseband < 4.0.
#     __add__ = __or__
# 
#     def _clear_caches(self):
#         """Clear the caches of the parser dicts. To be done on any change."""
#         for key in set(self.__dict__):
#             if isinstance(self.__class__.__dict__[key], ParserDict):
#                 del self.__dict__[key]
# 
# class HeaderParser(HeaderParserBase):
#     """Parser & setter for VLBI header keywords.
# 
#     A dictionary of header keywords, with values that describe how they are
#     encoded in a given VLBI header.  Initialisation is as a normal dict,
#     with (ordered) key, value pairs, with each value a tuple containing:
# 
#     word_index : int
#         Index into the header words for this key.
#     bit_index : int
#         Index to the starting bit of the part used for this key.
#     bit_length : int
#         Number of bits.
#     default : int or bool or None
#         Possible default value to use in initialisation (e.g., a sync pattern).
# 
#     The class provides dict-like properties ``parsers``, ``setters``, and
#     ``defaults``, which return functions that get a given keyword from header
#     words, set the corresponding part of the header words to a value, or
#     return the default value (if defined).  To speed up access to those,
#     they are precalculated on first access rather than calculated on the fly.
# 
#     """
#     parsers = ParserDict(make_parser)
#     setters = ParserDict(make_setter)
#     defaults = ParserDict(get_default)


# Path: baseband/base/tests/test_header_parser.py
import pytest
from ..header import ParserDict, HeaderParserBase, HeaderParser

        class H(HeaderParserBase):
            parsers = ParserDict(cls.create_parser)
            indices = ParserDict(cls.random_name)
            defaults = ParserDict(cls.get_default)

        cls.H = H

    def test_parserdict(self):
        assert self.H.parsers.name == 'parsers'
        assert self.H.indices.name == 'indices'
        assert repr(self.H.parsers).startswith('ParserDict')
        assert 'Lazily evaluated' in self.H.defaults.__doc__

    def test_init(self):
        h = self.H(self.hp)
        words = ['first', 'second']
        assert h.parsers['0'](words) == 'first'
        assert h.defaults['1'] == 'default1'
        assert h.indices['1'] == 1


class TestHeaderParser:
    def setup_class(cls):
        cls.header_parser = HeaderParser(
            (('x0_16_4', (0, 16, 4)),
             ('x0_31_1', (0, 31, 1, False)),
             ('x1_0_32', (1, 0, 32)),
             ('x2_0_64', (2, 0, 64, 1 << 32))))

    def test_header_parser_update(self):

        extra = HeaderParser((('x4_0_32', (4, 0, 32)),))